﻿Ext.override(Ext.menu.Menu, {
    autoWidth : function(){
        var el = this.el, ul = this.ul;
        if(!el){
            return;
        }
        var w = this.width;
        if(w){
            el.setWidth(w);
        }else if(Ext.isIE && (Ext.isIE6 || Ext.isIE7)){
            el.setWidth(this.minWidth);
            var t = el.dom.offsetWidth; // force recalc
            el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
        }
    }
});

Ext.override(Ext.form.ComboBox, {
	get: function(columnName) {
		var recIndex = this.store.find('ID', this.getValue());
		if(recIndex >= 0) {
			return this.store.getAt(recIndex).get(columnName);
		} else {
			return null;
		}
	}
});
Ext.override(Ext.grid.EditorGridPanel, {
	get: function(columns) {
		var col = columns.split(".");
		var cm = this.getColumnModel();
		var rec = this.getSelectionModel().getSelections();
		if(rec != null) {
			var colEditor = cm.getColumnById(col[0]);
			if(colEditor != null) {
				if(colEditor.editor.field.get != null) {
					var result = new Array();
					var y=0;
					for(var i=0;i<rec.length;i++) {
						var recIndex = colEditor.editor.field.store.find('ID', rec[i].get(col[0]));
						if(recIndex >= 0) {
							result[y] = colEditor.editor.field.store.getAt(recIndex).get(col[1]);
							y++;
						}
					}
					if(result.length == 1) {
						return result[0];
					} else {
						if(result.length > 1) {
							return result;
						}
					}
				}
			}
		}
		return null;
	},
	set: function(columnName, value) {
		var rec = this.getSelectionModel().getSelections();
		if(rec.length > 0) {
			rec[0].set(columnName, value);
			return rec[0];
		}
		return false;
	}
});

Ext.override(Ext.tree.TreeDropZone, {
	completeDrop : function(de){
		var ns = de.dropNode, p = de.point, t = de.target;
		if(!Ext.isArray(ns)){
			ns = [ns];
		}
		var n, node, ins = false;
		if (p != 'append'){
			ins = true;
			node = (p == 'above') ? t : t.nextSibling;
		}
		for(var i = 0, len = ns.length; i < len; i++){
			n = ns[i];
			if (ins){
				t.parentNode.insertBefore(n, node);
			}else{
				t.appendChild(n);
			}
			if(Ext.enableFx && this.tree.hlDrop){
	   		n.ui.highlight();
			}
		}
		ns[0].ui.focus();
		t.ui.endDrop();
		this.tree.fireEvent("nodedrop", de);
	}
	
}); 
 
Ext.ux.FixedMultiSelectionModel = Ext.extend(Ext.tree.MultiSelectionModel, {
	// disabled tracking of mouse clicks because it doubles up drag selection...
	onNodeClick : function(node, e){
		if (e.shiftKey) e.preventDefault();
		// this.select(node);
	},

	// private
	// for comparing node order... (taken from quirksmode.org and googlecode)
	compareNodeOrder: document.compareDocumentPosition ?
		function(node1, node2) {
			// W3C DOM lvl 3 method (Gecko)
			return 3 - (node1.ui.elNode.compareDocumentPosition(node2.ui.elNode) & 6);
		} : 
		(typeof document.documentElement.sourceIndex !== "undefined" ? 
			function(node1, node2) {
				// IE source index method
				return node1.ui.elNode.sourceIndex - node2.ui.elNode.sourceIndex;	
			} :
			function(node1, node2) {
				if (node1 == node2) return 0;
				// Safari doesn't support compareDocumentPosition or sourceIndex
				// from http://code.google.com/p/doctype/wiki/ArticleNodeCompareDocumentOrder
				var range1 = document.createRange();
				range1.selectNode(a.ui.elNode);
				range1.collapse(true);

				var range2 = document.createRange();
				range2.selectNode(b.ui.elNode);
				range2.collapse(true);

				return range1.compareBoundaryPoints(Range.START_TO_END, range2);
			}		
		),

	// private
	sortSelNodes: function() {
		if (this.selNodes.length > 1) {
			if (!this.selNodes[0].ui.elNode) return;
			this.selNodes.sort(this.compareNodeOrder);
		}
	},

	// private single point for selectNode
	selectNode: function(node, push) {
		if (!this.isSelected(node)) {
			this.selNodes.push(node);
			this.selMap[node.id] = node;
			node.ui.onSelectedChange(true);
		}
	},

	// overwritten from MultiSelectionModel to fix unselecting...
	select : function(node, e, keepExisting){
		// Add in setting an array as selected... (for multi-selecting D&D nodes)
		if(node instanceof Array){
			for (var c=0;c<node.length;c++) {
				this.selectNode(node[c]);
			}
			this.sortSelNodes();
			this.fireEvent("selectionchange", this, this.selNodes, this.lastSelNode);
			return node;
		}
		// Shift Select to select a range
		// NOTE: Doesn't change lastSelNode
		// EEK has to be a prettier way to do this
		if (e && e.shiftKey && this.selNodes.length > 0) {
			this.lastSelNode = this.lastSelNode || this.selNodes[0];
			var before = this.compareNodeOrder(this.lastSelNode, node) > 0;
			// if (this.lastSelNode == node) {
			// check dom node ordering (from ppk of quirksmode.org)
			this.clearSelections(true);
			var cont = true;
			var inside = false;
			var parent = this.lastSelNode;
			// ummm... yeah don't read this bit...
			do {
				for (var next=parent;next!=null;next=(before?next.previousSibling:next.nextSibling)) {
					// hack to make cascade work the way I want it to
					inside = inside || (before && (next == node || next.contains(node)));
					if (next.isExpanded()) {
						next.cascade(function(n) {
							if (cont != inside) {
								this.selectNode(n);
							}
							cont = (cont && n != node);
							return true;
						}, this);
					} else {
						this.selectNode(next);
						cont = (next != node);
					}
					if (!cont) break;
				}
				if (!cont) break;
				while ((parent = parent.parentNode) != null) {
					if (before) {
						this.selectNode(parent);
					}
					cont = (cont && parent != node);
					if (before && parent.previousSibling) {
						parent = parent.previousSibling;
						break;
					}
					if (!before && parent.nextSibling) {
						parent = parent.nextSibling;
						break;
					}
				}
				if (!cont) break;
			} while (parent != null);
			this.selectNode(node);
			// sort the list
			this.sortSelNodes();
			this.fireEvent("selectionchange", this, this.selNodes, node);
			e.preventDefault();
			return node;
		} else if(keepExisting !== true) {
			this.clearSelections(true);
		}
		if(this.isSelected(node)) {
			// handle deselect of node...
			if (keepExisting === true) {
				this.unselect(node);
				if (this.lastSelNode === node) {
					this.lastSelNode = this.selNodes[0];
				}
				return node;
			}
			this.lastSelNode = node;
			return node;
		}
		// save a resort later on...
		this.selectNode(node);
		this.sortSelNodes();
		this.lastSelNode = node;
		this.fireEvent("selectionchange", this, this.selNodes, this.lastSelNode);
		return node;
	},
	// returns selected nodes precluding children of other selected nodes...
	// used for multi drag and drop...
	getUniqueSelectedNodes: function() {
		var ret = [];
		for (var c=0;c<this.selNodes.length;c++) {
			var parent = this.selNodes[c];
			ret.push(parent);
			// nodes are sorted(?) so skip over subsequent nodes inside this one..
			while ((c+1)<this.selNodes.length && parent.contains(this.selNodes[c+1])) c++;
		}
		return ret;
	},
	
	// check for descendents when nodes are removed...
	unselect: function(node, subnodes) {
		if (subnodes) {
			for (var c=this.selNodes.length-1;c>=0;c--) {
				if (this.selNodes[c].isAncestor(node)) {
					Ext.ux.FixedMultiSelectionModel.superclass.unselect.call(this, this.selNodes[c]);
				}
			}		
		}
		return Ext.ux.FixedMultiSelectionModel.superclass.unselect.call(this, node);
	},
	
    /**
     * Selects the node above the selected node in the tree, intelligently walking the nodes
     * @return TreeNode The new selection
     */
    selectPrevious : function(keepExisting){
        var s = this.selNodes[0];
        if(!s){
            return null;
        }
        var ps = s.previousSibling;
        if(ps){
            if(!ps.isExpanded() || ps.childNodes.length < 1){
                return this.select(ps, null, keepExisting);
            } else{
                var lc = ps.lastChild;
                while(lc && lc.isExpanded() && lc.childNodes.length > 0){
                    lc = lc.lastChild;
                }
                return this.select(lc, null, keepExisting);
            }
        } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
            return this.select(s.parentNode, null, keepExisting);
        }
        return null;
    },

    /**
     * Selects the node above the selected node in the tree, intelligently walking the nodes
     * @return TreeNode The new selection
     */
    selectNext : function(keepExisting){
        var s = this.selNodes[this.selNodes.length-1];
        if(!s){
            return null;
        }
        if(s.firstChild && s.isExpanded()){
             return this.select(s.firstChild, null, keepExisting);
         }else if(s.nextSibling){
             return this.select(s.nextSibling, null, keepExisting);
         }else if(s.parentNode){
            var newS = null;
            s.parentNode.bubble(function(){
                if(this.nextSibling){
                    newS = this.getOwnerTree().selModel.select(this.nextSibling, null, keepExisting);
                    return false;
                }
            });
            return newS;
         }
        return null;
    },

    onKeyDown : function(e){
        var s = this.selNode || this.lastSelNode;
        // undesirable, but required
        var sm = this;
        if(!s){
            return;
        }
        var k = e.getKey();
        switch(k){
             case e.DOWN:
                 e.stopEvent();
                 this.selectNext(e.shiftKey || e.ctrlKey);
             break;
             case e.UP:
                 e.stopEvent();
                 this.selectPrevious(e.shiftKey || e.ctrlKey);
             break;
             case e.RIGHT:
                 e.preventDefault();
                 if(s.hasChildNodes()){
                     if(!s.isExpanded()){
                         s.expand();
                     }else if(s.firstChild){
                         this.select(s.firstChild, e, e.shiftKey || e.ctrlKey);
                     }
                 }
             break;
             case e.LEFT:
                 e.preventDefault();
                 if(s.hasChildNodes() && s.isExpanded()){
                     s.collapse();
                 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
                     this.select(s.parentNode, e, e.shiftKey || e.ctrlKey);
                 }
             break;
        };
    }
    	
});
/*
	Enhanced to support dragging multiple nodes...
	
	for extension refer to data.nodes instead of data.node
	
*/
Ext.ux.MultiSelectTreeDragZone = Ext.extend(Ext.tree.TreeDragZone, {
	onBeforeDrag : function(data, e){
		if (data.nodes && data.nodes.length > 0) {
			for (var c=0;c<data.nodes.length;c++) {
				n = data.nodes[c];
				if (n.draggable === false || n.disabled) return false
			}
			return true;
		} else if (data.node) {
			if (data.node.draggable === false || data.node.disabled) return false			
		}
		return false;
		
	},
	// v1.0
	// fixed to handle multiSelectionModel
	// Data now calls SelectionModel.select instead of waiting for the click event
	// Creates Ghost inline rather than calling TreeNodeUI.
	//
	// v1.1
	// cleanup to have ghost generation slightly less hacky... still hacky though...
	// fixes problems with using extra tag nesting in a custom TreeNodeUI.
	getDragData : function(e) {
		// use tree selection model..
		var selModel = this.tree.getSelectionModel();
		// get event target
		var target = Ext.dd.Registry.getHandleFromEvent(e);
		// if no target (die)
		if (target == null) return;
		if (target.node.isSelected() && e.ctrlKey) {
			selModel.unselect(target.node);
			return;
		}
		var selNodes = [];
		if (!selModel.getSelectedNodes) {
			// if not multiSelectionModel.. just use the target...
			selNodes = [target.node];
		} else {
			// if target not selected select it...
			if (!target.node.isSelected() || e.shiftKey) {
				selModel.select(target.node, e, e.ctrlKey);
			}
			// get selected nodes - nested nodes...
			selNodes = selModel.getUniqueSelectedNodes();
		}
		// if no nodes selected stop now...
		if (!selNodes || selNodes.length < 1) return;
		var dragData = { nodes: selNodes };
		// create a container for the proxy...
		var div = document.createElement('ul'); // create the multi element drag "ghost"
		// add classes to keep is pretty...
		div.className = 'x-tree-node-ct x-tree-lines';
		// add actual dom nodes to div (instead of tree nodes)
		var height = 0;
		for(var i = 0, len = selNodes.length; i < len; i++) {
			// add entire node to proxy
			// normally this is done by TreeNodeUI.appendDDGhost(), but overriding that class requires
			// also overriding TreeLoader etc. Ext.extend() is an option though...
			var clonenode = selNodes[i].ui.wrap.cloneNode(true);
			// fix extra indenting by removing extra spacers
			// should really modify UI rendering code to render a duplicate subtree but this is simpler...
			// count current indent nodes from ui indentNode... (add 1 for elbow)
			var subtract = selNodes[i].ui.indentNode.childNodes.length + 1;
			// avoid indent alterations if possible..
			if (subtract > 0) {
				// relies on node ui using the same tag for all elems...
				var subNodes = Ext.query(selNodes[i].ui.indentNode.nodeName+".x-tree-node-indent", clonenode);
				for (var c=0,clen=subNodes.length;c<clen;c++) {
					var inode = subNodes[c];
					var current = inode.childNodes.length;
					if (current <= subtract) {
						inode.innerHTML = "";
						// remove elbow icon as well..
						if (current < subtract) inode.parentNode.removeChild(subNodes[c].nextSibling);
					} else {
						for (var r=0;r<subtract;r++) {
							subNodes[c].removeChild(subNodes[c].firstChild);
						}
					}
				}
			}
			div.appendChild(clonenode);
			Ext.fly(clonenode).removeClass(['x-tree-selected','x-tree-node-over']);
		}
		dragData.ddel = div;
		return dragData;
	},
	// fix from TreeDragZone (references dragData.node instead of dragData.nodes)
	onInitDrag : function(e){
		var data = this.dragData;
		this.tree.eventModel.disable();
		this.proxy.update("");
		this.proxy.ghost.dom.appendChild(data.ddel);
		this.tree.fireEvent("startdrag", this.tree, data.nodes, e);
	},
	// Called from TreeDropZone (looks like hack for handling multiple tree nodes)
	getTreeNode: function() {
		return this.dragData.nodes;
	},
	// fix from TreeDragZone (refers to data.node instead of data.nodes)
	// Don't know what this does, so leaving as first node.
	getRepairXY : function(e, data){
		return data.nodes[0].ui.getDDRepairXY();
	},

	// fix from TreeDragZone (refers to data.node instead of data.nodes)
	onEndDrag : function(data, e){
		this.tree.eventModel.enable.defer(100, this.tree.eventModel);
		this.tree.fireEvent("enddrag", this.tree, data.nodes || [data.node], e);
	},

	// fix from TreeDragZone (refers to dragData.node instead of dragData.nodes)
	onValidDrop : function(dd, e, id){
		this.tree.fireEvent("dragdrop", this.tree, this.dragData.nodes, dd, e);
		this.hideProxy();
	},

	// fix for invalid Drop
	beforeInvalidDrop : function(e, id){
		// this scrolls the original position back into view
		var sm = this.tree.getSelectionModel();
		// sm.clearSelections();
		// sm.select(this.dragData.nodes, e, true);
	}

});

/*

MultiSelectTreeDropZone

Contains following fixups

- modified functions to handle multiple nodes in dd operation
	isValidDropPoint
	afterRepair
- modified getDropPoint such that isValidDropPoint can simulate leaf style below inserting.
	Overriding isValidDropPoint affects getDropPoint affects onNodeOver and onNodeDrop

Refer to data.nodes instead of data.node for events..

*/
Ext.ux.MultiSelectTreeDropZone = Ext.extend(Ext.tree.TreeDropZone, {

	// fix from TreeDropZone (referred to data.node instead of data.nodes)
	isValidDropPoint : function(n, pt, dd, e, data){
		if(!n || !data) { return false; }
		var targetNode = n.node;
		var dropNodes = data.nodes?data.nodes:[data.node];
		// default drop rules
		if(!(targetNode && targetNode.isTarget && pt)){
			return false;
		}
		if(pt == "append" && targetNode.allowChildren === false){
			return false;
		}
		if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
			return false;
		}
		// don't allow dropping a treenode inside itself...
		for (var c=0;c<dropNodes.length;c++) {
			if(dropNodes[c] && (targetNode == dropNodes[c] || dropNodes[c].contains(targetNode))){
				return false;
			}
		}
		// reuse the object
		var overEvent = this.dragOverData;
		overEvent.tree = this.tree;
		overEvent.target = targetNode;
		overEvent.data = data;
		overEvent.point = pt;
		overEvent.source = dd;
		overEvent.rawEvent = e;
		overEvent.dropNode = dropNodes;
		overEvent.cancel = false;
		var result = this.tree.fireEvent("nodedragover", overEvent);
		return overEvent.cancel === false && result !== false;
	},

	// override to allow insert "below" when leaf != true...
	getDropPoint : function(e, n, dd, data){
		var tn = n.node;
		if(tn.isRoot){
			return this.isValidDropPoint(n, "append", dd, e, data)? "append" : false;
		}
		var dragEl = n.ddel;
		var t = Ext.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
		var y = Ext.lib.Event.getPageY(e);
		var noAppend = tn.allowChildren === false || tn.isLeaf() || !this.isValidDropPoint(n, "append", dd, e, data);
		if(!this.appendOnly && tn.parentNode.allowChildren !== false){
			var noBelow = false;
			if(!this.allowParentInsert){
				noBelow = tn.hasChildNodes() && tn.isExpanded();
			}
			var q = (b - t) / (noAppend ? 2 : 3);
			if(y >= t && y < (t + q) && this.isValidDropPoint(n, "above", dd, e, data)){
				return "above";
			}else if(!noBelow && (noAppend || y >= b-q && y <= b) && this.isValidDropPoint(n, "below", dd, e, data)){
				return "below";
			}
		}
		return noAppend? false: "append";
	},

	// Override because it calls getDropPoint and isValidDropPoint
	onNodeOver : function(n, dd, e, data){
		var pt = this.getDropPoint(e, n, dd, data);
		var node = n.node;

		if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
			this.queueExpand(node);
		}else if(pt != "append"){
			this.cancelExpand();
		}

		var returnCls = this.dropNotAllowed;
		if(pt){
			var el = n.ddel;
			var cls;
			if(pt == "above"){
				returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
				cls = "x-tree-drag-insert-above";
			}else if(pt == "below"){
				returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
				cls = "x-tree-drag-insert-below";
			}else{
				returnCls = "x-tree-drop-ok-append";
				cls = "x-tree-drag-append";
			}
			if(this.lastInsertClass != cls){
				Ext.fly(el).replaceClass(this.lastInsertClass, cls);
				this.lastInsertClass = cls;
			}
		}
		return returnCls;
	},

	// Override because it calls getDropPoint and isValidDropPoint
	onNodeDrop : function(n, dd, e, data){
		var point = this.getDropPoint(e, n, dd, data);
		var targetNode = n.node;
		targetNode.ui.startDrop();
		if(point === false) {
			targetNode.ui.endDrop();
			return false;
		}

		var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
		var dropEvent = {
			tree : this.tree,
			target: targetNode,
			data: data,
			point: point,
			source: dd,
			rawEvent: e,
			dropNode: dropNode,
			cancel: !dropNode,
			dropStatus: false
		};
		var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
		if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
			targetNode.ui.endDrop();
			return dropEvent.dropStatus;
		}

		targetNode = dropEvent.target;
		if(point == "append" && !targetNode.isExpanded()){
			targetNode.expand(false, null, function(){
				this.completeDrop(dropEvent);
			}.createDelegate(this));
		}else{
			this.completeDrop(dropEvent);
		}
		return true;
	},

	// fix from TreeDropZone (referred to data.node instead of data.nodes)
	afterRepair : function(data){
		if(data && Ext.enableFx){
			var nl = data.nodes?data.nodes:[data.node];
			for (var c=0,len=nl.length;c<len;c++) {
				nl[c].ui.highlight();
			}
		}
		this.hideProxy();
	},

	// handle allowContainerDrop (appends nodes to the root node)
	onContainerDrop : function(dd, e, data) {
		if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
			var targetNode = this.tree.getRootNode();		
			targetNode.ui.startDrop();
			var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, "append", e) : null);
			var dropEvent = {
				tree : this.tree,
				target: targetNode,
				data: data,
				point: "append",
				source: dd,
				rawEvent: e,
				dropNode: dropNode,
				cancel: !dropNode,
				dropStatus: false
			};
			var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
			if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
				targetNode.ui.endDrop();
				return dropEvent.dropStatus;
			}
	
			targetNode = dropEvent.target;
			if(!targetNode.isExpanded()){
				targetNode.expand(false, null, function(){
					this.completeDrop(dropEvent);
				}.createDelegate(this));
			}else{
				this.completeDrop(dropEvent);
			}
			return true;
		}
		return false;
	},
	
	// handle allowContaineDrop (treat as a drop to the root node)
	onContainerOver : function(dd, e, data) {
		if (this.allowContainerDrop && this.isValidDropPoint({ ddel: this.tree.getRootNode().ui.elNode, node: this.tree.getRootNode() }, "append", dd, e, data)) {
			return this.dropAllowed;
		}
		return this.dropNotAllowed;
	}

});

/*

	MultiSelectTreePanel

	sets up using FixedMultiSelectionModel
	and initing with extended DragZone and DropZone by default

*/

Ext.ux.MultiSelectTreePanel = Ext.extend(Ext.tree.TreePanel, {

	getSelectionModel : function(){
		if(!this.selModel){
			this.selModel = new Ext.ux.FixedMultiSelectionModel();
		}
		return this.selModel;
	},

	initEvents: function() {
		if((this.enableDD || this.enableDrop) && !this.dropZone){
			this.dropZone = new Ext.ux.MultiSelectTreeDropZone(this, this.dropConfig || {
								ddGroup: this.ddGroup || "TreeDD",
								appendOnly: this.ddAppendOnly === true
							});
		}
		if((this.enableDD || this.enableDrag) && !this.dragZone){
			this.dragZone = new Ext.ux.MultiSelectTreeDragZone(this, {
								ddGroup: this.ddGroup || "TreeDD",
								scroll: this.ddScroll
							});
		}
		Ext.ux.MultiSelectTreePanel.superclass.initEvents.apply(this, arguments);

		// This is temporary. Should really Ext.extend on TreeNode.removeChild()
		// and call getOwnerTree().removeNode(node) or similar...

		this.on("remove", function(tree, parent, node) {
			tree.getSelectionModel().unselect(node, true);
		});
	}
});

Ext.reg('multiselecttreepanel', Ext.ux.MultiSelectTreePanel);


Ext.override(Ext.form.DateField, {
	initEvents: function() {
		Ext.form.NumberField.superclass.initEvents.call(this);
		this.menuListeners.select = function() {
			this.setValue(arguments[1]);
			if(this.events.select != null) { 
				if(this.events.select.listeners != null) {
					if(this.events.select.listeners[0] != null) {
						if(this.events.select.listeners[0].fireFn != null) {
							this.events.select.listeners[0].fireFn(); 
						}
					}
				}
			} 
		}
	}
});
Ext.override(Ext.grid.CellSelectionModel, {
	onEditorKey : function(field, e){
		if(field.parseValue != null) {
			field.value = field.getValue();
			field.setRawValue(field.getValue());
			field.parseValue(field.getValue());
		}
		var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
		var shift = e.shiftKey;
		if(k == e.TAB){
			e.stopEvent();
			ed.completeEdit();
			if(shift){
				newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
			}else{
				newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
			}
		}else if(k == e.ENTER || k == e.UP || k == e.DOWN){
			e.stopEvent();
			ed.completeEdit();
			if(this.moveEditorOnEnter !== false){
				if(shift && k == e.ENTER || k == e.UP){
					newCell = g.walkCells(ed.row - 1, ed.col, -1, this.acceptsNav, this);
				}else{
					newCell = g.walkCells(ed.row + 1, ed.col, 1, this.acceptsNav, this);
				}
			}
		}else if(k == e.ESC){
			ed.cancelEdit();
		}
		if(newCell){
			g.startEditing(newCell[0], newCell[1]);
		}
	}
});

Ext.grid.GroupSummary = function(config){
    Ext.apply(this, config);
};

Ext.extend(Ext.grid.GroupSummary, Ext.util.Observable, {
    init : function(grid){
        this.grid = grid;
        this.cm = grid.getColumnModel();
        this.view = grid.getView();

        var v = this.view;
        v.doGroupEnd = this.doGroupEnd.createDelegate(this);

        v.afterMethod('onColumnWidthUpdated', this.doWidth, this);
        v.afterMethod('onAllColumnWidthsUpdated', this.doAllWidths, this);
        v.afterMethod('onColumnHiddenUpdated', this.doHidden, this);
        v.afterMethod('onUpdate', this.doUpdate, this);
        v.afterMethod('onRemove', this.doRemove, this);

        if(!this.rowTpl){
            this.rowTpl = new Ext.Template(
                '<div class="x-grid3-summary-row" style="{tstyle}">',
                '<table class="x-grid3-summary-table" border="0" cellspacing="0" cellpadding="0" style="{tstyle}">',
                    '<tbody><tr>{cells}</tr></tbody>',
                '</table></div>'
            );
            this.rowTpl.disableFormats = true;
        }
        this.rowTpl.compile();

        if(!this.cellTpl){
            this.cellTpl = new Ext.Template(
                '<td class="x-grid3-col x-grid3-cell x-grid3-td-{id} {css}" style="{style}">',
                '<div class="x-grid3-cell-inner x-grid3-col-{id}" unselectable="on">{value}</div>',
                "</td>"
            );
            this.cellTpl.disableFormats = true;
        }
        this.cellTpl.compile();
    },

    toggleSummaries : function(visible){
        var el = this.grid.getGridEl();
        if(el){
            if(visible === undefined){
                visible = el.hasClass('x-grid-hide-summary');
            }
            el[visible ? 'removeClass' : 'addClass']('x-grid-hide-summary');
        }
    },

    renderSummary : function(o, cs){
        cs = cs || this.view.getColumnData();
        var cfg = this.cm.config;

        var buf = [], c, p = {}, cf, last = cs.length-1;
        for(var i = 0, len = cs.length; i < len; i++){
            c = cs[i];
            cf = cfg[i];
            p.id = c.id;
            p.style = c.style;
            p.css = i == 0 ? 'x-grid3-cell-first ' : (i == last ? 'x-grid3-cell-last ' : '');
            if(cf.summaryType || cf.summaryRenderer){
                p.value = (cf.summaryRenderer || c.renderer)(o.data[c.name], p, o);
            }else{
                p.value = '';
            }
            if(p.value == undefined || p.value === "") p.value = "&#160;";
            buf[buf.length] = this.cellTpl.apply(p);
        }

        return this.rowTpl.apply({
            tstyle: 'width:'+this.view.getTotalWidth()+';',
            cells: buf.join('')
        });
    },

    calculate : function(rs, cs){
        var data = {}, r, c, cfg = this.cm.config, cf;
        for(var j = 0, jlen = rs.length; j < jlen; j++){
            r = rs[j];
            for(var i = 0, len = cs.length; i < len; i++){
                c = cs[i];
                cf = cfg[i];
                if(cf.summaryType){
                    data[c.name] = Ext.grid.GroupSummary.Calculations[cf.summaryType](data[c.name] || 0, r, c.name, data);
                }
            }
        }
        return data;
    },

    doGroupEnd : function(buf, g, cs, ds, colCount){
        var data = this.calculate(g.rs, cs);
        buf.push('</div>', this.renderSummary({data: data}, cs), '</div>');
    },

    doWidth : function(col, w, tw){
        var gs = this.view.getGroups(), s;
        for(var i = 0, len = gs.length; i < len; i++){
            s = gs[i].childNodes[2];
            s.style.width = tw;
            s.firstChild.style.width = tw;
            s.firstChild.rows[0].childNodes[col].style.width = w;
        }
    },

    doAllWidths : function(ws, tw){
        var gs = this.view.getGroups(), s, cells, wlen = ws.length;
        for(var i = 0, len = gs.length; i < len; i++){
            s = gs[i].childNodes[2];
            s.style.width = tw;
            s.firstChild.style.width = tw;
            cells = s.firstChild.rows[0].childNodes;
            for(var j = 0; j < wlen; j++){
                cells[j].style.width = ws[j];
            }
        }
    },

    doHidden : function(col, hidden, tw){
        var gs = this.view.getGroups(), s, display = hidden ? 'none' : '';
        for(var i = 0, len = gs.length; i < len; i++){
            s = gs[i].childNodes[2];
            s.style.width = tw;
            s.firstChild.style.width = tw;
            s.firstChild.rows[0].childNodes[col].style.display = display;
        }
    },

    // Note: requires that all (or the first) record in the 
    // group share the same group value. Returns false if the group
    // could not be found.
    refreshSummary : function(groupValue){
        return this.refreshSummaryById(this.view.getGroupId(groupValue));
    },

    getSummaryNode : function(gid){
        var g = Ext.fly(gid, '_gsummary');
        if(g){
            return g.down('.x-grid3-summary-row', true);
        }
        return null;
    },

    refreshSummaryById : function(gid){
        var g = document.getElementById(gid);
        if(!g){
            return false;
        }
        var rs = [];
        this.grid.store.each(function(r){
            if(r._groupId == gid){
                rs[rs.length] = r;
            }
        });
        var cs = this.view.getColumnData();
        var data = this.calculate(rs, cs);
        var markup = this.renderSummary({data: data}, cs);

        var existing = this.getSummaryNode(gid);
        if(existing){
            g.removeChild(existing);
        }
        Ext.DomHelper.append(g, markup);
        return true;
    },

    doUpdate : function(ds, record){
        this.refreshSummaryById(record._groupId);
    },

    doRemove : function(ds, record, index, isUpdate){
        if(!isUpdate){
            this.refreshSummaryById(record._groupId);
        }
    },

    showSummaryMsg : function(groupValue, msg){
        var gid = this.view.getGroupId(groupValue);
        var node = this.getSummaryNode(gid);
        if(node){
            node.innerHTML = '<div class="x-grid3-summary-msg">' + msg + '</div>';
        }
    }
});

Ext.grid.GroupSummary.Calculations = {
    'sum' : function(v, record, field){
        return v + (record.data[field]||0);
    },

    'count' : function(v, record, field, data){
        return data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
    },

    'max' : function(v, record, field, data){
        var v = record.data[field];
        var max = data[field+'max'] === undefined ? (data[field+'max'] = v) : data[field+'max'];
        return v > max ? (data[field+'max'] = v) : max;
    },

    'min' : function(v, record, field, data){
        var v = record.data[field];
        var min = data[field+'min'] === undefined ? (data[field+'min'] = v) : data[field+'min'];
        return v < min ? (data[field+'min'] = v) : min;
    },

    'average' : function(v, record, field, data){
        var c = data[field+'count'] ? ++data[field+'count'] : (data[field+'count'] = 1);
        var t = (data[field+'total'] = ((data[field+'total']||0) + (record.data[field]||0)));
        return t === 0 ? 0 : t / c;
    }
}

Ext.grid.HybridSummary = Ext.extend(Ext.grid.GroupSummary, {
    calculate : function(rs, cs){
        var gcol = this.view.getGroupField();
        var gvalue = rs[0].data[gcol];
        var gdata = this.getSummaryData(gvalue);
        return gdata || Ext.grid.HybridSummary.superclass.calculate.call(this, rs, cs);
    },

    updateSummaryData : function(groupValue, data, skipRefresh){
        var json = this.grid.store.reader.jsonData;
        if(!json.summaryData){
            json.summaryData = {};
        }
        json.summaryData[groupValue] = data;
        if(!skipRefresh){
            this.refreshSummary(groupValue);
        }
    },

    getSummaryData : function(groupValue){
        var json = this.grid.store.reader.jsonData;
        if(json && json.summaryData){
            return json.summaryData[groupValue];
        }
        return null;
    }
});

Ext.override(Ext.grid.GridPanel, { 
	GridUpdateStore : function(obj) {
		this.store.load({
			params: Ext.decode("{\"filter\": \""+obj.filter+"\",\"filterValue\": \""+obj.value+"\"," + Ext.encode(this.store.lastOptions.params).substr(1))
		});
	},	
	Criterias : {
		currentFilters : new Array(),
		add: function(pId, pColumn, pOperator, pValue) {
			this.currentFilters[this.currentFilters.length] = {id: pId, column: pColumn, operator: pOperator, value: pValue};
		},
		remove: function(pId) {
			for(x in this.currentFilters) {
				if(this.currentFilters[x].id == pId) {
					this.currentFilters[x] = this.currentFilters[this.currentFilters.length];
					this.currentFilters.length--;
				}
			}
		},
		clear: function() {
			this.currentFilters = new Array();
		},
		getById: function(pId) {
			for(x in this.currentFilters) {
				if(this.currentFilters[x].id == pId) {
					return this.currentFilters[x];
				}
			}
			return null;
		},
		update: function() {
			updateStore();
		}
	},
	getSum: function(colName) {
		var sum=0,value=null;
		for(var i=0;i<this.store.data.items.length;i++) {
			value = parseFloat(this.store.getAt(i).get(colName));
			if(!isNaN(value)) {
				sum+=value;
			}
		}
		return sum;
	},
	getAverage: function(colName) {
		var sum=0,value=null;
		for(var i=0;i<this.store.data.items.length;i++) {
			value = parseFloat(this.store.getAt(i).get(colName));
			if(!isNaN(value)) {
				sum+=value;
			}
		}
		return sum/this.store.data.items.length;
	},
	getMin: function(colName) {
		var minValue=null,newValue=null;
		for(var i=0;i<this.store.data.items.length;i++) {
			newValue = parseFloat(this.store.getAt(i).get(colName));
			if(!isNaN(newValue)) {
				if(minValue == null) {
					minValue = newValue;
				} else {
					if(minValue > newValue) {
						minValue = newValue;
					}
				}
			}
		}
		return minValue;
	},
	getMax: function(colName) {
		var maxValue=null,newValue=null;
		for(var i=0;i<this.store.data.items.length;i++) {
			newValue = parseFloat(this.store.getAt(i).get(colName));
			if(!isNaN(newValue)) {
				if(maxValue == null) {
					maxValue = newValue;
				} else {
					if(maxValue < newValue) {
						maxValue = newValue;
					}
				}
			}
		}
		return maxValue;
	},
	getCount: function() {
		return this.store.data.items.length;
	}
});

Ext.namespace('Ext.ux');

Ext.ux.FCKEditor = function(config) {
	Ext.apply(this, config);
	if(config.renderTo != null) {
		this.render(config.renderTo);
	}
}
Ext.override(Ext.ux.FCKEditor, {
	render: function(el) {
		var div = null;
		switch(typeof el) {
			case 'string':
				div = document.getElementById(el);
				break;
			case 'object':
				div = el;
				break;
			default:
				break;
		}
		if(div != null) {
			var fck = new FCKeditor((this.name || this.id));
			fck.BasePath = (this.BasePath || "http://shared.beezilla.com/libs/htmleditor/fckeditor/") ;
			fck.Height = (this.height || 450);
			fck.Width = (this.width || 450);
			fck.Config['ImageUpload'] = true;
			filepath = window.parent.location.href;
			locationpath = filepath.split('/');
			fck.Config['SkinPath'] = filepath.substring(0,filepath.lastIndexOf(locationpath[locationpath.length-1])) +'../../libs/htmleditor/fckeditor/editor/skins/office2003/';
			fck.Config['AutoDetectLanguage'] = true;
			fck.ToolbarSet = 'Backoffice';

			if(this.value != null) {
				fck.Value = this.value;
			} else {
				fck.Value = '';
			}
			div.innerHTML = fck.CreateHtml();
		}
	},
	setValue: function(v) {
		if(this.fck == null) {
			var fckEditor = FCKeditorAPI.GetInstance(this.id);
			Ext.apply(this, {fck: fckEditor});
		}
		this.fck.SetHTML(v);
	},
	getValue: function() {
		return this.fck.GetHTML();
	},
	setHeight: function() {
		
	},
	setWidth: function() {
		
	}
});




Ext.ux.Toolbar = function(config) {
 
    // call parent constructor
    Ext.ux.Toolbar.superclass.constructor.call(this, config);
 
} // end of Ext.ux.Toolbar constructor

Ext.extend(Ext.ux.Toolbar, Ext.Toolbar, {
    toolbarView:null 
}); // end of extend


Ext.ux.Toolbar.Button = function(config){
    Ext.ux.Toolbar.Button.superclass.constructor.call(this, config);
};

Ext.extend(Ext.ux.Toolbar.Button, Ext.Toolbar.Button, {
    toolbarView:null 
}); // end of extend

Ext.ux.HourField = function(config) {
    Ext.ux.HourField.superclass.constructor.call(this, config);
};

Ext.extend(Ext.ux.HourField, Ext.form.NumberField, {
    hoursPerDay : 7.5 ,
    getNumberOfDays : function(){
        if (this.rendered) {
            return Math.round(parseFloat(parseFloat(this.getValue().toString().replace(",", ".")) / this.hoursPerDay) * 100) / 100;
        } else {
            return "";
        }
    }
}); // end of extend


Ext.override(Ext.form.NumberField, {
	initEvents : function() {
        Ext.form.NumberField.superclass.initEvents.call(this);
        var allowed = "0123456789";
        if(this.allowDecimals){
            allowed += ".,";
            //allowed += this.decimalSeparator;
        }
        if(this.allowNegative){
            allowed += "-";
        }
        this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
        var keyPress = function(e){
            var k = e.getKey();
            if(!Ext.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
                return;
            }
            var c = e.getCharCode();
            if(allowed.indexOf(String.fromCharCode(c)) === -1){
                e.stopEvent();
            }
        };
        this.el.on("keypress", keyPress, this);
		this.el.on("blur", function() {
			value = this.getValue().toString().replace(",", ".");
			value = String(value).replace(this.decimalSeparator, ".");
			value = parseFloat(value);
			
			value = parseFloat(String(value).replace(this.decimalSeparator, "."));
			this.setRawValue(isNaN(value) ? '' : value.toFixed(this.decimalPrecision));
		}, this);
	},
	parseValue : function(value){
        var s = value.toString();
        value = value.toString().replace(",", ".");
        value = String(value).replace(this.decimalSeparator, ".");
        value = parseFloat(value);
        
        value = parseFloat(String(value).replace(this.decimalSeparator, "."));
		
        return isNaN(value) ? '' : value;
    }
});


Ext.override(Ext.ux.HourField, {
  initEvents : function(){
        Ext.form.NumberField.superclass.initEvents.call(this);
        var allowed = "0123456789jd";
        if(this.allowDecimals){
            allowed += ".,";
            //allowed += this.decimalSeparator;
        }
        if(this.allowNegative){
            allowed += "-";
        }
        this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
        var keyPress = function(e){
            var k = e.getKey();
            if(!Ext.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
                return;
            }
            var c = e.getCharCode();
            if(allowed.indexOf(String.fromCharCode(c)) === -1){
                e.stopEvent();
            }
        };
        this.el.on("keypress", keyPress, this);
    },
    parseValue : function(value){
        var s = value.toString();
        value = value.toString().replace(",", ".");
        value = String(value).replace(this.decimalSeparator, ".");
        value = String(value).replace("j", "");
        value = String(value).replace("d", "");
        value = parseFloat(value);
        
        if (s.charAt(s.length -1) == "j" || s.charAt(s.length -1) == "d") {
            value = value * this.hoursPerDay;          
        }
    
        value = parseFloat(String(value).replace(this.decimalSeparator, "."));
        return isNaN(value) ? '' : value;
    }
});


Ext.ux.TimeField = function(config) {
    Ext.ux.TimeField.superclass.constructor.call(this, config);
};

Ext.extend(Ext.ux.TimeField, Ext.form.TextField, {
    startTime : '8:00',
    endTime : '17:00',
    timeFormat: 'H:m',
	validationEvent: false,
	listeners: {'blur': function() {
		this.validate();
	}}
}); // end of extend

Ext.override(Ext.ux.TimeField, {

    initEvents : function(){
        Ext.form.TextField.superclass.initEvents.call(this);
        if(this.validationEvent == 'keyup'){
            this.validationTask = new Ext.util.DelayedTask(this.validate, this);
            this.el.on('keyup', this.filterValidation, this);
        }
        else if(this.validationEvent !== false){
            this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
        }
        if(this.selectOnFocus || this.emptyText){
            this.on("focus", this.preFocus, this);
            if(this.emptyText){
                this.on('blur', this.postBlur, this);
                this.applyEmptyText();
            }
        }
        if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Ext.form.VTypes[this.vtype+'Mask']))){
            this.el.on("keypress", this.filterKeys, this);
        }
        if(this.grow){
            this.el.on("keyup", this.onKeyUp,  this, {buffer:50});
            this.el.on("click", this.autoSize,  this);
        }
        
        var allowed = "0123456789.,:";
        this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
        var keyPress = function(e){
            var k = e.getKey();
            if(!Ext.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
                return;
            }
            var c = e.getCharCode();
            if(allowed.indexOf(String.fromCharCode(c)) === -1){
                e.stopEvent();
            }
        };
        this.el.on("keypress", keyPress, this);
        
    },
    
    validateValue : function(value){    
        
        var s = value;
        s = String(s).replace(".", ":").replace(",", ":");
        if (s.indexOf(":") == -1 && s != "") {
            s += ":00"    
        }
      
        var a = s.split(":");
        if (a.length == 2) {
            if (a[1].toString().length == 1) {
                s += "0";
            } else if (a[1].toString().length == 0) {
                s += "00";
            }
        }
      
        value = s;
            
        if(value.length < 1 || value === this.emptyText){ // if it's blank
             if(this.allowBlank){
                 this.clearInvalid();
                 return true;
             }else{
                 this.markInvalid(this.blankText);
                 return false;
             }
        }
        if(value.length < this.minLength){
            this.markInvalid(String.format(this.minLengthText, this.minLength));
            return false;
        }
        if(value.length > this.maxLength){
            this.markInvalid(String.format(this.maxLengthText, this.maxLength));
            return false;
        }
        if(this.vtype){
            var vt = Ext.form.VTypes;
            if(!vt[this.vtype](value, this)){
                this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
                return false;
            }
        }
        if(typeof this.validator == "function"){
            var msg = this.validator(value);
            if(msg !== true){
                this.markInvalid(msg);
                return false;
            }
        }
        if(this.regex && !this.regex.test(value)){
            this.markInvalid(this.regexText);
            return false;
        }
        
        a = value.split(":");
        if (a.length == 2) {
            if (parseInt(a[0]) < 0 || parseInt(a[0]) > 23) {
                this.markInvalid('Invalid time, hours must be between 0 and 23');
                return false;
            }
            if (parseInt(a[1]) < 0 || parseInt(a[1]) > 59) {
                this.markInvalid('Invalid time, minutes must be between 0 and 59');
                return false;
            }
        }
        
        this.setRawValue(value);
        
        return true;
    }

});
Ext.override(Ext.form.TextField,
{
   selectText : function(start, end){
        var v = this.getRawValue();
        if(v.length > 0){
            start = start === undefined ? 0 : start;
            end = end === undefined ? v.length : end;
            var d = this.el.dom;
            if(d.setSelectionRange){
                d.setSelectionRange(start, end);
            }else if(d.createTextRange){
                var range = d.createTextRange();
                range.moveStart("character", start);
                range.moveEnd("character", end-v.length);
                range.select();
            }
			
			if(Ext.isGecko || Ext.isOpera){
				this.focus();
			}
        }
    }
}
);
Ext.override(Ext.form.DateField, {
  parseDate : function(value){
    //if user enters 0 returns current date (today), 
    //if user enters +7 returns current date + 7 days, 
    //if user enters -7 returns current date - 7 days
    var s = value.toString();
    if (s == "0") {
      value = new Date().clearTime();
    } else if (s.charAt(0) == "+" && s.length > 1) { 
      value = new Date().clearTime();
      value = value.add("d", parseInt(s.toString().substring(1))); 
    } else if (s.charAt(0) == "-" && s.length > 1) { 
      value = new Date().clearTime();
      value = value.add("d", parseInt(s.toString().substring(1)) * -1); 
    }
     
    if(!value || value instanceof Date){
      return value;
    }
    var v = Date.parseDate(value, this.format);
    if(!v && this.altFormats){
      if(!this.altFormatsArray){
        this.altFormatsArray = this.altFormats.split("|");
      }
      for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
        v = Date.parseDate(value, this.altFormatsArray[i]);
      }
    }
    return v;
  }
});

/****
 * Ext.ux.form.TranslationField

 */
Ext.namespace("Ext.ux.form");
Ext.ux.form.TranslationField = function(config) {
    Ext.ux.form.TranslationField.superclass.constructor.apply(this, arguments);        
};

Ext.extend(Ext.ux.form.TranslationField, Ext.form.ComboBox, {
    
    /***
     * trigger classes.
     */
	translationKey: '',
    trigger1Class: '',            
    trigger2Class: 'x-form-translate-trigger',
	tmpVal : null,
	tmpLng : null,
    /***
     * initComponent
     */
    initComponent : function(){
        Ext.ux.form.TranslationField.superclass.initComponent.call(this);
		
        /***
         * @event translate
         * @param {field: Ext.ux.form.TranslationField, button: Ext.Element}
         * fires when 2nd trigger is clicked
         */
        this.addEvents({translate : true});
		this.addEvents({change: true});
		this.tpl = new Ext.XTemplate(
				'<tpl for=".">',
					'<div class="language" style="padding-5px;font-weight:bold; /*\*/height: 35px;/**/ min-height: 35px; overflow: auto;">{text:this.getLanguage}<br/><span style="font-weight:normal;">{text:this.getValue}</span></div>',
				'</tpl>',
				{	
					parentCmb: this,
					
					getLanguage: function(val) {
						switch(arguments[1].Value) {
							case 'fr': 
								return 'Francais';	
								break;
							case 'en':
								return 'English';
								break;
							case 'es':
								return 'Espanol';
								break;
							default:
								return arguments[1].Value;
						}
						
					},
					getLanguageCode: function(lng) {
						switch(lng) {
							case 'Francais': 
								return 'fr';	
								break;
							case 'English':
								return 'en';
								break;
							case 'Espanol':
								return 'es';
								break;
							default:
								return lng;
						}
					},
					getValue: function(val) {
						if(this.parentCmb.tmpLng != null) {
							this.parentCmb.tmpLng = this.parentCmb.getValue().substr(0,2);
							this.parentCmb.tmpVal = this.parentCmb.getRawValue();
							this.parentCmb.languageValues.setValue(this.parentCmb.tmpLng, this.parentCmb.tmpVal);
						}
						//setting tmp values
						this.parentCmb.tmpVal = this.parentCmb.getRawValue();
						this.parentCmb.tmpLng = this.parentCmb.getValue().substr(0,2);
						//inserting value in cmb
						this.parentCmb.setRawValue(this.parentCmb.languageValues.getValue(this.parentCmb.tmpLng));
						val = this.parentCmb.languageValues.getValue(this.getLanguageCode(arguments[1].Value));
						return val;
						//return this.parentCmb;
					}
				}
			);
		//creating up the store
		var vdata = Array();
		var i = 0;
		for(x in this.languageValues) {
			if(x.length == 2) {
				vdata[i] = [x, ''];
				i++;
			}
		}
		
		
		
		
		this.triggerAction = 'all';
		this.typeAhead = false;
		this.forceSelection = false;
		this.disableKeyFilter = true;
		this.mode = 'local';
		this.displayField = 'Name'; 
		this.valueField = 'Value';
		this.store = new Ext.data.SimpleStore({
						fields: ['Value', 'Name'],
						data : vdata
					});
		this.itemSelector = 'div.language';
//        this.addEvents({blur: true});
        // implement triggerConfig from Ext.form.TwinTriggerField
        this.triggerConfig = {
            tag:'span', cls:'x-form-twin-triggers', cn:[
            {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
            {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
        ]};
		this.on('select', function() {
			this.tmpLng = this.getValue().substr(0,2);
			this.setRawValue(this.languageValues.getValue(this.tmpLng));
			this.setHiddenValue();
		});
		//	this.on('render', function getStore items... tableau object
		this.on('blur', function() { 
			this.tmpLng = this.getValue().substr(0,2);
			this.tmpVal = this.getRawValue();
			this.languageValues.setValue(this.tmpLng, this.tmpVal)
			this.setHiddenValue();
		});
		this.on('render', function() {
			this.setHiddenValue();
		});
		this.on('translate', function() {
			showTranslationDialog(this.translationKey, this.translationType, Ext.encode(this.languageValues));
		});
    },
	setHiddenValue : function() {
//		document.getElementById(this.hiddenName).value = Ext.encode({this.translationKey : this.languageValues});
		document.getElementById(this.hiddenName).value = Ext.encode({'translationkey': this.translationKey, 'values': this.languageValues});
	},
    
    /***
     * getTrigger
     * copied from Ext.form.TwinTriggerField
     * @param {Object} index
     */
    getTrigger : function(index){
        return this.triggers[index];
    },
	
	isEmpty : function() {
		for(x in this.languageValues) {
			if(x.length == 2) {
				if(this.languageValues.getValue(x) != "") {
					return false;
				}
			}
		}
		return true;
	},
    /***
     * initTrigger
     * copied from Ext.form.TwinTriggerField
     */
    initTrigger : function(){
        var ts = this.trigger.select('.x-form-trigger', true);
        this.wrap.setStyle('overflow', 'hidden');
        var triggerField = this;
        ts.each(function(t, all, index){
            t.hide = function(){
                var w = triggerField.wrap.getWidth();
                this.dom.style.display = 'none';
                triggerField.el.setWidth(w-triggerField.trigger.getWidth());
            };
            t.show = function(){
                var w = triggerField.wrap.getWidth();
                this.dom.style.display = '';
                triggerField.el.setWidth(w-triggerField.trigger.getWidth());
            };
            var triggerIndex = 'Trigger'+(index+1);

            if(this['hide'+triggerIndex]){
                t.dom.style.display = 'none';
            }
            t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
            t.addClassOnOver('x-form-trigger-over');
            t.addClassOnClick('x-form-trigger-click');
        }, this);
        this.triggers = ts.elements;
    },
    /***
     * onTrigger1Click
     * defer to std ComboBox trigger method
     */
    onTrigger1Click : function() {
		this.fireEvent('blur');
		this.setHiddenValue();
        this.onTriggerClick();    
    },
    /***
     * onTrigger2Click 
     * this is the "add" button handler.  fire 'add' event     
     */
	getValues : function (){
		return this.languageValues;
	},
    onTrigger2Click : function() {
		this.fireEvent('blur');
		showTranslationComboDialog(this.languageValues, this.translationType, this.updateValues, this);
		this.setHiddenValue();
        //this.fireEvent('translate', {field: this, button: this.triggers[1]});        
    },
	updateValues : function(pLanguageValues, scope) {
		//alert(pLanguageValues);
		pLanguageValues = Ext.decode(pLanguageValues);
		for(x in pLanguageValues) {
			scope.languageValues.setValue(x, eval('pLanguageValues.'+x));
		}
		scope.tmpLng = scope.getValue().substr(0,2);
		scope.setRawValue(scope.languageValues.getValue(scope.tmpLng));
		scope.tmpVal = scope.getRawValue();
		scope.setHiddenValue();
		
		//alert(Ext.encode(this.languageValues));
	},
    onChange : function() {
		this.fireEvents('change', {field: this});
	},
	/***
	 * insert
	 * provide a convenience method to insert ONE AND ONLY ONE record to the store.	 	 	 	 
	 * @param {Object} index
	 * @param {Object} data (
	 */
	insert : function(index, data) {
        this.reset();
        
        var rec = new this.store.recordType(data);                
        rec.id = rec.data.id; 
        this.store.insert(index, rec);
		this.setValue(rec.data.id);
		this.fireEvent('select', this, rec, index);        
	}
});
	 
	 
Ext.ux.MyDocumentGridEditor = function(config) {
 
    // call parent constructor
    Ext.ux.MyDocumentGridEditor.superclass.constructor.call(this, config);
 
} // end of Ext.ux.Toolbar constructor

Ext.extend(Ext.ux.MyDocumentGridEditor, Ext.form.TriggerField, {
   displayMode : 'image',
   windowWidth : 800,
   windowHeight : 600,
   onTriggerClick : function() {
		var w = screen.availWidth;
		var y = screen.availHeight;		
		var leftPos = (w - this.windowWidth)/2, topPos = (y - this.windowHeight)/2;
		window.open('/modules/mydocuments/index.php?mode=' + this.displayMode + '&templateid=0&act=link','selectpicture','width=' + this.windowWidth + ',height=' + this.windowHeight + ', top=' + topPos + ', left=' + leftPos);
	   
	}
}); // end of extend




Ext.ux.TranslationLabelEditor = function(config) {
    Ext.ux.TranslationLabelEditor.superclass.constructor.call(this, config);
}

Ext.ux.TranslationLabelEditor = Ext.extend(Ext.ux.TranslationLabelEditor, Ext.form.TriggerField, {
   translationKey: null,
   triggerClass:'x-form-translate-trigger',
   windowWidth : 800,
   windowHeight : 600,
   afterSave : Ext.emptyFn,/*function(trKey) {
	   this.setValue(trKey);
   },*/
   applicationId: null,
   onTriggerClick : function() {
	   if(this.applicationId != null && this.translationKey != null) {
		   window.top.Beezilla.Explorer.showDialog('/plugins/backoffice/modules/controlpanel/translation/edit.php?AppID='+this.applicationId+'&key=' + this.translationKey, 640, 480, 'Edit translation', this.afterSave);
	   }
   },
   setTranslationKey: function(tkey) {
	   this.translationKey = tkey;
   },
   setApplicationId: function(appid) {
	   this.applicationId = appid;
   }
}); // end of extend



Ext.ux.ErrorHandler = Ext.extend(Ext.util.Observable, (function() {
    var getStack = function(a, func) {
        if (func.caller) {
            getStack(a, func.caller);
        }
        var args = [];
        for (var x = 0; x < func.arguments.length; x++) {
            args[x] = func.arguments[x];
        }
        a.unshift({args: args, func: func});
    };
    return {
        /** @private */
        constructor: function() {
            Ext.ux.ErrorHandler.superclass.constructor.call(this);
            this.addEvents(
                /**
                 * Fires when an error has been handled.  This event is fired from the handleError method.
                 * @event error
                 * @param {Object} error An object containing the following:
                 * <ul>
                 *  <li>raw : <b>Object</b><p class="sub-desc">the original arguments passed to handleError</p></li>
                 *  <li>isError : <b>Boolean</b><p class="sub-desc">true, if the first argument is a JS Error object</p></li>
                 *  <li>isUnhandledException : <b>Boolean</b><p class="sub-desc">true, if the arguments match the signature of an unhandled exception <b><tt>(message, url, line)</tt></b></p></li>
                 *  <li>isImageLoadingError : <b>Boolean</b><p class="sub-desc">true, if IMG tag loading error</p></li>
                 *  <li>isScriptLoadingError : <b>Boolean</b><p class="sub-desc">true, if SCRIPT tag loading error <i>only supported by Firefox</i></p></li>
                 *  <li>name : <b>String</b><p class="sub-desc">name property of JS Error object</p></li>
                 *  <li>message : <b>String</b><p class="sub-desc">description of error</p></li>
                 *  <li>url : <b>String</b><p class="sub-desc">location of error</p></li>
                 *  <li>lineNumber : <b>Number</b><p class="sub-desc">location of error <i>(not reliable)</i></p></li>
                 *  <li>stack : <b>Array</b><p class="sub-desc">An array of objects containing a full stack trace (starting with the method that caused the exception)<br><b><tt>[{args: [], func: func}, ...]</tt></b></p></li>
                 * </ul>
                 */
                "error"
            );
        },
        /**
         * Sets up a handler for "unhandled" exceptions that bubble up to the browser's window object.
         * @return {void}
         */
        init: function () {
            // window.onerror is the browser's hook for unhandled exceptions (IE and Firefox only)
            // if another developer is already using window.onerror, let's be respectful
            window.onerror = !window.onerror ? Ext.ux.ErrorHandler.handleError : window.onerror.createSequence(Ext.ux.ErrorHandler.handleError);
            Ext.select("img").each(function(el, list, index) {
                el.on("error", Ext.ux.ErrorHandler.handleError);
            });
        },
        /**
         * This method handles all exception and fires the <b><tt>error</tt></b> event.
         * @param {Object...} args
         * @return {Boolean} Returns true, unless an event handler throws an exception (if this occurs, we allow the browser to handle these exceptions in a default manner)
         */
        handleError:  function () {
            // the arguments collection is not a true Array, so we'll make one
            var args = [];
            for (var x = 0; x < arguments.length; x++) {
                args[x] = arguments[x];
            }
            if (args.length > 0) {
                var ex = {
                    raw: null,
                    isError: false,
                    isUnhandledException: false,
                    isImageLoadingError: false,
                    isScriptLoadingError: false, // Firefox only
                    name: null,
                    message: null,
                    url: null, // Safari and Firefox only
                    lineNumber: null, // Safari and Firefox only
                    stack: null // Firefox and Opera only
                };
                ex.raw = args;
                ex.isError = args[0] instanceof Error; // Error object thrown in try...catch
                // Check the signature for a match with an unhandled exception
                ex.isUnhandledException = (args.length === 3) && (typeof args[2] === "number");
                ex.isImageLoadingError = !!args[0].browserEvent && args[1] && args[1].tagName == "IMG";
                if (ex.isError) {
                    var err = args[0];
                    ex.name = err.name || "Error"; // Safari is inconsistent
                    ex.message = err.message || err.type; // Chrome is inconsistent
                    ex.lineNumber = err.line || err.lineNumber; // Safari and Firefox
                    ex.url = err.sourceURL || err.fileName; // Safari and Firefox
                    ex.stack = err.stack || err.stacktrace; // Firefox and Opera
                } else if (ex.isUnhandledException) {
                    ex.name = "ERR_UNHANDLED";
                    ex.message = args[0];
                    ex.url = args[1];
                    ex.lineNumber = args[2];
                    if (ex.message == "Error loading script") {
                        ex.isScriptLoadingError = true;
                        ex.name = "ERR_LOAD_SCRIPT";
                    }
                } else if (ex.isImageLoadingError) {
                    ex.name = "ERR_LOAD_IMG";
                    ex.message = "Error loading image";
                    ex.url = args[1].src;
                }
                // rebuild the stack (ignore Firefox and Opera)
                //  arguments.callee               // the handleError method
                //  arguments.callee.caller        // delegate for handleError
                //  arguments.callee.caller.caller // the beginning of the stack
                if (arguments.callee && arguments.callee.caller && arguments.callee.caller.caller) {
                    var a = [];
                    getStack(a, arguments.callee.caller.caller);
                    ex.stack = a;
                }
                try {
                    this.fireEvent("error", ex);
                } catch (e) {
                    if (!ex.isUnhandledException) {
                        throw e;
                    }
                    // if the errorHandler is broken, let the user see the browser's error handler
                    return false;
                }
            }
            return true;
        }
    };
})());
// the following line makes this a singleton class
Ext.ux.ErrorHandler = new Ext.ux.ErrorHandler();
// the following line ensures that the handleError method always executes in the scope of ErrorHandler
Ext.ux.ErrorHandler.handleError = Ext.ux.ErrorHandler.handleError.createDelegate(Ext.ux.ErrorHandler);
Array.prototype.shuffle = function() {
	for(var j, x, i = this.length; i; j = parseInt(Math.random() * i), x = this[--i], this[i] = this[j], this[j] = x);
	return this;
}
Ext.ux.TwinTriggerCombo = Ext.extend(Ext.form.ComboBox, {
    initComponent: function() {
        this.triggerConfig = {
            tag:'span', cls:'x-form-twin-triggers', cn:[
            {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class},
            {tag: "img", src: Ext.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class}
        ]};
        this.onTrigger2Click = this.onTrigger2Click.createInterceptor(function() {
            this.collapse();
        });
        Ext.ux.TwinTriggerCombo.superclass.initComponent.call(this);
    },
    getTrigger: Ext.form.TwinTriggerField.prototype.getTrigger,
    initTrigger: Ext.form.TwinTriggerField.prototype.initTrigger,
    onTrigger2Click: Ext.form.ComboBox.prototype.onTriggerClick,
    trigger1Class: Ext.form.ComboBox.prototype.triggerClass
});