+Ext.addBehaviors({
+ // add a listener for click on all anchors in element with id foo
+ '#foo a@click' : function(e, t){
+ // do something
+ },
+
+ // add the same listener to multiple selectors (separated by comma BEFORE the @)
+ '#foo a, #bar span.some-class@mouseover' : function(){
+ // do something
+ }
+});
+
+ * @param {Object} obj The list of behaviors to apply
+ */
+ addBehaviors : function(o){
+ if(!Ext.isReady){
+ Ext.onReady(function(){
+ Ext.addBehaviors(o);
+ });
+ return;
+ }
+ var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
+ for(var b in o){
+ var parts = b.split('@');
+ if(parts[1]){ // for Object prototype breakers
+ var s = parts[0];
+ if(!cache[s]){
+ cache[s] = Ext.select(s);
+ }
+ cache[s].on(parts[1], o[b]);
+ }
+ }
+ cache = null;
+ },
+
+ /**
+ * Generates unique ids. If the element already has an id, it is unchanged
+ * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
+ * @param {String} prefix (optional) Id prefix (defaults "ext-gen")
+ * @return {String} The generated Id.
+ */
+ id : function(el, prefix){
+ prefix = prefix || "ext-gen";
+ el = Ext.getDom(el);
+ var id = prefix + (++idSeed);
+ return el ? (el.id ? el.id : (el.id = id)) : id;
+ },
+
+ /**
+ * Extends one class with another class and optionally overrides members with the passed literal. This class
+ * also adds the function "override()" to the class that can be used to override
+ * members on an instance.
+ * @param {Object} subclass The class inheriting the functionality
+ * @param {Object} superclass The class being extended
+ * @param {Object} overrides (optional) A literal with members
+ * @method extend
+ */
+ extend : function(){
+ // inline overrides
+ var io = function(o){
+ for(var m in o){
+ this[m] = o[m];
+ }
+ };
+ return function(sb, sp, overrides){
+ if(typeof sp == 'object'){
+ overrides = sp;
+ sp = sb;
+ sb = function(){sp.apply(this, arguments);};
+ }
+ var F = function(){}, sbp, spp = sp.prototype;
+ F.prototype = spp;
+ sbp = sb.prototype = new F();
+ sbp.constructor=sb;
+ sb.superclass=spp;
+ if(spp.constructor == Object.prototype.constructor){
+ spp.constructor=sp;
+ }
+ sb.override = function(o){
+ Ext.override(sb, o);
+ };
+ sbp.override = io;
+ Ext.override(sb, overrides);
+ return sb;
+ };
+ }(),
+
+ /**
+ * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
+ * Usage:
+Ext.override(MyClass, {
+ newMethod1: function(){
+ // etc.
+ },
+ newMethod2: function(foo){
+ // etc.
+ }
+});
+
+ * @param {Object} origclass The class to override
+ * @param {Object} overrides The list of functions to add to origClass. This should be specified as an object literal
+ * containing one or more methods.
+ * @method override
+ */
+ override : function(origclass, overrides){
+ if(overrides){
+ var p = origclass.prototype;
+ for(var method in overrides){
+ p[method] = overrides[method];
+ }
+ }
+ },
+ /**
+ * Creates namespaces to be used for scoping variables and classes so that they are not global. Usage:
+ *
+Ext.namespace('Company', 'Company.data');
+Company.Widget = function() { ... }
+Company.data.CustomStore = function(config) { ... }
+
+ * @param {String} namespace1
+ * @param {String} namespace2
+ * @param {String} etc
+ * @method namespace
+ */
+ namespace : function(){
+ var a=arguments, o=null, i, j, d, rt;
+ for (i=0; imyFunction.createCallback(myarg, myarg2)
+ * Will create a function that is bound to those 2 args.
+ * @return {Function} The new function
+ */
+ createCallback : function(/*args...*/){
+ // make args available, in function below
+ var args = arguments;
+ var method = this;
+ return function() {
+ return method.apply(window, args);
+ };
+ },
+
+ /**
+ * Creates a delegate (callback) that sets the scope to obj.
+ * Call directly on any function. Example: this.myFunction.createDelegate(this)
+ * Will create a function that is automatically scoped to this.
+ * @param {Object} obj (optional) The object for which the scope is set
+ * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
+ * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
+ * if a number the args are inserted at the specified position
+ * @return {Function} The new function
+ */
+ createDelegate : function(obj, args, appendArgs){
+ var method = this;
+ return function() {
+ var callArgs = args || arguments;
+ if(appendArgs === true){
+ callArgs = Array.prototype.slice.call(arguments, 0);
+ callArgs = callArgs.concat(args);
+ }else if(typeof appendArgs == "number"){
+ callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
+ var applyArgs = [appendArgs, 0].concat(args); // create method call params
+ Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
+ }
+ return method.apply(obj || window, callArgs);
+ };
+ },
+
+ /**
+ * Calls this function after the number of millseconds specified.
+ * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
+ * @param {Object} obj (optional) The object for which the scope is set
+ * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
+ * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
+ * if a number the args are inserted at the specified position
+ * @return {Number} The timeout id that can be used with clearTimeout
+ */
+ defer : function(millis, obj, args, appendArgs){
+ var fn = this.createDelegate(obj, args, appendArgs);
+ if(millis){
+ return setTimeout(fn, millis);
+ }
+ fn();
+ return 0;
+ },
+ /**
+ * Create a combined function call sequence of the original function + the passed function.
+ * The resulting function returns the results of the original function.
+ * The passed fcn is called with the parameters of the original function
+ * @param {Function} fcn The function to sequence
+ * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
+ * @return {Function} The new function
+ */
+ createSequence : function(fcn, scope){
+ if(typeof fcn != "function"){
+ return this;
+ }
+ var method = this;
+ return function() {
+ var retval = method.apply(this || window, arguments);
+ fcn.apply(scope || this || window, arguments);
+ return retval;
+ };
+ },
+
+ /**
+ * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
+ * The resulting function returns the results of the original function.
+ * The passed fcn is called with the parameters of the original function.
+ * @addon
+ * @param {Function} fcn The function to call before the original
+ * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
+ * @return {Function} The new function
+ */
+ createInterceptor : function(fcn, scope){
+ if(typeof fcn != "function"){
+ return this;
+ }
+ var method = this;
+ return function() {
+ fcn.target = this;
+ fcn.method = method;
+ if(fcn.apply(scope || this || window, arguments) === false){
+ return;
+ }
+ return method.apply(this || window, arguments);
+ };
+ }
+});
+
+/**
+ * @class String
+ * These functions are available as static methods on the JavaScript String object.
+ */
+Ext.applyIf(String, {
+
+ /**
+ * Escapes the passed string for ' and \
+ * @param {String} string The string to escape
+ * @return {String} The escaped string
+ * @static
+ */
+ escape : function(string) {
+ return string.replace(/('|\\)/g, "\\$1");
+ },
+
+ /**
+ * Pads the left side of a string with a specified character. This is especially useful
+ * for normalizing number and date strings. Example usage:
+ *
+var s = String.leftPad('123', 5, '0');
+// s now contains the string: '00123'
+
+ * @param {String} string The original string
+ * @param {Number} size The total length of the output string
+ * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
+ * @return {String} The padded string
+ * @static
+ */
+ leftPad : function (val, size, ch) {
+ var result = new String(val);
+ if(ch === null || ch === undefined || ch === '') {
+ ch = " ";
+ }
+ while (result.length < size) {
+ result = ch + result;
+ }
+ return result;
+ },
+
+ /**
+ * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens. Each
+ * token must be unique, and must increment in the format {0}, {1}, etc. Example usage:
+ *
+var cls = 'my-class', text = 'Some text';
+var s = String.format('{1}', cls, text);
+// s now contains the string: 'Some text'
+
+ * @param {String} string The tokenized string to be formatted
+ * @param {String} value1 The value to replace token {0}
+ * @param {String} value2 Etc...
+ * @return {String} The formatted string
+ * @static
+ */
+ format : function(format){
+ var args = Array.prototype.slice.call(arguments, 1);
+ return format.replace(/\{(\d+)\}/g, function(m, i){
+ return args[i];
+ });
+ }
+});
+
+/**
+ * Utility function that allows you to easily switch a string between two alternating values. The passed value
+ * is compared to the current string, and if they are equal, the other value that was passed in is returned. If
+ * they are already different, the first value passed in is returned. Note that this method returns the new value
+ * but does not change the current string.
+ *
+// alternate sort directions
+sort = sort.toggle('ASC', 'DESC');
+
+// instead of conditional logic:
+sort = (sort == 'ASC' ? 'DESC' : 'ASC');
+
+ * @param {String} value The value to compare to the current string
+ * @param {String} other The new value to use if the string already equals the first value passed in
+ * @return {String} The new value
+ */
+String.prototype.toggle = function(value, other){
+ return this == value ? other : value;
+};
+/**
+ * @class Number
+ */
+Ext.applyIf(Number.prototype, {
+ /**
+ * Checks whether or not the current number is within a desired range. If the number is already within the
+ * range it is returned, otherwise the min or max value is returned depending on which side of the range is
+ * exceeded. Note that this method returns the constrained value but does not change the current number.
+ * @param {Number} min The minimum number in the range
+ * @param {Number} max The maximum number in the range
+ * @return {Number} The constrained value if outside the range, otherwise the current value
+ */
+ constrain : function(min, max){
+ return Math.min(Math.max(this, min), max);
+ }
+});
+/**
+ * @class Array
+ */
+Ext.applyIf(Array.prototype, {
+ /**
+ * Checks whether or not the specified object exists in the array.
+ * @param {Object} o The object to check for
+ * @return {Number} The index of o in the array (or -1 if it is not found)
+ */
+ indexOf : function(o){
+ for (var i = 0, len = this.length; i < len; i++){
+ if(this[i] == o) return i;
+ }
+ return -1;
+ },
+
+ /**
+ * Removes the specified object from the array. If the object is not found nothing happens.
+ * @param {Object} o The object to remove
+ */
+ remove : function(o){
+ var index = this.indexOf(o);
+ if(index != -1){
+ this.splice(index, 1);
+ }
+ }
+});
+
+/**
+ Returns the number of milliseconds between this date and date
+ @param {Date} date (optional) Defaults to now
+ @return {Number} The diff in milliseconds
+ @member Date getElapsed
+ */
+Date.prototype.getElapsed = function(date) {
+ return Math.abs((date || new Date()).getTime()-this.getTime());
+};
+
+
+
+
+(function(){
+
+var libFlyweight;
+
+Ext.lib.Dom = {
+ getViewWidth : function(full){
+ return full ? this.getDocumentWidth() : this.getViewportWidth();
+ },
+
+ getViewHeight : function(full){
+ return full ? this.getDocumentHeight() : this.getViewportHeight();
+ },
+
+ getDocumentHeight: function() { // missing from prototype?
+ var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
+ return Math.max(scrollHeight, this.getViewportHeight());
+ },
+
+ getDocumentWidth: function() { // missing from prototype?
+ var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
+ return Math.max(scrollWidth, this.getViewportWidth());
+ },
+
+ getViewportHeight: function() { // missing from prototype?
+ var height = self.innerHeight;
+ var mode = document.compatMode;
+
+ if ( (mode || Ext.isIE) && !Ext.isOpera ) {
+ height = (mode == "CSS1Compat") ?
+ document.documentElement.clientHeight : // Standards
+ document.body.clientHeight; // Quirks
+ }
+
+ return height;
+ },
+
+ getViewportWidth: function() { // missing from prototype?
+ var width = self.innerWidth; // Safari
+ var mode = document.compatMode;
+
+ if (mode || Ext.isIE) { // IE, Gecko, Opera
+ width = (mode == "CSS1Compat") ?
+ document.documentElement.clientWidth : // Standards
+ document.body.clientWidth; // Quirks
+ }
+ return width;
+ },
+
+ isAncestor : function(p, c){ // missing from prototype?
+ p = Ext.getDom(p);
+ c = Ext.getDom(c);
+ if (!p || !c) {return false;}
+
+ if(p.contains && !Ext.isSafari) {
+ return p.contains(c);
+ }else if(p.compareDocumentPosition) {
+ return !!(p.compareDocumentPosition(c) & 16);
+ }else{
+ var parent = c.parentNode;
+ while (parent) {
+ if (parent == p) {
+ return true;
+ }
+ else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
+ return false;
+ }
+ parent = parent.parentNode;
+ }
+ return false;
+ }
+ },
+
+ getRegion : function(el){
+ return Ext.lib.Region.getRegion(el);
+ },
+
+ getY : function(el){
+ return this.getXY(el)[1];
+ },
+
+ getX : function(el){
+ return this.getXY(el)[0];
+ },
+
+ getXY : function(el){ // this initially used Position.cumulativeOffset but it is not accurate enough
+ var p, pe, b, scroll, bd = document.body;
+ el = Ext.getDom(el);
+
+ if (el.getBoundingClientRect) {
+ b = el.getBoundingClientRect();
+ scroll = fly(document).getScroll();
+ return [b.left + scroll.left, b.top + scroll.top];
+ }
+ var x = 0, y = 0;
+
+ p = el;
+
+ var hasAbsolute = fly(el).getStyle("position") == "absolute";
+
+ while (p) {
+
+ x += p.offsetLeft;
+ y += p.offsetTop;
+
+ if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
+ hasAbsolute = true;
+ }
+
+ if (Ext.isGecko) {
+ pe = fly(p);
+
+ var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
+ var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
+
+
+ x += bl;
+ y += bt;
+
+
+ if (p != el && pe.getStyle('overflow') != 'visible') {
+ x += bl;
+ y += bt;
+ }
+ }
+ p = p.offsetParent;
+ }
+
+ if (Ext.isSafari && hasAbsolute) {
+ x -= bd.offsetLeft;
+ y -= bd.offsetTop;
+ }
+
+ if (Ext.isGecko && !hasAbsolute) {
+ var dbd = fly(bd);
+ x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
+ y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
+ }
+
+ p = el.parentNode;
+ while (p && p != bd) {
+ if (!Ext.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
+ x -= p.scrollLeft;
+ y -= p.scrollTop;
+ }
+ p = p.parentNode;
+ }
+ return [x, y];
+ },
+
+ setXY : function(el, xy){ // this initially used Position.cumulativeOffset but it is not accurate enough
+ el = Ext.fly(el, '_setXY');
+ el.position();
+ var pts = el.translatePoints(xy);
+ if(xy[0] !== false){
+ el.dom.style.left = pts.left + "px";
+ }
+ if(xy[1] !== false){
+ el.dom.style.top = pts.top + "px";
+ }
+ },
+
+ setX : function(el, x){
+ this.setXY(el, [x, false]);
+ },
+
+ setY : function(el, y){
+ this.setXY(el, [false, y]);
+ }
+};
+
+Ext.lib.Event = {
+ getPageX : function(e){
+ return Event.pointerX(e.browserEvent || e);
+ },
+
+ getPageY : function(e){
+ return Event.pointerY(e.browserEvent || e);
+ },
+
+ getXY : function(e){
+ e = e.browserEvent || e;
+ return [Event.pointerX(e), Event.pointerY(e)];
+ },
+
+ getTarget : function(e){
+ return Event.element(e.browserEvent || e);
+ },
+
+ resolveTextNode: function(node) {
+ if (node && 3 == node.nodeType) {
+ return node.parentNode;
+ } else {
+ return node;
+ }
+ },
+
+ getRelatedTarget: function(ev) { // missing from prototype?
+ ev = ev.browserEvent || ev;
+ var t = ev.relatedTarget;
+ if (!t) {
+ if (ev.type == "mouseout") {
+ t = ev.toElement;
+ } else if (ev.type == "mouseover") {
+ t = ev.fromElement;
+ }
+ }
+
+ return this.resolveTextNode(t);
+ },
+
+ on : function(el, eventName, fn){
+ Event.observe(el, eventName, fn, false);
+ },
+
+ un : function(el, eventName, fn){
+ Event.stopObserving(el, eventName, fn, false);
+ },
+
+ purgeElement : function(el){
+ // no equiv?
+ },
+
+ preventDefault : function(e){ // missing from prototype?
+ e = e.browserEvent || e;
+ if(e.preventDefault) {
+ e.preventDefault();
+ } else {
+ e.returnValue = false;
+ }
+ },
+
+ stopPropagation : function(e){ // missing from prototype?
+ e = e.browserEvent || e;
+ if(e.stopPropagation) {
+ e.stopPropagation();
+ } else {
+ e.cancelBubble = true;
+ }
+ },
+
+ stopEvent : function(e){
+ Event.stop(e.browserEvent || e);
+ },
+
+ onAvailable : function(id, fn, scope){ // no equiv
+ var start = new Date(), iid;
+ var f = function(){
+ if(start.getElapsed() > 10000){
+ clearInterval(iid);
+ }
+ var el = document.getElementById(id);
+ if(el){
+ clearInterval(iid);
+ fn.call(scope||window, el);
+ }
+ };
+ iid = setInterval(f, 50);
+ }
+};
+
+Ext.lib.Ajax = function(){
+ var createSuccess = function(cb){
+ return cb.success ? function(xhr){
+ cb.success.call(cb.scope||window, {
+ responseText: xhr.responseText,
+ responseXML : xhr.responseXML,
+ argument: cb.argument
+ });
+ } : Ext.emptyFn;
+ };
+ var createFailure = function(cb){
+ return cb.failure ? function(xhr){
+ cb.failure.call(cb.scope||window, {
+ responseText: xhr.responseText,
+ responseXML : xhr.responseXML,
+ argument: cb.argument
+ });
+ } : Ext.emptyFn;
+ };
+ return {
+ request : function(method, uri, cb, data, options){
+ var o = {
+ method: method,
+ parameters: data || '',
+ timeout: cb.timeout,
+ onSuccess: createSuccess(cb),
+ onFailure: createFailure(cb)
+ };
+ if(options){
+ if(options.headers){
+ o.requestHeaders = options.headers;
+ }
+ if(options.xmlData){
+ method = 'POST';
+ o.contentType = 'text/xml';
+ o.postBody = options.xmlData;
+ delete o.parameters;
+ }
+ }
+ new Ajax.Request(uri, o);
+ },
+
+ formRequest : function(form, uri, cb, data, isUpload, sslUri){
+ new Ajax.Request(uri, {
+ method: Ext.getDom(form).method ||'POST',
+ parameters: Form.serialize(form)+(data?'&'+data:''),
+ timeout: cb.timeout,
+ onSuccess: createSuccess(cb),
+ onFailure: createFailure(cb)
+ });
+ },
+
+ isCallInProgress : function(trans){
+ return false;
+ },
+
+ abort : function(trans){
+ return false;
+ },
+
+ serializeForm : function(form){
+ return Form.serialize(form.dom||form);
+ }
+ };
+}();
+
+
+Ext.lib.Anim = function(){
+
+ var easings = {
+ easeOut: function(pos) {
+ return 1-Math.pow(1-pos,2);
+ },
+ easeIn: function(pos) {
+ return 1-Math.pow(1-pos,2);
+ }
+ };
+ var createAnim = function(cb, scope){
+ return {
+ stop : function(skipToLast){
+ this.effect.cancel();
+ },
+
+ isAnimated : function(){
+ return this.effect.state == 'running';
+ },
+
+ proxyCallback : function(){
+ Ext.callback(cb, scope);
+ }
+ };
+ };
+ return {
+ scroll : function(el, args, duration, easing, cb, scope){
+ // not supported so scroll immediately?
+ var anim = createAnim(cb, scope);
+ el = Ext.getDom(el);
+ if(typeof args.scroll.to[0] == 'number'){
+ el.scrollLeft = args.scroll.to[0];
+ }
+ if(typeof args.scroll.to[1] == 'number'){
+ el.scrollTop = args.scroll.to[1];
+ }
+ anim.proxyCallback();
+ return anim;
+ },
+
+ motion : function(el, args, duration, easing, cb, scope){
+ return this.run(el, args, duration, easing, cb, scope);
+ },
+
+ color : function(el, args, duration, easing, cb, scope){
+ return this.run(el, args, duration, easing, cb, scope);
+ },
+
+ run : function(el, args, duration, easing, cb, scope, type){
+ var o = {};
+ for(var k in args){
+ switch(k){ // scriptaculous doesn't support, so convert these
+ case 'points':
+ var by, pts, e = Ext.fly(el, '_animrun');
+ e.position();
+ if(by = args.points.by){
+ var xy = e.getXY();
+ pts = e.translatePoints([xy[0]+by[0], xy[1]+by[1]]);
+ }else{
+ pts = e.translatePoints(args.points.to);
+ }
+ o.left = pts.left+'px';
+ o.top = pts.top+'px';
+ break;
+ case 'width':
+ o.width = args.width.to+'px';
+ break;
+ case 'height':
+ o.height = args.height.to+'px';
+ break;
+ case 'opacity':
+ o.opacity = String(args.opacity.to);
+ break;
+ default:
+ o[k] = String(args[k].to);
+ break;
+ }
+ }
+ var anim = createAnim(cb, scope);
+ anim.effect = new Effect.Morph(Ext.id(el), {
+ duration: duration,
+ afterFinish: anim.proxyCallback,
+ transition: easings[easing] || Effect.Transitions.linear,
+ style: o
+ });
+ return anim;
+ }
+ };
+}();
+
+
+// all lib flyweight calls use their own flyweight to prevent collisions with developer flyweights
+function fly(el){
+ if(!libFlyweight){
+ libFlyweight = new Ext.Element.Flyweight();
+ }
+ libFlyweight.dom = el;
+ return libFlyweight;
+}
+
+Ext.lib.Region = function(t, r, b, l) {
+ this.top = t;
+ this[1] = t;
+ this.right = r;
+ this.bottom = b;
+ this.left = l;
+ this[0] = l;
+};
+
+Ext.lib.Region.prototype = {
+ contains : function(region) {
+ return ( region.left >= this.left &&
+ region.right <= this.right &&
+ region.top >= this.top &&
+ region.bottom <= this.bottom );
+
+ },
+
+ getArea : function() {
+ return ( (this.bottom - this.top) * (this.right - this.left) );
+ },
+
+ intersect : function(region) {
+ var t = Math.max( this.top, region.top );
+ var r = Math.min( this.right, region.right );
+ var b = Math.min( this.bottom, region.bottom );
+ var l = Math.max( this.left, region.left );
+
+ if (b >= t && r >= l) {
+ return new Ext.lib.Region(t, r, b, l);
+ } else {
+ return null;
+ }
+ },
+ union : function(region) {
+ var t = Math.min( this.top, region.top );
+ var r = Math.max( this.right, region.right );
+ var b = Math.max( this.bottom, region.bottom );
+ var l = Math.min( this.left, region.left );
+
+ return new Ext.lib.Region(t, r, b, l);
+ },
+
+ adjust : function(t, l, b, r){
+ this.top += t;
+ this.left += l;
+ this.right += r;
+ this.bottom += b;
+ return this;
+ }
+};
+
+Ext.lib.Region.getRegion = function(el) {
+ var p = Ext.lib.Dom.getXY(el);
+
+ var t = p[1];
+ var r = p[0] + el.offsetWidth;
+ var b = p[1] + el.offsetHeight;
+ var l = p[0];
+
+ return new Ext.lib.Region(t, r, b, l);
+};
+
+Ext.lib.Point = function(x, y) {
+ if (x instanceof Array) {
+ y = x[1];
+ x = x[0];
+ }
+ this.x = this.right = this.left = this[0] = x;
+ this.y = this.top = this.bottom = this[1] = y;
+};
+
+Ext.lib.Point.prototype = new Ext.lib.Region();
+
+
+// prevent IE leaks
+if(Ext.isIE) {
+ function fnCleanUp() {
+ var p = Function.prototype;
+ delete p.createSequence;
+ delete p.defer;
+ delete p.createDelegate;
+ delete p.createCallback;
+ delete p.createInterceptor;
+
+ window.detachEvent("onunload", fnCleanUp);
+ }
+ window.attachEvent("onunload", fnCleanUp);
+}
+})();
+
+
+
+/**
+ * @class Ext.DomHelper
+ * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
+ * For more information see this blog post with examples.
+ * @singleton
+ */
+Ext.DomHelper = function(){
+ var tempTableEl = null;
+ var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
+ var tableRe = /^table|tbody|tr|td$/i;
+
+ // build as innerHTML where available
+ /** @ignore */
+ var createHtml = function(o){
+ if(typeof o == 'string'){
+ return o;
+ }
+ var b = "";
+ if(!o.tag){
+ o.tag = "div";
+ }
+ b += "<" + o.tag;
+ for(var attr in o){
+ if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
+ if(attr == "style"){
+ var s = o["style"];
+ if(typeof s == "function"){
+ s = s.call();
+ }
+ if(typeof s == "string"){
+ b += ' style="' + s + '"';
+ }else if(typeof s == "object"){
+ b += ' style="';
+ for(var key in s){
+ if(typeof s[key] != "function"){
+ b += key + ":" + s[key] + ";";
+ }
+ }
+ b += '"';
+ }
+ }else{
+ if(attr == "cls"){
+ b += ' class="' + o["cls"] + '"';
+ }else if(attr == "htmlFor"){
+ b += ' for="' + o["htmlFor"] + '"';
+ }else{
+ b += " " + attr + '="' + o[attr] + '"';
+ }
+ }
+ }
+ if(emptyTags.test(o.tag)){
+ b += "/>";
+ }else{
+ b += ">";
+ var cn = o.children || o.cn;
+ if(cn){
+ if(cn instanceof Array){
+ for(var i = 0, len = cn.length; i < len; i++) {
+ b += createHtml(cn[i], b);
+ }
+ }else{
+ b += createHtml(cn, b);
+ }
+ }
+ if(o.html){
+ b += o.html;
+ }
+ b += "" + o.tag + ">";
+ }
+ return b;
+ };
+
+ // build as dom
+ /** @ignore */
+ var createDom = function(o, parentNode){
+ var el = document.createElement(o.tag||'div');
+ var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
+ for(var attr in o){
+ if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || attr == "style" || typeof o[attr] == "function") continue;
+ if(attr=="cls"){
+ el.className = o["cls"];
+ }else{
+ if(useSet) el.setAttribute(attr, o[attr]);
+ else el[attr] = o[attr];
+ }
+ }
+ Ext.DomHelper.applyStyles(el, o.style);
+ var cn = o.children || o.cn;
+ if(cn){
+ if(cn instanceof Array){
+ for(var i = 0, len = cn.length; i < len; i++) {
+ createDom(cn[i], el);
+ }
+ }else{
+ createDom(cn, el);
+ }
+ }
+ if(o.html){
+ el.innerHTML = o.html;
+ }
+ if(parentNode){
+ parentNode.appendChild(el);
+ }
+ return el;
+ };
+
+ var ieTable = function(depth, s, h, e){
+ tempTableEl.innerHTML = [s, h, e].join('');
+ var i = -1, el = tempTableEl;
+ while(++i < depth){
+ el = el.firstChild;
+ }
+ return el;
+ };
+
+ // kill repeat to save bytes
+ var ts = '
+ Employee = function(name){
+ this.name = name;
+ this.addEvents({
+ "fired" : true,
+ "quit" : true
+ });
+ }
+ Ext.extend(Employee, Ext.util.Observable);
+
+ */
+Ext.util.Observable = function(){
+ if(this.listeners){
+ this.on(this.listeners);
+ delete this.listeners;
+ }
+};
+Ext.util.Observable.prototype = {
+ /**
+ * Fires the specified event with the passed parameters (minus the event name).
+ * @param {String} eventName
+ * @param {Object...} args Variable number of parameters are passed to handlers
+ * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
+ */
+ fireEvent : function(){
+ var ce = this.events[arguments[0].toLowerCase()];
+ if(typeof ce == "object"){
+ return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
+ }else{
+ return true;
+ }
+ },
+
+ // private
+ filterOptRe : /^(?:scope|delay|buffer|single)$/,
+
+ /**
+ * Appends an event handler to this component
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The method the event invokes
+ * @param {Object} scope (optional) The scope in which to execute the handler
+ * function. The handler function's "this" context.
+ * @param {Object} options (optional) An object containing handler configuration
+ * properties. This may contain any of the following properties:
+ * Combining Options
+ * Using the options argument, it is possible to combine different types of listeners:
+ *
+ * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
+
+ el.on('click', this.onClick, this, {
+ single: true,
+ delay: 100,
+ forumId: 4
+ });
+
+ *
+ * Attaching multiple handlers in 1 call
+ * The method also allows for a single argument to be passed which is a config object containing properties
+ * which specify multiple handlers.
+ *
+ el.on({
+ 'click': {
+ fn: this.onClick,
+ scope: this,
+ delay: 100
+ },
+ 'mouseover': {
+ fn: this.onMouseOver,
+ scope: this
+ },
+ 'mouseout': {
+ fn: this.onMouseOut,
+ scope: this
+ }
+ });
+
+ * + * Or a shorthand syntax which passes the same scope object to all handlers: +
+ el.on({
+ 'click': this.onClick,
+ 'mouseover': this.onMouseOver,
+ 'mouseout': this.onMouseOut,
+ scope: this
+ });
+
+ */
+ addListener : function(eventName, fn, scope, o){
+ if(typeof eventName == "object"){
+ o = eventName;
+ for(var e in o){
+ if(this.filterOptRe.test(e)){
+ continue;
+ }
+ if(typeof o[e] == "function"){
+ // shared options
+ this.addListener(e, o[e], o.scope, o);
+ }else{
+ // individual options
+ this.addListener(e, o[e].fn, o[e].scope, o[e]);
+ }
+ }
+ return;
+ }
+ o = (!o || typeof o == "boolean") ? {} : o;
+ eventName = eventName.toLowerCase();
+ var ce = this.events[eventName] || true;
+ if(typeof ce == "boolean"){
+ ce = new Ext.util.Event(this, eventName);
+ this.events[eventName] = ce;
+ }
+ ce.addListener(fn, scope, o);
+ },
+
+ /**
+ * Removes a listener
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The handler to remove
+ * @param {Object} scope (optional) The scope (this object) for the handler
+ */
+ removeListener : function(eventName, fn, scope){
+ var ce = this.events[eventName.toLowerCase()];
+ if(typeof ce == "object"){
+ ce.removeListener(fn, scope);
+ }
+ },
+
+ /**
+ * Removes all listeners for this object
+ */
+ purgeListeners : function(){
+ for(var evt in this.events){
+ if(typeof this.events[evt] == "object"){
+ this.events[evt].clearListeners();
+ }
+ }
+ },
+
+ relayEvents : function(o, events){
+ var createHandler = function(ename){
+ return function(){
+ return this.fireEvent.apply(this, Ext.combine(ename, Array.prototype.slice.call(arguments, 0)));
+ };
+ };
+ for(var i = 0, len = events.length; i < len; i++){
+ var ename = events[i];
+ if(!this.events[ename]){ this.events[ename] = true; };
+ o.on(ename, createHandler(ename), this);
+ }
+ },
+
+ /**
+ * Used to define events on this Observable
+ * @param {Object} object The object with the events defined
+ */
+ addEvents : function(o){
+ if(!this.events){
+ this.events = {};
+ }
+ Ext.applyIf(this.events, o);
+ },
+
+ /**
+ * Checks to see if this object has any listeners for a specified event
+ * @param {String} eventName The name of the event to check for
+ * @return {Boolean} True if the event is being listened for, else false
+ */
+ hasListener : function(eventName){
+ var e = this.events[eventName];
+ return typeof e == "object" && e.listeners.length > 0;
+ }
+};
+/**
+ * Appends an event handler to this element (shorthand for addListener)
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The method the event invokes
+ * @param {Object} scope (optional) The scope in which to execute the handler
+ * function. The handler function's "this" context.
+ * @param {Object} options (optional)
+ * @method
+ */
+Ext.util.Observable.prototype.on = Ext.util.Observable.prototype.addListener;
+/**
+ * Removes a listener (shorthand for removeListener)
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The handler to remove
+ * @param {Object} scope (optional) The scope (this object) for the handler
+ * @method
+ */
+Ext.util.Observable.prototype.un = Ext.util.Observable.prototype.removeListener;
+
+/**
+ * Starts capture on the specified Observable. All events will be passed
+ * to the supplied function with the event name + standard signature of the event
+ * before the event is fired. If the supplied function returns false,
+ * the event will not fire.
+ * @param {Observable} o The Observable to capture
+ * @param {Function} fn The function to call
+ * @param {Object} scope (optional) The scope (this object) for the fn
+ * @static
+ */
+Ext.util.Observable.capture = function(o, fn, scope){
+ o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
+};
+
+/**
+ * Removes all added captures from the Observable.
+ * @param {Observable} o The Observable to release
+ * @static
+ */
+Ext.util.Observable.releaseCapture = function(o){
+ o.fireEvent = Ext.util.Observable.prototype.fireEvent;
+};
+
+(function(){
+
+ var createBuffered = function(h, o, scope){
+ var task = new Ext.util.DelayedTask();
+ return function(){
+ task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
+ };
+ };
+
+ var createSingle = function(h, e, fn, scope){
+ return function(){
+ e.removeListener(fn, scope);
+ return h.apply(scope, arguments);
+ };
+ };
+
+ var createDelayed = function(h, o, scope){
+ return function(){
+ var args = Array.prototype.slice.call(arguments, 0);
+ setTimeout(function(){
+ h.apply(scope, args);
+ }, o.delay || 10);
+ };
+ };
+
+ Ext.util.Event = function(obj, name){
+ this.name = name;
+ this.obj = obj;
+ this.listeners = [];
+ };
+
+ Ext.util.Event.prototype = {
+ addListener : function(fn, scope, options){
+ var o = options || {};
+ scope = scope || this.obj;
+ if(!this.isListening(fn, scope)){
+ var l = {fn: fn, scope: scope, options: o};
+ var h = fn;
+ if(o.delay){
+ h = createDelayed(h, o, scope);
+ }
+ if(o.single){
+ h = createSingle(h, this, fn, scope);
+ }
+ if(o.buffer){
+ h = createBuffered(h, o, scope);
+ }
+ l.fireFn = h;
+ if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
+ this.listeners.push(l);
+ }else{
+ this.listeners = this.listeners.slice(0);
+ this.listeners.push(l);
+ }
+ }
+ },
+
+ findListener : function(fn, scope){
+ scope = scope || this.obj;
+ var ls = this.listeners;
+ for(var i = 0, len = ls.length; i < len; i++){
+ var l = ls[i];
+ if(l.fn == fn && l.scope == scope){
+ return i;
+ }
+ }
+ return -1;
+ },
+
+ isListening : function(fn, scope){
+ return this.findListener(fn, scope) != -1;
+ },
+
+ removeListener : function(fn, scope){
+ var index;
+ if((index = this.findListener(fn, scope)) != -1){
+ if(!this.firing){
+ this.listeners.splice(index, 1);
+ }else{
+ this.listeners = this.listeners.slice(0);
+ this.listeners.splice(index, 1);
+ }
+ return true;
+ }
+ return false;
+ },
+
+ clearListeners : function(){
+ this.listeners = [];
+ },
+
+ fire : function(){
+ var ls = this.listeners, scope, len = ls.length;
+ if(len > 0){
+ this.firing = true;
+ var args = Array.prototype.slice.call(arguments, 0);
+ for(var i = 0; i < len; i++){
+ var l = ls[i];
+ if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
+ this.firing = false;
+ return false;
+ }
+ }
+ this.firing = false;
+ }
+ return true;
+ }
+ };
+})();
+
+
+
+/**
+ * @class Ext.EventManager
+ * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides
+ * several useful events directly.
+ * See {@link Ext.EventObject} for more details on normalized event objects.
+ * @singleton
+ */
+Ext.EventManager = function(){
+ var docReadyEvent, docReadyProcId, docReadyState = false;
+ var resizeEvent, resizeTask, textEvent, textSize;
+ var E = Ext.lib.Event;
+ var D = Ext.lib.Dom;
+
+
+ var fireDocReady = function(){
+ if(!docReadyState){
+ docReadyState = true;
+ Ext.isReady = true;
+ if(docReadyProcId){
+ clearInterval(docReadyProcId);
+ }
+ if(Ext.isGecko || Ext.isOpera) {
+ document.removeEventListener("DOMContentLoaded", fireDocReady, false);
+ }
+ if(Ext.isIE){
+ var defer = document.getElementById("ie-deferred-loader");
+ if(defer){
+ defer.onreadystatechange = null;
+ defer.parentNode.removeChild(defer);
+ }
+ }
+ if(docReadyEvent){
+ docReadyEvent.fire();
+ docReadyEvent.clearListeners();
+ }
+ }
+ };
+
+ var initDocReady = function(){
+ docReadyEvent = new Ext.util.Event();
+ if(Ext.isGecko || Ext.isOpera) {
+ document.addEventListener("DOMContentLoaded", fireDocReady, false);
+ }else if(Ext.isIE){
+ document.write("
+ * Combining Options
+ * Using the options argument, it is possible to combine different types of listeners:
+ *
+ * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
+el.on('click', this.onClick, this, {
+ single: true,
+ delay: 100,
+ stopEvent : true,
+ forumId: 4
+});
+ *
+ * Attaching multiple handlers in 1 call
+ * The method also allows for a single argument to be passed which is a config object containing properties
+ * which specify multiple handlers.
+ *
+ * Code:
+el.on({
+ 'click' : {
+ fn: this.onClick
+ scope: this,
+ delay: 100
+ },
+ 'mouseover' : {
+ fn: this.onMouseOver
+ scope: this
+ },
+ 'mouseout' : {
+ fn: this.onMouseOut
+ scope: this
+ }
+});
+ *
+ * Or a shorthand syntax:
+ * Code:
+el.on({
+ 'click' : this.onClick,
+ 'mouseover' : this.onMouseOver,
+ 'mouseout' : this.onMouseOut
+ scope: this
+});
+ */
+ addListener : function(element, eventName, fn, scope, options){
+ if(typeof eventName == "object"){
+ var o = eventName;
+ for(var e in o){
+ if(propRe.test(e)){
+ continue;
+ }
+ if(typeof o[e] == "function"){
+ // shared options
+ listen(element, e, o, o[e], o.scope);
+ }else{
+ // individual options
+ listen(element, e, o[e]);
+ }
+ }
+ return;
+ }
+ return listen(element, eventName, options, fn, scope);
+ },
+
+ /**
+ * Removes an event handler
+ *
+ * @param {String/HTMLElement} element The id or html element to remove the
+ * event from
+ * @param {String} eventName The type of event
+ * @param {Function} fn
+ * @return {Boolean} True if a listener was actually removed
+ */
+ removeListener : function(element, eventName, fn){
+ return stopListening(element, eventName, fn);
+ },
+
+ /**
+ * Fires when the document is ready (before onload and before images are loaded). Can be
+ * accessed shorthanded Ext.onReady().
+ * @param {Function} fn The method the event invokes
+ * @param {Object} scope An object that becomes the scope of the handler
+ * @param {boolean} options
+ */
+ onDocumentReady : function(fn, scope, options){
+ if(docReadyState){ // if it already fired
+ docReadyEvent.addListener(fn, scope, options);
+ docReadyEvent.fire();
+ docReadyEvent.clearListeners();
+ return;
+ }
+ if(!docReadyEvent){
+ initDocReady();
+ }
+ docReadyEvent.addListener(fn, scope, options);
+ },
+
+ /**
+ * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
+ * @param {Function} fn The method the event invokes
+ * @param {Object} scope An object that becomes the scope of the handler
+ * @param {boolean} options
+ */
+ onWindowResize : function(fn, scope, options){
+ if(!resizeEvent){
+ resizeEvent = new Ext.util.Event();
+ resizeTask = new Ext.util.DelayedTask(function(){
+ resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
+ });
+ E.on(window, "resize", function(){
+ if(Ext.isIE){
+ resizeTask.delay(50);
+ }else{
+ resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
+ }
+ });
+ }
+ resizeEvent.addListener(fn, scope, options);
+ },
+
+ /**
+ * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
+ * @param {Function} fn The method the event invokes
+ * @param {Object} scope An object that becomes the scope of the handler
+ * @param {boolean} options
+ */
+ onTextResize : function(fn, scope, options){
+ if(!textEvent){
+ textEvent = new Ext.util.Event();
+ var textEl = new Ext.Element(document.createElement('div'));
+ textEl.dom.className = 'x-text-resize';
+ textEl.dom.innerHTML = 'X';
+ textEl.appendTo(document.body);
+ textSize = textEl.dom.offsetHeight;
+ setInterval(function(){
+ if(textEl.dom.offsetHeight != textSize){
+ textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
+ }
+ }, this.textResizeInterval);
+ }
+ textEvent.addListener(fn, scope, options);
+ },
+
+ /**
+ * Removes the passed window resize listener.
+ * @param {Function} fn The method the event invokes
+ * @param {Object} scope The scope of handler
+ */
+ removeResizeListener : function(fn, scope){
+ if(resizeEvent){
+ resizeEvent.removeListener(fn, scope);
+ }
+ },
+
+ // private
+ fireResize : function(){
+ if(resizeEvent){
+ resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
+ }
+ },
+ /**
+ * Url used for onDocumentReady with using SSL (defaults to Ext.SSL_SECURE_URL)
+ */
+ ieDeferSrc : false,
+ /**
+ * The frequency, in milliseconds, to check for text resize events (defaults to 50)
+ */
+ textResizeInterval : 50
+ };
+ /**
+ * Appends an event handler to an element (shorthand for addListener)
+ * @param {String/HTMLElement} element The html element or id to assign the
+ * @param {String} eventName The type of event to listen for
+ * @param {Function} handler The method the event invokes
+ * @param {Object} scope (optional) The scope in which to execute the handler
+ * function. The handler function's "this" context.
+ * @param {Object} options (optional) An object containing handler configuration
+ * properties. This may contain any of the following properties:
+ * Combining Options
+ * Using the options argument, it is possible to combine different types of listeners:
+ *
+ * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
+el.on('click', this.onClick, this, {
+ single: true,
+ delay: 100,
+ stopEvent : true,
+ forumId: 4
+});
+ *
+ * Attaching multiple handlers in 1 call
+ * The method also allows for a single argument to be passed which is a config object containing properties
+ * which specify multiple handlers.
+ *
+ * Code:
+el.on({
+ 'click' : {
+ fn: this.onClick
+ scope: this,
+ delay: 100
+ },
+ 'mouseover' : {
+ fn: this.onMouseOver
+ scope: this
+ },
+ 'mouseout' : {
+ fn: this.onMouseOut
+ scope: this
+ }
+});
+ *
+ * Or a shorthand syntax:
+ * Code:
+el.on({
+ 'click' : this.onClick,
+ 'mouseover' : this.onMouseOver,
+ 'mouseout' : this.onMouseOut
+ scope: this
+});
+ */
+ pub.on = pub.addListener;
+ pub.un = pub.removeListener;
+
+ pub.stoppedMouseDownEvent = new Ext.util.Event();
+ return pub;
+}();
+/**
+ * Fires when the document is ready (before onload and before images are loaded). Shorthand of {@link Ext.EventManager#onDocumentReady}.
+ * @param {Function} fn The method the event invokes
+ * @param {Object} scope An object that becomes the scope of the handler
+ * @param {boolean} override If true, the obj passed in becomes
+ * the execution scope of the listener
+ * @member Ext
+ * @method onReady
+ */
+Ext.onReady = Ext.EventManager.onDocumentReady;
+
+Ext.onReady(function(){
+ var bd = Ext.get(document.body);
+ if(!bd){ return; }
+
+ var cls = [
+ Ext.isIE ? "ext-ie"
+ : Ext.isGecko ? "ext-gecko"
+ : Ext.isOpera ? "ext-opera"
+ : Ext.isSafari ? "ext-safari" : ""];
+
+ if(Ext.isMac){
+ cls.push("ext-mac");
+ }
+ if(Ext.isLinux){
+ cls.push("ext-linux");
+ }
+ if(Ext.isBorderBox){
+ cls.push('ext-border-box');
+ }
+ if(Ext.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
+ var p = bd.dom.parentNode;
+ if(p){
+ p.className += ' ext-strict';
+ }
+ }
+ bd.addClass(cls.join(' '));
+});
+
+/**
+ * @class Ext.EventObject
+ * EventObject exposes the Yahoo! UI Event functionality directly on the object
+ * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code
+ * Example:
+ *
+ function handleClick(e){ // e is not a standard event object, it is a Ext.EventObject
+ e.preventDefault();
+ var target = e.getTarget();
+ ...
+ }
+ var myDiv = Ext.get("myDiv");
+ myDiv.on("click", handleClick);
+ //or
+ Ext.EventManager.on("myDiv", 'click', handleClick);
+ Ext.EventManager.addListener("myDiv", 'click', handleClick);
+
+ * @singleton
+ */
+Ext.EventObject = function(){
+
+ var E = Ext.lib.Event;
+
+ // safari keypress events for special keys return bad keycodes
+ var safariKeys = {
+ 63234 : 37, // left
+ 63235 : 39, // right
+ 63232 : 38, // up
+ 63233 : 40, // down
+ 63276 : 33, // page up
+ 63277 : 34, // page down
+ 63272 : 46, // delete
+ 63273 : 36, // home
+ 63275 : 35 // end
+ };
+
+ // normalize button clicks
+ var btnMap = Ext.isIE ? {1:0,4:1,2:2} :
+ (Ext.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
+
+ Ext.EventObjectImpl = function(e){
+ if(e){
+ this.setEvent(e.browserEvent || e);
+ }
+ };
+ Ext.EventObjectImpl.prototype = {
+ /** The normal browser event */
+ browserEvent : null,
+ /** The button pressed in a mouse event */
+ button : -1,
+ /** True if the shift key was down during the event */
+ shiftKey : false,
+ /** True if the control key was down during the event */
+ ctrlKey : false,
+ /** True if the alt key was down during the event */
+ altKey : false,
+
+ /** Key constant @type Number */
+ BACKSPACE : 8,
+ /** Key constant @type Number */
+ TAB : 9,
+ /** Key constant @type Number */
+ RETURN : 13,
+ /** Key constant @type Number */
+ ENTER : 13,
+ /** Key constant @type Number */
+ SHIFT : 16,
+ /** Key constant @type Number */
+ CONTROL : 17,
+ /** Key constant @type Number */
+ ESC : 27,
+ /** Key constant @type Number */
+ SPACE : 32,
+ /** Key constant @type Number */
+ PAGEUP : 33,
+ /** Key constant @type Number */
+ PAGEDOWN : 34,
+ /** Key constant @type Number */
+ END : 35,
+ /** Key constant @type Number */
+ HOME : 36,
+ /** Key constant @type Number */
+ LEFT : 37,
+ /** Key constant @type Number */
+ UP : 38,
+ /** Key constant @type Number */
+ RIGHT : 39,
+ /** Key constant @type Number */
+ DOWN : 40,
+ /** Key constant @type Number */
+ DELETE : 46,
+ /** Key constant @type Number */
+ F5 : 116,
+
+ /** @private */
+ setEvent : function(e){
+ if(e == this || (e && e.browserEvent)){ // already wrapped
+ return e;
+ }
+ this.browserEvent = e;
+ if(e){
+ // normalize buttons
+ this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
+ if(e.type == 'click' && this.button == -1){
+ this.button = 0;
+ }
+ this.type = e.type;
+ this.shiftKey = e.shiftKey;
+ // mac metaKey behaves like ctrlKey
+ this.ctrlKey = e.ctrlKey || e.metaKey;
+ this.altKey = e.altKey;
+ // in getKey these will be normalized for the mac
+ this.keyCode = e.keyCode;
+ this.charCode = e.charCode;
+ // cache the target for the delayed and or buffered events
+ this.target = E.getTarget(e);
+ // same for XY
+ this.xy = E.getXY(e);
+ }else{
+ this.button = -1;
+ this.shiftKey = false;
+ this.ctrlKey = false;
+ this.altKey = false;
+ this.keyCode = 0;
+ this.charCode =0;
+ this.target = null;
+ this.xy = [0, 0];
+ }
+ return this;
+ },
+
+ /**
+ * Stop the event (preventDefault and stopPropagation)
+ */
+ stopEvent : function(){
+ if(this.browserEvent){
+ if(this.browserEvent.type == 'mousedown'){
+ Ext.EventManager.stoppedMouseDownEvent.fire(this);
+ }
+ E.stopEvent(this.browserEvent);
+ }
+ },
+
+ /**
+ * Prevents the browsers default handling of the event.
+ */
+ preventDefault : function(){
+ if(this.browserEvent){
+ E.preventDefault(this.browserEvent);
+ }
+ },
+
+ /** @private */
+ isNavKeyPress : function(){
+ var k = this.keyCode;
+ k = Ext.isSafari ? (safariKeys[k] || k) : k;
+ return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
+ },
+
+ isSpecialKey : function(){
+ var k = this.keyCode;
+ return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13 || k == 40 || k == 27 ||
+ (k == 16) || (k == 17) ||
+ (k >= 18 && k <= 20) ||
+ (k >= 33 && k <= 35) ||
+ (k >= 36 && k <= 39) ||
+ (k >= 44 && k <= 45);
+ },
+ /**
+ * Cancels bubbling of the event.
+ */
+ stopPropagation : function(){
+ if(this.browserEvent){
+ if(this.type == 'mousedown'){
+ Ext.EventManager.stoppedMouseDownEvent.fire(this);
+ }
+ E.stopPropagation(this.browserEvent);
+ }
+ },
+
+ /**
+ * Gets the key code for the event.
+ * @return {Number}
+ */
+ getCharCode : function(){
+ return this.charCode || this.keyCode;
+ },
+
+ /**
+ * Returns a normalized keyCode for the event.
+ * @return {Number} The key code
+ */
+ getKey : function(){
+ var k = this.keyCode || this.charCode;
+ return Ext.isSafari ? (safariKeys[k] || k) : k;
+ },
+
+ /**
+ * Gets the x coordinate of the event.
+ * @return {Number}
+ */
+ getPageX : function(){
+ return this.xy[0];
+ },
+
+ /**
+ * Gets the y coordinate of the event.
+ * @return {Number}
+ */
+ getPageY : function(){
+ return this.xy[1];
+ },
+
+ /**
+ * Gets the time of the event.
+ * @return {Number}
+ */
+ getTime : function(){
+ if(this.browserEvent){
+ return E.getTime(this.browserEvent);
+ }
+ return null;
+ },
+
+ /**
+ * Gets the page coordinates of the event.
+ * @return {Array} The xy values like [x, y]
+ */
+ getXY : function(){
+ return this.xy;
+ },
+
+ /**
+ * Gets the target for the event.
+ * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
+ * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
+ search as a number or element (defaults to 10 || document.body)
+ * @param {Boolean} returnEl (optional) True to return a Ext.Element object instead of DOM node
+ * @return {HTMLelement}
+ */
+ getTarget : function(selector, maxDepth, returnEl){
+ return selector ? Ext.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
+ },
+ /**
+ * Gets the related target.
+ * @return {HTMLElement}
+ */
+ getRelatedTarget : function(){
+ if(this.browserEvent){
+ return E.getRelatedTarget(this.browserEvent);
+ }
+ return null;
+ },
+
+ /**
+ * Normalizes mouse wheel delta across browsers
+ * @return {Number} The delta
+ */
+ getWheelDelta : function(){
+ var e = this.browserEvent;
+ var delta = 0;
+ if(e.wheelDelta){ /* IE/Opera. */
+ delta = e.wheelDelta/120;
+ }else if(e.detail){ /* Mozilla case. */
+ delta = -e.detail/3;
+ }
+ return delta;
+ },
+
+ /**
+ * Returns true if the control, meta, shift or alt key was pressed during this event.
+ * @return {Boolean}
+ */
+ hasModifier : function(){
+ return !!((this.ctrlKey || this.altKey) || this.shiftKey);
+ },
+
+ /**
+ * Returns true if the target of this event equals el or is a child of el
+ * @param {String/HTMLElement/Element} el
+ * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
+ * @return {Boolean}
+ */
+ within : function(el, related){
+ var t = this[related ? "getRelatedTarget" : "getTarget"]();
+ return t && Ext.fly(el).contains(t);
+ },
+
+ getPoint : function(){
+ return new Ext.lib.Point(this.xy[0], this.xy[1]);
+ }
+ };
+
+ return new Ext.EventObjectImpl();
+}();
+
+
+
+
+
+/**
+ * @class Ext.Element
+ * Represents an Element in the DOM.
+var el = Ext.get("my-div");
+
+// or with getEl
+var el = getEl("my-div");
+
+// or with a DOM element
+var el = Ext.get(myDivElement);
+
+ * Using Ext.get() or getEl() instead of calling the constructor directly ensures you get the same object
+ * each call instead of constructing a new one.+Option Default Description +--------- -------- --------------------------------------------- +duration .35 The duration of the animation in seconds +easing easeOut The YUI easing method +callback none A function to execute when the anim completes +scope this The scope (this) of the callback function ++* Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or +* manipulate the animation. Here's an example: +
+var el = Ext.get("my-div");
+
+// no animation
+el.setWidth(100);
+
+// default animation
+el.setWidth(100, true);
+
+// animation with some options set
+el.setWidth(100, {
+ duration: 1,
+ callback: this.foo,
+ scope: this
+});
+
+// using the "anim" property to get the Anim object
+var opt = {
+ duration: 1,
+ callback: this.foo,
+ scope: this
+};
+el.setWidth(100, opt);
+...
+if(opt.anim.isAnimated()){
+ opt.anim.stop();
+}
+
+* Composite (Collections of) Elements+Value Description +----- ----------------------------- +tl The top left corner (default) +t The center of the top edge +tr The top right corner +l The center of the left edge +c In the center of the element +r The center of the right edge +bl The bottom left corner +b The center of the bottom edge +br The bottom right corner ++Example Usage: +
+// align el to other-el using the default positioning ("tl-bl", non-constrained)
+el.alignTo("other-el");
+
+// align the top left corner of el with the top right corner of other-el (constrained to viewport)
+el.alignTo("other-el", "tr?");
+
+// align the bottom right corner of el with the center left edge of other-el
+el.alignTo("other-el", "br-l?");
+
+// align the center of el with the bottom left corner of other-el and
+// adjust the x position by -6 pixels (and the y position by 0)
+el.alignTo("other-el", "c-bl", [-6, 0]);
+
+ * @param {String/HTMLElement/Ext.Element} element The element to align to.
+ * @param {String} position The position to align to.
+ * @param {Array} offsets (optional) Offset the positioning by [x, y]
+ * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
+ * @return {Ext.Element} this
+ */
+ alignTo : function(element, position, offsets, animate){
+ var xy = this.getAlignToXY(element, position, offsets);
+ this.setXY(xy, this.preanim(arguments, 3));
+ return this;
+ },
+
+ /**
+ * Anchors an element to another element and realigns it when the window is resized.
+ * @param {String/HTMLElement/Ext.Element} element The element to align to.
+ * @param {String} position The position to align to.
+ * @param {Array} offsets (optional) Offset the positioning by [x, y]
+ * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
+ * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
+ * is a number, it is used as the buffer delay (defaults to 50ms).
+ * @param {Function} callback The function to call after the animation finishes
+ * @return {Ext.Element} this
+ */
+ anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
+ var action = function(){
+ this.alignTo(el, alignment, offsets, animate);
+ Ext.callback(callback, this);
+ };
+ Ext.EventManager.onWindowResize(action, this);
+ var tm = typeof monitorScroll;
+ if(tm != 'undefined'){
+ Ext.EventManager.on(window, 'scroll', action, this,
+ {buffer: tm == 'number' ? monitorScroll : 50});
+ }
+ action.call(this); // align immediately
+ return this;
+ },
+ /**
+ * Clears any opacity settings from this element. Required in some cases for IE.
+ * @return {Ext.Element} this
+ */
+ clearOpacity : function(){
+ if (window.ActiveXObject) {
+ if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
+ this.dom.style.filter = "";
+ }
+ } else {
+ this.dom.style.opacity = "";
+ this.dom.style["-moz-opacity"] = "";
+ this.dom.style["-khtml-opacity"] = "";
+ }
+ return this;
+ },
+
+ /**
+ * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
+ * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
+ * @return {Ext.Element} this
+ */
+ hide : function(animate){
+ this.setVisible(false, this.preanim(arguments, 0));
+ return this;
+ },
+
+ /**
+ * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
+ * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
+ * @return {Ext.Element} this
+ */
+ show : function(animate){
+ this.setVisible(true, this.preanim(arguments, 0));
+ return this;
+ },
+
+ /**
+ * @private Test if size has a unit, otherwise appends the default
+ */
+ addUnits : function(size){
+ return Ext.Element.addUnits(size, this.defaultUnit);
+ },
+
+ /**
+ * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
+ * @return {Ext.Element} this
+ */
+ beginMeasure : function(){
+ var el = this.dom;
+ if(el.offsetWidth || el.offsetHeight){
+ return this; // offsets work already
+ }
+ var changed = [];
+ var p = this.dom, b = document.body; // start with this element
+ while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
+ var pe = Ext.get(p);
+ if(pe.getStyle('display') == 'none'){
+ changed.push({el: p, visibility: pe.getStyle("visibility")});
+ p.style.visibility = "hidden";
+ p.style.display = "block";
+ }
+ p = p.parentNode;
+ }
+ this._measureChanged = changed;
+ return this;
+
+ },
+
+ /**
+ * Restores displays to before beginMeasure was called
+ * @return {Ext.Element} this
+ */
+ endMeasure : function(){
+ var changed = this._measureChanged;
+ if(changed){
+ for(var i = 0, len = changed.length; i < len; i++) {
+ var r = changed[i];
+ r.el.style.visibility = r.visibility;
+ r.el.style.display = "none";
+ }
+ this._measureChanged = null;
+ }
+ return this;
+ },
+
+ /**
+ * Update the innerHTML of this element, optionally searching for and processing scripts
+ * @param {String} html The new HTML
+ * @param {Boolean} loadScripts (optional) true to look for and process scripts
+ * @param {Function} callback For async script loading you can be noticed when the update completes
+ * @return {Ext.Element} this
+ */
+ update : function(html, loadScripts, callback){
+ if(typeof html == "undefined"){
+ html = "";
+ }
+ if(loadScripts !== true){
+ this.dom.innerHTML = html;
+ if(typeof callback == "function"){
+ callback();
+ }
+ return this;
+ }
+ var id = Ext.id();
+ var dom = this.dom;
+
+ html += '';
+
+ E.onAvailable(id, function(){
+ var hd = document.getElementsByTagName("head")[0];
+ var re = /(?: