4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
78 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
81 * The id of the element associated with this object. This is what we
82 * refer to as the "linked element" because the size and position of
83 * this element is used to determine when the drag and drop objects have
91 * Configuration attributes passed into the constructor
98 * The id of the element that will be dragged. By default this is same
99 * as the linked element , but could be changed to another element. Ex:
108 * the id of the element that initiates the drag operation. By default
109 * this is the linked element, but could be changed to be a child of this
110 * element. This lets us do things like only starting the drag when the
111 * header element within the linked html element is clicked.
112 * @property handleElId
119 * An associative array of HTML tags that will be ignored if clicked.
120 * @property invalidHandleTypes
121 * @type {string: string}
123 invalidHandleTypes: null,
126 * An associative array of ids for elements that will be ignored if clicked
127 * @property invalidHandleIds
128 * @type {string: string}
130 invalidHandleIds: null,
133 * An indexted array of css class names for elements that will be ignored
135 * @property invalidHandleClasses
138 invalidHandleClasses: null,
141 * The linked element's absolute X position at the time the drag was
143 * @property startPageX
150 * The linked element's absolute X position at the time the drag was
152 * @property startPageY
159 * The group defines a logical collection of DragDrop objects that are
160 * related. Instances only get events when interacting with other
161 * DragDrop object in the same group. This lets us define multiple
162 * groups using a single DragDrop subclass if we want.
164 * @type {string: string}
169 * Individual drag/drop instances can be locked. This will prevent
170 * onmousedown start drag.
181 lock: function() { this.locked = true; },
184 * Unlock this instace
187 unlock: function() { this.locked = false; },
190 * By default, all insances can be a drop target. This can be disabled by
191 * setting isTarget to false.
198 * The padding configured for this drag and drop object for calculating
199 * the drop zone intersection with this object.
206 * Cached reference to the linked element
213 * Internal typeof flag
214 * @property __ygDragDrop
220 * Set to true when horizontal contraints are applied
221 * @property constrainX
228 * Set to true when vertical contraints are applied
229 * @property constrainY
236 * The left constraint
244 * The right constraint
261 * The down constraint
269 * Maintain offsets when we resetconstraints. Set to true when you want
270 * the position of the element relative to its parent to stay the same
271 * when the page changes
273 * @property maintainOffset
276 maintainOffset: false,
279 * Array of pixel locations the element will snap to if we specified a
280 * horizontal graduation/interval. This array is generated automatically
281 * when you define a tick interval.
288 * Array of pixel locations the element will snap to if we specified a
289 * vertical graduation/interval. This array is generated automatically
290 * when you define a tick interval.
297 * By default the drag and drop instance will only respond to the primary
298 * button click (left button for a right-handed mouse). Set to true to
299 * allow drag and drop to start with any mouse click that is propogated
301 * @property primaryButtonOnly
304 primaryButtonOnly: true,
307 * The availabe property is false until the linked dom element is accessible.
308 * @property available
314 * By default, drags can only be initiated if the mousedown occurs in the
315 * region the linked element is. This is done in part to work around a
316 * bug in some browsers that mis-report the mousedown if the previous
317 * mouseup happened outside of the window. This property is set to true
318 * if outer handles are defined.
320 * @property hasOuterHandles
324 hasOuterHandles: false,
327 * Code that executes immediately before the startDrag event
328 * @method b4StartDrag
331 b4StartDrag: function(x, y) { },
334 * Abstract method called after a drag/drop object is clicked
335 * and the drag or mousedown time thresholds have beeen met.
337 * @param {int} X click location
338 * @param {int} Y click location
340 startDrag: function(x, y) { /* override this */ },
343 * Code that executes immediately before the onDrag event
347 b4Drag: function(e) { },
350 * Abstract method called during the onMouseMove event while dragging an
353 * @param {Event} e the mousemove event
355 onDrag: function(e) { /* override this */ },
358 * Abstract method called when this element fist begins hovering over
359 * another DragDrop obj
360 * @method onDragEnter
361 * @param {Event} e the mousemove event
362 * @param {String|DragDrop[]} id In POINT mode, the element
363 * id this is hovering over. In INTERSECT mode, an array of one or more
364 * dragdrop items being hovered over.
366 onDragEnter: function(e, id) { /* override this */ },
369 * Code that executes immediately before the onDragOver event
373 b4DragOver: function(e) { },
376 * Abstract method called when this element is hovering over another
379 * @param {Event} e the mousemove event
380 * @param {String|DragDrop[]} id In POINT mode, the element
381 * id this is hovering over. In INTERSECT mode, an array of dd items
382 * being hovered over.
384 onDragOver: function(e, id) { /* override this */ },
387 * Code that executes immediately before the onDragOut event
391 b4DragOut: function(e) { },
394 * Abstract method called when we are no longer hovering over an element
396 * @param {Event} e the mousemove event
397 * @param {String|DragDrop[]} id In POINT mode, the element
398 * id this was hovering over. In INTERSECT mode, an array of dd items
399 * that the mouse is no longer over.
401 onDragOut: function(e, id) { /* override this */ },
404 * Code that executes immediately before the onDragDrop event
408 b4DragDrop: function(e) { },
411 * Abstract method called when this item is dropped on another DragDrop
414 * @param {Event} e the mouseup event
415 * @param {String|DragDrop[]} id In POINT mode, the element
416 * id this was dropped on. In INTERSECT mode, an array of dd items this
419 onDragDrop: function(e, id) { /* override this */ },
422 * Abstract method called when this item is dropped on an area with no
424 * @method onInvalidDrop
425 * @param {Event} e the mouseup event
427 onInvalidDrop: function(e) { /* override this */ },
430 * Code that executes immediately before the endDrag event
434 b4EndDrag: function(e) { },
437 * Fired when we are done dragging the object
439 * @param {Event} e the mouseup event
441 endDrag: function(e) { /* override this */ },
444 * Code executed immediately before the onMouseDown event
445 * @method b4MouseDown
446 * @param {Event} e the mousedown event
449 b4MouseDown: function(e) { },
452 * Event handler that fires when a drag/drop obj gets a mousedown
453 * @method onMouseDown
454 * @param {Event} e the mousedown event
456 onMouseDown: function(e) { /* override this */ },
459 * Event handler that fires when a drag/drop obj gets a mouseup
461 * @param {Event} e the mouseup event
463 onMouseUp: function(e) { /* override this */ },
466 * Override the onAvailable method to do what is needed after the initial
467 * position was determined.
468 * @method onAvailable
470 onAvailable: function () {
474 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
477 defaultPadding : {left:0, right:0, top:0, bottom:0},
480 * Initializes the drag drop object's constraints to restrict movement to a certain element.
484 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
485 { dragElId: "existingProxyDiv" });
486 dd.startDrag = function(){
487 this.constrainTo("parent-id");
490 * Or you can initalize it using the {@link Roo.Element} object:
492 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
493 startDrag : function(){
494 this.constrainTo("parent-id");
498 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
499 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
500 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
501 * an object containing the sides to pad. For example: {right:10, bottom:10}
502 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
504 constrainTo : function(constrainTo, pad, inContent){
505 if(typeof pad == "number"){
506 pad = {left: pad, right:pad, top:pad, bottom:pad};
508 pad = pad || this.defaultPadding;
509 var b = Roo.get(this.getEl()).getBox();
510 var ce = Roo.get(constrainTo);
511 var s = ce.getScroll();
513 if(cd == document.body){
514 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
517 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
521 var topSpace = b.y - c.y;
522 var leftSpace = b.x - c.x;
524 this.resetConstraints();
525 this.setXConstraint(leftSpace - (pad.left||0), // left
526 c.width - leftSpace - b.width - (pad.right||0) //right
528 this.setYConstraint(topSpace - (pad.top||0), //top
529 c.height - topSpace - b.height - (pad.bottom||0) //bottom
534 * Returns a reference to the linked element
536 * @return {HTMLElement} the html element
540 this._domRef = Roo.getDom(this.id);
547 * Returns a reference to the actual element to drag. By default this is
548 * the same as the html element, but it can be assigned to another
549 * element. An example of this can be found in Roo.dd.DDProxy
551 * @return {HTMLElement} the html element
553 getDragEl: function() {
554 return Roo.getDom(this.dragElId);
558 * Sets up the DragDrop object. Must be called in the constructor of any
559 * Roo.dd.DragDrop subclass
561 * @param id the id of the linked element
562 * @param {String} sGroup the group of related items
563 * @param {object} config configuration attributes
565 init: function(id, sGroup, config) {
566 this.initTarget(id, sGroup, config);
567 Event.on(this.id, "mousedown", this.handleMouseDown, this);
568 // Event.on(this.id, "selectstart", Event.preventDefault);
572 * Initializes Targeting functionality only... the object does not
573 * get a mousedown handler.
575 * @param id the id of the linked element
576 * @param {String} sGroup the group of related items
577 * @param {object} config configuration attributes
579 initTarget: function(id, sGroup, config) {
581 // configuration attributes
582 this.config = config || {};
584 // create a local reference to the drag and drop manager
585 this.DDM = Roo.dd.DDM;
586 // initialize the groups array
589 // assume that we have an element reference instead of an id if the
590 // parameter is not a string
591 if (typeof id !== "string") {
598 // add to an interaction group
599 this.addToGroup((sGroup) ? sGroup : "default");
601 // We don't want to register this as the handle with the manager
602 // so we just set the id rather than calling the setter.
603 this.handleElId = id;
605 // the linked element is the element that gets dragged by default
606 this.setDragElId(id);
608 // by default, clicked anchors will not start drag operations.
609 this.invalidHandleTypes = { A: "A" };
610 this.invalidHandleIds = {};
611 this.invalidHandleClasses = [];
615 this.handleOnAvailable();
619 * Applies the configuration parameters that were passed into the constructor.
620 * This is supposed to happen at each level through the inheritance chain. So
621 * a DDProxy implentation will execute apply config on DDProxy, DD, and
622 * DragDrop in order to get all of the parameters that are available in
624 * @method applyConfig
626 applyConfig: function() {
628 // configurable properties:
629 // padding, isTarget, maintainOffset, primaryButtonOnly
630 this.padding = this.config.padding || [0, 0, 0, 0];
631 this.isTarget = (this.config.isTarget !== false);
632 this.maintainOffset = (this.config.maintainOffset);
633 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
638 * Executed when the linked element is available
639 * @method handleOnAvailable
642 handleOnAvailable: function() {
643 this.available = true;
644 this.resetConstraints();
649 * Configures the padding for the target zone in px. Effectively expands
650 * (or reduces) the virtual object size for targeting calculations.
651 * Supports css-style shorthand; if only one parameter is passed, all sides
652 * will have that padding, and if only two are passed, the top and bottom
653 * will have the first param, the left and right the second.
655 * @param {int} iTop Top pad
656 * @param {int} iRight Right pad
657 * @param {int} iBot Bot pad
658 * @param {int} iLeft Left pad
660 setPadding: function(iTop, iRight, iBot, iLeft) {
661 // this.padding = [iLeft, iRight, iTop, iBot];
662 if (!iRight && 0 !== iRight) {
663 this.padding = [iTop, iTop, iTop, iTop];
664 } else if (!iBot && 0 !== iBot) {
665 this.padding = [iTop, iRight, iTop, iRight];
667 this.padding = [iTop, iRight, iBot, iLeft];
672 * Stores the initial placement of the linked element.
673 * @method setInitialPosition
674 * @param {int} diffX the X offset, default 0
675 * @param {int} diffY the Y offset, default 0
677 setInitPosition: function(diffX, diffY) {
678 var el = this.getEl();
680 if (!this.DDM.verifyEl(el)) {
687 var p = Dom.getXY( el );
689 this.initPageX = p[0] - dx;
690 this.initPageY = p[1] - dy;
692 this.lastPageX = p[0];
693 this.lastPageY = p[1];
696 this.setStartPosition(p);
700 * Sets the start position of the element. This is set when the obj
701 * is initialized, the reset when a drag is started.
702 * @method setStartPosition
703 * @param pos current position (from previous lookup)
706 setStartPosition: function(pos) {
707 var p = pos || Dom.getXY( this.getEl() );
708 this.deltaSetXY = null;
710 this.startPageX = p[0];
711 this.startPageY = p[1];
715 * Add this instance to a group of related drag/drop objects. All
716 * instances belong to at least one group, and can belong to as many
719 * @param sGroup {string} the name of the group
721 addToGroup: function(sGroup) {
722 this.groups[sGroup] = true;
723 this.DDM.regDragDrop(this, sGroup);
727 * Remove's this instance from the supplied interaction group
728 * @method removeFromGroup
729 * @param {string} sGroup The group to drop
731 removeFromGroup: function(sGroup) {
732 if (this.groups[sGroup]) {
733 delete this.groups[sGroup];
736 this.DDM.removeDDFromGroup(this, sGroup);
740 * Allows you to specify that an element other than the linked element
741 * will be moved with the cursor during a drag
742 * @method setDragElId
743 * @param id {string} the id of the element that will be used to initiate the drag
745 setDragElId: function(id) {
750 * Allows you to specify a child of the linked element that should be
751 * used to initiate the drag operation. An example of this would be if
752 * you have a content div with text and links. Clicking anywhere in the
753 * content area would normally start the drag operation. Use this method
754 * to specify that an element inside of the content div is the element
755 * that starts the drag operation.
756 * @method setHandleElId
757 * @param id {string} the id of the element that will be used to
760 setHandleElId: function(id) {
761 if (typeof id !== "string") {
764 this.handleElId = id;
765 this.DDM.regHandle(this.id, id);
769 * Allows you to set an element outside of the linked element as a drag
771 * @method setOuterHandleElId
772 * @param id the id of the element that will be used to initiate the drag
774 setOuterHandleElId: function(id) {
775 if (typeof id !== "string") {
778 Event.on(id, "mousedown",
779 this.handleMouseDown, this);
780 this.setHandleElId(id);
782 this.hasOuterHandles = true;
786 * Remove all drag and drop hooks for this element
790 Event.un(this.id, "mousedown",
791 this.handleMouseDown);
793 this.DDM._remove(this);
796 destroy : function(){
801 * Returns true if this instance is locked, or the drag drop mgr is locked
802 * (meaning that all drag/drop is disabled on the page.)
804 * @return {boolean} true if this obj or all drag/drop is locked, else
807 isLocked: function() {
808 return (this.DDM.isLocked() || this.locked);
812 * Fired when this object is clicked
813 * @method handleMouseDown
815 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
818 handleMouseDown: function(e, oDD){
819 if (this.primaryButtonOnly && e.button != 0) {
823 if (this.isLocked()) {
827 this.DDM.refreshCache(this.groups);
829 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
830 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
832 if (this.clickValidator(e)) {
834 // set the initial element position
835 this.setStartPosition();
841 this.DDM.handleMouseDown(e, this);
843 this.DDM.stopEvent(e);
851 clickValidator: function(e) {
852 var target = e.getTarget();
853 return ( this.isValidHandleChild(target) &&
854 (this.id == this.handleElId ||
855 this.DDM.handleWasClicked(target, this.id)) );
859 * Allows you to specify a tag name that should not start a drag operation
860 * when clicked. This is designed to facilitate embedding links within a
861 * drag handle that do something other than start the drag.
862 * @method addInvalidHandleType
863 * @param {string} tagName the type of element to exclude
865 addInvalidHandleType: function(tagName) {
866 var type = tagName.toUpperCase();
867 this.invalidHandleTypes[type] = type;
871 * Lets you to specify an element id for a child of a drag handle
872 * that should not initiate a drag
873 * @method addInvalidHandleId
874 * @param {string} id the element id of the element you wish to ignore
876 addInvalidHandleId: function(id) {
877 if (typeof id !== "string") {
880 this.invalidHandleIds[id] = id;
884 * Lets you specify a css class of elements that will not initiate a drag
885 * @method addInvalidHandleClass
886 * @param {string} cssClass the class of the elements you wish to ignore
888 addInvalidHandleClass: function(cssClass) {
889 this.invalidHandleClasses.push(cssClass);
893 * Unsets an excluded tag name set by addInvalidHandleType
894 * @method removeInvalidHandleType
895 * @param {string} tagName the type of element to unexclude
897 removeInvalidHandleType: function(tagName) {
898 var type = tagName.toUpperCase();
899 // this.invalidHandleTypes[type] = null;
900 delete this.invalidHandleTypes[type];
904 * Unsets an invalid handle id
905 * @method removeInvalidHandleId
906 * @param {string} id the id of the element to re-enable
908 removeInvalidHandleId: function(id) {
909 if (typeof id !== "string") {
912 delete this.invalidHandleIds[id];
916 * Unsets an invalid css class
917 * @method removeInvalidHandleClass
918 * @param {string} cssClass the class of the element(s) you wish to
921 removeInvalidHandleClass: function(cssClass) {
922 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
923 if (this.invalidHandleClasses[i] == cssClass) {
924 delete this.invalidHandleClasses[i];
930 * Checks the tag exclusion list to see if this click should be ignored
931 * @method isValidHandleChild
932 * @param {HTMLElement} node the HTMLElement to evaluate
933 * @return {boolean} true if this is a valid tag type, false if not
935 isValidHandleChild: function(node) {
938 // var n = (node.nodeName == "#text") ? node.parentNode : node;
941 nodeName = node.nodeName.toUpperCase();
943 nodeName = node.nodeName;
945 valid = valid && !this.invalidHandleTypes[nodeName];
946 valid = valid && !this.invalidHandleIds[node.id];
948 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
949 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
958 * Create the array of horizontal tick marks if an interval was specified
959 * in setXConstraint().
963 setXTicks: function(iStartX, iTickSize) {
965 this.xTickSize = iTickSize;
969 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
971 this.xTicks[this.xTicks.length] = i;
976 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
978 this.xTicks[this.xTicks.length] = i;
983 this.xTicks.sort(this.DDM.numericSort) ;
987 * Create the array of vertical tick marks if an interval was specified in
992 setYTicks: function(iStartY, iTickSize) {
994 this.yTickSize = iTickSize;
998 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1000 this.yTicks[this.yTicks.length] = i;
1005 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1007 this.yTicks[this.yTicks.length] = i;
1012 this.yTicks.sort(this.DDM.numericSort) ;
1016 * By default, the element can be dragged any place on the screen. Use
1017 * this method to limit the horizontal travel of the element. Pass in
1018 * 0,0 for the parameters if you want to lock the drag to the y axis.
1019 * @method setXConstraint
1020 * @param {int} iLeft the number of pixels the element can move to the left
1021 * @param {int} iRight the number of pixels the element can move to the
1023 * @param {int} iTickSize optional parameter for specifying that the
1025 * should move iTickSize pixels at a time.
1027 setXConstraint: function(iLeft, iRight, iTickSize) {
1028 this.leftConstraint = iLeft;
1029 this.rightConstraint = iRight;
1031 this.minX = this.initPageX - iLeft;
1032 this.maxX = this.initPageX + iRight;
1033 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1035 this.constrainX = true;
1039 * Clears any constraints applied to this instance. Also clears ticks
1040 * since they can't exist independent of a constraint at this time.
1041 * @method clearConstraints
1043 clearConstraints: function() {
1044 this.constrainX = false;
1045 this.constrainY = false;
1050 * Clears any tick interval defined for this instance
1051 * @method clearTicks
1053 clearTicks: function() {
1061 * By default, the element can be dragged any place on the screen. Set
1062 * this to limit the vertical travel of the element. Pass in 0,0 for the
1063 * parameters if you want to lock the drag to the x axis.
1064 * @method setYConstraint
1065 * @param {int} iUp the number of pixels the element can move up
1066 * @param {int} iDown the number of pixels the element can move down
1067 * @param {int} iTickSize optional parameter for specifying that the
1068 * element should move iTickSize pixels at a time.
1070 setYConstraint: function(iUp, iDown, iTickSize) {
1071 this.topConstraint = iUp;
1072 this.bottomConstraint = iDown;
1074 this.minY = this.initPageY - iUp;
1075 this.maxY = this.initPageY + iDown;
1076 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1078 this.constrainY = true;
1083 * resetConstraints must be called if you manually reposition a dd element.
1084 * @method resetConstraints
1085 * @param {boolean} maintainOffset
1087 resetConstraints: function() {
1090 // Maintain offsets if necessary
1091 if (this.initPageX || this.initPageX === 0) {
1092 // figure out how much this thing has moved
1093 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1094 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1096 this.setInitPosition(dx, dy);
1098 // This is the first time we have detected the element's position
1100 this.setInitPosition();
1103 if (this.constrainX) {
1104 this.setXConstraint( this.leftConstraint,
1105 this.rightConstraint,
1109 if (this.constrainY) {
1110 this.setYConstraint( this.topConstraint,
1111 this.bottomConstraint,
1117 * Normally the drag element is moved pixel by pixel, but we can specify
1118 * that it move a number of pixels at a time. This method resolves the
1119 * location when we have it set up like this.
1121 * @param {int} val where we want to place the object
1122 * @param {int[]} tickArray sorted array of valid points
1123 * @return {int} the closest tick
1126 getTick: function(val, tickArray) {
1129 // If tick interval is not defined, it is effectively 1 pixel,
1130 // so we return the value passed to us.
1132 } else if (tickArray[0] >= val) {
1133 // The value is lower than the first tick, so we return the first
1135 return tickArray[0];
1137 for (var i=0, len=tickArray.length; i<len; ++i) {
1139 if (tickArray[next] && tickArray[next] >= val) {
1140 var diff1 = val - tickArray[i];
1141 var diff2 = tickArray[next] - val;
1142 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1146 // The value is larger than the last tick, so we return the last
1148 return tickArray[tickArray.length - 1];
1155 * @return {string} string representation of the dd obj
1157 toString: function() {
1158 return ("DragDrop " + this.id);
1166 * Ext JS Library 1.1.1
1167 * Copyright(c) 2006-2007, Ext JS, LLC.
1169 * Originally Released Under LGPL - original licence link has changed is not relivant.
1172 * <script type="text/javascript">
1177 * The drag and drop utility provides a framework for building drag and drop
1178 * applications. In addition to enabling drag and drop for specific elements,
1179 * the drag and drop elements are tracked by the manager class, and the
1180 * interactions between the various elements are tracked during the drag and
1181 * the implementing code is notified about these important moments.
1184 // Only load the library once. Rewriting the manager class would orphan
1185 // existing drag and drop instances.
1186 if (!Roo.dd.DragDropMgr) {
1189 * @class Roo.dd.DragDropMgr
1190 * DragDropMgr is a singleton that tracks the element interaction for
1191 * all DragDrop items in the window. Generally, you will not call
1192 * this class directly, but it does have helper methods that could
1193 * be useful in your DragDrop implementations.
1196 Roo.dd.DragDropMgr = function() {
1198 var Event = Roo.EventManager;
1203 * Two dimensional Array of registered DragDrop objects. The first
1204 * dimension is the DragDrop item group, the second the DragDrop
1207 * @type {string: string}
1214 * Array of element ids defined as drag handles. Used to determine
1215 * if the element that generated the mousedown event is actually the
1216 * handle and not the html element itself.
1217 * @property handleIds
1218 * @type {string: string}
1225 * the DragDrop object that is currently being dragged
1226 * @property dragCurrent
1234 * the DragDrop object(s) that are being hovered over
1235 * @property dragOvers
1243 * the X distance between the cursor and the object being dragged
1252 * the Y distance between the cursor and the object being dragged
1261 * Flag to determine if we should prevent the default behavior of the
1262 * events we define. By default this is true, but this can be set to
1263 * false if you need the default behavior (not recommended)
1264 * @property preventDefault
1268 preventDefault: true,
1271 * Flag to determine if we should stop the propagation of the events
1272 * we generate. This is true by default but you may want to set it to
1273 * false if the html element contains other features that require the
1275 * @property stopPropagation
1279 stopPropagation: true,
1282 * Internal flag that is set to true when drag and drop has been
1284 * @property initialized
1291 * All drag and drop can be disabled.
1299 * Called the first time an element is registered.
1305 this.initialized = true;
1309 * In point mode, drag and drop interaction is defined by the
1310 * location of the cursor during the drag/drop
1318 * In intersect mode, drag and drop interactio nis defined by the
1319 * overlap of two or more drag and drop objects.
1320 * @property INTERSECT
1327 * The current drag and drop mode. Default: POINT
1335 * Runs method on all drag and drop objects
1336 * @method _execOnAll
1340 _execOnAll: function(sMethod, args) {
1341 for (var i in this.ids) {
1342 for (var j in this.ids[i]) {
1343 var oDD = this.ids[i][j];
1344 if (! this.isTypeOfDD(oDD)) {
1347 oDD[sMethod].apply(oDD, args);
1353 * Drag and drop initialization. Sets up the global event handlers
1358 _onLoad: function() {
1363 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1364 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1365 Event.on(window, "unload", this._onUnload, this, true);
1366 Event.on(window, "resize", this._onResize, this, true);
1367 // Event.on(window, "mouseout", this._test);
1372 * Reset constraints on all drag and drop objs
1377 _onResize: function(e) {
1378 this._execOnAll("resetConstraints", []);
1382 * Lock all drag and drop functionality
1386 lock: function() { this.locked = true; },
1389 * Unlock all drag and drop functionality
1393 unlock: function() { this.locked = false; },
1396 * Is drag and drop locked?
1398 * @return {boolean} True if drag and drop is locked, false otherwise.
1401 isLocked: function() { return this.locked; },
1404 * Location cache that is set for all drag drop objects when a drag is
1405 * initiated, cleared when the drag is finished.
1406 * @property locationCache
1413 * Set useCache to false if you want to force object the lookup of each
1414 * drag and drop linked element constantly during a drag.
1415 * @property useCache
1422 * The number of pixels that the mouse needs to move after the
1423 * mousedown before the drag is initiated. Default=3;
1424 * @property clickPixelThresh
1428 clickPixelThresh: 3,
1431 * The number of milliseconds after the mousedown event to initiate the
1432 * drag if we don't get a mouseup event. Default=1000
1433 * @property clickTimeThresh
1437 clickTimeThresh: 350,
1440 * Flag that indicates that either the drag pixel threshold or the
1441 * mousdown time threshold has been met
1442 * @property dragThreshMet
1447 dragThreshMet: false,
1450 * Timeout used for the click time threshold
1451 * @property clickTimeout
1459 * The X position of the mousedown event stored for later use when a
1460 * drag threshold is met.
1469 * The Y position of the mousedown event stored for later use when a
1470 * drag threshold is met.
1479 * Each DragDrop instance must be registered with the DragDropMgr.
1480 * This is executed in DragDrop.init()
1481 * @method regDragDrop
1482 * @param {DragDrop} oDD the DragDrop object to register
1483 * @param {String} sGroup the name of the group this element belongs to
1486 regDragDrop: function(oDD, sGroup) {
1487 if (!this.initialized) { this.init(); }
1489 if (!this.ids[sGroup]) {
1490 this.ids[sGroup] = {};
1492 this.ids[sGroup][oDD.id] = oDD;
1496 * Removes the supplied dd instance from the supplied group. Executed
1497 * by DragDrop.removeFromGroup, so don't call this function directly.
1498 * @method removeDDFromGroup
1502 removeDDFromGroup: function(oDD, sGroup) {
1503 if (!this.ids[sGroup]) {
1504 this.ids[sGroup] = {};
1507 var obj = this.ids[sGroup];
1508 if (obj && obj[oDD.id]) {
1514 * Unregisters a drag and drop item. This is executed in
1515 * DragDrop.unreg, use that method instead of calling this directly.
1520 _remove: function(oDD) {
1521 for (var g in oDD.groups) {
1522 if (g && this.ids[g][oDD.id]) {
1523 delete this.ids[g][oDD.id];
1526 delete this.handleIds[oDD.id];
1530 * Each DragDrop handle element must be registered. This is done
1531 * automatically when executing DragDrop.setHandleElId()
1533 * @param {String} sDDId the DragDrop id this element is a handle for
1534 * @param {String} sHandleId the id of the element that is the drag
1538 regHandle: function(sDDId, sHandleId) {
1539 if (!this.handleIds[sDDId]) {
1540 this.handleIds[sDDId] = {};
1542 this.handleIds[sDDId][sHandleId] = sHandleId;
1546 * Utility function to determine if a given element has been
1547 * registered as a drag drop item.
1548 * @method isDragDrop
1549 * @param {String} id the element id to check
1550 * @return {boolean} true if this element is a DragDrop item,
1554 isDragDrop: function(id) {
1555 return ( this.getDDById(id) ) ? true : false;
1559 * Returns the drag and drop instances that are in all groups the
1560 * passed in instance belongs to.
1561 * @method getRelated
1562 * @param {DragDrop} p_oDD the obj to get related data for
1563 * @param {boolean} bTargetsOnly if true, only return targetable objs
1564 * @return {DragDrop[]} the related instances
1567 getRelated: function(p_oDD, bTargetsOnly) {
1569 for (var i in p_oDD.groups) {
1570 for (j in this.ids[i]) {
1571 var dd = this.ids[i][j];
1572 if (! this.isTypeOfDD(dd)) {
1575 if (!bTargetsOnly || dd.isTarget) {
1576 oDDs[oDDs.length] = dd;
1585 * Returns true if the specified dd target is a legal target for
1586 * the specifice drag obj
1587 * @method isLegalTarget
1588 * @param {DragDrop} the drag obj
1589 * @param {DragDrop} the target
1590 * @return {boolean} true if the target is a legal target for the
1594 isLegalTarget: function (oDD, oTargetDD) {
1595 var targets = this.getRelated(oDD, true);
1596 for (var i=0, len=targets.length;i<len;++i) {
1597 if (targets[i].id == oTargetDD.id) {
1606 * My goal is to be able to transparently determine if an object is
1607 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1608 * returns "object", oDD.constructor.toString() always returns
1609 * "DragDrop" and not the name of the subclass. So for now it just
1610 * evaluates a well-known variable in DragDrop.
1611 * @method isTypeOfDD
1612 * @param {Object} the object to evaluate
1613 * @return {boolean} true if typeof oDD = DragDrop
1616 isTypeOfDD: function (oDD) {
1617 return (oDD && oDD.__ygDragDrop);
1621 * Utility function to determine if a given element has been
1622 * registered as a drag drop handle for the given Drag Drop object.
1624 * @param {String} id the element id to check
1625 * @return {boolean} true if this element is a DragDrop handle, false
1629 isHandle: function(sDDId, sHandleId) {
1630 return ( this.handleIds[sDDId] &&
1631 this.handleIds[sDDId][sHandleId] );
1635 * Returns the DragDrop instance for a given id
1637 * @param {String} id the id of the DragDrop object
1638 * @return {DragDrop} the drag drop object, null if it is not found
1641 getDDById: function(id) {
1642 for (var i in this.ids) {
1643 if (this.ids[i][id]) {
1644 return this.ids[i][id];
1651 * Fired after a registered DragDrop object gets the mousedown event.
1652 * Sets up the events required to track the object being dragged
1653 * @method handleMouseDown
1654 * @param {Event} e the event
1655 * @param oDD the DragDrop object being dragged
1659 handleMouseDown: function(e, oDD) {
1661 Roo.QuickTips.disable();
1663 this.currentTarget = e.getTarget();
1665 this.dragCurrent = oDD;
1667 var el = oDD.getEl();
1669 // track start position
1670 this.startX = e.getPageX();
1671 this.startY = e.getPageY();
1673 this.deltaX = this.startX - el.offsetLeft;
1674 this.deltaY = this.startY - el.offsetTop;
1676 this.dragThreshMet = false;
1678 this.clickTimeout = setTimeout(
1680 var DDM = Roo.dd.DDM;
1681 DDM.startDrag(DDM.startX, DDM.startY);
1683 this.clickTimeThresh );
1687 * Fired when either the drag pixel threshol or the mousedown hold
1688 * time threshold has been met.
1690 * @param x {int} the X position of the original mousedown
1691 * @param y {int} the Y position of the original mousedown
1694 startDrag: function(x, y) {
1695 clearTimeout(this.clickTimeout);
1696 if (this.dragCurrent) {
1697 this.dragCurrent.b4StartDrag(x, y);
1698 this.dragCurrent.startDrag(x, y);
1700 this.dragThreshMet = true;
1704 * Internal function to handle the mouseup event. Will be invoked
1705 * from the context of the document.
1706 * @method handleMouseUp
1707 * @param {Event} e the event
1711 handleMouseUp: function(e) {
1714 Roo.QuickTips.enable();
1716 if (! this.dragCurrent) {
1720 clearTimeout(this.clickTimeout);
1722 if (this.dragThreshMet) {
1723 this.fireEvents(e, true);
1733 * Utility to stop event propagation and event default, if these
1734 * features are turned on.
1736 * @param {Event} e the event as returned by this.getEvent()
1739 stopEvent: function(e){
1740 if(this.stopPropagation) {
1741 e.stopPropagation();
1744 if (this.preventDefault) {
1750 * Internal function to clean up event handlers after the drag
1751 * operation is complete
1753 * @param {Event} e the event
1757 stopDrag: function(e) {
1758 // Fire the drag end event for the item that was dragged
1759 if (this.dragCurrent) {
1760 if (this.dragThreshMet) {
1761 this.dragCurrent.b4EndDrag(e);
1762 this.dragCurrent.endDrag(e);
1765 this.dragCurrent.onMouseUp(e);
1768 this.dragCurrent = null;
1769 this.dragOvers = {};
1773 * Internal function to handle the mousemove event. Will be invoked
1774 * from the context of the html element.
1776 * @TODO figure out what we can do about mouse events lost when the
1777 * user drags objects beyond the window boundary. Currently we can
1778 * detect this in internet explorer by verifying that the mouse is
1779 * down during the mousemove event. Firefox doesn't give us the
1780 * button state on the mousemove event.
1781 * @method handleMouseMove
1782 * @param {Event} e the event
1786 handleMouseMove: function(e) {
1787 if (! this.dragCurrent) {
1791 // var button = e.which || e.button;
1793 // check for IE mouseup outside of page boundary
1794 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1796 return this.handleMouseUp(e);
1799 if (!this.dragThreshMet) {
1800 var diffX = Math.abs(this.startX - e.getPageX());
1801 var diffY = Math.abs(this.startY - e.getPageY());
1802 if (diffX > this.clickPixelThresh ||
1803 diffY > this.clickPixelThresh) {
1804 this.startDrag(this.startX, this.startY);
1808 if (this.dragThreshMet) {
1809 this.dragCurrent.b4Drag(e);
1810 this.dragCurrent.onDrag(e);
1811 if(!this.dragCurrent.moveOnly){
1812 this.fireEvents(e, false);
1822 * Iterates over all of the DragDrop elements to find ones we are
1823 * hovering over or dropping on
1824 * @method fireEvents
1825 * @param {Event} e the event
1826 * @param {boolean} isDrop is this a drop op or a mouseover op?
1830 fireEvents: function(e, isDrop) {
1831 var dc = this.dragCurrent;
1833 // If the user did the mouse up outside of the window, we could
1834 // get here even though we have ended the drag.
1835 if (!dc || dc.isLocked()) {
1839 var pt = e.getPoint();
1841 // cache the previous dragOver array
1849 // Check to see if the object(s) we were hovering over is no longer
1850 // being hovered over so we can fire the onDragOut event
1851 for (var i in this.dragOvers) {
1853 var ddo = this.dragOvers[i];
1855 if (! this.isTypeOfDD(ddo)) {
1859 if (! this.isOverTarget(pt, ddo, this.mode)) {
1860 outEvts.push( ddo );
1864 delete this.dragOvers[i];
1867 for (var sGroup in dc.groups) {
1869 if ("string" != typeof sGroup) {
1873 for (i in this.ids[sGroup]) {
1874 var oDD = this.ids[sGroup][i];
1875 if (! this.isTypeOfDD(oDD)) {
1879 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1880 if (this.isOverTarget(pt, oDD, this.mode)) {
1881 // look for drop interactions
1883 dropEvts.push( oDD );
1884 // look for drag enter and drag over interactions
1887 // initial drag over: dragEnter fires
1888 if (!oldOvers[oDD.id]) {
1889 enterEvts.push( oDD );
1890 // subsequent drag overs: dragOver fires
1892 overEvts.push( oDD );
1895 this.dragOvers[oDD.id] = oDD;
1903 if (outEvts.length) {
1904 dc.b4DragOut(e, outEvts);
1905 dc.onDragOut(e, outEvts);
1908 if (enterEvts.length) {
1909 dc.onDragEnter(e, enterEvts);
1912 if (overEvts.length) {
1913 dc.b4DragOver(e, overEvts);
1914 dc.onDragOver(e, overEvts);
1917 if (dropEvts.length) {
1918 dc.b4DragDrop(e, dropEvts);
1919 dc.onDragDrop(e, dropEvts);
1923 // fire dragout events
1925 for (i=0, len=outEvts.length; i<len; ++i) {
1926 dc.b4DragOut(e, outEvts[i].id);
1927 dc.onDragOut(e, outEvts[i].id);
1930 // fire enter events
1931 for (i=0,len=enterEvts.length; i<len; ++i) {
1932 // dc.b4DragEnter(e, oDD.id);
1933 dc.onDragEnter(e, enterEvts[i].id);
1937 for (i=0,len=overEvts.length; i<len; ++i) {
1938 dc.b4DragOver(e, overEvts[i].id);
1939 dc.onDragOver(e, overEvts[i].id);
1943 for (i=0, len=dropEvts.length; i<len; ++i) {
1944 dc.b4DragDrop(e, dropEvts[i].id);
1945 dc.onDragDrop(e, dropEvts[i].id);
1950 // notify about a drop that did not find a target
1951 if (isDrop && !dropEvts.length) {
1952 dc.onInvalidDrop(e);
1958 * Helper function for getting the best match from the list of drag
1959 * and drop objects returned by the drag and drop events when we are
1960 * in INTERSECT mode. It returns either the first object that the
1961 * cursor is over, or the object that has the greatest overlap with
1962 * the dragged element.
1963 * @method getBestMatch
1964 * @param {DragDrop[]} dds The array of drag and drop objects
1966 * @return {DragDrop} The best single match
1969 getBestMatch: function(dds) {
1971 // Return null if the input is not what we expect
1972 //if (!dds || !dds.length || dds.length == 0) {
1974 // If there is only one item, it wins
1975 //} else if (dds.length == 1) {
1977 var len = dds.length;
1982 // Loop through the targeted items
1983 for (var i=0; i<len; ++i) {
1985 // If the cursor is over the object, it wins. If the
1986 // cursor is over multiple matches, the first one we come
1988 if (dd.cursorIsOver) {
1991 // Otherwise the object with the most overlap wins
1994 winner.overlap.getArea() < dd.overlap.getArea()) {
2005 * Refreshes the cache of the top-left and bottom-right points of the
2006 * drag and drop objects in the specified group(s). This is in the
2007 * format that is stored in the drag and drop instance, so typical
2010 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2014 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2016 * @TODO this really should be an indexed array. Alternatively this
2017 * method could accept both.
2018 * @method refreshCache
2019 * @param {Object} groups an associative array of groups to refresh
2022 refreshCache: function(groups) {
2023 for (var sGroup in groups) {
2024 if ("string" != typeof sGroup) {
2027 for (var i in this.ids[sGroup]) {
2028 var oDD = this.ids[sGroup][i];
2030 if (this.isTypeOfDD(oDD)) {
2031 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2032 var loc = this.getLocation(oDD);
2034 this.locationCache[oDD.id] = loc;
2036 delete this.locationCache[oDD.id];
2037 // this will unregister the drag and drop object if
2038 // the element is not in a usable state
2047 * This checks to make sure an element exists and is in the DOM. The
2048 * main purpose is to handle cases where innerHTML is used to remove
2049 * drag and drop objects from the DOM. IE provides an 'unspecified
2050 * error' when trying to access the offsetParent of such an element
2052 * @param {HTMLElement} el the element to check
2053 * @return {boolean} true if the element looks usable
2056 verifyEl: function(el) {
2061 parent = el.offsetParent;
2064 parent = el.offsetParent;
2075 * Returns a Region object containing the drag and drop element's position
2076 * and size, including the padding configured for it
2077 * @method getLocation
2078 * @param {DragDrop} oDD the drag and drop object to get the
2080 * @return {Roo.lib.Region} a Region object representing the total area
2081 * the element occupies, including any padding
2082 * the instance is configured for.
2085 getLocation: function(oDD) {
2086 if (! this.isTypeOfDD(oDD)) {
2090 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2093 pos= Roo.lib.Dom.getXY(el);
2101 x2 = x1 + el.offsetWidth;
2103 y2 = y1 + el.offsetHeight;
2105 t = y1 - oDD.padding[0];
2106 r = x2 + oDD.padding[1];
2107 b = y2 + oDD.padding[2];
2108 l = x1 - oDD.padding[3];
2110 return new Roo.lib.Region( t, r, b, l );
2114 * Checks the cursor location to see if it over the target
2115 * @method isOverTarget
2116 * @param {Roo.lib.Point} pt The point to evaluate
2117 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2118 * @return {boolean} true if the mouse is over the target
2122 isOverTarget: function(pt, oTarget, intersect) {
2123 // use cache if available
2124 var loc = this.locationCache[oTarget.id];
2125 if (!loc || !this.useCache) {
2126 loc = this.getLocation(oTarget);
2127 this.locationCache[oTarget.id] = loc;
2135 oTarget.cursorIsOver = loc.contains( pt );
2137 // DragDrop is using this as a sanity check for the initial mousedown
2138 // in this case we are done. In POINT mode, if the drag obj has no
2139 // contraints, we are also done. Otherwise we need to evaluate the
2140 // location of the target as related to the actual location of the
2142 var dc = this.dragCurrent;
2143 if (!dc || !dc.getTargetCoord ||
2144 (!intersect && !dc.constrainX && !dc.constrainY)) {
2145 return oTarget.cursorIsOver;
2148 oTarget.overlap = null;
2150 // Get the current location of the drag element, this is the
2151 // location of the mouse event less the delta that represents
2152 // where the original mousedown happened on the element. We
2153 // need to consider constraints and ticks as well.
2154 var pos = dc.getTargetCoord(pt.x, pt.y);
2156 var el = dc.getDragEl();
2157 var curRegion = new Roo.lib.Region( pos.y,
2158 pos.x + el.offsetWidth,
2159 pos.y + el.offsetHeight,
2162 var overlap = curRegion.intersect(loc);
2165 oTarget.overlap = overlap;
2166 return (intersect) ? true : oTarget.cursorIsOver;
2173 * unload event handler
2178 _onUnload: function(e, me) {
2179 Roo.dd.DragDropMgr.unregAll();
2183 * Cleans up the drag and drop events and objects.
2188 unregAll: function() {
2190 if (this.dragCurrent) {
2192 this.dragCurrent = null;
2195 this._execOnAll("unreg", []);
2197 for (i in this.elementCache) {
2198 delete this.elementCache[i];
2201 this.elementCache = {};
2206 * A cache of DOM elements
2207 * @property elementCache
2214 * Get the wrapper for the DOM element specified
2215 * @method getElWrapper
2216 * @param {String} id the id of the element to get
2217 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2219 * @deprecated This wrapper isn't that useful
2222 getElWrapper: function(id) {
2223 var oWrapper = this.elementCache[id];
2224 if (!oWrapper || !oWrapper.el) {
2225 oWrapper = this.elementCache[id] =
2226 new this.ElementWrapper(Roo.getDom(id));
2232 * Returns the actual DOM element
2233 * @method getElement
2234 * @param {String} id the id of the elment to get
2235 * @return {Object} The element
2236 * @deprecated use Roo.getDom instead
2239 getElement: function(id) {
2240 return Roo.getDom(id);
2244 * Returns the style property for the DOM element (i.e.,
2245 * document.getElById(id).style)
2247 * @param {String} id the id of the elment to get
2248 * @return {Object} The style property of the element
2249 * @deprecated use Roo.getDom instead
2252 getCss: function(id) {
2253 var el = Roo.getDom(id);
2254 return (el) ? el.style : null;
2258 * Inner class for cached elements
2259 * @class DragDropMgr.ElementWrapper
2264 ElementWrapper: function(el) {
2269 this.el = el || null;
2274 this.id = this.el && el.id;
2276 * A reference to the style property
2279 this.css = this.el && el.style;
2283 * Returns the X position of an html element
2285 * @param el the element for which to get the position
2286 * @return {int} the X coordinate
2288 * @deprecated use Roo.lib.Dom.getX instead
2291 getPosX: function(el) {
2292 return Roo.lib.Dom.getX(el);
2296 * Returns the Y position of an html element
2298 * @param el the element for which to get the position
2299 * @return {int} the Y coordinate
2300 * @deprecated use Roo.lib.Dom.getY instead
2303 getPosY: function(el) {
2304 return Roo.lib.Dom.getY(el);
2308 * Swap two nodes. In IE, we use the native method, for others we
2309 * emulate the IE behavior
2311 * @param n1 the first node to swap
2312 * @param n2 the other node to swap
2315 swapNode: function(n1, n2) {
2319 var p = n2.parentNode;
2320 var s = n2.nextSibling;
2323 p.insertBefore(n1, n2);
2324 } else if (n2 == n1.nextSibling) {
2325 p.insertBefore(n2, n1);
2327 n1.parentNode.replaceChild(n2, n1);
2328 p.insertBefore(n1, s);
2334 * Returns the current scroll position
2339 getScroll: function () {
2340 var t, l, dde=document.documentElement, db=document.body;
2341 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2350 return { top: t, left: l };
2354 * Returns the specified element style property
2356 * @param {HTMLElement} el the element
2357 * @param {string} styleProp the style property
2358 * @return {string} The value of the style property
2359 * @deprecated use Roo.lib.Dom.getStyle
2362 getStyle: function(el, styleProp) {
2363 return Roo.fly(el).getStyle(styleProp);
2367 * Gets the scrollTop
2368 * @method getScrollTop
2369 * @return {int} the document's scrollTop
2372 getScrollTop: function () { return this.getScroll().top; },
2375 * Gets the scrollLeft
2376 * @method getScrollLeft
2377 * @return {int} the document's scrollTop
2380 getScrollLeft: function () { return this.getScroll().left; },
2383 * Sets the x/y position of an element to the location of the
2386 * @param {HTMLElement} moveEl The element to move
2387 * @param {HTMLElement} targetEl The position reference element
2390 moveToEl: function (moveEl, targetEl) {
2391 var aCoord = Roo.lib.Dom.getXY(targetEl);
2392 Roo.lib.Dom.setXY(moveEl, aCoord);
2396 * Numeric array sort function
2397 * @method numericSort
2400 numericSort: function(a, b) { return (a - b); },
2404 * @property _timeoutCount
2411 * Trying to make the load order less important. Without this we get
2412 * an error if this file is loaded before the Event Utility.
2413 * @method _addListeners
2417 _addListeners: function() {
2418 var DDM = Roo.dd.DDM;
2419 if ( Roo.lib.Event && document ) {
2422 if (DDM._timeoutCount > 2000) {
2424 setTimeout(DDM._addListeners, 10);
2425 if (document && document.body) {
2426 DDM._timeoutCount += 1;
2433 * Recursively searches the immediate parent and all child nodes for
2434 * the handle element in order to determine wheter or not it was
2436 * @method handleWasClicked
2437 * @param node the html element to inspect
2440 handleWasClicked: function(node, id) {
2441 if (this.isHandle(id, node.id)) {
2444 // check to see if this is a text node child of the one we want
2445 var p = node.parentNode;
2448 if (this.isHandle(id, p.id)) {
2463 // shorter alias, save a few bytes
2464 Roo.dd.DDM = Roo.dd.DragDropMgr;
2465 Roo.dd.DDM._addListeners();
2469 * Ext JS Library 1.1.1
2470 * Copyright(c) 2006-2007, Ext JS, LLC.
2472 * Originally Released Under LGPL - original licence link has changed is not relivant.
2475 * <script type="text/javascript">
2480 * A DragDrop implementation where the linked element follows the
2481 * mouse cursor during a drag.
2482 * @extends Roo.dd.DragDrop
2484 * @param {String} id the id of the linked element
2485 * @param {String} sGroup the group of related DragDrop items
2486 * @param {object} config an object containing configurable attributes
2487 * Valid properties for DD:
2490 Roo.dd.DD = function(id, sGroup, config) {
2492 this.init(id, sGroup, config);
2496 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2499 * When set to true, the utility automatically tries to scroll the browser
2500 * window wehn a drag and drop element is dragged near the viewport boundary.
2508 * Sets the pointer offset to the distance between the linked element's top
2509 * left corner and the location the element was clicked
2510 * @method autoOffset
2511 * @param {int} iPageX the X coordinate of the click
2512 * @param {int} iPageY the Y coordinate of the click
2514 autoOffset: function(iPageX, iPageY) {
2515 var x = iPageX - this.startPageX;
2516 var y = iPageY - this.startPageY;
2517 this.setDelta(x, y);
2521 * Sets the pointer offset. You can call this directly to force the
2522 * offset to be in a particular location (e.g., pass in 0,0 to set it
2523 * to the center of the object)
2525 * @param {int} iDeltaX the distance from the left
2526 * @param {int} iDeltaY the distance from the top
2528 setDelta: function(iDeltaX, iDeltaY) {
2529 this.deltaX = iDeltaX;
2530 this.deltaY = iDeltaY;
2534 * Sets the drag element to the location of the mousedown or click event,
2535 * maintaining the cursor location relative to the location on the element
2536 * that was clicked. Override this if you want to place the element in a
2537 * location other than where the cursor is.
2538 * @method setDragElPos
2539 * @param {int} iPageX the X coordinate of the mousedown or drag event
2540 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2542 setDragElPos: function(iPageX, iPageY) {
2543 // the first time we do this, we are going to check to make sure
2544 // the element has css positioning
2546 var el = this.getDragEl();
2547 this.alignElWithMouse(el, iPageX, iPageY);
2551 * Sets the element to the location of the mousedown or click event,
2552 * maintaining the cursor location relative to the location on the element
2553 * that was clicked. Override this if you want to place the element in a
2554 * location other than where the cursor is.
2555 * @method alignElWithMouse
2556 * @param {HTMLElement} el the element to move
2557 * @param {int} iPageX the X coordinate of the mousedown or drag event
2558 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2560 alignElWithMouse: function(el, iPageX, iPageY) {
2561 var oCoord = this.getTargetCoord(iPageX, iPageY);
2562 var fly = el.dom ? el : Roo.fly(el);
2563 if (!this.deltaSetXY) {
2564 var aCoord = [oCoord.x, oCoord.y];
2566 var newLeft = fly.getLeft(true);
2567 var newTop = fly.getTop(true);
2568 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2570 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2573 this.cachePosition(oCoord.x, oCoord.y);
2574 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2579 * Saves the most recent position so that we can reset the constraints and
2580 * tick marks on-demand. We need to know this so that we can calculate the
2581 * number of pixels the element is offset from its original position.
2582 * @method cachePosition
2583 * @param iPageX the current x position (optional, this just makes it so we
2584 * don't have to look it up again)
2585 * @param iPageY the current y position (optional, this just makes it so we
2586 * don't have to look it up again)
2588 cachePosition: function(iPageX, iPageY) {
2590 this.lastPageX = iPageX;
2591 this.lastPageY = iPageY;
2593 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2594 this.lastPageX = aCoord[0];
2595 this.lastPageY = aCoord[1];
2600 * Auto-scroll the window if the dragged object has been moved beyond the
2601 * visible window boundary.
2602 * @method autoScroll
2603 * @param {int} x the drag element's x position
2604 * @param {int} y the drag element's y position
2605 * @param {int} h the height of the drag element
2606 * @param {int} w the width of the drag element
2609 autoScroll: function(x, y, h, w) {
2612 // The client height
2613 var clientH = Roo.lib.Dom.getViewWidth();
2616 var clientW = Roo.lib.Dom.getViewHeight();
2618 // The amt scrolled down
2619 var st = this.DDM.getScrollTop();
2621 // The amt scrolled right
2622 var sl = this.DDM.getScrollLeft();
2624 // Location of the bottom of the element
2627 // Location of the right of the element
2630 // The distance from the cursor to the bottom of the visible area,
2631 // adjusted so that we don't scroll if the cursor is beyond the
2632 // element drag constraints
2633 var toBot = (clientH + st - y - this.deltaY);
2635 // The distance from the cursor to the right of the visible area
2636 var toRight = (clientW + sl - x - this.deltaX);
2639 // How close to the edge the cursor must be before we scroll
2640 // var thresh = (document.all) ? 100 : 40;
2643 // How many pixels to scroll per autoscroll op. This helps to reduce
2644 // clunky scrolling. IE is more sensitive about this ... it needs this
2645 // value to be higher.
2646 var scrAmt = (document.all) ? 80 : 30;
2648 // Scroll down if we are near the bottom of the visible page and the
2649 // obj extends below the crease
2650 if ( bot > clientH && toBot < thresh ) {
2651 window.scrollTo(sl, st + scrAmt);
2654 // Scroll up if the window is scrolled down and the top of the object
2655 // goes above the top border
2656 if ( y < st && st > 0 && y - st < thresh ) {
2657 window.scrollTo(sl, st - scrAmt);
2660 // Scroll right if the obj is beyond the right border and the cursor is
2662 if ( right > clientW && toRight < thresh ) {
2663 window.scrollTo(sl + scrAmt, st);
2666 // Scroll left if the window has been scrolled to the right and the obj
2667 // extends past the left border
2668 if ( x < sl && sl > 0 && x - sl < thresh ) {
2669 window.scrollTo(sl - scrAmt, st);
2675 * Finds the location the element should be placed if we want to move
2676 * it to where the mouse location less the click offset would place us.
2677 * @method getTargetCoord
2678 * @param {int} iPageX the X coordinate of the click
2679 * @param {int} iPageY the Y coordinate of the click
2680 * @return an object that contains the coordinates (Object.x and Object.y)
2683 getTargetCoord: function(iPageX, iPageY) {
2686 var x = iPageX - this.deltaX;
2687 var y = iPageY - this.deltaY;
2689 if (this.constrainX) {
2690 if (x < this.minX) { x = this.minX; }
2691 if (x > this.maxX) { x = this.maxX; }
2694 if (this.constrainY) {
2695 if (y < this.minY) { y = this.minY; }
2696 if (y > this.maxY) { y = this.maxY; }
2699 x = this.getTick(x, this.xTicks);
2700 y = this.getTick(y, this.yTicks);
2707 * Sets up config options specific to this class. Overrides
2708 * Roo.dd.DragDrop, but all versions of this method through the
2709 * inheritance chain are called
2711 applyConfig: function() {
2712 Roo.dd.DD.superclass.applyConfig.call(this);
2713 this.scroll = (this.config.scroll !== false);
2717 * Event that fires prior to the onMouseDown event. Overrides
2720 b4MouseDown: function(e) {
2721 // this.resetConstraints();
2722 this.autoOffset(e.getPageX(),
2727 * Event that fires prior to the onDrag event. Overrides
2730 b4Drag: function(e) {
2731 this.setDragElPos(e.getPageX(),
2735 toString: function() {
2736 return ("DD " + this.id);
2739 //////////////////////////////////////////////////////////////////////////
2740 // Debugging ygDragDrop events that can be overridden
2741 //////////////////////////////////////////////////////////////////////////
2743 startDrag: function(x, y) {
2746 onDrag: function(e) {
2749 onDragEnter: function(e, id) {
2752 onDragOver: function(e, id) {
2755 onDragOut: function(e, id) {
2758 onDragDrop: function(e, id) {
2761 endDrag: function(e) {
2768 * Ext JS Library 1.1.1
2769 * Copyright(c) 2006-2007, Ext JS, LLC.
2771 * Originally Released Under LGPL - original licence link has changed is not relivant.
2774 * <script type="text/javascript">
2778 * @class Roo.dd.DDProxy
2779 * A DragDrop implementation that inserts an empty, bordered div into
2780 * the document that follows the cursor during drag operations. At the time of
2781 * the click, the frame div is resized to the dimensions of the linked html
2782 * element, and moved to the exact location of the linked element.
2784 * References to the "frame" element refer to the single proxy element that
2785 * was created to be dragged in place of all DDProxy elements on the
2788 * @extends Roo.dd.DD
2790 * @param {String} id the id of the linked html element
2791 * @param {String} sGroup the group of related DragDrop objects
2792 * @param {object} config an object containing configurable attributes
2793 * Valid properties for DDProxy in addition to those in DragDrop:
2794 * resizeFrame, centerFrame, dragElId
2796 Roo.dd.DDProxy = function(id, sGroup, config) {
2798 this.init(id, sGroup, config);
2804 * The default drag frame div id
2805 * @property Roo.dd.DDProxy.dragElId
2809 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2811 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2814 * By default we resize the drag frame to be the same size as the element
2815 * we want to drag (this is to get the frame effect). We can turn it off
2816 * if we want a different behavior.
2817 * @property resizeFrame
2823 * By default the frame is positioned exactly where the drag element is, so
2824 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2825 * you do not have constraints on the obj is to have the drag frame centered
2826 * around the cursor. Set centerFrame to true for this effect.
2827 * @property centerFrame
2833 * Creates the proxy element if it does not yet exist
2834 * @method createFrame
2836 createFrame: function() {
2838 var body = document.body;
2840 if (!body || !body.firstChild) {
2841 setTimeout( function() { self.createFrame(); }, 50 );
2845 var div = this.getDragEl();
2848 div = document.createElement("div");
2849 div.id = this.dragElId;
2852 s.position = "absolute";
2853 s.visibility = "hidden";
2855 s.border = "2px solid #aaa";
2858 // appendChild can blow up IE if invoked prior to the window load event
2859 // while rendering a table. It is possible there are other scenarios
2860 // that would cause this to happen as well.
2861 body.insertBefore(div, body.firstChild);
2866 * Initialization for the drag frame element. Must be called in the
2867 * constructor of all subclasses
2870 initFrame: function() {
2874 applyConfig: function() {
2875 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2877 this.resizeFrame = (this.config.resizeFrame !== false);
2878 this.centerFrame = (this.config.centerFrame);
2879 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2883 * Resizes the drag frame to the dimensions of the clicked object, positions
2884 * it over the object, and finally displays it
2886 * @param {int} iPageX X click position
2887 * @param {int} iPageY Y click position
2890 showFrame: function(iPageX, iPageY) {
2891 var el = this.getEl();
2892 var dragEl = this.getDragEl();
2893 var s = dragEl.style;
2895 this._resizeProxy();
2897 if (this.centerFrame) {
2898 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2899 Math.round(parseInt(s.height, 10)/2) );
2902 this.setDragElPos(iPageX, iPageY);
2904 Roo.fly(dragEl).show();
2908 * The proxy is automatically resized to the dimensions of the linked
2909 * element when a drag is initiated, unless resizeFrame is set to false
2910 * @method _resizeProxy
2913 _resizeProxy: function() {
2914 if (this.resizeFrame) {
2915 var el = this.getEl();
2916 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2920 // overrides Roo.dd.DragDrop
2921 b4MouseDown: function(e) {
2922 var x = e.getPageX();
2923 var y = e.getPageY();
2924 this.autoOffset(x, y);
2925 this.setDragElPos(x, y);
2928 // overrides Roo.dd.DragDrop
2929 b4StartDrag: function(x, y) {
2930 // show the drag frame
2931 this.showFrame(x, y);
2934 // overrides Roo.dd.DragDrop
2935 b4EndDrag: function(e) {
2936 Roo.fly(this.getDragEl()).hide();
2939 // overrides Roo.dd.DragDrop
2940 // By default we try to move the element to the last location of the frame.
2941 // This is so that the default behavior mirrors that of Roo.dd.DD.
2942 endDrag: function(e) {
2944 var lel = this.getEl();
2945 var del = this.getDragEl();
2947 // Show the drag frame briefly so we can get its position
2948 del.style.visibility = "";
2951 // Hide the linked element before the move to get around a Safari
2953 lel.style.visibility = "hidden";
2954 Roo.dd.DDM.moveToEl(lel, del);
2955 del.style.visibility = "hidden";
2956 lel.style.visibility = "";
2961 beforeMove : function(){
2965 afterDrag : function(){
2969 toString: function() {
2970 return ("DDProxy " + this.id);
2976 * Ext JS Library 1.1.1
2977 * Copyright(c) 2006-2007, Ext JS, LLC.
2979 * Originally Released Under LGPL - original licence link has changed is not relivant.
2982 * <script type="text/javascript">
2986 * @class Roo.dd.DDTarget
2987 * A DragDrop implementation that does not move, but can be a drop
2988 * target. You would get the same result by simply omitting implementation
2989 * for the event callbacks, but this way we reduce the processing cost of the
2990 * event listener and the callbacks.
2991 * @extends Roo.dd.DragDrop
2993 * @param {String} id the id of the element that is a drop target
2994 * @param {String} sGroup the group of related DragDrop objects
2995 * @param {object} config an object containing configurable attributes
2996 * Valid properties for DDTarget in addition to those in
3000 Roo.dd.DDTarget = function(id, sGroup, config) {
3002 this.initTarget(id, sGroup, config);
3004 if (config.listeners || config.events) {
3005 Roo.dd.DragDrop.superclass.constructor.call(this, {
3006 listeners : config.listeners || {},
3007 events : config.events || {}
3012 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3013 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3014 toString: function() {
3015 return ("DDTarget " + this.id);
3020 * Ext JS Library 1.1.1
3021 * Copyright(c) 2006-2007, Ext JS, LLC.
3023 * Originally Released Under LGPL - original licence link has changed is not relivant.
3026 * <script type="text/javascript">
3031 * @class Roo.dd.ScrollManager
3032 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3033 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3036 Roo.dd.ScrollManager = function(){
3037 var ddm = Roo.dd.DragDropMgr;
3042 var onStop = function(e){
3047 var triggerRefresh = function(){
3048 if(ddm.dragCurrent){
3049 ddm.refreshCache(ddm.dragCurrent.groups);
3053 var doScroll = function(){
3054 if(ddm.dragCurrent){
3055 var dds = Roo.dd.ScrollManager;
3057 if(proc.el.scroll(proc.dir, dds.increment)){
3061 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3066 var clearProc = function(){
3068 clearInterval(proc.id);
3075 var startProc = function(el, dir){
3079 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3082 var onFire = function(e, isDrop){
3083 if(isDrop || !ddm.dragCurrent){ return; }
3084 var dds = Roo.dd.ScrollManager;
3085 if(!dragEl || dragEl != ddm.dragCurrent){
3086 dragEl = ddm.dragCurrent;
3087 // refresh regions on drag start
3091 var xy = Roo.lib.Event.getXY(e);
3092 var pt = new Roo.lib.Point(xy[0], xy[1]);
3094 var el = els[id], r = el._region;
3095 if(r && r.contains(pt) && el.isScrollable()){
3096 if(r.bottom - pt.y <= dds.thresh){
3098 startProc(el, "down");
3101 }else if(r.right - pt.x <= dds.thresh){
3103 startProc(el, "left");
3106 }else if(pt.y - r.top <= dds.thresh){
3108 startProc(el, "up");
3111 }else if(pt.x - r.left <= dds.thresh){
3113 startProc(el, "right");
3122 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3123 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3127 * Registers new overflow element(s) to auto scroll
3128 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3130 register : function(el){
3131 if(el instanceof Array){
3132 for(var i = 0, len = el.length; i < len; i++) {
3133 this.register(el[i]);
3142 * Unregisters overflow element(s) so they are no longer scrolled
3143 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3145 unregister : function(el){
3146 if(el instanceof Array){
3147 for(var i = 0, len = el.length; i < len; i++) {
3148 this.unregister(el[i]);
3157 * The number of pixels from the edge of a container the pointer needs to be to
3158 * trigger scrolling (defaults to 25)
3164 * The number of pixels to scroll in each scroll increment (defaults to 50)
3170 * The frequency of scrolls in milliseconds (defaults to 500)
3176 * True to animate the scroll (defaults to true)
3182 * The animation duration in seconds -
3183 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3189 * Manually trigger a cache refresh.
3191 refreshCache : function(){
3193 if(typeof els[id] == 'object'){ // for people extending the object prototype
3194 els[id]._region = els[id].getRegion();
3201 * Ext JS Library 1.1.1
3202 * Copyright(c) 2006-2007, Ext JS, LLC.
3204 * Originally Released Under LGPL - original licence link has changed is not relivant.
3207 * <script type="text/javascript">
3212 * @class Roo.dd.Registry
3213 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3214 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3217 Roo.dd.Registry = function(){
3222 var getId = function(el, autogen){
3223 if(typeof el == "string"){
3227 if(!id && autogen !== false){
3228 id = "roodd-" + (++autoIdSeed);
3236 * Register a drag drop element
3237 * @param {String|HTMLElement} element The id or DOM node to register
3238 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3239 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3240 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3241 * populated in the data object (if applicable):
3243 Value Description<br />
3244 --------- ------------------------------------------<br />
3245 handles Array of DOM nodes that trigger dragging<br />
3246 for the element being registered<br />
3247 isHandle True if the element passed in triggers<br />
3248 dragging itself, else false
3251 register : function(el, data){
3253 if(typeof el == "string"){
3254 el = document.getElementById(el);
3257 elements[getId(el)] = data;
3258 if(data.isHandle !== false){
3259 handles[data.ddel.id] = data;
3262 var hs = data.handles;
3263 for(var i = 0, len = hs.length; i < len; i++){
3264 handles[getId(hs[i])] = data;
3270 * Unregister a drag drop element
3271 * @param {String|HTMLElement} element The id or DOM node to unregister
3273 unregister : function(el){
3274 var id = getId(el, false);
3275 var data = elements[id];
3277 delete elements[id];
3279 var hs = data.handles;
3280 for(var i = 0, len = hs.length; i < len; i++){
3281 delete handles[getId(hs[i], false)];
3288 * Returns the handle registered for a DOM Node by id
3289 * @param {String|HTMLElement} id The DOM node or id to look up
3290 * @return {Object} handle The custom handle data
3292 getHandle : function(id){
3293 if(typeof id != "string"){ // must be element?
3300 * Returns the handle that is registered for the DOM node that is the target of the event
3301 * @param {Event} e The event
3302 * @return {Object} handle The custom handle data
3304 getHandleFromEvent : function(e){
3305 var t = Roo.lib.Event.getTarget(e);
3306 return t ? handles[t.id] : null;
3310 * Returns a custom data object that is registered for a DOM node by id
3311 * @param {String|HTMLElement} id The DOM node or id to look up
3312 * @return {Object} data The custom data
3314 getTarget : function(id){
3315 if(typeof id != "string"){ // must be element?
3318 return elements[id];
3322 * Returns a custom data object that is registered for the DOM node that is the target of the event
3323 * @param {Event} e The event
3324 * @return {Object} data The custom data
3326 getTargetFromEvent : function(e){
3327 var t = Roo.lib.Event.getTarget(e);
3328 return t ? elements[t.id] || handles[t.id] : null;
3333 * Ext JS Library 1.1.1
3334 * Copyright(c) 2006-2007, Ext JS, LLC.
3336 * Originally Released Under LGPL - original licence link has changed is not relivant.
3339 * <script type="text/javascript">
3344 * @class Roo.dd.StatusProxy
3345 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3346 * default drag proxy used by all Roo.dd components.
3348 * @param {Object} config
3350 Roo.dd.StatusProxy = function(config){
3351 Roo.apply(this, config);
3352 this.id = this.id || Roo.id();
3353 this.el = new Roo.Layer({
3355 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3356 {tag: "div", cls: "x-dd-drop-icon"},
3357 {tag: "div", cls: "x-dd-drag-ghost"}
3360 shadow: !config || config.shadow !== false
3362 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3363 this.dropStatus = this.dropNotAllowed;
3366 Roo.dd.StatusProxy.prototype = {
3368 * @cfg {String} dropAllowed
3369 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3371 dropAllowed : "x-dd-drop-ok",
3373 * @cfg {String} dropNotAllowed
3374 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3376 dropNotAllowed : "x-dd-drop-nodrop",
3379 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3380 * over the current target element.
3381 * @param {String} cssClass The css class for the new drop status indicator image
3383 setStatus : function(cssClass){
3384 cssClass = cssClass || this.dropNotAllowed;
3385 if(this.dropStatus != cssClass){
3386 this.el.replaceClass(this.dropStatus, cssClass);
3387 this.dropStatus = cssClass;
3392 * Resets the status indicator to the default dropNotAllowed value
3393 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3395 reset : function(clearGhost){
3396 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3397 this.dropStatus = this.dropNotAllowed;
3399 this.ghost.update("");
3404 * Updates the contents of the ghost element
3405 * @param {String} html The html that will replace the current innerHTML of the ghost element
3407 update : function(html){
3408 if(typeof html == "string"){
3409 this.ghost.update(html);
3411 this.ghost.update("");
3412 html.style.margin = "0";
3413 this.ghost.dom.appendChild(html);
3415 // ensure float = none set?? cant remember why though.
3416 var el = this.ghost.dom.firstChild;
3418 Roo.fly(el).setStyle('float', 'none');
3423 * Returns the underlying proxy {@link Roo.Layer}
3424 * @return {Roo.Layer} el
3431 * Returns the ghost element
3432 * @return {Roo.Element} el
3434 getGhost : function(){
3440 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3442 hide : function(clear){
3450 * Stops the repair animation if it's currently running
3453 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3459 * Displays this proxy
3466 * Force the Layer to sync its shadow and shim positions to the element
3473 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3474 * invalid drop operation by the item being dragged.
3475 * @param {Array} xy The XY position of the element ([x, y])
3476 * @param {Function} callback The function to call after the repair is complete
3477 * @param {Object} scope The scope in which to execute the callback
3479 repair : function(xy, callback, scope){
3480 this.callback = callback;
3482 if(xy && this.animRepair !== false){
3483 this.el.addClass("x-dd-drag-repair");
3484 this.el.hideUnders(true);
3485 this.anim = this.el.shift({
3486 duration: this.repairDuration || .5,
3490 callback: this.afterRepair,
3499 afterRepair : function(){
3501 if(typeof this.callback == "function"){
3502 this.callback.call(this.scope || this);
3504 this.callback = null;
3509 * Ext JS Library 1.1.1
3510 * Copyright(c) 2006-2007, Ext JS, LLC.
3512 * Originally Released Under LGPL - original licence link has changed is not relivant.
3515 * <script type="text/javascript">
3519 * @class Roo.dd.DragSource
3520 * @extends Roo.dd.DDProxy
3521 * A simple class that provides the basic implementation needed to make any element draggable.
3523 * @param {String/HTMLElement/Element} el The container element
3524 * @param {Object} config
3526 Roo.dd.DragSource = function(el, config){
3527 this.el = Roo.get(el);
3530 Roo.apply(this, config);
3533 this.proxy = new Roo.dd.StatusProxy();
3536 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3537 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3539 this.dragging = false;
3542 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3544 * @cfg {String} dropAllowed
3545 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3547 dropAllowed : "x-dd-drop-ok",
3549 * @cfg {String} dropNotAllowed
3550 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3552 dropNotAllowed : "x-dd-drop-nodrop",
3555 * Returns the data object associated with this drag source
3556 * @return {Object} data An object containing arbitrary data
3558 getDragData : function(e){
3559 return this.dragData;
3563 onDragEnter : function(e, id){
3564 var target = Roo.dd.DragDropMgr.getDDById(id);
3565 this.cachedTarget = target;
3566 if(this.beforeDragEnter(target, e, id) !== false){
3567 if(target.isNotifyTarget){
3568 var status = target.notifyEnter(this, e, this.dragData);
3569 this.proxy.setStatus(status);
3571 this.proxy.setStatus(this.dropAllowed);
3574 if(this.afterDragEnter){
3576 * An empty function by default, but provided so that you can perform a custom action
3577 * when the dragged item enters the drop target by providing an implementation.
3578 * @param {Roo.dd.DragDrop} target The drop target
3579 * @param {Event} e The event object
3580 * @param {String} id The id of the dragged element
3581 * @method afterDragEnter
3583 this.afterDragEnter(target, e, id);
3589 * An empty function by default, but provided so that you can perform a custom action
3590 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3591 * @param {Roo.dd.DragDrop} target The drop target
3592 * @param {Event} e The event object
3593 * @param {String} id The id of the dragged element
3594 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3596 beforeDragEnter : function(target, e, id){
3601 alignElWithMouse: function() {
3602 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3607 onDragOver : function(e, id){
3608 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3609 if(this.beforeDragOver(target, e, id) !== false){
3610 if(target.isNotifyTarget){
3611 var status = target.notifyOver(this, e, this.dragData);
3612 this.proxy.setStatus(status);
3615 if(this.afterDragOver){
3617 * An empty function by default, but provided so that you can perform a custom action
3618 * while the dragged item is over the drop target by providing an implementation.
3619 * @param {Roo.dd.DragDrop} target The drop target
3620 * @param {Event} e The event object
3621 * @param {String} id The id of the dragged element
3622 * @method afterDragOver
3624 this.afterDragOver(target, e, id);
3630 * An empty function by default, but provided so that you can perform a custom action
3631 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3632 * @param {Roo.dd.DragDrop} target The drop target
3633 * @param {Event} e The event object
3634 * @param {String} id The id of the dragged element
3635 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3637 beforeDragOver : function(target, e, id){
3642 onDragOut : function(e, id){
3643 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3644 if(this.beforeDragOut(target, e, id) !== false){
3645 if(target.isNotifyTarget){
3646 target.notifyOut(this, e, this.dragData);
3649 if(this.afterDragOut){
3651 * An empty function by default, but provided so that you can perform a custom action
3652 * after the dragged item is dragged out of the target without dropping.
3653 * @param {Roo.dd.DragDrop} target The drop target
3654 * @param {Event} e The event object
3655 * @param {String} id The id of the dragged element
3656 * @method afterDragOut
3658 this.afterDragOut(target, e, id);
3661 this.cachedTarget = null;
3665 * An empty function by default, but provided so that you can perform a custom action before the dragged
3666 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3667 * @param {Roo.dd.DragDrop} target The drop target
3668 * @param {Event} e The event object
3669 * @param {String} id The id of the dragged element
3670 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3672 beforeDragOut : function(target, e, id){
3677 onDragDrop : function(e, id){
3678 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3679 if(this.beforeDragDrop(target, e, id) !== false){
3680 if(target.isNotifyTarget){
3681 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3682 this.onValidDrop(target, e, id);
3684 this.onInvalidDrop(target, e, id);
3687 this.onValidDrop(target, e, id);
3690 if(this.afterDragDrop){
3692 * An empty function by default, but provided so that you can perform a custom action
3693 * after a valid drag drop has occurred by providing an implementation.
3694 * @param {Roo.dd.DragDrop} target The drop target
3695 * @param {Event} e The event object
3696 * @param {String} id The id of the dropped element
3697 * @method afterDragDrop
3699 this.afterDragDrop(target, e, id);
3702 delete this.cachedTarget;
3706 * An empty function by default, but provided so that you can perform a custom action before the dragged
3707 * item is dropped onto the target and optionally cancel the onDragDrop.
3708 * @param {Roo.dd.DragDrop} target The drop target
3709 * @param {Event} e The event object
3710 * @param {String} id The id of the dragged element
3711 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3713 beforeDragDrop : function(target, e, id){
3718 onValidDrop : function(target, e, id){
3720 if(this.afterValidDrop){
3722 * An empty function by default, but provided so that you can perform a custom action
3723 * after a valid drop has occurred by providing an implementation.
3724 * @param {Object} target The target DD
3725 * @param {Event} e The event object
3726 * @param {String} id The id of the dropped element
3727 * @method afterInvalidDrop
3729 this.afterValidDrop(target, e, id);
3734 getRepairXY : function(e, data){
3735 return this.el.getXY();
3739 onInvalidDrop : function(target, e, id){
3740 this.beforeInvalidDrop(target, e, id);
3741 if(this.cachedTarget){
3742 if(this.cachedTarget.isNotifyTarget){
3743 this.cachedTarget.notifyOut(this, e, this.dragData);
3745 this.cacheTarget = null;
3747 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3749 if(this.afterInvalidDrop){
3751 * An empty function by default, but provided so that you can perform a custom action
3752 * after an invalid drop has occurred by providing an implementation.
3753 * @param {Event} e The event object
3754 * @param {String} id The id of the dropped element
3755 * @method afterInvalidDrop
3757 this.afterInvalidDrop(e, id);
3762 afterRepair : function(){
3764 this.el.highlight(this.hlColor || "c3daf9");
3766 this.dragging = false;
3770 * An empty function by default, but provided so that you can perform a custom action after an invalid
3771 * drop has occurred.
3772 * @param {Roo.dd.DragDrop} target The drop target
3773 * @param {Event} e The event object
3774 * @param {String} id The id of the dragged element
3775 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3777 beforeInvalidDrop : function(target, e, id){
3782 handleMouseDown : function(e){
3786 var data = this.getDragData(e);
3787 if(data && this.onBeforeDrag(data, e) !== false){
3788 this.dragData = data;
3790 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3795 * An empty function by default, but provided so that you can perform a custom action before the initial
3796 * drag event begins and optionally cancel it.
3797 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3798 * @param {Event} e The event object
3799 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3801 onBeforeDrag : function(data, e){
3806 * An empty function by default, but provided so that you can perform a custom action once the initial
3807 * drag event has begun. The drag cannot be canceled from this function.
3808 * @param {Number} x The x position of the click on the dragged object
3809 * @param {Number} y The y position of the click on the dragged object
3811 onStartDrag : Roo.emptyFn,
3813 // private - YUI override
3814 startDrag : function(x, y){
3816 this.dragging = true;
3817 this.proxy.update("");
3818 this.onInitDrag(x, y);
3823 onInitDrag : function(x, y){
3824 var clone = this.el.dom.cloneNode(true);
3825 clone.id = Roo.id(); // prevent duplicate ids
3826 this.proxy.update(clone);
3827 this.onStartDrag(x, y);
3832 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3833 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3835 getProxy : function(){
3840 * Hides the drag source's {@link Roo.dd.StatusProxy}
3842 hideProxy : function(){
3844 this.proxy.reset(true);
3845 this.dragging = false;
3849 triggerCacheRefresh : function(){
3850 Roo.dd.DDM.refreshCache(this.groups);
3853 // private - override to prevent hiding
3854 b4EndDrag: function(e) {
3857 // private - override to prevent moving
3858 endDrag : function(e){
3859 this.onEndDrag(this.dragData, e);
3863 onEndDrag : function(data, e){
3866 // private - pin to cursor
3867 autoOffset : function(x, y) {
3868 this.setDelta(-12, -20);
3872 * Ext JS Library 1.1.1
3873 * Copyright(c) 2006-2007, Ext JS, LLC.
3875 * Originally Released Under LGPL - original licence link has changed is not relivant.
3878 * <script type="text/javascript">
3883 * @class Roo.dd.DropTarget
3884 * @extends Roo.dd.DDTarget
3885 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3886 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3888 * @param {String/HTMLElement/Element} el The container element
3889 * @param {Object} config
3891 Roo.dd.DropTarget = function(el, config){
3892 this.el = Roo.get(el);
3894 var listeners = config.listeners;
3896 delete config.listeners;
3898 Roo.apply(this, config);
3900 if(this.containerScroll){
3901 Roo.dd.ScrollManager.register(this.el);
3905 * @scope Roo.dd.DropTarget
3910 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3911 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3912 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3914 * IMPORTANT : it should set this.overClass and this.dropAllowed
3916 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3917 * @param {Event} e The event
3918 * @param {Object} data An object containing arbitrary data supplied by the drag source
3924 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3925 * This method will be called on every mouse movement while the drag source is over the drop target.
3926 * This default implementation simply returns the dropAllowed config value.
3928 * IMPORTANT : it should set this.dropAllowed
3930 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3931 * @param {Event} e The event
3932 * @param {Object} data An object containing arbitrary data supplied by the drag source
3938 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3939 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3940 * overClass (if any) from the drop element.
3941 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3942 * @param {Event} e The event
3943 * @param {Object} data An object containing arbitrary data supplied by the drag source
3949 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3950 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3951 * implementation that does something to process the drop event and returns true so that the drag source's
3952 * repair action does not run.
3954 * IMPORTANT : it should set this.success
3956 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3957 * @param {Event} e The event
3958 * @param {Object} data An object containing arbitrary data supplied by the drag source
3964 Roo.dd.DropTarget.superclass.constructor.call( this,
3966 this.ddGroup || this.group,
3969 listeners : listeners || {}
3977 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3979 * @cfg {String} overClass
3980 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3983 * @cfg {String} ddGroup
3984 * The drag drop group to handle drop events for
3988 * @cfg {String} dropAllowed
3989 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3991 dropAllowed : "x-dd-drop-ok",
3993 * @cfg {String} dropNotAllowed
3994 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3996 dropNotAllowed : "x-dd-drop-nodrop",
3998 * @cfg {boolean} success
3999 * set this after drop listener..
4003 * @cfg {boolean} valid
4004 * if the drop point is valid for over/enter..
4011 isNotifyTarget : true,
4016 notifyEnter : function(dd, e, data){
4018 this.fireEvent('enter', this, dd, e, data);
4020 this.el.addClass(this.overClass);
4022 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4028 notifyOver : function(dd, e, data){
4030 this.fireEvent('over', this, dd, e, data);
4031 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4037 notifyOut : function(dd, e, data){
4038 this.fireEvent('out', this, dd, e, data);
4040 this.el.removeClass(this.overClass);
4047 notifyDrop : function(dd, e, data){
4048 this.success = false;
4049 this.fireEvent('drop', this, dd, e, data);
4050 return this.success;
4054 * Ext JS Library 1.1.1
4055 * Copyright(c) 2006-2007, Ext JS, LLC.
4057 * Originally Released Under LGPL - original licence link has changed is not relivant.
4060 * <script type="text/javascript">
4065 * @class Roo.dd.DragZone
4066 * @extends Roo.dd.DragSource
4067 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4068 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4070 * @param {String/HTMLElement/Element} el The container element
4071 * @param {Object} config
4073 Roo.dd.DragZone = function(el, config){
4074 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4075 if(this.containerScroll){
4076 Roo.dd.ScrollManager.register(this.el);
4080 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4082 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4083 * for auto scrolling during drag operations.
4086 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4087 * method after a failed drop (defaults to "c3daf9" - light blue)
4091 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4092 * for a valid target to drag based on the mouse down. Override this method
4093 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4094 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4095 * @param {EventObject} e The mouse down event
4096 * @return {Object} The dragData
4098 getDragData : function(e){
4099 return Roo.dd.Registry.getHandleFromEvent(e);
4103 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4104 * this.dragData.ddel
4105 * @param {Number} x The x position of the click on the dragged object
4106 * @param {Number} y The y position of the click on the dragged object
4107 * @return {Boolean} true to continue the drag, false to cancel
4109 onInitDrag : function(x, y){
4110 this.proxy.update(this.dragData.ddel.cloneNode(true));
4111 this.onStartDrag(x, y);
4116 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4118 afterRepair : function(){
4120 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4122 this.dragging = false;
4126 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4127 * the XY of this.dragData.ddel
4128 * @param {EventObject} e The mouse up event
4129 * @return {Array} The xy location (e.g. [100, 200])
4131 getRepairXY : function(e){
4132 return Roo.Element.fly(this.dragData.ddel).getXY();
4136 * Ext JS Library 1.1.1
4137 * Copyright(c) 2006-2007, Ext JS, LLC.
4139 * Originally Released Under LGPL - original licence link has changed is not relivant.
4142 * <script type="text/javascript">
4145 * @class Roo.dd.DropZone
4146 * @extends Roo.dd.DropTarget
4147 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4148 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4150 * @param {String/HTMLElement/Element} el The container element
4151 * @param {Object} config
4153 Roo.dd.DropZone = function(el, config){
4154 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4157 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4159 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4160 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4161 * provide your own custom lookup.
4162 * @param {Event} e The event
4163 * @return {Object} data The custom data
4165 getTargetFromEvent : function(e){
4166 return Roo.dd.Registry.getTargetFromEvent(e);
4170 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4171 * that it has registered. This method has no default implementation and should be overridden to provide
4172 * node-specific processing if necessary.
4173 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4174 * {@link #getTargetFromEvent} for this node)
4175 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4176 * @param {Event} e The event
4177 * @param {Object} data An object containing arbitrary data supplied by the drag source
4179 onNodeEnter : function(n, dd, e, data){
4184 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4185 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4186 * overridden to provide the proper feedback.
4187 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4188 * {@link #getTargetFromEvent} for this node)
4189 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4190 * @param {Event} e The event
4191 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4193 * underlying {@link Roo.dd.StatusProxy} can be updated
4195 onNodeOver : function(n, dd, e, data){
4196 return this.dropAllowed;
4200 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4201 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4202 * node-specific processing if necessary.
4203 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4204 * {@link #getTargetFromEvent} for this node)
4205 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4206 * @param {Event} e The event
4207 * @param {Object} data An object containing arbitrary data supplied by the drag source
4209 onNodeOut : function(n, dd, e, data){
4214 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4215 * the drop node. The default implementation returns false, so it should be overridden to provide the
4216 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4217 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4218 * {@link #getTargetFromEvent} for this node)
4219 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4220 * @param {Event} e The event
4221 * @param {Object} data An object containing arbitrary data supplied by the drag source
4222 * @return {Boolean} True if the drop was valid, else false
4224 onNodeDrop : function(n, dd, e, data){
4229 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4230 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4231 * it should be overridden to provide the proper feedback if necessary.
4232 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4233 * @param {Event} e The event
4234 * @param {Object} data An object containing arbitrary data supplied by the drag source
4235 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4236 * underlying {@link Roo.dd.StatusProxy} can be updated
4238 onContainerOver : function(dd, e, data){
4239 return this.dropNotAllowed;
4243 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4244 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4245 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4246 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4247 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4248 * @param {Event} e The event
4249 * @param {Object} data An object containing arbitrary data supplied by the drag source
4250 * @return {Boolean} True if the drop was valid, else false
4252 onContainerDrop : function(dd, e, data){
4257 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4258 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4259 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4260 * you should override this method and provide a custom implementation.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyEnter : function(dd, e, data){
4268 return this.dropNotAllowed;
4272 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4273 * This method will be called on every mouse movement while the drag source is over the drop zone.
4274 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4275 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4276 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4277 * registered node, it will call {@link #onContainerOver}.
4278 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4279 * @param {Event} e The event
4280 * @param {Object} data An object containing arbitrary data supplied by the drag source
4281 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4282 * underlying {@link Roo.dd.StatusProxy} can be updated
4284 notifyOver : function(dd, e, data){
4285 var n = this.getTargetFromEvent(e);
4286 if(!n){ // not over valid drop target
4287 if(this.lastOverNode){
4288 this.onNodeOut(this.lastOverNode, dd, e, data);
4289 this.lastOverNode = null;
4291 return this.onContainerOver(dd, e, data);
4293 if(this.lastOverNode != n){
4294 if(this.lastOverNode){
4295 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.onNodeEnter(n, dd, e, data);
4298 this.lastOverNode = n;
4300 return this.onNodeOver(n, dd, e, data);
4304 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4305 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4306 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4307 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4308 * @param {Event} e The event
4309 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4311 notifyOut : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4319 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4320 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4321 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4322 * otherwise it will call {@link #onContainerDrop}.
4323 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4324 * @param {Event} e The event
4325 * @param {Object} data An object containing arbitrary data supplied by the drag source
4326 * @return {Boolean} True if the drop was valid, else false
4328 notifyDrop : function(dd, e, data){
4329 if(this.lastOverNode){
4330 this.onNodeOut(this.lastOverNode, dd, e, data);
4331 this.lastOverNode = null;
4333 var n = this.getTargetFromEvent(e);
4335 this.onNodeDrop(n, dd, e, data) :
4336 this.onContainerDrop(dd, e, data);
4340 triggerCacheRefresh : function(){
4341 Roo.dd.DDM.refreshCache(this.groups);
4345 * Ext JS Library 1.1.1
4346 * Copyright(c) 2006-2007, Ext JS, LLC.
4348 * Originally Released Under LGPL - original licence link has changed is not relivant.
4351 * <script type="text/javascript">
4356 * @class Roo.data.SortTypes
4358 * Defines the default sorting (casting?) comparison functions used when sorting data.
4360 Roo.data.SortTypes = {
4362 * Default sort that does nothing
4363 * @param {Mixed} s The value being converted
4364 * @return {Mixed} The comparison value
4371 * The regular expression used to strip tags
4375 stripTagsRE : /<\/?[^>]+>/gi,
4378 * Strips all HTML tags to sort on text only
4379 * @param {Mixed} s The value being converted
4380 * @return {String} The comparison value
4382 asText : function(s){
4383 return String(s).replace(this.stripTagsRE, "");
4387 * Strips all HTML tags to sort on text only - Case insensitive
4388 * @param {Mixed} s The value being converted
4389 * @return {String} The comparison value
4391 asUCText : function(s){
4392 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4396 * Case insensitive string
4397 * @param {Mixed} s The value being converted
4398 * @return {String} The comparison value
4400 asUCString : function(s) {
4401 return String(s).toUpperCase();
4406 * @param {Mixed} s The value being converted
4407 * @return {Number} The comparison value
4409 asDate : function(s) {
4413 if(s instanceof Date){
4416 return Date.parse(String(s));
4421 * @param {Mixed} s The value being converted
4422 * @return {Float} The comparison value
4424 asFloat : function(s) {
4425 var val = parseFloat(String(s).replace(/,/g, ""));
4426 if(isNaN(val)) val = 0;
4432 * @param {Mixed} s The value being converted
4433 * @return {Number} The comparison value
4435 asInt : function(s) {
4436 var val = parseInt(String(s).replace(/,/g, ""));
4437 if(isNaN(val)) val = 0;
4442 * Ext JS Library 1.1.1
4443 * Copyright(c) 2006-2007, Ext JS, LLC.
4445 * Originally Released Under LGPL - original licence link has changed is not relivant.
4448 * <script type="text/javascript">
4452 * @class Roo.data.Record
4453 * Instances of this class encapsulate both record <em>definition</em> information, and record
4454 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4455 * to access Records cached in an {@link Roo.data.Store} object.<br>
4457 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4458 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4461 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4463 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4464 * {@link #create}. The parameters are the same.
4465 * @param {Array} data An associative Array of data values keyed by the field name.
4466 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4467 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4468 * not specified an integer id is generated.
4470 Roo.data.Record = function(data, id){
4471 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4476 * Generate a constructor for a specific record layout.
4477 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4478 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4479 * Each field definition object may contain the following properties: <ul>
4480 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4481 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4482 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4483 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4484 * is being used, then this is a string containing the javascript expression to reference the data relative to
4485 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4486 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4487 * this may be omitted.</p></li>
4488 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4489 * <ul><li>auto (Default, implies no conversion)</li>
4494 * <li>date</li></ul></p></li>
4495 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4496 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4497 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4498 * by the Reader into an object that will be stored in the Record. It is passed the
4499 * following parameters:<ul>
4500 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4502 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4504 * <br>usage:<br><pre><code>
4505 var TopicRecord = Roo.data.Record.create(
4506 {name: 'title', mapping: 'topic_title'},
4507 {name: 'author', mapping: 'username'},
4508 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4509 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4510 {name: 'lastPoster', mapping: 'user2'},
4511 {name: 'excerpt', mapping: 'post_text'}
4514 var myNewRecord = new TopicRecord({
4515 title: 'Do my job please',
4518 lastPost: new Date(),
4519 lastPoster: 'Animal',
4520 excerpt: 'No way dude!'
4522 myStore.add(myNewRecord);
4527 Roo.data.Record.create = function(o){
4529 f.superclass.constructor.apply(this, arguments);
4531 Roo.extend(f, Roo.data.Record);
4532 var p = f.prototype;
4533 p.fields = new Roo.util.MixedCollection(false, function(field){
4536 for(var i = 0, len = o.length; i < len; i++){
4537 p.fields.add(new Roo.data.Field(o[i]));
4539 f.getField = function(name){
4540 return p.fields.get(name);
4545 Roo.data.Record.AUTO_ID = 1000;
4546 Roo.data.Record.EDIT = 'edit';
4547 Roo.data.Record.REJECT = 'reject';
4548 Roo.data.Record.COMMIT = 'commit';
4550 Roo.data.Record.prototype = {
4552 * Readonly flag - true if this record has been modified.
4561 join : function(store){
4566 * Set the named field to the specified value.
4567 * @param {String} name The name of the field to set.
4568 * @param {Object} value The value to set the field to.
4570 set : function(name, value){
4571 if(this.data[name] == value){
4578 if(typeof this.modified[name] == 'undefined'){
4579 this.modified[name] = this.data[name];
4581 this.data[name] = value;
4583 this.store.afterEdit(this);
4588 * Get the value of the named field.
4589 * @param {String} name The name of the field to get the value of.
4590 * @return {Object} The value of the field.
4592 get : function(name){
4593 return this.data[name];
4597 beginEdit : function(){
4598 this.editing = true;
4603 cancelEdit : function(){
4604 this.editing = false;
4605 delete this.modified;
4609 endEdit : function(){
4610 this.editing = false;
4611 if(this.dirty && this.store){
4612 this.store.afterEdit(this);
4617 * Usually called by the {@link Roo.data.Store} which owns the Record.
4618 * Rejects all changes made to the Record since either creation, or the last commit operation.
4619 * Modified fields are reverted to their original values.
4621 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4622 * of reject operations.
4624 reject : function(){
4625 var m = this.modified;
4627 if(typeof m[n] != "function"){
4628 this.data[n] = m[n];
4632 delete this.modified;
4633 this.editing = false;
4635 this.store.afterReject(this);
4640 * Usually called by the {@link Roo.data.Store} which owns the Record.
4641 * Commits all changes made to the Record since either creation, or the last commit operation.
4643 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4644 * of commit operations.
4646 commit : function(){
4648 delete this.modified;
4649 this.editing = false;
4651 this.store.afterCommit(this);
4656 hasError : function(){
4657 return this.error != null;
4661 clearError : function(){
4666 * Creates a copy of this record.
4667 * @param {String} id (optional) A new record id if you don't want to use this record's id
4670 copy : function(newId) {
4671 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4675 * Ext JS Library 1.1.1
4676 * Copyright(c) 2006-2007, Ext JS, LLC.
4678 * Originally Released Under LGPL - original licence link has changed is not relivant.
4681 * <script type="text/javascript">
4687 * @class Roo.data.Store
4688 * @extends Roo.util.Observable
4689 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4690 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4692 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4693 * has no knowledge of the format of the data returned by the Proxy.<br>
4695 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4696 * instances from the data object. These records are cached and made available through accessor functions.
4698 * Creates a new Store.
4699 * @param {Object} config A config object containing the objects needed for the Store to access data,
4700 * and read the data into Records.
4702 Roo.data.Store = function(config){
4703 this.data = new Roo.util.MixedCollection(false);
4704 this.data.getKey = function(o){
4707 this.baseParams = {};
4716 if(config && config.data){
4717 this.inlineData = config.data;
4721 Roo.apply(this, config);
4723 if(this.reader){ // reader passed
4724 this.reader = Roo.factory(this.reader, Roo.data);
4725 this.reader.xmodule = this.xmodule || false;
4726 if(!this.recordType){
4727 this.recordType = this.reader.recordType;
4729 if(this.reader.onMetaChange){
4730 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4734 if(this.recordType){
4735 this.fields = this.recordType.prototype.fields;
4741 * @event datachanged
4742 * Fires when the data cache has changed, and a widget which is using this Store
4743 * as a Record cache should refresh its view.
4744 * @param {Store} this
4749 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4750 * @param {Store} this
4751 * @param {Object} meta The JSON metadata
4756 * Fires when Records have been added to the Store
4757 * @param {Store} this
4758 * @param {Roo.data.Record[]} records The array of Records added
4759 * @param {Number} index The index at which the record(s) were added
4764 * Fires when a Record has been removed from the Store
4765 * @param {Store} this
4766 * @param {Roo.data.Record} record The Record that was removed
4767 * @param {Number} index The index at which the record was removed
4772 * Fires when a Record has been updated
4773 * @param {Store} this
4774 * @param {Roo.data.Record} record The Record that was updated
4775 * @param {String} operation The update operation being performed. Value may be one of:
4777 Roo.data.Record.EDIT
4778 Roo.data.Record.REJECT
4779 Roo.data.Record.COMMIT
4785 * Fires when the data cache has been cleared.
4786 * @param {Store} this
4791 * Fires before a request is made for a new data object. If the beforeload handler returns false
4792 * the load action will be canceled.
4793 * @param {Store} this
4794 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4799 * Fires after a new set of Records has been loaded.
4800 * @param {Store} this
4801 * @param {Roo.data.Record[]} records The Records that were loaded
4802 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4806 * @event loadexception
4807 * Fires if an exception occurs in the Proxy during loading.
4808 * Called with the signature of the Proxy's "loadexception" event.
4809 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4812 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4813 * @param {Object} load options
4814 * @param {Object} jsonData from your request (normally this contains the Exception)
4816 loadexception : true
4820 this.proxy = Roo.factory(this.proxy, Roo.data);
4821 this.proxy.xmodule = this.xmodule || false;
4822 this.relayEvents(this.proxy, ["loadexception"]);
4824 this.sortToggle = {};
4826 Roo.data.Store.superclass.constructor.call(this);
4828 if(this.inlineData){
4829 this.loadData(this.inlineData);
4830 delete this.inlineData;
4833 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4835 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4836 * without a remote query - used by combo/forms at present.
4840 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4843 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4846 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4847 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4850 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4851 * on any HTTP request
4854 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4857 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4858 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4863 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4864 * loaded or when a record is removed. (defaults to false).
4866 pruneModifiedRecords : false,
4872 * Add Records to the Store and fires the add event.
4873 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4875 add : function(records){
4876 records = [].concat(records);
4877 for(var i = 0, len = records.length; i < len; i++){
4878 records[i].join(this);
4880 var index = this.data.length;
4881 this.data.addAll(records);
4882 this.fireEvent("add", this, records, index);
4886 * Remove a Record from the Store and fires the remove event.
4887 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4889 remove : function(record){
4890 var index = this.data.indexOf(record);
4891 this.data.removeAt(index);
4892 if(this.pruneModifiedRecords){
4893 this.modified.remove(record);
4895 this.fireEvent("remove", this, record, index);
4899 * Remove all Records from the Store and fires the clear event.
4901 removeAll : function(){
4903 if(this.pruneModifiedRecords){
4906 this.fireEvent("clear", this);
4910 * Inserts Records to the Store at the given index and fires the add event.
4911 * @param {Number} index The start index at which to insert the passed Records.
4912 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4914 insert : function(index, records){
4915 records = [].concat(records);
4916 for(var i = 0, len = records.length; i < len; i++){
4917 this.data.insert(index, records[i]);
4918 records[i].join(this);
4920 this.fireEvent("add", this, records, index);
4924 * Get the index within the cache of the passed Record.
4925 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4926 * @return {Number} The index of the passed Record. Returns -1 if not found.
4928 indexOf : function(record){
4929 return this.data.indexOf(record);
4933 * Get the index within the cache of the Record with the passed id.
4934 * @param {String} id The id of the Record to find.
4935 * @return {Number} The index of the Record. Returns -1 if not found.
4937 indexOfId : function(id){
4938 return this.data.indexOfKey(id);
4942 * Get the Record with the specified id.
4943 * @param {String} id The id of the Record to find.
4944 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4946 getById : function(id){
4947 return this.data.key(id);
4951 * Get the Record at the specified index.
4952 * @param {Number} index The index of the Record to find.
4953 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4955 getAt : function(index){
4956 return this.data.itemAt(index);
4960 * Returns a range of Records between specified indices.
4961 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4962 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4963 * @return {Roo.data.Record[]} An array of Records
4965 getRange : function(start, end){
4966 return this.data.getRange(start, end);
4970 storeOptions : function(o){
4971 o = Roo.apply({}, o);
4974 this.lastOptions = o;
4978 * Loads the Record cache from the configured Proxy using the configured Reader.
4980 * If using remote paging, then the first load call must specify the <em>start</em>
4981 * and <em>limit</em> properties in the options.params property to establish the initial
4982 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4984 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4985 * and this call will return before the new data has been loaded. Perform any post-processing
4986 * in a callback function, or in a "load" event handler.</strong>
4988 * @param {Object} options An object containing properties which control loading options:<ul>
4989 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4990 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4991 * passed the following arguments:<ul>
4992 * <li>r : Roo.data.Record[]</li>
4993 * <li>options: Options object from the load call</li>
4994 * <li>success: Boolean success indicator</li></ul></li>
4995 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4996 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4999 load : function(options){
5000 options = options || {};
5001 if(this.fireEvent("beforeload", this, options) !== false){
5002 this.storeOptions(options);
5003 var p = Roo.apply(options.params || {}, this.baseParams);
5004 // if meta was not loaded from remote source.. try requesting it.
5005 if (!this.reader.metaFromRemote) {
5008 if(this.sortInfo && this.remoteSort){
5009 var pn = this.paramNames;
5010 p[pn["sort"]] = this.sortInfo.field;
5011 p[pn["dir"]] = this.sortInfo.direction;
5013 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5018 * Reloads the Record cache from the configured Proxy using the configured Reader and
5019 * the options from the last load operation performed.
5020 * @param {Object} options (optional) An object containing properties which may override the options
5021 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5022 * the most recently used options are reused).
5024 reload : function(options){
5025 this.load(Roo.applyIf(options||{}, this.lastOptions));
5029 // Called as a callback by the Reader during a load operation.
5030 loadRecords : function(o, options, success){
5031 if(!o || success === false){
5032 if(success !== false){
5033 this.fireEvent("load", this, [], options);
5035 if(options.callback){
5036 options.callback.call(options.scope || this, [], options, false);
5040 // if data returned failure - throw an exception.
5041 if (o.success === false) {
5042 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5045 var r = o.records, t = o.totalRecords || r.length;
5046 if(!options || options.add !== true){
5047 if(this.pruneModifiedRecords){
5050 for(var i = 0, len = r.length; i < len; i++){
5054 this.data = this.snapshot;
5055 delete this.snapshot;
5058 this.data.addAll(r);
5059 this.totalLength = t;
5061 this.fireEvent("datachanged", this);
5063 this.totalLength = Math.max(t, this.data.length+r.length);
5066 this.fireEvent("load", this, r, options);
5067 if(options.callback){
5068 options.callback.call(options.scope || this, r, options, true);
5073 * Loads data from a passed data block. A Reader which understands the format of the data
5074 * must have been configured in the constructor.
5075 * @param {Object} data The data block from which to read the Records. The format of the data expected
5076 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5077 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5079 loadData : function(o, append){
5080 var r = this.reader.readRecords(o);
5081 this.loadRecords(r, {add: append}, true);
5085 * Gets the number of cached records.
5087 * <em>If using paging, this may not be the total size of the dataset. If the data object
5088 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5089 * the data set size</em>
5091 getCount : function(){
5092 return this.data.length || 0;
5096 * Gets the total number of records in the dataset as returned by the server.
5098 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5099 * the dataset size</em>
5101 getTotalCount : function(){
5102 return this.totalLength || 0;
5106 * Returns the sort state of the Store as an object with two properties:
5108 field {String} The name of the field by which the Records are sorted
5109 direction {String} The sort order, "ASC" or "DESC"
5112 getSortState : function(){
5113 return this.sortInfo;
5117 applySort : function(){
5118 if(this.sortInfo && !this.remoteSort){
5119 var s = this.sortInfo, f = s.field;
5120 var st = this.fields.get(f).sortType;
5121 var fn = function(r1, r2){
5122 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5123 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5125 this.data.sort(s.direction, fn);
5126 if(this.snapshot && this.snapshot != this.data){
5127 this.snapshot.sort(s.direction, fn);
5133 * Sets the default sort column and order to be used by the next load operation.
5134 * @param {String} fieldName The name of the field to sort by.
5135 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5137 setDefaultSort : function(field, dir){
5138 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5143 * If remote sorting is used, the sort is performed on the server, and the cache is
5144 * reloaded. If local sorting is used, the cache is sorted internally.
5145 * @param {String} fieldName The name of the field to sort by.
5146 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5148 sort : function(fieldName, dir){
5149 var f = this.fields.get(fieldName);
5151 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5152 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5157 this.sortToggle[f.name] = dir;
5158 this.sortInfo = {field: f.name, direction: dir};
5159 if(!this.remoteSort){
5161 this.fireEvent("datachanged", this);
5163 this.load(this.lastOptions);
5168 * Calls the specified function for each of the Records in the cache.
5169 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5170 * Returning <em>false</em> aborts and exits the iteration.
5171 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5173 each : function(fn, scope){
5174 this.data.each(fn, scope);
5178 * Gets all records modified since the last commit. Modified records are persisted across load operations
5179 * (e.g., during paging).
5180 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5182 getModifiedRecords : function(){
5183 return this.modified;
5187 createFilterFn : function(property, value, anyMatch){
5188 if(!value.exec){ // not a regex
5189 value = String(value);
5190 if(value.length == 0){
5193 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5196 return value.test(r.data[property]);
5201 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5202 * @param {String} property A field on your records
5203 * @param {Number} start The record index to start at (defaults to 0)
5204 * @param {Number} end The last record index to include (defaults to length - 1)
5205 * @return {Number} The sum
5207 sum : function(property, start, end){
5208 var rs = this.data.items, v = 0;
5210 end = (end || end === 0) ? end : rs.length-1;
5212 for(var i = start; i <= end; i++){
5213 v += (rs[i].data[property] || 0);
5219 * Filter the records by a specified property.
5220 * @param {String} field A field on your records
5221 * @param {String/RegExp} value Either a string that the field
5222 * should start with or a RegExp to test against the field
5223 * @param {Boolean} anyMatch True to match any part not just the beginning
5225 filter : function(property, value, anyMatch){
5226 var fn = this.createFilterFn(property, value, anyMatch);
5227 return fn ? this.filterBy(fn) : this.clearFilter();
5231 * Filter by a function. The specified function will be called with each
5232 * record in this data source. If the function returns true the record is included,
5233 * otherwise it is filtered.
5234 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5235 * @param {Object} scope (optional) The scope of the function (defaults to this)
5237 filterBy : function(fn, scope){
5238 this.snapshot = this.snapshot || this.data;
5239 this.data = this.queryBy(fn, scope||this);
5240 this.fireEvent("datachanged", this);
5244 * Query the records by a specified property.
5245 * @param {String} field A field on your records
5246 * @param {String/RegExp} value Either a string that the field
5247 * should start with or a RegExp to test against the field
5248 * @param {Boolean} anyMatch True to match any part not just the beginning
5249 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5251 query : function(property, value, anyMatch){
5252 var fn = this.createFilterFn(property, value, anyMatch);
5253 return fn ? this.queryBy(fn) : this.data.clone();
5257 * Query by a function. The specified function will be called with each
5258 * record in this data source. If the function returns true the record is included
5260 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5261 * @param {Object} scope (optional) The scope of the function (defaults to this)
5262 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5264 queryBy : function(fn, scope){
5265 var data = this.snapshot || this.data;
5266 return data.filterBy(fn, scope||this);
5270 * Collects unique values for a particular dataIndex from this store.
5271 * @param {String} dataIndex The property to collect
5272 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5273 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5274 * @return {Array} An array of the unique values
5276 collect : function(dataIndex, allowNull, bypassFilter){
5277 var d = (bypassFilter === true && this.snapshot) ?
5278 this.snapshot.items : this.data.items;
5279 var v, sv, r = [], l = {};
5280 for(var i = 0, len = d.length; i < len; i++){
5281 v = d[i].data[dataIndex];
5283 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5292 * Revert to a view of the Record cache with no filtering applied.
5293 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5295 clearFilter : function(suppressEvent){
5296 if(this.snapshot && this.snapshot != this.data){
5297 this.data = this.snapshot;
5298 delete this.snapshot;
5299 if(suppressEvent !== true){
5300 this.fireEvent("datachanged", this);
5306 afterEdit : function(record){
5307 if(this.modified.indexOf(record) == -1){
5308 this.modified.push(record);
5310 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5314 afterReject : function(record){
5315 this.modified.remove(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5320 afterCommit : function(record){
5321 this.modified.remove(record);
5322 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5326 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5327 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5329 commitChanges : function(){
5330 var m = this.modified.slice(0);
5332 for(var i = 0, len = m.length; i < len; i++){
5338 * Cancel outstanding changes on all changed records.
5340 rejectChanges : function(){
5341 var m = this.modified.slice(0);
5343 for(var i = 0, len = m.length; i < len; i++){
5348 onMetaChange : function(meta, rtype, o){
5349 this.recordType = rtype;
5350 this.fields = rtype.prototype.fields;
5351 delete this.snapshot;
5352 this.sortInfo = meta.sortInfo || this.sortInfo;
5354 this.fireEvent('metachange', this, this.reader.meta);
5358 * Ext JS Library 1.1.1
5359 * Copyright(c) 2006-2007, Ext JS, LLC.
5361 * Originally Released Under LGPL - original licence link has changed is not relivant.
5364 * <script type="text/javascript">
5368 * @class Roo.data.SimpleStore
5369 * @extends Roo.data.Store
5370 * Small helper class to make creating Stores from Array data easier.
5371 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5372 * @cfg {Array} fields An array of field definition objects, or field name strings.
5373 * @cfg {Array} data The multi-dimensional array of data
5375 * @param {Object} config
5377 Roo.data.SimpleStore = function(config){
5378 Roo.data.SimpleStore.superclass.constructor.call(this, {
5380 reader: new Roo.data.ArrayReader({
5383 Roo.data.Record.create(config.fields)
5385 proxy : new Roo.data.MemoryProxy(config.data)
5389 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5391 * Ext JS Library 1.1.1
5392 * Copyright(c) 2006-2007, Ext JS, LLC.
5394 * Originally Released Under LGPL - original licence link has changed is not relivant.
5397 * <script type="text/javascript">
5402 * @extends Roo.data.Store
5403 * @class Roo.data.JsonStore
5404 * Small helper class to make creating Stores for JSON data easier. <br/>
5406 var store = new Roo.data.JsonStore({
5407 url: 'get-images.php',
5409 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5412 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5413 * JsonReader and HttpProxy (unless inline data is provided).</b>
5414 * @cfg {Array} fields An array of field definition objects, or field name strings.
5416 * @param {Object} config
5418 Roo.data.JsonStore = function(c){
5419 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5420 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5421 reader: new Roo.data.JsonReader(c, c.fields)
5424 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5426 * Ext JS Library 1.1.1
5427 * Copyright(c) 2006-2007, Ext JS, LLC.
5429 * Originally Released Under LGPL - original licence link has changed is not relivant.
5432 * <script type="text/javascript">
5436 Roo.data.Field = function(config){
5437 if(typeof config == "string"){
5438 config = {name: config};
5440 Roo.apply(this, config);
5446 var st = Roo.data.SortTypes;
5447 // named sortTypes are supported, here we look them up
5448 if(typeof this.sortType == "string"){
5449 this.sortType = st[this.sortType];
5452 // set default sortType for strings and dates
5456 this.sortType = st.asUCString;
5459 this.sortType = st.asDate;
5462 this.sortType = st.none;
5467 var stripRe = /[\$,%]/g;
5469 // prebuilt conversion function for this field, instead of
5470 // switching every time we're reading a value
5472 var cv, dateFormat = this.dateFormat;
5477 cv = function(v){ return v; };
5480 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5484 return v !== undefined && v !== null && v !== '' ?
5485 parseInt(String(v).replace(stripRe, ""), 10) : '';
5490 return v !== undefined && v !== null && v !== '' ?
5491 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5496 cv = function(v){ return v === true || v === "true" || v == 1; };
5503 if(v instanceof Date){
5507 if(dateFormat == "timestamp"){
5508 return new Date(v*1000);
5510 return Date.parseDate(v, dateFormat);
5512 var parsed = Date.parse(v);
5513 return parsed ? new Date(parsed) : null;
5522 Roo.data.Field.prototype = {
5530 * Ext JS Library 1.1.1
5531 * Copyright(c) 2006-2007, Ext JS, LLC.
5533 * Originally Released Under LGPL - original licence link has changed is not relivant.
5536 * <script type="text/javascript">
5539 // Base class for reading structured data from a data source. This class is intended to be
5540 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5543 * @class Roo.data.DataReader
5544 * Base class for reading structured data from a data source. This class is intended to be
5545 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5548 Roo.data.DataReader = function(meta, recordType){
5552 this.recordType = recordType instanceof Array ?
5553 Roo.data.Record.create(recordType) : recordType;
5556 Roo.data.DataReader.prototype = {
5558 * Create an empty record
5559 * @param {Object} data (optional) - overlay some values
5560 * @return {Roo.data.Record} record created.
5562 newRow : function(d) {
5564 this.recordType.prototype.fields.each(function(c) {
5566 case 'int' : da[c.name] = 0; break;
5567 case 'date' : da[c.name] = new Date(); break;
5568 case 'float' : da[c.name] = 0.0; break;
5569 case 'boolean' : da[c.name] = false; break;
5570 default : da[c.name] = ""; break;
5574 return new this.recordType(Roo.apply(da, d));
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.data.DataProxy
5590 * @extends Roo.data.Observable
5591 * This class is an abstract base class for implementations which provide retrieval of
5592 * unformatted data objects.<br>
5594 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5595 * (of the appropriate type which knows how to parse the data object) to provide a block of
5596 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5598 * Custom implementations must implement the load method as described in
5599 * {@link Roo.data.HttpProxy#load}.
5601 Roo.data.DataProxy = function(){
5605 * Fires before a network request is made to retrieve a data object.
5606 * @param {Object} This DataProxy object.
5607 * @param {Object} params The params parameter to the load function.
5612 * Fires before the load method's callback is called.
5613 * @param {Object} This DataProxy object.
5614 * @param {Object} o The data object.
5615 * @param {Object} arg The callback argument object passed to the load function.
5619 * @event loadexception
5620 * Fires if an Exception occurs during data retrieval.
5621 * @param {Object} This DataProxy object.
5622 * @param {Object} o The data object.
5623 * @param {Object} arg The callback argument object passed to the load function.
5624 * @param {Object} e The Exception.
5626 loadexception : true
5628 Roo.data.DataProxy.superclass.constructor.call(this);
5631 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5634 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5638 * Ext JS Library 1.1.1
5639 * Copyright(c) 2006-2007, Ext JS, LLC.
5641 * Originally Released Under LGPL - original licence link has changed is not relivant.
5644 * <script type="text/javascript">
5647 * @class Roo.data.MemoryProxy
5648 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5649 * to the Reader when its load method is called.
5651 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5653 Roo.data.MemoryProxy = function(data){
5657 Roo.data.MemoryProxy.superclass.constructor.call(this);
5661 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5663 * Load data from the requested source (in this case an in-memory
5664 * data object passed to the constructor), read the data object into
5665 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5666 * process that block using the passed callback.
5667 * @param {Object} params This parameter is not used by the MemoryProxy class.
5668 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5669 * object into a block of Roo.data.Records.
5670 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5671 * The function must be passed <ul>
5672 * <li>The Record block object</li>
5673 * <li>The "arg" argument from the load function</li>
5674 * <li>A boolean success indicator</li>
5676 * @param {Object} scope The scope in which to call the callback
5677 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5679 load : function(params, reader, callback, scope, arg){
5680 params = params || {};
5683 result = reader.readRecords(this.data);
5685 this.fireEvent("loadexception", this, arg, null, e);
5686 callback.call(scope, null, arg, false);
5689 callback.call(scope, result, arg, true);
5693 update : function(params, records){
5698 * Ext JS Library 1.1.1
5699 * Copyright(c) 2006-2007, Ext JS, LLC.
5701 * Originally Released Under LGPL - original licence link has changed is not relivant.
5704 * <script type="text/javascript">
5707 * @class Roo.data.HttpProxy
5708 * @extends Roo.data.DataProxy
5709 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5710 * configured to reference a certain URL.<br><br>
5712 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5713 * from which the running page was served.<br><br>
5715 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5717 * Be aware that to enable the browser to parse an XML document, the server must set
5718 * the Content-Type header in the HTTP response to "text/xml".
5720 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5721 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5722 * will be used to make the request.
5724 Roo.data.HttpProxy = function(conn){
5725 Roo.data.HttpProxy.superclass.constructor.call(this);
5726 // is conn a conn config or a real conn?
5728 this.useAjax = !conn || !conn.events;
5732 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5733 // thse are take from connection...
5736 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5739 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5740 * extra parameters to each request made by this object. (defaults to undefined)
5743 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5744 * to each request made by this object. (defaults to undefined)
5747 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5750 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5753 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5759 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5763 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5764 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5765 * a finer-grained basis than the DataProxy events.
5767 getConnection : function(){
5768 return this.useAjax ? Roo.Ajax : this.conn;
5772 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5773 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5774 * process that block using the passed callback.
5775 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5776 * for the request to the remote server.
5777 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5778 * object into a block of Roo.data.Records.
5779 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5780 * The function must be passed <ul>
5781 * <li>The Record block object</li>
5782 * <li>The "arg" argument from the load function</li>
5783 * <li>A boolean success indicator</li>
5785 * @param {Object} scope The scope in which to call the callback
5786 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5788 load : function(params, reader, callback, scope, arg){
5789 if(this.fireEvent("beforeload", this, params) !== false){
5791 params : params || {},
5793 callback : callback,
5798 callback : this.loadResponse,
5802 Roo.applyIf(o, this.conn);
5803 if(this.activeRequest){
5804 Roo.Ajax.abort(this.activeRequest);
5806 this.activeRequest = Roo.Ajax.request(o);
5808 this.conn.request(o);
5811 callback.call(scope||this, null, arg, false);
5816 loadResponse : function(o, success, response){
5817 delete this.activeRequest;
5819 this.fireEvent("loadexception", this, o, response);
5820 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5825 result = o.reader.read(response);
5827 this.fireEvent("loadexception", this, o, response, e);
5828 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5832 this.fireEvent("load", this, o, o.request.arg);
5833 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5837 update : function(dataSet){
5842 updateResponse : function(dataSet){
5847 * Ext JS Library 1.1.1
5848 * Copyright(c) 2006-2007, Ext JS, LLC.
5850 * Originally Released Under LGPL - original licence link has changed is not relivant.
5853 * <script type="text/javascript">
5857 * @class Roo.data.ScriptTagProxy
5858 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5859 * other than the originating domain of the running page.<br><br>
5861 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5862 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5864 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5865 * source code that is used as the source inside a <script> tag.<br><br>
5867 * In order for the browser to process the returned data, the server must wrap the data object
5868 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5869 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5870 * depending on whether the callback name was passed:
5873 boolean scriptTag = false;
5874 String cb = request.getParameter("callback");
5877 response.setContentType("text/javascript");
5879 response.setContentType("application/x-json");
5881 Writer out = response.getWriter();
5883 out.write(cb + "(");
5885 out.print(dataBlock.toJsonString());
5892 * @param {Object} config A configuration object.
5894 Roo.data.ScriptTagProxy = function(config){
5895 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5896 Roo.apply(this, config);
5897 this.head = document.getElementsByTagName("head")[0];
5900 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5902 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5904 * @cfg {String} url The URL from which to request the data object.
5907 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5911 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5912 * the server the name of the callback function set up by the load call to process the returned data object.
5913 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5914 * javascript output which calls this named function passing the data object as its only parameter.
5916 callbackParam : "callback",
5918 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5919 * name to the request.
5924 * Load data from the configured URL, read the data object into
5925 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5926 * process that block using the passed callback.
5927 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5928 * for the request to the remote server.
5929 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5930 * object into a block of Roo.data.Records.
5931 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5932 * The function must be passed <ul>
5933 * <li>The Record block object</li>
5934 * <li>The "arg" argument from the load function</li>
5935 * <li>A boolean success indicator</li>
5937 * @param {Object} scope The scope in which to call the callback
5938 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5940 load : function(params, reader, callback, scope, arg){
5941 if(this.fireEvent("beforeload", this, params) !== false){
5943 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5946 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5948 url += "&_dc=" + (new Date().getTime());
5950 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5953 cb : "stcCallback"+transId,
5954 scriptId : "stcScript"+transId,
5958 callback : callback,
5964 window[trans.cb] = function(o){
5965 conn.handleResponse(o, trans);
5968 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5970 if(this.autoAbort !== false){
5974 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5976 var script = document.createElement("script");
5977 script.setAttribute("src", url);
5978 script.setAttribute("type", "text/javascript");
5979 script.setAttribute("id", trans.scriptId);
5980 this.head.appendChild(script);
5984 callback.call(scope||this, null, arg, false);
5989 isLoading : function(){
5990 return this.trans ? true : false;
5994 * Abort the current server request.
5997 if(this.isLoading()){
5998 this.destroyTrans(this.trans);
6003 destroyTrans : function(trans, isLoaded){
6004 this.head.removeChild(document.getElementById(trans.scriptId));
6005 clearTimeout(trans.timeoutId);
6007 window[trans.cb] = undefined;
6009 delete window[trans.cb];
6012 // if hasn't been loaded, wait for load to remove it to prevent script error
6013 window[trans.cb] = function(){
6014 window[trans.cb] = undefined;
6016 delete window[trans.cb];
6023 handleResponse : function(o, trans){
6025 this.destroyTrans(trans, true);
6028 result = trans.reader.readRecords(o);
6030 this.fireEvent("loadexception", this, o, trans.arg, e);
6031 trans.callback.call(trans.scope||window, null, trans.arg, false);
6034 this.fireEvent("load", this, o, trans.arg);
6035 trans.callback.call(trans.scope||window, result, trans.arg, true);
6039 handleFailure : function(trans){
6041 this.destroyTrans(trans, false);
6042 this.fireEvent("loadexception", this, null, trans.arg);
6043 trans.callback.call(trans.scope||window, null, trans.arg, false);
6047 * Ext JS Library 1.1.1
6048 * Copyright(c) 2006-2007, Ext JS, LLC.
6050 * Originally Released Under LGPL - original licence link has changed is not relivant.
6053 * <script type="text/javascript">
6057 * @class Roo.data.JsonReader
6058 * @extends Roo.data.DataReader
6059 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6060 * based on mappings in a provided Roo.data.Record constructor.
6062 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6063 * in the reply previously.
6068 var RecordDef = Roo.data.Record.create([
6069 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6070 {name: 'occupation'} // This field will use "occupation" as the mapping.
6072 var myReader = new Roo.data.JsonReader({
6073 totalProperty: "results", // The property which contains the total dataset size (optional)
6074 root: "rows", // The property which contains an Array of row objects
6075 id: "id" // The property within each row object that provides an ID for the record (optional)
6079 * This would consume a JSON file like this:
6081 { 'results': 2, 'rows': [
6082 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6083 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6086 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6087 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6088 * paged from the remote server.
6089 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6090 * @cfg {String} root name of the property which contains the Array of row objects.
6091 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6093 * Create a new JsonReader
6094 * @param {Object} meta Metadata configuration options
6095 * @param {Object} recordType Either an Array of field definition objects,
6096 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6098 Roo.data.JsonReader = function(meta, recordType){
6101 // set some defaults:
6103 totalProperty: 'total',
6104 successProperty : 'success',
6109 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6111 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6114 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6115 * Used by Store query builder to append _requestMeta to params.
6118 metaFromRemote : false,
6120 * This method is only used by a DataProxy which has retrieved data from a remote server.
6121 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6122 * @return {Object} data A data block which is used by an Roo.data.Store object as
6123 * a cache of Roo.data.Records.
6125 read : function(response){
6126 var json = response.responseText;
6128 var o = /* eval:var:o */ eval("("+json+")");
6130 throw {message: "JsonReader.read: Json object not found"};
6136 this.metaFromRemote = true;
6137 this.meta = o.metaData;
6138 this.recordType = Roo.data.Record.create(o.metaData.fields);
6139 this.onMetaChange(this.meta, this.recordType, o);
6141 return this.readRecords(o);
6144 // private function a store will implement
6145 onMetaChange : function(meta, recordType, o){
6152 simpleAccess: function(obj, subsc) {
6159 getJsonAccessor: function(){
6161 return function(expr) {
6163 return(re.test(expr))
6164 ? new Function("obj", "return obj." + expr)
6174 * Create a data block containing Roo.data.Records from an XML document.
6175 * @param {Object} o An object which contains an Array of row objects in the property specified
6176 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6177 * which contains the total size of the dataset.
6178 * @return {Object} data A data block which is used by an Roo.data.Store object as
6179 * a cache of Roo.data.Records.
6181 readRecords : function(o){
6183 * After any data loads, the raw JSON data is available for further custom processing.
6187 var s = this.meta, Record = this.recordType,
6188 f = Record.prototype.fields, fi = f.items, fl = f.length;
6190 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6192 if(s.totalProperty) {
6193 this.getTotal = this.getJsonAccessor(s.totalProperty);
6195 if(s.successProperty) {
6196 this.getSuccess = this.getJsonAccessor(s.successProperty);
6198 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6200 var g = this.getJsonAccessor(s.id);
6201 this.getId = function(rec) {
6203 return (r === undefined || r === "") ? null : r;
6206 this.getId = function(){return null;};
6209 for(var jj = 0; jj < fl; jj++){
6211 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6212 this.ef[jj] = this.getJsonAccessor(map);
6216 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6217 if(s.totalProperty){
6218 var vt = parseInt(this.getTotal(o), 10);
6223 if(s.successProperty){
6224 var vs = this.getSuccess(o);
6225 if(vs === false || vs === 'false'){
6230 for(var i = 0; i < c; i++){
6233 var id = this.getId(n);
6234 for(var j = 0; j < fl; j++){
6236 var v = this.ef[j](n);
6238 Roo.log('missing convert for ' + f.name);
6242 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6244 var record = new Record(values, id);
6246 records[i] = record;
6251 totalRecords : totalRecords
6256 * Ext JS Library 1.1.1
6257 * Copyright(c) 2006-2007, Ext JS, LLC.
6259 * Originally Released Under LGPL - original licence link has changed is not relivant.
6262 * <script type="text/javascript">
6266 * @class Roo.data.XmlReader
6267 * @extends Roo.data.DataReader
6268 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6269 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6271 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6272 * header in the HTTP response must be set to "text/xml".</em>
6276 var RecordDef = Roo.data.Record.create([
6277 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6278 {name: 'occupation'} // This field will use "occupation" as the mapping.
6280 var myReader = new Roo.data.XmlReader({
6281 totalRecords: "results", // The element which contains the total dataset size (optional)
6282 record: "row", // The repeated element which contains row information
6283 id: "id" // The element within the row that provides an ID for the record (optional)
6287 * This would consume an XML file like this:
6291 <results>2</results>
6294 <name>Bill</name>
6295 <occupation>Gardener</occupation>
6299 <name>Ben</name>
6300 <occupation>Horticulturalist</occupation>
6304 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6305 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6306 * paged from the remote server.
6307 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6308 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6309 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6310 * a record identifier value.
6312 * Create a new XmlReader
6313 * @param {Object} meta Metadata configuration options
6314 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6315 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6316 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6318 Roo.data.XmlReader = function(meta, recordType){
6320 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6322 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6324 * This method is only used by a DataProxy which has retrieved data from a remote server.
6325 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6326 * to contain a method called 'responseXML' that returns an XML document object.
6327 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6328 * a cache of Roo.data.Records.
6330 read : function(response){
6331 var doc = response.responseXML;
6333 throw {message: "XmlReader.read: XML Document not available"};
6335 return this.readRecords(doc);
6339 * Create a data block containing Roo.data.Records from an XML document.
6340 * @param {Object} doc A parsed XML document.
6341 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6342 * a cache of Roo.data.Records.
6344 readRecords : function(doc){
6346 * After any data loads/reads, the raw XML Document is available for further custom processing.
6350 var root = doc.documentElement || doc;
6351 var q = Roo.DomQuery;
6352 var recordType = this.recordType, fields = recordType.prototype.fields;
6353 var sid = this.meta.id;
6354 var totalRecords = 0, success = true;
6355 if(this.meta.totalRecords){
6356 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6359 if(this.meta.success){
6360 var sv = q.selectValue(this.meta.success, root, true);
6361 success = sv !== false && sv !== 'false';
6364 var ns = q.select(this.meta.record, root);
6365 for(var i = 0, len = ns.length; i < len; i++) {
6368 var id = sid ? q.selectValue(sid, n) : undefined;
6369 for(var j = 0, jlen = fields.length; j < jlen; j++){
6370 var f = fields.items[j];
6371 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6375 var record = new recordType(values, id);
6377 records[records.length] = record;
6383 totalRecords : totalRecords || records.length
6388 * Ext JS Library 1.1.1
6389 * Copyright(c) 2006-2007, Ext JS, LLC.
6391 * Originally Released Under LGPL - original licence link has changed is not relivant.
6394 * <script type="text/javascript">
6398 * @class Roo.data.ArrayReader
6399 * @extends Roo.data.DataReader
6400 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6401 * Each element of that Array represents a row of data fields. The
6402 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6403 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6407 var RecordDef = Roo.data.Record.create([
6408 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6409 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6411 var myReader = new Roo.data.ArrayReader({
6412 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6416 * This would consume an Array like this:
6418 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6420 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6422 * Create a new JsonReader
6423 * @param {Object} meta Metadata configuration options.
6424 * @param {Object} recordType Either an Array of field definition objects
6425 * as specified to {@link Roo.data.Record#create},
6426 * or an {@link Roo.data.Record} object
6427 * created using {@link Roo.data.Record#create}.
6429 Roo.data.ArrayReader = function(meta, recordType){
6430 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6433 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6435 * Create a data block containing Roo.data.Records from an XML document.
6436 * @param {Object} o An Array of row objects which represents the dataset.
6437 * @return {Object} data A data block which is used by an Roo.data.Store object as
6438 * a cache of Roo.data.Records.
6440 readRecords : function(o){
6441 var sid = this.meta ? this.meta.id : null;
6442 var recordType = this.recordType, fields = recordType.prototype.fields;
6445 for(var i = 0; i < root.length; i++){
6448 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6449 for(var j = 0, jlen = fields.length; j < jlen; j++){
6450 var f = fields.items[j];
6451 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6452 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6456 var record = new recordType(values, id);
6458 records[records.length] = record;
6462 totalRecords : records.length
6467 * Ext JS Library 1.1.1
6468 * Copyright(c) 2006-2007, Ext JS, LLC.
6470 * Originally Released Under LGPL - original licence link has changed is not relivant.
6473 * <script type="text/javascript">
6478 * @class Roo.data.Tree
6479 * @extends Roo.util.Observable
6480 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6481 * in the tree have most standard DOM functionality.
6483 * @param {Node} root (optional) The root node
6485 Roo.data.Tree = function(root){
6488 * The root node for this tree
6493 this.setRootNode(root);
6498 * Fires when a new child node is appended to a node in this tree.
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} parent The parent node
6501 * @param {Node} node The newly appended node
6502 * @param {Number} index The index of the newly appended node
6507 * Fires when a child node is removed from a node in this tree.
6508 * @param {Tree} tree The owner tree
6509 * @param {Node} parent The parent node
6510 * @param {Node} node The child node removed
6515 * Fires when a node is moved to a new location in the tree
6516 * @param {Tree} tree The owner tree
6517 * @param {Node} node The node moved
6518 * @param {Node} oldParent The old parent of this node
6519 * @param {Node} newParent The new parent of this node
6520 * @param {Number} index The index it was moved to
6525 * Fires when a new child node is inserted in a node in this tree.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node inserted
6529 * @param {Node} refNode The child node the node was inserted before
6533 * @event beforeappend
6534 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6535 * @param {Tree} tree The owner tree
6536 * @param {Node} parent The parent node
6537 * @param {Node} node The child node to be appended
6539 "beforeappend" : true,
6541 * @event beforeremove
6542 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6543 * @param {Tree} tree The owner tree
6544 * @param {Node} parent The parent node
6545 * @param {Node} node The child node to be removed
6547 "beforeremove" : true,
6550 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6551 * @param {Tree} tree The owner tree
6552 * @param {Node} node The node being moved
6553 * @param {Node} oldParent The parent of the node
6554 * @param {Node} newParent The new parent the node is moving to
6555 * @param {Number} index The index it is being moved to
6557 "beforemove" : true,
6559 * @event beforeinsert
6560 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6561 * @param {Tree} tree The owner tree
6562 * @param {Node} parent The parent node
6563 * @param {Node} node The child node to be inserted
6564 * @param {Node} refNode The child node the node is being inserted before
6566 "beforeinsert" : true
6569 Roo.data.Tree.superclass.constructor.call(this);
6572 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6575 proxyNodeEvent : function(){
6576 return this.fireEvent.apply(this, arguments);
6580 * Returns the root node for this tree.
6583 getRootNode : function(){
6588 * Sets the root node for this tree.
6589 * @param {Node} node
6592 setRootNode : function(node){
6594 node.ownerTree = this;
6596 this.registerNode(node);
6601 * Gets a node in this tree by its id.
6602 * @param {String} id
6605 getNodeById : function(id){
6606 return this.nodeHash[id];
6609 registerNode : function(node){
6610 this.nodeHash[node.id] = node;
6613 unregisterNode : function(node){
6614 delete this.nodeHash[node.id];
6617 toString : function(){
6618 return "[Tree"+(this.id?" "+this.id:"")+"]";
6623 * @class Roo.data.Node
6624 * @extends Roo.util.Observable
6625 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6626 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6628 * @param {Object} attributes The attributes/config for the node
6630 Roo.data.Node = function(attributes){
6632 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6635 this.attributes = attributes || {};
6636 this.leaf = this.attributes.leaf;
6638 * The node id. @type String
6640 this.id = this.attributes.id;
6642 this.id = Roo.id(null, "ynode-");
6643 this.attributes.id = this.id;
6646 * All child nodes of this node. @type Array
6648 this.childNodes = [];
6649 if(!this.childNodes.indexOf){ // indexOf is a must
6650 this.childNodes.indexOf = function(o){
6651 for(var i = 0, len = this.length; i < len; i++){
6660 * The parent node for this node. @type Node
6662 this.parentNode = null;
6664 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6666 this.firstChild = null;
6668 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6670 this.lastChild = null;
6672 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6674 this.previousSibling = null;
6676 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6678 this.nextSibling = null;
6683 * Fires when a new child node is appended
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} node The newly appended node
6687 * @param {Number} index The index of the newly appended node
6692 * Fires when a child node is removed
6693 * @param {Tree} tree The owner tree
6694 * @param {Node} this This node
6695 * @param {Node} node The removed node
6700 * Fires when this node is moved to a new location in the tree
6701 * @param {Tree} tree The owner tree
6702 * @param {Node} this This node
6703 * @param {Node} oldParent The old parent of this node
6704 * @param {Node} newParent The new parent of this node
6705 * @param {Number} index The index it was moved to
6710 * Fires when a new child node is inserted.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node inserted
6714 * @param {Node} refNode The child node the node was inserted before
6718 * @event beforeappend
6719 * Fires before a new child is appended, return false to cancel the append.
6720 * @param {Tree} tree The owner tree
6721 * @param {Node} this This node
6722 * @param {Node} node The child node to be appended
6724 "beforeappend" : true,
6726 * @event beforeremove
6727 * Fires before a child is removed, return false to cancel the remove.
6728 * @param {Tree} tree The owner tree
6729 * @param {Node} this This node
6730 * @param {Node} node The child node to be removed
6732 "beforeremove" : true,
6735 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6736 * @param {Tree} tree The owner tree
6737 * @param {Node} this This node
6738 * @param {Node} oldParent The parent of this node
6739 * @param {Node} newParent The new parent this node is moving to
6740 * @param {Number} index The index it is being moved to
6742 "beforemove" : true,
6744 * @event beforeinsert
6745 * Fires before a new child is inserted, return false to cancel the insert.
6746 * @param {Tree} tree The owner tree
6747 * @param {Node} this This node
6748 * @param {Node} node The child node to be inserted
6749 * @param {Node} refNode The child node the node is being inserted before
6751 "beforeinsert" : true
6753 this.listeners = this.attributes.listeners;
6754 Roo.data.Node.superclass.constructor.call(this);
6757 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6758 fireEvent : function(evtName){
6759 // first do standard event for this node
6760 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6763 // then bubble it up to the tree if the event wasn't cancelled
6764 var ot = this.getOwnerTree();
6766 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6774 * Returns true if this node is a leaf
6777 isLeaf : function(){
6778 return this.leaf === true;
6782 setFirstChild : function(node){
6783 this.firstChild = node;
6787 setLastChild : function(node){
6788 this.lastChild = node;
6793 * Returns true if this node is the last child of its parent
6796 isLast : function(){
6797 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6801 * Returns true if this node is the first child of its parent
6804 isFirst : function(){
6805 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6808 hasChildNodes : function(){
6809 return !this.isLeaf() && this.childNodes.length > 0;
6813 * Insert node(s) as the last child node of this node.
6814 * @param {Node/Array} node The node or Array of nodes to append
6815 * @return {Node} The appended node if single append, or null if an array was passed
6817 appendChild : function(node){
6819 if(node instanceof Array){
6821 }else if(arguments.length > 1){
6824 // if passed an array or multiple args do them one by one
6826 for(var i = 0, len = multi.length; i < len; i++) {
6827 this.appendChild(multi[i]);
6830 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6833 var index = this.childNodes.length;
6834 var oldParent = node.parentNode;
6835 // it's a move, make sure we move it cleanly
6837 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6840 oldParent.removeChild(node);
6842 index = this.childNodes.length;
6844 this.setFirstChild(node);
6846 this.childNodes.push(node);
6847 node.parentNode = this;
6848 var ps = this.childNodes[index-1];
6850 node.previousSibling = ps;
6851 ps.nextSibling = node;
6853 node.previousSibling = null;
6855 node.nextSibling = null;
6856 this.setLastChild(node);
6857 node.setOwnerTree(this.getOwnerTree());
6858 this.fireEvent("append", this.ownerTree, this, node, index);
6860 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6867 * Removes a child node from this node.
6868 * @param {Node} node The node to remove
6869 * @return {Node} The removed node
6871 removeChild : function(node){
6872 var index = this.childNodes.indexOf(node);
6876 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6880 // remove it from childNodes collection
6881 this.childNodes.splice(index, 1);
6884 if(node.previousSibling){
6885 node.previousSibling.nextSibling = node.nextSibling;
6887 if(node.nextSibling){
6888 node.nextSibling.previousSibling = node.previousSibling;
6891 // update child refs
6892 if(this.firstChild == node){
6893 this.setFirstChild(node.nextSibling);
6895 if(this.lastChild == node){
6896 this.setLastChild(node.previousSibling);
6899 node.setOwnerTree(null);
6900 // clear any references from the node
6901 node.parentNode = null;
6902 node.previousSibling = null;
6903 node.nextSibling = null;
6904 this.fireEvent("remove", this.ownerTree, this, node);
6909 * Inserts the first node before the second node in this nodes childNodes collection.
6910 * @param {Node} node The node to insert
6911 * @param {Node} refNode The node to insert before (if null the node is appended)
6912 * @return {Node} The inserted node
6914 insertBefore : function(node, refNode){
6915 if(!refNode){ // like standard Dom, refNode can be null for append
6916 return this.appendChild(node);
6919 if(node == refNode){
6923 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6926 var index = this.childNodes.indexOf(refNode);
6927 var oldParent = node.parentNode;
6928 var refIndex = index;
6930 // when moving internally, indexes will change after remove
6931 if(oldParent == this && this.childNodes.indexOf(node) < index){
6935 // it's a move, make sure we move it cleanly
6937 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6940 oldParent.removeChild(node);
6943 this.setFirstChild(node);
6945 this.childNodes.splice(refIndex, 0, node);
6946 node.parentNode = this;
6947 var ps = this.childNodes[refIndex-1];
6949 node.previousSibling = ps;
6950 ps.nextSibling = node;
6952 node.previousSibling = null;
6954 node.nextSibling = refNode;
6955 refNode.previousSibling = node;
6956 node.setOwnerTree(this.getOwnerTree());
6957 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6959 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6965 * Returns the child node at the specified index.
6966 * @param {Number} index
6969 item : function(index){
6970 return this.childNodes[index];
6974 * Replaces one child node in this node with another.
6975 * @param {Node} newChild The replacement node
6976 * @param {Node} oldChild The node to replace
6977 * @return {Node} The replaced node
6979 replaceChild : function(newChild, oldChild){
6980 this.insertBefore(newChild, oldChild);
6981 this.removeChild(oldChild);
6986 * Returns the index of a child node
6987 * @param {Node} node
6988 * @return {Number} The index of the node or -1 if it was not found
6990 indexOf : function(child){
6991 return this.childNodes.indexOf(child);
6995 * Returns the tree this node is in.
6998 getOwnerTree : function(){
6999 // if it doesn't have one, look for one
7000 if(!this.ownerTree){
7004 this.ownerTree = p.ownerTree;
7010 return this.ownerTree;
7014 * Returns depth of this node (the root node has a depth of 0)
7017 getDepth : function(){
7020 while(p.parentNode){
7028 setOwnerTree : function(tree){
7029 // if it's move, we need to update everyone
7030 if(tree != this.ownerTree){
7032 this.ownerTree.unregisterNode(this);
7034 this.ownerTree = tree;
7035 var cs = this.childNodes;
7036 for(var i = 0, len = cs.length; i < len; i++) {
7037 cs[i].setOwnerTree(tree);
7040 tree.registerNode(this);
7046 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7047 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7048 * @return {String} The path
7050 getPath : function(attr){
7051 attr = attr || "id";
7052 var p = this.parentNode;
7053 var b = [this.attributes[attr]];
7055 b.unshift(p.attributes[attr]);
7058 var sep = this.getOwnerTree().pathSeparator;
7059 return sep + b.join(sep);
7063 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7064 * function call will be the scope provided or the current node. The arguments to the function
7065 * will be the args provided or the current node. If the function returns false at any point,
7066 * the bubble is stopped.
7067 * @param {Function} fn The function to call
7068 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7069 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7071 bubble : function(fn, scope, args){
7074 if(fn.call(scope || p, args || p) === false){
7082 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7083 * function call will be the scope provided or the current node. The arguments to the function
7084 * will be the args provided or the current node. If the function returns false at any point,
7085 * the cascade is stopped on that branch.
7086 * @param {Function} fn The function to call
7087 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7088 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7090 cascade : function(fn, scope, args){
7091 if(fn.call(scope || this, args || this) !== false){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 cs[i].cascade(fn, scope, args);
7100 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7101 * function call will be the scope provided or the current node. The arguments to the function
7102 * will be the args provided or the current node. If the function returns false at any point,
7103 * the iteration stops.
7104 * @param {Function} fn The function to call
7105 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7106 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7108 eachChild : function(fn, scope, args){
7109 var cs = this.childNodes;
7110 for(var i = 0, len = cs.length; i < len; i++) {
7111 if(fn.call(scope || this, args || cs[i]) === false){
7118 * Finds the first child that has the attribute with the specified value.
7119 * @param {String} attribute The attribute name
7120 * @param {Mixed} value The value to search for
7121 * @return {Node} The found child or null if none was found
7123 findChild : function(attribute, value){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(cs[i].attributes[attribute] == value){
7134 * Finds the first child by a custom function. The child matches if the function passed
7136 * @param {Function} fn
7137 * @param {Object} scope (optional)
7138 * @return {Node} The found child or null if none was found
7140 findChildBy : function(fn, scope){
7141 var cs = this.childNodes;
7142 for(var i = 0, len = cs.length; i < len; i++) {
7143 if(fn.call(scope||cs[i], cs[i]) === true){
7151 * Sorts this nodes children using the supplied sort function
7152 * @param {Function} fn
7153 * @param {Object} scope (optional)
7155 sort : function(fn, scope){
7156 var cs = this.childNodes;
7157 var len = cs.length;
7159 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7161 for(var i = 0; i < len; i++){
7163 n.previousSibling = cs[i-1];
7164 n.nextSibling = cs[i+1];
7166 this.setFirstChild(n);
7169 this.setLastChild(n);
7176 * Returns true if this node is an ancestor (at any point) of the passed node.
7177 * @param {Node} node
7180 contains : function(node){
7181 return node.isAncestor(this);
7185 * Returns true if the passed node is an ancestor (at any point) of this node.
7186 * @param {Node} node
7189 isAncestor : function(node){
7190 var p = this.parentNode;
7200 toString : function(){
7201 return "[Node"+(this.id?" "+this.id:"")+"]";
7205 * Ext JS Library 1.1.1
7206 * Copyright(c) 2006-2007, Ext JS, LLC.
7208 * Originally Released Under LGPL - original licence link has changed is not relivant.
7211 * <script type="text/javascript">
7216 * @class Roo.ComponentMgr
7217 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7220 Roo.ComponentMgr = function(){
7221 var all = new Roo.util.MixedCollection();
7225 * Registers a component.
7226 * @param {Roo.Component} c The component
7228 register : function(c){
7233 * Unregisters a component.
7234 * @param {Roo.Component} c The component
7236 unregister : function(c){
7241 * Returns a component by id
7242 * @param {String} id The component id
7249 * Registers a function that will be called when a specified component is added to ComponentMgr
7250 * @param {String} id The component id
7251 * @param {Funtction} fn The callback function
7252 * @param {Object} scope The scope of the callback
7254 onAvailable : function(id, fn, scope){
7255 all.on("add", function(index, o){
7257 fn.call(scope || o, o);
7258 all.un("add", fn, scope);
7265 * Ext JS Library 1.1.1
7266 * Copyright(c) 2006-2007, Ext JS, LLC.
7268 * Originally Released Under LGPL - original licence link has changed is not relivant.
7271 * <script type="text/javascript">
7275 * @class Roo.Component
7276 * @extends Roo.util.Observable
7277 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7278 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7279 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7280 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7281 * All visual components (widgets) that require rendering into a layout should subclass Component.
7283 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7284 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
7285 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7287 Roo.Component = function(config){
7288 config = config || {};
7289 if(config.tagName || config.dom || typeof config == "string"){ // element object
7290 config = {el: config, id: config.id || config};
7292 this.initialConfig = config;
7294 Roo.apply(this, config);
7298 * Fires after the component is disabled.
7299 * @param {Roo.Component} this
7304 * Fires after the component is enabled.
7305 * @param {Roo.Component} this
7310 * Fires before the component is shown. Return false to stop the show.
7311 * @param {Roo.Component} this
7316 * Fires after the component is shown.
7317 * @param {Roo.Component} this
7322 * Fires before the component is hidden. Return false to stop the hide.
7323 * @param {Roo.Component} this
7328 * Fires after the component is hidden.
7329 * @param {Roo.Component} this
7333 * @event beforerender
7334 * Fires before the component is rendered. Return false to stop the render.
7335 * @param {Roo.Component} this
7337 beforerender : true,
7340 * Fires after the component is rendered.
7341 * @param {Roo.Component} this
7345 * @event beforedestroy
7346 * Fires before the component is destroyed. Return false to stop the destroy.
7347 * @param {Roo.Component} this
7349 beforedestroy : true,
7352 * Fires after the component is destroyed.
7353 * @param {Roo.Component} this
7358 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7360 Roo.ComponentMgr.register(this);
7361 Roo.Component.superclass.constructor.call(this);
7362 this.initComponent();
7363 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7364 this.render(this.renderTo);
7365 delete this.renderTo;
7370 Roo.Component.AUTO_ID = 1000;
7372 Roo.extend(Roo.Component, Roo.util.Observable, {
7374 * @property {Boolean} hidden
7375 * true if this component is hidden. Read-only.
7379 * true if this component is disabled. Read-only.
7383 * true if this component has been rendered. Read-only.
7387 /** @cfg {String} disableClass
7388 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7390 disabledClass : "x-item-disabled",
7391 /** @cfg {Boolean} allowDomMove
7392 * Whether the component can move the Dom node when rendering (defaults to true).
7394 allowDomMove : true,
7395 /** @cfg {String} hideMode
7396 * How this component should hidden. Supported values are
7397 * "visibility" (css visibility), "offsets" (negative offset position) and
7398 * "display" (css display) - defaults to "display".
7400 hideMode: 'display',
7403 ctype : "Roo.Component",
7405 /** @cfg {String} actionMode
7406 * which property holds the element that used for hide() / show() / disable() / enable()
7412 getActionEl : function(){
7413 return this[this.actionMode];
7416 initComponent : Roo.emptyFn,
7418 * If this is a lazy rendering component, render it to its container element.
7419 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
7421 render : function(container, position){
7422 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7423 if(!container && this.el){
7424 this.el = Roo.get(this.el);
7425 container = this.el.dom.parentNode;
7426 this.allowDomMove = false;
7428 this.container = Roo.get(container);
7429 this.rendered = true;
7430 if(position !== undefined){
7431 if(typeof position == 'number'){
7432 position = this.container.dom.childNodes[position];
7434 position = Roo.getDom(position);
7437 this.onRender(this.container, position || null);
7439 this.el.addClass(this.cls);
7443 this.el.applyStyles(this.style);
7446 this.fireEvent("render", this);
7447 this.afterRender(this.container);
7459 // default function is not really useful
7460 onRender : function(ct, position){
7462 this.el = Roo.get(this.el);
7463 if(this.allowDomMove !== false){
7464 ct.dom.insertBefore(this.el.dom, position);
7470 getAutoCreate : function(){
7471 var cfg = typeof this.autoCreate == "object" ?
7472 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7473 if(this.id && !cfg.id){
7480 afterRender : Roo.emptyFn,
7483 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7484 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7486 destroy : function(){
7487 if(this.fireEvent("beforedestroy", this) !== false){
7488 this.purgeListeners();
7489 this.beforeDestroy();
7491 this.el.removeAllListeners();
7493 if(this.actionMode == "container"){
7494 this.container.remove();
7498 Roo.ComponentMgr.unregister(this);
7499 this.fireEvent("destroy", this);
7504 beforeDestroy : function(){
7509 onDestroy : function(){
7514 * Returns the underlying {@link Roo.Element}.
7515 * @return {Roo.Element} The element
7522 * Returns the id of this component.
7530 * Try to focus this component.
7531 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7532 * @return {Roo.Component} this
7534 focus : function(selectText){
7537 if(selectText === true){
7538 this.el.dom.select();
7553 * Disable this component.
7554 * @return {Roo.Component} this
7556 disable : function(){
7560 this.disabled = true;
7561 this.fireEvent("disable", this);
7566 onDisable : function(){
7567 this.getActionEl().addClass(this.disabledClass);
7568 this.el.dom.disabled = true;
7572 * Enable this component.
7573 * @return {Roo.Component} this
7575 enable : function(){
7579 this.disabled = false;
7580 this.fireEvent("enable", this);
7585 onEnable : function(){
7586 this.getActionEl().removeClass(this.disabledClass);
7587 this.el.dom.disabled = false;
7591 * Convenience function for setting disabled/enabled by boolean.
7592 * @param {Boolean} disabled
7594 setDisabled : function(disabled){
7595 this[disabled ? "disable" : "enable"]();
7599 * Show this component.
7600 * @return {Roo.Component} this
7603 if(this.fireEvent("beforeshow", this) !== false){
7604 this.hidden = false;
7608 this.fireEvent("show", this);
7614 onShow : function(){
7615 var ae = this.getActionEl();
7616 if(this.hideMode == 'visibility'){
7617 ae.dom.style.visibility = "visible";
7618 }else if(this.hideMode == 'offsets'){
7619 ae.removeClass('x-hidden');
7621 ae.dom.style.display = "";
7626 * Hide this component.
7627 * @return {Roo.Component} this
7630 if(this.fireEvent("beforehide", this) !== false){
7635 this.fireEvent("hide", this);
7641 onHide : function(){
7642 var ae = this.getActionEl();
7643 if(this.hideMode == 'visibility'){
7644 ae.dom.style.visibility = "hidden";
7645 }else if(this.hideMode == 'offsets'){
7646 ae.addClass('x-hidden');
7648 ae.dom.style.display = "none";
7653 * Convenience function to hide or show this component by boolean.
7654 * @param {Boolean} visible True to show, false to hide
7655 * @return {Roo.Component} this
7657 setVisible: function(visible){
7667 * Returns true if this component is visible.
7669 isVisible : function(){
7670 return this.getActionEl().isVisible();
7673 cloneConfig : function(overrides){
7674 overrides = overrides || {};
7675 var id = overrides.id || Roo.id();
7676 var cfg = Roo.applyIf(overrides, this.initialConfig);
7677 cfg.id = id; // prevent dup id
7678 return new this.constructor(cfg);
7682 * Ext JS Library 1.1.1
7683 * Copyright(c) 2006-2007, Ext JS, LLC.
7685 * Originally Released Under LGPL - original licence link has changed is not relivant.
7688 * <script type="text/javascript">
7693 * @extends Roo.Element
7694 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7695 * automatic maintaining of shadow/shim positions.
7696 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7697 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7698 * you can pass a string with a CSS class name. False turns off the shadow.
7699 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7700 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7701 * @cfg {String} cls CSS class to add to the element
7702 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7703 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7705 * @param {Object} config An object with config options.
7706 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7709 Roo.Layer = function(config, existingEl){
7710 config = config || {};
7711 var dh = Roo.DomHelper;
7712 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7714 this.dom = Roo.getDom(existingEl);
7717 var o = config.dh || {tag: "div", cls: "x-layer"};
7718 this.dom = dh.append(pel, o);
7721 this.addClass(config.cls);
7723 this.constrain = config.constrain !== false;
7724 this.visibilityMode = Roo.Element.VISIBILITY;
7726 this.id = this.dom.id = config.id;
7728 this.id = Roo.id(this.dom);
7730 this.zindex = config.zindex || this.getZIndex();
7731 this.position("absolute", this.zindex);
7733 this.shadowOffset = config.shadowOffset || 4;
7734 this.shadow = new Roo.Shadow({
7735 offset : this.shadowOffset,
7736 mode : config.shadow
7739 this.shadowOffset = 0;
7741 this.useShim = config.shim !== false && Roo.useShims;
7742 this.useDisplay = config.useDisplay;
7746 var supr = Roo.Element.prototype;
7748 // shims are shared among layer to keep from having 100 iframes
7751 Roo.extend(Roo.Layer, Roo.Element, {
7753 getZIndex : function(){
7754 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7757 getShim : function(){
7764 var shim = shims.shift();
7766 shim = this.createShim();
7767 shim.enableDisplayMode('block');
7768 shim.dom.style.display = 'none';
7769 shim.dom.style.visibility = 'visible';
7771 var pn = this.dom.parentNode;
7772 if(shim.dom.parentNode != pn){
7773 pn.insertBefore(shim.dom, this.dom);
7775 shim.setStyle('z-index', this.getZIndex()-2);
7780 hideShim : function(){
7782 this.shim.setDisplayed(false);
7783 shims.push(this.shim);
7788 disableShadow : function(){
7790 this.shadowDisabled = true;
7792 this.lastShadowOffset = this.shadowOffset;
7793 this.shadowOffset = 0;
7797 enableShadow : function(show){
7799 this.shadowDisabled = false;
7800 this.shadowOffset = this.lastShadowOffset;
7801 delete this.lastShadowOffset;
7809 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7810 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7811 sync : function(doShow){
7812 var sw = this.shadow;
7813 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7814 var sh = this.getShim();
7816 var w = this.getWidth(),
7817 h = this.getHeight();
7819 var l = this.getLeft(true),
7820 t = this.getTop(true);
7822 if(sw && !this.shadowDisabled){
7823 if(doShow && !sw.isVisible()){
7826 sw.realign(l, t, w, h);
7832 // fit the shim behind the shadow, so it is shimmed too
7833 var a = sw.adjusts, s = sh.dom.style;
7834 s.left = (Math.min(l, l+a.l))+"px";
7835 s.top = (Math.min(t, t+a.t))+"px";
7836 s.width = (w+a.w)+"px";
7837 s.height = (h+a.h)+"px";
7844 sh.setLeftTop(l, t);
7851 destroy : function(){
7856 this.removeAllListeners();
7857 var pn = this.dom.parentNode;
7859 pn.removeChild(this.dom);
7861 Roo.Element.uncache(this.id);
7864 remove : function(){
7869 beginUpdate : function(){
7870 this.updating = true;
7874 endUpdate : function(){
7875 this.updating = false;
7880 hideUnders : function(negOffset){
7888 constrainXY : function(){
7890 var vw = Roo.lib.Dom.getViewWidth(),
7891 vh = Roo.lib.Dom.getViewHeight();
7892 var s = Roo.get(document).getScroll();
7894 var xy = this.getXY();
7895 var x = xy[0], y = xy[1];
7896 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7897 // only move it if it needs it
7899 // first validate right/bottom
7900 if((x + w) > vw+s.left){
7901 x = vw - w - this.shadowOffset;
7904 if((y + h) > vh+s.top){
7905 y = vh - h - this.shadowOffset;
7908 // then make sure top/left isn't negative
7919 var ay = this.avoidY;
7920 if(y <= ay && (y+h) >= ay){
7926 supr.setXY.call(this, xy);
7932 isVisible : function(){
7933 return this.visible;
7937 showAction : function(){
7938 this.visible = true; // track visibility to prevent getStyle calls
7939 if(this.useDisplay === true){
7940 this.setDisplayed("");
7941 }else if(this.lastXY){
7942 supr.setXY.call(this, this.lastXY);
7943 }else if(this.lastLT){
7944 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7949 hideAction : function(){
7950 this.visible = false;
7951 if(this.useDisplay === true){
7952 this.setDisplayed(false);
7954 this.setLeftTop(-10000,-10000);
7958 // overridden Element method
7959 setVisible : function(v, a, d, c, e){
7964 var cb = function(){
7969 }.createDelegate(this);
7970 supr.setVisible.call(this, true, true, d, cb, e);
7973 this.hideUnders(true);
7982 }.createDelegate(this);
7984 supr.setVisible.call(this, v, a, d, cb, e);
7993 storeXY : function(xy){
7998 storeLeftTop : function(left, top){
8000 this.lastLT = [left, top];
8004 beforeFx : function(){
8005 this.beforeAction();
8006 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8010 afterFx : function(){
8011 Roo.Layer.superclass.afterFx.apply(this, arguments);
8012 this.sync(this.isVisible());
8016 beforeAction : function(){
8017 if(!this.updating && this.shadow){
8022 // overridden Element method
8023 setLeft : function(left){
8024 this.storeLeftTop(left, this.getTop(true));
8025 supr.setLeft.apply(this, arguments);
8029 setTop : function(top){
8030 this.storeLeftTop(this.getLeft(true), top);
8031 supr.setTop.apply(this, arguments);
8035 setLeftTop : function(left, top){
8036 this.storeLeftTop(left, top);
8037 supr.setLeftTop.apply(this, arguments);
8041 setXY : function(xy, a, d, c, e){
8043 this.beforeAction();
8045 var cb = this.createCB(c);
8046 supr.setXY.call(this, xy, a, d, cb, e);
8053 createCB : function(c){
8064 // overridden Element method
8065 setX : function(x, a, d, c, e){
8066 this.setXY([x, this.getY()], a, d, c, e);
8069 // overridden Element method
8070 setY : function(y, a, d, c, e){
8071 this.setXY([this.getX(), y], a, d, c, e);
8074 // overridden Element method
8075 setSize : function(w, h, a, d, c, e){
8076 this.beforeAction();
8077 var cb = this.createCB(c);
8078 supr.setSize.call(this, w, h, a, d, cb, e);
8084 // overridden Element method
8085 setWidth : function(w, a, d, c, e){
8086 this.beforeAction();
8087 var cb = this.createCB(c);
8088 supr.setWidth.call(this, w, a, d, cb, e);
8094 // overridden Element method
8095 setHeight : function(h, a, d, c, e){
8096 this.beforeAction();
8097 var cb = this.createCB(c);
8098 supr.setHeight.call(this, h, a, d, cb, e);
8104 // overridden Element method
8105 setBounds : function(x, y, w, h, a, d, c, e){
8106 this.beforeAction();
8107 var cb = this.createCB(c);
8109 this.storeXY([x, y]);
8110 supr.setXY.call(this, [x, y]);
8111 supr.setSize.call(this, w, h, a, d, cb, e);
8114 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8120 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8121 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8122 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8123 * @param {Number} zindex The new z-index to set
8124 * @return {this} The Layer
8126 setZIndex : function(zindex){
8127 this.zindex = zindex;
8128 this.setStyle("z-index", zindex + 2);
8130 this.shadow.setZIndex(zindex + 1);
8133 this.shim.setStyle("z-index", zindex);
8139 * Ext JS Library 1.1.1
8140 * Copyright(c) 2006-2007, Ext JS, LLC.
8142 * Originally Released Under LGPL - original licence link has changed is not relivant.
8145 * <script type="text/javascript">
8151 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8152 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8153 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8155 * Create a new Shadow
8156 * @param {Object} config The config object
8158 Roo.Shadow = function(config){
8159 Roo.apply(this, config);
8160 if(typeof this.mode != "string"){
8161 this.mode = this.defaultMode;
8163 var o = this.offset, a = {h: 0};
8164 var rad = Math.floor(this.offset/2);
8165 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8171 a.l -= this.offset + rad;
8172 a.t -= this.offset + rad;
8183 a.l -= (this.offset - rad);
8184 a.t -= this.offset + rad;
8186 a.w -= (this.offset - rad)*2;
8197 a.l -= (this.offset - rad);
8198 a.t -= (this.offset - rad);
8200 a.w -= (this.offset + rad + 1);
8201 a.h -= (this.offset + rad);
8210 Roo.Shadow.prototype = {
8212 * @cfg {String} mode
8213 * The shadow display mode. Supports the following options:<br />
8214 * sides: Shadow displays on both sides and bottom only<br />
8215 * frame: Shadow displays equally on all four sides<br />
8216 * drop: Traditional bottom-right drop shadow (default)
8219 * @cfg {String} offset
8220 * The number of pixels to offset the shadow from the element (defaults to 4)
8225 defaultMode: "drop",
8228 * Displays the shadow under the target element
8229 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8231 show : function(target){
8232 target = Roo.get(target);
8234 this.el = Roo.Shadow.Pool.pull();
8235 if(this.el.dom.nextSibling != target.dom){
8236 this.el.insertBefore(target);
8239 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8241 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8244 target.getLeft(true),
8245 target.getTop(true),
8249 this.el.dom.style.display = "block";
8253 * Returns true if the shadow is visible, else false
8255 isVisible : function(){
8256 return this.el ? true : false;
8260 * Direct alignment when values are already available. Show must be called at least once before
8261 * calling this method to ensure it is initialized.
8262 * @param {Number} left The target element left position
8263 * @param {Number} top The target element top position
8264 * @param {Number} width The target element width
8265 * @param {Number} height The target element height
8267 realign : function(l, t, w, h){
8271 var a = this.adjusts, d = this.el.dom, s = d.style;
8273 s.left = (l+a.l)+"px";
8274 s.top = (t+a.t)+"px";
8275 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8277 if(s.width != sws || s.height != shs){
8281 var cn = d.childNodes;
8282 var sww = Math.max(0, (sw-12))+"px";
8283 cn[0].childNodes[1].style.width = sww;
8284 cn[1].childNodes[1].style.width = sww;
8285 cn[2].childNodes[1].style.width = sww;
8286 cn[1].style.height = Math.max(0, (sh-12))+"px";
8296 this.el.dom.style.display = "none";
8297 Roo.Shadow.Pool.push(this.el);
8303 * Adjust the z-index of this shadow
8304 * @param {Number} zindex The new z-index
8306 setZIndex : function(z){
8309 this.el.setStyle("z-index", z);
8314 // Private utility class that manages the internal Shadow cache
8315 Roo.Shadow.Pool = function(){
8317 var markup = Roo.isIE ?
8318 '<div class="x-ie-shadow"></div>' :
8319 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
8324 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8325 sh.autoBoxAdjust = false;
8330 push : function(sh){
8336 * Ext JS Library 1.1.1
8337 * Copyright(c) 2006-2007, Ext JS, LLC.
8339 * Originally Released Under LGPL - original licence link has changed is not relivant.
8342 * <script type="text/javascript">
8346 * @class Roo.BoxComponent
8347 * @extends Roo.Component
8348 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8349 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8350 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8351 * layout containers.
8353 * @param {Roo.Element/String/Object} config The configuration options.
8355 Roo.BoxComponent = function(config){
8356 Roo.Component.call(this, config);
8360 * Fires after the component is resized.
8361 * @param {Roo.Component} this
8362 * @param {Number} adjWidth The box-adjusted width that was set
8363 * @param {Number} adjHeight The box-adjusted height that was set
8364 * @param {Number} rawWidth The width that was originally specified
8365 * @param {Number} rawHeight The height that was originally specified
8370 * Fires after the component is moved.
8371 * @param {Roo.Component} this
8372 * @param {Number} x The new x position
8373 * @param {Number} y The new y position
8379 Roo.extend(Roo.BoxComponent, Roo.Component, {
8380 // private, set in afterRender to signify that the component has been rendered
8382 // private, used to defer height settings to subclasses
8384 /** @cfg {Number} width
8385 * width (optional) size of component
8387 /** @cfg {Number} height
8388 * height (optional) size of component
8392 * Sets the width and height of the component. This method fires the resize event. This method can accept
8393 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8394 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8395 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8396 * @return {Roo.BoxComponent} this
8398 setSize : function(w, h){
8399 // support for standard size objects
8400 if(typeof w == 'object'){
8411 // prevent recalcs when not needed
8412 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8415 this.lastSize = {width: w, height: h};
8417 var adj = this.adjustSize(w, h);
8418 var aw = adj.width, ah = adj.height;
8419 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8420 var rz = this.getResizeEl();
8421 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8423 }else if(!this.deferHeight && ah !== undefined){
8425 }else if(aw !== undefined){
8428 this.onResize(aw, ah, w, h);
8429 this.fireEvent('resize', this, aw, ah, w, h);
8435 * Gets the current size of the component's underlying element.
8436 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8438 getSize : function(){
8439 return this.el.getSize();
8443 * Gets the current XY position of the component's underlying element.
8444 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8445 * @return {Array} The XY position of the element (e.g., [100, 200])
8447 getPosition : function(local){
8449 return [this.el.getLeft(true), this.el.getTop(true)];
8451 return this.xy || this.el.getXY();
8455 * Gets the current box measurements of the component's underlying element.
8456 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8457 * @returns {Object} box An object in the format {x, y, width, height}
8459 getBox : function(local){
8460 var s = this.el.getSize();
8462 s.x = this.el.getLeft(true);
8463 s.y = this.el.getTop(true);
8465 var xy = this.xy || this.el.getXY();
8473 * Sets the current box measurements of the component's underlying element.
8474 * @param {Object} box An object in the format {x, y, width, height}
8475 * @returns {Roo.BoxComponent} this
8477 updateBox : function(box){
8478 this.setSize(box.width, box.height);
8479 this.setPagePosition(box.x, box.y);
8484 getResizeEl : function(){
8485 return this.resizeEl || this.el;
8489 getPositionEl : function(){
8490 return this.positionEl || this.el;
8494 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8495 * This method fires the move event.
8496 * @param {Number} left The new left
8497 * @param {Number} top The new top
8498 * @returns {Roo.BoxComponent} this
8500 setPosition : function(x, y){
8506 var adj = this.adjustPosition(x, y);
8507 var ax = adj.x, ay = adj.y;
8509 var el = this.getPositionEl();
8510 if(ax !== undefined || ay !== undefined){
8511 if(ax !== undefined && ay !== undefined){
8512 el.setLeftTop(ax, ay);
8513 }else if(ax !== undefined){
8515 }else if(ay !== undefined){
8518 this.onPosition(ax, ay);
8519 this.fireEvent('move', this, ax, ay);
8525 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8526 * This method fires the move event.
8527 * @param {Number} x The new x position
8528 * @param {Number} y The new y position
8529 * @returns {Roo.BoxComponent} this
8531 setPagePosition : function(x, y){
8537 if(x === undefined || y === undefined){ // cannot translate undefined points
8540 var p = this.el.translatePoints(x, y);
8541 this.setPosition(p.left, p.top);
8546 onRender : function(ct, position){
8547 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8549 this.resizeEl = Roo.get(this.resizeEl);
8551 if(this.positionEl){
8552 this.positionEl = Roo.get(this.positionEl);
8557 afterRender : function(){
8558 Roo.BoxComponent.superclass.afterRender.call(this);
8559 this.boxReady = true;
8560 this.setSize(this.width, this.height);
8561 if(this.x || this.y){
8562 this.setPosition(this.x, this.y);
8564 if(this.pageX || this.pageY){
8565 this.setPagePosition(this.pageX, this.pageY);
8570 * Force the component's size to recalculate based on the underlying element's current height and width.
8571 * @returns {Roo.BoxComponent} this
8573 syncSize : function(){
8574 delete this.lastSize;
8575 this.setSize(this.el.getWidth(), this.el.getHeight());
8580 * Called after the component is resized, this method is empty by default but can be implemented by any
8581 * subclass that needs to perform custom logic after a resize occurs.
8582 * @param {Number} adjWidth The box-adjusted width that was set
8583 * @param {Number} adjHeight The box-adjusted height that was set
8584 * @param {Number} rawWidth The width that was originally specified
8585 * @param {Number} rawHeight The height that was originally specified
8587 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8592 * Called after the component is moved, this method is empty by default but can be implemented by any
8593 * subclass that needs to perform custom logic after a move occurs.
8594 * @param {Number} x The new x position
8595 * @param {Number} y The new y position
8597 onPosition : function(x, y){
8602 adjustSize : function(w, h){
8606 if(this.autoHeight){
8609 return {width : w, height: h};
8613 adjustPosition : function(x, y){
8614 return {x : x, y: y};
8618 * Ext JS Library 1.1.1
8619 * Copyright(c) 2006-2007, Ext JS, LLC.
8621 * Originally Released Under LGPL - original licence link has changed is not relivant.
8624 * <script type="text/javascript">
8629 * @class Roo.SplitBar
8630 * @extends Roo.util.Observable
8631 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8635 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8636 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8637 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8638 split.minSize = 100;
8639 split.maxSize = 600;
8640 split.animate = true;
8641 split.on('moved', splitterMoved);
8644 * Create a new SplitBar
8645 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8646 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8647 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8648 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8649 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8650 position of the SplitBar).
8652 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8655 this.el = Roo.get(dragElement, true);
8656 this.el.dom.unselectable = "on";
8658 this.resizingEl = Roo.get(resizingElement, true);
8662 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8663 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8666 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8669 * The minimum size of the resizing element. (Defaults to 0)
8675 * The maximum size of the resizing element. (Defaults to 2000)
8678 this.maxSize = 2000;
8681 * Whether to animate the transition to the new size
8684 this.animate = false;
8687 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8690 this.useShim = false;
8697 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8699 this.proxy = Roo.get(existingProxy).dom;
8702 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8705 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8708 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8711 this.dragSpecs = {};
8714 * @private The adapter to use to positon and resize elements
8716 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8717 this.adapter.init(this);
8719 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8721 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8722 this.el.addClass("x-splitbar-h");
8725 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8726 this.el.addClass("x-splitbar-v");
8732 * Fires when the splitter is moved (alias for {@link #event-moved})
8733 * @param {Roo.SplitBar} this
8734 * @param {Number} newSize the new width or height
8739 * Fires when the splitter is moved
8740 * @param {Roo.SplitBar} this
8741 * @param {Number} newSize the new width or height
8745 * @event beforeresize
8746 * Fires before the splitter is dragged
8747 * @param {Roo.SplitBar} this
8749 "beforeresize" : true,
8751 "beforeapply" : true
8754 Roo.util.Observable.call(this);
8757 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8758 onStartProxyDrag : function(x, y){
8759 this.fireEvent("beforeresize", this);
8761 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8763 o.enableDisplayMode("block");
8764 // all splitbars share the same overlay
8765 Roo.SplitBar.prototype.overlay = o;
8767 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8768 this.overlay.show();
8769 Roo.get(this.proxy).setDisplayed("block");
8770 var size = this.adapter.getElementSize(this);
8771 this.activeMinSize = this.getMinimumSize();;
8772 this.activeMaxSize = this.getMaximumSize();;
8773 var c1 = size - this.activeMinSize;
8774 var c2 = Math.max(this.activeMaxSize - size, 0);
8775 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8776 this.dd.resetConstraints();
8777 this.dd.setXConstraint(
8778 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8779 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8781 this.dd.setYConstraint(0, 0);
8783 this.dd.resetConstraints();
8784 this.dd.setXConstraint(0, 0);
8785 this.dd.setYConstraint(
8786 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8787 this.placement == Roo.SplitBar.TOP ? c2 : c1
8790 this.dragSpecs.startSize = size;
8791 this.dragSpecs.startPoint = [x, y];
8792 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8796 * @private Called after the drag operation by the DDProxy
8798 onEndProxyDrag : function(e){
8799 Roo.get(this.proxy).setDisplayed(false);
8800 var endPoint = Roo.lib.Event.getXY(e);
8802 this.overlay.hide();
8805 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8806 newSize = this.dragSpecs.startSize +
8807 (this.placement == Roo.SplitBar.LEFT ?
8808 endPoint[0] - this.dragSpecs.startPoint[0] :
8809 this.dragSpecs.startPoint[0] - endPoint[0]
8812 newSize = this.dragSpecs.startSize +
8813 (this.placement == Roo.SplitBar.TOP ?
8814 endPoint[1] - this.dragSpecs.startPoint[1] :
8815 this.dragSpecs.startPoint[1] - endPoint[1]
8818 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8819 if(newSize != this.dragSpecs.startSize){
8820 if(this.fireEvent('beforeapply', this, newSize) !== false){
8821 this.adapter.setElementSize(this, newSize);
8822 this.fireEvent("moved", this, newSize);
8823 this.fireEvent("resize", this, newSize);
8829 * Get the adapter this SplitBar uses
8830 * @return The adapter object
8832 getAdapter : function(){
8833 return this.adapter;
8837 * Set the adapter this SplitBar uses
8838 * @param {Object} adapter A SplitBar adapter object
8840 setAdapter : function(adapter){
8841 this.adapter = adapter;
8842 this.adapter.init(this);
8846 * Gets the minimum size for the resizing element
8847 * @return {Number} The minimum size
8849 getMinimumSize : function(){
8850 return this.minSize;
8854 * Sets the minimum size for the resizing element
8855 * @param {Number} minSize The minimum size
8857 setMinimumSize : function(minSize){
8858 this.minSize = minSize;
8862 * Gets the maximum size for the resizing element
8863 * @return {Number} The maximum size
8865 getMaximumSize : function(){
8866 return this.maxSize;
8870 * Sets the maximum size for the resizing element
8871 * @param {Number} maxSize The maximum size
8873 setMaximumSize : function(maxSize){
8874 this.maxSize = maxSize;
8878 * Sets the initialize size for the resizing element
8879 * @param {Number} size The initial size
8881 setCurrentSize : function(size){
8882 var oldAnimate = this.animate;
8883 this.animate = false;
8884 this.adapter.setElementSize(this, size);
8885 this.animate = oldAnimate;
8889 * Destroy this splitbar.
8890 * @param {Boolean} removeEl True to remove the element
8892 destroy : function(removeEl){
8897 this.proxy.parentNode.removeChild(this.proxy);
8905 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
8907 Roo.SplitBar.createProxy = function(dir){
8908 var proxy = new Roo.Element(document.createElement("div"));
8909 proxy.unselectable();
8910 var cls = 'x-splitbar-proxy';
8911 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8912 document.body.appendChild(proxy.dom);
8917 * @class Roo.SplitBar.BasicLayoutAdapter
8918 * Default Adapter. It assumes the splitter and resizing element are not positioned
8919 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8921 Roo.SplitBar.BasicLayoutAdapter = function(){
8924 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8925 // do nothing for now
8930 * Called before drag operations to get the current size of the resizing element.
8931 * @param {Roo.SplitBar} s The SplitBar using this adapter
8933 getElementSize : function(s){
8934 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8935 return s.resizingEl.getWidth();
8937 return s.resizingEl.getHeight();
8942 * Called after drag operations to set the size of the resizing element.
8943 * @param {Roo.SplitBar} s The SplitBar using this adapter
8944 * @param {Number} newSize The new size to set
8945 * @param {Function} onComplete A function to be invoked when resizing is complete
8947 setElementSize : function(s, newSize, onComplete){
8948 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8950 s.resizingEl.setWidth(newSize);
8952 onComplete(s, newSize);
8955 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8960 s.resizingEl.setHeight(newSize);
8962 onComplete(s, newSize);
8965 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8972 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8973 * @extends Roo.SplitBar.BasicLayoutAdapter
8974 * Adapter that moves the splitter element to align with the resized sizing element.
8975 * Used with an absolute positioned SplitBar.
8976 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8977 * document.body, make sure you assign an id to the body element.
8979 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8980 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8981 this.container = Roo.get(container);
8984 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8989 getElementSize : function(s){
8990 return this.basic.getElementSize(s);
8993 setElementSize : function(s, newSize, onComplete){
8994 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8997 moveSplitter : function(s){
8998 var yes = Roo.SplitBar;
8999 switch(s.placement){
9001 s.el.setX(s.resizingEl.getRight());
9004 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9007 s.el.setY(s.resizingEl.getBottom());
9010 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9017 * Orientation constant - Create a vertical SplitBar
9021 Roo.SplitBar.VERTICAL = 1;
9024 * Orientation constant - Create a horizontal SplitBar
9028 Roo.SplitBar.HORIZONTAL = 2;
9031 * Placement constant - The resizing element is to the left of the splitter element
9035 Roo.SplitBar.LEFT = 1;
9038 * Placement constant - The resizing element is to the right of the splitter element
9042 Roo.SplitBar.RIGHT = 2;
9045 * Placement constant - The resizing element is positioned above the splitter element
9049 Roo.SplitBar.TOP = 3;
9052 * Placement constant - The resizing element is positioned under splitter element
9056 Roo.SplitBar.BOTTOM = 4;
9059 * Ext JS Library 1.1.1
9060 * Copyright(c) 2006-2007, Ext JS, LLC.
9062 * Originally Released Under LGPL - original licence link has changed is not relivant.
9065 * <script type="text/javascript">
9070 * @extends Roo.util.Observable
9071 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9072 * This class also supports single and multi selection modes. <br>
9073 * Create a data model bound view:
9075 var store = new Roo.data.Store(...);
9077 var view = new Roo.View({
9079 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9082 selectedClass: "ydataview-selected",
9086 // listen for node click?
9087 view.on("click", function(vw, index, node, e){
9088 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9092 dataModel.load("foobar.xml");
9094 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9096 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9097 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9099 * Note: old style constructor is still suported (container, template, config)
9103 * @param {Object} config The config object
9106 Roo.View = function(config, depreciated_tpl, depreciated_config){
9108 if (typeof(depreciated_tpl) == 'undefined') {
9109 // new way.. - universal constructor.
9110 Roo.apply(this, config);
9111 this.el = Roo.get(this.el);
9114 this.el = Roo.get(config);
9115 this.tpl = depreciated_tpl;
9116 Roo.apply(this, depreciated_config);
9120 if(typeof(this.tpl) == "string"){
9121 this.tpl = new Roo.Template(this.tpl);
9123 // support xtype ctors..
9124 this.tpl = new Roo.factory(this.tpl, Roo);
9135 * @event beforeclick
9136 * Fires before a click is processed. Returns false to cancel the default action.
9137 * @param {Roo.View} this
9138 * @param {Number} index The index of the target node
9139 * @param {HTMLElement} node The target node
9140 * @param {Roo.EventObject} e The raw event object
9142 "beforeclick" : true,
9145 * Fires when a template node is clicked.
9146 * @param {Roo.View} this
9147 * @param {Number} index The index of the target node
9148 * @param {HTMLElement} node The target node
9149 * @param {Roo.EventObject} e The raw event object
9154 * Fires when a template node is double clicked.
9155 * @param {Roo.View} this
9156 * @param {Number} index The index of the target node
9157 * @param {HTMLElement} node The target node
9158 * @param {Roo.EventObject} e The raw event object
9162 * @event contextmenu
9163 * Fires when a template node is right clicked.
9164 * @param {Roo.View} this
9165 * @param {Number} index The index of the target node
9166 * @param {HTMLElement} node The target node
9167 * @param {Roo.EventObject} e The raw event object
9169 "contextmenu" : true,
9171 * @event selectionchange
9172 * Fires when the selected nodes change.
9173 * @param {Roo.View} this
9174 * @param {Array} selections Array of the selected nodes
9176 "selectionchange" : true,
9179 * @event beforeselect
9180 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9181 * @param {Roo.View} this
9182 * @param {HTMLElement} node The node to be selected
9183 * @param {Array} selections Array of currently selected nodes
9185 "beforeselect" : true
9189 "click": this.onClick,
9190 "dblclick": this.onDblClick,
9191 "contextmenu": this.onContextMenu,
9195 this.selections = [];
9197 this.cmp = new Roo.CompositeElementLite([]);
9199 this.store = Roo.factory(this.store, Roo.data);
9200 this.setStore(this.store, true);
9202 Roo.View.superclass.constructor.call(this);
9205 Roo.extend(Roo.View, Roo.util.Observable, {
9208 * @cfg {Roo.data.Store} store Data store to load data from.
9213 * @cfg {String|Roo.Element} el The container element.
9218 * @cfg {String|Roo.Template} tpl The template used by this View
9223 * @cfg {String} selectedClass The css class to add to selected nodes
9225 selectedClass : "x-view-selected",
9227 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9231 * @cfg {Boolean} multiSelect Allow multiple selection
9234 multiSelect : false,
9236 * @cfg {Boolean} singleSelect Allow single selection
9238 singleSelect: false,
9241 * Returns the element this view is bound to.
9242 * @return {Roo.Element}
9249 * Refreshes the view.
9251 refresh : function(){
9253 this.clearSelections();
9256 var records = this.store.getRange();
9257 if(records.length < 1){
9258 this.el.update(this.emptyText);
9261 for(var i = 0, len = records.length; i < len; i++){
9262 var data = this.prepareData(records[i].data, i, records[i]);
9263 html[html.length] = t.apply(data);
9265 this.el.update(html.join(""));
9266 this.nodes = this.el.dom.childNodes;
9267 this.updateIndexes(0);
9271 * Function to override to reformat the data that is sent to
9272 * the template for each node.
9273 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9274 * a JSON object for an UpdateManager bound view).
9276 prepareData : function(data){
9280 onUpdate : function(ds, record){
9281 this.clearSelections();
9282 var index = this.store.indexOf(record);
9283 var n = this.nodes[index];
9284 this.tpl.insertBefore(n, this.prepareData(record.data));
9285 n.parentNode.removeChild(n);
9286 this.updateIndexes(index, index);
9289 onAdd : function(ds, records, index){
9290 this.clearSelections();
9291 if(this.nodes.length == 0){
9295 var n = this.nodes[index];
9296 for(var i = 0, len = records.length; i < len; i++){
9297 var d = this.prepareData(records[i].data);
9299 this.tpl.insertBefore(n, d);
9301 this.tpl.append(this.el, d);
9304 this.updateIndexes(index);
9307 onRemove : function(ds, record, index){
9308 this.clearSelections();
9309 this.el.dom.removeChild(this.nodes[index]);
9310 this.updateIndexes(index);
9314 * Refresh an individual node.
9315 * @param {Number} index
9317 refreshNode : function(index){
9318 this.onUpdate(this.store, this.store.getAt(index));
9321 updateIndexes : function(startIndex, endIndex){
9322 var ns = this.nodes;
9323 startIndex = startIndex || 0;
9324 endIndex = endIndex || ns.length - 1;
9325 for(var i = startIndex; i <= endIndex; i++){
9326 ns[i].nodeIndex = i;
9331 * Changes the data store this view uses and refresh the view.
9332 * @param {Store} store
9334 setStore : function(store, initial){
9335 if(!initial && this.store){
9336 this.store.un("datachanged", this.refresh);
9337 this.store.un("add", this.onAdd);
9338 this.store.un("remove", this.onRemove);
9339 this.store.un("update", this.onUpdate);
9340 this.store.un("clear", this.refresh);
9344 store.on("datachanged", this.refresh, this);
9345 store.on("add", this.onAdd, this);
9346 store.on("remove", this.onRemove, this);
9347 store.on("update", this.onUpdate, this);
9348 store.on("clear", this.refresh, this);
9357 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9358 * @param {HTMLElement} node
9359 * @return {HTMLElement} The template node
9361 findItemFromChild : function(node){
9362 var el = this.el.dom;
9363 if(!node || node.parentNode == el){
9366 var p = node.parentNode;
9367 while(p && p != el){
9368 if(p.parentNode == el){
9377 onClick : function(e){
9378 var item = this.findItemFromChild(e.getTarget());
9380 var index = this.indexOf(item);
9381 if(this.onItemClick(item, index, e) !== false){
9382 this.fireEvent("click", this, index, item, e);
9385 this.clearSelections();
9390 onContextMenu : function(e){
9391 var item = this.findItemFromChild(e.getTarget());
9393 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9398 onDblClick : function(e){
9399 var item = this.findItemFromChild(e.getTarget());
9401 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9405 onItemClick : function(item, index, e){
9406 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9409 if(this.multiSelect || this.singleSelect){
9410 if(this.multiSelect && e.shiftKey && this.lastSelection){
9411 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9413 this.select(item, this.multiSelect && e.ctrlKey);
9414 this.lastSelection = item;
9422 * Get the number of selected nodes.
9425 getSelectionCount : function(){
9426 return this.selections.length;
9430 * Get the currently selected nodes.
9431 * @return {Array} An array of HTMLElements
9433 getSelectedNodes : function(){
9434 return this.selections;
9438 * Get the indexes of the selected nodes.
9441 getSelectedIndexes : function(){
9442 var indexes = [], s = this.selections;
9443 for(var i = 0, len = s.length; i < len; i++){
9444 indexes.push(s[i].nodeIndex);
9450 * Clear all selections
9451 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9453 clearSelections : function(suppressEvent){
9454 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9455 this.cmp.elements = this.selections;
9456 this.cmp.removeClass(this.selectedClass);
9457 this.selections = [];
9459 this.fireEvent("selectionchange", this, this.selections);
9465 * Returns true if the passed node is selected
9466 * @param {HTMLElement/Number} node The node or node index
9469 isSelected : function(node){
9470 var s = this.selections;
9474 node = this.getNode(node);
9475 return s.indexOf(node) !== -1;
9480 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
9481 * @param {Boolean} keepExisting (optional) true to keep existing selections
9482 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9484 select : function(nodeInfo, keepExisting, suppressEvent){
9485 if(nodeInfo instanceof Array){
9487 this.clearSelections(true);
9489 for(var i = 0, len = nodeInfo.length; i < len; i++){
9490 this.select(nodeInfo[i], true, true);
9493 var node = this.getNode(nodeInfo);
9494 if(node && !this.isSelected(node)){
9496 this.clearSelections(true);
9498 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9499 Roo.fly(node).addClass(this.selectedClass);
9500 this.selections.push(node);
9502 this.fireEvent("selectionchange", this, this.selections);
9510 * Gets a template node.
9511 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9512 * @return {HTMLElement} The node or null if it wasn't found
9514 getNode : function(nodeInfo){
9515 if(typeof nodeInfo == "string"){
9516 return document.getElementById(nodeInfo);
9517 }else if(typeof nodeInfo == "number"){
9518 return this.nodes[nodeInfo];
9524 * Gets a range template nodes.
9525 * @param {Number} startIndex
9526 * @param {Number} endIndex
9527 * @return {Array} An array of nodes
9529 getNodes : function(start, end){
9530 var ns = this.nodes;
9532 end = typeof end == "undefined" ? ns.length - 1 : end;
9535 for(var i = start; i <= end; i++){
9539 for(var i = start; i >= end; i--){
9547 * Finds the index of the passed node
9548 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9549 * @return {Number} The index of the node or -1
9551 indexOf : function(node){
9552 node = this.getNode(node);
9553 if(typeof node.nodeIndex == "number"){
9554 return node.nodeIndex;
9556 var ns = this.nodes;
9557 for(var i = 0, len = ns.length; i < len; i++){
9567 * Ext JS Library 1.1.1
9568 * Copyright(c) 2006-2007, Ext JS, LLC.
9570 * Originally Released Under LGPL - original licence link has changed is not relivant.
9573 * <script type="text/javascript">
9577 * @class Roo.JsonView
9579 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9581 var view = new Roo.JsonView({
9582 container: "my-element",
9583 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9588 // listen for node click?
9589 view.on("click", function(vw, index, node, e){
9590 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9593 // direct load of JSON data
9594 view.load("foobar.php");
9596 // Example from my blog list
9597 var tpl = new Roo.Template(
9598 '<div class="entry">' +
9599 '<a class="entry-title" href="{link}">{title}</a>' +
9600 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9601 "</div><hr />"
9604 var moreView = new Roo.JsonView({
9605 container : "entry-list",
9609 moreView.on("beforerender", this.sortEntries, this);
9611 url: "/blog/get-posts.php",
9612 params: "allposts=true",
9613 text: "Loading Blog Entries..."
9617 * Note: old code is supported with arguments : (container, template, config)
9621 * Create a new JsonView
9623 * @param {Object} config The config object
9626 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9629 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9631 var um = this.el.getUpdateManager();
9632 um.setRenderer(this);
9633 um.on("update", this.onLoad, this);
9634 um.on("failure", this.onLoadException, this);
9637 * @event beforerender
9638 * Fires before rendering of the downloaded JSON data.
9639 * @param {Roo.JsonView} this
9640 * @param {Object} data The JSON data loaded
9644 * Fires when data is loaded.
9645 * @param {Roo.JsonView} this
9646 * @param {Object} data The JSON data loaded
9647 * @param {Object} response The raw Connect response object
9650 * @event loadexception
9651 * Fires when loading fails.
9652 * @param {Roo.JsonView} this
9653 * @param {Object} response The raw Connect response object
9656 'beforerender' : true,
9658 'loadexception' : true
9661 Roo.extend(Roo.JsonView, Roo.View, {
9663 * @type {String} The root property in the loaded JSON object that contains the data
9668 * Refreshes the view.
9670 refresh : function(){
9671 this.clearSelections();
9674 var o = this.jsonData;
9675 if(o && o.length > 0){
9676 for(var i = 0, len = o.length; i < len; i++){
9677 var data = this.prepareData(o[i], i, o);
9678 html[html.length] = this.tpl.apply(data);
9681 html.push(this.emptyText);
9683 this.el.update(html.join(""));
9684 this.nodes = this.el.dom.childNodes;
9685 this.updateIndexes(0);
9689 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
9690 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
9693 url: "your-url.php",
9694 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9695 callback: yourFunction,
9696 scope: yourObject, //(optional scope)
9704 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9705 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
9706 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
9707 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9708 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
9711 var um = this.el.getUpdateManager();
9712 um.update.apply(um, arguments);
9715 render : function(el, response){
9716 this.clearSelections();
9720 o = Roo.util.JSON.decode(response.responseText);
9723 o = o[this.jsonRoot];
9728 * The current JSON data or null
9731 this.beforeRender();
9736 * Get the number of records in the current JSON dataset
9739 getCount : function(){
9740 return this.jsonData ? this.jsonData.length : 0;
9744 * Returns the JSON object for the specified node(s)
9745 * @param {HTMLElement/Array} node The node or an array of nodes
9746 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9747 * you get the JSON object for the node
9749 getNodeData : function(node){
9750 if(node instanceof Array){
9752 for(var i = 0, len = node.length; i < len; i++){
9753 data.push(this.getNodeData(node[i]));
9757 return this.jsonData[this.indexOf(node)] || null;
9760 beforeRender : function(){
9761 this.snapshot = this.jsonData;
9763 this.sort.apply(this, this.sortInfo);
9765 this.fireEvent("beforerender", this, this.jsonData);
9768 onLoad : function(el, o){
9769 this.fireEvent("load", this, this.jsonData, o);
9772 onLoadException : function(el, o){
9773 this.fireEvent("loadexception", this, o);
9777 * Filter the data by a specific property.
9778 * @param {String} property A property on your JSON objects
9779 * @param {String/RegExp} value Either string that the property values
9780 * should start with, or a RegExp to test against the property
9782 filter : function(property, value){
9785 var ss = this.snapshot;
9786 if(typeof value == "string"){
9787 var vlen = value.length;
9792 value = value.toLowerCase();
9793 for(var i = 0, len = ss.length; i < len; i++){
9795 if(o[property].substr(0, vlen).toLowerCase() == value){
9799 } else if(value.exec){ // regex?
9800 for(var i = 0, len = ss.length; i < len; i++){
9802 if(value.test(o[property])){
9809 this.jsonData = data;
9815 * Filter by a function. The passed function will be called with each
9816 * object in the current dataset. If the function returns true the value is kept,
9817 * otherwise it is filtered.
9818 * @param {Function} fn
9819 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9821 filterBy : function(fn, scope){
9824 var ss = this.snapshot;
9825 for(var i = 0, len = ss.length; i < len; i++){
9827 if(fn.call(scope || this, o)){
9831 this.jsonData = data;
9837 * Clears the current filter.
9839 clearFilter : function(){
9840 if(this.snapshot && this.jsonData != this.snapshot){
9841 this.jsonData = this.snapshot;
9848 * Sorts the data for this view and refreshes it.
9849 * @param {String} property A property on your JSON objects to sort on
9850 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9851 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9853 sort : function(property, dir, sortType){
9854 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9857 var dsc = dir && dir.toLowerCase() == "desc";
9858 var f = function(o1, o2){
9859 var v1 = sortType ? sortType(o1[p]) : o1[p];
9860 var v2 = sortType ? sortType(o2[p]) : o2[p];
9863 return dsc ? +1 : -1;
9865 return dsc ? -1 : +1;
9870 this.jsonData.sort(f);
9872 if(this.jsonData != this.snapshot){
9873 this.snapshot.sort(f);
9879 * Ext JS Library 1.1.1
9880 * Copyright(c) 2006-2007, Ext JS, LLC.
9882 * Originally Released Under LGPL - original licence link has changed is not relivant.
9885 * <script type="text/javascript">
9890 * @class Roo.ColorPalette
9891 * @extends Roo.Component
9892 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9893 * Here's an example of typical usage:
9895 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9896 cp.render('my-div');
9898 cp.on('select', function(palette, selColor){
9899 // do something with selColor
9903 * Create a new ColorPalette
9904 * @param {Object} config The config object
9906 Roo.ColorPalette = function(config){
9907 Roo.ColorPalette.superclass.constructor.call(this, config);
9911 * Fires when a color is selected
9912 * @param {ColorPalette} this
9913 * @param {String} color The 6-digit color hex code (without the # symbol)
9919 this.on("select", this.handler, this.scope, true);
9922 Roo.extend(Roo.ColorPalette, Roo.Component, {
9924 * @cfg {String} itemCls
9925 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9927 itemCls : "x-color-palette",
9929 * @cfg {String} value
9930 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9931 * the hex codes are case-sensitive.
9936 ctype: "Roo.ColorPalette",
9939 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9941 allowReselect : false,
9944 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9945 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9946 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9947 * of colors with the width setting until the box is symmetrical.</p>
9948 * <p>You can override individual colors if needed:</p>
9950 var cp = new Roo.ColorPalette();
9951 cp.colors[0] = "FF0000"; // change the first box to red
9954 Or you can provide a custom array of your own for complete control:
9956 var cp = new Roo.ColorPalette();
9957 cp.colors = ["000000", "993300", "333300"];
9962 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9963 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9964 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9965 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9966 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9970 onRender : function(container, position){
9971 var t = new Roo.MasterTemplate(
9972 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9974 var c = this.colors;
9975 for(var i = 0, len = c.length; i < len; i++){
9978 var el = document.createElement("div");
9979 el.className = this.itemCls;
9981 container.dom.insertBefore(el, position);
9982 this.el = Roo.get(el);
9983 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9984 if(this.clickEvent != 'click'){
9985 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9990 afterRender : function(){
9991 Roo.ColorPalette.superclass.afterRender.call(this);
10000 handleClick : function(e, t){
10001 e.preventDefault();
10002 if(!this.disabled){
10003 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10004 this.select(c.toUpperCase());
10009 * Selects the specified color in the palette (fires the select event)
10010 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10012 select : function(color){
10013 color = color.replace("#", "");
10014 if(color != this.value || this.allowReselect){
10017 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10019 el.child("a.color-"+color).addClass("x-color-palette-sel");
10020 this.value = color;
10021 this.fireEvent("select", this, color);
10026 * Ext JS Library 1.1.1
10027 * Copyright(c) 2006-2007, Ext JS, LLC.
10029 * Originally Released Under LGPL - original licence link has changed is not relivant.
10032 * <script type="text/javascript">
10036 * @class Roo.DatePicker
10037 * @extends Roo.Component
10038 * Simple date picker class.
10040 * Create a new DatePicker
10041 * @param {Object} config The config object
10043 Roo.DatePicker = function(config){
10044 Roo.DatePicker.superclass.constructor.call(this, config);
10046 this.value = config && config.value ?
10047 config.value.clearTime() : new Date().clearTime();
10052 * Fires when a date is selected
10053 * @param {DatePicker} this
10054 * @param {Date} date The selected date
10060 this.on("select", this.handler, this.scope || this);
10062 // build the disabledDatesRE
10063 if(!this.disabledDatesRE && this.disabledDates){
10064 var dd = this.disabledDates;
10066 for(var i = 0; i < dd.length; i++){
10068 if(i != dd.length-1) re += "|";
10070 this.disabledDatesRE = new RegExp(re + ")");
10074 Roo.extend(Roo.DatePicker, Roo.Component, {
10076 * @cfg {String} todayText
10077 * The text to display on the button that selects the current date (defaults to "Today")
10079 todayText : "Today",
10081 * @cfg {String} okText
10082 * The text to display on the ok button
10084 okText : " OK ", //   to give the user extra clicking room
10086 * @cfg {String} cancelText
10087 * The text to display on the cancel button
10089 cancelText : "Cancel",
10091 * @cfg {String} todayTip
10092 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10094 todayTip : "{0} (Spacebar)",
10096 * @cfg {Date} minDate
10097 * Minimum allowable date (JavaScript date object, defaults to null)
10101 * @cfg {Date} maxDate
10102 * Maximum allowable date (JavaScript date object, defaults to null)
10106 * @cfg {String} minText
10107 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10109 minText : "This date is before the minimum date",
10111 * @cfg {String} maxText
10112 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10114 maxText : "This date is after the maximum date",
10116 * @cfg {String} format
10117 * The default date format string which can be overriden for localization support. The format must be
10118 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10122 * @cfg {Array} disabledDays
10123 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10125 disabledDays : null,
10127 * @cfg {String} disabledDaysText
10128 * The tooltip to display when the date falls on a disabled day (defaults to "")
10130 disabledDaysText : "",
10132 * @cfg {RegExp} disabledDatesRE
10133 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10135 disabledDatesRE : null,
10137 * @cfg {String} disabledDatesText
10138 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10140 disabledDatesText : "",
10142 * @cfg {Boolean} constrainToViewport
10143 * True to constrain the date picker to the viewport (defaults to true)
10145 constrainToViewport : true,
10147 * @cfg {Array} monthNames
10148 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10150 monthNames : Date.monthNames,
10152 * @cfg {Array} dayNames
10153 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10155 dayNames : Date.dayNames,
10157 * @cfg {String} nextText
10158 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10160 nextText: 'Next Month (Control+Right)',
10162 * @cfg {String} prevText
10163 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10165 prevText: 'Previous Month (Control+Left)',
10167 * @cfg {String} monthYearText
10168 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10170 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10172 * @cfg {Number} startDay
10173 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10177 * @cfg {Bool} showClear
10178 * Show a clear button (usefull for date form elements that can be blank.)
10184 * Sets the value of the date field
10185 * @param {Date} value The date to set
10187 setValue : function(value){
10188 var old = this.value;
10189 this.value = value.clearTime(true);
10191 this.update(this.value);
10196 * Gets the current selected value of the date field
10197 * @return {Date} The selected date
10199 getValue : function(){
10204 focus : function(){
10206 this.update(this.activeDate);
10211 onRender : function(container, position){
10213 '<table cellspacing="0">',
10214 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
10215 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10216 var dn = this.dayNames;
10217 for(var i = 0; i < 7; i++){
10218 var d = this.startDay+i;
10222 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10224 m[m.length] = "</tr></thead><tbody><tr>";
10225 for(var i = 0; i < 42; i++) {
10226 if(i % 7 == 0 && i != 0){
10227 m[m.length] = "</tr><tr>";
10229 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10231 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10232 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10234 var el = document.createElement("div");
10235 el.className = "x-date-picker";
10236 el.innerHTML = m.join("");
10238 container.dom.insertBefore(el, position);
10240 this.el = Roo.get(el);
10241 this.eventEl = Roo.get(el.firstChild);
10243 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10244 handler: this.showPrevMonth,
10246 preventDefault:true,
10250 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10251 handler: this.showNextMonth,
10253 preventDefault:true,
10257 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10259 this.monthPicker = this.el.down('div.x-date-mp');
10260 this.monthPicker.enableDisplayMode('block');
10262 var kn = new Roo.KeyNav(this.eventEl, {
10263 "left" : function(e){
10265 this.showPrevMonth() :
10266 this.update(this.activeDate.add("d", -1));
10269 "right" : function(e){
10271 this.showNextMonth() :
10272 this.update(this.activeDate.add("d", 1));
10275 "up" : function(e){
10277 this.showNextYear() :
10278 this.update(this.activeDate.add("d", -7));
10281 "down" : function(e){
10283 this.showPrevYear() :
10284 this.update(this.activeDate.add("d", 7));
10287 "pageUp" : function(e){
10288 this.showNextMonth();
10291 "pageDown" : function(e){
10292 this.showPrevMonth();
10295 "enter" : function(e){
10296 e.stopPropagation();
10303 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10305 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10307 this.el.unselectable();
10309 this.cells = this.el.select("table.x-date-inner tbody td");
10310 this.textNodes = this.el.query("table.x-date-inner tbody span");
10312 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10314 tooltip: this.monthYearText
10317 this.mbtn.on('click', this.showMonthPicker, this);
10318 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10321 var today = (new Date()).dateFormat(this.format);
10323 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10324 if (this.showClear) {
10325 baseTb.add( new Roo.Toolbar.Fill());
10328 text: String.format(this.todayText, today),
10329 tooltip: String.format(this.todayTip, today),
10330 handler: this.selectToday,
10334 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10337 if (this.showClear) {
10339 baseTb.add( new Roo.Toolbar.Fill());
10342 cls: 'x-btn-icon x-btn-clear',
10343 handler: function() {
10345 this.fireEvent("select", this, '');
10355 this.update(this.value);
10358 createMonthPicker : function(){
10359 if(!this.monthPicker.dom.firstChild){
10360 var buf = ['<table border="0" cellspacing="0">'];
10361 for(var i = 0; i < 6; i++){
10363 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10364 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10366 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
10367 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10371 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10373 '</button><button type="button" class="x-date-mp-cancel">',
10375 '</button></td></tr>',
10378 this.monthPicker.update(buf.join(''));
10379 this.monthPicker.on('click', this.onMonthClick, this);
10380 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10382 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10383 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10385 this.mpMonths.each(function(m, a, i){
10388 m.dom.xmonth = 5 + Math.round(i * .5);
10390 m.dom.xmonth = Math.round((i-1) * .5);
10396 showMonthPicker : function(){
10397 this.createMonthPicker();
10398 var size = this.el.getSize();
10399 this.monthPicker.setSize(size);
10400 this.monthPicker.child('table').setSize(size);
10402 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10403 this.updateMPMonth(this.mpSelMonth);
10404 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10405 this.updateMPYear(this.mpSelYear);
10407 this.monthPicker.slideIn('t', {duration:.2});
10410 updateMPYear : function(y){
10412 var ys = this.mpYears.elements;
10413 for(var i = 1; i <= 10; i++){
10414 var td = ys[i-1], y2;
10416 y2 = y + Math.round(i * .5);
10417 td.firstChild.innerHTML = y2;
10420 y2 = y - (5-Math.round(i * .5));
10421 td.firstChild.innerHTML = y2;
10424 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10428 updateMPMonth : function(sm){
10429 this.mpMonths.each(function(m, a, i){
10430 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10434 selectMPMonth: function(m){
10438 onMonthClick : function(e, t){
10440 var el = new Roo.Element(t), pn;
10441 if(el.is('button.x-date-mp-cancel')){
10442 this.hideMonthPicker();
10444 else if(el.is('button.x-date-mp-ok')){
10445 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10446 this.hideMonthPicker();
10448 else if(pn = el.up('td.x-date-mp-month', 2)){
10449 this.mpMonths.removeClass('x-date-mp-sel');
10450 pn.addClass('x-date-mp-sel');
10451 this.mpSelMonth = pn.dom.xmonth;
10453 else if(pn = el.up('td.x-date-mp-year', 2)){
10454 this.mpYears.removeClass('x-date-mp-sel');
10455 pn.addClass('x-date-mp-sel');
10456 this.mpSelYear = pn.dom.xyear;
10458 else if(el.is('a.x-date-mp-prev')){
10459 this.updateMPYear(this.mpyear-10);
10461 else if(el.is('a.x-date-mp-next')){
10462 this.updateMPYear(this.mpyear+10);
10466 onMonthDblClick : function(e, t){
10468 var el = new Roo.Element(t), pn;
10469 if(pn = el.up('td.x-date-mp-month', 2)){
10470 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10471 this.hideMonthPicker();
10473 else if(pn = el.up('td.x-date-mp-year', 2)){
10474 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10475 this.hideMonthPicker();
10479 hideMonthPicker : function(disableAnim){
10480 if(this.monthPicker){
10481 if(disableAnim === true){
10482 this.monthPicker.hide();
10484 this.monthPicker.slideOut('t', {duration:.2});
10490 showPrevMonth : function(e){
10491 this.update(this.activeDate.add("mo", -1));
10495 showNextMonth : function(e){
10496 this.update(this.activeDate.add("mo", 1));
10500 showPrevYear : function(){
10501 this.update(this.activeDate.add("y", -1));
10505 showNextYear : function(){
10506 this.update(this.activeDate.add("y", 1));
10510 handleMouseWheel : function(e){
10511 var delta = e.getWheelDelta();
10513 this.showPrevMonth();
10515 } else if(delta < 0){
10516 this.showNextMonth();
10522 handleDateClick : function(e, t){
10524 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10525 this.setValue(new Date(t.dateValue));
10526 this.fireEvent("select", this, this.value);
10531 selectToday : function(){
10532 this.setValue(new Date().clearTime());
10533 this.fireEvent("select", this, this.value);
10537 update : function(date){
10538 var vd = this.activeDate;
10539 this.activeDate = date;
10541 var t = date.getTime();
10542 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10543 this.cells.removeClass("x-date-selected");
10544 this.cells.each(function(c){
10545 if(c.dom.firstChild.dateValue == t){
10546 c.addClass("x-date-selected");
10547 setTimeout(function(){
10548 try{c.dom.firstChild.focus();}catch(e){}
10556 var days = date.getDaysInMonth();
10557 var firstOfMonth = date.getFirstDateOfMonth();
10558 var startingPos = firstOfMonth.getDay()-this.startDay;
10560 if(startingPos <= this.startDay){
10564 var pm = date.add("mo", -1);
10565 var prevStart = pm.getDaysInMonth()-startingPos;
10567 var cells = this.cells.elements;
10568 var textEls = this.textNodes;
10569 days += startingPos;
10571 // convert everything to numbers so it's fast
10572 var day = 86400000;
10573 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10574 var today = new Date().clearTime().getTime();
10575 var sel = date.clearTime().getTime();
10576 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10577 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10578 var ddMatch = this.disabledDatesRE;
10579 var ddText = this.disabledDatesText;
10580 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10581 var ddaysText = this.disabledDaysText;
10582 var format = this.format;
10584 var setCellClass = function(cal, cell){
10586 var t = d.getTime();
10587 cell.firstChild.dateValue = t;
10589 cell.className += " x-date-today";
10590 cell.title = cal.todayText;
10593 cell.className += " x-date-selected";
10594 setTimeout(function(){
10595 try{cell.firstChild.focus();}catch(e){}
10600 cell.className = " x-date-disabled";
10601 cell.title = cal.minText;
10605 cell.className = " x-date-disabled";
10606 cell.title = cal.maxText;
10610 if(ddays.indexOf(d.getDay()) != -1){
10611 cell.title = ddaysText;
10612 cell.className = " x-date-disabled";
10615 if(ddMatch && format){
10616 var fvalue = d.dateFormat(format);
10617 if(ddMatch.test(fvalue)){
10618 cell.title = ddText.replace("%0", fvalue);
10619 cell.className = " x-date-disabled";
10625 for(; i < startingPos; i++) {
10626 textEls[i].innerHTML = (++prevStart);
10627 d.setDate(d.getDate()+1);
10628 cells[i].className = "x-date-prevday";
10629 setCellClass(this, cells[i]);
10631 for(; i < days; i++){
10632 intDay = i - startingPos + 1;
10633 textEls[i].innerHTML = (intDay);
10634 d.setDate(d.getDate()+1);
10635 cells[i].className = "x-date-active";
10636 setCellClass(this, cells[i]);
10639 for(; i < 42; i++) {
10640 textEls[i].innerHTML = (++extraDays);
10641 d.setDate(d.getDate()+1);
10642 cells[i].className = "x-date-nextday";
10643 setCellClass(this, cells[i]);
10646 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10648 if(!this.internalRender){
10649 var main = this.el.dom.firstChild;
10650 var w = main.offsetWidth;
10651 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10652 Roo.fly(main).setWidth(w);
10653 this.internalRender = true;
10654 // opera does not respect the auto grow header center column
10655 // then, after it gets a width opera refuses to recalculate
10656 // without a second pass
10657 if(Roo.isOpera && !this.secondPass){
10658 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10659 this.secondPass = true;
10660 this.update.defer(10, this, [date]);
10666 * Ext JS Library 1.1.1
10667 * Copyright(c) 2006-2007, Ext JS, LLC.
10669 * Originally Released Under LGPL - original licence link has changed is not relivant.
10672 * <script type="text/javascript">
10675 * @class Roo.TabPanel
10676 * @extends Roo.util.Observable
10677 * A lightweight tab container.
10681 // basic tabs 1, built from existing content
10682 var tabs = new Roo.TabPanel("tabs1");
10683 tabs.addTab("script", "View Script");
10684 tabs.addTab("markup", "View Markup");
10685 tabs.activate("script");
10687 // more advanced tabs, built from javascript
10688 var jtabs = new Roo.TabPanel("jtabs");
10689 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10691 // set up the UpdateManager
10692 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10693 var updater = tab2.getUpdateManager();
10694 updater.setDefaultUrl("ajax1.htm");
10695 tab2.on('activate', updater.refresh, updater, true);
10697 // Use setUrl for Ajax loading
10698 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10699 tab3.setUrl("ajax2.htm", null, true);
10702 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10705 jtabs.activate("jtabs-1");
10708 * Create a new TabPanel.
10709 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10710 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10712 Roo.TabPanel = function(container, config){
10714 * The container element for this TabPanel.
10715 * @type Roo.Element
10717 this.el = Roo.get(container, true);
10719 if(typeof config == "boolean"){
10720 this.tabPosition = config ? "bottom" : "top";
10722 Roo.apply(this, config);
10725 if(this.tabPosition == "bottom"){
10726 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10727 this.el.addClass("x-tabs-bottom");
10729 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10730 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10731 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10733 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10735 if(this.tabPosition != "bottom"){
10736 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10737 * @type Roo.Element
10739 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10740 this.el.addClass("x-tabs-top");
10744 this.bodyEl.setStyle("position", "relative");
10746 this.active = null;
10747 this.activateDelegate = this.activate.createDelegate(this);
10752 * Fires when the active tab changes
10753 * @param {Roo.TabPanel} this
10754 * @param {Roo.TabPanelItem} activePanel The new active tab
10758 * @event beforetabchange
10759 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10760 * @param {Roo.TabPanel} this
10761 * @param {Object} e Set cancel to true on this object to cancel the tab change
10762 * @param {Roo.TabPanelItem} tab The tab being changed to
10764 "beforetabchange" : true
10767 Roo.EventManager.onWindowResize(this.onResize, this);
10768 this.cpad = this.el.getPadding("lr");
10769 this.hiddenCount = 0;
10771 Roo.TabPanel.superclass.constructor.call(this);
10774 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10776 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10778 tabPosition : "top",
10780 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10782 currentTabWidth : 0,
10784 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10788 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10792 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10794 preferredTabWidth : 175,
10796 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10798 resizeTabs : false,
10800 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10802 monitorResize : true,
10805 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10806 * @param {String} id The id of the div to use <b>or create</b>
10807 * @param {String} text The text for the tab
10808 * @param {String} content (optional) Content to put in the TabPanelItem body
10809 * @param {Boolean} closable (optional) True to create a close icon on the tab
10810 * @return {Roo.TabPanelItem} The created TabPanelItem
10812 addTab : function(id, text, content, closable){
10813 var item = new Roo.TabPanelItem(this, id, text, closable);
10814 this.addTabItem(item);
10816 item.setContent(content);
10822 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10823 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10824 * @return {Roo.TabPanelItem}
10826 getTab : function(id){
10827 return this.items[id];
10831 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10832 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10834 hideTab : function(id){
10835 var t = this.items[id];
10838 this.hiddenCount++;
10839 this.autoSizeTabs();
10844 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10845 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10847 unhideTab : function(id){
10848 var t = this.items[id];
10850 t.setHidden(false);
10851 this.hiddenCount--;
10852 this.autoSizeTabs();
10857 * Adds an existing {@link Roo.TabPanelItem}.
10858 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10860 addTabItem : function(item){
10861 this.items[item.id] = item;
10862 this.items.push(item);
10863 if(this.resizeTabs){
10864 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10865 this.autoSizeTabs();
10872 * Removes a {@link Roo.TabPanelItem}.
10873 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10875 removeTab : function(id){
10876 var items = this.items;
10877 var tab = items[id];
10878 if(!tab) { return; }
10879 var index = items.indexOf(tab);
10880 if(this.active == tab && items.length > 1){
10881 var newTab = this.getNextAvailable(index);
10886 this.stripEl.dom.removeChild(tab.pnode.dom);
10887 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10888 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10890 items.splice(index, 1);
10891 delete this.items[tab.id];
10892 tab.fireEvent("close", tab);
10893 tab.purgeListeners();
10894 this.autoSizeTabs();
10897 getNextAvailable : function(start){
10898 var items = this.items;
10900 // look for a next tab that will slide over to
10901 // replace the one being removed
10902 while(index < items.length){
10903 var item = items[++index];
10904 if(item && !item.isHidden()){
10908 // if one isn't found select the previous tab (on the left)
10911 var item = items[--index];
10912 if(item && !item.isHidden()){
10920 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10921 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10923 disableTab : function(id){
10924 var tab = this.items[id];
10925 if(tab && this.active != tab){
10931 * Enables a {@link Roo.TabPanelItem} that is disabled.
10932 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10934 enableTab : function(id){
10935 var tab = this.items[id];
10940 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10941 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10942 * @return {Roo.TabPanelItem} The TabPanelItem.
10944 activate : function(id){
10945 var tab = this.items[id];
10949 if(tab == this.active || tab.disabled){
10953 this.fireEvent("beforetabchange", this, e, tab);
10954 if(e.cancel !== true && !tab.disabled){
10956 this.active.hide();
10958 this.active = this.items[id];
10959 this.active.show();
10960 this.fireEvent("tabchange", this, this.active);
10966 * Gets the active {@link Roo.TabPanelItem}.
10967 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10969 getActiveTab : function(){
10970 return this.active;
10974 * Updates the tab body element to fit the height of the container element
10975 * for overflow scrolling
10976 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10978 syncHeight : function(targetHeight){
10979 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10980 var bm = this.bodyEl.getMargins();
10981 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10982 this.bodyEl.setHeight(newHeight);
10986 onResize : function(){
10987 if(this.monitorResize){
10988 this.autoSizeTabs();
10993 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10995 beginUpdate : function(){
10996 this.updating = true;
11000 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11002 endUpdate : function(){
11003 this.updating = false;
11004 this.autoSizeTabs();
11008 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11010 autoSizeTabs : function(){
11011 var count = this.items.length;
11012 var vcount = count - this.hiddenCount;
11013 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11014 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11015 var availWidth = Math.floor(w / vcount);
11016 var b = this.stripBody;
11017 if(b.getWidth() > w){
11018 var tabs = this.items;
11019 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11020 if(availWidth < this.minTabWidth){
11021 /*if(!this.sleft){ // incomplete scrolling code
11022 this.createScrollButtons();
11025 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11028 if(this.currentTabWidth < this.preferredTabWidth){
11029 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11035 * Returns the number of tabs in this TabPanel.
11038 getCount : function(){
11039 return this.items.length;
11043 * Resizes all the tabs to the passed width
11044 * @param {Number} The new width
11046 setTabWidth : function(width){
11047 this.currentTabWidth = width;
11048 for(var i = 0, len = this.items.length; i < len; i++) {
11049 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11054 * Destroys this TabPanel
11055 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11057 destroy : function(removeEl){
11058 Roo.EventManager.removeResizeListener(this.onResize, this);
11059 for(var i = 0, len = this.items.length; i < len; i++){
11060 this.items[i].purgeListeners();
11062 if(removeEl === true){
11063 this.el.update("");
11070 * @class Roo.TabPanelItem
11071 * @extends Roo.util.Observable
11072 * Represents an individual item (tab plus body) in a TabPanel.
11073 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11074 * @param {String} id The id of this TabPanelItem
11075 * @param {String} text The text for the tab of this TabPanelItem
11076 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11078 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11080 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11081 * @type Roo.TabPanel
11083 this.tabPanel = tabPanel;
11085 * The id for this TabPanelItem
11090 this.disabled = false;
11094 this.loaded = false;
11095 this.closable = closable;
11098 * The body element for this TabPanelItem.
11099 * @type Roo.Element
11101 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11102 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11103 this.bodyEl.setStyle("display", "block");
11104 this.bodyEl.setStyle("zoom", "1");
11107 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11109 this.el = Roo.get(els.el, true);
11110 this.inner = Roo.get(els.inner, true);
11111 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11112 this.pnode = Roo.get(els.el.parentNode, true);
11113 this.el.on("mousedown", this.onTabMouseDown, this);
11114 this.el.on("click", this.onTabClick, this);
11117 var c = Roo.get(els.close, true);
11118 c.dom.title = this.closeText;
11119 c.addClassOnOver("close-over");
11120 c.on("click", this.closeClick, this);
11126 * Fires when this tab becomes the active tab.
11127 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11128 * @param {Roo.TabPanelItem} this
11132 * @event beforeclose
11133 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11134 * @param {Roo.TabPanelItem} this
11135 * @param {Object} e Set cancel to true on this object to cancel the close.
11137 "beforeclose": true,
11140 * Fires when this tab is closed.
11141 * @param {Roo.TabPanelItem} this
11145 * @event deactivate
11146 * Fires when this tab is no longer the active tab.
11147 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11148 * @param {Roo.TabPanelItem} this
11150 "deactivate" : true
11152 this.hidden = false;
11154 Roo.TabPanelItem.superclass.constructor.call(this);
11157 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11158 purgeListeners : function(){
11159 Roo.util.Observable.prototype.purgeListeners.call(this);
11160 this.el.removeAllListeners();
11163 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11166 this.pnode.addClass("on");
11169 this.tabPanel.stripWrap.repaint();
11171 this.fireEvent("activate", this.tabPanel, this);
11175 * Returns true if this tab is the active tab.
11176 * @return {Boolean}
11178 isActive : function(){
11179 return this.tabPanel.getActiveTab() == this;
11183 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11186 this.pnode.removeClass("on");
11188 this.fireEvent("deactivate", this.tabPanel, this);
11191 hideAction : function(){
11192 this.bodyEl.hide();
11193 this.bodyEl.setStyle("position", "absolute");
11194 this.bodyEl.setLeft("-20000px");
11195 this.bodyEl.setTop("-20000px");
11198 showAction : function(){
11199 this.bodyEl.setStyle("position", "relative");
11200 this.bodyEl.setTop("");
11201 this.bodyEl.setLeft("");
11202 this.bodyEl.show();
11206 * Set the tooltip for the tab.
11207 * @param {String} tooltip The tab's tooltip
11209 setTooltip : function(text){
11210 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11211 this.textEl.dom.qtip = text;
11212 this.textEl.dom.removeAttribute('title');
11214 this.textEl.dom.title = text;
11218 onTabClick : function(e){
11219 e.preventDefault();
11220 this.tabPanel.activate(this.id);
11223 onTabMouseDown : function(e){
11224 e.preventDefault();
11225 this.tabPanel.activate(this.id);
11228 getWidth : function(){
11229 return this.inner.getWidth();
11232 setWidth : function(width){
11233 var iwidth = width - this.pnode.getPadding("lr");
11234 this.inner.setWidth(iwidth);
11235 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11236 this.pnode.setWidth(width);
11240 * Show or hide the tab
11241 * @param {Boolean} hidden True to hide or false to show.
11243 setHidden : function(hidden){
11244 this.hidden = hidden;
11245 this.pnode.setStyle("display", hidden ? "none" : "");
11249 * Returns true if this tab is "hidden"
11250 * @return {Boolean}
11252 isHidden : function(){
11253 return this.hidden;
11257 * Returns the text for this tab
11260 getText : function(){
11264 autoSize : function(){
11265 //this.el.beginMeasure();
11266 this.textEl.setWidth(1);
11267 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11268 //this.el.endMeasure();
11272 * Sets the text for the tab (Note: this also sets the tooltip text)
11273 * @param {String} text The tab's text and tooltip
11275 setText : function(text){
11277 this.textEl.update(text);
11278 this.setTooltip(text);
11279 if(!this.tabPanel.resizeTabs){
11284 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11286 activate : function(){
11287 this.tabPanel.activate(this.id);
11291 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11293 disable : function(){
11294 if(this.tabPanel.active != this){
11295 this.disabled = true;
11296 this.pnode.addClass("disabled");
11301 * Enables this TabPanelItem if it was previously disabled.
11303 enable : function(){
11304 this.disabled = false;
11305 this.pnode.removeClass("disabled");
11309 * Sets the content for this TabPanelItem.
11310 * @param {String} content The content
11311 * @param {Boolean} loadScripts true to look for and load scripts
11313 setContent : function(content, loadScripts){
11314 this.bodyEl.update(content, loadScripts);
11318 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11319 * @return {Roo.UpdateManager} The UpdateManager
11321 getUpdateManager : function(){
11322 return this.bodyEl.getUpdateManager();
11326 * Set a URL to be used to load the content for this TabPanelItem.
11327 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11328 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
11329 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
11330 * @return {Roo.UpdateManager} The UpdateManager
11332 setUrl : function(url, params, loadOnce){
11333 if(this.refreshDelegate){
11334 this.un('activate', this.refreshDelegate);
11336 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11337 this.on("activate", this.refreshDelegate);
11338 return this.bodyEl.getUpdateManager();
11342 _handleRefresh : function(url, params, loadOnce){
11343 if(!loadOnce || !this.loaded){
11344 var updater = this.bodyEl.getUpdateManager();
11345 updater.update(url, params, this._setLoaded.createDelegate(this));
11350 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11351 * Will fail silently if the setUrl method has not been called.
11352 * This does not activate the panel, just updates its content.
11354 refresh : function(){
11355 if(this.refreshDelegate){
11356 this.loaded = false;
11357 this.refreshDelegate();
11362 _setLoaded : function(){
11363 this.loaded = true;
11367 closeClick : function(e){
11370 this.fireEvent("beforeclose", this, o);
11371 if(o.cancel !== true){
11372 this.tabPanel.removeTab(this.id);
11376 * The text displayed in the tooltip for the close icon.
11379 closeText : "Close this tab"
11383 Roo.TabPanel.prototype.createStrip = function(container){
11384 var strip = document.createElement("div");
11385 strip.className = "x-tabs-wrap";
11386 container.appendChild(strip);
11390 Roo.TabPanel.prototype.createStripList = function(strip){
11391 // div wrapper for retard IE
11392 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11393 return strip.firstChild.firstChild.firstChild.firstChild;
11396 Roo.TabPanel.prototype.createBody = function(container){
11397 var body = document.createElement("div");
11398 Roo.id(body, "tab-body");
11399 Roo.fly(body).addClass("x-tabs-body");
11400 container.appendChild(body);
11404 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11405 var body = Roo.getDom(id);
11407 body = document.createElement("div");
11410 Roo.fly(body).addClass("x-tabs-item-body");
11411 bodyEl.insertBefore(body, bodyEl.firstChild);
11415 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11416 var td = document.createElement("td");
11417 stripEl.appendChild(td);
11419 td.className = "x-tabs-closable";
11420 if(!this.closeTpl){
11421 this.closeTpl = new Roo.Template(
11422 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11423 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11424 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11427 var el = this.closeTpl.overwrite(td, {"text": text});
11428 var close = el.getElementsByTagName("div")[0];
11429 var inner = el.getElementsByTagName("em")[0];
11430 return {"el": el, "close": close, "inner": inner};
11433 this.tabTpl = new Roo.Template(
11434 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11435 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11438 var el = this.tabTpl.overwrite(td, {"text": text});
11439 var inner = el.getElementsByTagName("em")[0];
11440 return {"el": el, "inner": inner};
11444 * Ext JS Library 1.1.1
11445 * Copyright(c) 2006-2007, Ext JS, LLC.
11447 * Originally Released Under LGPL - original licence link has changed is not relivant.
11450 * <script type="text/javascript">
11454 * @class Roo.Button
11455 * @extends Roo.util.Observable
11456 * Simple Button class
11457 * @cfg {String} text The button text
11458 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11459 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11460 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11461 * @cfg {Object} scope The scope of the handler
11462 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11463 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11464 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11465 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11466 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11467 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11468 applies if enableToggle = true)
11469 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11470 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11471 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11473 * Create a new button
11474 * @param {Object} config The config object
11476 Roo.Button = function(renderTo, config)
11480 renderTo = config.renderTo || false;
11483 Roo.apply(this, config);
11487 * Fires when this button is clicked
11488 * @param {Button} this
11489 * @param {EventObject} e The click event
11494 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11495 * @param {Button} this
11496 * @param {Boolean} pressed
11501 * Fires when the mouse hovers over the button
11502 * @param {Button} this
11503 * @param {Event} e The event object
11505 'mouseover' : true,
11508 * Fires when the mouse exits the button
11509 * @param {Button} this
11510 * @param {Event} e The event object
11515 * Fires when the button is rendered
11516 * @param {Button} this
11521 this.menu = Roo.menu.MenuMgr.get(this.menu);
11523 // register listeners first!! - so render can be captured..
11524 Roo.util.Observable.call(this);
11526 this.render(renderTo);
11532 Roo.extend(Roo.Button, Roo.util.Observable, {
11538 * Read-only. True if this button is hidden
11543 * Read-only. True if this button is disabled
11548 * Read-only. True if this button is pressed (only if enableToggle = true)
11554 * @cfg {Number} tabIndex
11555 * The DOM tabIndex for this button (defaults to undefined)
11557 tabIndex : undefined,
11560 * @cfg {Boolean} enableToggle
11561 * True to enable pressed/not pressed toggling (defaults to false)
11563 enableToggle: false,
11565 * @cfg {Mixed} menu
11566 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11570 * @cfg {String} menuAlign
11571 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11573 menuAlign : "tl-bl?",
11576 * @cfg {String} iconCls
11577 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11579 iconCls : undefined,
11581 * @cfg {String} type
11582 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11587 menuClassTarget: 'tr',
11590 * @cfg {String} clickEvent
11591 * The type of event to map to the button's event handler (defaults to 'click')
11593 clickEvent : 'click',
11596 * @cfg {Boolean} handleMouseEvents
11597 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11599 handleMouseEvents : true,
11602 * @cfg {String} tooltipType
11603 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11605 tooltipType : 'qtip',
11608 * @cfg {String} cls
11609 * A CSS class to apply to the button's main element.
11613 * @cfg {Roo.Template} template (Optional)
11614 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11615 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11616 * require code modifications if required elements (e.g. a button) aren't present.
11620 render : function(renderTo){
11622 if(this.hideParent){
11623 this.parentEl = Roo.get(renderTo);
11625 if(!this.dhconfig){
11626 if(!this.template){
11627 if(!Roo.Button.buttonTemplate){
11628 // hideous table template
11629 Roo.Button.buttonTemplate = new Roo.Template(
11630 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11631 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
11632 "</tr></tbody></table>");
11634 this.template = Roo.Button.buttonTemplate;
11636 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11637 var btnEl = btn.child("button:first");
11638 btnEl.on('focus', this.onFocus, this);
11639 btnEl.on('blur', this.onBlur, this);
11641 btn.addClass(this.cls);
11644 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11647 btnEl.addClass(this.iconCls);
11649 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11652 if(this.tabIndex !== undefined){
11653 btnEl.dom.tabIndex = this.tabIndex;
11656 if(typeof this.tooltip == 'object'){
11657 Roo.QuickTips.tips(Roo.apply({
11661 btnEl.dom[this.tooltipType] = this.tooltip;
11665 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11669 this.el.dom.id = this.el.id = this.id;
11672 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11673 this.menu.on("show", this.onMenuShow, this);
11674 this.menu.on("hide", this.onMenuHide, this);
11676 btn.addClass("x-btn");
11677 if(Roo.isIE && !Roo.isIE7){
11678 this.autoWidth.defer(1, this);
11682 if(this.handleMouseEvents){
11683 btn.on("mouseover", this.onMouseOver, this);
11684 btn.on("mouseout", this.onMouseOut, this);
11685 btn.on("mousedown", this.onMouseDown, this);
11687 btn.on(this.clickEvent, this.onClick, this);
11688 //btn.on("mouseup", this.onMouseUp, this);
11695 Roo.ButtonToggleMgr.register(this);
11697 this.el.addClass("x-btn-pressed");
11700 var repeater = new Roo.util.ClickRepeater(btn,
11701 typeof this.repeat == "object" ? this.repeat : {}
11703 repeater.on("click", this.onClick, this);
11706 this.fireEvent('render', this);
11710 * Returns the button's underlying element
11711 * @return {Roo.Element} The element
11713 getEl : function(){
11718 * Destroys this Button and removes any listeners.
11720 destroy : function(){
11721 Roo.ButtonToggleMgr.unregister(this);
11722 this.el.removeAllListeners();
11723 this.purgeListeners();
11728 autoWidth : function(){
11730 this.el.setWidth("auto");
11731 if(Roo.isIE7 && Roo.isStrict){
11732 var ib = this.el.child('button');
11733 if(ib && ib.getWidth() > 20){
11735 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11740 this.el.beginMeasure();
11742 if(this.el.getWidth() < this.minWidth){
11743 this.el.setWidth(this.minWidth);
11746 this.el.endMeasure();
11753 * Assigns this button's click handler
11754 * @param {Function} handler The function to call when the button is clicked
11755 * @param {Object} scope (optional) Scope for the function passed in
11757 setHandler : function(handler, scope){
11758 this.handler = handler;
11759 this.scope = scope;
11763 * Sets this button's text
11764 * @param {String} text The button text
11766 setText : function(text){
11769 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11775 * Gets the text for this button
11776 * @return {String} The button text
11778 getText : function(){
11786 this.hidden = false;
11788 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11796 this.hidden = true;
11798 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11803 * Convenience function for boolean show/hide
11804 * @param {Boolean} visible True to show, false to hide
11806 setVisible: function(visible){
11815 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11816 * @param {Boolean} state (optional) Force a particular state
11818 toggle : function(state){
11819 state = state === undefined ? !this.pressed : state;
11820 if(state != this.pressed){
11822 this.el.addClass("x-btn-pressed");
11823 this.pressed = true;
11824 this.fireEvent("toggle", this, true);
11826 this.el.removeClass("x-btn-pressed");
11827 this.pressed = false;
11828 this.fireEvent("toggle", this, false);
11830 if(this.toggleHandler){
11831 this.toggleHandler.call(this.scope || this, this, state);
11839 focus : function(){
11840 this.el.child('button:first').focus();
11844 * Disable this button
11846 disable : function(){
11848 this.el.addClass("x-btn-disabled");
11850 this.disabled = true;
11854 * Enable this button
11856 enable : function(){
11858 this.el.removeClass("x-btn-disabled");
11860 this.disabled = false;
11864 * Convenience function for boolean enable/disable
11865 * @param {Boolean} enabled True to enable, false to disable
11867 setDisabled : function(v){
11868 this[v !== true ? "enable" : "disable"]();
11872 onClick : function(e){
11874 e.preventDefault();
11879 if(!this.disabled){
11880 if(this.enableToggle){
11883 if(this.menu && !this.menu.isVisible()){
11884 this.menu.show(this.el, this.menuAlign);
11886 this.fireEvent("click", this, e);
11888 this.el.removeClass("x-btn-over");
11889 this.handler.call(this.scope || this, this, e);
11894 onMouseOver : function(e){
11895 if(!this.disabled){
11896 this.el.addClass("x-btn-over");
11897 this.fireEvent('mouseover', this, e);
11901 onMouseOut : function(e){
11902 if(!e.within(this.el, true)){
11903 this.el.removeClass("x-btn-over");
11904 this.fireEvent('mouseout', this, e);
11908 onFocus : function(e){
11909 if(!this.disabled){
11910 this.el.addClass("x-btn-focus");
11914 onBlur : function(e){
11915 this.el.removeClass("x-btn-focus");
11918 onMouseDown : function(e){
11919 if(!this.disabled && e.button == 0){
11920 this.el.addClass("x-btn-click");
11921 Roo.get(document).on('mouseup', this.onMouseUp, this);
11925 onMouseUp : function(e){
11927 this.el.removeClass("x-btn-click");
11928 Roo.get(document).un('mouseup', this.onMouseUp, this);
11932 onMenuShow : function(e){
11933 this.el.addClass("x-btn-menu-active");
11936 onMenuHide : function(e){
11937 this.el.removeClass("x-btn-menu-active");
11941 // Private utility class used by Button
11942 Roo.ButtonToggleMgr = function(){
11945 function toggleGroup(btn, state){
11947 var g = groups[btn.toggleGroup];
11948 for(var i = 0, l = g.length; i < l; i++){
11950 g[i].toggle(false);
11957 register : function(btn){
11958 if(!btn.toggleGroup){
11961 var g = groups[btn.toggleGroup];
11963 g = groups[btn.toggleGroup] = [];
11966 btn.on("toggle", toggleGroup);
11969 unregister : function(btn){
11970 if(!btn.toggleGroup){
11973 var g = groups[btn.toggleGroup];
11976 btn.un("toggle", toggleGroup);
11982 * Ext JS Library 1.1.1
11983 * Copyright(c) 2006-2007, Ext JS, LLC.
11985 * Originally Released Under LGPL - original licence link has changed is not relivant.
11988 * <script type="text/javascript">
11992 * @class Roo.SplitButton
11993 * @extends Roo.Button
11994 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11995 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11996 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11997 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11998 * @cfg {String} arrowTooltip The title attribute of the arrow
12000 * Create a new menu button
12001 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12002 * @param {Object} config The config object
12004 Roo.SplitButton = function(renderTo, config){
12005 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12007 * @event arrowclick
12008 * Fires when this button's arrow is clicked
12009 * @param {SplitButton} this
12010 * @param {EventObject} e The click event
12012 this.addEvents({"arrowclick":true});
12015 Roo.extend(Roo.SplitButton, Roo.Button, {
12016 render : function(renderTo){
12017 // this is one sweet looking template!
12018 var tpl = new Roo.Template(
12019 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12020 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12021 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
12022 "</tbody></table></td><td>",
12023 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12024 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
12025 "</tbody></table></td></tr></table>"
12027 var btn = tpl.append(renderTo, [this.text, this.type], true);
12028 var btnEl = btn.child("button");
12030 btn.addClass(this.cls);
12033 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12036 btnEl.addClass(this.iconCls);
12038 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12042 if(this.handleMouseEvents){
12043 btn.on("mouseover", this.onMouseOver, this);
12044 btn.on("mouseout", this.onMouseOut, this);
12045 btn.on("mousedown", this.onMouseDown, this);
12046 btn.on("mouseup", this.onMouseUp, this);
12048 btn.on(this.clickEvent, this.onClick, this);
12050 if(typeof this.tooltip == 'object'){
12051 Roo.QuickTips.tips(Roo.apply({
12055 btnEl.dom[this.tooltipType] = this.tooltip;
12058 if(this.arrowTooltip){
12059 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12068 this.el.addClass("x-btn-pressed");
12070 if(Roo.isIE && !Roo.isIE7){
12071 this.autoWidth.defer(1, this);
12076 this.menu.on("show", this.onMenuShow, this);
12077 this.menu.on("hide", this.onMenuHide, this);
12079 this.fireEvent('render', this);
12083 autoWidth : function(){
12085 var tbl = this.el.child("table:first");
12086 var tbl2 = this.el.child("table:last");
12087 this.el.setWidth("auto");
12088 tbl.setWidth("auto");
12089 if(Roo.isIE7 && Roo.isStrict){
12090 var ib = this.el.child('button:first');
12091 if(ib && ib.getWidth() > 20){
12093 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12098 this.el.beginMeasure();
12100 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12101 tbl.setWidth(this.minWidth-tbl2.getWidth());
12104 this.el.endMeasure();
12107 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12111 * Sets this button's click handler
12112 * @param {Function} handler The function to call when the button is clicked
12113 * @param {Object} scope (optional) Scope for the function passed above
12115 setHandler : function(handler, scope){
12116 this.handler = handler;
12117 this.scope = scope;
12121 * Sets this button's arrow click handler
12122 * @param {Function} handler The function to call when the arrow is clicked
12123 * @param {Object} scope (optional) Scope for the function passed above
12125 setArrowHandler : function(handler, scope){
12126 this.arrowHandler = handler;
12127 this.scope = scope;
12133 focus : function(){
12135 this.el.child("button:first").focus();
12140 onClick : function(e){
12141 e.preventDefault();
12142 if(!this.disabled){
12143 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12144 if(this.menu && !this.menu.isVisible()){
12145 this.menu.show(this.el, this.menuAlign);
12147 this.fireEvent("arrowclick", this, e);
12148 if(this.arrowHandler){
12149 this.arrowHandler.call(this.scope || this, this, e);
12152 this.fireEvent("click", this, e);
12154 this.handler.call(this.scope || this, this, e);
12160 onMouseDown : function(e){
12161 if(!this.disabled){
12162 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12166 onMouseUp : function(e){
12167 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12172 // backwards compat
12173 Roo.MenuButton = Roo.SplitButton;/*
12175 * Ext JS Library 1.1.1
12176 * Copyright(c) 2006-2007, Ext JS, LLC.
12178 * Originally Released Under LGPL - original licence link has changed is not relivant.
12181 * <script type="text/javascript">
12185 * @class Roo.Toolbar
12186 * Basic Toolbar class.
12188 * Creates a new Toolbar
12189 * @param {Object} config The config object
12191 Roo.Toolbar = function(container, buttons, config)
12193 /// old consturctor format still supported..
12194 if(container instanceof Array){ // omit the container for later rendering
12195 buttons = container;
12199 if (typeof(container) == 'object' && container.xtype) {
12200 config = container;
12201 container = config.container;
12202 buttons = config.buttons; // not really - use items!!
12205 if (config && config.items) {
12206 xitems = config.items;
12207 delete config.items;
12209 Roo.apply(this, config);
12210 this.buttons = buttons;
12213 this.render(container);
12215 Roo.each(xitems, function(b) {
12221 Roo.Toolbar.prototype = {
12223 * @cfg {Roo.data.Store} items
12224 * array of button configs or elements to add
12228 * @cfg {String/HTMLElement/Element} container
12229 * The id or element that will contain the toolbar
12232 render : function(ct){
12233 this.el = Roo.get(ct);
12235 this.el.addClass(this.cls);
12237 // using a table allows for vertical alignment
12238 // 100% width is needed by Safari...
12239 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12240 this.tr = this.el.child("tr", true);
12242 this.items = new Roo.util.MixedCollection(false, function(o){
12243 return o.id || ("item" + (++autoId));
12246 this.add.apply(this, this.buttons);
12247 delete this.buttons;
12252 * Adds element(s) to the toolbar -- this function takes a variable number of
12253 * arguments of mixed type and adds them to the toolbar.
12254 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12256 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12257 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12258 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12259 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12260 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12261 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12262 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12263 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12264 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12266 * @param {Mixed} arg2
12267 * @param {Mixed} etc.
12270 var a = arguments, l = a.length;
12271 for(var i = 0; i < l; i++){
12276 _add : function(el) {
12279 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12282 if (el.applyTo){ // some kind of form field
12283 return this.addField(el);
12285 if (el.render){ // some kind of Toolbar.Item
12286 return this.addItem(el);
12288 if (typeof el == "string"){ // string
12289 if(el == "separator" || el == "-"){
12290 return this.addSeparator();
12293 return this.addSpacer();
12296 return this.addFill();
12298 return this.addText(el);
12301 if(el.tagName){ // element
12302 return this.addElement(el);
12304 if(typeof el == "object"){ // must be button config?
12305 return this.addButton(el);
12307 // and now what?!?!
12313 * Add an Xtype element
12314 * @param {Object} xtype Xtype Object
12315 * @return {Object} created Object
12317 addxtype : function(e){
12318 return this.add(e);
12322 * Returns the Element for this toolbar.
12323 * @return {Roo.Element}
12325 getEl : function(){
12331 * @return {Roo.Toolbar.Item} The separator item
12333 addSeparator : function(){
12334 return this.addItem(new Roo.Toolbar.Separator());
12338 * Adds a spacer element
12339 * @return {Roo.Toolbar.Spacer} The spacer item
12341 addSpacer : function(){
12342 return this.addItem(new Roo.Toolbar.Spacer());
12346 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12347 * @return {Roo.Toolbar.Fill} The fill item
12349 addFill : function(){
12350 return this.addItem(new Roo.Toolbar.Fill());
12354 * Adds any standard HTML element to the toolbar
12355 * @param {String/HTMLElement/Element} el The element or id of the element to add
12356 * @return {Roo.Toolbar.Item} The element's item
12358 addElement : function(el){
12359 return this.addItem(new Roo.Toolbar.Item(el));
12362 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12363 * @type Roo.util.MixedCollection
12368 * Adds any Toolbar.Item or subclass
12369 * @param {Roo.Toolbar.Item} item
12370 * @return {Roo.Toolbar.Item} The item
12372 addItem : function(item){
12373 var td = this.nextBlock();
12375 this.items.add(item);
12380 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12381 * @param {Object/Array} config A button config or array of configs
12382 * @return {Roo.Toolbar.Button/Array}
12384 addButton : function(config){
12385 if(config instanceof Array){
12387 for(var i = 0, len = config.length; i < len; i++) {
12388 buttons.push(this.addButton(config[i]));
12393 if(!(config instanceof Roo.Toolbar.Button)){
12395 new Roo.Toolbar.SplitButton(config) :
12396 new Roo.Toolbar.Button(config);
12398 var td = this.nextBlock();
12405 * Adds text to the toolbar
12406 * @param {String} text The text to add
12407 * @return {Roo.Toolbar.Item} The element's item
12409 addText : function(text){
12410 return this.addItem(new Roo.Toolbar.TextItem(text));
12414 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12415 * @param {Number} index The index where the item is to be inserted
12416 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12417 * @return {Roo.Toolbar.Button/Item}
12419 insertButton : function(index, item){
12420 if(item instanceof Array){
12422 for(var i = 0, len = item.length; i < len; i++) {
12423 buttons.push(this.insertButton(index + i, item[i]));
12427 if (!(item instanceof Roo.Toolbar.Button)){
12428 item = new Roo.Toolbar.Button(item);
12430 var td = document.createElement("td");
12431 this.tr.insertBefore(td, this.tr.childNodes[index]);
12433 this.items.insert(index, item);
12438 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12439 * @param {Object} config
12440 * @return {Roo.Toolbar.Item} The element's item
12442 addDom : function(config, returnEl){
12443 var td = this.nextBlock();
12444 Roo.DomHelper.overwrite(td, config);
12445 var ti = new Roo.Toolbar.Item(td.firstChild);
12447 this.items.add(ti);
12452 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12453 * @type Roo.util.MixedCollection
12458 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12459 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12460 * @param {Roo.form.Field} field
12461 * @return {Roo.ToolbarItem}
12465 addField : function(field) {
12466 if (!this.fields) {
12468 this.fields = new Roo.util.MixedCollection(false, function(o){
12469 return o.id || ("item" + (++autoId));
12474 var td = this.nextBlock();
12476 var ti = new Roo.Toolbar.Item(td.firstChild);
12478 this.items.add(ti);
12479 this.fields.add(field);
12490 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12491 this.el.child('div').hide();
12499 this.el.child('div').show();
12503 nextBlock : function(){
12504 var td = document.createElement("td");
12505 this.tr.appendChild(td);
12510 destroy : function(){
12511 if(this.items){ // rendered?
12512 Roo.destroy.apply(Roo, this.items.items);
12514 if(this.fields){ // rendered?
12515 Roo.destroy.apply(Roo, this.fields.items);
12517 Roo.Element.uncache(this.el, this.tr);
12522 * @class Roo.Toolbar.Item
12523 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12525 * Creates a new Item
12526 * @param {HTMLElement} el
12528 Roo.Toolbar.Item = function(el){
12529 this.el = Roo.getDom(el);
12530 this.id = Roo.id(this.el);
12531 this.hidden = false;
12534 Roo.Toolbar.Item.prototype = {
12537 * Get this item's HTML Element
12538 * @return {HTMLElement}
12540 getEl : function(){
12545 render : function(td){
12547 td.appendChild(this.el);
12551 * Removes and destroys this item.
12553 destroy : function(){
12554 this.td.parentNode.removeChild(this.td);
12561 this.hidden = false;
12562 this.td.style.display = "";
12569 this.hidden = true;
12570 this.td.style.display = "none";
12574 * Convenience function for boolean show/hide.
12575 * @param {Boolean} visible true to show/false to hide
12577 setVisible: function(visible){
12586 * Try to focus this item.
12588 focus : function(){
12589 Roo.fly(this.el).focus();
12593 * Disables this item.
12595 disable : function(){
12596 Roo.fly(this.td).addClass("x-item-disabled");
12597 this.disabled = true;
12598 this.el.disabled = true;
12602 * Enables this item.
12604 enable : function(){
12605 Roo.fly(this.td).removeClass("x-item-disabled");
12606 this.disabled = false;
12607 this.el.disabled = false;
12613 * @class Roo.Toolbar.Separator
12614 * @extends Roo.Toolbar.Item
12615 * A simple toolbar separator class
12617 * Creates a new Separator
12619 Roo.Toolbar.Separator = function(){
12620 var s = document.createElement("span");
12621 s.className = "ytb-sep";
12622 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12624 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12625 enable:Roo.emptyFn,
12626 disable:Roo.emptyFn,
12631 * @class Roo.Toolbar.Spacer
12632 * @extends Roo.Toolbar.Item
12633 * A simple element that adds extra horizontal space to a toolbar.
12635 * Creates a new Spacer
12637 Roo.Toolbar.Spacer = function(){
12638 var s = document.createElement("div");
12639 s.className = "ytb-spacer";
12640 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12642 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12643 enable:Roo.emptyFn,
12644 disable:Roo.emptyFn,
12649 * @class Roo.Toolbar.Fill
12650 * @extends Roo.Toolbar.Spacer
12651 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12653 * Creates a new Spacer
12655 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12657 render : function(td){
12658 td.style.width = '100%';
12659 Roo.Toolbar.Fill.superclass.render.call(this, td);
12664 * @class Roo.Toolbar.TextItem
12665 * @extends Roo.Toolbar.Item
12666 * A simple class that renders text directly into a toolbar.
12668 * Creates a new TextItem
12669 * @param {String} text
12671 Roo.Toolbar.TextItem = function(text){
12672 if (typeof(text) == 'object') {
12675 var s = document.createElement("span");
12676 s.className = "ytb-text";
12677 s.innerHTML = text;
12678 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12680 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12681 enable:Roo.emptyFn,
12682 disable:Roo.emptyFn,
12687 * @class Roo.Toolbar.Button
12688 * @extends Roo.Button
12689 * A button that renders into a toolbar.
12691 * Creates a new Button
12692 * @param {Object} config A standard {@link Roo.Button} config object
12694 Roo.Toolbar.Button = function(config){
12695 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12697 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12698 render : function(td){
12700 Roo.Toolbar.Button.superclass.render.call(this, td);
12704 * Removes and destroys this button
12706 destroy : function(){
12707 Roo.Toolbar.Button.superclass.destroy.call(this);
12708 this.td.parentNode.removeChild(this.td);
12712 * Shows this button
12715 this.hidden = false;
12716 this.td.style.display = "";
12720 * Hides this button
12723 this.hidden = true;
12724 this.td.style.display = "none";
12728 * Disables this item
12730 disable : function(){
12731 Roo.fly(this.td).addClass("x-item-disabled");
12732 this.disabled = true;
12736 * Enables this item
12738 enable : function(){
12739 Roo.fly(this.td).removeClass("x-item-disabled");
12740 this.disabled = false;
12743 // backwards compat
12744 Roo.ToolbarButton = Roo.Toolbar.Button;
12747 * @class Roo.Toolbar.SplitButton
12748 * @extends Roo.SplitButton
12749 * A menu button that renders into a toolbar.
12751 * Creates a new SplitButton
12752 * @param {Object} config A standard {@link Roo.SplitButton} config object
12754 Roo.Toolbar.SplitButton = function(config){
12755 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12757 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12758 render : function(td){
12760 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12764 * Removes and destroys this button
12766 destroy : function(){
12767 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12768 this.td.parentNode.removeChild(this.td);
12772 * Shows this button
12775 this.hidden = false;
12776 this.td.style.display = "";
12780 * Hides this button
12783 this.hidden = true;
12784 this.td.style.display = "none";
12788 // backwards compat
12789 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12791 * Ext JS Library 1.1.1
12792 * Copyright(c) 2006-2007, Ext JS, LLC.
12794 * Originally Released Under LGPL - original licence link has changed is not relivant.
12797 * <script type="text/javascript">
12801 * @class Roo.PagingToolbar
12802 * @extends Roo.Toolbar
12803 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12805 * Create a new PagingToolbar
12806 * @param {Object} config The config object
12808 Roo.PagingToolbar = function(el, ds, config)
12810 // old args format still supported... - xtype is prefered..
12811 if (typeof(el) == 'object' && el.xtype) {
12812 // created from xtype...
12814 ds = el.dataSource;
12815 el = config.container;
12818 if (config.items) {
12819 items = config.items;
12823 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12826 this.renderButtons(this.el);
12829 // supprot items array.
12831 Roo.each(items, function(e) {
12832 this.add(Roo.factory(e));
12837 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12839 * @cfg {Roo.data.Store} dataSource
12840 * The underlying data store providing the paged data
12843 * @cfg {String/HTMLElement/Element} container
12844 * container The id or element that will contain the toolbar
12847 * @cfg {Boolean} displayInfo
12848 * True to display the displayMsg (defaults to false)
12851 * @cfg {Number} pageSize
12852 * The number of records to display per page (defaults to 20)
12856 * @cfg {String} displayMsg
12857 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12859 displayMsg : 'Displaying {0} - {1} of {2}',
12861 * @cfg {String} emptyMsg
12862 * The message to display when no records are found (defaults to "No data to display")
12864 emptyMsg : 'No data to display',
12866 * Customizable piece of the default paging text (defaults to "Page")
12869 beforePageText : "Page",
12871 * Customizable piece of the default paging text (defaults to "of %0")
12874 afterPageText : "of {0}",
12876 * Customizable piece of the default paging text (defaults to "First Page")
12879 firstText : "First Page",
12881 * Customizable piece of the default paging text (defaults to "Previous Page")
12884 prevText : "Previous Page",
12886 * Customizable piece of the default paging text (defaults to "Next Page")
12889 nextText : "Next Page",
12891 * Customizable piece of the default paging text (defaults to "Last Page")
12894 lastText : "Last Page",
12896 * Customizable piece of the default paging text (defaults to "Refresh")
12899 refreshText : "Refresh",
12902 renderButtons : function(el){
12903 Roo.PagingToolbar.superclass.render.call(this, el);
12904 this.first = this.addButton({
12905 tooltip: this.firstText,
12906 cls: "x-btn-icon x-grid-page-first",
12908 handler: this.onClick.createDelegate(this, ["first"])
12910 this.prev = this.addButton({
12911 tooltip: this.prevText,
12912 cls: "x-btn-icon x-grid-page-prev",
12914 handler: this.onClick.createDelegate(this, ["prev"])
12916 //this.addSeparator();
12917 this.add(this.beforePageText);
12918 this.field = Roo.get(this.addDom({
12923 cls: "x-grid-page-number"
12925 this.field.on("keydown", this.onPagingKeydown, this);
12926 this.field.on("focus", function(){this.dom.select();});
12927 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12928 this.field.setHeight(18);
12929 //this.addSeparator();
12930 this.next = this.addButton({
12931 tooltip: this.nextText,
12932 cls: "x-btn-icon x-grid-page-next",
12934 handler: this.onClick.createDelegate(this, ["next"])
12936 this.last = this.addButton({
12937 tooltip: this.lastText,
12938 cls: "x-btn-icon x-grid-page-last",
12940 handler: this.onClick.createDelegate(this, ["last"])
12942 //this.addSeparator();
12943 this.loading = this.addButton({
12944 tooltip: this.refreshText,
12945 cls: "x-btn-icon x-grid-loading",
12946 handler: this.onClick.createDelegate(this, ["refresh"])
12949 if(this.displayInfo){
12950 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12955 updateInfo : function(){
12956 if(this.displayEl){
12957 var count = this.ds.getCount();
12958 var msg = count == 0 ?
12962 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12964 this.displayEl.update(msg);
12969 onLoad : function(ds, r, o){
12970 this.cursor = o.params ? o.params.start : 0;
12971 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12973 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12974 this.field.dom.value = ap;
12975 this.first.setDisabled(ap == 1);
12976 this.prev.setDisabled(ap == 1);
12977 this.next.setDisabled(ap == ps);
12978 this.last.setDisabled(ap == ps);
12979 this.loading.enable();
12984 getPageData : function(){
12985 var total = this.ds.getTotalCount();
12988 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12989 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12994 onLoadError : function(){
12995 this.loading.enable();
12999 onPagingKeydown : function(e){
13000 var k = e.getKey();
13001 var d = this.getPageData();
13003 var v = this.field.dom.value, pageNum;
13004 if(!v || isNaN(pageNum = parseInt(v, 10))){
13005 this.field.dom.value = d.activePage;
13008 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13009 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13012 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
13014 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13015 this.field.dom.value = pageNum;
13016 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13019 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13021 var v = this.field.dom.value, pageNum;
13022 var increment = (e.shiftKey) ? 10 : 1;
13023 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13025 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13026 this.field.dom.value = d.activePage;
13029 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13031 this.field.dom.value = parseInt(v, 10) + increment;
13032 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13033 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13040 beforeLoad : function(){
13042 this.loading.disable();
13047 onClick : function(which){
13051 ds.load({params:{start: 0, limit: this.pageSize}});
13054 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13057 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13060 var total = ds.getTotalCount();
13061 var extra = total % this.pageSize;
13062 var lastStart = extra ? (total - extra) : total-this.pageSize;
13063 ds.load({params:{start: lastStart, limit: this.pageSize}});
13066 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13072 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13073 * @param {Roo.data.Store} store The data store to unbind
13075 unbind : function(ds){
13076 ds.un("beforeload", this.beforeLoad, this);
13077 ds.un("load", this.onLoad, this);
13078 ds.un("loadexception", this.onLoadError, this);
13079 ds.un("remove", this.updateInfo, this);
13080 ds.un("add", this.updateInfo, this);
13081 this.ds = undefined;
13085 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13086 * @param {Roo.data.Store} store The data store to bind
13088 bind : function(ds){
13089 ds.on("beforeload", this.beforeLoad, this);
13090 ds.on("load", this.onLoad, this);
13091 ds.on("loadexception", this.onLoadError, this);
13092 ds.on("remove", this.updateInfo, this);
13093 ds.on("add", this.updateInfo, this);
13098 * Ext JS Library 1.1.1
13099 * Copyright(c) 2006-2007, Ext JS, LLC.
13101 * Originally Released Under LGPL - original licence link has changed is not relivant.
13104 * <script type="text/javascript">
13108 * @class Roo.Resizable
13109 * @extends Roo.util.Observable
13110 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13111 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13112 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
13113 * the element will be wrapped for you automatically.</p>
13114 * <p>Here is the list of valid resize handles:</p>
13117 ------ -------------------
13126 'hd' horizontal drag
13129 * <p>Here's an example showing the creation of a typical Resizable:</p>
13131 var resizer = new Roo.Resizable("element-id", {
13139 resizer.on("resize", myHandler);
13141 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13142 * resizer.east.setDisplayed(false);</p>
13143 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13144 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13145 * resize operation's new size (defaults to [0, 0])
13146 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13147 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13148 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13149 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13150 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13151 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13152 * @cfg {Number} width The width of the element in pixels (defaults to null)
13153 * @cfg {Number} height The height of the element in pixels (defaults to null)
13154 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13155 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13156 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13157 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13158 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13159 * in favor of the handles config option (defaults to false)
13160 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13161 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13162 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13163 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13164 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13165 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13166 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13167 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13168 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13169 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13170 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13172 * Create a new resizable component
13173 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13174 * @param {Object} config configuration options
13176 Roo.Resizable = function(el, config)
13178 this.el = Roo.get(el);
13180 if(config && config.wrap){
13181 config.resizeChild = this.el;
13182 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13183 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13184 this.el.setStyle("overflow", "hidden");
13185 this.el.setPositioning(config.resizeChild.getPositioning());
13186 config.resizeChild.clearPositioning();
13187 if(!config.width || !config.height){
13188 var csize = config.resizeChild.getSize();
13189 this.el.setSize(csize.width, csize.height);
13191 if(config.pinned && !config.adjustments){
13192 config.adjustments = "auto";
13196 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13197 this.proxy.unselectable();
13198 this.proxy.enableDisplayMode('block');
13200 Roo.apply(this, config);
13203 this.disableTrackOver = true;
13204 this.el.addClass("x-resizable-pinned");
13206 // if the element isn't positioned, make it relative
13207 var position = this.el.getStyle("position");
13208 if(position != "absolute" && position != "fixed"){
13209 this.el.setStyle("position", "relative");
13211 if(!this.handles){ // no handles passed, must be legacy style
13212 this.handles = 's,e,se';
13213 if(this.multiDirectional){
13214 this.handles += ',n,w';
13217 if(this.handles == "all"){
13218 this.handles = "n s e w ne nw se sw";
13220 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13221 var ps = Roo.Resizable.positions;
13222 for(var i = 0, len = hs.length; i < len; i++){
13223 if(hs[i] && ps[hs[i]]){
13224 var pos = ps[hs[i]];
13225 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13229 this.corner = this.southeast;
13231 // updateBox = the box can move..
13232 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13233 this.updateBox = true;
13236 this.activeHandle = null;
13238 if(this.resizeChild){
13239 if(typeof this.resizeChild == "boolean"){
13240 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13242 this.resizeChild = Roo.get(this.resizeChild, true);
13246 if(this.adjustments == "auto"){
13247 var rc = this.resizeChild;
13248 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13249 if(rc && (hw || hn)){
13250 rc.position("relative");
13251 rc.setLeft(hw ? hw.el.getWidth() : 0);
13252 rc.setTop(hn ? hn.el.getHeight() : 0);
13254 this.adjustments = [
13255 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13256 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13260 if(this.draggable){
13261 this.dd = this.dynamic ?
13262 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13263 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13269 * @event beforeresize
13270 * Fired before resize is allowed. Set enabled to false to cancel resize.
13271 * @param {Roo.Resizable} this
13272 * @param {Roo.EventObject} e The mousedown event
13274 "beforeresize" : true,
13277 * Fired after a resize.
13278 * @param {Roo.Resizable} this
13279 * @param {Number} width The new width
13280 * @param {Number} height The new height
13281 * @param {Roo.EventObject} e The mouseup event
13286 if(this.width !== null && this.height !== null){
13287 this.resizeTo(this.width, this.height);
13289 this.updateChildSize();
13292 this.el.dom.style.zoom = 1;
13294 Roo.Resizable.superclass.constructor.call(this);
13297 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13298 resizeChild : false,
13299 adjustments : [0, 0],
13309 multiDirectional : false,
13310 disableTrackOver : false,
13311 easing : 'easeOutStrong',
13312 widthIncrement : 0,
13313 heightIncrement : 0,
13317 preserveRatio : false,
13318 transparent: false,
13324 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13326 constrainTo: undefined,
13328 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13330 resizeRegion: undefined,
13334 * Perform a manual resize
13335 * @param {Number} width
13336 * @param {Number} height
13338 resizeTo : function(width, height){
13339 this.el.setSize(width, height);
13340 this.updateChildSize();
13341 this.fireEvent("resize", this, width, height, null);
13345 startSizing : function(e, handle){
13346 this.fireEvent("beforeresize", this, e);
13347 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13350 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13351 this.overlay.unselectable();
13352 this.overlay.enableDisplayMode("block");
13353 this.overlay.on("mousemove", this.onMouseMove, this);
13354 this.overlay.on("mouseup", this.onMouseUp, this);
13356 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13358 this.resizing = true;
13359 this.startBox = this.el.getBox();
13360 this.startPoint = e.getXY();
13361 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13362 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13364 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13365 this.overlay.show();
13367 if(this.constrainTo) {
13368 var ct = Roo.get(this.constrainTo);
13369 this.resizeRegion = ct.getRegion().adjust(
13370 ct.getFrameWidth('t'),
13371 ct.getFrameWidth('l'),
13372 -ct.getFrameWidth('b'),
13373 -ct.getFrameWidth('r')
13377 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13379 this.proxy.setBox(this.startBox);
13381 this.proxy.setStyle('visibility', 'visible');
13387 onMouseDown : function(handle, e){
13390 this.activeHandle = handle;
13391 this.startSizing(e, handle);
13396 onMouseUp : function(e){
13397 var size = this.resizeElement();
13398 this.resizing = false;
13400 this.overlay.hide();
13402 this.fireEvent("resize", this, size.width, size.height, e);
13406 updateChildSize : function(){
13407 if(this.resizeChild){
13409 var child = this.resizeChild;
13410 var adj = this.adjustments;
13411 if(el.dom.offsetWidth){
13412 var b = el.getSize(true);
13413 child.setSize(b.width+adj[0], b.height+adj[1]);
13415 // Second call here for IE
13416 // The first call enables instant resizing and
13417 // the second call corrects scroll bars if they
13420 setTimeout(function(){
13421 if(el.dom.offsetWidth){
13422 var b = el.getSize(true);
13423 child.setSize(b.width+adj[0], b.height+adj[1]);
13431 snap : function(value, inc, min){
13432 if(!inc || !value) return value;
13433 var newValue = value;
13434 var m = value % inc;
13437 newValue = value + (inc-m);
13439 newValue = value - m;
13442 return Math.max(min, newValue);
13446 resizeElement : function(){
13447 var box = this.proxy.getBox();
13448 if(this.updateBox){
13449 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13451 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13453 this.updateChildSize();
13461 constrain : function(v, diff, m, mx){
13464 }else if(v - diff > mx){
13471 onMouseMove : function(e){
13473 try{// try catch so if something goes wrong the user doesn't get hung
13475 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13479 //var curXY = this.startPoint;
13480 var curSize = this.curSize || this.startBox;
13481 var x = this.startBox.x, y = this.startBox.y;
13482 var ox = x, oy = y;
13483 var w = curSize.width, h = curSize.height;
13484 var ow = w, oh = h;
13485 var mw = this.minWidth, mh = this.minHeight;
13486 var mxw = this.maxWidth, mxh = this.maxHeight;
13487 var wi = this.widthIncrement;
13488 var hi = this.heightIncrement;
13490 var eventXY = e.getXY();
13491 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13492 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13494 var pos = this.activeHandle.position;
13499 w = Math.min(Math.max(mw, w), mxw);
13504 h = Math.min(Math.max(mh, h), mxh);
13509 w = Math.min(Math.max(mw, w), mxw);
13510 h = Math.min(Math.max(mh, h), mxh);
13513 diffY = this.constrain(h, diffY, mh, mxh);
13520 var adiffX = Math.abs(diffX);
13521 var sub = (adiffX % wi); // how much
13522 if (sub > (wi/2)) { // far enough to snap
13523 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13525 // remove difference..
13526 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13530 x = Math.max(this.minX, x);
13533 diffX = this.constrain(w, diffX, mw, mxw);
13539 w = Math.min(Math.max(mw, w), mxw);
13540 diffY = this.constrain(h, diffY, mh, mxh);
13545 diffX = this.constrain(w, diffX, mw, mxw);
13546 diffY = this.constrain(h, diffY, mh, mxh);
13553 diffX = this.constrain(w, diffX, mw, mxw);
13555 h = Math.min(Math.max(mh, h), mxh);
13561 var sw = this.snap(w, wi, mw);
13562 var sh = this.snap(h, hi, mh);
13563 if(sw != w || sh != h){
13586 if(this.preserveRatio){
13591 h = Math.min(Math.max(mh, h), mxh);
13596 w = Math.min(Math.max(mw, w), mxw);
13601 w = Math.min(Math.max(mw, w), mxw);
13607 w = Math.min(Math.max(mw, w), mxw);
13613 h = Math.min(Math.max(mh, h), mxh);
13621 h = Math.min(Math.max(mh, h), mxh);
13631 h = Math.min(Math.max(mh, h), mxh);
13639 if (pos == 'hdrag') {
13642 this.proxy.setBounds(x, y, w, h);
13644 this.resizeElement();
13651 handleOver : function(){
13653 this.el.addClass("x-resizable-over");
13658 handleOut : function(){
13659 if(!this.resizing){
13660 this.el.removeClass("x-resizable-over");
13665 * Returns the element this component is bound to.
13666 * @return {Roo.Element}
13668 getEl : function(){
13673 * Returns the resizeChild element (or null).
13674 * @return {Roo.Element}
13676 getResizeChild : function(){
13677 return this.resizeChild;
13681 * Destroys this resizable. If the element was wrapped and
13682 * removeEl is not true then the element remains.
13683 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13685 destroy : function(removeEl){
13686 this.proxy.remove();
13688 this.overlay.removeAllListeners();
13689 this.overlay.remove();
13691 var ps = Roo.Resizable.positions;
13693 if(typeof ps[k] != "function" && this[ps[k]]){
13694 var h = this[ps[k]];
13695 h.el.removeAllListeners();
13700 this.el.update("");
13707 // hash to map config positions to true positions
13708 Roo.Resizable.positions = {
13709 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13714 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13716 // only initialize the template if resizable is used
13717 var tpl = Roo.DomHelper.createTemplate(
13718 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13721 Roo.Resizable.Handle.prototype.tpl = tpl;
13723 this.position = pos;
13725 // show north drag fro topdra
13726 var handlepos = pos == 'hdrag' ? 'north' : pos;
13728 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13729 if (pos == 'hdrag') {
13730 this.el.setStyle('cursor', 'pointer');
13732 this.el.unselectable();
13734 this.el.setOpacity(0);
13736 this.el.on("mousedown", this.onMouseDown, this);
13737 if(!disableTrackOver){
13738 this.el.on("mouseover", this.onMouseOver, this);
13739 this.el.on("mouseout", this.onMouseOut, this);
13744 Roo.Resizable.Handle.prototype = {
13745 afterResize : function(rz){
13749 onMouseDown : function(e){
13750 this.rz.onMouseDown(this, e);
13753 onMouseOver : function(e){
13754 this.rz.handleOver(this, e);
13757 onMouseOut : function(e){
13758 this.rz.handleOut(this, e);
13762 * Ext JS Library 1.1.1
13763 * Copyright(c) 2006-2007, Ext JS, LLC.
13765 * Originally Released Under LGPL - original licence link has changed is not relivant.
13768 * <script type="text/javascript">
13772 * @class Roo.Editor
13773 * @extends Roo.Component
13774 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13776 * Create a new Editor
13777 * @param {Roo.form.Field} field The Field object (or descendant)
13778 * @param {Object} config The config object
13780 Roo.Editor = function(field, config){
13781 Roo.Editor.superclass.constructor.call(this, config);
13782 this.field = field;
13785 * @event beforestartedit
13786 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13787 * false from the handler of this event.
13788 * @param {Editor} this
13789 * @param {Roo.Element} boundEl The underlying element bound to this editor
13790 * @param {Mixed} value The field value being set
13792 "beforestartedit" : true,
13795 * Fires when this editor is displayed
13796 * @param {Roo.Element} boundEl The underlying element bound to this editor
13797 * @param {Mixed} value The starting field value
13799 "startedit" : true,
13801 * @event beforecomplete
13802 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13803 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13804 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13805 * event will not fire since no edit actually occurred.
13806 * @param {Editor} this
13807 * @param {Mixed} value The current field value
13808 * @param {Mixed} startValue The original field value
13810 "beforecomplete" : true,
13813 * Fires after editing is complete and any changed value has been written to the underlying field.
13814 * @param {Editor} this
13815 * @param {Mixed} value The current field value
13816 * @param {Mixed} startValue The original field value
13820 * @event specialkey
13821 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13822 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13823 * @param {Roo.form.Field} this
13824 * @param {Roo.EventObject} e The event object
13826 "specialkey" : true
13830 Roo.extend(Roo.Editor, Roo.Component, {
13832 * @cfg {Boolean/String} autosize
13833 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13834 * or "height" to adopt the height only (defaults to false)
13837 * @cfg {Boolean} revertInvalid
13838 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13839 * validation fails (defaults to true)
13842 * @cfg {Boolean} ignoreNoChange
13843 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13844 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13845 * will never be ignored.
13848 * @cfg {Boolean} hideEl
13849 * False to keep the bound element visible while the editor is displayed (defaults to true)
13852 * @cfg {Mixed} value
13853 * The data value of the underlying field (defaults to "")
13857 * @cfg {String} alignment
13858 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13862 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13863 * for bottom-right shadow (defaults to "frame")
13867 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13871 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13873 completeOnEnter : false,
13875 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13877 cancelOnEsc : false,
13879 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13884 onRender : function(ct, position){
13885 this.el = new Roo.Layer({
13886 shadow: this.shadow,
13892 constrain: this.constrain
13894 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13895 if(this.field.msgTarget != 'title'){
13896 this.field.msgTarget = 'qtip';
13898 this.field.render(this.el);
13900 this.field.el.dom.setAttribute('autocomplete', 'off');
13902 this.field.on("specialkey", this.onSpecialKey, this);
13903 if(this.swallowKeys){
13904 this.field.el.swallowEvent(['keydown','keypress']);
13907 this.field.on("blur", this.onBlur, this);
13908 if(this.field.grow){
13909 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13913 onSpecialKey : function(field, e){
13914 //Roo.log('editor onSpecialKey');
13915 if(this.completeOnEnter && e.getKey() == e.ENTER){
13917 this.completeEdit();
13918 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13921 this.fireEvent('specialkey', field, e);
13926 * Starts the editing process and shows the editor.
13927 * @param {String/HTMLElement/Element} el The element to edit
13928 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13929 * to the innerHTML of el.
13931 startEdit : function(el, value){
13933 this.completeEdit();
13935 this.boundEl = Roo.get(el);
13936 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13937 if(!this.rendered){
13938 this.render(this.parentEl || document.body);
13940 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13943 this.startValue = v;
13944 this.field.setValue(v);
13946 var sz = this.boundEl.getSize();
13947 switch(this.autoSize){
13949 this.setSize(sz.width, "");
13952 this.setSize("", sz.height);
13955 this.setSize(sz.width, sz.height);
13958 this.el.alignTo(this.boundEl, this.alignment);
13959 this.editing = true;
13961 Roo.QuickTips.disable();
13967 * Sets the height and width of this editor.
13968 * @param {Number} width The new width
13969 * @param {Number} height The new height
13971 setSize : function(w, h){
13972 this.field.setSize(w, h);
13979 * Realigns the editor to the bound field based on the current alignment config value.
13981 realign : function(){
13982 this.el.alignTo(this.boundEl, this.alignment);
13986 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13987 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13989 completeEdit : function(remainVisible){
13993 var v = this.getValue();
13994 if(this.revertInvalid !== false && !this.field.isValid()){
13995 v = this.startValue;
13996 this.cancelEdit(true);
13998 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13999 this.editing = false;
14003 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
14004 this.editing = false;
14005 if(this.updateEl && this.boundEl){
14006 this.boundEl.update(v);
14008 if(remainVisible !== true){
14011 this.fireEvent("complete", this, v, this.startValue);
14016 onShow : function(){
14018 if(this.hideEl !== false){
14019 this.boundEl.hide();
14022 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14023 this.fixIEFocus = true;
14024 this.deferredFocus.defer(50, this);
14026 this.field.focus();
14028 this.fireEvent("startedit", this.boundEl, this.startValue);
14031 deferredFocus : function(){
14033 this.field.focus();
14038 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14039 * reverted to the original starting value.
14040 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14041 * cancel (defaults to false)
14043 cancelEdit : function(remainVisible){
14045 this.setValue(this.startValue);
14046 if(remainVisible !== true){
14053 onBlur : function(){
14054 if(this.allowBlur !== true && this.editing){
14055 this.completeEdit();
14060 onHide : function(){
14062 this.completeEdit();
14066 if(this.field.collapse){
14067 this.field.collapse();
14070 if(this.hideEl !== false){
14071 this.boundEl.show();
14074 Roo.QuickTips.enable();
14079 * Sets the data value of the editor
14080 * @param {Mixed} value Any valid value supported by the underlying field
14082 setValue : function(v){
14083 this.field.setValue(v);
14087 * Gets the data value of the editor
14088 * @return {Mixed} The data value
14090 getValue : function(){
14091 return this.field.getValue();
14095 * Ext JS Library 1.1.1
14096 * Copyright(c) 2006-2007, Ext JS, LLC.
14098 * Originally Released Under LGPL - original licence link has changed is not relivant.
14101 * <script type="text/javascript">
14105 * @class Roo.BasicDialog
14106 * @extends Roo.util.Observable
14107 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14109 var dlg = new Roo.BasicDialog("my-dlg", {
14118 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14119 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14120 dlg.addButton('Cancel', dlg.hide, dlg);
14123 <b>A Dialog should always be a direct child of the body element.</b>
14124 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14125 * @cfg {String} title Default text to display in the title bar (defaults to null)
14126 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14127 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14128 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14129 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14130 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14131 * (defaults to null with no animation)
14132 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14133 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14134 * property for valid values (defaults to 'all')
14135 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14136 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14137 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14138 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14139 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14140 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14141 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14142 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14143 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14144 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14145 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14146 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14147 * draggable = true (defaults to false)
14148 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14149 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14150 * shadow (defaults to false)
14151 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14152 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14153 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14154 * @cfg {Array} buttons Array of buttons
14155 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14157 * Create a new BasicDialog.
14158 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14159 * @param {Object} config Configuration options
14161 Roo.BasicDialog = function(el, config){
14162 this.el = Roo.get(el);
14163 var dh = Roo.DomHelper;
14164 if(!this.el && config && config.autoCreate){
14165 if(typeof config.autoCreate == "object"){
14166 if(!config.autoCreate.id){
14167 config.autoCreate.id = el;
14169 this.el = dh.append(document.body,
14170 config.autoCreate, true);
14172 this.el = dh.append(document.body,
14173 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14177 el.setDisplayed(true);
14178 el.hide = this.hideAction;
14180 el.addClass("x-dlg");
14182 Roo.apply(this, config);
14184 this.proxy = el.createProxy("x-dlg-proxy");
14185 this.proxy.hide = this.hideAction;
14186 this.proxy.setOpacity(.5);
14190 el.setWidth(config.width);
14193 el.setHeight(config.height);
14195 this.size = el.getSize();
14196 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14197 this.xy = [config.x,config.y];
14199 this.xy = el.getCenterXY(true);
14201 /** The header element @type Roo.Element */
14202 this.header = el.child("> .x-dlg-hd");
14203 /** The body element @type Roo.Element */
14204 this.body = el.child("> .x-dlg-bd");
14205 /** The footer element @type Roo.Element */
14206 this.footer = el.child("> .x-dlg-ft");
14209 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14212 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14215 this.header.unselectable();
14217 this.header.update(this.title);
14219 // this element allows the dialog to be focused for keyboard event
14220 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14221 this.focusEl.swallowEvent("click", true);
14223 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14225 // wrap the body and footer for special rendering
14226 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14228 this.bwrap.dom.appendChild(this.footer.dom);
14231 this.bg = this.el.createChild({
14232 tag: "div", cls:"x-dlg-bg",
14233 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14235 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14238 if(this.autoScroll !== false && !this.autoTabs){
14239 this.body.setStyle("overflow", "auto");
14242 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14244 if(this.closable !== false){
14245 this.el.addClass("x-dlg-closable");
14246 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14247 this.close.on("click", this.closeClick, this);
14248 this.close.addClassOnOver("x-dlg-close-over");
14250 if(this.collapsible !== false){
14251 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14252 this.collapseBtn.on("click", this.collapseClick, this);
14253 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14254 this.header.on("dblclick", this.collapseClick, this);
14256 if(this.resizable !== false){
14257 this.el.addClass("x-dlg-resizable");
14258 this.resizer = new Roo.Resizable(el, {
14259 minWidth: this.minWidth || 80,
14260 minHeight:this.minHeight || 80,
14261 handles: this.resizeHandles || "all",
14264 this.resizer.on("beforeresize", this.beforeResize, this);
14265 this.resizer.on("resize", this.onResize, this);
14267 if(this.draggable !== false){
14268 el.addClass("x-dlg-draggable");
14269 if (!this.proxyDrag) {
14270 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14273 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14275 dd.setHandleElId(this.header.id);
14276 dd.endDrag = this.endMove.createDelegate(this);
14277 dd.startDrag = this.startMove.createDelegate(this);
14278 dd.onDrag = this.onDrag.createDelegate(this);
14283 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14284 this.mask.enableDisplayMode("block");
14286 this.el.addClass("x-dlg-modal");
14289 this.shadow = new Roo.Shadow({
14290 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14291 offset : this.shadowOffset
14294 this.shadowOffset = 0;
14296 if(Roo.useShims && this.shim !== false){
14297 this.shim = this.el.createShim();
14298 this.shim.hide = this.hideAction;
14306 if (this.buttons) {
14307 var bts= this.buttons;
14309 Roo.each(bts, function(b) {
14318 * Fires when a key is pressed
14319 * @param {Roo.BasicDialog} this
14320 * @param {Roo.EventObject} e
14325 * Fires when this dialog is moved by the user.
14326 * @param {Roo.BasicDialog} this
14327 * @param {Number} x The new page X
14328 * @param {Number} y The new page Y
14333 * Fires when this dialog is resized by the user.
14334 * @param {Roo.BasicDialog} this
14335 * @param {Number} width The new width
14336 * @param {Number} height The new height
14340 * @event beforehide
14341 * Fires before this dialog is hidden.
14342 * @param {Roo.BasicDialog} this
14344 "beforehide" : true,
14347 * Fires when this dialog is hidden.
14348 * @param {Roo.BasicDialog} this
14352 * @event beforeshow
14353 * Fires before this dialog is shown.
14354 * @param {Roo.BasicDialog} this
14356 "beforeshow" : true,
14359 * Fires when this dialog is shown.
14360 * @param {Roo.BasicDialog} this
14364 el.on("keydown", this.onKeyDown, this);
14365 el.on("mousedown", this.toFront, this);
14366 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14368 Roo.DialogManager.register(this);
14369 Roo.BasicDialog.superclass.constructor.call(this);
14372 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14373 shadowOffset: Roo.isIE ? 6 : 5,
14376 minButtonWidth: 75,
14377 defaultButton: null,
14378 buttonAlign: "right",
14383 * Sets the dialog title text
14384 * @param {String} text The title text to display
14385 * @return {Roo.BasicDialog} this
14387 setTitle : function(text){
14388 this.header.update(text);
14393 closeClick : function(){
14398 collapseClick : function(){
14399 this[this.collapsed ? "expand" : "collapse"]();
14403 * Collapses the dialog to its minimized state (only the title bar is visible).
14404 * Equivalent to the user clicking the collapse dialog button.
14406 collapse : function(){
14407 if(!this.collapsed){
14408 this.collapsed = true;
14409 this.el.addClass("x-dlg-collapsed");
14410 this.restoreHeight = this.el.getHeight();
14411 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14416 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14417 * clicking the expand dialog button.
14419 expand : function(){
14420 if(this.collapsed){
14421 this.collapsed = false;
14422 this.el.removeClass("x-dlg-collapsed");
14423 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14428 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14429 * @return {Roo.TabPanel} The tabs component
14431 initTabs : function(){
14432 var tabs = this.getTabs();
14433 while(tabs.getTab(0)){
14436 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14438 tabs.addTab(Roo.id(dom), dom.title);
14446 beforeResize : function(){
14447 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14451 onResize : function(){
14452 this.refreshSize();
14453 this.syncBodyHeight();
14454 this.adjustAssets();
14456 this.fireEvent("resize", this, this.size.width, this.size.height);
14460 onKeyDown : function(e){
14461 if(this.isVisible()){
14462 this.fireEvent("keydown", this, e);
14467 * Resizes the dialog.
14468 * @param {Number} width
14469 * @param {Number} height
14470 * @return {Roo.BasicDialog} this
14472 resizeTo : function(width, height){
14473 this.el.setSize(width, height);
14474 this.size = {width: width, height: height};
14475 this.syncBodyHeight();
14476 if(this.fixedcenter){
14479 if(this.isVisible()){
14480 this.constrainXY();
14481 this.adjustAssets();
14483 this.fireEvent("resize", this, width, height);
14489 * Resizes the dialog to fit the specified content size.
14490 * @param {Number} width
14491 * @param {Number} height
14492 * @return {Roo.BasicDialog} this
14494 setContentSize : function(w, h){
14495 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14496 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14497 //if(!this.el.isBorderBox()){
14498 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14499 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14502 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14503 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14505 this.resizeTo(w, h);
14510 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14511 * executed in response to a particular key being pressed while the dialog is active.
14512 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14513 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14514 * @param {Function} fn The function to call
14515 * @param {Object} scope (optional) The scope of the function
14516 * @return {Roo.BasicDialog} this
14518 addKeyListener : function(key, fn, scope){
14519 var keyCode, shift, ctrl, alt;
14520 if(typeof key == "object" && !(key instanceof Array)){
14521 keyCode = key["key"];
14522 shift = key["shift"];
14523 ctrl = key["ctrl"];
14528 var handler = function(dlg, e){
14529 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14530 var k = e.getKey();
14531 if(keyCode instanceof Array){
14532 for(var i = 0, len = keyCode.length; i < len; i++){
14533 if(keyCode[i] == k){
14534 fn.call(scope || window, dlg, k, e);
14540 fn.call(scope || window, dlg, k, e);
14545 this.on("keydown", handler);
14550 * Returns the TabPanel component (creates it if it doesn't exist).
14551 * Note: If you wish to simply check for the existence of tabs without creating them,
14552 * check for a null 'tabs' property.
14553 * @return {Roo.TabPanel} The tabs component
14555 getTabs : function(){
14557 this.el.addClass("x-dlg-auto-tabs");
14558 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14559 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14565 * Adds a button to the footer section of the dialog.
14566 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14567 * object or a valid Roo.DomHelper element config
14568 * @param {Function} handler The function called when the button is clicked
14569 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14570 * @return {Roo.Button} The new button
14572 addButton : function(config, handler, scope){
14573 var dh = Roo.DomHelper;
14575 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14577 if(!this.btnContainer){
14578 var tb = this.footer.createChild({
14580 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14581 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14583 this.btnContainer = tb.firstChild.firstChild.firstChild;
14588 minWidth: this.minButtonWidth,
14591 if(typeof config == "string"){
14592 bconfig.text = config;
14595 bconfig.dhconfig = config;
14597 Roo.apply(bconfig, config);
14601 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14602 bconfig.position = Math.max(0, bconfig.position);
14603 fc = this.btnContainer.childNodes[bconfig.position];
14606 var btn = new Roo.Button(
14608 this.btnContainer.insertBefore(document.createElement("td"),fc)
14609 : this.btnContainer.appendChild(document.createElement("td")),
14610 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14613 this.syncBodyHeight();
14616 * Array of all the buttons that have been added to this dialog via addButton
14621 this.buttons.push(btn);
14626 * Sets the default button to be focused when the dialog is displayed.
14627 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14628 * @return {Roo.BasicDialog} this
14630 setDefaultButton : function(btn){
14631 this.defaultButton = btn;
14636 getHeaderFooterHeight : function(safe){
14639 height += this.header.getHeight();
14642 var fm = this.footer.getMargins();
14643 height += (this.footer.getHeight()+fm.top+fm.bottom);
14645 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14646 height += this.centerBg.getPadding("tb");
14651 syncBodyHeight : function(){
14652 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14653 var height = this.size.height - this.getHeaderFooterHeight(false);
14654 bd.setHeight(height-bd.getMargins("tb"));
14655 var hh = this.header.getHeight();
14656 var h = this.size.height-hh;
14658 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14659 bw.setHeight(h-cb.getPadding("tb"));
14660 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14661 bd.setWidth(bw.getWidth(true));
14663 this.tabs.syncHeight();
14665 this.tabs.el.repaint();
14671 * Restores the previous state of the dialog if Roo.state is configured.
14672 * @return {Roo.BasicDialog} this
14674 restoreState : function(){
14675 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14676 if(box && box.width){
14677 this.xy = [box.x, box.y];
14678 this.resizeTo(box.width, box.height);
14684 beforeShow : function(){
14686 if(this.fixedcenter){
14687 this.xy = this.el.getCenterXY(true);
14690 Roo.get(document.body).addClass("x-body-masked");
14691 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14694 this.constrainXY();
14698 animShow : function(){
14699 var b = Roo.get(this.animateTarget).getBox();
14700 this.proxy.setSize(b.width, b.height);
14701 this.proxy.setLocation(b.x, b.y);
14703 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14704 true, .35, this.showEl.createDelegate(this));
14708 * Shows the dialog.
14709 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14710 * @return {Roo.BasicDialog} this
14712 show : function(animateTarget){
14713 if (this.fireEvent("beforeshow", this) === false){
14716 if(this.syncHeightBeforeShow){
14717 this.syncBodyHeight();
14718 }else if(this.firstShow){
14719 this.firstShow = false;
14720 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14722 this.animateTarget = animateTarget || this.animateTarget;
14723 if(!this.el.isVisible()){
14725 if(this.animateTarget && Roo.get(this.animateTarget)){
14735 showEl : function(){
14737 this.el.setXY(this.xy);
14739 this.adjustAssets(true);
14742 // IE peekaboo bug - fix found by Dave Fenwick
14746 this.fireEvent("show", this);
14750 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14751 * dialog itself will receive focus.
14753 focus : function(){
14754 if(this.defaultButton){
14755 this.defaultButton.focus();
14757 this.focusEl.focus();
14762 constrainXY : function(){
14763 if(this.constraintoviewport !== false){
14764 if(!this.viewSize){
14765 if(this.container){
14766 var s = this.container.getSize();
14767 this.viewSize = [s.width, s.height];
14769 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14772 var s = Roo.get(this.container||document).getScroll();
14774 var x = this.xy[0], y = this.xy[1];
14775 var w = this.size.width, h = this.size.height;
14776 var vw = this.viewSize[0], vh = this.viewSize[1];
14777 // only move it if it needs it
14779 // first validate right/bottom
14780 if(x + w > vw+s.left){
14784 if(y + h > vh+s.top){
14788 // then make sure top/left isn't negative
14800 if(this.isVisible()){
14801 this.el.setLocation(x, y);
14802 this.adjustAssets();
14809 onDrag : function(){
14810 if(!this.proxyDrag){
14811 this.xy = this.el.getXY();
14812 this.adjustAssets();
14817 adjustAssets : function(doShow){
14818 var x = this.xy[0], y = this.xy[1];
14819 var w = this.size.width, h = this.size.height;
14820 if(doShow === true){
14822 this.shadow.show(this.el);
14828 if(this.shadow && this.shadow.isVisible()){
14829 this.shadow.show(this.el);
14831 if(this.shim && this.shim.isVisible()){
14832 this.shim.setBounds(x, y, w, h);
14837 adjustViewport : function(w, h){
14839 w = Roo.lib.Dom.getViewWidth();
14840 h = Roo.lib.Dom.getViewHeight();
14843 this.viewSize = [w, h];
14844 if(this.modal && this.mask.isVisible()){
14845 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14846 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14848 if(this.isVisible()){
14849 this.constrainXY();
14854 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14855 * shadow, proxy, mask, etc.) Also removes all event listeners.
14856 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14858 destroy : function(removeEl){
14859 if(this.isVisible()){
14860 this.animateTarget = null;
14863 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14865 this.tabs.destroy(removeEl);
14878 for(var i = 0, len = this.buttons.length; i < len; i++){
14879 this.buttons[i].destroy();
14882 this.el.removeAllListeners();
14883 if(removeEl === true){
14884 this.el.update("");
14887 Roo.DialogManager.unregister(this);
14891 startMove : function(){
14892 if(this.proxyDrag){
14895 if(this.constraintoviewport !== false){
14896 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14901 endMove : function(){
14902 if(!this.proxyDrag){
14903 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14905 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14908 this.refreshSize();
14909 this.adjustAssets();
14911 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14915 * Brings this dialog to the front of any other visible dialogs
14916 * @return {Roo.BasicDialog} this
14918 toFront : function(){
14919 Roo.DialogManager.bringToFront(this);
14924 * Sends this dialog to the back (under) of any other visible dialogs
14925 * @return {Roo.BasicDialog} this
14927 toBack : function(){
14928 Roo.DialogManager.sendToBack(this);
14933 * Centers this dialog in the viewport
14934 * @return {Roo.BasicDialog} this
14936 center : function(){
14937 var xy = this.el.getCenterXY(true);
14938 this.moveTo(xy[0], xy[1]);
14943 * Moves the dialog's top-left corner to the specified point
14944 * @param {Number} x
14945 * @param {Number} y
14946 * @return {Roo.BasicDialog} this
14948 moveTo : function(x, y){
14950 if(this.isVisible()){
14951 this.el.setXY(this.xy);
14952 this.adjustAssets();
14958 * Aligns the dialog to the specified element
14959 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14960 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14961 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14962 * @return {Roo.BasicDialog} this
14964 alignTo : function(element, position, offsets){
14965 this.xy = this.el.getAlignToXY(element, position, offsets);
14966 if(this.isVisible()){
14967 this.el.setXY(this.xy);
14968 this.adjustAssets();
14974 * Anchors an element to another element and realigns it when the window is resized.
14975 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14976 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14977 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14978 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14979 * is a number, it is used as the buffer delay (defaults to 50ms).
14980 * @return {Roo.BasicDialog} this
14982 anchorTo : function(el, alignment, offsets, monitorScroll){
14983 var action = function(){
14984 this.alignTo(el, alignment, offsets);
14986 Roo.EventManager.onWindowResize(action, this);
14987 var tm = typeof monitorScroll;
14988 if(tm != 'undefined'){
14989 Roo.EventManager.on(window, 'scroll', action, this,
14990 {buffer: tm == 'number' ? monitorScroll : 50});
14997 * Returns true if the dialog is visible
14998 * @return {Boolean}
15000 isVisible : function(){
15001 return this.el.isVisible();
15005 animHide : function(callback){
15006 var b = Roo.get(this.animateTarget).getBox();
15008 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15010 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15011 this.hideEl.createDelegate(this, [callback]));
15015 * Hides the dialog.
15016 * @param {Function} callback (optional) Function to call when the dialog is hidden
15017 * @return {Roo.BasicDialog} this
15019 hide : function(callback){
15020 if (this.fireEvent("beforehide", this) === false){
15024 this.shadow.hide();
15029 // sometimes animateTarget seems to get set.. causing problems...
15030 // this just double checks..
15031 if(this.animateTarget && Roo.get(this.animateTarget)) {
15032 this.animHide(callback);
15035 this.hideEl(callback);
15041 hideEl : function(callback){
15045 Roo.get(document.body).removeClass("x-body-masked");
15047 this.fireEvent("hide", this);
15048 if(typeof callback == "function"){
15054 hideAction : function(){
15055 this.setLeft("-10000px");
15056 this.setTop("-10000px");
15057 this.setStyle("visibility", "hidden");
15061 refreshSize : function(){
15062 this.size = this.el.getSize();
15063 this.xy = this.el.getXY();
15064 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15068 // z-index is managed by the DialogManager and may be overwritten at any time
15069 setZIndex : function(index){
15071 this.mask.setStyle("z-index", index);
15074 this.shim.setStyle("z-index", ++index);
15077 this.shadow.setZIndex(++index);
15079 this.el.setStyle("z-index", ++index);
15081 this.proxy.setStyle("z-index", ++index);
15084 this.resizer.proxy.setStyle("z-index", ++index);
15087 this.lastZIndex = index;
15091 * Returns the element for this dialog
15092 * @return {Roo.Element} The underlying dialog Element
15094 getEl : function(){
15100 * @class Roo.DialogManager
15101 * Provides global access to BasicDialogs that have been created and
15102 * support for z-indexing (layering) multiple open dialogs.
15104 Roo.DialogManager = function(){
15106 var accessList = [];
15110 var sortDialogs = function(d1, d2){
15111 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15115 var orderDialogs = function(){
15116 accessList.sort(sortDialogs);
15117 var seed = Roo.DialogManager.zseed;
15118 for(var i = 0, len = accessList.length; i < len; i++){
15119 var dlg = accessList[i];
15121 dlg.setZIndex(seed + (i*10));
15128 * The starting z-index for BasicDialogs (defaults to 9000)
15129 * @type Number The z-index value
15134 register : function(dlg){
15135 list[dlg.id] = dlg;
15136 accessList.push(dlg);
15140 unregister : function(dlg){
15141 delete list[dlg.id];
15144 if(!accessList.indexOf){
15145 for( i = 0, len = accessList.length; i < len; i++){
15146 if(accessList[i] == dlg){
15147 accessList.splice(i, 1);
15152 i = accessList.indexOf(dlg);
15154 accessList.splice(i, 1);
15160 * Gets a registered dialog by id
15161 * @param {String/Object} id The id of the dialog or a dialog
15162 * @return {Roo.BasicDialog} this
15164 get : function(id){
15165 return typeof id == "object" ? id : list[id];
15169 * Brings the specified dialog to the front
15170 * @param {String/Object} dlg The id of the dialog or a dialog
15171 * @return {Roo.BasicDialog} this
15173 bringToFront : function(dlg){
15174 dlg = this.get(dlg);
15177 dlg._lastAccess = new Date().getTime();
15184 * Sends the specified dialog to the back
15185 * @param {String/Object} dlg The id of the dialog or a dialog
15186 * @return {Roo.BasicDialog} this
15188 sendToBack : function(dlg){
15189 dlg = this.get(dlg);
15190 dlg._lastAccess = -(new Date().getTime());
15196 * Hides all dialogs
15198 hideAll : function(){
15199 for(var id in list){
15200 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15209 * @class Roo.LayoutDialog
15210 * @extends Roo.BasicDialog
15211 * Dialog which provides adjustments for working with a layout in a Dialog.
15212 * Add your necessary layout config options to the dialog's config.<br>
15213 * Example usage (including a nested layout):
15216 dialog = new Roo.LayoutDialog("download-dlg", {
15225 // layout config merges with the dialog config
15227 tabPosition: "top",
15228 alwaysShowTabs: true
15231 dialog.addKeyListener(27, dialog.hide, dialog);
15232 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15233 dialog.addButton("Build It!", this.getDownload, this);
15235 // we can even add nested layouts
15236 var innerLayout = new Roo.BorderLayout("dl-inner", {
15246 innerLayout.beginUpdate();
15247 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15248 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15249 innerLayout.endUpdate(true);
15251 var layout = dialog.getLayout();
15252 layout.beginUpdate();
15253 layout.add("center", new Roo.ContentPanel("standard-panel",
15254 {title: "Download the Source", fitToFrame:true}));
15255 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15256 {title: "Build your own roo.js"}));
15257 layout.getRegion("center").showPanel(sp);
15258 layout.endUpdate();
15262 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15263 * @param {Object} config configuration options
15265 Roo.LayoutDialog = function(el, cfg){
15268 if (typeof(cfg) == 'undefined') {
15269 config = Roo.apply({}, el);
15270 // not sure why we use documentElement here.. - it should always be body.
15271 // IE7 borks horribly if we use documentElement.
15272 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15273 //config.autoCreate = true;
15277 config.autoTabs = false;
15278 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15279 this.body.setStyle({overflow:"hidden", position:"relative"});
15280 this.layout = new Roo.BorderLayout(this.body.dom, config);
15281 this.layout.monitorWindowResize = false;
15282 this.el.addClass("x-dlg-auto-layout");
15283 // fix case when center region overwrites center function
15284 this.center = Roo.BasicDialog.prototype.center;
15285 this.on("show", this.layout.layout, this.layout, true);
15286 if (config.items) {
15287 var xitems = config.items;
15288 delete config.items;
15289 Roo.each(xitems, this.addxtype, this);
15294 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15296 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15299 endUpdate : function(){
15300 this.layout.endUpdate();
15304 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15307 beginUpdate : function(){
15308 this.layout.beginUpdate();
15312 * Get the BorderLayout for this dialog
15313 * @return {Roo.BorderLayout}
15315 getLayout : function(){
15316 return this.layout;
15319 showEl : function(){
15320 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15322 this.layout.layout();
15327 // Use the syncHeightBeforeShow config option to control this automatically
15328 syncBodyHeight : function(){
15329 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15330 if(this.layout){this.layout.layout();}
15334 * Add an xtype element (actually adds to the layout.)
15335 * @return {Object} xdata xtype object data.
15338 addxtype : function(c) {
15339 return this.layout.addxtype(c);
15343 * Ext JS Library 1.1.1
15344 * Copyright(c) 2006-2007, Ext JS, LLC.
15346 * Originally Released Under LGPL - original licence link has changed is not relivant.
15349 * <script type="text/javascript">
15353 * @class Roo.MessageBox
15354 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15358 Roo.Msg.alert('Status', 'Changes saved successfully.');
15360 // Prompt for user data:
15361 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15363 // process text value...
15367 // Show a dialog using config options:
15369 title:'Save Changes?',
15370 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15371 buttons: Roo.Msg.YESNOCANCEL,
15378 Roo.MessageBox = function(){
15379 var dlg, opt, mask, waitTimer;
15380 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15381 var buttons, activeTextEl, bwidth;
15384 var handleButton = function(button){
15386 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15390 var handleHide = function(){
15391 if(opt && opt.cls){
15392 dlg.el.removeClass(opt.cls);
15395 Roo.TaskMgr.stop(waitTimer);
15401 var updateButtons = function(b){
15404 buttons["ok"].hide();
15405 buttons["cancel"].hide();
15406 buttons["yes"].hide();
15407 buttons["no"].hide();
15408 dlg.footer.dom.style.display = 'none';
15411 dlg.footer.dom.style.display = '';
15412 for(var k in buttons){
15413 if(typeof buttons[k] != "function"){
15416 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15417 width += buttons[k].el.getWidth()+15;
15427 var handleEsc = function(d, k, e){
15428 if(opt && opt.closable !== false){
15438 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15439 * @return {Roo.BasicDialog} The BasicDialog element
15441 getDialog : function(){
15443 dlg = new Roo.BasicDialog("x-msg-box", {
15448 constraintoviewport:false,
15450 collapsible : false,
15453 width:400, height:100,
15454 buttonAlign:"center",
15455 closeClick : function(){
15456 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15457 handleButton("no");
15459 handleButton("cancel");
15463 dlg.on("hide", handleHide);
15465 dlg.addKeyListener(27, handleEsc);
15467 var bt = this.buttonText;
15468 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15469 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15470 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15471 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15472 bodyEl = dlg.body.createChild({
15474 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
15476 msgEl = bodyEl.dom.firstChild;
15477 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15478 textboxEl.enableDisplayMode();
15479 textboxEl.addKeyListener([10,13], function(){
15480 if(dlg.isVisible() && opt && opt.buttons){
15481 if(opt.buttons.ok){
15482 handleButton("ok");
15483 }else if(opt.buttons.yes){
15484 handleButton("yes");
15488 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15489 textareaEl.enableDisplayMode();
15490 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15491 progressEl.enableDisplayMode();
15492 var pf = progressEl.dom.firstChild;
15494 pp = Roo.get(pf.firstChild);
15495 pp.setHeight(pf.offsetHeight);
15503 * Updates the message box body text
15504 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15505 * the XHTML-compliant non-breaking space character '&#160;')
15506 * @return {Roo.MessageBox} This message box
15508 updateText : function(text){
15509 if(!dlg.isVisible() && !opt.width){
15510 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15512 msgEl.innerHTML = text || ' ';
15513 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15514 Math.max(opt.minWidth || this.minWidth, bwidth));
15516 activeTextEl.setWidth(w);
15518 if(dlg.isVisible()){
15519 dlg.fixedcenter = false;
15521 dlg.setContentSize(w, bodyEl.getHeight());
15522 if(dlg.isVisible()){
15523 dlg.fixedcenter = true;
15529 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15530 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15531 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15532 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15533 * @return {Roo.MessageBox} This message box
15535 updateProgress : function(value, text){
15537 this.updateText(text);
15539 if (pp) { // weird bug on my firefox - for some reason this is not defined
15540 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15546 * Returns true if the message box is currently displayed
15547 * @return {Boolean} True if the message box is visible, else false
15549 isVisible : function(){
15550 return dlg && dlg.isVisible();
15554 * Hides the message box if it is displayed
15557 if(this.isVisible()){
15563 * Displays a new message box, or reinitializes an existing message box, based on the config options
15564 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15565 * The following config object properties are supported:
15567 Property Type Description
15568 ---------- --------------- ------------------------------------------------------------------------------------
15569 animEl String/Element An id or Element from which the message box should animate as it opens and
15570 closes (defaults to undefined)
15571 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15572 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15573 closable Boolean False to hide the top-right close button (defaults to true). Note that
15574 progress and wait dialogs will ignore this property and always hide the
15575 close button as they can only be closed programmatically.
15576 cls String A custom CSS class to apply to the message box element
15577 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15578 displayed (defaults to 75)
15579 fn Function A callback function to execute after closing the dialog. The arguments to the
15580 function will be btn (the name of the button that was clicked, if applicable,
15581 e.g. "ok"), and text (the value of the active text field, if applicable).
15582 Progress and wait dialogs will ignore this option since they do not respond to
15583 user actions and can only be closed programmatically, so any required function
15584 should be called by the same code after it closes the dialog.
15585 icon String A CSS class that provides a background image to be used as an icon for
15586 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15587 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15588 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15589 modal Boolean False to allow user interaction with the page while the message box is
15590 displayed (defaults to true)
15591 msg String A string that will replace the existing message box body text (defaults
15592 to the XHTML-compliant non-breaking space character ' ')
15593 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15594 progress Boolean True to display a progress bar (defaults to false)
15595 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15596 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15597 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15598 title String The title text
15599 value String The string value to set into the active textbox element if displayed
15600 wait Boolean True to display a progress bar (defaults to false)
15601 width Number The width of the dialog in pixels
15608 msg: 'Please enter your address:',
15610 buttons: Roo.MessageBox.OKCANCEL,
15613 animEl: 'addAddressBtn'
15616 * @param {Object} config Configuration options
15617 * @return {Roo.MessageBox} This message box
15619 show : function(options){
15620 if(this.isVisible()){
15623 var d = this.getDialog();
15625 d.setTitle(opt.title || " ");
15626 d.close.setDisplayed(opt.closable !== false);
15627 activeTextEl = textboxEl;
15628 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15633 textareaEl.setHeight(typeof opt.multiline == "number" ?
15634 opt.multiline : this.defaultTextHeight);
15635 activeTextEl = textareaEl;
15644 progressEl.setDisplayed(opt.progress === true);
15645 this.updateProgress(0);
15646 activeTextEl.dom.value = opt.value || "";
15648 dlg.setDefaultButton(activeTextEl);
15650 var bs = opt.buttons;
15653 db = buttons["ok"];
15654 }else if(bs && bs.yes){
15655 db = buttons["yes"];
15657 dlg.setDefaultButton(db);
15659 bwidth = updateButtons(opt.buttons);
15660 this.updateText(opt.msg);
15662 d.el.addClass(opt.cls);
15664 d.proxyDrag = opt.proxyDrag === true;
15665 d.modal = opt.modal !== false;
15666 d.mask = opt.modal !== false ? mask : false;
15667 if(!d.isVisible()){
15668 // force it to the end of the z-index stack so it gets a cursor in FF
15669 document.body.appendChild(dlg.el.dom);
15670 d.animateTarget = null;
15671 d.show(options.animEl);
15677 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15678 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15679 * and closing the message box when the process is complete.
15680 * @param {String} title The title bar text
15681 * @param {String} msg The message box body text
15682 * @return {Roo.MessageBox} This message box
15684 progress : function(title, msg){
15691 minWidth: this.minProgressWidth,
15698 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15699 * If a callback function is passed it will be called after the user clicks the button, and the
15700 * id of the button that was clicked will be passed as the only parameter to the callback
15701 * (could also be the top-right close button).
15702 * @param {String} title The title bar text
15703 * @param {String} msg The message box body text
15704 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15705 * @param {Object} scope (optional) The scope of the callback function
15706 * @return {Roo.MessageBox} This message box
15708 alert : function(title, msg, fn, scope){
15721 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15722 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15723 * You are responsible for closing the message box when the process is complete.
15724 * @param {String} msg The message box body text
15725 * @param {String} title (optional) The title bar text
15726 * @return {Roo.MessageBox} This message box
15728 wait : function(msg, title){
15739 waitTimer = Roo.TaskMgr.start({
15741 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15749 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15750 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15751 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15752 * @param {String} title The title bar text
15753 * @param {String} msg The message box body text
15754 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15755 * @param {Object} scope (optional) The scope of the callback function
15756 * @return {Roo.MessageBox} This message box
15758 confirm : function(title, msg, fn, scope){
15762 buttons: this.YESNO,
15771 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15772 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15773 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15774 * (could also be the top-right close button) and the text that was entered will be passed as the two
15775 * parameters to the callback.
15776 * @param {String} title The title bar text
15777 * @param {String} msg The message box body text
15778 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15779 * @param {Object} scope (optional) The scope of the callback function
15780 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15781 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15782 * @return {Roo.MessageBox} This message box
15784 prompt : function(title, msg, fn, scope, multiline){
15788 buttons: this.OKCANCEL,
15793 multiline: multiline,
15800 * Button config that displays a single OK button
15805 * Button config that displays Yes and No buttons
15808 YESNO : {yes:true, no:true},
15810 * Button config that displays OK and Cancel buttons
15813 OKCANCEL : {ok:true, cancel:true},
15815 * Button config that displays Yes, No and Cancel buttons
15818 YESNOCANCEL : {yes:true, no:true, cancel:true},
15821 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15824 defaultTextHeight : 75,
15826 * The maximum width in pixels of the message box (defaults to 600)
15831 * The minimum width in pixels of the message box (defaults to 100)
15836 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15837 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15840 minProgressWidth : 250,
15842 * An object containing the default button text strings that can be overriden for localized language support.
15843 * Supported properties are: ok, cancel, yes and no.
15844 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15857 * Shorthand for {@link Roo.MessageBox}
15859 Roo.Msg = Roo.MessageBox;/*
15861 * Ext JS Library 1.1.1
15862 * Copyright(c) 2006-2007, Ext JS, LLC.
15864 * Originally Released Under LGPL - original licence link has changed is not relivant.
15867 * <script type="text/javascript">
15870 * @class Roo.QuickTips
15871 * Provides attractive and customizable tooltips for any element.
15874 Roo.QuickTips = function(){
15875 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15876 var ce, bd, xy, dd;
15877 var visible = false, disabled = true, inited = false;
15878 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15880 var onOver = function(e){
15884 var t = e.getTarget();
15885 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15888 if(ce && t == ce.el){
15889 clearTimeout(hideProc);
15892 if(t && tagEls[t.id]){
15893 tagEls[t.id].el = t;
15894 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15897 var ttp, et = Roo.fly(t);
15898 var ns = cfg.namespace;
15899 if(tm.interceptTitles && t.title){
15902 t.removeAttribute("title");
15903 e.preventDefault();
15905 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15908 showProc = show.defer(tm.showDelay, tm, [{
15911 width: et.getAttributeNS(ns, cfg.width),
15912 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15913 title: et.getAttributeNS(ns, cfg.title),
15914 cls: et.getAttributeNS(ns, cfg.cls)
15919 var onOut = function(e){
15920 clearTimeout(showProc);
15921 var t = e.getTarget();
15922 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15923 hideProc = setTimeout(hide, tm.hideDelay);
15927 var onMove = function(e){
15933 if(tm.trackMouse && ce){
15938 var onDown = function(e){
15939 clearTimeout(showProc);
15940 clearTimeout(hideProc);
15942 if(tm.hideOnClick){
15945 tm.enable.defer(100, tm);
15950 var getPad = function(){
15951 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15954 var show = function(o){
15958 clearTimeout(dismissProc);
15960 if(removeCls){ // in case manually hidden
15961 el.removeClass(removeCls);
15965 el.addClass(ce.cls);
15966 removeCls = ce.cls;
15969 tipTitle.update(ce.title);
15972 tipTitle.update('');
15975 el.dom.style.width = tm.maxWidth+'px';
15976 //tipBody.dom.style.width = '';
15977 tipBodyText.update(o.text);
15978 var p = getPad(), w = ce.width;
15980 var td = tipBodyText.dom;
15981 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15982 if(aw > tm.maxWidth){
15984 }else if(aw < tm.minWidth){
15990 //tipBody.setWidth(w);
15991 el.setWidth(parseInt(w, 10) + p);
15992 if(ce.autoHide === false){
15993 close.setDisplayed(true);
15998 close.setDisplayed(false);
16004 el.avoidY = xy[1]-18;
16009 el.setStyle("visibility", "visible");
16010 el.fadeIn({callback: afterShow});
16016 var afterShow = function(){
16020 if(tm.autoDismiss && ce.autoHide !== false){
16021 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16026 var hide = function(noanim){
16027 clearTimeout(dismissProc);
16028 clearTimeout(hideProc);
16030 if(el.isVisible()){
16032 if(noanim !== true && tm.animate){
16033 el.fadeOut({callback: afterHide});
16040 var afterHide = function(){
16043 el.removeClass(removeCls);
16050 * @cfg {Number} minWidth
16051 * The minimum width of the quick tip (defaults to 40)
16055 * @cfg {Number} maxWidth
16056 * The maximum width of the quick tip (defaults to 300)
16060 * @cfg {Boolean} interceptTitles
16061 * True to automatically use the element's DOM title value if available (defaults to false)
16063 interceptTitles : false,
16065 * @cfg {Boolean} trackMouse
16066 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16068 trackMouse : false,
16070 * @cfg {Boolean} hideOnClick
16071 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16073 hideOnClick : true,
16075 * @cfg {Number} showDelay
16076 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16080 * @cfg {Number} hideDelay
16081 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16085 * @cfg {Boolean} autoHide
16086 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16087 * Used in conjunction with hideDelay.
16092 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16093 * (defaults to true). Used in conjunction with autoDismissDelay.
16095 autoDismiss : true,
16098 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16100 autoDismissDelay : 5000,
16102 * @cfg {Boolean} animate
16103 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16108 * @cfg {String} title
16109 * Title text to display (defaults to ''). This can be any valid HTML markup.
16113 * @cfg {String} text
16114 * Body text to display (defaults to ''). This can be any valid HTML markup.
16118 * @cfg {String} cls
16119 * A CSS class to apply to the base quick tip element (defaults to '').
16123 * @cfg {Number} width
16124 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16125 * minWidth or maxWidth.
16130 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16131 * or display QuickTips in a page.
16134 tm = Roo.QuickTips;
16135 cfg = tm.tagConfig;
16137 if(!Roo.isReady){ // allow calling of init() before onReady
16138 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16141 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16142 el.fxDefaults = {stopFx: true};
16143 // maximum custom styling
16144 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
16145 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
16146 tipTitle = el.child('h3');
16147 tipTitle.enableDisplayMode("block");
16148 tipBody = el.child('div.x-tip-bd');
16149 tipBodyText = el.child('div.x-tip-bd-inner');
16150 //bdLeft = el.child('div.x-tip-bd-left');
16151 //bdRight = el.child('div.x-tip-bd-right');
16152 close = el.child('div.x-tip-close');
16153 close.enableDisplayMode("block");
16154 close.on("click", hide);
16155 var d = Roo.get(document);
16156 d.on("mousedown", onDown);
16157 d.on("mouseover", onOver);
16158 d.on("mouseout", onOut);
16159 d.on("mousemove", onMove);
16160 esc = d.addKeyListener(27, hide);
16163 dd = el.initDD("default", null, {
16164 onDrag : function(){
16168 dd.setHandleElId(tipTitle.id);
16177 * Configures a new quick tip instance and assigns it to a target element. The following config options
16180 Property Type Description
16181 ---------- --------------------- ------------------------------------------------------------------------
16182 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16184 * @param {Object} config The config object
16186 register : function(config){
16187 var cs = config instanceof Array ? config : arguments;
16188 for(var i = 0, len = cs.length; i < len; i++) {
16190 var target = c.target;
16192 if(target instanceof Array){
16193 for(var j = 0, jlen = target.length; j < jlen; j++){
16194 tagEls[target[j]] = c;
16197 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16204 * Removes this quick tip from its element and destroys it.
16205 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16207 unregister : function(el){
16208 delete tagEls[Roo.id(el)];
16212 * Enable this quick tip.
16214 enable : function(){
16215 if(inited && disabled){
16217 if(locks.length < 1){
16224 * Disable this quick tip.
16226 disable : function(){
16228 clearTimeout(showProc);
16229 clearTimeout(hideProc);
16230 clearTimeout(dismissProc);
16238 * Returns true if the quick tip is enabled, else false.
16240 isEnabled : function(){
16247 attribute : "qtip",
16257 // backwards compat
16258 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16260 * Ext JS Library 1.1.1
16261 * Copyright(c) 2006-2007, Ext JS, LLC.
16263 * Originally Released Under LGPL - original licence link has changed is not relivant.
16266 * <script type="text/javascript">
16271 * @class Roo.tree.TreePanel
16272 * @extends Roo.data.Tree
16274 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16275 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16276 * @cfg {Boolean} enableDD true to enable drag and drop
16277 * @cfg {Boolean} enableDrag true to enable just drag
16278 * @cfg {Boolean} enableDrop true to enable just drop
16279 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16280 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16281 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16282 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16283 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16284 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16285 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16286 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16287 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16288 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16289 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16290 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16291 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16292 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16293 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16296 * @param {String/HTMLElement/Element} el The container element
16297 * @param {Object} config
16299 Roo.tree.TreePanel = function(el, config){
16301 var loader = false;
16303 root = config.root;
16304 delete config.root;
16306 if (config.loader) {
16307 loader = config.loader;
16308 delete config.loader;
16311 Roo.apply(this, config);
16312 Roo.tree.TreePanel.superclass.constructor.call(this);
16313 this.el = Roo.get(el);
16314 this.el.addClass('x-tree');
16315 //console.log(root);
16317 this.setRootNode( Roo.factory(root, Roo.tree));
16320 this.loader = Roo.factory(loader, Roo.tree);
16323 * Read-only. The id of the container element becomes this TreePanel's id.
16325 this.id = this.el.id;
16328 * @event beforeload
16329 * Fires before a node is loaded, return false to cancel
16330 * @param {Node} node The node being loaded
16332 "beforeload" : true,
16335 * Fires when a node is loaded
16336 * @param {Node} node The node that was loaded
16340 * @event textchange
16341 * Fires when the text for a node is changed
16342 * @param {Node} node The node
16343 * @param {String} text The new text
16344 * @param {String} oldText The old text
16346 "textchange" : true,
16348 * @event beforeexpand
16349 * Fires before a node is expanded, return false to cancel.
16350 * @param {Node} node The node
16351 * @param {Boolean} deep
16352 * @param {Boolean} anim
16354 "beforeexpand" : true,
16356 * @event beforecollapse
16357 * Fires before a node is collapsed, return false to cancel.
16358 * @param {Node} node The node
16359 * @param {Boolean} deep
16360 * @param {Boolean} anim
16362 "beforecollapse" : true,
16365 * Fires when a node is expanded
16366 * @param {Node} node The node
16370 * @event disabledchange
16371 * Fires when the disabled status of a node changes
16372 * @param {Node} node The node
16373 * @param {Boolean} disabled
16375 "disabledchange" : true,
16378 * Fires when a node is collapsed
16379 * @param {Node} node The node
16383 * @event beforeclick
16384 * Fires before click processing on a node. Return false to cancel the default action.
16385 * @param {Node} node The node
16386 * @param {Roo.EventObject} e The event object
16388 "beforeclick":true,
16390 * @event checkchange
16391 * Fires when a node with a checkbox's checked property changes
16392 * @param {Node} this This node
16393 * @param {Boolean} checked
16395 "checkchange":true,
16398 * Fires when a node is clicked
16399 * @param {Node} node The node
16400 * @param {Roo.EventObject} e The event object
16405 * Fires when a node is double clicked
16406 * @param {Node} node The node
16407 * @param {Roo.EventObject} e The event object
16411 * @event contextmenu
16412 * Fires when a node is right clicked
16413 * @param {Node} node The node
16414 * @param {Roo.EventObject} e The event object
16416 "contextmenu":true,
16418 * @event beforechildrenrendered
16419 * Fires right before the child nodes for a node are rendered
16420 * @param {Node} node The node
16422 "beforechildrenrendered":true,
16425 * Fires when a node starts being dragged
16426 * @param {Roo.tree.TreePanel} this
16427 * @param {Roo.tree.TreeNode} node
16428 * @param {event} e The raw browser event
16430 "startdrag" : true,
16433 * Fires when a drag operation is complete
16434 * @param {Roo.tree.TreePanel} this
16435 * @param {Roo.tree.TreeNode} node
16436 * @param {event} e The raw browser event
16441 * Fires when a dragged node is dropped on a valid DD target
16442 * @param {Roo.tree.TreePanel} this
16443 * @param {Roo.tree.TreeNode} node
16444 * @param {DD} dd The dd it was dropped on
16445 * @param {event} e The raw browser event
16449 * @event beforenodedrop
16450 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16451 * passed to handlers has the following properties:<br />
16452 * <ul style="padding:5px;padding-left:16px;">
16453 * <li>tree - The TreePanel</li>
16454 * <li>target - The node being targeted for the drop</li>
16455 * <li>data - The drag data from the drag source</li>
16456 * <li>point - The point of the drop - append, above or below</li>
16457 * <li>source - The drag source</li>
16458 * <li>rawEvent - Raw mouse event</li>
16459 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16460 * to be inserted by setting them on this object.</li>
16461 * <li>cancel - Set this to true to cancel the drop.</li>
16463 * @param {Object} dropEvent
16465 "beforenodedrop" : true,
16468 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16469 * passed to handlers has the following properties:<br />
16470 * <ul style="padding:5px;padding-left:16px;">
16471 * <li>tree - The TreePanel</li>
16472 * <li>target - The node being targeted for the drop</li>
16473 * <li>data - The drag data from the drag source</li>
16474 * <li>point - The point of the drop - append, above or below</li>
16475 * <li>source - The drag source</li>
16476 * <li>rawEvent - Raw mouse event</li>
16477 * <li>dropNode - Dropped node(s).</li>
16479 * @param {Object} dropEvent
16483 * @event nodedragover
16484 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16485 * passed to handlers has the following properties:<br />
16486 * <ul style="padding:5px;padding-left:16px;">
16487 * <li>tree - The TreePanel</li>
16488 * <li>target - The node being targeted for the drop</li>
16489 * <li>data - The drag data from the drag source</li>
16490 * <li>point - The point of the drop - append, above or below</li>
16491 * <li>source - The drag source</li>
16492 * <li>rawEvent - Raw mouse event</li>
16493 * <li>dropNode - Drop node(s) provided by the source.</li>
16494 * <li>cancel - Set this to true to signal drop not allowed.</li>
16496 * @param {Object} dragOverEvent
16498 "nodedragover" : true
16501 if(this.singleExpand){
16502 this.on("beforeexpand", this.restrictExpand, this);
16505 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16506 rootVisible : true,
16507 animate: Roo.enableFx,
16510 hlDrop : Roo.enableFx,
16514 rendererTip: false,
16516 restrictExpand : function(node){
16517 var p = node.parentNode;
16519 if(p.expandedChild && p.expandedChild.parentNode == p){
16520 p.expandedChild.collapse();
16522 p.expandedChild = node;
16526 // private override
16527 setRootNode : function(node){
16528 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16529 if(!this.rootVisible){
16530 node.ui = new Roo.tree.RootTreeNodeUI(node);
16536 * Returns the container element for this TreePanel
16538 getEl : function(){
16543 * Returns the default TreeLoader for this TreePanel
16545 getLoader : function(){
16546 return this.loader;
16552 expandAll : function(){
16553 this.root.expand(true);
16557 * Collapse all nodes
16559 collapseAll : function(){
16560 this.root.collapse(true);
16564 * Returns the selection model used by this TreePanel
16566 getSelectionModel : function(){
16567 if(!this.selModel){
16568 this.selModel = new Roo.tree.DefaultSelectionModel();
16570 return this.selModel;
16574 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16575 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16576 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16579 getChecked : function(a, startNode){
16580 startNode = startNode || this.root;
16582 var f = function(){
16583 if(this.attributes.checked){
16584 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16587 startNode.cascade(f);
16592 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16593 * @param {String} path
16594 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16595 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16596 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16598 expandPath : function(path, attr, callback){
16599 attr = attr || "id";
16600 var keys = path.split(this.pathSeparator);
16601 var curNode = this.root;
16602 if(curNode.attributes[attr] != keys[1]){ // invalid root
16604 callback(false, null);
16609 var f = function(){
16610 if(++index == keys.length){
16612 callback(true, curNode);
16616 var c = curNode.findChild(attr, keys[index]);
16619 callback(false, curNode);
16624 c.expand(false, false, f);
16626 curNode.expand(false, false, f);
16630 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16631 * @param {String} path
16632 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16633 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16634 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16636 selectPath : function(path, attr, callback){
16637 attr = attr || "id";
16638 var keys = path.split(this.pathSeparator);
16639 var v = keys.pop();
16640 if(keys.length > 0){
16641 var f = function(success, node){
16642 if(success && node){
16643 var n = node.findChild(attr, v);
16649 }else if(callback){
16650 callback(false, n);
16654 callback(false, n);
16658 this.expandPath(keys.join(this.pathSeparator), attr, f);
16660 this.root.select();
16662 callback(true, this.root);
16667 getTreeEl : function(){
16672 * Trigger rendering of this TreePanel
16674 render : function(){
16675 if (this.innerCt) {
16676 return this; // stop it rendering more than once!!
16679 this.innerCt = this.el.createChild({tag:"ul",
16680 cls:"x-tree-root-ct " +
16681 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16683 if(this.containerScroll){
16684 Roo.dd.ScrollManager.register(this.el);
16686 if((this.enableDD || this.enableDrop) && !this.dropZone){
16688 * The dropZone used by this tree if drop is enabled
16689 * @type Roo.tree.TreeDropZone
16691 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16692 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16695 if((this.enableDD || this.enableDrag) && !this.dragZone){
16697 * The dragZone used by this tree if drag is enabled
16698 * @type Roo.tree.TreeDragZone
16700 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16701 ddGroup: this.ddGroup || "TreeDD",
16702 scroll: this.ddScroll
16705 this.getSelectionModel().init(this);
16707 console.log("ROOT not set in tree");
16710 this.root.render();
16711 if(!this.rootVisible){
16712 this.root.renderChildren();
16718 * Ext JS Library 1.1.1
16719 * Copyright(c) 2006-2007, Ext JS, LLC.
16721 * Originally Released Under LGPL - original licence link has changed is not relivant.
16724 * <script type="text/javascript">
16729 * @class Roo.tree.DefaultSelectionModel
16730 * @extends Roo.util.Observable
16731 * The default single selection for a TreePanel.
16733 Roo.tree.DefaultSelectionModel = function(){
16734 this.selNode = null;
16738 * @event selectionchange
16739 * Fires when the selected node changes
16740 * @param {DefaultSelectionModel} this
16741 * @param {TreeNode} node the new selection
16743 "selectionchange" : true,
16746 * @event beforeselect
16747 * Fires before the selected node changes, return false to cancel the change
16748 * @param {DefaultSelectionModel} this
16749 * @param {TreeNode} node the new selection
16750 * @param {TreeNode} node the old selection
16752 "beforeselect" : true
16756 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16757 init : function(tree){
16759 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16760 tree.on("click", this.onNodeClick, this);
16763 onNodeClick : function(node, e){
16764 if (e.ctrlKey && this.selNode == node) {
16765 this.unselect(node);
16773 * @param {TreeNode} node The node to select
16774 * @return {TreeNode} The selected node
16776 select : function(node){
16777 var last = this.selNode;
16778 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16780 last.ui.onSelectedChange(false);
16782 this.selNode = node;
16783 node.ui.onSelectedChange(true);
16784 this.fireEvent("selectionchange", this, node, last);
16791 * @param {TreeNode} node The node to unselect
16793 unselect : function(node){
16794 if(this.selNode == node){
16795 this.clearSelections();
16800 * Clear all selections
16802 clearSelections : function(){
16803 var n = this.selNode;
16805 n.ui.onSelectedChange(false);
16806 this.selNode = null;
16807 this.fireEvent("selectionchange", this, null);
16813 * Get the selected node
16814 * @return {TreeNode} The selected node
16816 getSelectedNode : function(){
16817 return this.selNode;
16821 * Returns true if the node is selected
16822 * @param {TreeNode} node The node to check
16823 * @return {Boolean}
16825 isSelected : function(node){
16826 return this.selNode == node;
16830 * Selects the node above the selected node in the tree, intelligently walking the nodes
16831 * @return TreeNode The new selection
16833 selectPrevious : function(){
16834 var s = this.selNode || this.lastSelNode;
16838 var ps = s.previousSibling;
16840 if(!ps.isExpanded() || ps.childNodes.length < 1){
16841 return this.select(ps);
16843 var lc = ps.lastChild;
16844 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16847 return this.select(lc);
16849 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16850 return this.select(s.parentNode);
16856 * Selects the node above the selected node in the tree, intelligently walking the nodes
16857 * @return TreeNode The new selection
16859 selectNext : function(){
16860 var s = this.selNode || this.lastSelNode;
16864 if(s.firstChild && s.isExpanded()){
16865 return this.select(s.firstChild);
16866 }else if(s.nextSibling){
16867 return this.select(s.nextSibling);
16868 }else if(s.parentNode){
16870 s.parentNode.bubble(function(){
16871 if(this.nextSibling){
16872 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16881 onKeyDown : function(e){
16882 var s = this.selNode || this.lastSelNode;
16883 // undesirable, but required
16888 var k = e.getKey();
16896 this.selectPrevious();
16899 e.preventDefault();
16900 if(s.hasChildNodes()){
16901 if(!s.isExpanded()){
16903 }else if(s.firstChild){
16904 this.select(s.firstChild, e);
16909 e.preventDefault();
16910 if(s.hasChildNodes() && s.isExpanded()){
16912 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16913 this.select(s.parentNode, e);
16921 * @class Roo.tree.MultiSelectionModel
16922 * @extends Roo.util.Observable
16923 * Multi selection for a TreePanel.
16925 Roo.tree.MultiSelectionModel = function(){
16926 this.selNodes = [];
16930 * @event selectionchange
16931 * Fires when the selected nodes change
16932 * @param {MultiSelectionModel} this
16933 * @param {Array} nodes Array of the selected nodes
16935 "selectionchange" : true
16939 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16940 init : function(tree){
16942 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16943 tree.on("click", this.onNodeClick, this);
16946 onNodeClick : function(node, e){
16947 this.select(node, e, e.ctrlKey);
16952 * @param {TreeNode} node The node to select
16953 * @param {EventObject} e (optional) An event associated with the selection
16954 * @param {Boolean} keepExisting True to retain existing selections
16955 * @return {TreeNode} The selected node
16957 select : function(node, e, keepExisting){
16958 if(keepExisting !== true){
16959 this.clearSelections(true);
16961 if(this.isSelected(node)){
16962 this.lastSelNode = node;
16965 this.selNodes.push(node);
16966 this.selMap[node.id] = node;
16967 this.lastSelNode = node;
16968 node.ui.onSelectedChange(true);
16969 this.fireEvent("selectionchange", this, this.selNodes);
16975 * @param {TreeNode} node The node to unselect
16977 unselect : function(node){
16978 if(this.selMap[node.id]){
16979 node.ui.onSelectedChange(false);
16980 var sn = this.selNodes;
16983 index = sn.indexOf(node);
16985 for(var i = 0, len = sn.length; i < len; i++){
16993 this.selNodes.splice(index, 1);
16995 delete this.selMap[node.id];
16996 this.fireEvent("selectionchange", this, this.selNodes);
17001 * Clear all selections
17003 clearSelections : function(suppressEvent){
17004 var sn = this.selNodes;
17006 for(var i = 0, len = sn.length; i < len; i++){
17007 sn[i].ui.onSelectedChange(false);
17009 this.selNodes = [];
17011 if(suppressEvent !== true){
17012 this.fireEvent("selectionchange", this, this.selNodes);
17018 * Returns true if the node is selected
17019 * @param {TreeNode} node The node to check
17020 * @return {Boolean}
17022 isSelected : function(node){
17023 return this.selMap[node.id] ? true : false;
17027 * Returns an array of the selected nodes
17030 getSelectedNodes : function(){
17031 return this.selNodes;
17034 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17036 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17038 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17041 * Ext JS Library 1.1.1
17042 * Copyright(c) 2006-2007, Ext JS, LLC.
17044 * Originally Released Under LGPL - original licence link has changed is not relivant.
17047 * <script type="text/javascript">
17051 * @class Roo.tree.TreeNode
17052 * @extends Roo.data.Node
17053 * @cfg {String} text The text for this node
17054 * @cfg {Boolean} expanded true to start the node expanded
17055 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17056 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17057 * @cfg {Boolean} disabled true to start the node disabled
17058 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17059 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17060 * @cfg {String} cls A css class to be added to the node
17061 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17062 * @cfg {String} href URL of the link used for the node (defaults to #)
17063 * @cfg {String} hrefTarget target frame for the link
17064 * @cfg {String} qtip An Ext QuickTip for the node
17065 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17066 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17067 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17068 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17069 * (defaults to undefined with no checkbox rendered)
17071 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17073 Roo.tree.TreeNode = function(attributes){
17074 attributes = attributes || {};
17075 if(typeof attributes == "string"){
17076 attributes = {text: attributes};
17078 this.childrenRendered = false;
17079 this.rendered = false;
17080 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17081 this.expanded = attributes.expanded === true;
17082 this.isTarget = attributes.isTarget !== false;
17083 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17084 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17087 * Read-only. The text for this node. To change it use setText().
17090 this.text = attributes.text;
17092 * True if this node is disabled.
17095 this.disabled = attributes.disabled === true;
17099 * @event textchange
17100 * Fires when the text for this node is changed
17101 * @param {Node} this This node
17102 * @param {String} text The new text
17103 * @param {String} oldText The old text
17105 "textchange" : true,
17107 * @event beforeexpand
17108 * Fires before this node is expanded, return false to cancel.
17109 * @param {Node} this This node
17110 * @param {Boolean} deep
17111 * @param {Boolean} anim
17113 "beforeexpand" : true,
17115 * @event beforecollapse
17116 * Fires before this node is collapsed, return false to cancel.
17117 * @param {Node} this This node
17118 * @param {Boolean} deep
17119 * @param {Boolean} anim
17121 "beforecollapse" : true,
17124 * Fires when this node is expanded
17125 * @param {Node} this This node
17129 * @event disabledchange
17130 * Fires when the disabled status of this node changes
17131 * @param {Node} this This node
17132 * @param {Boolean} disabled
17134 "disabledchange" : true,
17137 * Fires when this node is collapsed
17138 * @param {Node} this This node
17142 * @event beforeclick
17143 * Fires before click processing. Return false to cancel the default action.
17144 * @param {Node} this This node
17145 * @param {Roo.EventObject} e The event object
17147 "beforeclick":true,
17149 * @event checkchange
17150 * Fires when a node with a checkbox's checked property changes
17151 * @param {Node} this This node
17152 * @param {Boolean} checked
17154 "checkchange":true,
17157 * Fires when this node is clicked
17158 * @param {Node} this This node
17159 * @param {Roo.EventObject} e The event object
17164 * Fires when this node is double clicked
17165 * @param {Node} this This node
17166 * @param {Roo.EventObject} e The event object
17170 * @event contextmenu
17171 * Fires when this node is right clicked
17172 * @param {Node} this This node
17173 * @param {Roo.EventObject} e The event object
17175 "contextmenu":true,
17177 * @event beforechildrenrendered
17178 * Fires right before the child nodes for this node are rendered
17179 * @param {Node} this This node
17181 "beforechildrenrendered":true
17184 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17187 * Read-only. The UI for this node
17190 this.ui = new uiClass(this);
17192 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17193 preventHScroll: true,
17195 * Returns true if this node is expanded
17196 * @return {Boolean}
17198 isExpanded : function(){
17199 return this.expanded;
17203 * Returns the UI object for this node
17204 * @return {TreeNodeUI}
17206 getUI : function(){
17210 // private override
17211 setFirstChild : function(node){
17212 var of = this.firstChild;
17213 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17214 if(this.childrenRendered && of && node != of){
17215 of.renderIndent(true, true);
17218 this.renderIndent(true, true);
17222 // private override
17223 setLastChild : function(node){
17224 var ol = this.lastChild;
17225 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17226 if(this.childrenRendered && ol && node != ol){
17227 ol.renderIndent(true, true);
17230 this.renderIndent(true, true);
17234 // these methods are overridden to provide lazy rendering support
17235 // private override
17236 appendChild : function(){
17237 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17238 if(node && this.childrenRendered){
17241 this.ui.updateExpandIcon();
17245 // private override
17246 removeChild : function(node){
17247 this.ownerTree.getSelectionModel().unselect(node);
17248 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17249 // if it's been rendered remove dom node
17250 if(this.childrenRendered){
17253 if(this.childNodes.length < 1){
17254 this.collapse(false, false);
17256 this.ui.updateExpandIcon();
17258 if(!this.firstChild) {
17259 this.childrenRendered = false;
17264 // private override
17265 insertBefore : function(node, refNode){
17266 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17267 if(newNode && refNode && this.childrenRendered){
17270 this.ui.updateExpandIcon();
17275 * Sets the text for this node
17276 * @param {String} text
17278 setText : function(text){
17279 var oldText = this.text;
17281 this.attributes.text = text;
17282 if(this.rendered){ // event without subscribing
17283 this.ui.onTextChange(this, text, oldText);
17285 this.fireEvent("textchange", this, text, oldText);
17289 * Triggers selection of this node
17291 select : function(){
17292 this.getOwnerTree().getSelectionModel().select(this);
17296 * Triggers deselection of this node
17298 unselect : function(){
17299 this.getOwnerTree().getSelectionModel().unselect(this);
17303 * Returns true if this node is selected
17304 * @return {Boolean}
17306 isSelected : function(){
17307 return this.getOwnerTree().getSelectionModel().isSelected(this);
17311 * Expand this node.
17312 * @param {Boolean} deep (optional) True to expand all children as well
17313 * @param {Boolean} anim (optional) false to cancel the default animation
17314 * @param {Function} callback (optional) A callback to be called when
17315 * expanding this node completes (does not wait for deep expand to complete).
17316 * Called with 1 parameter, this node.
17318 expand : function(deep, anim, callback){
17319 if(!this.expanded){
17320 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17323 if(!this.childrenRendered){
17324 this.renderChildren();
17326 this.expanded = true;
17327 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17328 this.ui.animExpand(function(){
17329 this.fireEvent("expand", this);
17330 if(typeof callback == "function"){
17334 this.expandChildNodes(true);
17336 }.createDelegate(this));
17340 this.fireEvent("expand", this);
17341 if(typeof callback == "function"){
17346 if(typeof callback == "function"){
17351 this.expandChildNodes(true);
17355 isHiddenRoot : function(){
17356 return this.isRoot && !this.getOwnerTree().rootVisible;
17360 * Collapse this node.
17361 * @param {Boolean} deep (optional) True to collapse all children as well
17362 * @param {Boolean} anim (optional) false to cancel the default animation
17364 collapse : function(deep, anim){
17365 if(this.expanded && !this.isHiddenRoot()){
17366 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17369 this.expanded = false;
17370 if((this.getOwnerTree().animate && anim !== false) || anim){
17371 this.ui.animCollapse(function(){
17372 this.fireEvent("collapse", this);
17374 this.collapseChildNodes(true);
17376 }.createDelegate(this));
17379 this.ui.collapse();
17380 this.fireEvent("collapse", this);
17384 var cs = this.childNodes;
17385 for(var i = 0, len = cs.length; i < len; i++) {
17386 cs[i].collapse(true, false);
17392 delayedExpand : function(delay){
17393 if(!this.expandProcId){
17394 this.expandProcId = this.expand.defer(delay, this);
17399 cancelExpand : function(){
17400 if(this.expandProcId){
17401 clearTimeout(this.expandProcId);
17403 this.expandProcId = false;
17407 * Toggles expanded/collapsed state of the node
17409 toggle : function(){
17418 * Ensures all parent nodes are expanded
17420 ensureVisible : function(callback){
17421 var tree = this.getOwnerTree();
17422 tree.expandPath(this.parentNode.getPath(), false, function(){
17423 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17424 Roo.callback(callback);
17425 }.createDelegate(this));
17429 * Expand all child nodes
17430 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17432 expandChildNodes : function(deep){
17433 var cs = this.childNodes;
17434 for(var i = 0, len = cs.length; i < len; i++) {
17435 cs[i].expand(deep);
17440 * Collapse all child nodes
17441 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17443 collapseChildNodes : function(deep){
17444 var cs = this.childNodes;
17445 for(var i = 0, len = cs.length; i < len; i++) {
17446 cs[i].collapse(deep);
17451 * Disables this node
17453 disable : function(){
17454 this.disabled = true;
17456 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17457 this.ui.onDisableChange(this, true);
17459 this.fireEvent("disabledchange", this, true);
17463 * Enables this node
17465 enable : function(){
17466 this.disabled = false;
17467 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17468 this.ui.onDisableChange(this, false);
17470 this.fireEvent("disabledchange", this, false);
17474 renderChildren : function(suppressEvent){
17475 if(suppressEvent !== false){
17476 this.fireEvent("beforechildrenrendered", this);
17478 var cs = this.childNodes;
17479 for(var i = 0, len = cs.length; i < len; i++){
17480 cs[i].render(true);
17482 this.childrenRendered = true;
17486 sort : function(fn, scope){
17487 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17488 if(this.childrenRendered){
17489 var cs = this.childNodes;
17490 for(var i = 0, len = cs.length; i < len; i++){
17491 cs[i].render(true);
17497 render : function(bulkRender){
17498 this.ui.render(bulkRender);
17499 if(!this.rendered){
17500 this.rendered = true;
17502 this.expanded = false;
17503 this.expand(false, false);
17509 renderIndent : function(deep, refresh){
17511 this.ui.childIndent = null;
17513 this.ui.renderIndent();
17514 if(deep === true && this.childrenRendered){
17515 var cs = this.childNodes;
17516 for(var i = 0, len = cs.length; i < len; i++){
17517 cs[i].renderIndent(true, refresh);
17523 * Ext JS Library 1.1.1
17524 * Copyright(c) 2006-2007, Ext JS, LLC.
17526 * Originally Released Under LGPL - original licence link has changed is not relivant.
17529 * <script type="text/javascript">
17533 * @class Roo.tree.AsyncTreeNode
17534 * @extends Roo.tree.TreeNode
17535 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17537 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17539 Roo.tree.AsyncTreeNode = function(config){
17540 this.loaded = false;
17541 this.loading = false;
17542 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17544 * @event beforeload
17545 * Fires before this node is loaded, return false to cancel
17546 * @param {Node} this This node
17548 this.addEvents({'beforeload':true, 'load': true});
17551 * Fires when this node is loaded
17552 * @param {Node} this This node
17555 * The loader used by this node (defaults to using the tree's defined loader)
17560 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17561 expand : function(deep, anim, callback){
17562 if(this.loading){ // if an async load is already running, waiting til it's done
17564 var f = function(){
17565 if(!this.loading){ // done loading
17566 clearInterval(timer);
17567 this.expand(deep, anim, callback);
17569 }.createDelegate(this);
17570 timer = setInterval(f, 200);
17574 if(this.fireEvent("beforeload", this) === false){
17577 this.loading = true;
17578 this.ui.beforeLoad(this);
17579 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17581 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17585 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17589 * Returns true if this node is currently loading
17590 * @return {Boolean}
17592 isLoading : function(){
17593 return this.loading;
17596 loadComplete : function(deep, anim, callback){
17597 this.loading = false;
17598 this.loaded = true;
17599 this.ui.afterLoad(this);
17600 this.fireEvent("load", this);
17601 this.expand(deep, anim, callback);
17605 * Returns true if this node has been loaded
17606 * @return {Boolean}
17608 isLoaded : function(){
17609 return this.loaded;
17612 hasChildNodes : function(){
17613 if(!this.isLeaf() && !this.loaded){
17616 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17621 * Trigger a reload for this node
17622 * @param {Function} callback
17624 reload : function(callback){
17625 this.collapse(false, false);
17626 while(this.firstChild){
17627 this.removeChild(this.firstChild);
17629 this.childrenRendered = false;
17630 this.loaded = false;
17631 if(this.isHiddenRoot()){
17632 this.expanded = false;
17634 this.expand(false, false, callback);
17638 * Ext JS Library 1.1.1
17639 * Copyright(c) 2006-2007, Ext JS, LLC.
17641 * Originally Released Under LGPL - original licence link has changed is not relivant.
17644 * <script type="text/javascript">
17648 * @class Roo.tree.TreeNodeUI
17650 * @param {Object} node The node to render
17651 * The TreeNode UI implementation is separate from the
17652 * tree implementation. Unless you are customizing the tree UI,
17653 * you should never have to use this directly.
17655 Roo.tree.TreeNodeUI = function(node){
17657 this.rendered = false;
17658 this.animating = false;
17659 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17662 Roo.tree.TreeNodeUI.prototype = {
17663 removeChild : function(node){
17665 this.ctNode.removeChild(node.ui.getEl());
17669 beforeLoad : function(){
17670 this.addClass("x-tree-node-loading");
17673 afterLoad : function(){
17674 this.removeClass("x-tree-node-loading");
17677 onTextChange : function(node, text, oldText){
17679 this.textNode.innerHTML = text;
17683 onDisableChange : function(node, state){
17684 this.disabled = state;
17686 this.addClass("x-tree-node-disabled");
17688 this.removeClass("x-tree-node-disabled");
17692 onSelectedChange : function(state){
17695 this.addClass("x-tree-selected");
17698 this.removeClass("x-tree-selected");
17702 onMove : function(tree, node, oldParent, newParent, index, refNode){
17703 this.childIndent = null;
17705 var targetNode = newParent.ui.getContainer();
17706 if(!targetNode){//target not rendered
17707 this.holder = document.createElement("div");
17708 this.holder.appendChild(this.wrap);
17711 var insertBefore = refNode ? refNode.ui.getEl() : null;
17713 targetNode.insertBefore(this.wrap, insertBefore);
17715 targetNode.appendChild(this.wrap);
17717 this.node.renderIndent(true);
17721 addClass : function(cls){
17723 Roo.fly(this.elNode).addClass(cls);
17727 removeClass : function(cls){
17729 Roo.fly(this.elNode).removeClass(cls);
17733 remove : function(){
17735 this.holder = document.createElement("div");
17736 this.holder.appendChild(this.wrap);
17740 fireEvent : function(){
17741 return this.node.fireEvent.apply(this.node, arguments);
17744 initEvents : function(){
17745 this.node.on("move", this.onMove, this);
17746 var E = Roo.EventManager;
17747 var a = this.anchor;
17749 var el = Roo.fly(a, '_treeui');
17751 if(Roo.isOpera){ // opera render bug ignores the CSS
17752 el.setStyle("text-decoration", "none");
17755 el.on("click", this.onClick, this);
17756 el.on("dblclick", this.onDblClick, this);
17759 Roo.EventManager.on(this.checkbox,
17760 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17763 el.on("contextmenu", this.onContextMenu, this);
17765 var icon = Roo.fly(this.iconNode);
17766 icon.on("click", this.onClick, this);
17767 icon.on("dblclick", this.onDblClick, this);
17768 icon.on("contextmenu", this.onContextMenu, this);
17769 E.on(this.ecNode, "click", this.ecClick, this, true);
17771 if(this.node.disabled){
17772 this.addClass("x-tree-node-disabled");
17774 if(this.node.hidden){
17775 this.addClass("x-tree-node-disabled");
17777 var ot = this.node.getOwnerTree();
17778 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17779 if(dd && (!this.node.isRoot || ot.rootVisible)){
17780 Roo.dd.Registry.register(this.elNode, {
17782 handles: this.getDDHandles(),
17788 getDDHandles : function(){
17789 return [this.iconNode, this.textNode];
17794 this.wrap.style.display = "none";
17800 this.wrap.style.display = "";
17804 onContextMenu : function(e){
17805 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17806 e.preventDefault();
17808 this.fireEvent("contextmenu", this.node, e);
17812 onClick : function(e){
17817 if(this.fireEvent("beforeclick", this.node, e) !== false){
17818 if(!this.disabled && this.node.attributes.href){
17819 this.fireEvent("click", this.node, e);
17822 e.preventDefault();
17827 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17828 this.node.toggle();
17831 this.fireEvent("click", this.node, e);
17837 onDblClick : function(e){
17838 e.preventDefault();
17843 this.toggleCheck();
17845 if(!this.animating && this.node.hasChildNodes()){
17846 this.node.toggle();
17848 this.fireEvent("dblclick", this.node, e);
17851 onCheckChange : function(){
17852 var checked = this.checkbox.checked;
17853 this.node.attributes.checked = checked;
17854 this.fireEvent('checkchange', this.node, checked);
17857 ecClick : function(e){
17858 if(!this.animating && this.node.hasChildNodes()){
17859 this.node.toggle();
17863 startDrop : function(){
17864 this.dropping = true;
17867 // delayed drop so the click event doesn't get fired on a drop
17868 endDrop : function(){
17869 setTimeout(function(){
17870 this.dropping = false;
17871 }.createDelegate(this), 50);
17874 expand : function(){
17875 this.updateExpandIcon();
17876 this.ctNode.style.display = "";
17879 focus : function(){
17880 if(!this.node.preventHScroll){
17881 try{this.anchor.focus();
17883 }else if(!Roo.isIE){
17885 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17886 var l = noscroll.scrollLeft;
17887 this.anchor.focus();
17888 noscroll.scrollLeft = l;
17893 toggleCheck : function(value){
17894 var cb = this.checkbox;
17896 cb.checked = (value === undefined ? !cb.checked : value);
17902 this.anchor.blur();
17906 animExpand : function(callback){
17907 var ct = Roo.get(this.ctNode);
17909 if(!this.node.hasChildNodes()){
17910 this.updateExpandIcon();
17911 this.ctNode.style.display = "";
17912 Roo.callback(callback);
17915 this.animating = true;
17916 this.updateExpandIcon();
17919 callback : function(){
17920 this.animating = false;
17921 Roo.callback(callback);
17924 duration: this.node.ownerTree.duration || .25
17928 highlight : function(){
17929 var tree = this.node.getOwnerTree();
17930 Roo.fly(this.wrap).highlight(
17931 tree.hlColor || "C3DAF9",
17932 {endColor: tree.hlBaseColor}
17936 collapse : function(){
17937 this.updateExpandIcon();
17938 this.ctNode.style.display = "none";
17941 animCollapse : function(callback){
17942 var ct = Roo.get(this.ctNode);
17943 ct.enableDisplayMode('block');
17946 this.animating = true;
17947 this.updateExpandIcon();
17950 callback : function(){
17951 this.animating = false;
17952 Roo.callback(callback);
17955 duration: this.node.ownerTree.duration || .25
17959 getContainer : function(){
17960 return this.ctNode;
17963 getEl : function(){
17967 appendDDGhost : function(ghostNode){
17968 ghostNode.appendChild(this.elNode.cloneNode(true));
17971 getDDRepairXY : function(){
17972 return Roo.lib.Dom.getXY(this.iconNode);
17975 onRender : function(){
17979 render : function(bulkRender){
17980 var n = this.node, a = n.attributes;
17981 var targetNode = n.parentNode ?
17982 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17984 if(!this.rendered){
17985 this.rendered = true;
17987 this.renderElements(n, a, targetNode, bulkRender);
17990 if(this.textNode.setAttributeNS){
17991 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17993 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17996 this.textNode.setAttribute("ext:qtip", a.qtip);
17998 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
18001 }else if(a.qtipCfg){
18002 a.qtipCfg.target = Roo.id(this.textNode);
18003 Roo.QuickTips.register(a.qtipCfg);
18006 if(!this.node.expanded){
18007 this.updateExpandIcon();
18010 if(bulkRender === true) {
18011 targetNode.appendChild(this.wrap);
18016 renderElements : function(n, a, targetNode, bulkRender){
18017 // add some indent caching, this helps performance when rendering a large tree
18018 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18019 var t = n.getOwnerTree();
18020 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18021 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18022 var cb = typeof a.checked == 'boolean';
18023 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18024 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18025 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18026 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18027 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18028 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18029 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18030 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18031 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18032 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18035 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18036 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18037 n.nextSibling.ui.getEl(), buf.join(""));
18039 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18042 this.elNode = this.wrap.childNodes[0];
18043 this.ctNode = this.wrap.childNodes[1];
18044 var cs = this.elNode.childNodes;
18045 this.indentNode = cs[0];
18046 this.ecNode = cs[1];
18047 this.iconNode = cs[2];
18050 this.checkbox = cs[3];
18053 this.anchor = cs[index];
18054 this.textNode = cs[index].firstChild;
18057 getAnchor : function(){
18058 return this.anchor;
18061 getTextEl : function(){
18062 return this.textNode;
18065 getIconEl : function(){
18066 return this.iconNode;
18069 isChecked : function(){
18070 return this.checkbox ? this.checkbox.checked : false;
18073 updateExpandIcon : function(){
18075 var n = this.node, c1, c2;
18076 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18077 var hasChild = n.hasChildNodes();
18081 c1 = "x-tree-node-collapsed";
18082 c2 = "x-tree-node-expanded";
18085 c1 = "x-tree-node-expanded";
18086 c2 = "x-tree-node-collapsed";
18089 this.removeClass("x-tree-node-leaf");
18090 this.wasLeaf = false;
18092 if(this.c1 != c1 || this.c2 != c2){
18093 Roo.fly(this.elNode).replaceClass(c1, c2);
18094 this.c1 = c1; this.c2 = c2;
18098 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18101 this.wasLeaf = true;
18104 var ecc = "x-tree-ec-icon "+cls;
18105 if(this.ecc != ecc){
18106 this.ecNode.className = ecc;
18112 getChildIndent : function(){
18113 if(!this.childIndent){
18117 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18119 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18121 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18126 this.childIndent = buf.join("");
18128 return this.childIndent;
18131 renderIndent : function(){
18134 var p = this.node.parentNode;
18136 indent = p.ui.getChildIndent();
18138 if(this.indentMarkup != indent){ // don't rerender if not required
18139 this.indentNode.innerHTML = indent;
18140 this.indentMarkup = indent;
18142 this.updateExpandIcon();
18147 Roo.tree.RootTreeNodeUI = function(){
18148 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18150 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18151 render : function(){
18152 if(!this.rendered){
18153 var targetNode = this.node.ownerTree.innerCt.dom;
18154 this.node.expanded = true;
18155 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18156 this.wrap = this.ctNode = targetNode.firstChild;
18159 collapse : function(){
18161 expand : function(){
18165 * Ext JS Library 1.1.1
18166 * Copyright(c) 2006-2007, Ext JS, LLC.
18168 * Originally Released Under LGPL - original licence link has changed is not relivant.
18171 * <script type="text/javascript">
18174 * @class Roo.tree.TreeLoader
18175 * @extends Roo.util.Observable
18176 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18177 * nodes from a specified URL. The response must be a javascript Array definition
18178 * who's elements are node definition objects. eg:
18180 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18181 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18184 * A server request is sent, and child nodes are loaded only when a node is expanded.
18185 * The loading node's id is passed to the server under the parameter name "node" to
18186 * enable the server to produce the correct child nodes.
18188 * To pass extra parameters, an event handler may be attached to the "beforeload"
18189 * event, and the parameters specified in the TreeLoader's baseParams property:
18191 myTreeLoader.on("beforeload", function(treeLoader, node) {
18192 this.baseParams.category = node.attributes.category;
18195 * This would pass an HTTP parameter called "category" to the server containing
18196 * the value of the Node's "category" attribute.
18198 * Creates a new Treeloader.
18199 * @param {Object} config A config object containing config properties.
18201 Roo.tree.TreeLoader = function(config){
18202 this.baseParams = {};
18203 this.requestMethod = "POST";
18204 Roo.apply(this, config);
18209 * @event beforeload
18210 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18211 * @param {Object} This TreeLoader object.
18212 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18213 * @param {Object} callback The callback function specified in the {@link #load} call.
18218 * Fires when the node has been successfuly loaded.
18219 * @param {Object} This TreeLoader object.
18220 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18221 * @param {Object} response The response object containing the data from the server.
18225 * @event loadexception
18226 * Fires if the network request failed.
18227 * @param {Object} This TreeLoader object.
18228 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18229 * @param {Object} response The response object containing the data from the server.
18231 loadexception : true,
18234 * Fires before a node is created, enabling you to return custom Node types
18235 * @param {Object} This TreeLoader object.
18236 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18241 Roo.tree.TreeLoader.superclass.constructor.call(this);
18244 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18246 * @cfg {String} dataUrl The URL from which to request a Json string which
18247 * specifies an array of node definition object representing the child nodes
18251 * @cfg {Object} baseParams (optional) An object containing properties which
18252 * specify HTTP parameters to be passed to each request for child nodes.
18255 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18256 * created by this loader. If the attributes sent by the server have an attribute in this object,
18257 * they take priority.
18260 * @cfg {Object} uiProviders (optional) An object containing properties which
18262 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18263 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18264 * <i>uiProvider</i> attribute of a returned child node is a string rather
18265 * than a reference to a TreeNodeUI implementation, this that string value
18266 * is used as a property name in the uiProviders object. You can define the provider named
18267 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18272 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18273 * child nodes before loading.
18275 clearOnLoad : true,
18278 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18279 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18280 * Grid query { data : [ .....] }
18285 * @cfg {String} queryParam (optional)
18286 * Name of the query as it will be passed on the querystring (defaults to 'node')
18287 * eg. the request will be ?node=[id]
18294 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18295 * This is called automatically when a node is expanded, but may be used to reload
18296 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18297 * @param {Roo.tree.TreeNode} node
18298 * @param {Function} callback
18300 load : function(node, callback){
18301 if(this.clearOnLoad){
18302 while(node.firstChild){
18303 node.removeChild(node.firstChild);
18306 if(node.attributes.children){ // preloaded json children
18307 var cs = node.attributes.children;
18308 for(var i = 0, len = cs.length; i < len; i++){
18309 node.appendChild(this.createNode(cs[i]));
18311 if(typeof callback == "function"){
18314 }else if(this.dataUrl){
18315 this.requestData(node, callback);
18319 getParams: function(node){
18320 var buf = [], bp = this.baseParams;
18321 for(var key in bp){
18322 if(typeof bp[key] != "function"){
18323 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18326 var n = this.queryParam === false ? 'node' : this.queryParam;
18327 buf.push(n + "=", encodeURIComponent(node.id));
18328 return buf.join("");
18331 requestData : function(node, callback){
18332 if(this.fireEvent("beforeload", this, node, callback) !== false){
18333 this.transId = Roo.Ajax.request({
18334 method:this.requestMethod,
18335 url: this.dataUrl||this.url,
18336 success: this.handleResponse,
18337 failure: this.handleFailure,
18339 argument: {callback: callback, node: node},
18340 params: this.getParams(node)
18343 // if the load is cancelled, make sure we notify
18344 // the node that we are done
18345 if(typeof callback == "function"){
18351 isLoading : function(){
18352 return this.transId ? true : false;
18355 abort : function(){
18356 if(this.isLoading()){
18357 Roo.Ajax.abort(this.transId);
18362 createNode : function(attr){
18363 // apply baseAttrs, nice idea Corey!
18364 if(this.baseAttrs){
18365 Roo.applyIf(attr, this.baseAttrs);
18367 if(this.applyLoader !== false){
18368 attr.loader = this;
18370 // uiProvider = depreciated..
18372 if(typeof(attr.uiProvider) == 'string'){
18373 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18374 /** eval:var:attr */ eval(attr.uiProvider);
18376 if(typeof(this.uiProviders['default']) != 'undefined') {
18377 attr.uiProvider = this.uiProviders['default'];
18380 this.fireEvent('create', this, attr);
18382 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18384 new Roo.tree.TreeNode(attr) :
18385 new Roo.tree.AsyncTreeNode(attr));
18388 processResponse : function(response, node, callback){
18389 var json = response.responseText;
18392 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18393 if (this.root !== false) {
18397 for(var i = 0, len = o.length; i < len; i++){
18398 var n = this.createNode(o[i]);
18400 node.appendChild(n);
18403 if(typeof callback == "function"){
18404 callback(this, node);
18407 this.handleFailure(response);
18411 handleResponse : function(response){
18412 this.transId = false;
18413 var a = response.argument;
18414 this.processResponse(response, a.node, a.callback);
18415 this.fireEvent("load", this, a.node, response);
18418 handleFailure : function(response){
18419 this.transId = false;
18420 var a = response.argument;
18421 this.fireEvent("loadexception", this, a.node, response);
18422 if(typeof a.callback == "function"){
18423 a.callback(this, a.node);
18428 * Ext JS Library 1.1.1
18429 * Copyright(c) 2006-2007, Ext JS, LLC.
18431 * Originally Released Under LGPL - original licence link has changed is not relivant.
18434 * <script type="text/javascript">
18438 * @class Roo.tree.TreeFilter
18439 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18440 * @param {TreePanel} tree
18441 * @param {Object} config (optional)
18443 Roo.tree.TreeFilter = function(tree, config){
18445 this.filtered = {};
18446 Roo.apply(this, config);
18449 Roo.tree.TreeFilter.prototype = {
18456 * Filter the data by a specific attribute.
18457 * @param {String/RegExp} value Either string that the attribute value
18458 * should start with or a RegExp to test against the attribute
18459 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18460 * @param {TreeNode} startNode (optional) The node to start the filter at.
18462 filter : function(value, attr, startNode){
18463 attr = attr || "text";
18465 if(typeof value == "string"){
18466 var vlen = value.length;
18467 // auto clear empty filter
18468 if(vlen == 0 && this.clearBlank){
18472 value = value.toLowerCase();
18474 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18476 }else if(value.exec){ // regex?
18478 return value.test(n.attributes[attr]);
18481 throw 'Illegal filter type, must be string or regex';
18483 this.filterBy(f, null, startNode);
18487 * Filter by a function. The passed function will be called with each
18488 * node in the tree (or from the startNode). If the function returns true, the node is kept
18489 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18490 * @param {Function} fn The filter function
18491 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18493 filterBy : function(fn, scope, startNode){
18494 startNode = startNode || this.tree.root;
18495 if(this.autoClear){
18498 var af = this.filtered, rv = this.reverse;
18499 var f = function(n){
18500 if(n == startNode){
18506 var m = fn.call(scope || n, n);
18514 startNode.cascade(f);
18517 if(typeof id != "function"){
18519 if(n && n.parentNode){
18520 n.parentNode.removeChild(n);
18528 * Clears the current filter. Note: with the "remove" option
18529 * set a filter cannot be cleared.
18531 clear : function(){
18533 var af = this.filtered;
18535 if(typeof id != "function"){
18542 this.filtered = {};
18547 * Ext JS Library 1.1.1
18548 * Copyright(c) 2006-2007, Ext JS, LLC.
18550 * Originally Released Under LGPL - original licence link has changed is not relivant.
18553 * <script type="text/javascript">
18558 * @class Roo.tree.TreeSorter
18559 * Provides sorting of nodes in a TreePanel
18561 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18562 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18563 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18564 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18565 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18566 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18568 * @param {TreePanel} tree
18569 * @param {Object} config
18571 Roo.tree.TreeSorter = function(tree, config){
18572 Roo.apply(this, config);
18573 tree.on("beforechildrenrendered", this.doSort, this);
18574 tree.on("append", this.updateSort, this);
18575 tree.on("insert", this.updateSort, this);
18577 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18578 var p = this.property || "text";
18579 var sortType = this.sortType;
18580 var fs = this.folderSort;
18581 var cs = this.caseSensitive === true;
18582 var leafAttr = this.leafAttr || 'leaf';
18584 this.sortFn = function(n1, n2){
18586 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18589 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18593 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18594 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18596 return dsc ? +1 : -1;
18598 return dsc ? -1 : +1;
18605 Roo.tree.TreeSorter.prototype = {
18606 doSort : function(node){
18607 node.sort(this.sortFn);
18610 compareNodes : function(n1, n2){
18611 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18614 updateSort : function(tree, node){
18615 if(node.childrenRendered){
18616 this.doSort.defer(1, this, [node]);
18621 * Ext JS Library 1.1.1
18622 * Copyright(c) 2006-2007, Ext JS, LLC.
18624 * Originally Released Under LGPL - original licence link has changed is not relivant.
18627 * <script type="text/javascript">
18630 if(Roo.dd.DropZone){
18632 Roo.tree.TreeDropZone = function(tree, config){
18633 this.allowParentInsert = false;
18634 this.allowContainerDrop = false;
18635 this.appendOnly = false;
18636 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18638 this.lastInsertClass = "x-tree-no-status";
18639 this.dragOverData = {};
18642 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18643 ddGroup : "TreeDD",
18645 expandDelay : 1000,
18647 expandNode : function(node){
18648 if(node.hasChildNodes() && !node.isExpanded()){
18649 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18653 queueExpand : function(node){
18654 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18657 cancelExpand : function(){
18658 if(this.expandProcId){
18659 clearTimeout(this.expandProcId);
18660 this.expandProcId = false;
18664 isValidDropPoint : function(n, pt, dd, e, data){
18665 if(!n || !data){ return false; }
18666 var targetNode = n.node;
18667 var dropNode = data.node;
18668 // default drop rules
18669 if(!(targetNode && targetNode.isTarget && pt)){
18672 if(pt == "append" && targetNode.allowChildren === false){
18675 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18678 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18681 // reuse the object
18682 var overEvent = this.dragOverData;
18683 overEvent.tree = this.tree;
18684 overEvent.target = targetNode;
18685 overEvent.data = data;
18686 overEvent.point = pt;
18687 overEvent.source = dd;
18688 overEvent.rawEvent = e;
18689 overEvent.dropNode = dropNode;
18690 overEvent.cancel = false;
18691 var result = this.tree.fireEvent("nodedragover", overEvent);
18692 return overEvent.cancel === false && result !== false;
18695 getDropPoint : function(e, n, dd){
18698 return tn.allowChildren !== false ? "append" : false; // always append for root
18700 var dragEl = n.ddel;
18701 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18702 var y = Roo.lib.Event.getPageY(e);
18703 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18705 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18706 var noAppend = tn.allowChildren === false;
18707 if(this.appendOnly || tn.parentNode.allowChildren === false){
18708 return noAppend ? false : "append";
18710 var noBelow = false;
18711 if(!this.allowParentInsert){
18712 noBelow = tn.hasChildNodes() && tn.isExpanded();
18714 var q = (b - t) / (noAppend ? 2 : 3);
18715 if(y >= t && y < (t + q)){
18717 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18724 onNodeEnter : function(n, dd, e, data){
18725 this.cancelExpand();
18728 onNodeOver : function(n, dd, e, data){
18729 var pt = this.getDropPoint(e, n, dd);
18732 // auto node expand check
18733 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18734 this.queueExpand(node);
18735 }else if(pt != "append"){
18736 this.cancelExpand();
18739 // set the insert point style on the target node
18740 var returnCls = this.dropNotAllowed;
18741 if(this.isValidDropPoint(n, pt, dd, e, data)){
18746 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18747 cls = "x-tree-drag-insert-above";
18748 }else if(pt == "below"){
18749 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18750 cls = "x-tree-drag-insert-below";
18752 returnCls = "x-tree-drop-ok-append";
18753 cls = "x-tree-drag-append";
18755 if(this.lastInsertClass != cls){
18756 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18757 this.lastInsertClass = cls;
18764 onNodeOut : function(n, dd, e, data){
18765 this.cancelExpand();
18766 this.removeDropIndicators(n);
18769 onNodeDrop : function(n, dd, e, data){
18770 var point = this.getDropPoint(e, n, dd);
18771 var targetNode = n.node;
18772 targetNode.ui.startDrop();
18773 if(!this.isValidDropPoint(n, point, dd, e, data)){
18774 targetNode.ui.endDrop();
18777 // first try to find the drop node
18778 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18781 target: targetNode,
18786 dropNode: dropNode,
18789 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18790 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18791 targetNode.ui.endDrop();
18794 // allow target changing
18795 targetNode = dropEvent.target;
18796 if(point == "append" && !targetNode.isExpanded()){
18797 targetNode.expand(false, null, function(){
18798 this.completeDrop(dropEvent);
18799 }.createDelegate(this));
18801 this.completeDrop(dropEvent);
18806 completeDrop : function(de){
18807 var ns = de.dropNode, p = de.point, t = de.target;
18808 if(!(ns instanceof Array)){
18812 for(var i = 0, len = ns.length; i < len; i++){
18815 t.parentNode.insertBefore(n, t);
18816 }else if(p == "below"){
18817 t.parentNode.insertBefore(n, t.nextSibling);
18823 if(this.tree.hlDrop){
18827 this.tree.fireEvent("nodedrop", de);
18830 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18831 if(this.tree.hlDrop){
18832 dropNode.ui.focus();
18833 dropNode.ui.highlight();
18835 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18838 getTree : function(){
18842 removeDropIndicators : function(n){
18845 Roo.fly(el).removeClass([
18846 "x-tree-drag-insert-above",
18847 "x-tree-drag-insert-below",
18848 "x-tree-drag-append"]);
18849 this.lastInsertClass = "_noclass";
18853 beforeDragDrop : function(target, e, id){
18854 this.cancelExpand();
18858 afterRepair : function(data){
18859 if(data && Roo.enableFx){
18860 data.node.ui.highlight();
18869 * Ext JS Library 1.1.1
18870 * Copyright(c) 2006-2007, Ext JS, LLC.
18872 * Originally Released Under LGPL - original licence link has changed is not relivant.
18875 * <script type="text/javascript">
18879 if(Roo.dd.DragZone){
18880 Roo.tree.TreeDragZone = function(tree, config){
18881 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18885 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18886 ddGroup : "TreeDD",
18888 onBeforeDrag : function(data, e){
18890 return n && n.draggable && !n.disabled;
18893 onInitDrag : function(e){
18894 var data = this.dragData;
18895 this.tree.getSelectionModel().select(data.node);
18896 this.proxy.update("");
18897 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18898 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18901 getRepairXY : function(e, data){
18902 return data.node.ui.getDDRepairXY();
18905 onEndDrag : function(data, e){
18906 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18909 onValidDrop : function(dd, e, id){
18910 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18914 beforeInvalidDrop : function(e, id){
18915 // this scrolls the original position back into view
18916 var sm = this.tree.getSelectionModel();
18917 sm.clearSelections();
18918 sm.select(this.dragData.node);
18923 * Ext JS Library 1.1.1
18924 * Copyright(c) 2006-2007, Ext JS, LLC.
18926 * Originally Released Under LGPL - original licence link has changed is not relivant.
18929 * <script type="text/javascript">
18932 * @class Roo.tree.TreeEditor
18933 * @extends Roo.Editor
18934 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18935 * as the editor field.
18937 * @param {TreePanel} tree
18938 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18940 Roo.tree.TreeEditor = function(tree, config){
18941 config = config || {};
18942 var field = config.events ? config : new Roo.form.TextField(config);
18943 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18947 tree.on('beforeclick', this.beforeNodeClick, this);
18948 tree.getTreeEl().on('mousedown', this.hide, this);
18949 this.on('complete', this.updateNode, this);
18950 this.on('beforestartedit', this.fitToTree, this);
18951 this.on('startedit', this.bindScroll, this, {delay:10});
18952 this.on('specialkey', this.onSpecialKey, this);
18955 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18957 * @cfg {String} alignment
18958 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18964 * @cfg {Boolean} hideEl
18965 * True to hide the bound element while the editor is displayed (defaults to false)
18969 * @cfg {String} cls
18970 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18972 cls: "x-small-editor x-tree-editor",
18974 * @cfg {Boolean} shim
18975 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18981 * @cfg {Number} maxWidth
18982 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18983 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18984 * scroll and client offsets into account prior to each edit.
18991 fitToTree : function(ed, el){
18992 var td = this.tree.getTreeEl().dom, nd = el.dom;
18993 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
18994 td.scrollLeft = nd.offsetLeft;
18998 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
18999 this.setSize(w, '');
19003 triggerEdit : function(node){
19004 this.completeEdit();
19005 this.editNode = node;
19006 this.startEdit(node.ui.textNode, node.text);
19010 bindScroll : function(){
19011 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19015 beforeNodeClick : function(node, e){
19016 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19017 this.lastClick = new Date();
19018 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19020 this.triggerEdit(node);
19026 updateNode : function(ed, value){
19027 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19028 this.editNode.setText(value);
19032 onHide : function(){
19033 Roo.tree.TreeEditor.superclass.onHide.call(this);
19035 this.editNode.ui.focus();
19040 onSpecialKey : function(field, e){
19041 var k = e.getKey();
19045 }else if(k == e.ENTER && !e.hasModifier()){
19047 this.completeEdit();
19050 });//<Script type="text/javascript">
19053 * Ext JS Library 1.1.1
19054 * Copyright(c) 2006-2007, Ext JS, LLC.
19056 * Originally Released Under LGPL - original licence link has changed is not relivant.
19059 * <script type="text/javascript">
19063 * Not documented??? - probably should be...
19066 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19067 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19069 renderElements : function(n, a, targetNode, bulkRender){
19070 //consel.log("renderElements?");
19071 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19073 var t = n.getOwnerTree();
19074 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19076 var cols = t.columns;
19077 var bw = t.borderWidth;
19079 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19080 var cb = typeof a.checked == "boolean";
19081 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19082 var colcls = 'x-t-' + tid + '-c0';
19084 '<li class="x-tree-node">',
19087 '<div class="x-tree-node-el ', a.cls,'">',
19089 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19092 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19093 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19094 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19095 (a.icon ? ' x-tree-node-inline-icon' : ''),
19096 (a.iconCls ? ' '+a.iconCls : ''),
19097 '" unselectable="on" />',
19098 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19099 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19101 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19102 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19103 '<span unselectable="on" qtip="' + tx + '">',
19107 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19108 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19110 for(var i = 1, len = cols.length; i < len; i++){
19112 colcls = 'x-t-' + tid + '-c' +i;
19113 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19114 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19115 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19121 '<div class="x-clear"></div></div>',
19122 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19125 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19126 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19127 n.nextSibling.ui.getEl(), buf.join(""));
19129 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19131 var el = this.wrap.firstChild;
19133 this.elNode = el.firstChild;
19134 this.ranchor = el.childNodes[1];
19135 this.ctNode = this.wrap.childNodes[1];
19136 var cs = el.firstChild.childNodes;
19137 this.indentNode = cs[0];
19138 this.ecNode = cs[1];
19139 this.iconNode = cs[2];
19142 this.checkbox = cs[3];
19145 this.anchor = cs[index];
19147 this.textNode = cs[index].firstChild;
19149 //el.on("click", this.onClick, this);
19150 //el.on("dblclick", this.onDblClick, this);
19153 // console.log(this);
19155 initEvents : function(){
19156 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19159 var a = this.ranchor;
19161 var el = Roo.get(a);
19163 if(Roo.isOpera){ // opera render bug ignores the CSS
19164 el.setStyle("text-decoration", "none");
19167 el.on("click", this.onClick, this);
19168 el.on("dblclick", this.onDblClick, this);
19169 el.on("contextmenu", this.onContextMenu, this);
19173 /*onSelectedChange : function(state){
19176 this.addClass("x-tree-selected");
19179 this.removeClass("x-tree-selected");
19182 addClass : function(cls){
19184 Roo.fly(this.elRow).addClass(cls);
19190 removeClass : function(cls){
19192 Roo.fly(this.elRow).removeClass(cls);
19198 });//<Script type="text/javascript">
19202 * Ext JS Library 1.1.1
19203 * Copyright(c) 2006-2007, Ext JS, LLC.
19205 * Originally Released Under LGPL - original licence link has changed is not relivant.
19208 * <script type="text/javascript">
19213 * @class Roo.tree.ColumnTree
19214 * @extends Roo.data.TreePanel
19215 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19216 * @cfg {int} borderWidth compined right/left border allowance
19218 * @param {String/HTMLElement/Element} el The container element
19219 * @param {Object} config
19221 Roo.tree.ColumnTree = function(el, config)
19223 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19227 * Fire this event on a container when it resizes
19228 * @param {int} w Width
19229 * @param {int} h Height
19233 this.on('resize', this.onResize, this);
19236 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19240 borderWidth: Roo.isBorderBox ? 0 : 2,
19243 render : function(){
19244 // add the header.....
19246 Roo.tree.ColumnTree.superclass.render.apply(this);
19248 this.el.addClass('x-column-tree');
19250 this.headers = this.el.createChild(
19251 {cls:'x-tree-headers'},this.innerCt.dom);
19253 var cols = this.columns, c;
19254 var totalWidth = 0;
19256 var len = cols.length;
19257 for(var i = 0; i < len; i++){
19259 totalWidth += c.width;
19260 this.headEls.push(this.headers.createChild({
19261 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19263 cls:'x-tree-hd-text',
19266 style:'width:'+(c.width-this.borderWidth)+'px;'
19269 this.headers.createChild({cls:'x-clear'});
19270 // prevent floats from wrapping when clipped
19271 this.headers.setWidth(totalWidth);
19272 //this.innerCt.setWidth(totalWidth);
19273 this.innerCt.setStyle({ overflow: 'auto' });
19274 this.onResize(this.width, this.height);
19278 onResize : function(w,h)
19283 this.innerCt.setWidth(this.width);
19284 this.innerCt.setHeight(this.height-20);
19287 var cols = this.columns, c;
19288 var totalWidth = 0;
19290 var len = cols.length;
19291 for(var i = 0; i < len; i++){
19293 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19294 // it's the expander..
19295 expEl = this.headEls[i];
19298 totalWidth += c.width;
19302 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19304 this.headers.setWidth(w-20);
19313 * Ext JS Library 1.1.1
19314 * Copyright(c) 2006-2007, Ext JS, LLC.
19316 * Originally Released Under LGPL - original licence link has changed is not relivant.
19319 * <script type="text/javascript">
19323 * @class Roo.menu.Menu
19324 * @extends Roo.util.Observable
19325 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19326 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19328 * Creates a new Menu
19329 * @param {Object} config Configuration options
19331 Roo.menu.Menu = function(config){
19332 Roo.apply(this, config);
19333 this.id = this.id || Roo.id();
19336 * @event beforeshow
19337 * Fires before this menu is displayed
19338 * @param {Roo.menu.Menu} this
19342 * @event beforehide
19343 * Fires before this menu is hidden
19344 * @param {Roo.menu.Menu} this
19349 * Fires after this menu is displayed
19350 * @param {Roo.menu.Menu} this
19355 * Fires after this menu is hidden
19356 * @param {Roo.menu.Menu} this
19361 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19362 * @param {Roo.menu.Menu} this
19363 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19364 * @param {Roo.EventObject} e
19369 * Fires when the mouse is hovering over this menu
19370 * @param {Roo.menu.Menu} this
19371 * @param {Roo.EventObject} e
19372 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19377 * Fires when the mouse exits this menu
19378 * @param {Roo.menu.Menu} this
19379 * @param {Roo.EventObject} e
19380 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19385 * Fires when a menu item contained in this menu is clicked
19386 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19387 * @param {Roo.EventObject} e
19391 if (this.registerMenu) {
19392 Roo.menu.MenuMgr.register(this);
19395 var mis = this.items;
19396 this.items = new Roo.util.MixedCollection();
19398 this.add.apply(this, mis);
19402 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19404 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19408 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19409 * for bottom-right shadow (defaults to "sides")
19413 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19414 * this menu (defaults to "tl-tr?")
19416 subMenuAlign : "tl-tr?",
19418 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19419 * relative to its element of origin (defaults to "tl-bl?")
19421 defaultAlign : "tl-bl?",
19423 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19425 allowOtherMenus : false,
19427 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19429 registerMenu : true,
19434 render : function(){
19438 var el = this.el = new Roo.Layer({
19440 shadow:this.shadow,
19442 parentEl: this.parentEl || document.body,
19446 this.keyNav = new Roo.menu.MenuNav(this);
19449 el.addClass("x-menu-plain");
19452 el.addClass(this.cls);
19454 // generic focus element
19455 this.focusEl = el.createChild({
19456 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19458 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19459 ul.on("click", this.onClick, this);
19460 ul.on("mouseover", this.onMouseOver, this);
19461 ul.on("mouseout", this.onMouseOut, this);
19462 this.items.each(function(item){
19463 var li = document.createElement("li");
19464 li.className = "x-menu-list-item";
19465 ul.dom.appendChild(li);
19466 item.render(li, this);
19473 autoWidth : function(){
19474 var el = this.el, ul = this.ul;
19478 var w = this.width;
19481 }else if(Roo.isIE){
19482 el.setWidth(this.minWidth);
19483 var t = el.dom.offsetWidth; // force recalc
19484 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19489 delayAutoWidth : function(){
19492 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19494 this.awTask.delay(20);
19499 findTargetItem : function(e){
19500 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19501 if(t && t.menuItemId){
19502 return this.items.get(t.menuItemId);
19507 onClick : function(e){
19509 if(t = this.findTargetItem(e)){
19511 this.fireEvent("click", this, t, e);
19516 setActiveItem : function(item, autoExpand){
19517 if(item != this.activeItem){
19518 if(this.activeItem){
19519 this.activeItem.deactivate();
19521 this.activeItem = item;
19522 item.activate(autoExpand);
19523 }else if(autoExpand){
19529 tryActivate : function(start, step){
19530 var items = this.items;
19531 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19532 var item = items.get(i);
19533 if(!item.disabled && item.canActivate){
19534 this.setActiveItem(item, false);
19542 onMouseOver : function(e){
19544 if(t = this.findTargetItem(e)){
19545 if(t.canActivate && !t.disabled){
19546 this.setActiveItem(t, true);
19549 this.fireEvent("mouseover", this, e, t);
19553 onMouseOut : function(e){
19555 if(t = this.findTargetItem(e)){
19556 if(t == this.activeItem && t.shouldDeactivate(e)){
19557 this.activeItem.deactivate();
19558 delete this.activeItem;
19561 this.fireEvent("mouseout", this, e, t);
19565 * Read-only. Returns true if the menu is currently displayed, else false.
19568 isVisible : function(){
19569 return this.el && !this.hidden;
19573 * Displays this menu relative to another element
19574 * @param {String/HTMLElement/Roo.Element} element The element to align to
19575 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19576 * the element (defaults to this.defaultAlign)
19577 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19579 show : function(el, pos, parentMenu){
19580 this.parentMenu = parentMenu;
19584 this.fireEvent("beforeshow", this);
19585 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19589 * Displays this menu at a specific xy position
19590 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19591 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19593 showAt : function(xy, parentMenu, /* private: */_e){
19594 this.parentMenu = parentMenu;
19599 this.fireEvent("beforeshow", this);
19600 xy = this.el.adjustForConstraints(xy);
19604 this.hidden = false;
19606 this.fireEvent("show", this);
19609 focus : function(){
19611 this.doFocus.defer(50, this);
19615 doFocus : function(){
19617 this.focusEl.focus();
19622 * Hides this menu and optionally all parent menus
19623 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19625 hide : function(deep){
19626 if(this.el && this.isVisible()){
19627 this.fireEvent("beforehide", this);
19628 if(this.activeItem){
19629 this.activeItem.deactivate();
19630 this.activeItem = null;
19633 this.hidden = true;
19634 this.fireEvent("hide", this);
19636 if(deep === true && this.parentMenu){
19637 this.parentMenu.hide(true);
19642 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19643 * Any of the following are valid:
19645 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19646 * <li>An HTMLElement object which will be converted to a menu item</li>
19647 * <li>A menu item config object that will be created as a new menu item</li>
19648 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19649 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19654 var menu = new Roo.menu.Menu();
19656 // Create a menu item to add by reference
19657 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19659 // Add a bunch of items at once using different methods.
19660 // Only the last item added will be returned.
19661 var item = menu.add(
19662 menuItem, // add existing item by ref
19663 'Dynamic Item', // new TextItem
19664 '-', // new separator
19665 { text: 'Config Item' } // new item by config
19668 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19669 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19672 var a = arguments, l = a.length, item;
19673 for(var i = 0; i < l; i++){
19675 if ((typeof(el) == "object") && el.xtype && el.xns) {
19676 el = Roo.factory(el, Roo.menu);
19679 if(el.render){ // some kind of Item
19680 item = this.addItem(el);
19681 }else if(typeof el == "string"){ // string
19682 if(el == "separator" || el == "-"){
19683 item = this.addSeparator();
19685 item = this.addText(el);
19687 }else if(el.tagName || el.el){ // element
19688 item = this.addElement(el);
19689 }else if(typeof el == "object"){ // must be menu item config?
19690 item = this.addMenuItem(el);
19697 * Returns this menu's underlying {@link Roo.Element} object
19698 * @return {Roo.Element} The element
19700 getEl : function(){
19708 * Adds a separator bar to the menu
19709 * @return {Roo.menu.Item} The menu item that was added
19711 addSeparator : function(){
19712 return this.addItem(new Roo.menu.Separator());
19716 * Adds an {@link Roo.Element} object to the menu
19717 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19718 * @return {Roo.menu.Item} The menu item that was added
19720 addElement : function(el){
19721 return this.addItem(new Roo.menu.BaseItem(el));
19725 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19726 * @param {Roo.menu.Item} item The menu item to add
19727 * @return {Roo.menu.Item} The menu item that was added
19729 addItem : function(item){
19730 this.items.add(item);
19732 var li = document.createElement("li");
19733 li.className = "x-menu-list-item";
19734 this.ul.dom.appendChild(li);
19735 item.render(li, this);
19736 this.delayAutoWidth();
19742 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19743 * @param {Object} config A MenuItem config object
19744 * @return {Roo.menu.Item} The menu item that was added
19746 addMenuItem : function(config){
19747 if(!(config instanceof Roo.menu.Item)){
19748 if(typeof config.checked == "boolean"){ // must be check menu item config?
19749 config = new Roo.menu.CheckItem(config);
19751 config = new Roo.menu.Item(config);
19754 return this.addItem(config);
19758 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19759 * @param {String} text The text to display in the menu item
19760 * @return {Roo.menu.Item} The menu item that was added
19762 addText : function(text){
19763 return this.addItem(new Roo.menu.TextItem({ text : text }));
19767 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19768 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19769 * @param {Roo.menu.Item} item The menu item to add
19770 * @return {Roo.menu.Item} The menu item that was added
19772 insert : function(index, item){
19773 this.items.insert(index, item);
19775 var li = document.createElement("li");
19776 li.className = "x-menu-list-item";
19777 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19778 item.render(li, this);
19779 this.delayAutoWidth();
19785 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19786 * @param {Roo.menu.Item} item The menu item to remove
19788 remove : function(item){
19789 this.items.removeKey(item.id);
19794 * Removes and destroys all items in the menu
19796 removeAll : function(){
19798 while(f = this.items.first()){
19804 // MenuNav is a private utility class used internally by the Menu
19805 Roo.menu.MenuNav = function(menu){
19806 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19807 this.scope = this.menu = menu;
19810 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19811 doRelay : function(e, h){
19812 var k = e.getKey();
19813 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19814 this.menu.tryActivate(0, 1);
19817 return h.call(this.scope || this, e, this.menu);
19820 up : function(e, m){
19821 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19822 m.tryActivate(m.items.length-1, -1);
19826 down : function(e, m){
19827 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19828 m.tryActivate(0, 1);
19832 right : function(e, m){
19834 m.activeItem.expandMenu(true);
19838 left : function(e, m){
19840 if(m.parentMenu && m.parentMenu.activeItem){
19841 m.parentMenu.activeItem.activate();
19845 enter : function(e, m){
19847 e.stopPropagation();
19848 m.activeItem.onClick(e);
19849 m.fireEvent("click", this, m.activeItem);
19855 * Ext JS Library 1.1.1
19856 * Copyright(c) 2006-2007, Ext JS, LLC.
19858 * Originally Released Under LGPL - original licence link has changed is not relivant.
19861 * <script type="text/javascript">
19865 * @class Roo.menu.MenuMgr
19866 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19869 Roo.menu.MenuMgr = function(){
19870 var menus, active, groups = {}, attached = false, lastShow = new Date();
19872 // private - called when first menu is created
19875 active = new Roo.util.MixedCollection();
19876 Roo.get(document).addKeyListener(27, function(){
19877 if(active.length > 0){
19884 function hideAll(){
19885 if(active && active.length > 0){
19886 var c = active.clone();
19887 c.each(function(m){
19894 function onHide(m){
19896 if(active.length < 1){
19897 Roo.get(document).un("mousedown", onMouseDown);
19903 function onShow(m){
19904 var last = active.last();
19905 lastShow = new Date();
19908 Roo.get(document).on("mousedown", onMouseDown);
19912 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19913 m.parentMenu.activeChild = m;
19914 }else if(last && last.isVisible()){
19915 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19920 function onBeforeHide(m){
19922 m.activeChild.hide();
19924 if(m.autoHideTimer){
19925 clearTimeout(m.autoHideTimer);
19926 delete m.autoHideTimer;
19931 function onBeforeShow(m){
19932 var pm = m.parentMenu;
19933 if(!pm && !m.allowOtherMenus){
19935 }else if(pm && pm.activeChild && active != m){
19936 pm.activeChild.hide();
19941 function onMouseDown(e){
19942 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19948 function onBeforeCheck(mi, state){
19950 var g = groups[mi.group];
19951 for(var i = 0, l = g.length; i < l; i++){
19953 g[i].setChecked(false);
19962 * Hides all menus that are currently visible
19964 hideAll : function(){
19969 register : function(menu){
19973 menus[menu.id] = menu;
19974 menu.on("beforehide", onBeforeHide);
19975 menu.on("hide", onHide);
19976 menu.on("beforeshow", onBeforeShow);
19977 menu.on("show", onShow);
19978 var g = menu.group;
19979 if(g && menu.events["checkchange"]){
19983 groups[g].push(menu);
19984 menu.on("checkchange", onCheck);
19989 * Returns a {@link Roo.menu.Menu} object
19990 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19991 * be used to generate and return a new Menu instance.
19993 get : function(menu){
19994 if(typeof menu == "string"){ // menu id
19995 return menus[menu];
19996 }else if(menu.events){ // menu instance
19998 }else if(typeof menu.length == 'number'){ // array of menu items?
19999 return new Roo.menu.Menu({items:menu});
20000 }else{ // otherwise, must be a config
20001 return new Roo.menu.Menu(menu);
20006 unregister : function(menu){
20007 delete menus[menu.id];
20008 menu.un("beforehide", onBeforeHide);
20009 menu.un("hide", onHide);
20010 menu.un("beforeshow", onBeforeShow);
20011 menu.un("show", onShow);
20012 var g = menu.group;
20013 if(g && menu.events["checkchange"]){
20014 groups[g].remove(menu);
20015 menu.un("checkchange", onCheck);
20020 registerCheckable : function(menuItem){
20021 var g = menuItem.group;
20026 groups[g].push(menuItem);
20027 menuItem.on("beforecheckchange", onBeforeCheck);
20032 unregisterCheckable : function(menuItem){
20033 var g = menuItem.group;
20035 groups[g].remove(menuItem);
20036 menuItem.un("beforecheckchange", onBeforeCheck);
20042 * Ext JS Library 1.1.1
20043 * Copyright(c) 2006-2007, Ext JS, LLC.
20045 * Originally Released Under LGPL - original licence link has changed is not relivant.
20048 * <script type="text/javascript">
20053 * @class Roo.menu.BaseItem
20054 * @extends Roo.Component
20055 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20056 * management and base configuration options shared by all menu components.
20058 * Creates a new BaseItem
20059 * @param {Object} config Configuration options
20061 Roo.menu.BaseItem = function(config){
20062 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20067 * Fires when this item is clicked
20068 * @param {Roo.menu.BaseItem} this
20069 * @param {Roo.EventObject} e
20074 * Fires when this item is activated
20075 * @param {Roo.menu.BaseItem} this
20079 * @event deactivate
20080 * Fires when this item is deactivated
20081 * @param {Roo.menu.BaseItem} this
20087 this.on("click", this.handler, this.scope, true);
20091 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20093 * @cfg {Function} handler
20094 * A function that will handle the click event of this menu item (defaults to undefined)
20097 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20099 canActivate : false,
20101 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20103 activeClass : "x-menu-item-active",
20105 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20107 hideOnClick : true,
20109 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20114 ctype: "Roo.menu.BaseItem",
20117 actionMode : "container",
20120 render : function(container, parentMenu){
20121 this.parentMenu = parentMenu;
20122 Roo.menu.BaseItem.superclass.render.call(this, container);
20123 this.container.menuItemId = this.id;
20127 onRender : function(container, position){
20128 this.el = Roo.get(this.el);
20129 container.dom.appendChild(this.el.dom);
20133 onClick : function(e){
20134 if(!this.disabled && this.fireEvent("click", this, e) !== false
20135 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20136 this.handleClick(e);
20143 activate : function(){
20147 var li = this.container;
20148 li.addClass(this.activeClass);
20149 this.region = li.getRegion().adjust(2, 2, -2, -2);
20150 this.fireEvent("activate", this);
20155 deactivate : function(){
20156 this.container.removeClass(this.activeClass);
20157 this.fireEvent("deactivate", this);
20161 shouldDeactivate : function(e){
20162 return !this.region || !this.region.contains(e.getPoint());
20166 handleClick : function(e){
20167 if(this.hideOnClick){
20168 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20173 expandMenu : function(autoActivate){
20178 hideMenu : function(){
20183 * Ext JS Library 1.1.1
20184 * Copyright(c) 2006-2007, Ext JS, LLC.
20186 * Originally Released Under LGPL - original licence link has changed is not relivant.
20189 * <script type="text/javascript">
20193 * @class Roo.menu.Adapter
20194 * @extends Roo.menu.BaseItem
20195 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
20196 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20198 * Creates a new Adapter
20199 * @param {Object} config Configuration options
20201 Roo.menu.Adapter = function(component, config){
20202 Roo.menu.Adapter.superclass.constructor.call(this, config);
20203 this.component = component;
20205 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20207 canActivate : true,
20210 onRender : function(container, position){
20211 this.component.render(container);
20212 this.el = this.component.getEl();
20216 activate : function(){
20220 this.component.focus();
20221 this.fireEvent("activate", this);
20226 deactivate : function(){
20227 this.fireEvent("deactivate", this);
20231 disable : function(){
20232 this.component.disable();
20233 Roo.menu.Adapter.superclass.disable.call(this);
20237 enable : function(){
20238 this.component.enable();
20239 Roo.menu.Adapter.superclass.enable.call(this);
20243 * Ext JS Library 1.1.1
20244 * Copyright(c) 2006-2007, Ext JS, LLC.
20246 * Originally Released Under LGPL - original licence link has changed is not relivant.
20249 * <script type="text/javascript">
20253 * @class Roo.menu.TextItem
20254 * @extends Roo.menu.BaseItem
20255 * Adds a static text string to a menu, usually used as either a heading or group separator.
20256 * Note: old style constructor with text is still supported.
20259 * Creates a new TextItem
20260 * @param {Object} cfg Configuration
20262 Roo.menu.TextItem = function(cfg){
20263 if (typeof(cfg) == 'string') {
20266 Roo.apply(this,cfg);
20269 Roo.menu.TextItem.superclass.constructor.call(this);
20272 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20274 * @cfg {Boolean} text Text to show on item.
20279 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20281 hideOnClick : false,
20283 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20285 itemCls : "x-menu-text",
20288 onRender : function(){
20289 var s = document.createElement("span");
20290 s.className = this.itemCls;
20291 s.innerHTML = this.text;
20293 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20297 * Ext JS Library 1.1.1
20298 * Copyright(c) 2006-2007, Ext JS, LLC.
20300 * Originally Released Under LGPL - original licence link has changed is not relivant.
20303 * <script type="text/javascript">
20307 * @class Roo.menu.Separator
20308 * @extends Roo.menu.BaseItem
20309 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20310 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20312 * @param {Object} config Configuration options
20314 Roo.menu.Separator = function(config){
20315 Roo.menu.Separator.superclass.constructor.call(this, config);
20318 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20320 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20322 itemCls : "x-menu-sep",
20324 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20326 hideOnClick : false,
20329 onRender : function(li){
20330 var s = document.createElement("span");
20331 s.className = this.itemCls;
20332 s.innerHTML = " ";
20334 li.addClass("x-menu-sep-li");
20335 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20339 * Ext JS Library 1.1.1
20340 * Copyright(c) 2006-2007, Ext JS, LLC.
20342 * Originally Released Under LGPL - original licence link has changed is not relivant.
20345 * <script type="text/javascript">
20348 * @class Roo.menu.Item
20349 * @extends Roo.menu.BaseItem
20350 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20351 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20352 * activation and click handling.
20354 * Creates a new Item
20355 * @param {Object} config Configuration options
20357 Roo.menu.Item = function(config){
20358 Roo.menu.Item.superclass.constructor.call(this, config);
20360 this.menu = Roo.menu.MenuMgr.get(this.menu);
20363 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20366 * @cfg {String} text
20367 * The text to show on the menu item.
20371 * @cfg {String} HTML to render in menu
20372 * The text to show on the menu item (HTML version).
20376 * @cfg {String} icon
20377 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20381 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20383 itemCls : "x-menu-item",
20385 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20387 canActivate : true,
20389 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20392 // doc'd in BaseItem
20396 ctype: "Roo.menu.Item",
20399 onRender : function(container, position){
20400 var el = document.createElement("a");
20401 el.hideFocus = true;
20402 el.unselectable = "on";
20403 el.href = this.href || "#";
20404 if(this.hrefTarget){
20405 el.target = this.hrefTarget;
20407 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20409 var html = this.html.length ? this.html : String.format('{0}',this.text);
20411 el.innerHTML = String.format(
20412 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20413 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20415 Roo.menu.Item.superclass.onRender.call(this, container, position);
20419 * Sets the text to display in this menu item
20420 * @param {String} text The text to display
20421 * @param {Boolean} isHTML true to indicate text is pure html.
20423 setText : function(text, isHTML){
20431 var html = this.html.length ? this.html : String.format('{0}',this.text);
20433 this.el.update(String.format(
20434 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20435 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20436 this.parentMenu.autoWidth();
20441 handleClick : function(e){
20442 if(!this.href){ // if no link defined, stop the event automatically
20445 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20449 activate : function(autoExpand){
20450 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20460 shouldDeactivate : function(e){
20461 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20462 if(this.menu && this.menu.isVisible()){
20463 return !this.menu.getEl().getRegion().contains(e.getPoint());
20471 deactivate : function(){
20472 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20477 expandMenu : function(autoActivate){
20478 if(!this.disabled && this.menu){
20479 clearTimeout(this.hideTimer);
20480 delete this.hideTimer;
20481 if(!this.menu.isVisible() && !this.showTimer){
20482 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20483 }else if (this.menu.isVisible() && autoActivate){
20484 this.menu.tryActivate(0, 1);
20490 deferExpand : function(autoActivate){
20491 delete this.showTimer;
20492 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20494 this.menu.tryActivate(0, 1);
20499 hideMenu : function(){
20500 clearTimeout(this.showTimer);
20501 delete this.showTimer;
20502 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20503 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20508 deferHide : function(){
20509 delete this.hideTimer;
20514 * Ext JS Library 1.1.1
20515 * Copyright(c) 2006-2007, Ext JS, LLC.
20517 * Originally Released Under LGPL - original licence link has changed is not relivant.
20520 * <script type="text/javascript">
20524 * @class Roo.menu.CheckItem
20525 * @extends Roo.menu.Item
20526 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20528 * Creates a new CheckItem
20529 * @param {Object} config Configuration options
20531 Roo.menu.CheckItem = function(config){
20532 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20535 * @event beforecheckchange
20536 * Fires before the checked value is set, providing an opportunity to cancel if needed
20537 * @param {Roo.menu.CheckItem} this
20538 * @param {Boolean} checked The new checked value that will be set
20540 "beforecheckchange" : true,
20542 * @event checkchange
20543 * Fires after the checked value has been set
20544 * @param {Roo.menu.CheckItem} this
20545 * @param {Boolean} checked The checked value that was set
20547 "checkchange" : true
20549 if(this.checkHandler){
20550 this.on('checkchange', this.checkHandler, this.scope);
20553 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20555 * @cfg {String} group
20556 * All check items with the same group name will automatically be grouped into a single-select
20557 * radio button group (defaults to '')
20560 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20562 itemCls : "x-menu-item x-menu-check-item",
20564 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20566 groupClass : "x-menu-group-item",
20569 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20570 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20571 * initialized with checked = true will be rendered as checked.
20576 ctype: "Roo.menu.CheckItem",
20579 onRender : function(c){
20580 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20582 this.el.addClass(this.groupClass);
20584 Roo.menu.MenuMgr.registerCheckable(this);
20586 this.checked = false;
20587 this.setChecked(true, true);
20592 destroy : function(){
20594 Roo.menu.MenuMgr.unregisterCheckable(this);
20596 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20600 * Set the checked state of this item
20601 * @param {Boolean} checked The new checked value
20602 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20604 setChecked : function(state, suppressEvent){
20605 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20606 if(this.container){
20607 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20609 this.checked = state;
20610 if(suppressEvent !== true){
20611 this.fireEvent("checkchange", this, state);
20617 handleClick : function(e){
20618 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20619 this.setChecked(!this.checked);
20621 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20625 * Ext JS Library 1.1.1
20626 * Copyright(c) 2006-2007, Ext JS, LLC.
20628 * Originally Released Under LGPL - original licence link has changed is not relivant.
20631 * <script type="text/javascript">
20635 * @class Roo.menu.DateItem
20636 * @extends Roo.menu.Adapter
20637 * A menu item that wraps the {@link Roo.DatPicker} component.
20639 * Creates a new DateItem
20640 * @param {Object} config Configuration options
20642 Roo.menu.DateItem = function(config){
20643 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20644 /** The Roo.DatePicker object @type Roo.DatePicker */
20645 this.picker = this.component;
20646 this.addEvents({select: true});
20648 this.picker.on("render", function(picker){
20649 picker.getEl().swallowEvent("click");
20650 picker.container.addClass("x-menu-date-item");
20653 this.picker.on("select", this.onSelect, this);
20656 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20658 onSelect : function(picker, date){
20659 this.fireEvent("select", this, date, picker);
20660 Roo.menu.DateItem.superclass.handleClick.call(this);
20664 * Ext JS Library 1.1.1
20665 * Copyright(c) 2006-2007, Ext JS, LLC.
20667 * Originally Released Under LGPL - original licence link has changed is not relivant.
20670 * <script type="text/javascript">
20674 * @class Roo.menu.ColorItem
20675 * @extends Roo.menu.Adapter
20676 * A menu item that wraps the {@link Roo.ColorPalette} component.
20678 * Creates a new ColorItem
20679 * @param {Object} config Configuration options
20681 Roo.menu.ColorItem = function(config){
20682 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20683 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20684 this.palette = this.component;
20685 this.relayEvents(this.palette, ["select"]);
20686 if(this.selectHandler){
20687 this.on('select', this.selectHandler, this.scope);
20690 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20692 * Ext JS Library 1.1.1
20693 * Copyright(c) 2006-2007, Ext JS, LLC.
20695 * Originally Released Under LGPL - original licence link has changed is not relivant.
20698 * <script type="text/javascript">
20703 * @class Roo.menu.DateMenu
20704 * @extends Roo.menu.Menu
20705 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20707 * Creates a new DateMenu
20708 * @param {Object} config Configuration options
20710 Roo.menu.DateMenu = function(config){
20711 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20713 var di = new Roo.menu.DateItem(config);
20716 * The {@link Roo.DatePicker} instance for this DateMenu
20719 this.picker = di.picker;
20722 * @param {DatePicker} picker
20723 * @param {Date} date
20725 this.relayEvents(di, ["select"]);
20727 this.on('beforeshow', function(){
20729 this.picker.hideMonthPicker(true);
20733 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20737 * Ext JS Library 1.1.1
20738 * Copyright(c) 2006-2007, Ext JS, LLC.
20740 * Originally Released Under LGPL - original licence link has changed is not relivant.
20743 * <script type="text/javascript">
20748 * @class Roo.menu.ColorMenu
20749 * @extends Roo.menu.Menu
20750 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20752 * Creates a new ColorMenu
20753 * @param {Object} config Configuration options
20755 Roo.menu.ColorMenu = function(config){
20756 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20758 var ci = new Roo.menu.ColorItem(config);
20761 * The {@link Roo.ColorPalette} instance for this ColorMenu
20762 * @type ColorPalette
20764 this.palette = ci.palette;
20767 * @param {ColorPalette} palette
20768 * @param {String} color
20770 this.relayEvents(ci, ["select"]);
20772 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20774 * Ext JS Library 1.1.1
20775 * Copyright(c) 2006-2007, Ext JS, LLC.
20777 * Originally Released Under LGPL - original licence link has changed is not relivant.
20780 * <script type="text/javascript">
20784 * @class Roo.form.Field
20785 * @extends Roo.BoxComponent
20786 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20788 * Creates a new Field
20789 * @param {Object} config Configuration options
20791 Roo.form.Field = function(config){
20792 Roo.form.Field.superclass.constructor.call(this, config);
20795 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20797 * @cfg {String} fieldLabel Label to use when rendering a form.
20800 * @cfg {String} qtip Mouse over tip
20804 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20806 invalidClass : "x-form-invalid",
20808 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
20810 invalidText : "The value in this field is invalid",
20812 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20814 focusClass : "x-form-focus",
20816 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20817 automatic validation (defaults to "keyup").
20819 validationEvent : "keyup",
20821 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20823 validateOnBlur : true,
20825 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20827 validationDelay : 250,
20829 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20830 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20832 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20834 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20836 fieldClass : "x-form-field",
20838 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20841 ----------- ----------------------------------------------------------------------
20842 qtip Display a quick tip when the user hovers over the field
20843 title Display a default browser title attribute popup
20844 under Add a block div beneath the field containing the error text
20845 side Add an error icon to the right of the field with a popup on hover
20846 [element id] Add the error text directly to the innerHTML of the specified element
20849 msgTarget : 'qtip',
20851 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20856 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
20861 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20866 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20868 inputType : undefined,
20871 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
20873 tabIndex : undefined,
20876 isFormField : true,
20881 * @property {Roo.Element} fieldEl
20882 * Element Containing the rendered Field (with label etc.)
20885 * @cfg {Mixed} value A value to initialize this field with.
20890 * @cfg {String} name The field's HTML name attribute.
20893 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20897 initComponent : function(){
20898 Roo.form.Field.superclass.initComponent.call(this);
20902 * Fires when this field receives input focus.
20903 * @param {Roo.form.Field} this
20908 * Fires when this field loses input focus.
20909 * @param {Roo.form.Field} this
20913 * @event specialkey
20914 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20915 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20916 * @param {Roo.form.Field} this
20917 * @param {Roo.EventObject} e The event object
20922 * Fires just before the field blurs if the field value has changed.
20923 * @param {Roo.form.Field} this
20924 * @param {Mixed} newValue The new value
20925 * @param {Mixed} oldValue The original value
20930 * Fires after the field has been marked as invalid.
20931 * @param {Roo.form.Field} this
20932 * @param {String} msg The validation message
20937 * Fires after the field has been validated with no errors.
20938 * @param {Roo.form.Field} this
20943 * Fires after the key up
20944 * @param {Roo.form.Field} this
20945 * @param {Roo.EventObject} e The event Object
20952 * Returns the name attribute of the field if available
20953 * @return {String} name The field name
20955 getName: function(){
20956 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20960 onRender : function(ct, position){
20961 Roo.form.Field.superclass.onRender.call(this, ct, position);
20963 var cfg = this.getAutoCreate();
20965 cfg.name = this.name || this.id;
20967 if(this.inputType){
20968 cfg.type = this.inputType;
20970 this.el = ct.createChild(cfg, position);
20972 var type = this.el.dom.type;
20974 if(type == 'password'){
20977 this.el.addClass('x-form-'+type);
20980 this.el.dom.readOnly = true;
20982 if(this.tabIndex !== undefined){
20983 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20986 this.el.addClass([this.fieldClass, this.cls]);
20991 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20992 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20993 * @return {Roo.form.Field} this
20995 applyTo : function(target){
20996 this.allowDomMove = false;
20997 this.el = Roo.get(target);
20998 this.render(this.el.dom.parentNode);
21003 initValue : function(){
21004 if(this.value !== undefined){
21005 this.setValue(this.value);
21006 }else if(this.el.dom.value.length > 0){
21007 this.setValue(this.el.dom.value);
21012 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21014 isDirty : function() {
21015 if(this.disabled) {
21018 return String(this.getValue()) !== String(this.originalValue);
21022 afterRender : function(){
21023 Roo.form.Field.superclass.afterRender.call(this);
21028 fireKey : function(e){
21029 //Roo.log('field ' + e.getKey());
21030 if(e.isNavKeyPress()){
21031 this.fireEvent("specialkey", this, e);
21036 * Resets the current field value to the originally loaded value and clears any validation messages
21038 reset : function(){
21039 this.setValue(this.originalValue);
21040 this.clearInvalid();
21044 initEvents : function(){
21045 // safari killled keypress - so keydown is now used..
21046 this.el.on("keydown" , this.fireKey, this);
21047 this.el.on("focus", this.onFocus, this);
21048 this.el.on("blur", this.onBlur, this);
21049 this.el.relayEvent('keyup', this);
21051 // reference to original value for reset
21052 this.originalValue = this.getValue();
21056 onFocus : function(){
21057 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21058 this.el.addClass(this.focusClass);
21060 if(!this.hasFocus){
21061 this.hasFocus = true;
21062 this.startValue = this.getValue();
21063 this.fireEvent("focus", this);
21067 beforeBlur : Roo.emptyFn,
21070 onBlur : function(){
21072 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21073 this.el.removeClass(this.focusClass);
21075 this.hasFocus = false;
21076 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21079 var v = this.getValue();
21080 if(String(v) !== String(this.startValue)){
21081 this.fireEvent('change', this, v, this.startValue);
21083 this.fireEvent("blur", this);
21087 * Returns whether or not the field value is currently valid
21088 * @param {Boolean} preventMark True to disable marking the field invalid
21089 * @return {Boolean} True if the value is valid, else false
21091 isValid : function(preventMark){
21095 var restore = this.preventMark;
21096 this.preventMark = preventMark === true;
21097 var v = this.validateValue(this.processValue(this.getRawValue()));
21098 this.preventMark = restore;
21103 * Validates the field value
21104 * @return {Boolean} True if the value is valid, else false
21106 validate : function(){
21107 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21108 this.clearInvalid();
21114 processValue : function(value){
21119 // Subclasses should provide the validation implementation by overriding this
21120 validateValue : function(value){
21125 * Mark this field as invalid
21126 * @param {String} msg The validation message
21128 markInvalid : function(msg){
21129 if(!this.rendered || this.preventMark){ // not rendered
21132 this.el.addClass(this.invalidClass);
21133 msg = msg || this.invalidText;
21134 switch(this.msgTarget){
21136 this.el.dom.qtip = msg;
21137 this.el.dom.qclass = 'x-form-invalid-tip';
21138 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21139 Roo.QuickTips.enable();
21143 this.el.dom.title = msg;
21147 var elp = this.el.findParent('.x-form-element', 5, true);
21148 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21149 this.errorEl.setWidth(elp.getWidth(true)-20);
21151 this.errorEl.update(msg);
21152 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21155 if(!this.errorIcon){
21156 var elp = this.el.findParent('.x-form-element', 5, true);
21157 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21159 this.alignErrorIcon();
21160 this.errorIcon.dom.qtip = msg;
21161 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21162 this.errorIcon.show();
21163 this.on('resize', this.alignErrorIcon, this);
21166 var t = Roo.getDom(this.msgTarget);
21168 t.style.display = this.msgDisplay;
21171 this.fireEvent('invalid', this, msg);
21175 alignErrorIcon : function(){
21176 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21180 * Clear any invalid styles/messages for this field
21182 clearInvalid : function(){
21183 if(!this.rendered || this.preventMark){ // not rendered
21186 this.el.removeClass(this.invalidClass);
21187 switch(this.msgTarget){
21189 this.el.dom.qtip = '';
21192 this.el.dom.title = '';
21196 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21200 if(this.errorIcon){
21201 this.errorIcon.dom.qtip = '';
21202 this.errorIcon.hide();
21203 this.un('resize', this.alignErrorIcon, this);
21207 var t = Roo.getDom(this.msgTarget);
21209 t.style.display = 'none';
21212 this.fireEvent('valid', this);
21216 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21217 * @return {Mixed} value The field value
21219 getRawValue : function(){
21220 var v = this.el.getValue();
21221 if(v === this.emptyText){
21228 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21229 * @return {Mixed} value The field value
21231 getValue : function(){
21232 var v = this.el.getValue();
21233 if(v === this.emptyText || v === undefined){
21240 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21241 * @param {Mixed} value The value to set
21243 setRawValue : function(v){
21244 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21248 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21249 * @param {Mixed} value The value to set
21251 setValue : function(v){
21254 this.el.dom.value = (v === null || v === undefined ? '' : v);
21259 adjustSize : function(w, h){
21260 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21261 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21265 adjustWidth : function(tag, w){
21266 tag = tag.toLowerCase();
21267 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21268 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21269 if(tag == 'input'){
21272 if(tag = 'textarea'){
21275 }else if(Roo.isOpera){
21276 if(tag == 'input'){
21279 if(tag = 'textarea'){
21289 // anything other than normal should be considered experimental
21290 Roo.form.Field.msgFx = {
21292 show: function(msgEl, f){
21293 msgEl.setDisplayed('block');
21296 hide : function(msgEl, f){
21297 msgEl.setDisplayed(false).update('');
21302 show: function(msgEl, f){
21303 msgEl.slideIn('t', {stopFx:true});
21306 hide : function(msgEl, f){
21307 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21312 show: function(msgEl, f){
21313 msgEl.fixDisplay();
21314 msgEl.alignTo(f.el, 'tl-tr');
21315 msgEl.slideIn('l', {stopFx:true});
21318 hide : function(msgEl, f){
21319 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21324 * Ext JS Library 1.1.1
21325 * Copyright(c) 2006-2007, Ext JS, LLC.
21327 * Originally Released Under LGPL - original licence link has changed is not relivant.
21330 * <script type="text/javascript">
21335 * @class Roo.form.TextField
21336 * @extends Roo.form.Field
21337 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21338 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21340 * Creates a new TextField
21341 * @param {Object} config Configuration options
21343 Roo.form.TextField = function(config){
21344 Roo.form.TextField.superclass.constructor.call(this, config);
21348 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21349 * according to the default logic, but this event provides a hook for the developer to apply additional
21350 * logic at runtime to resize the field if needed.
21351 * @param {Roo.form.Field} this This text field
21352 * @param {Number} width The new field width
21358 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21360 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21364 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21368 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21372 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21376 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21380 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21382 disableKeyFilter : false,
21384 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21388 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21392 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21394 maxLength : Number.MAX_VALUE,
21396 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21398 minLengthText : "The minimum length for this field is {0}",
21400 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21402 maxLengthText : "The maximum length for this field is {0}",
21404 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21406 selectOnFocus : false,
21408 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21410 blankText : "This field is required",
21412 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21413 * If available, this function will be called only after the basic validators all return true, and will be passed the
21414 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21418 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21419 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21420 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21424 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21428 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21432 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21433 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21435 emptyClass : 'x-form-empty-field',
21438 initEvents : function(){
21439 Roo.form.TextField.superclass.initEvents.call(this);
21440 if(this.validationEvent == 'keyup'){
21441 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21442 this.el.on('keyup', this.filterValidation, this);
21444 else if(this.validationEvent !== false){
21445 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21447 if(this.selectOnFocus || this.emptyText){
21448 this.on("focus", this.preFocus, this);
21449 if(this.emptyText){
21450 this.on('blur', this.postBlur, this);
21451 this.applyEmptyText();
21454 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21455 this.el.on("keypress", this.filterKeys, this);
21458 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21459 this.el.on("click", this.autoSize, this);
21463 processValue : function(value){
21464 if(this.stripCharsRe){
21465 var newValue = value.replace(this.stripCharsRe, '');
21466 if(newValue !== value){
21467 this.setRawValue(newValue);
21474 filterValidation : function(e){
21475 if(!e.isNavKeyPress()){
21476 this.validationTask.delay(this.validationDelay);
21481 onKeyUp : function(e){
21482 if(!e.isNavKeyPress()){
21488 * Resets the current field value to the originally-loaded value and clears any validation messages.
21489 * Also adds emptyText and emptyClass if the original value was blank.
21491 reset : function(){
21492 Roo.form.TextField.superclass.reset.call(this);
21493 this.applyEmptyText();
21496 applyEmptyText : function(){
21497 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21498 this.setRawValue(this.emptyText);
21499 this.el.addClass(this.emptyClass);
21504 preFocus : function(){
21505 if(this.emptyText){
21506 if(this.el.dom.value == this.emptyText){
21507 this.setRawValue('');
21509 this.el.removeClass(this.emptyClass);
21511 if(this.selectOnFocus){
21512 this.el.dom.select();
21517 postBlur : function(){
21518 this.applyEmptyText();
21522 filterKeys : function(e){
21523 var k = e.getKey();
21524 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21527 var c = e.getCharCode(), cc = String.fromCharCode(c);
21528 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21531 if(!this.maskRe.test(cc)){
21536 setValue : function(v){
21537 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21538 this.el.removeClass(this.emptyClass);
21540 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21541 this.applyEmptyText();
21546 * Validates a value according to the field's validation rules and marks the field as invalid
21547 * if the validation fails
21548 * @param {Mixed} value The value to validate
21549 * @return {Boolean} True if the value is valid, else false
21551 validateValue : function(value){
21552 if(value.length < 1 || value === this.emptyText){ // if it's blank
21553 if(this.allowBlank){
21554 this.clearInvalid();
21557 this.markInvalid(this.blankText);
21561 if(value.length < this.minLength){
21562 this.markInvalid(String.format(this.minLengthText, this.minLength));
21565 if(value.length > this.maxLength){
21566 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21570 var vt = Roo.form.VTypes;
21571 if(!vt[this.vtype](value, this)){
21572 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21576 if(typeof this.validator == "function"){
21577 var msg = this.validator(value);
21579 this.markInvalid(msg);
21583 if(this.regex && !this.regex.test(value)){
21584 this.markInvalid(this.regexText);
21591 * Selects text in this field
21592 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21593 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21595 selectText : function(start, end){
21596 var v = this.getRawValue();
21598 start = start === undefined ? 0 : start;
21599 end = end === undefined ? v.length : end;
21600 var d = this.el.dom;
21601 if(d.setSelectionRange){
21602 d.setSelectionRange(start, end);
21603 }else if(d.createTextRange){
21604 var range = d.createTextRange();
21605 range.moveStart("character", start);
21606 range.moveEnd("character", v.length-end);
21613 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21614 * This only takes effect if grow = true, and fires the autosize event.
21616 autoSize : function(){
21617 if(!this.grow || !this.rendered){
21621 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21624 var v = el.dom.value;
21625 var d = document.createElement('div');
21626 d.appendChild(document.createTextNode(v));
21630 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21631 this.el.setWidth(w);
21632 this.fireEvent("autosize", this, w);
21636 * Ext JS Library 1.1.1
21637 * Copyright(c) 2006-2007, Ext JS, LLC.
21639 * Originally Released Under LGPL - original licence link has changed is not relivant.
21642 * <script type="text/javascript">
21646 * @class Roo.form.Hidden
21647 * @extends Roo.form.TextField
21648 * Simple Hidden element used on forms
21650 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21653 * Creates a new Hidden form element.
21654 * @param {Object} config Configuration options
21659 // easy hidden field...
21660 Roo.form.Hidden = function(config){
21661 Roo.form.Hidden.superclass.constructor.call(this, config);
21664 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21666 inputType: 'hidden',
21669 labelSeparator: '',
21671 itemCls : 'x-form-item-display-none'
21679 * Ext JS Library 1.1.1
21680 * Copyright(c) 2006-2007, Ext JS, LLC.
21682 * Originally Released Under LGPL - original licence link has changed is not relivant.
21685 * <script type="text/javascript">
21689 * @class Roo.form.TriggerField
21690 * @extends Roo.form.TextField
21691 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21692 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21693 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21694 * for which you can provide a custom implementation. For example:
21696 var trigger = new Roo.form.TriggerField();
21697 trigger.onTriggerClick = myTriggerFn;
21698 trigger.applyTo('my-field');
21701 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21702 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21703 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21704 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21706 * Create a new TriggerField.
21707 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21708 * to the base TextField)
21710 Roo.form.TriggerField = function(config){
21711 this.mimicing = false;
21712 Roo.form.TriggerField.superclass.constructor.call(this, config);
21715 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21717 * @cfg {String} triggerClass A CSS class to apply to the trigger
21720 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21721 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21723 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21725 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21729 /** @cfg {Boolean} grow @hide */
21730 /** @cfg {Number} growMin @hide */
21731 /** @cfg {Number} growMax @hide */
21737 autoSize: Roo.emptyFn,
21741 deferHeight : true,
21744 actionMode : 'wrap',
21746 onResize : function(w, h){
21747 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21748 if(typeof w == 'number'){
21749 var x = w - this.trigger.getWidth();
21750 this.el.setWidth(this.adjustWidth('input', x));
21751 this.trigger.setStyle('left', x+'px');
21756 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21759 getResizeEl : function(){
21764 getPositionEl : function(){
21769 alignErrorIcon : function(){
21770 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21774 onRender : function(ct, position){
21775 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21776 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21777 this.trigger = this.wrap.createChild(this.triggerConfig ||
21778 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21779 if(this.hideTrigger){
21780 this.trigger.setDisplayed(false);
21782 this.initTrigger();
21784 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21789 initTrigger : function(){
21790 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21791 this.trigger.addClassOnOver('x-form-trigger-over');
21792 this.trigger.addClassOnClick('x-form-trigger-click');
21796 onDestroy : function(){
21798 this.trigger.removeAllListeners();
21799 this.trigger.remove();
21802 this.wrap.remove();
21804 Roo.form.TriggerField.superclass.onDestroy.call(this);
21808 onFocus : function(){
21809 Roo.form.TriggerField.superclass.onFocus.call(this);
21810 if(!this.mimicing){
21811 this.wrap.addClass('x-trigger-wrap-focus');
21812 this.mimicing = true;
21813 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21814 if(this.monitorTab){
21815 this.el.on("keydown", this.checkTab, this);
21821 checkTab : function(e){
21822 if(e.getKey() == e.TAB){
21823 this.triggerBlur();
21828 onBlur : function(){
21833 mimicBlur : function(e, t){
21834 if(!this.wrap.contains(t) && this.validateBlur()){
21835 this.triggerBlur();
21840 triggerBlur : function(){
21841 this.mimicing = false;
21842 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21843 if(this.monitorTab){
21844 this.el.un("keydown", this.checkTab, this);
21846 this.wrap.removeClass('x-trigger-wrap-focus');
21847 Roo.form.TriggerField.superclass.onBlur.call(this);
21851 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21852 validateBlur : function(e, t){
21857 onDisable : function(){
21858 Roo.form.TriggerField.superclass.onDisable.call(this);
21860 this.wrap.addClass('x-item-disabled');
21865 onEnable : function(){
21866 Roo.form.TriggerField.superclass.onEnable.call(this);
21868 this.wrap.removeClass('x-item-disabled');
21873 onShow : function(){
21874 var ae = this.getActionEl();
21877 ae.dom.style.display = '';
21878 ae.dom.style.visibility = 'visible';
21884 onHide : function(){
21885 var ae = this.getActionEl();
21886 ae.dom.style.display = 'none';
21890 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21891 * by an implementing function.
21893 * @param {EventObject} e
21895 onTriggerClick : Roo.emptyFn
21898 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21899 // to be extended by an implementing class. For an example of implementing this class, see the custom
21900 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21901 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21902 initComponent : function(){
21903 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21905 this.triggerConfig = {
21906 tag:'span', cls:'x-form-twin-triggers', cn:[
21907 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21908 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21912 getTrigger : function(index){
21913 return this.triggers[index];
21916 initTrigger : function(){
21917 var ts = this.trigger.select('.x-form-trigger', true);
21918 this.wrap.setStyle('overflow', 'hidden');
21919 var triggerField = this;
21920 ts.each(function(t, all, index){
21921 t.hide = function(){
21922 var w = triggerField.wrap.getWidth();
21923 this.dom.style.display = 'none';
21924 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21926 t.show = function(){
21927 var w = triggerField.wrap.getWidth();
21928 this.dom.style.display = '';
21929 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21931 var triggerIndex = 'Trigger'+(index+1);
21933 if(this['hide'+triggerIndex]){
21934 t.dom.style.display = 'none';
21936 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21937 t.addClassOnOver('x-form-trigger-over');
21938 t.addClassOnClick('x-form-trigger-click');
21940 this.triggers = ts.elements;
21943 onTrigger1Click : Roo.emptyFn,
21944 onTrigger2Click : Roo.emptyFn
21947 * Ext JS Library 1.1.1
21948 * Copyright(c) 2006-2007, Ext JS, LLC.
21950 * Originally Released Under LGPL - original licence link has changed is not relivant.
21953 * <script type="text/javascript">
21957 * @class Roo.form.TextArea
21958 * @extends Roo.form.TextField
21959 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21960 * support for auto-sizing.
21962 * Creates a new TextArea
21963 * @param {Object} config Configuration options
21965 Roo.form.TextArea = function(config){
21966 Roo.form.TextArea.superclass.constructor.call(this, config);
21967 // these are provided exchanges for backwards compat
21968 // minHeight/maxHeight were replaced by growMin/growMax to be
21969 // compatible with TextField growing config values
21970 if(this.minHeight !== undefined){
21971 this.growMin = this.minHeight;
21973 if(this.maxHeight !== undefined){
21974 this.growMax = this.maxHeight;
21978 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
21980 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
21984 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
21988 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
21989 * in the field (equivalent to setting overflow: hidden, defaults to false)
21991 preventScrollbars: false,
21993 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21994 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
21998 onRender : function(ct, position){
22000 this.defaultAutoCreate = {
22002 style:"width:300px;height:60px;",
22003 autocomplete: "off"
22006 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22008 this.textSizeEl = Roo.DomHelper.append(document.body, {
22009 tag: "pre", cls: "x-form-grow-sizer"
22011 if(this.preventScrollbars){
22012 this.el.setStyle("overflow", "hidden");
22014 this.el.setHeight(this.growMin);
22018 onDestroy : function(){
22019 if(this.textSizeEl){
22020 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22022 Roo.form.TextArea.superclass.onDestroy.call(this);
22026 onKeyUp : function(e){
22027 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22033 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22034 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22036 autoSize : function(){
22037 if(!this.grow || !this.textSizeEl){
22041 var v = el.dom.value;
22042 var ts = this.textSizeEl;
22045 ts.appendChild(document.createTextNode(v));
22048 Roo.fly(ts).setWidth(this.el.getWidth());
22050 v = "  ";
22053 v = v.replace(/\n/g, '<p> </p>');
22055 v += " \n ";
22058 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22059 if(h != this.lastHeight){
22060 this.lastHeight = h;
22061 this.el.setHeight(h);
22062 this.fireEvent("autosize", this, h);
22067 * Ext JS Library 1.1.1
22068 * Copyright(c) 2006-2007, Ext JS, LLC.
22070 * Originally Released Under LGPL - original licence link has changed is not relivant.
22073 * <script type="text/javascript">
22078 * @class Roo.form.NumberField
22079 * @extends Roo.form.TextField
22080 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22082 * Creates a new NumberField
22083 * @param {Object} config Configuration options
22085 Roo.form.NumberField = function(config){
22086 Roo.form.NumberField.superclass.constructor.call(this, config);
22089 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22091 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22093 fieldClass: "x-form-field x-form-num-field",
22095 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22097 allowDecimals : true,
22099 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22101 decimalSeparator : ".",
22103 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22105 decimalPrecision : 2,
22107 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22109 allowNegative : true,
22111 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22113 minValue : Number.NEGATIVE_INFINITY,
22115 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22117 maxValue : Number.MAX_VALUE,
22119 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22121 minText : "The minimum value for this field is {0}",
22123 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22125 maxText : "The maximum value for this field is {0}",
22127 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22128 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22130 nanText : "{0} is not a valid number",
22133 initEvents : function(){
22134 Roo.form.NumberField.superclass.initEvents.call(this);
22135 var allowed = "0123456789";
22136 if(this.allowDecimals){
22137 allowed += this.decimalSeparator;
22139 if(this.allowNegative){
22142 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22143 var keyPress = function(e){
22144 var k = e.getKey();
22145 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22148 var c = e.getCharCode();
22149 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22153 this.el.on("keypress", keyPress, this);
22157 validateValue : function(value){
22158 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22161 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22164 var num = this.parseValue(value);
22166 this.markInvalid(String.format(this.nanText, value));
22169 if(num < this.minValue){
22170 this.markInvalid(String.format(this.minText, this.minValue));
22173 if(num > this.maxValue){
22174 this.markInvalid(String.format(this.maxText, this.maxValue));
22180 getValue : function(){
22181 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22185 parseValue : function(value){
22186 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22187 return isNaN(value) ? '' : value;
22191 fixPrecision : function(value){
22192 var nan = isNaN(value);
22193 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22194 return nan ? '' : value;
22196 return parseFloat(value).toFixed(this.decimalPrecision);
22199 setValue : function(v){
22200 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22204 decimalPrecisionFcn : function(v){
22205 return Math.floor(v);
22208 beforeBlur : function(){
22209 var v = this.parseValue(this.getRawValue());
22211 this.setValue(this.fixPrecision(v));
22216 * Ext JS Library 1.1.1
22217 * Copyright(c) 2006-2007, Ext JS, LLC.
22219 * Originally Released Under LGPL - original licence link has changed is not relivant.
22222 * <script type="text/javascript">
22226 * @class Roo.form.DateField
22227 * @extends Roo.form.TriggerField
22228 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22230 * Create a new DateField
22231 * @param {Object} config
22233 Roo.form.DateField = function(config){
22234 Roo.form.DateField.superclass.constructor.call(this, config);
22240 * Fires when a date is selected
22241 * @param {Roo.form.DateField} combo This combo box
22242 * @param {Date} date The date selected
22249 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22250 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22251 this.ddMatch = null;
22252 if(this.disabledDates){
22253 var dd = this.disabledDates;
22255 for(var i = 0; i < dd.length; i++){
22257 if(i != dd.length-1) re += "|";
22259 this.ddMatch = new RegExp(re + ")");
22263 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22265 * @cfg {String} format
22266 * The default date format string which can be overriden for localization support. The format must be
22267 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22271 * @cfg {String} altFormats
22272 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22273 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22275 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22277 * @cfg {Array} disabledDays
22278 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22280 disabledDays : null,
22282 * @cfg {String} disabledDaysText
22283 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22285 disabledDaysText : "Disabled",
22287 * @cfg {Array} disabledDates
22288 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22289 * expression so they are very powerful. Some examples:
22291 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22292 * <li>["03/08", "09/16"] would disable those days for every year</li>
22293 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22294 * <li>["03/../2006"] would disable every day in March 2006</li>
22295 * <li>["^03"] would disable every day in every March</li>
22297 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22298 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22300 disabledDates : null,
22302 * @cfg {String} disabledDatesText
22303 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22305 disabledDatesText : "Disabled",
22307 * @cfg {Date/String} minValue
22308 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22309 * valid format (defaults to null).
22313 * @cfg {Date/String} maxValue
22314 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22315 * valid format (defaults to null).
22319 * @cfg {String} minText
22320 * The error text to display when the date in the cell is before minValue (defaults to
22321 * 'The date in this field must be after {minValue}').
22323 minText : "The date in this field must be equal to or after {0}",
22325 * @cfg {String} maxText
22326 * The error text to display when the date in the cell is after maxValue (defaults to
22327 * 'The date in this field must be before {maxValue}').
22329 maxText : "The date in this field must be equal to or before {0}",
22331 * @cfg {String} invalidText
22332 * The error text to display when the date in the field is invalid (defaults to
22333 * '{value} is not a valid date - it must be in the format {format}').
22335 invalidText : "{0} is not a valid date - it must be in the format {1}",
22337 * @cfg {String} triggerClass
22338 * An additional CSS class used to style the trigger button. The trigger will always get the
22339 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22340 * which displays a calendar icon).
22342 triggerClass : 'x-form-date-trigger',
22346 * @cfg {bool} useIso
22347 * if enabled, then the date field will use a hidden field to store the
22348 * real value as iso formated date. default (false)
22352 * @cfg {String/Object} autoCreate
22353 * A DomHelper element spec, or true for a default element spec (defaults to
22354 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22357 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22360 hiddenField: false,
22362 onRender : function(ct, position)
22364 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22366 this.el.dom.removeAttribute('name');
22367 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22369 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22370 // prevent input submission
22371 this.hiddenName = this.name;
22378 validateValue : function(value)
22380 value = this.formatDate(value);
22381 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22384 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22387 var svalue = value;
22388 value = this.parseDate(value);
22390 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22393 var time = value.getTime();
22394 if(this.minValue && time < this.minValue.getTime()){
22395 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22398 if(this.maxValue && time > this.maxValue.getTime()){
22399 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22402 if(this.disabledDays){
22403 var day = value.getDay();
22404 for(var i = 0; i < this.disabledDays.length; i++) {
22405 if(day === this.disabledDays[i]){
22406 this.markInvalid(this.disabledDaysText);
22411 var fvalue = this.formatDate(value);
22412 if(this.ddMatch && this.ddMatch.test(fvalue)){
22413 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22420 // Provides logic to override the default TriggerField.validateBlur which just returns true
22421 validateBlur : function(){
22422 return !this.menu || !this.menu.isVisible();
22426 * Returns the current date value of the date field.
22427 * @return {Date} The date value
22429 getValue : function(){
22431 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22435 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22436 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22437 * (the default format used is "m/d/y").
22440 //All of these calls set the same date value (May 4, 2006)
22442 //Pass a date object:
22443 var dt = new Date('5/4/06');
22444 dateField.setValue(dt);
22446 //Pass a date string (default format):
22447 dateField.setValue('5/4/06');
22449 //Pass a date string (custom format):
22450 dateField.format = 'Y-m-d';
22451 dateField.setValue('2006-5-4');
22453 * @param {String/Date} date The date or valid date string
22455 setValue : function(date){
22456 if (this.hiddenField) {
22457 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22459 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22463 parseDate : function(value){
22464 if(!value || value instanceof Date){
22467 var v = Date.parseDate(value, this.format);
22468 if(!v && this.altFormats){
22469 if(!this.altFormatsArray){
22470 this.altFormatsArray = this.altFormats.split("|");
22472 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22473 v = Date.parseDate(value, this.altFormatsArray[i]);
22480 formatDate : function(date, fmt){
22481 return (!date || !(date instanceof Date)) ?
22482 date : date.dateFormat(fmt || this.format);
22487 select: function(m, d){
22489 this.fireEvent('select', this, d);
22491 show : function(){ // retain focus styling
22495 this.focus.defer(10, this);
22496 var ml = this.menuListeners;
22497 this.menu.un("select", ml.select, this);
22498 this.menu.un("show", ml.show, this);
22499 this.menu.un("hide", ml.hide, this);
22504 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22505 onTriggerClick : function(){
22509 if(this.menu == null){
22510 this.menu = new Roo.menu.DateMenu();
22512 Roo.apply(this.menu.picker, {
22513 showClear: this.allowBlank,
22514 minDate : this.minValue,
22515 maxDate : this.maxValue,
22516 disabledDatesRE : this.ddMatch,
22517 disabledDatesText : this.disabledDatesText,
22518 disabledDays : this.disabledDays,
22519 disabledDaysText : this.disabledDaysText,
22520 format : this.format,
22521 minText : String.format(this.minText, this.formatDate(this.minValue)),
22522 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22524 this.menu.on(Roo.apply({}, this.menuListeners, {
22527 this.menu.picker.setValue(this.getValue() || new Date());
22528 this.menu.show(this.el, "tl-bl?");
22531 beforeBlur : function(){
22532 var v = this.parseDate(this.getRawValue());
22538 /** @cfg {Boolean} grow @hide */
22539 /** @cfg {Number} growMin @hide */
22540 /** @cfg {Number} growMax @hide */
22547 * Ext JS Library 1.1.1
22548 * Copyright(c) 2006-2007, Ext JS, LLC.
22550 * Originally Released Under LGPL - original licence link has changed is not relivant.
22553 * <script type="text/javascript">
22558 * @class Roo.form.ComboBox
22559 * @extends Roo.form.TriggerField
22560 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22562 * Create a new ComboBox.
22563 * @param {Object} config Configuration options
22565 Roo.form.ComboBox = function(config){
22566 Roo.form.ComboBox.superclass.constructor.call(this, config);
22570 * Fires when the dropdown list is expanded
22571 * @param {Roo.form.ComboBox} combo This combo box
22576 * Fires when the dropdown list is collapsed
22577 * @param {Roo.form.ComboBox} combo This combo box
22581 * @event beforeselect
22582 * Fires before a list item is selected. Return false to cancel the selection.
22583 * @param {Roo.form.ComboBox} combo This combo box
22584 * @param {Roo.data.Record} record The data record returned from the underlying store
22585 * @param {Number} index The index of the selected item in the dropdown list
22587 'beforeselect' : true,
22590 * Fires when a list item is selected
22591 * @param {Roo.form.ComboBox} combo This combo box
22592 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22593 * @param {Number} index The index of the selected item in the dropdown list
22597 * @event beforequery
22598 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22599 * The event object passed has these properties:
22600 * @param {Roo.form.ComboBox} combo This combo box
22601 * @param {String} query The query
22602 * @param {Boolean} forceAll true to force "all" query
22603 * @param {Boolean} cancel true to cancel the query
22604 * @param {Object} e The query event object
22606 'beforequery': true,
22609 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22610 * @param {Roo.form.ComboBox} combo This combo box
22615 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22616 * @param {Roo.form.ComboBox} combo This combo box
22617 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22623 if(this.transform){
22624 this.allowDomMove = false;
22625 var s = Roo.getDom(this.transform);
22626 if(!this.hiddenName){
22627 this.hiddenName = s.name;
22630 this.mode = 'local';
22631 var d = [], opts = s.options;
22632 for(var i = 0, len = opts.length;i < len; i++){
22634 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22636 this.value = value;
22638 d.push([value, o.text]);
22640 this.store = new Roo.data.SimpleStore({
22642 fields: ['value', 'text'],
22645 this.valueField = 'value';
22646 this.displayField = 'text';
22648 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22649 if(!this.lazyRender){
22650 this.target = true;
22651 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22652 s.parentNode.removeChild(s); // remove it
22653 this.render(this.el.parentNode);
22655 s.parentNode.removeChild(s); // remove it
22660 this.store = Roo.factory(this.store, Roo.data);
22663 this.selectedIndex = -1;
22664 if(this.mode == 'local'){
22665 if(config.queryDelay === undefined){
22666 this.queryDelay = 10;
22668 if(config.minChars === undefined){
22674 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22676 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22679 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22680 * rendering into an Roo.Editor, defaults to false)
22683 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22684 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22687 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22690 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22691 * the dropdown list (defaults to undefined, with no header element)
22695 * @cfg {String/Roo.Template} tpl The template to use to render the output
22699 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22701 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22703 listWidth: undefined,
22705 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22706 * mode = 'remote' or 'text' if mode = 'local')
22708 displayField: undefined,
22710 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22711 * mode = 'remote' or 'value' if mode = 'local').
22712 * Note: use of a valueField requires the user make a selection
22713 * in order for a value to be mapped.
22715 valueField: undefined,
22717 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22718 * field's data value (defaults to the underlying DOM element's name)
22720 hiddenName: undefined,
22722 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22726 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22728 selectedClass: 'x-combo-selected',
22730 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22731 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22732 * which displays a downward arrow icon).
22734 triggerClass : 'x-form-arrow-trigger',
22736 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22740 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22741 * anchor positions (defaults to 'tl-bl')
22743 listAlign: 'tl-bl?',
22745 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22749 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22750 * query specified by the allQuery config option (defaults to 'query')
22752 triggerAction: 'query',
22754 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22755 * (defaults to 4, does not apply if editable = false)
22759 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22760 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22764 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22765 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22769 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22770 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22774 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22775 * when editable = true (defaults to false)
22777 selectOnFocus:false,
22779 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22781 queryParam: 'query',
22783 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22784 * when mode = 'remote' (defaults to 'Loading...')
22786 loadingText: 'Loading...',
22788 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22792 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22796 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22797 * traditional select (defaults to true)
22801 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22805 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22809 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22810 * listWidth has a higher value)
22814 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22815 * allow the user to set arbitrary text into the field (defaults to false)
22817 forceSelection:false,
22819 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22820 * if typeAhead = true (defaults to 250)
22822 typeAheadDelay : 250,
22824 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22825 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22827 valueNotFoundText : undefined,
22829 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22831 blockFocus : false,
22834 * @cfg {Boolean} disableClear Disable showing of clear button.
22836 disableClear : false,
22838 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22840 alwaysQuery : false,
22848 onRender : function(ct, position){
22849 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22850 if(this.hiddenName){
22851 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22853 this.hiddenField.value =
22854 this.hiddenValue !== undefined ? this.hiddenValue :
22855 this.value !== undefined ? this.value : '';
22857 // prevent input submission
22858 this.el.dom.removeAttribute('name');
22861 this.el.dom.setAttribute('autocomplete', 'off');
22864 var cls = 'x-combo-list';
22866 this.list = new Roo.Layer({
22867 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22870 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22871 this.list.setWidth(lw);
22872 this.list.swallowEvent('mousewheel');
22873 this.assetHeight = 0;
22876 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22877 this.assetHeight += this.header.getHeight();
22880 this.innerList = this.list.createChild({cls:cls+'-inner'});
22881 this.innerList.on('mouseover', this.onViewOver, this);
22882 this.innerList.on('mousemove', this.onViewMove, this);
22883 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22885 if(this.allowBlank && !this.pageSize && !this.disableClear){
22886 this.footer = this.list.createChild({cls:cls+'-ft'});
22887 this.pageTb = new Roo.Toolbar(this.footer);
22891 this.footer = this.list.createChild({cls:cls+'-ft'});
22892 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22893 {pageSize: this.pageSize});
22897 if (this.pageTb && this.allowBlank && !this.disableClear) {
22899 this.pageTb.add(new Roo.Toolbar.Fill(), {
22900 cls: 'x-btn-icon x-btn-clear',
22902 handler: function()
22905 _this.clearValue();
22906 _this.onSelect(false, -1);
22911 this.assetHeight += this.footer.getHeight();
22916 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22919 this.view = new Roo.View(this.innerList, this.tpl, {
22920 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22923 this.view.on('click', this.onViewClick, this);
22925 this.store.on('beforeload', this.onBeforeLoad, this);
22926 this.store.on('load', this.onLoad, this);
22927 this.store.on('loadexception', this.collapse, this);
22929 if(this.resizable){
22930 this.resizer = new Roo.Resizable(this.list, {
22931 pinned:true, handles:'se'
22933 this.resizer.on('resize', function(r, w, h){
22934 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22935 this.listWidth = w;
22936 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22937 this.restrictHeight();
22939 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22941 if(!this.editable){
22942 this.editable = true;
22943 this.setEditable(false);
22947 if (typeof(this.events.add.listeners) != 'undefined') {
22949 this.addicon = this.wrap.createChild(
22950 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22952 this.addicon.on('click', function(e) {
22953 this.fireEvent('add', this);
22956 if (typeof(this.events.edit.listeners) != 'undefined') {
22958 this.editicon = this.wrap.createChild(
22959 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22960 if (this.addicon) {
22961 this.editicon.setStyle('margin-left', '40px');
22963 this.editicon.on('click', function(e) {
22965 // we fire even if inothing is selected..
22966 this.fireEvent('edit', this, this.lastData );
22976 initEvents : function(){
22977 Roo.form.ComboBox.superclass.initEvents.call(this);
22979 this.keyNav = new Roo.KeyNav(this.el, {
22980 "up" : function(e){
22981 this.inKeyMode = true;
22985 "down" : function(e){
22986 if(!this.isExpanded()){
22987 this.onTriggerClick();
22989 this.inKeyMode = true;
22994 "enter" : function(e){
22995 this.onViewClick();
22999 "esc" : function(e){
23003 "tab" : function(e){
23004 this.onViewClick(false);
23010 doRelay : function(foo, bar, hname){
23011 if(hname == 'down' || this.scope.isExpanded()){
23012 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23019 this.queryDelay = Math.max(this.queryDelay || 10,
23020 this.mode == 'local' ? 10 : 250);
23021 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23022 if(this.typeAhead){
23023 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23025 if(this.editable !== false){
23026 this.el.on("keyup", this.onKeyUp, this);
23028 if(this.forceSelection){
23029 this.on('blur', this.doForce, this);
23033 onDestroy : function(){
23035 this.view.setStore(null);
23036 this.view.el.removeAllListeners();
23037 this.view.el.remove();
23038 this.view.purgeListeners();
23041 this.list.destroy();
23044 this.store.un('beforeload', this.onBeforeLoad, this);
23045 this.store.un('load', this.onLoad, this);
23046 this.store.un('loadexception', this.collapse, this);
23048 Roo.form.ComboBox.superclass.onDestroy.call(this);
23052 fireKey : function(e){
23053 if(e.isNavKeyPress() && !this.list.isVisible()){
23054 this.fireEvent("specialkey", this, e);
23059 onResize: function(w, h){
23060 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23062 if(typeof w != 'number'){
23063 // we do not handle it!?!?
23066 var tw = this.trigger.getWidth();
23067 tw += this.addicon ? this.addicon.getWidth() : 0;
23068 tw += this.editicon ? this.editicon.getWidth() : 0;
23070 this.el.setWidth( this.adjustWidth('input', x));
23072 this.trigger.setStyle('left', x+'px');
23074 if(this.list && this.listWidth === undefined){
23075 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23076 this.list.setWidth(lw);
23077 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23085 * Allow or prevent the user from directly editing the field text. If false is passed,
23086 * the user will only be able to select from the items defined in the dropdown list. This method
23087 * is the runtime equivalent of setting the 'editable' config option at config time.
23088 * @param {Boolean} value True to allow the user to directly edit the field text
23090 setEditable : function(value){
23091 if(value == this.editable){
23094 this.editable = value;
23096 this.el.dom.setAttribute('readOnly', true);
23097 this.el.on('mousedown', this.onTriggerClick, this);
23098 this.el.addClass('x-combo-noedit');
23100 this.el.dom.setAttribute('readOnly', false);
23101 this.el.un('mousedown', this.onTriggerClick, this);
23102 this.el.removeClass('x-combo-noedit');
23107 onBeforeLoad : function(){
23108 if(!this.hasFocus){
23111 this.innerList.update(this.loadingText ?
23112 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23113 this.restrictHeight();
23114 this.selectedIndex = -1;
23118 onLoad : function(){
23119 if(!this.hasFocus){
23122 if(this.store.getCount() > 0){
23124 this.restrictHeight();
23125 if(this.lastQuery == this.allQuery){
23127 this.el.dom.select();
23129 if(!this.selectByValue(this.value, true)){
23130 this.select(0, true);
23134 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23135 this.taTask.delay(this.typeAheadDelay);
23139 this.onEmptyResults();
23145 onTypeAhead : function(){
23146 if(this.store.getCount() > 0){
23147 var r = this.store.getAt(0);
23148 var newValue = r.data[this.displayField];
23149 var len = newValue.length;
23150 var selStart = this.getRawValue().length;
23151 if(selStart != len){
23152 this.setRawValue(newValue);
23153 this.selectText(selStart, newValue.length);
23159 onSelect : function(record, index){
23160 if(this.fireEvent('beforeselect', this, record, index) !== false){
23161 this.setFromData(index > -1 ? record.data : false);
23163 this.fireEvent('select', this, record, index);
23168 * Returns the currently selected field value or empty string if no value is set.
23169 * @return {String} value The selected value
23171 getValue : function(){
23172 if(this.valueField){
23173 return typeof this.value != 'undefined' ? this.value : '';
23175 return Roo.form.ComboBox.superclass.getValue.call(this);
23180 * Clears any text/value currently set in the field
23182 clearValue : function(){
23183 if(this.hiddenField){
23184 this.hiddenField.value = '';
23187 this.setRawValue('');
23188 this.lastSelectionText = '';
23189 this.applyEmptyText();
23193 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23194 * will be displayed in the field. If the value does not match the data value of an existing item,
23195 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23196 * Otherwise the field will be blank (although the value will still be set).
23197 * @param {String} value The value to match
23199 setValue : function(v){
23201 if(this.valueField){
23202 var r = this.findRecord(this.valueField, v);
23204 text = r.data[this.displayField];
23205 }else if(this.valueNotFoundText !== undefined){
23206 text = this.valueNotFoundText;
23209 this.lastSelectionText = text;
23210 if(this.hiddenField){
23211 this.hiddenField.value = v;
23213 Roo.form.ComboBox.superclass.setValue.call(this, text);
23217 * @property {Object} the last set data for the element
23222 * Sets the value of the field based on a object which is related to the record format for the store.
23223 * @param {Object} value the value to set as. or false on reset?
23225 setFromData : function(o){
23226 var dv = ''; // display value
23227 var vv = ''; // value value..
23229 if (this.displayField) {
23230 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23232 // this is an error condition!!!
23233 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23236 if(this.valueField){
23237 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23239 if(this.hiddenField){
23240 this.hiddenField.value = vv;
23242 this.lastSelectionText = dv;
23243 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23247 // no hidden field.. - we store the value in 'value', but still display
23248 // display field!!!!
23249 this.lastSelectionText = dv;
23250 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23256 reset : function(){
23257 // overridden so that last data is reset..
23258 this.setValue(this.originalValue);
23259 this.clearInvalid();
23260 this.lastData = false;
23263 findRecord : function(prop, value){
23265 if(this.store.getCount() > 0){
23266 this.store.each(function(r){
23267 if(r.data[prop] == value){
23277 onViewMove : function(e, t){
23278 this.inKeyMode = false;
23282 onViewOver : function(e, t){
23283 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23286 var item = this.view.findItemFromChild(t);
23288 var index = this.view.indexOf(item);
23289 this.select(index, false);
23294 onViewClick : function(doFocus){
23295 var index = this.view.getSelectedIndexes()[0];
23296 var r = this.store.getAt(index);
23298 this.onSelect(r, index);
23300 if(doFocus !== false && !this.blockFocus){
23306 restrictHeight : function(){
23307 this.innerList.dom.style.height = '';
23308 var inner = this.innerList.dom;
23309 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23310 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23311 this.list.beginUpdate();
23312 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23313 this.list.alignTo(this.el, this.listAlign);
23314 this.list.endUpdate();
23318 onEmptyResults : function(){
23323 * Returns true if the dropdown list is expanded, else false.
23325 isExpanded : function(){
23326 return this.list.isVisible();
23330 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23331 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23332 * @param {String} value The data value of the item to select
23333 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23334 * selected item if it is not currently in view (defaults to true)
23335 * @return {Boolean} True if the value matched an item in the list, else false
23337 selectByValue : function(v, scrollIntoView){
23338 if(v !== undefined && v !== null){
23339 var r = this.findRecord(this.valueField || this.displayField, v);
23341 this.select(this.store.indexOf(r), scrollIntoView);
23349 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23350 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23351 * @param {Number} index The zero-based index of the list item to select
23352 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23353 * selected item if it is not currently in view (defaults to true)
23355 select : function(index, scrollIntoView){
23356 this.selectedIndex = index;
23357 this.view.select(index);
23358 if(scrollIntoView !== false){
23359 var el = this.view.getNode(index);
23361 this.innerList.scrollChildIntoView(el, false);
23367 selectNext : function(){
23368 var ct = this.store.getCount();
23370 if(this.selectedIndex == -1){
23372 }else if(this.selectedIndex < ct-1){
23373 this.select(this.selectedIndex+1);
23379 selectPrev : function(){
23380 var ct = this.store.getCount();
23382 if(this.selectedIndex == -1){
23384 }else if(this.selectedIndex != 0){
23385 this.select(this.selectedIndex-1);
23391 onKeyUp : function(e){
23392 if(this.editable !== false && !e.isSpecialKey()){
23393 this.lastKey = e.getKey();
23394 this.dqTask.delay(this.queryDelay);
23399 validateBlur : function(){
23400 return !this.list || !this.list.isVisible();
23404 initQuery : function(){
23405 this.doQuery(this.getRawValue());
23409 doForce : function(){
23410 if(this.el.dom.value.length > 0){
23411 this.el.dom.value =
23412 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23413 this.applyEmptyText();
23418 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23419 * query allowing the query action to be canceled if needed.
23420 * @param {String} query The SQL query to execute
23421 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23422 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23423 * saved in the current store (defaults to false)
23425 doQuery : function(q, forceAll){
23426 if(q === undefined || q === null){
23431 forceAll: forceAll,
23435 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23439 forceAll = qe.forceAll;
23440 if(forceAll === true || (q.length >= this.minChars)){
23441 if(this.lastQuery != q || this.alwaysQuery){
23442 this.lastQuery = q;
23443 if(this.mode == 'local'){
23444 this.selectedIndex = -1;
23446 this.store.clearFilter();
23448 this.store.filter(this.displayField, q);
23452 this.store.baseParams[this.queryParam] = q;
23454 params: this.getParams(q)
23459 this.selectedIndex = -1;
23466 getParams : function(q){
23468 //p[this.queryParam] = q;
23471 p.limit = this.pageSize;
23477 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23479 collapse : function(){
23480 if(!this.isExpanded()){
23484 Roo.get(document).un('mousedown', this.collapseIf, this);
23485 Roo.get(document).un('mousewheel', this.collapseIf, this);
23486 if (!this.editable) {
23487 Roo.get(document).un('keydown', this.listKeyPress, this);
23489 this.fireEvent('collapse', this);
23493 collapseIf : function(e){
23494 if(!e.within(this.wrap) && !e.within(this.list)){
23500 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23502 expand : function(){
23503 if(this.isExpanded() || !this.hasFocus){
23506 this.list.alignTo(this.el, this.listAlign);
23508 Roo.get(document).on('mousedown', this.collapseIf, this);
23509 Roo.get(document).on('mousewheel', this.collapseIf, this);
23510 if (!this.editable) {
23511 Roo.get(document).on('keydown', this.listKeyPress, this);
23514 this.fireEvent('expand', this);
23518 // Implements the default empty TriggerField.onTriggerClick function
23519 onTriggerClick : function(){
23523 if(this.isExpanded()){
23525 if (!this.blockFocus) {
23530 this.hasFocus = true;
23531 if(this.triggerAction == 'all') {
23532 this.doQuery(this.allQuery, true);
23534 this.doQuery(this.getRawValue());
23536 if (!this.blockFocus) {
23541 listKeyPress : function(e)
23543 //Roo.log('listkeypress');
23544 // scroll to first matching element based on key pres..
23545 if (e.isSpecialKey()) {
23548 var k = String.fromCharCode(e.getKey()).toUpperCase();
23551 var csel = this.view.getSelectedNodes();
23552 var cselitem = false;
23554 var ix = this.view.indexOf(csel[0]);
23555 cselitem = this.store.getAt(ix);
23556 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23562 this.store.each(function(v) {
23564 // start at existing selection.
23565 if (cselitem.id == v.id) {
23571 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23572 match = this.store.indexOf(v);
23577 if (match === false) {
23578 return true; // no more action?
23581 this.view.select(match);
23582 var sn = Roo.get(this.view.getSelectedNodes()[0])
23583 sn.scrollIntoView(sn.dom.parentNode, false);
23587 * @cfg {Boolean} grow
23591 * @cfg {Number} growMin
23595 * @cfg {Number} growMax
23604 * Ext JS Library 1.1.1
23605 * Copyright(c) 2006-2007, Ext JS, LLC.
23607 * Originally Released Under LGPL - original licence link has changed is not relivant.
23610 * <script type="text/javascript">
23613 * @class Roo.form.Checkbox
23614 * @extends Roo.form.Field
23615 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23617 * Creates a new Checkbox
23618 * @param {Object} config Configuration options
23620 Roo.form.Checkbox = function(config){
23621 Roo.form.Checkbox.superclass.constructor.call(this, config);
23625 * Fires when the checkbox is checked or unchecked.
23626 * @param {Roo.form.Checkbox} this This checkbox
23627 * @param {Boolean} checked The new checked value
23633 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23635 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23637 focusClass : undefined,
23639 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23641 fieldClass: "x-form-field",
23643 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23647 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23648 * {tag: "input", type: "checkbox", autocomplete: "off"})
23650 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23652 * @cfg {String} boxLabel The text that appears beside the checkbox
23656 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23660 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23662 valueOff: '0', // value when not checked..
23664 actionMode : 'viewEl',
23667 itemCls : 'x-menu-check-item x-form-item',
23668 groupClass : 'x-menu-group-item',
23669 inputType : 'hidden',
23672 inSetChecked: false, // check that we are not calling self...
23674 inputElement: false, // real input element?
23675 basedOn: false, // ????
23677 isFormField: true, // not sure where this is needed!!!!
23679 onResize : function(){
23680 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23681 if(!this.boxLabel){
23682 this.el.alignTo(this.wrap, 'c-c');
23686 initEvents : function(){
23687 Roo.form.Checkbox.superclass.initEvents.call(this);
23688 this.el.on("click", this.onClick, this);
23689 this.el.on("change", this.onClick, this);
23693 getResizeEl : function(){
23697 getPositionEl : function(){
23702 onRender : function(ct, position){
23703 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23705 if(this.inputValue !== undefined){
23706 this.el.dom.value = this.inputValue;
23709 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23710 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23711 var viewEl = this.wrap.createChild({
23712 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23713 this.viewEl = viewEl;
23714 this.wrap.on('click', this.onClick, this);
23716 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23717 this.el.on('propertychange', this.setFromHidden, this); //ie
23722 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23723 // viewEl.on('click', this.onClick, this);
23725 //if(this.checked){
23726 this.setChecked(this.checked);
23728 //this.checked = this.el.dom;
23734 initValue : Roo.emptyFn,
23737 * Returns the checked state of the checkbox.
23738 * @return {Boolean} True if checked, else false
23740 getValue : function(){
23742 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23744 return this.valueOff;
23749 onClick : function(){
23750 this.setChecked(!this.checked);
23752 //if(this.el.dom.checked != this.checked){
23753 // this.setValue(this.el.dom.checked);
23758 * Sets the checked state of the checkbox.
23759 * On is always based on a string comparison between inputValue and the param.
23760 * @param {Boolean/String} value - the value to set
23761 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23763 setValue : function(v,suppressEvent){
23766 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23767 //if(this.el && this.el.dom){
23768 // this.el.dom.checked = this.checked;
23769 // this.el.dom.defaultChecked = this.checked;
23771 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23772 //this.fireEvent("check", this, this.checked);
23775 setChecked : function(state,suppressEvent)
23777 if (this.inSetChecked) {
23778 this.checked = state;
23784 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23786 this.checked = state;
23787 if(suppressEvent !== true){
23788 this.fireEvent('check', this, state);
23790 this.inSetChecked = true;
23791 this.el.dom.value = state ? this.inputValue : this.valueOff;
23792 this.inSetChecked = false;
23795 // handle setting of hidden value by some other method!!?!?
23796 setFromHidden: function()
23801 //console.log("SET FROM HIDDEN");
23802 //alert('setFrom hidden');
23803 this.setValue(this.el.dom.value);
23806 onDestroy : function()
23809 Roo.get(this.viewEl).remove();
23812 Roo.form.Checkbox.superclass.onDestroy.call(this);
23817 * Ext JS Library 1.1.1
23818 * Copyright(c) 2006-2007, Ext JS, LLC.
23820 * Originally Released Under LGPL - original licence link has changed is not relivant.
23823 * <script type="text/javascript">
23827 * @class Roo.form.Radio
23828 * @extends Roo.form.Checkbox
23829 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23830 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23832 * Creates a new Radio
23833 * @param {Object} config Configuration options
23835 Roo.form.Radio = function(){
23836 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23838 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23839 inputType: 'radio',
23842 * If this radio is part of a group, it will return the selected value
23845 getGroupValue : function(){
23846 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23848 });//<script type="text/javascript">
23851 * Ext JS Library 1.1.1
23852 * Copyright(c) 2006-2007, Ext JS, LLC.
23853 * licensing@extjs.com
23855 * http://www.extjs.com/license
23861 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23862 * - IE ? - no idea how much works there.
23870 * @class Ext.form.HtmlEditor
23871 * @extends Ext.form.Field
23872 * Provides a lightweight HTML Editor component.
23873 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23875 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23876 * supported by this editor.</b><br/><br/>
23877 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23878 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23880 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23882 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23886 * @cfg {String} createLinkText The default text for the create link prompt
23888 createLinkText : 'Please enter the URL for the link:',
23890 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23892 defaultLinkValue : 'http:/'+'/',
23898 // private properties
23899 validationEvent : false,
23901 initialized : false,
23903 sourceEditMode : false,
23904 onFocus : Roo.emptyFn,
23906 hideMode:'offsets',
23907 defaultAutoCreate : {
23909 style:"width:500px;height:300px;",
23910 autocomplete: "off"
23914 initComponent : function(){
23917 * @event initialize
23918 * Fires when the editor is fully initialized (including the iframe)
23919 * @param {HtmlEditor} this
23924 * Fires when the editor is first receives the focus. Any insertion must wait
23925 * until after this event.
23926 * @param {HtmlEditor} this
23930 * @event beforesync
23931 * Fires before the textarea is updated with content from the editor iframe. Return false
23932 * to cancel the sync.
23933 * @param {HtmlEditor} this
23934 * @param {String} html
23938 * @event beforepush
23939 * Fires before the iframe editor is updated with content from the textarea. Return false
23940 * to cancel the push.
23941 * @param {HtmlEditor} this
23942 * @param {String} html
23947 * Fires when the textarea is updated with content from the editor iframe.
23948 * @param {HtmlEditor} this
23949 * @param {String} html
23954 * Fires when the iframe editor is updated with content from the textarea.
23955 * @param {HtmlEditor} this
23956 * @param {String} html
23960 * @event editmodechange
23961 * Fires when the editor switches edit modes
23962 * @param {HtmlEditor} this
23963 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23965 editmodechange: true,
23967 * @event editorevent
23968 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23969 * @param {HtmlEditor} this
23976 * Protected method that will not generally be called directly. It
23977 * is called when the editor creates its toolbar. Override this method if you need to
23978 * add custom toolbar buttons.
23979 * @param {HtmlEditor} editor
23981 createToolbar : function(editor){
23982 if (!editor.toolbars || !editor.toolbars.length) {
23983 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
23986 for (var i =0 ; i < editor.toolbars.length;i++) {
23987 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
23988 editor.toolbars[i].init(editor);
23995 * Protected method that will not generally be called directly. It
23996 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23997 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23999 getDocMarkup : function(){
24000 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
24004 onRender : function(ct, position){
24005 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24006 this.el.dom.style.border = '0 none';
24007 this.el.dom.setAttribute('tabIndex', -1);
24008 this.el.addClass('x-hidden');
24009 if(Roo.isIE){ // fix IE 1px bogus margin
24010 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24012 this.wrap = this.el.wrap({
24013 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24016 this.frameId = Roo.id();
24017 this.createToolbar(this);
24024 var iframe = this.wrap.createChild({
24027 name: this.frameId,
24028 frameBorder : 'no',
24029 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24032 // console.log(iframe);
24033 //this.wrap.dom.appendChild(iframe);
24035 this.iframe = iframe.dom;
24037 this.assignDocWin();
24039 this.doc.designMode = 'on';
24042 this.doc.write(this.getDocMarkup());
24046 var task = { // must defer to wait for browser to be ready
24048 //console.log("run task?" + this.doc.readyState);
24049 this.assignDocWin();
24050 if(this.doc.body || this.doc.readyState == 'complete'){
24052 this.doc.designMode="on";
24056 Roo.TaskMgr.stop(task);
24057 this.initEditor.defer(10, this);
24064 Roo.TaskMgr.start(task);
24067 this.setSize(this.el.getSize());
24072 onResize : function(w, h){
24073 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24074 if(this.el && this.iframe){
24075 if(typeof w == 'number'){
24076 var aw = w - this.wrap.getFrameWidth('lr');
24077 this.el.setWidth(this.adjustWidth('textarea', aw));
24078 this.iframe.style.width = aw + 'px';
24080 if(typeof h == 'number'){
24082 for (var i =0; i < this.toolbars.length;i++) {
24083 // fixme - ask toolbars for heights?
24084 tbh += this.toolbars[i].tb.el.getHeight();
24090 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24091 this.el.setHeight(this.adjustWidth('textarea', ah));
24092 this.iframe.style.height = ah + 'px';
24094 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24101 * Toggles the editor between standard and source edit mode.
24102 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24104 toggleSourceEdit : function(sourceEditMode){
24106 this.sourceEditMode = sourceEditMode === true;
24108 if(this.sourceEditMode){
24111 this.iframe.className = 'x-hidden';
24112 this.el.removeClass('x-hidden');
24113 this.el.dom.removeAttribute('tabIndex');
24118 this.iframe.className = '';
24119 this.el.addClass('x-hidden');
24120 this.el.dom.setAttribute('tabIndex', -1);
24123 this.setSize(this.wrap.getSize());
24124 this.fireEvent('editmodechange', this, this.sourceEditMode);
24127 // private used internally
24128 createLink : function(){
24129 var url = prompt(this.createLinkText, this.defaultLinkValue);
24130 if(url && url != 'http:/'+'/'){
24131 this.relayCmd('createlink', url);
24135 // private (for BoxComponent)
24136 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24138 // private (for BoxComponent)
24139 getResizeEl : function(){
24143 // private (for BoxComponent)
24144 getPositionEl : function(){
24149 initEvents : function(){
24150 this.originalValue = this.getValue();
24154 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24157 markInvalid : Roo.emptyFn,
24159 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24162 clearInvalid : Roo.emptyFn,
24164 setValue : function(v){
24165 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24170 * Protected method that will not generally be called directly. If you need/want
24171 * custom HTML cleanup, this is the method you should override.
24172 * @param {String} html The HTML to be cleaned
24173 * return {String} The cleaned HTML
24175 cleanHtml : function(html){
24176 html = String(html);
24177 if(html.length > 5){
24178 if(Roo.isSafari){ // strip safari nonsense
24179 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24182 if(html == ' '){
24189 * Protected method that will not generally be called directly. Syncs the contents
24190 * of the editor iframe with the textarea.
24192 syncValue : function(){
24193 if(this.initialized){
24194 var bd = (this.doc.body || this.doc.documentElement);
24195 var html = bd.innerHTML;
24197 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24198 var m = bs.match(/text-align:(.*?);/i);
24200 html = '<div style="'+m[0]+'">' + html + '</div>';
24203 html = this.cleanHtml(html);
24204 if(this.fireEvent('beforesync', this, html) !== false){
24205 this.el.dom.value = html;
24206 this.fireEvent('sync', this, html);
24212 * Protected method that will not generally be called directly. Pushes the value of the textarea
24213 * into the iframe editor.
24215 pushValue : function(){
24216 if(this.initialized){
24217 var v = this.el.dom.value;
24221 if(this.fireEvent('beforepush', this, v) !== false){
24222 (this.doc.body || this.doc.documentElement).innerHTML = v;
24223 this.fireEvent('push', this, v);
24229 deferFocus : function(){
24230 this.focus.defer(10, this);
24234 focus : function(){
24235 if(this.win && !this.sourceEditMode){
24242 assignDocWin: function()
24244 var iframe = this.iframe;
24247 this.doc = iframe.contentWindow.document;
24248 this.win = iframe.contentWindow;
24250 if (!Roo.get(this.frameId)) {
24253 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24254 this.win = Roo.get(this.frameId).dom.contentWindow;
24259 initEditor : function(){
24260 //console.log("INIT EDITOR");
24261 this.assignDocWin();
24265 this.doc.designMode="on";
24267 this.doc.write(this.getDocMarkup());
24270 var dbody = (this.doc.body || this.doc.documentElement);
24271 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24272 // this copies styles from the containing element into thsi one..
24273 // not sure why we need all of this..
24274 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24275 ss['background-attachment'] = 'fixed'; // w3c
24276 dbody.bgProperties = 'fixed'; // ie
24277 Roo.DomHelper.applyStyles(dbody, ss);
24278 Roo.EventManager.on(this.doc, {
24279 'mousedown': this.onEditorEvent,
24280 'dblclick': this.onEditorEvent,
24281 'click': this.onEditorEvent,
24282 'keyup': this.onEditorEvent,
24287 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24289 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24290 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24292 this.initialized = true;
24294 this.fireEvent('initialize', this);
24299 onDestroy : function(){
24305 for (var i =0; i < this.toolbars.length;i++) {
24306 // fixme - ask toolbars for heights?
24307 this.toolbars[i].onDestroy();
24310 this.wrap.dom.innerHTML = '';
24311 this.wrap.remove();
24316 onFirstFocus : function(){
24318 this.assignDocWin();
24321 this.activated = true;
24322 for (var i =0; i < this.toolbars.length;i++) {
24323 this.toolbars[i].onFirstFocus();
24326 if(Roo.isGecko){ // prevent silly gecko errors
24328 var s = this.win.getSelection();
24329 if(!s.focusNode || s.focusNode.nodeType != 3){
24330 var r = s.getRangeAt(0);
24331 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24336 this.execCmd('useCSS', true);
24337 this.execCmd('styleWithCSS', false);
24340 this.fireEvent('activate', this);
24344 adjustFont: function(btn){
24345 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24346 //if(Roo.isSafari){ // safari
24349 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24350 if(Roo.isSafari){ // safari
24351 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24352 v = (v < 10) ? 10 : v;
24353 v = (v > 48) ? 48 : v;
24354 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24359 v = Math.max(1, v+adjust);
24361 this.execCmd('FontSize', v );
24364 onEditorEvent : function(e){
24365 this.fireEvent('editorevent', this, e);
24366 // this.updateToolbar();
24370 insertTag : function(tg)
24372 // could be a bit smarter... -> wrap the current selected tRoo..
24374 this.execCmd("formatblock", tg);
24378 insertText : function(txt)
24382 range = this.createRange();
24383 range.deleteContents();
24384 //alert(Sender.getAttribute('label'));
24386 range.insertNode(this.doc.createTextNode(txt));
24390 relayBtnCmd : function(btn){
24391 this.relayCmd(btn.cmd);
24395 * Executes a Midas editor command on the editor document and performs necessary focus and
24396 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24397 * @param {String} cmd The Midas command
24398 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24400 relayCmd : function(cmd, value){
24402 this.execCmd(cmd, value);
24403 this.fireEvent('editorevent', this);
24404 //this.updateToolbar();
24409 * Executes a Midas editor command directly on the editor document.
24410 * For visual commands, you should use {@link #relayCmd} instead.
24411 * <b>This should only be called after the editor is initialized.</b>
24412 * @param {String} cmd The Midas command
24413 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24415 execCmd : function(cmd, value){
24416 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24422 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24424 * @param {String} text
24426 insertAtCursor : function(text){
24427 if(!this.activated){
24432 var r = this.doc.selection.createRange();
24439 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24441 this.execCmd('InsertHTML', text);
24446 mozKeyPress : function(e){
24448 var c = e.getCharCode(), cmd;
24451 c = String.fromCharCode(c).toLowerCase();
24462 this.cleanUpPaste.defer(100, this);
24470 e.preventDefault();
24478 fixKeys : function(){ // load time branching for fastest keydown performance
24480 return function(e){
24481 var k = e.getKey(), r;
24484 r = this.doc.selection.createRange();
24487 r.pasteHTML('    ');
24494 r = this.doc.selection.createRange();
24496 var target = r.parentElement();
24497 if(!target || target.tagName.toLowerCase() != 'li'){
24499 r.pasteHTML('<br />');
24505 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24506 this.cleanUpPaste.defer(100, this);
24512 }else if(Roo.isOpera){
24513 return function(e){
24514 var k = e.getKey();
24518 this.execCmd('InsertHTML','    ');
24521 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24522 this.cleanUpPaste.defer(100, this);
24527 }else if(Roo.isSafari){
24528 return function(e){
24529 var k = e.getKey();
24533 this.execCmd('InsertText','\t');
24537 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24538 this.cleanUpPaste.defer(100, this);
24546 getAllAncestors: function()
24548 var p = this.getSelectedNode();
24551 a.push(p); // push blank onto stack..
24552 p = this.getParentElement();
24556 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24560 a.push(this.doc.body);
24564 lastSelNode : false,
24567 getSelection : function()
24569 this.assignDocWin();
24570 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24573 getSelectedNode: function()
24575 // this may only work on Gecko!!!
24577 // should we cache this!!!!
24582 var range = this.createRange(this.getSelection());
24585 var parent = range.parentElement();
24587 var testRange = range.duplicate();
24588 testRange.moveToElementText(parent);
24589 if (testRange.inRange(range)) {
24592 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24595 parent = parent.parentElement;
24601 var ar = range.endContainer.childNodes;
24603 ar = range.commonAncestorContainer.childNodes;
24604 //alert(ar.length);
24607 var other_nodes = [];
24608 var has_other_nodes = false;
24609 for (var i=0;i<ar.length;i++) {
24610 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24613 // fullly contained node.
24615 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24620 // probably selected..
24621 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24622 other_nodes.push(ar[i]);
24625 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24630 has_other_nodes = true;
24632 if (!nodes.length && other_nodes.length) {
24633 nodes= other_nodes;
24635 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24641 createRange: function(sel)
24643 // this has strange effects when using with
24644 // top toolbar - not sure if it's a great idea.
24645 //this.editor.contentWindow.focus();
24646 if (typeof sel != "undefined") {
24648 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24650 return this.doc.createRange();
24653 return this.doc.createRange();
24656 getParentElement: function()
24659 this.assignDocWin();
24660 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24662 var range = this.createRange(sel);
24665 var p = range.commonAncestorContainer;
24666 while (p.nodeType == 3) { // text node
24678 // BC Hacks - cause I cant work out what i was trying to do..
24679 rangeIntersectsNode : function(range, node)
24681 var nodeRange = node.ownerDocument.createRange();
24683 nodeRange.selectNode(node);
24686 nodeRange.selectNodeContents(node);
24689 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24690 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24692 rangeCompareNode : function(range, node) {
24693 var nodeRange = node.ownerDocument.createRange();
24695 nodeRange.selectNode(node);
24697 nodeRange.selectNodeContents(node);
24699 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24700 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24702 if (nodeIsBefore && !nodeIsAfter)
24704 if (!nodeIsBefore && nodeIsAfter)
24706 if (nodeIsBefore && nodeIsAfter)
24712 // private? - in a new class?
24713 cleanUpPaste : function()
24715 // cleans up the whole document..
24716 // console.log('cleanuppaste');
24717 this.cleanUpChildren(this.doc.body)
24721 cleanUpChildren : function (n)
24723 if (!n.childNodes.length) {
24726 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24727 this.cleanUpChild(n.childNodes[i]);
24734 cleanUpChild : function (node)
24736 //console.log(node);
24737 if (node.nodeName == "#text") {
24738 // clean up silly Windows -- stuff?
24741 if (node.nodeName == "#comment") {
24742 node.parentNode.removeChild(node);
24743 // clean up silly Windows -- stuff?
24747 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24749 node.parentNode.removeChild(node);
24753 if (!node.attributes || !node.attributes.length) {
24754 this.cleanUpChildren(node);
24758 function cleanAttr(n,v)
24761 if (v.match(/^\./) || v.match(/^\//)) {
24764 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24767 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24768 node.removeAttribute(n);
24772 function cleanStyle(n,v)
24774 if (v.match(/expression/)) { //XSS?? should we even bother..
24775 node.removeAttribute(n);
24780 var parts = v.split(/;/);
24781 Roo.each(parts, function(p) {
24782 p = p.replace(/\s+/g,'');
24786 var l = p.split(':').shift().replace(/\s+/g,'');
24788 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24789 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24790 node.removeAttribute(n);
24799 for (var i = node.attributes.length-1; i > -1 ; i--) {
24800 var a = node.attributes[i];
24802 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24803 node.removeAttribute(a.name);
24806 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24807 cleanAttr(a.name,a.value); // fixme..
24810 if (a.name == 'style') {
24811 cleanStyle(a.name,a.value);
24813 /// clean up MS crap..
24814 if (a.name == 'class') {
24815 if (a.value.match(/^Mso/)) {
24816 node.className = '';
24826 this.cleanUpChildren(node);
24832 // hide stuff that is not compatible
24846 * @event specialkey
24850 * @cfg {String} fieldClass @hide
24853 * @cfg {String} focusClass @hide
24856 * @cfg {String} autoCreate @hide
24859 * @cfg {String} inputType @hide
24862 * @cfg {String} invalidClass @hide
24865 * @cfg {String} invalidText @hide
24868 * @cfg {String} msgFx @hide
24871 * @cfg {String} validateOnBlur @hide
24875 Roo.form.HtmlEditor.white = [
24876 'area', 'br', 'img', 'input', 'hr', 'wbr',
24878 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24879 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24880 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24881 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24882 'table', 'ul', 'xmp',
24884 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24887 'dir', 'menu', 'ol', 'ul', 'dl',
24893 Roo.form.HtmlEditor.black = [
24894 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24896 'base', 'basefont', 'bgsound', 'blink', 'body',
24897 'frame', 'frameset', 'head', 'html', 'ilayer',
24898 'iframe', 'layer', 'link', 'meta', 'object',
24899 'script', 'style' ,'title', 'xml' // clean later..
24901 Roo.form.HtmlEditor.clean = [
24902 'script', 'style', 'title', 'xml'
24907 Roo.form.HtmlEditor.ablack = [
24911 Roo.form.HtmlEditor.aclean = [
24912 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24916 Roo.form.HtmlEditor.pwhite= [
24917 'http', 'https', 'mailto'
24920 Roo.form.HtmlEditor.cwhite= [
24925 // <script type="text/javascript">
24928 * Ext JS Library 1.1.1
24929 * Copyright(c) 2006-2007, Ext JS, LLC.
24935 * @class Roo.form.HtmlEditorToolbar1
24940 new Roo.form.HtmlEditor({
24943 new Roo.form.HtmlEditorToolbar1({
24944 disable : { fonts: 1 , format: 1, ..., ... , ...],
24950 * @cfg {Object} disable List of elements to disable..
24951 * @cfg {Array} btns List of additional buttons.
24955 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24958 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24961 Roo.apply(this, config);
24962 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24963 // dont call parent... till later.
24966 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
24974 * @cfg {Object} disable List of toolbar elements to disable
24979 * @cfg {Array} fontFamilies An array of available font families
24997 // "á" , ?? a acute?
25002 "°" // , // degrees
25004 // "é" , // e ecute
25005 // "ú" , // u ecute?
25008 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25009 "input:submit", "input:button", "select", "textarea", "label" ],
25012 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25014 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25017 * @cfg {String} defaultFont default font to use.
25019 defaultFont: 'tahoma',
25021 fontSelect : false,
25024 formatCombo : false,
25026 init : function(editor)
25028 this.editor = editor;
25031 var fid = editor.frameId;
25033 function btn(id, toggle, handler){
25034 var xid = fid + '-'+ id ;
25038 cls : 'x-btn-icon x-edit-'+id,
25039 enableToggle:toggle !== false,
25040 scope: editor, // was editor...
25041 handler:handler||editor.relayBtnCmd,
25042 clickEvent:'mousedown',
25043 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25050 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25052 // stop form submits
25053 tb.el.on('click', function(e){
25054 e.preventDefault(); // what does this do?
25057 if(!this.disable.font && !Roo.isSafari){
25058 /* why no safari for fonts
25059 editor.fontSelect = tb.el.createChild({
25062 cls:'x-font-select',
25063 html: editor.createFontOptions()
25065 editor.fontSelect.on('change', function(){
25066 var font = editor.fontSelect.dom.value;
25067 editor.relayCmd('fontname', font);
25068 editor.deferFocus();
25071 editor.fontSelect.dom,
25076 if(!this.disable.formats){
25077 this.formatCombo = new Roo.form.ComboBox({
25078 store: new Roo.data.SimpleStore({
25081 data : this.formats // from states.js
25084 //autoCreate : {tag: "div", size: "20"},
25085 displayField:'tag',
25089 triggerAction: 'all',
25090 emptyText:'Add tag',
25091 selectOnFocus:true,
25094 'select': function(c, r, i) {
25095 editor.insertTag(r.get('tag'));
25101 tb.addField(this.formatCombo);
25105 if(!this.disable.format){
25112 if(!this.disable.fontSize){
25117 btn('increasefontsize', false, editor.adjustFont),
25118 btn('decreasefontsize', false, editor.adjustFont)
25123 if(this.disable.colors){
25126 id:editor.frameId +'-forecolor',
25127 cls:'x-btn-icon x-edit-forecolor',
25128 clickEvent:'mousedown',
25129 tooltip: this.buttonTips['forecolor'] || undefined,
25131 menu : new Roo.menu.ColorMenu({
25132 allowReselect: true,
25133 focus: Roo.emptyFn,
25136 selectHandler: function(cp, color){
25137 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25138 editor.deferFocus();
25141 clickEvent:'mousedown'
25144 id:editor.frameId +'backcolor',
25145 cls:'x-btn-icon x-edit-backcolor',
25146 clickEvent:'mousedown',
25147 tooltip: this.buttonTips['backcolor'] || undefined,
25149 menu : new Roo.menu.ColorMenu({
25150 focus: Roo.emptyFn,
25153 allowReselect: true,
25154 selectHandler: function(cp, color){
25156 editor.execCmd('useCSS', false);
25157 editor.execCmd('hilitecolor', color);
25158 editor.execCmd('useCSS', true);
25159 editor.deferFocus();
25161 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25162 Roo.isSafari || Roo.isIE ? '#'+color : color);
25163 editor.deferFocus();
25167 clickEvent:'mousedown'
25172 // now add all the items...
25175 if(!this.disable.alignments){
25178 btn('justifyleft'),
25179 btn('justifycenter'),
25180 btn('justifyright')
25184 //if(!Roo.isSafari){
25185 if(!this.disable.links){
25188 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25192 if(!this.disable.lists){
25195 btn('insertorderedlist'),
25196 btn('insertunorderedlist')
25199 if(!this.disable.sourceEdit){
25202 btn('sourceedit', true, function(btn){
25203 this.toggleSourceEdit(btn.pressed);
25210 // special menu.. - needs to be tidied up..
25211 if (!this.disable.special) {
25214 cls: 'x-edit-none',
25219 for (var i =0; i < this.specialChars.length; i++) {
25220 smenu.menu.items.push({
25222 html: this.specialChars[i],
25223 handler: function(a,b) {
25224 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25237 for(var i =0; i< this.btns.length;i++) {
25238 var b = this.btns[i];
25239 b.cls = 'x-edit-none';
25248 // disable everything...
25250 this.tb.items.each(function(item){
25251 if(item.id != editor.frameId+ '-sourceedit'){
25255 this.rendered = true;
25257 // the all the btns;
25258 editor.on('editorevent', this.updateToolbar, this);
25259 // other toolbars need to implement this..
25260 //editor.on('editmodechange', this.updateToolbar, this);
25266 * Protected method that will not generally be called directly. It triggers
25267 * a toolbar update by reading the markup state of the current selection in the editor.
25269 updateToolbar: function(){
25271 if(!this.editor.activated){
25272 this.editor.onFirstFocus();
25276 var btns = this.tb.items.map,
25277 doc = this.editor.doc,
25278 frameId = this.editor.frameId;
25280 if(!this.disable.font && !Roo.isSafari){
25282 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25283 if(name != this.fontSelect.dom.value){
25284 this.fontSelect.dom.value = name;
25288 if(!this.disable.format){
25289 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25290 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25291 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25293 if(!this.disable.alignments){
25294 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25295 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25296 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25298 if(!Roo.isSafari && !this.disable.lists){
25299 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25300 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25303 var ans = this.editor.getAllAncestors();
25304 if (this.formatCombo) {
25307 var store = this.formatCombo.store;
25308 this.formatCombo.setValue("");
25309 for (var i =0; i < ans.length;i++) {
25310 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25312 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25320 // hides menus... - so this cant be on a menu...
25321 Roo.menu.MenuMgr.hideAll();
25323 //this.editorsyncValue();
25327 createFontOptions : function(){
25328 var buf = [], fs = this.fontFamilies, ff, lc;
25329 for(var i = 0, len = fs.length; i< len; i++){
25331 lc = ff.toLowerCase();
25333 '<option value="',lc,'" style="font-family:',ff,';"',
25334 (this.defaultFont == lc ? ' selected="true">' : '>'),
25339 return buf.join('');
25342 toggleSourceEdit : function(sourceEditMode){
25343 if(sourceEditMode === undefined){
25344 sourceEditMode = !this.sourceEditMode;
25346 this.sourceEditMode = sourceEditMode === true;
25347 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25348 // just toggle the button?
25349 if(btn.pressed !== this.editor.sourceEditMode){
25350 btn.toggle(this.editor.sourceEditMode);
25354 if(this.sourceEditMode){
25355 this.tb.items.each(function(item){
25356 if(item.cmd != 'sourceedit'){
25362 if(this.initialized){
25363 this.tb.items.each(function(item){
25369 // tell the editor that it's been pressed..
25370 this.editor.toggleSourceEdit(sourceEditMode);
25374 * Object collection of toolbar tooltips for the buttons in the editor. The key
25375 * is the command id associated with that button and the value is a valid QuickTips object.
25380 title: 'Bold (Ctrl+B)',
25381 text: 'Make the selected text bold.',
25382 cls: 'x-html-editor-tip'
25385 title: 'Italic (Ctrl+I)',
25386 text: 'Make the selected text italic.',
25387 cls: 'x-html-editor-tip'
25395 title: 'Bold (Ctrl+B)',
25396 text: 'Make the selected text bold.',
25397 cls: 'x-html-editor-tip'
25400 title: 'Italic (Ctrl+I)',
25401 text: 'Make the selected text italic.',
25402 cls: 'x-html-editor-tip'
25405 title: 'Underline (Ctrl+U)',
25406 text: 'Underline the selected text.',
25407 cls: 'x-html-editor-tip'
25409 increasefontsize : {
25410 title: 'Grow Text',
25411 text: 'Increase the font size.',
25412 cls: 'x-html-editor-tip'
25414 decreasefontsize : {
25415 title: 'Shrink Text',
25416 text: 'Decrease the font size.',
25417 cls: 'x-html-editor-tip'
25420 title: 'Text Highlight Color',
25421 text: 'Change the background color of the selected text.',
25422 cls: 'x-html-editor-tip'
25425 title: 'Font Color',
25426 text: 'Change the color of the selected text.',
25427 cls: 'x-html-editor-tip'
25430 title: 'Align Text Left',
25431 text: 'Align text to the left.',
25432 cls: 'x-html-editor-tip'
25435 title: 'Center Text',
25436 text: 'Center text in the editor.',
25437 cls: 'x-html-editor-tip'
25440 title: 'Align Text Right',
25441 text: 'Align text to the right.',
25442 cls: 'x-html-editor-tip'
25444 insertunorderedlist : {
25445 title: 'Bullet List',
25446 text: 'Start a bulleted list.',
25447 cls: 'x-html-editor-tip'
25449 insertorderedlist : {
25450 title: 'Numbered List',
25451 text: 'Start a numbered list.',
25452 cls: 'x-html-editor-tip'
25455 title: 'Hyperlink',
25456 text: 'Make the selected text a hyperlink.',
25457 cls: 'x-html-editor-tip'
25460 title: 'Source Edit',
25461 text: 'Switch to source editing mode.',
25462 cls: 'x-html-editor-tip'
25466 onDestroy : function(){
25469 this.tb.items.each(function(item){
25471 item.menu.removeAll();
25473 item.menu.el.destroy();
25481 onFirstFocus: function() {
25482 this.tb.items.each(function(item){
25491 // <script type="text/javascript">
25494 * Ext JS Library 1.1.1
25495 * Copyright(c) 2006-2007, Ext JS, LLC.
25502 * @class Roo.form.HtmlEditor.ToolbarContext
25507 new Roo.form.HtmlEditor({
25510 new Roo.form.HtmlEditor.ToolbarStandard(),
25511 new Roo.form.HtmlEditor.ToolbarContext()
25516 * @config : {Object} disable List of elements to disable.. (not done yet.)
25521 Roo.form.HtmlEditor.ToolbarContext = function(config)
25524 Roo.apply(this, config);
25525 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25526 // dont call parent... till later.
25528 Roo.form.HtmlEditor.ToolbarContext.types = {
25540 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25602 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25607 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25671 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25679 * @cfg {Object} disable List of toolbar elements to disable
25688 init : function(editor)
25690 this.editor = editor;
25693 var fid = editor.frameId;
25695 function btn(id, toggle, handler){
25696 var xid = fid + '-'+ id ;
25700 cls : 'x-btn-icon x-edit-'+id,
25701 enableToggle:toggle !== false,
25702 scope: editor, // was editor...
25703 handler:handler||editor.relayBtnCmd,
25704 clickEvent:'mousedown',
25705 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25709 // create a new element.
25710 var wdiv = editor.wrap.createChild({
25712 }, editor.wrap.dom.firstChild.nextSibling, true);
25714 // can we do this more than once??
25716 // stop form submits
25719 // disable everything...
25720 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25721 this.toolbars = {};
25723 for (var i in ty) {
25725 this.toolbars[i] = this.buildToolbar(ty[i],i);
25727 this.tb = this.toolbars.BODY;
25731 this.rendered = true;
25733 // the all the btns;
25734 editor.on('editorevent', this.updateToolbar, this);
25735 // other toolbars need to implement this..
25736 //editor.on('editmodechange', this.updateToolbar, this);
25742 * Protected method that will not generally be called directly. It triggers
25743 * a toolbar update by reading the markup state of the current selection in the editor.
25745 updateToolbar: function(){
25747 if(!this.editor.activated){
25748 this.editor.onFirstFocus();
25753 var ans = this.editor.getAllAncestors();
25756 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25757 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25758 sel = sel ? sel : this.editor.doc.body;
25759 sel = sel.tagName.length ? sel : this.editor.doc.body;
25760 var tn = sel.tagName.toUpperCase();
25761 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25762 tn = sel.tagName.toUpperCase();
25763 if (this.tb.name == tn) {
25764 return; // no change
25767 ///console.log("show: " + tn);
25768 this.tb = this.toolbars[tn];
25770 this.tb.fields.each(function(e) {
25771 e.setValue(sel.getAttribute(e.name));
25773 this.tb.selectedNode = sel;
25776 Roo.menu.MenuMgr.hideAll();
25778 //this.editorsyncValue();
25783 onDestroy : function(){
25786 this.tb.items.each(function(item){
25788 item.menu.removeAll();
25790 item.menu.el.destroy();
25798 onFirstFocus: function() {
25799 // need to do this for all the toolbars..
25800 this.tb.items.each(function(item){
25804 buildToolbar: function(tlist, nm)
25806 var editor = this.editor;
25807 // create a new element.
25808 var wdiv = editor.wrap.createChild({
25810 }, editor.wrap.dom.firstChild.nextSibling, true);
25813 var tb = new Roo.Toolbar(wdiv);
25814 tb.add(nm+ ": ");
25815 for (var i in tlist) {
25816 var item = tlist[i];
25817 tb.add(item.title + ": ");
25822 tb.addField( new Roo.form.ComboBox({
25823 store: new Roo.data.SimpleStore({
25826 data : item.opts // from states.js
25829 displayField:'val',
25833 triggerAction: 'all',
25834 emptyText:'Select',
25835 selectOnFocus:true,
25836 width: item.width ? item.width : 130,
25838 'select': function(c, r, i) {
25839 tb.selectedNode.setAttribute(c.name, r.get('val'));
25850 tb.addField( new Roo.form.TextField({
25853 //allowBlank:false,
25858 tb.addField( new Roo.form.TextField({
25864 'change' : function(f, nv, ov) {
25865 tb.selectedNode.setAttribute(f.name, nv);
25871 tb.el.on('click', function(e){
25872 e.preventDefault(); // what does this do?
25874 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25877 // dont need to disable them... as they will get hidden
25894 * Ext JS Library 1.1.1
25895 * Copyright(c) 2006-2007, Ext JS, LLC.
25897 * Originally Released Under LGPL - original licence link has changed is not relivant.
25900 * <script type="text/javascript">
25904 * @class Roo.form.BasicForm
25905 * @extends Roo.util.Observable
25906 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25908 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25909 * @param {Object} config Configuration options
25911 Roo.form.BasicForm = function(el, config){
25912 this.allItems = [];
25913 this.childForms = [];
25914 Roo.apply(this, config);
25916 * The Roo.form.Field items in this form.
25917 * @type MixedCollection
25921 this.items = new Roo.util.MixedCollection(false, function(o){
25922 return o.id || (o.id = Roo.id());
25926 * @event beforeaction
25927 * Fires before any action is performed. Return false to cancel the action.
25928 * @param {Form} this
25929 * @param {Action} action The action to be performed
25931 beforeaction: true,
25933 * @event actionfailed
25934 * Fires when an action fails.
25935 * @param {Form} this
25936 * @param {Action} action The action that failed
25938 actionfailed : true,
25940 * @event actioncomplete
25941 * Fires when an action is completed.
25942 * @param {Form} this
25943 * @param {Action} action The action that completed
25945 actioncomplete : true
25950 Roo.form.BasicForm.superclass.constructor.call(this);
25953 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25955 * @cfg {String} method
25956 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25959 * @cfg {DataReader} reader
25960 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25961 * This is optional as there is built-in support for processing JSON.
25964 * @cfg {DataReader} errorReader
25965 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
25966 * This is completely optional as there is built-in support for processing JSON.
25969 * @cfg {String} url
25970 * The URL to use for form actions if one isn't supplied in the action options.
25973 * @cfg {Boolean} fileUpload
25974 * Set to true if this form is a file upload.
25977 * @cfg {Object} baseParams
25978 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
25981 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
25986 activeAction : null,
25989 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
25990 * or setValues() data instead of when the form was first created.
25992 trackResetOnLoad : false,
25996 * childForms - used for multi-tab forms
25999 childForms : false,
26002 * allItems - full list of fields.
26008 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26009 * element by passing it or its id or mask the form itself by passing in true.
26012 waitMsgTarget : undefined,
26015 initEl : function(el){
26016 this.el = Roo.get(el);
26017 this.id = this.el.id || Roo.id();
26018 this.el.on('submit', this.onSubmit, this);
26019 this.el.addClass('x-form');
26023 onSubmit : function(e){
26028 * Returns true if client-side validation on the form is successful.
26031 isValid : function(){
26033 this.items.each(function(f){
26042 * Returns true if any fields in this form have changed since their original load.
26045 isDirty : function(){
26047 this.items.each(function(f){
26057 * Performs a predefined action (submit or load) or custom actions you define on this form.
26058 * @param {String} actionName The name of the action type
26059 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26060 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26061 * accept other config options):
26063 Property Type Description
26064 ---------------- --------------- ----------------------------------------------------------------------------------
26065 url String The url for the action (defaults to the form's url)
26066 method String The form method to use (defaults to the form's method, or POST if not defined)
26067 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26068 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26069 validate the form on the client (defaults to false)
26071 * @return {BasicForm} this
26073 doAction : function(action, options){
26074 if(typeof action == 'string'){
26075 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26077 if(this.fireEvent('beforeaction', this, action) !== false){
26078 this.beforeAction(action);
26079 action.run.defer(100, action);
26085 * Shortcut to do a submit action.
26086 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26087 * @return {BasicForm} this
26089 submit : function(options){
26090 this.doAction('submit', options);
26095 * Shortcut to do a load action.
26096 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26097 * @return {BasicForm} this
26099 load : function(options){
26100 this.doAction('load', options);
26105 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26106 * @param {Record} record The record to edit
26107 * @return {BasicForm} this
26109 updateRecord : function(record){
26110 record.beginEdit();
26111 var fs = record.fields;
26112 fs.each(function(f){
26113 var field = this.findField(f.name);
26115 record.set(f.name, field.getValue());
26123 * Loads an Roo.data.Record into this form.
26124 * @param {Record} record The record to load
26125 * @return {BasicForm} this
26127 loadRecord : function(record){
26128 this.setValues(record.data);
26133 beforeAction : function(action){
26134 var o = action.options;
26136 if(this.waitMsgTarget === true){
26137 this.el.mask(o.waitMsg, 'x-mask-loading');
26138 }else if(this.waitMsgTarget){
26139 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26140 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
26142 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
26148 afterAction : function(action, success){
26149 this.activeAction = null;
26150 var o = action.options;
26152 if(this.waitMsgTarget === true){
26154 }else if(this.waitMsgTarget){
26155 this.waitMsgTarget.unmask();
26157 Roo.MessageBox.updateProgress(1);
26158 Roo.MessageBox.hide();
26165 Roo.callback(o.success, o.scope, [this, action]);
26166 this.fireEvent('actioncomplete', this, action);
26168 Roo.callback(o.failure, o.scope, [this, action]);
26169 this.fireEvent('actionfailed', this, action);
26174 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26175 * @param {String} id The value to search for
26178 findField : function(id){
26179 var field = this.items.get(id);
26181 this.items.each(function(f){
26182 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26188 return field || null;
26192 * Add a secondary form to this one,
26193 * Used to provide tabbed forms. One form is primary, with hidden values
26194 * which mirror the elements from the other forms.
26196 * @param {Roo.form.Form} form to add.
26199 addForm : function(form)
26202 if (this.childForms.indexOf(form) > -1) {
26206 this.childForms.push(form);
26208 Roo.each(form.allItems, function (fe) {
26210 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26211 if (this.findField(n)) { // already added..
26214 var add = new Roo.form.Hidden({
26217 add.render(this.el);
26224 * Mark fields in this form invalid in bulk.
26225 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26226 * @return {BasicForm} this
26228 markInvalid : function(errors){
26229 if(errors instanceof Array){
26230 for(var i = 0, len = errors.length; i < len; i++){
26231 var fieldError = errors[i];
26232 var f = this.findField(fieldError.id);
26234 f.markInvalid(fieldError.msg);
26240 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26241 field.markInvalid(errors[id]);
26245 Roo.each(this.childForms || [], function (f) {
26246 f.markInvalid(errors);
26253 * Set values for fields in this form in bulk.
26254 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26255 * @return {BasicForm} this
26257 setValues : function(values){
26258 if(values instanceof Array){ // array of objects
26259 for(var i = 0, len = values.length; i < len; i++){
26261 var f = this.findField(v.id);
26263 f.setValue(v.value);
26264 if(this.trackResetOnLoad){
26265 f.originalValue = f.getValue();
26269 }else{ // object hash
26272 if(typeof values[id] != 'function' && (field = this.findField(id))){
26274 if (field.setFromData &&
26275 field.valueField &&
26276 field.displayField &&
26277 // combos' with local stores can
26278 // be queried via setValue()
26279 // to set their value..
26280 (field.store && !field.store.isLocal)
26284 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26285 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26286 field.setFromData(sd);
26289 field.setValue(values[id]);
26293 if(this.trackResetOnLoad){
26294 field.originalValue = field.getValue();
26300 Roo.each(this.childForms || [], function (f) {
26301 f.setValues(values);
26308 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26309 * they are returned as an array.
26310 * @param {Boolean} asString
26313 getValues : function(asString){
26314 if (this.childForms) {
26315 // copy values from the child forms
26316 Roo.each(this.childForms, function (f) {
26317 this.setValues(f.getValues());
26323 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26324 if(asString === true){
26327 return Roo.urlDecode(fs);
26331 * Returns the fields in this form as an object with key/value pairs.
26332 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26335 getFieldValues : function()
26337 if (this.childForms) {
26338 // copy values from the child forms
26339 Roo.each(this.childForms, function (f) {
26340 this.setValues(f.getValues());
26345 this.items.each(function(f){
26346 if (!f.getName()) {
26349 var v = f.getValue();
26350 if ((typeof(v) == 'object') && f.getRawValue) {
26351 v = f.getRawValue() ; // dates..
26353 ret[f.getName()] = v;
26360 * Clears all invalid messages in this form.
26361 * @return {BasicForm} this
26363 clearInvalid : function(){
26364 this.items.each(function(f){
26368 Roo.each(this.childForms || [], function (f) {
26377 * Resets this form.
26378 * @return {BasicForm} this
26380 reset : function(){
26381 this.items.each(function(f){
26385 Roo.each(this.childForms || [], function (f) {
26394 * Add Roo.form components to this form.
26395 * @param {Field} field1
26396 * @param {Field} field2 (optional)
26397 * @param {Field} etc (optional)
26398 * @return {BasicForm} this
26401 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26407 * Removes a field from the items collection (does NOT remove its markup).
26408 * @param {Field} field
26409 * @return {BasicForm} this
26411 remove : function(field){
26412 this.items.remove(field);
26417 * Looks at the fields in this form, checks them for an id attribute,
26418 * and calls applyTo on the existing dom element with that id.
26419 * @return {BasicForm} this
26421 render : function(){
26422 this.items.each(function(f){
26423 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26431 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26432 * @param {Object} values
26433 * @return {BasicForm} this
26435 applyToFields : function(o){
26436 this.items.each(function(f){
26443 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26444 * @param {Object} values
26445 * @return {BasicForm} this
26447 applyIfToFields : function(o){
26448 this.items.each(function(f){
26456 Roo.BasicForm = Roo.form.BasicForm;/*
26458 * Ext JS Library 1.1.1
26459 * Copyright(c) 2006-2007, Ext JS, LLC.
26461 * Originally Released Under LGPL - original licence link has changed is not relivant.
26464 * <script type="text/javascript">
26468 * @class Roo.form.Form
26469 * @extends Roo.form.BasicForm
26470 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26472 * @param {Object} config Configuration options
26474 Roo.form.Form = function(config){
26476 if (config.items) {
26477 xitems = config.items;
26478 delete config.items;
26482 Roo.form.Form.superclass.constructor.call(this, null, config);
26483 this.url = this.url || this.action;
26485 this.root = new Roo.form.Layout(Roo.applyIf({
26489 this.active = this.root;
26491 * Array of all the buttons that have been added to this form via {@link addButton}
26495 this.allItems = [];
26498 * @event clientvalidation
26499 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26500 * @param {Form} this
26501 * @param {Boolean} valid true if the form has passed client-side validation
26503 clientvalidation: true,
26506 * Fires when the form is rendered
26507 * @param {Roo.form.Form} form
26512 if (this.progressUrl) {
26513 // push a hidden field onto the list of fields..
26517 name : 'UPLOAD_IDENTIFIER'
26522 Roo.each(xitems, this.addxtype, this);
26528 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26530 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26533 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26536 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26538 buttonAlign:'center',
26541 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26546 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26547 * This property cascades to child containers if not set.
26552 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26553 * fires a looping event with that state. This is required to bind buttons to the valid
26554 * state using the config value formBind:true on the button.
26556 monitorValid : false,
26559 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26564 * @cfg {String} progressUrl - Url to return progress data
26567 progressUrl : false,
26570 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26571 * fields are added and the column is closed. If no fields are passed the column remains open
26572 * until end() is called.
26573 * @param {Object} config The config to pass to the column
26574 * @param {Field} field1 (optional)
26575 * @param {Field} field2 (optional)
26576 * @param {Field} etc (optional)
26577 * @return Column The column container object
26579 column : function(c){
26580 var col = new Roo.form.Column(c);
26582 if(arguments.length > 1){ // duplicate code required because of Opera
26583 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26590 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26591 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26592 * until end() is called.
26593 * @param {Object} config The config to pass to the fieldset
26594 * @param {Field} field1 (optional)
26595 * @param {Field} field2 (optional)
26596 * @param {Field} etc (optional)
26597 * @return FieldSet The fieldset container object
26599 fieldset : function(c){
26600 var fs = new Roo.form.FieldSet(c);
26602 if(arguments.length > 1){ // duplicate code required because of Opera
26603 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26610 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26611 * fields are added and the container is closed. If no fields are passed the container remains open
26612 * until end() is called.
26613 * @param {Object} config The config to pass to the Layout
26614 * @param {Field} field1 (optional)
26615 * @param {Field} field2 (optional)
26616 * @param {Field} etc (optional)
26617 * @return Layout The container object
26619 container : function(c){
26620 var l = new Roo.form.Layout(c);
26622 if(arguments.length > 1){ // duplicate code required because of Opera
26623 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26630 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26631 * @param {Object} container A Roo.form.Layout or subclass of Layout
26632 * @return {Form} this
26634 start : function(c){
26635 // cascade label info
26636 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26637 this.active.stack.push(c);
26638 c.ownerCt = this.active;
26644 * Closes the current open container
26645 * @return {Form} this
26648 if(this.active == this.root){
26651 this.active = this.active.ownerCt;
26656 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26657 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26658 * as the label of the field.
26659 * @param {Field} field1
26660 * @param {Field} field2 (optional)
26661 * @param {Field} etc. (optional)
26662 * @return {Form} this
26665 this.active.stack.push.apply(this.active.stack, arguments);
26666 this.allItems.push.apply(this.allItems,arguments);
26668 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26669 if(a[i].isFormField){
26674 Roo.form.Form.superclass.add.apply(this, r);
26684 * Find any element that has been added to a form, using it's ID or name
26685 * This can include framesets, columns etc. along with regular fields..
26686 * @param {String} id - id or name to find.
26688 * @return {Element} e - or false if nothing found.
26690 findbyId : function(id)
26696 Ext.each(this.allItems, function(f){
26697 if (f.id == id || f.name == id ){
26708 * Render this form into the passed container. This should only be called once!
26709 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26710 * @return {Form} this
26712 render : function(ct)
26718 var o = this.autoCreate || {
26720 method : this.method || 'POST',
26721 id : this.id || Roo.id()
26723 this.initEl(ct.createChild(o));
26725 this.root.render(this.el);
26729 this.items.each(function(f){
26730 f.render('x-form-el-'+f.id);
26733 if(this.buttons.length > 0){
26734 // tables are required to maintain order and for correct IE layout
26735 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26736 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26737 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26739 var tr = tb.getElementsByTagName('tr')[0];
26740 for(var i = 0, len = this.buttons.length; i < len; i++) {
26741 var b = this.buttons[i];
26742 var td = document.createElement('td');
26743 td.className = 'x-form-btn-td';
26744 b.render(tr.appendChild(td));
26747 if(this.monitorValid){ // initialize after render
26748 this.startMonitoring();
26750 this.fireEvent('rendered', this);
26755 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26756 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26757 * object or a valid Roo.DomHelper element config
26758 * @param {Function} handler The function called when the button is clicked
26759 * @param {Object} scope (optional) The scope of the handler function
26760 * @return {Roo.Button}
26762 addButton : function(config, handler, scope){
26766 minWidth: this.minButtonWidth,
26769 if(typeof config == "string"){
26772 Roo.apply(bc, config);
26774 var btn = new Roo.Button(null, bc);
26775 this.buttons.push(btn);
26780 * Adds a series of form elements (using the xtype property as the factory method.
26781 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26782 * @param {Object} config
26785 addxtype : function()
26787 var ar = Array.prototype.slice.call(arguments, 0);
26789 for(var i = 0; i < ar.length; i++) {
26791 continue; // skip -- if this happends something invalid got sent, we
26792 // should ignore it, as basically that interface element will not show up
26793 // and that should be pretty obvious!!
26796 if (Roo.form[ar[i].xtype]) {
26798 var fe = Roo.factory(ar[i], Roo.form);
26804 fe.store.form = this;
26809 this.allItems.push(fe);
26810 if (fe.items && fe.addxtype) {
26811 fe.addxtype.apply(fe, fe.items);
26821 // console.log('adding ' + ar[i].xtype);
26823 if (ar[i].xtype == 'Button') {
26824 //console.log('adding button');
26825 //console.log(ar[i]);
26826 this.addButton(ar[i]);
26827 this.allItems.push(fe);
26831 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26832 alert('end is not supported on xtype any more, use items');
26834 // //console.log('adding end');
26842 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26843 * option "monitorValid"
26845 startMonitoring : function(){
26848 Roo.TaskMgr.start({
26849 run : this.bindHandler,
26850 interval : this.monitorPoll || 200,
26857 * Stops monitoring of the valid state of this form
26859 stopMonitoring : function(){
26860 this.bound = false;
26864 bindHandler : function(){
26866 return false; // stops binding
26869 this.items.each(function(f){
26870 if(!f.isValid(true)){
26875 for(var i = 0, len = this.buttons.length; i < len; i++){
26876 var btn = this.buttons[i];
26877 if(btn.formBind === true && btn.disabled === valid){
26878 btn.setDisabled(!valid);
26881 this.fireEvent('clientvalidation', this, valid);
26895 Roo.Form = Roo.form.Form;
26898 * Ext JS Library 1.1.1
26899 * Copyright(c) 2006-2007, Ext JS, LLC.
26901 * Originally Released Under LGPL - original licence link has changed is not relivant.
26904 * <script type="text/javascript">
26908 * @class Roo.form.Action
26909 * Internal Class used to handle form actions
26911 * @param {Roo.form.BasicForm} el The form element or its id
26912 * @param {Object} config Configuration options
26916 // define the action interface
26917 Roo.form.Action = function(form, options){
26919 this.options = options || {};
26922 * Client Validation Failed
26925 Roo.form.Action.CLIENT_INVALID = 'client';
26927 * Server Validation Failed
26930 Roo.form.Action.SERVER_INVALID = 'server';
26932 * Connect to Server Failed
26935 Roo.form.Action.CONNECT_FAILURE = 'connect';
26937 * Reading Data from Server Failed
26940 Roo.form.Action.LOAD_FAILURE = 'load';
26942 Roo.form.Action.prototype = {
26944 failureType : undefined,
26945 response : undefined,
26946 result : undefined,
26948 // interface method
26949 run : function(options){
26953 // interface method
26954 success : function(response){
26958 // interface method
26959 handleResponse : function(response){
26963 // default connection failure
26964 failure : function(response){
26965 this.response = response;
26966 this.failureType = Roo.form.Action.CONNECT_FAILURE;
26967 this.form.afterAction(this, false);
26970 processResponse : function(response){
26971 this.response = response;
26972 if(!response.responseText){
26975 this.result = this.handleResponse(response);
26976 return this.result;
26979 // utility functions used internally
26980 getUrl : function(appendParams){
26981 var url = this.options.url || this.form.url || this.form.el.dom.action;
26983 var p = this.getParams();
26985 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
26991 getMethod : function(){
26992 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
26995 getParams : function(){
26996 var bp = this.form.baseParams;
26997 var p = this.options.params;
26999 if(typeof p == "object"){
27000 p = Roo.urlEncode(Roo.applyIf(p, bp));
27001 }else if(typeof p == 'string' && bp){
27002 p += '&' + Roo.urlEncode(bp);
27005 p = Roo.urlEncode(bp);
27010 createCallback : function(){
27012 success: this.success,
27013 failure: this.failure,
27015 timeout: (this.form.timeout*1000),
27016 upload: this.form.fileUpload ? this.success : undefined
27021 Roo.form.Action.Submit = function(form, options){
27022 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27025 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27028 haveProgress : false,
27029 uploadComplete : false,
27031 // uploadProgress indicator.
27032 uploadProgress : function()
27034 if (!this.form.progressUrl) {
27038 if (!this.haveProgress) {
27039 Roo.MessageBox.progress("Uploading", "Uploading");
27041 if (this.uploadComplete) {
27042 Roo.MessageBox.hide();
27046 this.haveProgress = true;
27048 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27050 var c = new Roo.data.Connection();
27052 url : this.form.progressUrl,
27057 success : function(req){
27058 //console.log(data);
27062 rdata = Roo.decode(req.responseText)
27064 Roo.log("Invalid data from server..");
27068 if (!rdata || !rdata.success) {
27072 var data = rdata.data;
27074 if (this.uploadComplete) {
27075 Roo.MessageBox.hide();
27080 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27081 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27084 this.uploadProgress.defer(2000,this);
27087 failure: function(data) {
27088 Roo.log('progress url failed ');
27099 // run get Values on the form, so it syncs any secondary forms.
27100 this.form.getValues();
27102 var o = this.options;
27103 var method = this.getMethod();
27104 var isPost = method == 'POST';
27105 if(o.clientValidation === false || this.form.isValid()){
27107 if (this.form.progressUrl) {
27108 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27109 (new Date() * 1) + '' + Math.random());
27113 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27114 form:this.form.el.dom,
27115 url:this.getUrl(!isPost),
27117 params:isPost ? this.getParams() : null,
27118 isUpload: this.form.fileUpload
27121 this.uploadProgress();
27123 }else if (o.clientValidation !== false){ // client validation failed
27124 this.failureType = Roo.form.Action.CLIENT_INVALID;
27125 this.form.afterAction(this, false);
27129 success : function(response)
27131 this.uploadComplete= true;
27132 if (this.haveProgress) {
27133 Roo.MessageBox.hide();
27136 var result = this.processResponse(response);
27137 if(result === true || result.success){
27138 this.form.afterAction(this, true);
27142 this.form.markInvalid(result.errors);
27143 this.failureType = Roo.form.Action.SERVER_INVALID;
27145 this.form.afterAction(this, false);
27147 failure : function(response)
27149 this.uploadComplete= true;
27150 if (this.haveProgress) {
27151 Roo.MessageBox.hide();
27154 this.response = response;
27155 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27156 this.form.afterAction(this, false);
27159 handleResponse : function(response){
27160 if(this.form.errorReader){
27161 var rs = this.form.errorReader.read(response);
27164 for(var i = 0, len = rs.records.length; i < len; i++) {
27165 var r = rs.records[i];
27166 errors[i] = r.data;
27169 if(errors.length < 1){
27173 success : rs.success,
27179 ret = Roo.decode(response.responseText);
27183 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27193 Roo.form.Action.Load = function(form, options){
27194 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27195 this.reader = this.form.reader;
27198 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27202 Roo.Ajax.request(Roo.apply(
27203 this.createCallback(), {
27204 method:this.getMethod(),
27205 url:this.getUrl(false),
27206 params:this.getParams()
27210 success : function(response){
27211 var result = this.processResponse(response);
27212 if(result === true || !result.success || !result.data){
27213 this.failureType = Roo.form.Action.LOAD_FAILURE;
27214 this.form.afterAction(this, false);
27217 this.form.clearInvalid();
27218 this.form.setValues(result.data);
27219 this.form.afterAction(this, true);
27222 handleResponse : function(response){
27223 if(this.form.reader){
27224 var rs = this.form.reader.read(response);
27225 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27227 success : rs.success,
27231 return Roo.decode(response.responseText);
27235 Roo.form.Action.ACTION_TYPES = {
27236 'load' : Roo.form.Action.Load,
27237 'submit' : Roo.form.Action.Submit
27240 * Ext JS Library 1.1.1
27241 * Copyright(c) 2006-2007, Ext JS, LLC.
27243 * Originally Released Under LGPL - original licence link has changed is not relivant.
27246 * <script type="text/javascript">
27250 * @class Roo.form.Layout
27251 * @extends Roo.Component
27252 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27254 * @param {Object} config Configuration options
27256 Roo.form.Layout = function(config){
27258 if (config.items) {
27259 xitems = config.items;
27260 delete config.items;
27262 Roo.form.Layout.superclass.constructor.call(this, config);
27264 Roo.each(xitems, this.addxtype, this);
27268 Roo.extend(Roo.form.Layout, Roo.Component, {
27270 * @cfg {String/Object} autoCreate
27271 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27274 * @cfg {String/Object/Function} style
27275 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27276 * a function which returns such a specification.
27279 * @cfg {String} labelAlign
27280 * Valid values are "left," "top" and "right" (defaults to "left")
27283 * @cfg {Number} labelWidth
27284 * Fixed width in pixels of all field labels (defaults to undefined)
27287 * @cfg {Boolean} clear
27288 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27292 * @cfg {String} labelSeparator
27293 * The separator to use after field labels (defaults to ':')
27295 labelSeparator : ':',
27297 * @cfg {Boolean} hideLabels
27298 * True to suppress the display of field labels in this layout (defaults to false)
27300 hideLabels : false,
27303 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27308 onRender : function(ct, position){
27309 if(this.el){ // from markup
27310 this.el = Roo.get(this.el);
27311 }else { // generate
27312 var cfg = this.getAutoCreate();
27313 this.el = ct.createChild(cfg, position);
27316 this.el.applyStyles(this.style);
27318 if(this.labelAlign){
27319 this.el.addClass('x-form-label-'+this.labelAlign);
27321 if(this.hideLabels){
27322 this.labelStyle = "display:none";
27323 this.elementStyle = "padding-left:0;";
27325 if(typeof this.labelWidth == 'number'){
27326 this.labelStyle = "width:"+this.labelWidth+"px;";
27327 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27329 if(this.labelAlign == 'top'){
27330 this.labelStyle = "width:auto;";
27331 this.elementStyle = "padding-left:0;";
27334 var stack = this.stack;
27335 var slen = stack.length;
27337 if(!this.fieldTpl){
27338 var t = new Roo.Template(
27339 '<div class="x-form-item {5}">',
27340 '<label for="{0}" style="{2}">{1}{4}</label>',
27341 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27343 '</div><div class="x-form-clear-left"></div>'
27345 t.disableFormats = true;
27347 Roo.form.Layout.prototype.fieldTpl = t;
27349 for(var i = 0; i < slen; i++) {
27350 if(stack[i].isFormField){
27351 this.renderField(stack[i]);
27353 this.renderComponent(stack[i]);
27358 this.el.createChild({cls:'x-form-clear'});
27363 renderField : function(f){
27364 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27367 f.labelStyle||this.labelStyle||'', //2
27368 this.elementStyle||'', //3
27369 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27370 f.itemCls||this.itemCls||'' //5
27371 ], true).getPrevSibling());
27375 renderComponent : function(c){
27376 c.render(c.isLayout ? this.el : this.el.createChild());
27379 * Adds a object form elements (using the xtype property as the factory method.)
27380 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27381 * @param {Object} config
27383 addxtype : function(o)
27385 // create the lement.
27386 o.form = this.form;
27387 var fe = Roo.factory(o, Roo.form);
27388 this.form.allItems.push(fe);
27389 this.stack.push(fe);
27391 if (fe.isFormField) {
27392 this.form.items.add(fe);
27400 * @class Roo.form.Column
27401 * @extends Roo.form.Layout
27402 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27404 * @param {Object} config Configuration options
27406 Roo.form.Column = function(config){
27407 Roo.form.Column.superclass.constructor.call(this, config);
27410 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27412 * @cfg {Number/String} width
27413 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27416 * @cfg {String/Object} autoCreate
27417 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27421 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27424 onRender : function(ct, position){
27425 Roo.form.Column.superclass.onRender.call(this, ct, position);
27427 this.el.setWidth(this.width);
27434 * @class Roo.form.Row
27435 * @extends Roo.form.Layout
27436 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27438 * @param {Object} config Configuration options
27442 Roo.form.Row = function(config){
27443 Roo.form.Row.superclass.constructor.call(this, config);
27446 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27448 * @cfg {Number/String} width
27449 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27452 * @cfg {Number/String} height
27453 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27455 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27459 onRender : function(ct, position){
27460 //console.log('row render');
27462 var t = new Roo.Template(
27463 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27464 '<label for="{0}" style="{2}">{1}{4}</label>',
27465 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27469 t.disableFormats = true;
27471 Roo.form.Layout.prototype.rowTpl = t;
27473 this.fieldTpl = this.rowTpl;
27475 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27476 var labelWidth = 100;
27478 if ((this.labelAlign != 'top')) {
27479 if (typeof this.labelWidth == 'number') {
27480 labelWidth = this.labelWidth
27482 this.padWidth = 20 + labelWidth;
27486 Roo.form.Column.superclass.onRender.call(this, ct, position);
27488 this.el.setWidth(this.width);
27491 this.el.setHeight(this.height);
27496 renderField : function(f){
27497 f.fieldEl = this.fieldTpl.append(this.el, [
27498 f.id, f.fieldLabel,
27499 f.labelStyle||this.labelStyle||'',
27500 this.elementStyle||'',
27501 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27502 f.itemCls||this.itemCls||'',
27503 f.width ? f.width + this.padWidth : 160 + this.padWidth
27510 * @class Roo.form.FieldSet
27511 * @extends Roo.form.Layout
27512 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27514 * @param {Object} config Configuration options
27516 Roo.form.FieldSet = function(config){
27517 Roo.form.FieldSet.superclass.constructor.call(this, config);
27520 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27522 * @cfg {String} legend
27523 * The text to display as the legend for the FieldSet (defaults to '')
27526 * @cfg {String/Object} autoCreate
27527 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27531 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27534 onRender : function(ct, position){
27535 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27537 this.setLegend(this.legend);
27542 setLegend : function(text){
27544 this.el.child('legend').update(text);
27549 * Ext JS Library 1.1.1
27550 * Copyright(c) 2006-2007, Ext JS, LLC.
27552 * Originally Released Under LGPL - original licence link has changed is not relivant.
27555 * <script type="text/javascript">
27558 * @class Roo.form.VTypes
27559 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27562 Roo.form.VTypes = function(){
27563 // closure these in so they are only created once.
27564 var alpha = /^[a-zA-Z_]+$/;
27565 var alphanum = /^[a-zA-Z0-9_]+$/;
27566 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27567 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27569 // All these messages and functions are configurable
27572 * The function used to validate email addresses
27573 * @param {String} value The email address
27575 'email' : function(v){
27576 return email.test(v);
27579 * The error text to display when the email validation function returns false
27582 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27584 * The keystroke filter mask to be applied on email input
27587 'emailMask' : /[a-z0-9_\.\-@]/i,
27590 * The function used to validate URLs
27591 * @param {String} value The URL
27593 'url' : function(v){
27594 return url.test(v);
27597 * The error text to display when the url validation function returns false
27600 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27603 * The function used to validate alpha values
27604 * @param {String} value The value
27606 'alpha' : function(v){
27607 return alpha.test(v);
27610 * The error text to display when the alpha validation function returns false
27613 'alphaText' : 'This field should only contain letters and _',
27615 * The keystroke filter mask to be applied on alpha input
27618 'alphaMask' : /[a-z_]/i,
27621 * The function used to validate alphanumeric values
27622 * @param {String} value The value
27624 'alphanum' : function(v){
27625 return alphanum.test(v);
27628 * The error text to display when the alphanumeric validation function returns false
27631 'alphanumText' : 'This field should only contain letters, numbers and _',
27633 * The keystroke filter mask to be applied on alphanumeric input
27636 'alphanumMask' : /[a-z0-9_]/i
27638 }();//<script type="text/javascript">
27641 * @class Roo.form.FCKeditor
27642 * @extends Roo.form.TextArea
27643 * Wrapper around the FCKEditor http://www.fckeditor.net
27645 * Creates a new FCKeditor
27646 * @param {Object} config Configuration options
27648 Roo.form.FCKeditor = function(config){
27649 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27652 * @event editorinit
27653 * Fired when the editor is initialized - you can add extra handlers here..
27654 * @param {FCKeditor} this
27655 * @param {Object} the FCK object.
27662 Roo.form.FCKeditor.editors = { };
27663 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27665 //defaultAutoCreate : {
27666 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27670 * @cfg {Object} fck options - see fck manual for details.
27675 * @cfg {Object} fck toolbar set (Basic or Default)
27677 toolbarSet : 'Basic',
27679 * @cfg {Object} fck BasePath
27681 basePath : '/fckeditor/',
27689 onRender : function(ct, position)
27692 this.defaultAutoCreate = {
27694 style:"width:300px;height:60px;",
27695 autocomplete: "off"
27698 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27701 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27702 if(this.preventScrollbars){
27703 this.el.setStyle("overflow", "hidden");
27705 this.el.setHeight(this.growMin);
27708 //console.log('onrender' + this.getId() );
27709 Roo.form.FCKeditor.editors[this.getId()] = this;
27712 this.replaceTextarea() ;
27716 getEditor : function() {
27717 return this.fckEditor;
27720 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27721 * @param {Mixed} value The value to set
27725 setValue : function(value)
27727 //console.log('setValue: ' + value);
27729 if(typeof(value) == 'undefined') { // not sure why this is happending...
27732 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27734 //if(!this.el || !this.getEditor()) {
27735 // this.value = value;
27736 //this.setValue.defer(100,this,[value]);
27740 if(!this.getEditor()) {
27744 this.getEditor().SetData(value);
27751 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27752 * @return {Mixed} value The field value
27754 getValue : function()
27757 if (this.frame && this.frame.dom.style.display == 'none') {
27758 return Roo.form.FCKeditor.superclass.getValue.call(this);
27761 if(!this.el || !this.getEditor()) {
27763 // this.getValue.defer(100,this);
27768 var value=this.getEditor().GetData();
27769 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27770 return Roo.form.FCKeditor.superclass.getValue.call(this);
27776 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27777 * @return {Mixed} value The field value
27779 getRawValue : function()
27781 if (this.frame && this.frame.dom.style.display == 'none') {
27782 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27785 if(!this.el || !this.getEditor()) {
27786 //this.getRawValue.defer(100,this);
27793 var value=this.getEditor().GetData();
27794 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27795 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27799 setSize : function(w,h) {
27803 //if (this.frame && this.frame.dom.style.display == 'none') {
27804 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27807 //if(!this.el || !this.getEditor()) {
27808 // this.setSize.defer(100,this, [w,h]);
27814 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27816 this.frame.dom.setAttribute('width', w);
27817 this.frame.dom.setAttribute('height', h);
27818 this.frame.setSize(w,h);
27822 toggleSourceEdit : function(value) {
27826 this.el.dom.style.display = value ? '' : 'none';
27827 this.frame.dom.style.display = value ? 'none' : '';
27832 focus: function(tag)
27834 if (this.frame.dom.style.display == 'none') {
27835 return Roo.form.FCKeditor.superclass.focus.call(this);
27837 if(!this.el || !this.getEditor()) {
27838 this.focus.defer(100,this, [tag]);
27845 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27846 this.getEditor().Focus();
27848 if (!this.getEditor().Selection.GetSelection()) {
27849 this.focus.defer(100,this, [tag]);
27854 var r = this.getEditor().EditorDocument.createRange();
27855 r.setStart(tgs[0],0);
27856 r.setEnd(tgs[0],0);
27857 this.getEditor().Selection.GetSelection().removeAllRanges();
27858 this.getEditor().Selection.GetSelection().addRange(r);
27859 this.getEditor().Focus();
27866 replaceTextarea : function()
27868 if ( document.getElementById( this.getId() + '___Frame' ) )
27870 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27872 // We must check the elements firstly using the Id and then the name.
27873 var oTextarea = document.getElementById( this.getId() );
27875 var colElementsByName = document.getElementsByName( this.getId() ) ;
27877 oTextarea.style.display = 'none' ;
27879 if ( oTextarea.tabIndex ) {
27880 this.TabIndex = oTextarea.tabIndex ;
27883 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27884 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27885 this.frame = Roo.get(this.getId() + '___Frame')
27888 _getConfigHtml : function()
27892 for ( var o in this.fckconfig ) {
27893 sConfig += sConfig.length > 0 ? '&' : '';
27894 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27897 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27901 _getIFrameHtml : function()
27903 var sFile = 'fckeditor.html' ;
27904 /* no idea what this is about..
27907 if ( (/fcksource=true/i).test( window.top.location.search ) )
27908 sFile = 'fckeditor.original.html' ;
27913 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27914 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27917 var html = '<iframe id="' + this.getId() +
27918 '___Frame" src="' + sLink +
27919 '" width="' + this.width +
27920 '" height="' + this.height + '"' +
27921 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27922 ' frameborder="0" scrolling="no"></iframe>' ;
27927 _insertHtmlBefore : function( html, element )
27929 if ( element.insertAdjacentHTML ) {
27931 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27933 var oRange = document.createRange() ;
27934 oRange.setStartBefore( element ) ;
27935 var oFragment = oRange.createContextualFragment( html );
27936 element.parentNode.insertBefore( oFragment, element ) ;
27949 //Roo.reg('fckeditor', Roo.form.FCKeditor);
27951 function FCKeditor_OnComplete(editorInstance){
27952 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
27953 f.fckEditor = editorInstance;
27954 //console.log("loaded");
27955 f.fireEvent('editorinit', f, editorInstance);
27975 //<script type="text/javascript">
27977 * @class Roo.form.GridField
27978 * @extends Roo.form.Field
27979 * Embed a grid (or editable grid into a form)
27982 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
27984 * xgrid.store = Roo.data.Store
27985 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
27986 * xgrid.store.reader = Roo.data.JsonReader
27990 * Creates a new GridField
27991 * @param {Object} config Configuration options
27993 Roo.form.GridField = function(config){
27994 Roo.form.GridField.superclass.constructor.call(this, config);
27998 Roo.extend(Roo.form.GridField, Roo.form.Field, {
28000 * @cfg {Number} width - used to restrict width of grid..
28004 * @cfg {Number} height - used to restrict height of grid..
28008 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28014 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28015 * {tag: "input", type: "checkbox", autocomplete: "off"})
28017 // defaultAutoCreate : { tag: 'div' },
28018 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28020 * @cfg {String} addTitle Text to include for adding a title.
28024 onResize : function(){
28025 Roo.form.Field.superclass.onResize.apply(this, arguments);
28028 initEvents : function(){
28029 // Roo.form.Checkbox.superclass.initEvents.call(this);
28030 // has no events...
28035 getResizeEl : function(){
28039 getPositionEl : function(){
28044 onRender : function(ct, position){
28046 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28047 var style = this.style;
28050 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28051 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28052 this.viewEl = this.wrap.createChild({ tag: 'div' });
28054 this.viewEl.applyStyles(style);
28057 this.viewEl.setWidth(this.width);
28060 this.viewEl.setHeight(this.height);
28062 //if(this.inputValue !== undefined){
28063 //this.setValue(this.value);
28066 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28069 this.grid.render();
28070 this.grid.getDataSource().on('remove', this.refreshValue, this);
28071 this.grid.getDataSource().on('update', this.refreshValue, this);
28072 this.grid.on('afteredit', this.refreshValue, this);
28078 * Sets the value of the item.
28079 * @param {String} either an object or a string..
28081 setValue : function(v){
28083 v = v || []; // empty set..
28084 // this does not seem smart - it really only affects memoryproxy grids..
28085 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28086 var ds = this.grid.getDataSource();
28087 // assumes a json reader..
28089 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28090 ds.loadData( data);
28092 Roo.form.GridField.superclass.setValue.call(this, v);
28093 this.refreshValue();
28094 // should load data in the grid really....
28098 refreshValue: function() {
28100 this.grid.getDataSource().each(function(r) {
28103 this.el.dom.value = Roo.encode(val);
28111 * Ext JS Library 1.1.1
28112 * Copyright(c) 2006-2007, Ext JS, LLC.
28114 * Originally Released Under LGPL - original licence link has changed is not relivant.
28117 * <script type="text/javascript">
28120 * @class Roo.form.DisplayField
28121 * @extends Roo.form.Field
28122 * A generic Field to display non-editable data.
28124 * Creates a new Display Field item.
28125 * @param {Object} config Configuration options
28127 Roo.form.DisplayField = function(config){
28128 Roo.form.DisplayField.superclass.constructor.call(this, config);
28132 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28133 inputType: 'hidden',
28139 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28141 focusClass : undefined,
28143 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28145 fieldClass: 'x-form-field',
28148 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28150 valueRenderer: undefined,
28154 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28155 * {tag: "input", type: "checkbox", autocomplete: "off"})
28158 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28160 onResize : function(){
28161 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28165 initEvents : function(){
28166 // Roo.form.Checkbox.superclass.initEvents.call(this);
28167 // has no events...
28172 getResizeEl : function(){
28176 getPositionEl : function(){
28181 onRender : function(ct, position){
28183 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28184 //if(this.inputValue !== undefined){
28185 this.wrap = this.el.wrap();
28187 this.viewEl = this.wrap.createChild({ tag: 'div'});
28189 if (this.bodyStyle) {
28190 this.viewEl.applyStyles(this.bodyStyle);
28192 //this.viewEl.setStyle('padding', '2px');
28194 this.setValue(this.value);
28199 initValue : Roo.emptyFn,
28204 onClick : function(){
28209 * Sets the checked state of the checkbox.
28210 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28212 setValue : function(v){
28214 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28215 // this might be called before we have a dom element..
28216 if (!this.viewEl) {
28219 this.viewEl.dom.innerHTML = html;
28220 Roo.form.DisplayField.superclass.setValue.call(this, v);
28223 });//<script type="text/javasscript">
28227 * @class Roo.DDView
28228 * A DnD enabled version of Roo.View.
28229 * @param {Element/String} container The Element in which to create the View.
28230 * @param {String} tpl The template string used to create the markup for each element of the View
28231 * @param {Object} config The configuration properties. These include all the config options of
28232 * {@link Roo.View} plus some specific to this class.<br>
28234 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28235 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28237 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28238 .x-view-drag-insert-above {
28239 border-top:1px dotted #3366cc;
28241 .x-view-drag-insert-below {
28242 border-bottom:1px dotted #3366cc;
28248 Roo.DDView = function(container, tpl, config) {
28249 Roo.DDView.superclass.constructor.apply(this, arguments);
28250 this.getEl().setStyle("outline", "0px none");
28251 this.getEl().unselectable();
28252 if (this.dragGroup) {
28253 this.setDraggable(this.dragGroup.split(","));
28255 if (this.dropGroup) {
28256 this.setDroppable(this.dropGroup.split(","));
28258 if (this.deletable) {
28259 this.setDeletable();
28261 this.isDirtyFlag = false;
28267 Roo.extend(Roo.DDView, Roo.View, {
28268 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28269 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28270 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28271 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28275 reset: Roo.emptyFn,
28277 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28279 validate: function() {
28283 destroy: function() {
28284 this.purgeListeners();
28285 this.getEl.removeAllListeners();
28286 this.getEl().remove();
28287 if (this.dragZone) {
28288 if (this.dragZone.destroy) {
28289 this.dragZone.destroy();
28292 if (this.dropZone) {
28293 if (this.dropZone.destroy) {
28294 this.dropZone.destroy();
28299 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28300 getName: function() {
28304 /** Loads the View from a JSON string representing the Records to put into the Store. */
28305 setValue: function(v) {
28307 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28310 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28311 this.store.proxy = new Roo.data.MemoryProxy(data);
28315 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28316 getValue: function() {
28318 this.store.each(function(rec) {
28319 result += rec.id + ',';
28321 return result.substr(0, result.length - 1) + ')';
28324 getIds: function() {
28325 var i = 0, result = new Array(this.store.getCount());
28326 this.store.each(function(rec) {
28327 result[i++] = rec.id;
28332 isDirty: function() {
28333 return this.isDirtyFlag;
28337 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28338 * whole Element becomes the target, and this causes the drop gesture to append.
28340 getTargetFromEvent : function(e) {
28341 var target = e.getTarget();
28342 while ((target !== null) && (target.parentNode != this.el.dom)) {
28343 target = target.parentNode;
28346 target = this.el.dom.lastChild || this.el.dom;
28352 * Create the drag data which consists of an object which has the property "ddel" as
28353 * the drag proxy element.
28355 getDragData : function(e) {
28356 var target = this.findItemFromChild(e.getTarget());
28358 this.handleSelection(e);
28359 var selNodes = this.getSelectedNodes();
28362 copy: this.copy || (this.allowCopy && e.ctrlKey),
28366 var selectedIndices = this.getSelectedIndexes();
28367 for (var i = 0; i < selectedIndices.length; i++) {
28368 dragData.records.push(this.store.getAt(selectedIndices[i]));
28370 if (selNodes.length == 1) {
28371 dragData.ddel = target.cloneNode(true); // the div element
28373 var div = document.createElement('div'); // create the multi element drag "ghost"
28374 div.className = 'multi-proxy';
28375 for (var i = 0, len = selNodes.length; i < len; i++) {
28376 div.appendChild(selNodes[i].cloneNode(true));
28378 dragData.ddel = div;
28380 //console.log(dragData)
28381 //console.log(dragData.ddel.innerHTML)
28384 //console.log('nodragData')
28388 /** Specify to which ddGroup items in this DDView may be dragged. */
28389 setDraggable: function(ddGroup) {
28390 if (ddGroup instanceof Array) {
28391 Roo.each(ddGroup, this.setDraggable, this);
28394 if (this.dragZone) {
28395 this.dragZone.addToGroup(ddGroup);
28397 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28398 containerScroll: true,
28402 // Draggability implies selection. DragZone's mousedown selects the element.
28403 if (!this.multiSelect) { this.singleSelect = true; }
28405 // Wire the DragZone's handlers up to methods in *this*
28406 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28410 /** Specify from which ddGroup this DDView accepts drops. */
28411 setDroppable: function(ddGroup) {
28412 if (ddGroup instanceof Array) {
28413 Roo.each(ddGroup, this.setDroppable, this);
28416 if (this.dropZone) {
28417 this.dropZone.addToGroup(ddGroup);
28419 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28420 containerScroll: true,
28424 // Wire the DropZone's handlers up to methods in *this*
28425 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28426 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28427 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28428 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28429 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28433 /** Decide whether to drop above or below a View node. */
28434 getDropPoint : function(e, n, dd){
28435 if (n == this.el.dom) { return "above"; }
28436 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28437 var c = t + (b - t) / 2;
28438 var y = Roo.lib.Event.getPageY(e);
28446 onNodeEnter : function(n, dd, e, data){
28450 onNodeOver : function(n, dd, e, data){
28451 var pt = this.getDropPoint(e, n, dd);
28452 // set the insert point style on the target node
28453 var dragElClass = this.dropNotAllowed;
28456 if (pt == "above"){
28457 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28458 targetElClass = "x-view-drag-insert-above";
28460 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28461 targetElClass = "x-view-drag-insert-below";
28463 if (this.lastInsertClass != targetElClass){
28464 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28465 this.lastInsertClass = targetElClass;
28468 return dragElClass;
28471 onNodeOut : function(n, dd, e, data){
28472 this.removeDropIndicators(n);
28475 onNodeDrop : function(n, dd, e, data){
28476 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28479 var pt = this.getDropPoint(e, n, dd);
28480 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28481 if (pt == "below") { insertAt++; }
28482 for (var i = 0; i < data.records.length; i++) {
28483 var r = data.records[i];
28484 var dup = this.store.getById(r.id);
28485 if (dup && (dd != this.dragZone)) {
28486 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28489 this.store.insert(insertAt++, r.copy());
28491 data.source.isDirtyFlag = true;
28493 this.store.insert(insertAt++, r);
28495 this.isDirtyFlag = true;
28498 this.dragZone.cachedTarget = null;
28502 removeDropIndicators : function(n){
28504 Roo.fly(n).removeClass([
28505 "x-view-drag-insert-above",
28506 "x-view-drag-insert-below"]);
28507 this.lastInsertClass = "_noclass";
28512 * Utility method. Add a delete option to the DDView's context menu.
28513 * @param {String} imageUrl The URL of the "delete" icon image.
28515 setDeletable: function(imageUrl) {
28516 if (!this.singleSelect && !this.multiSelect) {
28517 this.singleSelect = true;
28519 var c = this.getContextMenu();
28520 this.contextMenu.on("itemclick", function(item) {
28523 this.remove(this.getSelectedIndexes());
28527 this.contextMenu.add({
28534 /** Return the context menu for this DDView. */
28535 getContextMenu: function() {
28536 if (!this.contextMenu) {
28537 // Create the View's context menu
28538 this.contextMenu = new Roo.menu.Menu({
28539 id: this.id + "-contextmenu"
28541 this.el.on("contextmenu", this.showContextMenu, this);
28543 return this.contextMenu;
28546 disableContextMenu: function() {
28547 if (this.contextMenu) {
28548 this.el.un("contextmenu", this.showContextMenu, this);
28552 showContextMenu: function(e, item) {
28553 item = this.findItemFromChild(e.getTarget());
28556 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28557 this.contextMenu.showAt(e.getXY());
28562 * Remove {@link Roo.data.Record}s at the specified indices.
28563 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28565 remove: function(selectedIndices) {
28566 selectedIndices = [].concat(selectedIndices);
28567 for (var i = 0; i < selectedIndices.length; i++) {
28568 var rec = this.store.getAt(selectedIndices[i]);
28569 this.store.remove(rec);
28574 * Double click fires the event, but also, if this is draggable, and there is only one other
28575 * related DropZone, it transfers the selected node.
28577 onDblClick : function(e){
28578 var item = this.findItemFromChild(e.getTarget());
28580 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28583 if (this.dragGroup) {
28584 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28585 while (targets.indexOf(this.dropZone) > -1) {
28586 targets.remove(this.dropZone);
28588 if (targets.length == 1) {
28589 this.dragZone.cachedTarget = null;
28590 var el = Roo.get(targets[0].getEl());
28591 var box = el.getBox(true);
28592 targets[0].onNodeDrop(el.dom, {
28594 xy: [box.x, box.y + box.height - 1]
28595 }, null, this.getDragData(e));
28601 handleSelection: function(e) {
28602 this.dragZone.cachedTarget = null;
28603 var item = this.findItemFromChild(e.getTarget());
28605 this.clearSelections(true);
28608 if (item && (this.multiSelect || this.singleSelect)){
28609 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28610 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28611 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28612 this.unselect(item);
28614 this.select(item, this.multiSelect && e.ctrlKey);
28615 this.lastSelection = item;
28620 onItemClick : function(item, index, e){
28621 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28627 unselect : function(nodeInfo, suppressEvent){
28628 var node = this.getNode(nodeInfo);
28629 if(node && this.isSelected(node)){
28630 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28631 Roo.fly(node).removeClass(this.selectedClass);
28632 this.selections.remove(node);
28633 if(!suppressEvent){
28634 this.fireEvent("selectionchange", this, this.selections);
28642 * Ext JS Library 1.1.1
28643 * Copyright(c) 2006-2007, Ext JS, LLC.
28645 * Originally Released Under LGPL - original licence link has changed is not relivant.
28648 * <script type="text/javascript">
28652 * @class Roo.LayoutManager
28653 * @extends Roo.util.Observable
28654 * Base class for layout managers.
28656 Roo.LayoutManager = function(container, config){
28657 Roo.LayoutManager.superclass.constructor.call(this);
28658 this.el = Roo.get(container);
28659 // ie scrollbar fix
28660 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28661 document.body.scroll = "no";
28662 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28663 this.el.position('relative');
28665 this.id = this.el.id;
28666 this.el.addClass("x-layout-container");
28667 /** false to disable window resize monitoring @type Boolean */
28668 this.monitorWindowResize = true;
28673 * Fires when a layout is performed.
28674 * @param {Roo.LayoutManager} this
28678 * @event regionresized
28679 * Fires when the user resizes a region.
28680 * @param {Roo.LayoutRegion} region The resized region
28681 * @param {Number} newSize The new size (width for east/west, height for north/south)
28683 "regionresized" : true,
28685 * @event regioncollapsed
28686 * Fires when a region is collapsed.
28687 * @param {Roo.LayoutRegion} region The collapsed region
28689 "regioncollapsed" : true,
28691 * @event regionexpanded
28692 * Fires when a region is expanded.
28693 * @param {Roo.LayoutRegion} region The expanded region
28695 "regionexpanded" : true
28697 this.updating = false;
28698 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28701 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28703 * Returns true if this layout is currently being updated
28704 * @return {Boolean}
28706 isUpdating : function(){
28707 return this.updating;
28711 * Suspend the LayoutManager from doing auto-layouts while
28712 * making multiple add or remove calls
28714 beginUpdate : function(){
28715 this.updating = true;
28719 * Restore auto-layouts and optionally disable the manager from performing a layout
28720 * @param {Boolean} noLayout true to disable a layout update
28722 endUpdate : function(noLayout){
28723 this.updating = false;
28729 layout: function(){
28733 onRegionResized : function(region, newSize){
28734 this.fireEvent("regionresized", region, newSize);
28738 onRegionCollapsed : function(region){
28739 this.fireEvent("regioncollapsed", region);
28742 onRegionExpanded : function(region){
28743 this.fireEvent("regionexpanded", region);
28747 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28748 * performs box-model adjustments.
28749 * @return {Object} The size as an object {width: (the width), height: (the height)}
28751 getViewSize : function(){
28753 if(this.el.dom != document.body){
28754 size = this.el.getSize();
28756 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28758 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28759 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28764 * Returns the Element this layout is bound to.
28765 * @return {Roo.Element}
28767 getEl : function(){
28772 * Returns the specified region.
28773 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
28774 * @return {Roo.LayoutRegion}
28776 getRegion : function(target){
28777 return this.regions[target.toLowerCase()];
28780 onWindowResize : function(){
28781 if(this.monitorWindowResize){
28787 * Ext JS Library 1.1.1
28788 * Copyright(c) 2006-2007, Ext JS, LLC.
28790 * Originally Released Under LGPL - original licence link has changed is not relivant.
28793 * <script type="text/javascript">
28796 * @class Roo.BorderLayout
28797 * @extends Roo.LayoutManager
28798 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
28799 * please see: <br><br>
28800 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
28801 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
28804 var layout = new Roo.BorderLayout(document.body, {
28838 preferredTabWidth: 150
28843 var CP = Roo.ContentPanel;
28845 layout.beginUpdate();
28846 layout.add("north", new CP("north", "North"));
28847 layout.add("south", new CP("south", {title: "South", closable: true}));
28848 layout.add("west", new CP("west", {title: "West"}));
28849 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
28850 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
28851 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
28852 layout.getRegion("center").showPanel("center1");
28853 layout.endUpdate();
28856 <b>The container the layout is rendered into can be either the body element or any other element.
28857 If it is not the body element, the container needs to either be an absolute positioned element,
28858 or you will need to add "position:relative" to the css of the container. You will also need to specify
28859 the container size if it is not the body element.</b>
28862 * Create a new BorderLayout
28863 * @param {String/HTMLElement/Element} container The container this layout is bound to
28864 * @param {Object} config Configuration options
28866 Roo.BorderLayout = function(container, config){
28867 config = config || {};
28868 Roo.BorderLayout.superclass.constructor.call(this, container, config);
28869 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
28870 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
28871 var target = this.factory.validRegions[i];
28872 if(config[target]){
28873 this.addRegion(target, config[target]);
28878 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
28880 * Creates and adds a new region if it doesn't already exist.
28881 * @param {String} target The target region key (north, south, east, west or center).
28882 * @param {Object} config The regions config object
28883 * @return {BorderLayoutRegion} The new region
28885 addRegion : function(target, config){
28886 if(!this.regions[target]){
28887 var r = this.factory.create(target, this, config);
28888 this.bindRegion(target, r);
28890 return this.regions[target];
28894 bindRegion : function(name, r){
28895 this.regions[name] = r;
28896 r.on("visibilitychange", this.layout, this);
28897 r.on("paneladded", this.layout, this);
28898 r.on("panelremoved", this.layout, this);
28899 r.on("invalidated", this.layout, this);
28900 r.on("resized", this.onRegionResized, this);
28901 r.on("collapsed", this.onRegionCollapsed, this);
28902 r.on("expanded", this.onRegionExpanded, this);
28906 * Performs a layout update.
28908 layout : function(){
28909 if(this.updating) return;
28910 var size = this.getViewSize();
28911 var w = size.width;
28912 var h = size.height;
28917 //var x = 0, y = 0;
28919 var rs = this.regions;
28920 var north = rs["north"];
28921 var south = rs["south"];
28922 var west = rs["west"];
28923 var east = rs["east"];
28924 var center = rs["center"];
28925 //if(this.hideOnLayout){ // not supported anymore
28926 //c.el.setStyle("display", "none");
28928 if(north && north.isVisible()){
28929 var b = north.getBox();
28930 var m = north.getMargins();
28931 b.width = w - (m.left+m.right);
28934 centerY = b.height + b.y + m.bottom;
28935 centerH -= centerY;
28936 north.updateBox(this.safeBox(b));
28938 if(south && south.isVisible()){
28939 var b = south.getBox();
28940 var m = south.getMargins();
28941 b.width = w - (m.left+m.right);
28943 var totalHeight = (b.height + m.top + m.bottom);
28944 b.y = h - totalHeight + m.top;
28945 centerH -= totalHeight;
28946 south.updateBox(this.safeBox(b));
28948 if(west && west.isVisible()){
28949 var b = west.getBox();
28950 var m = west.getMargins();
28951 b.height = centerH - (m.top+m.bottom);
28953 b.y = centerY + m.top;
28954 var totalWidth = (b.width + m.left + m.right);
28955 centerX += totalWidth;
28956 centerW -= totalWidth;
28957 west.updateBox(this.safeBox(b));
28959 if(east && east.isVisible()){
28960 var b = east.getBox();
28961 var m = east.getMargins();
28962 b.height = centerH - (m.top+m.bottom);
28963 var totalWidth = (b.width + m.left + m.right);
28964 b.x = w - totalWidth + m.left;
28965 b.y = centerY + m.top;
28966 centerW -= totalWidth;
28967 east.updateBox(this.safeBox(b));
28970 var m = center.getMargins();
28972 x: centerX + m.left,
28973 y: centerY + m.top,
28974 width: centerW - (m.left+m.right),
28975 height: centerH - (m.top+m.bottom)
28977 //if(this.hideOnLayout){
28978 //center.el.setStyle("display", "block");
28980 center.updateBox(this.safeBox(centerBox));
28983 this.fireEvent("layout", this);
28987 safeBox : function(box){
28988 box.width = Math.max(0, box.width);
28989 box.height = Math.max(0, box.height);
28994 * Adds a ContentPanel (or subclass) to this layout.
28995 * @param {String} target The target region key (north, south, east, west or center).
28996 * @param {Roo.ContentPanel} panel The panel to add
28997 * @return {Roo.ContentPanel} The added panel
28999 add : function(target, panel){
29001 target = target.toLowerCase();
29002 return this.regions[target].add(panel);
29006 * Remove a ContentPanel (or subclass) to this layout.
29007 * @param {String} target The target region key (north, south, east, west or center).
29008 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29009 * @return {Roo.ContentPanel} The removed panel
29011 remove : function(target, panel){
29012 target = target.toLowerCase();
29013 return this.regions[target].remove(panel);
29017 * Searches all regions for a panel with the specified id
29018 * @param {String} panelId
29019 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29021 findPanel : function(panelId){
29022 var rs = this.regions;
29023 for(var target in rs){
29024 if(typeof rs[target] != "function"){
29025 var p = rs[target].getPanel(panelId);
29035 * Searches all regions for a panel with the specified id and activates (shows) it.
29036 * @param {String/ContentPanel} panelId The panels id or the panel itself
29037 * @return {Roo.ContentPanel} The shown panel or null
29039 showPanel : function(panelId) {
29040 var rs = this.regions;
29041 for(var target in rs){
29042 var r = rs[target];
29043 if(typeof r != "function"){
29044 if(r.hasPanel(panelId)){
29045 return r.showPanel(panelId);
29053 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29054 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29056 restoreState : function(provider){
29058 provider = Roo.state.Manager;
29060 var sm = new Roo.LayoutStateManager();
29061 sm.init(this, provider);
29065 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29066 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29067 * a valid ContentPanel config object. Example:
29069 // Create the main layout
29070 var layout = new Roo.BorderLayout('main-ct', {
29081 // Create and add multiple ContentPanels at once via configs
29084 id: 'source-files',
29086 title:'Ext Source Files',
29099 * @param {Object} regions An object containing ContentPanel configs by region name
29101 batchAdd : function(regions){
29102 this.beginUpdate();
29103 for(var rname in regions){
29104 var lr = this.regions[rname];
29106 this.addTypedPanels(lr, regions[rname]);
29113 addTypedPanels : function(lr, ps){
29114 if(typeof ps == 'string'){
29115 lr.add(new Roo.ContentPanel(ps));
29117 else if(ps instanceof Array){
29118 for(var i =0, len = ps.length; i < len; i++){
29119 this.addTypedPanels(lr, ps[i]);
29122 else if(!ps.events){ // raw config?
29124 delete ps.el; // prevent conflict
29125 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29127 else { // panel object assumed!
29132 * Adds a xtype elements to the layout.
29136 xtype : 'ContentPanel',
29143 xtype : 'NestedLayoutPanel',
29149 items : [ ... list of content panels or nested layout panels.. ]
29153 * @param {Object} cfg Xtype definition of item to add.
29155 addxtype : function(cfg)
29157 // basically accepts a pannel...
29158 // can accept a layout region..!?!?
29159 // console.log('BorderLayout add ' + cfg.xtype)
29161 if (!cfg.xtype.match(/Panel$/)) {
29165 var region = cfg.region;
29171 xitems = cfg.items;
29178 case 'ContentPanel': // ContentPanel (el, cfg)
29179 case 'ScrollPanel': // ContentPanel (el, cfg)
29180 if(cfg.autoCreate) {
29181 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29183 var el = this.el.createChild();
29184 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29187 this.add(region, ret);
29191 case 'TreePanel': // our new panel!
29192 cfg.el = this.el.createChild();
29193 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29194 this.add(region, ret);
29197 case 'NestedLayoutPanel':
29198 // create a new Layout (which is a Border Layout...
29199 var el = this.el.createChild();
29200 var clayout = cfg.layout;
29202 clayout.items = clayout.items || [];
29203 // replace this exitems with the clayout ones..
29204 xitems = clayout.items;
29207 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29208 cfg.background = false;
29210 var layout = new Roo.BorderLayout(el, clayout);
29212 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29213 //console.log('adding nested layout panel ' + cfg.toSource());
29214 this.add(region, ret);
29220 // needs grid and region
29222 //var el = this.getRegion(region).el.createChild();
29223 var el = this.el.createChild();
29224 // create the grid first...
29226 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29228 if (region == 'center' && this.active ) {
29229 cfg.background = false;
29231 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29233 this.add(region, ret);
29234 if (cfg.background) {
29235 ret.on('activate', function(gp) {
29236 if (!gp.grid.rendered) {
29249 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29251 // GridPanel (grid, cfg)
29254 this.beginUpdate();
29256 Roo.each(xitems, function(i) {
29266 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29267 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29268 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29269 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29272 var CP = Roo.ContentPanel;
29274 var layout = Roo.BorderLayout.create({
29278 panels: [new CP("north", "North")]
29287 panels: [new CP("west", {title: "West"})]
29296 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29305 panels: [new CP("south", {title: "South", closable: true})]
29312 preferredTabWidth: 150,
29314 new CP("center1", {title: "Close Me", closable: true}),
29315 new CP("center2", {title: "Center Panel", closable: false})
29320 layout.getRegion("center").showPanel("center1");
29325 Roo.BorderLayout.create = function(config, targetEl){
29326 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29327 layout.beginUpdate();
29328 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29329 for(var j = 0, jlen = regions.length; j < jlen; j++){
29330 var lr = regions[j];
29331 if(layout.regions[lr] && config[lr].panels){
29332 var r = layout.regions[lr];
29333 var ps = config[lr].panels;
29334 layout.addTypedPanels(r, ps);
29337 layout.endUpdate();
29342 Roo.BorderLayout.RegionFactory = {
29344 validRegions : ["north","south","east","west","center"],
29347 create : function(target, mgr, config){
29348 target = target.toLowerCase();
29349 if(config.lightweight || config.basic){
29350 return new Roo.BasicLayoutRegion(mgr, config, target);
29354 return new Roo.NorthLayoutRegion(mgr, config);
29356 return new Roo.SouthLayoutRegion(mgr, config);
29358 return new Roo.EastLayoutRegion(mgr, config);
29360 return new Roo.WestLayoutRegion(mgr, config);
29362 return new Roo.CenterLayoutRegion(mgr, config);
29364 throw 'Layout region "'+target+'" not supported.';
29368 * Ext JS Library 1.1.1
29369 * Copyright(c) 2006-2007, Ext JS, LLC.
29371 * Originally Released Under LGPL - original licence link has changed is not relivant.
29374 * <script type="text/javascript">
29378 * @class Roo.BasicLayoutRegion
29379 * @extends Roo.util.Observable
29380 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29381 * and does not have a titlebar, tabs or any other features. All it does is size and position
29382 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29384 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29386 this.position = pos;
29389 * @scope Roo.BasicLayoutRegion
29393 * @event beforeremove
29394 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29395 * @param {Roo.LayoutRegion} this
29396 * @param {Roo.ContentPanel} panel The panel
29397 * @param {Object} e The cancel event object
29399 "beforeremove" : true,
29401 * @event invalidated
29402 * Fires when the layout for this region is changed.
29403 * @param {Roo.LayoutRegion} this
29405 "invalidated" : true,
29407 * @event visibilitychange
29408 * Fires when this region is shown or hidden
29409 * @param {Roo.LayoutRegion} this
29410 * @param {Boolean} visibility true or false
29412 "visibilitychange" : true,
29414 * @event paneladded
29415 * Fires when a panel is added.
29416 * @param {Roo.LayoutRegion} this
29417 * @param {Roo.ContentPanel} panel The panel
29419 "paneladded" : true,
29421 * @event panelremoved
29422 * Fires when a panel is removed.
29423 * @param {Roo.LayoutRegion} this
29424 * @param {Roo.ContentPanel} panel The panel
29426 "panelremoved" : true,
29429 * Fires when this region is collapsed.
29430 * @param {Roo.LayoutRegion} this
29432 "collapsed" : true,
29435 * Fires when this region is expanded.
29436 * @param {Roo.LayoutRegion} this
29441 * Fires when this region is slid into view.
29442 * @param {Roo.LayoutRegion} this
29444 "slideshow" : true,
29447 * Fires when this region slides out of view.
29448 * @param {Roo.LayoutRegion} this
29450 "slidehide" : true,
29452 * @event panelactivated
29453 * Fires when a panel is activated.
29454 * @param {Roo.LayoutRegion} this
29455 * @param {Roo.ContentPanel} panel The activated panel
29457 "panelactivated" : true,
29460 * Fires when the user resizes this region.
29461 * @param {Roo.LayoutRegion} this
29462 * @param {Number} newSize The new size (width for east/west, height for north/south)
29466 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29467 this.panels = new Roo.util.MixedCollection();
29468 this.panels.getKey = this.getPanelId.createDelegate(this);
29470 this.activePanel = null;
29471 // ensure listeners are added...
29473 if (config.listeners || config.events) {
29474 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29475 listeners : config.listeners || {},
29476 events : config.events || {}
29480 if(skipConfig !== true){
29481 this.applyConfig(config);
29485 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29486 getPanelId : function(p){
29490 applyConfig : function(config){
29491 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29492 this.config = config;
29497 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29498 * the width, for horizontal (north, south) the height.
29499 * @param {Number} newSize The new width or height
29501 resizeTo : function(newSize){
29502 var el = this.el ? this.el :
29503 (this.activePanel ? this.activePanel.getEl() : null);
29505 switch(this.position){
29508 el.setWidth(newSize);
29509 this.fireEvent("resized", this, newSize);
29513 el.setHeight(newSize);
29514 this.fireEvent("resized", this, newSize);
29520 getBox : function(){
29521 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29524 getMargins : function(){
29525 return this.margins;
29528 updateBox : function(box){
29530 var el = this.activePanel.getEl();
29531 el.dom.style.left = box.x + "px";
29532 el.dom.style.top = box.y + "px";
29533 this.activePanel.setSize(box.width, box.height);
29537 * Returns the container element for this region.
29538 * @return {Roo.Element}
29540 getEl : function(){
29541 return this.activePanel;
29545 * Returns true if this region is currently visible.
29546 * @return {Boolean}
29548 isVisible : function(){
29549 return this.activePanel ? true : false;
29552 setActivePanel : function(panel){
29553 panel = this.getPanel(panel);
29554 if(this.activePanel && this.activePanel != panel){
29555 this.activePanel.setActiveState(false);
29556 this.activePanel.getEl().setLeftTop(-10000,-10000);
29558 this.activePanel = panel;
29559 panel.setActiveState(true);
29561 panel.setSize(this.box.width, this.box.height);
29563 this.fireEvent("panelactivated", this, panel);
29564 this.fireEvent("invalidated");
29568 * Show the specified panel.
29569 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29570 * @return {Roo.ContentPanel} The shown panel or null
29572 showPanel : function(panel){
29573 if(panel = this.getPanel(panel)){
29574 this.setActivePanel(panel);
29580 * Get the active panel for this region.
29581 * @return {Roo.ContentPanel} The active panel or null
29583 getActivePanel : function(){
29584 return this.activePanel;
29588 * Add the passed ContentPanel(s)
29589 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29590 * @return {Roo.ContentPanel} The panel added (if only one was added)
29592 add : function(panel){
29593 if(arguments.length > 1){
29594 for(var i = 0, len = arguments.length; i < len; i++) {
29595 this.add(arguments[i]);
29599 if(this.hasPanel(panel)){
29600 this.showPanel(panel);
29603 var el = panel.getEl();
29604 if(el.dom.parentNode != this.mgr.el.dom){
29605 this.mgr.el.dom.appendChild(el.dom);
29607 if(panel.setRegion){
29608 panel.setRegion(this);
29610 this.panels.add(panel);
29611 el.setStyle("position", "absolute");
29612 if(!panel.background){
29613 this.setActivePanel(panel);
29614 if(this.config.initialSize && this.panels.getCount()==1){
29615 this.resizeTo(this.config.initialSize);
29618 this.fireEvent("paneladded", this, panel);
29623 * Returns true if the panel is in this region.
29624 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29625 * @return {Boolean}
29627 hasPanel : function(panel){
29628 if(typeof panel == "object"){ // must be panel obj
29629 panel = panel.getId();
29631 return this.getPanel(panel) ? true : false;
29635 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29636 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29637 * @param {Boolean} preservePanel Overrides the config preservePanel option
29638 * @return {Roo.ContentPanel} The panel that was removed
29640 remove : function(panel, preservePanel){
29641 panel = this.getPanel(panel);
29646 this.fireEvent("beforeremove", this, panel, e);
29647 if(e.cancel === true){
29650 var panelId = panel.getId();
29651 this.panels.removeKey(panelId);
29656 * Returns the panel specified or null if it's not in this region.
29657 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29658 * @return {Roo.ContentPanel}
29660 getPanel : function(id){
29661 if(typeof id == "object"){ // must be panel obj
29664 return this.panels.get(id);
29668 * Returns this regions position (north/south/east/west/center).
29671 getPosition: function(){
29672 return this.position;
29676 * Ext JS Library 1.1.1
29677 * Copyright(c) 2006-2007, Ext JS, LLC.
29679 * Originally Released Under LGPL - original licence link has changed is not relivant.
29682 * <script type="text/javascript">
29686 * @class Roo.LayoutRegion
29687 * @extends Roo.BasicLayoutRegion
29688 * This class represents a region in a layout manager.
29689 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29690 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29691 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29692 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29693 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
29694 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29695 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29696 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29697 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29698 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29699 * @cfg {String} title The title for the region (overrides panel titles)
29700 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29701 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29702 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29703 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29704 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29705 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29706 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29707 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29708 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29709 * @cfg {Boolean} showPin True to show a pin button
29710 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29711 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29712 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29713 * @cfg {Number} width For East/West panels
29714 * @cfg {Number} height For North/South panels
29715 * @cfg {Boolean} split To show the splitter
29717 Roo.LayoutRegion = function(mgr, config, pos){
29718 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29719 var dh = Roo.DomHelper;
29720 /** This region's container element
29721 * @type Roo.Element */
29722 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29723 /** This region's title element
29724 * @type Roo.Element */
29726 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29727 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29728 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29730 this.titleEl.enableDisplayMode();
29731 /** This region's title text element
29732 * @type HTMLElement */
29733 this.titleTextEl = this.titleEl.dom.firstChild;
29734 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29735 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29736 this.closeBtn.enableDisplayMode();
29737 this.closeBtn.on("click", this.closeClicked, this);
29738 this.closeBtn.hide();
29740 this.createBody(config);
29741 this.visible = true;
29742 this.collapsed = false;
29744 if(config.hideWhenEmpty){
29746 this.on("paneladded", this.validateVisibility, this);
29747 this.on("panelremoved", this.validateVisibility, this);
29749 this.applyConfig(config);
29752 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29754 createBody : function(){
29755 /** This region's body element
29756 * @type Roo.Element */
29757 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29760 applyConfig : function(c){
29761 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29762 var dh = Roo.DomHelper;
29763 if(c.titlebar !== false){
29764 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
29765 this.collapseBtn.on("click", this.collapse, this);
29766 this.collapseBtn.enableDisplayMode();
29768 if(c.showPin === true || this.showPin){
29769 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
29770 this.stickBtn.enableDisplayMode();
29771 this.stickBtn.on("click", this.expand, this);
29772 this.stickBtn.hide();
29775 /** This region's collapsed element
29776 * @type Roo.Element */
29777 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
29778 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
29780 if(c.floatable !== false){
29781 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
29782 this.collapsedEl.on("click", this.collapseClick, this);
29785 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
29786 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
29787 id: "message", unselectable: "on", style:{"float":"left"}});
29788 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
29790 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
29791 this.expandBtn.on("click", this.expand, this);
29793 if(this.collapseBtn){
29794 this.collapseBtn.setVisible(c.collapsible == true);
29796 this.cmargins = c.cmargins || this.cmargins ||
29797 (this.position == "west" || this.position == "east" ?
29798 {top: 0, left: 2, right:2, bottom: 0} :
29799 {top: 2, left: 0, right:0, bottom: 2});
29800 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29801 this.bottomTabs = c.tabPosition != "top";
29802 this.autoScroll = c.autoScroll || false;
29803 if(this.autoScroll){
29804 this.bodyEl.setStyle("overflow", "auto");
29806 this.bodyEl.setStyle("overflow", "hidden");
29808 //if(c.titlebar !== false){
29809 if((!c.titlebar && !c.title) || c.titlebar === false){
29810 this.titleEl.hide();
29812 this.titleEl.show();
29814 this.titleTextEl.innerHTML = c.title;
29818 this.duration = c.duration || .30;
29819 this.slideDuration = c.slideDuration || .45;
29822 this.collapse(true);
29829 * Returns true if this region is currently visible.
29830 * @return {Boolean}
29832 isVisible : function(){
29833 return this.visible;
29837 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
29838 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
29840 setCollapsedTitle : function(title){
29841 title = title || " ";
29842 if(this.collapsedTitleTextEl){
29843 this.collapsedTitleTextEl.innerHTML = title;
29847 getBox : function(){
29849 if(!this.collapsed){
29850 b = this.el.getBox(false, true);
29852 b = this.collapsedEl.getBox(false, true);
29857 getMargins : function(){
29858 return this.collapsed ? this.cmargins : this.margins;
29861 highlight : function(){
29862 this.el.addClass("x-layout-panel-dragover");
29865 unhighlight : function(){
29866 this.el.removeClass("x-layout-panel-dragover");
29869 updateBox : function(box){
29871 if(!this.collapsed){
29872 this.el.dom.style.left = box.x + "px";
29873 this.el.dom.style.top = box.y + "px";
29874 this.updateBody(box.width, box.height);
29876 this.collapsedEl.dom.style.left = box.x + "px";
29877 this.collapsedEl.dom.style.top = box.y + "px";
29878 this.collapsedEl.setSize(box.width, box.height);
29881 this.tabs.autoSizeTabs();
29885 updateBody : function(w, h){
29887 this.el.setWidth(w);
29888 w -= this.el.getBorderWidth("rl");
29889 if(this.config.adjustments){
29890 w += this.config.adjustments[0];
29894 this.el.setHeight(h);
29895 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
29896 h -= this.el.getBorderWidth("tb");
29897 if(this.config.adjustments){
29898 h += this.config.adjustments[1];
29900 this.bodyEl.setHeight(h);
29902 h = this.tabs.syncHeight(h);
29905 if(this.panelSize){
29906 w = w !== null ? w : this.panelSize.width;
29907 h = h !== null ? h : this.panelSize.height;
29909 if(this.activePanel){
29910 var el = this.activePanel.getEl();
29911 w = w !== null ? w : el.getWidth();
29912 h = h !== null ? h : el.getHeight();
29913 this.panelSize = {width: w, height: h};
29914 this.activePanel.setSize(w, h);
29916 if(Roo.isIE && this.tabs){
29917 this.tabs.el.repaint();
29922 * Returns the container element for this region.
29923 * @return {Roo.Element}
29925 getEl : function(){
29930 * Hides this region.
29933 if(!this.collapsed){
29934 this.el.dom.style.left = "-2000px";
29937 this.collapsedEl.dom.style.left = "-2000px";
29938 this.collapsedEl.hide();
29940 this.visible = false;
29941 this.fireEvent("visibilitychange", this, false);
29945 * Shows this region if it was previously hidden.
29948 if(!this.collapsed){
29951 this.collapsedEl.show();
29953 this.visible = true;
29954 this.fireEvent("visibilitychange", this, true);
29957 closeClicked : function(){
29958 if(this.activePanel){
29959 this.remove(this.activePanel);
29963 collapseClick : function(e){
29965 e.stopPropagation();
29968 e.stopPropagation();
29974 * Collapses this region.
29975 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
29977 collapse : function(skipAnim){
29978 if(this.collapsed) return;
29979 this.collapsed = true;
29981 this.split.el.hide();
29983 if(this.config.animate && skipAnim !== true){
29984 this.fireEvent("invalidated", this);
29985 this.animateCollapse();
29987 this.el.setLocation(-20000,-20000);
29989 this.collapsedEl.show();
29990 this.fireEvent("collapsed", this);
29991 this.fireEvent("invalidated", this);
29995 animateCollapse : function(){
30000 * Expands this region if it was previously collapsed.
30001 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
30002 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
30004 expand : function(e, skipAnim){
30005 if(e) e.stopPropagation();
30006 if(!this.collapsed || this.el.hasActiveFx()) return;
30008 this.afterSlideIn();
30011 this.collapsed = false;
30012 if(this.config.animate && skipAnim !== true){
30013 this.animateExpand();
30017 this.split.el.show();
30019 this.collapsedEl.setLocation(-2000,-2000);
30020 this.collapsedEl.hide();
30021 this.fireEvent("invalidated", this);
30022 this.fireEvent("expanded", this);
30026 animateExpand : function(){
30030 initTabs : function(){
30031 this.bodyEl.setStyle("overflow", "hidden");
30032 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30033 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30034 disableTooltips: this.config.disableTabTips
30036 if(this.config.hideTabs){
30037 ts.stripWrap.setDisplayed(false);
30040 ts.resizeTabs = this.config.resizeTabs === true;
30041 ts.minTabWidth = this.config.minTabWidth || 40;
30042 ts.maxTabWidth = this.config.maxTabWidth || 250;
30043 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30044 ts.monitorResize = false;
30045 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30046 ts.bodyEl.addClass('x-layout-tabs-body');
30047 this.panels.each(this.initPanelAsTab, this);
30050 initPanelAsTab : function(panel){
30051 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30052 this.config.closeOnTab && panel.isClosable());
30053 if(panel.tabTip !== undefined){
30054 ti.setTooltip(panel.tabTip);
30056 ti.on("activate", function(){
30057 this.setActivePanel(panel);
30059 if(this.config.closeOnTab){
30060 ti.on("beforeclose", function(t, e){
30062 this.remove(panel);
30068 updatePanelTitle : function(panel, title){
30069 if(this.activePanel == panel){
30070 this.updateTitle(title);
30073 var ti = this.tabs.getTab(panel.getEl().id);
30075 if(panel.tabTip !== undefined){
30076 ti.setTooltip(panel.tabTip);
30081 updateTitle : function(title){
30082 if(this.titleTextEl && !this.config.title){
30083 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30087 setActivePanel : function(panel){
30088 panel = this.getPanel(panel);
30089 if(this.activePanel && this.activePanel != panel){
30090 this.activePanel.setActiveState(false);
30092 this.activePanel = panel;
30093 panel.setActiveState(true);
30094 if(this.panelSize){
30095 panel.setSize(this.panelSize.width, this.panelSize.height);
30098 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30100 this.updateTitle(panel.getTitle());
30102 this.fireEvent("invalidated", this);
30104 this.fireEvent("panelactivated", this, panel);
30108 * Shows the specified panel.
30109 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30110 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30112 showPanel : function(panel){
30113 if(panel = this.getPanel(panel)){
30115 var tab = this.tabs.getTab(panel.getEl().id);
30116 if(tab.isHidden()){
30117 this.tabs.unhideTab(tab.id);
30121 this.setActivePanel(panel);
30128 * Get the active panel for this region.
30129 * @return {Roo.ContentPanel} The active panel or null
30131 getActivePanel : function(){
30132 return this.activePanel;
30135 validateVisibility : function(){
30136 if(this.panels.getCount() < 1){
30137 this.updateTitle(" ");
30138 this.closeBtn.hide();
30141 if(!this.isVisible()){
30148 * Adds the passed ContentPanel(s) to this region.
30149 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30150 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30152 add : function(panel){
30153 if(arguments.length > 1){
30154 for(var i = 0, len = arguments.length; i < len; i++) {
30155 this.add(arguments[i]);
30159 if(this.hasPanel(panel)){
30160 this.showPanel(panel);
30163 panel.setRegion(this);
30164 this.panels.add(panel);
30165 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30166 this.bodyEl.dom.appendChild(panel.getEl().dom);
30167 if(panel.background !== true){
30168 this.setActivePanel(panel);
30170 this.fireEvent("paneladded", this, panel);
30176 this.initPanelAsTab(panel);
30178 if(panel.background !== true){
30179 this.tabs.activate(panel.getEl().id);
30181 this.fireEvent("paneladded", this, panel);
30186 * Hides the tab for the specified panel.
30187 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30189 hidePanel : function(panel){
30190 if(this.tabs && (panel = this.getPanel(panel))){
30191 this.tabs.hideTab(panel.getEl().id);
30196 * Unhides the tab for a previously hidden panel.
30197 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30199 unhidePanel : function(panel){
30200 if(this.tabs && (panel = this.getPanel(panel))){
30201 this.tabs.unhideTab(panel.getEl().id);
30205 clearPanels : function(){
30206 while(this.panels.getCount() > 0){
30207 this.remove(this.panels.first());
30212 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30213 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30214 * @param {Boolean} preservePanel Overrides the config preservePanel option
30215 * @return {Roo.ContentPanel} The panel that was removed
30217 remove : function(panel, preservePanel){
30218 panel = this.getPanel(panel);
30223 this.fireEvent("beforeremove", this, panel, e);
30224 if(e.cancel === true){
30227 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30228 var panelId = panel.getId();
30229 this.panels.removeKey(panelId);
30231 document.body.appendChild(panel.getEl().dom);
30234 this.tabs.removeTab(panel.getEl().id);
30235 }else if (!preservePanel){
30236 this.bodyEl.dom.removeChild(panel.getEl().dom);
30238 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30239 var p = this.panels.first();
30240 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30241 tempEl.appendChild(p.getEl().dom);
30242 this.bodyEl.update("");
30243 this.bodyEl.dom.appendChild(p.getEl().dom);
30245 this.updateTitle(p.getTitle());
30247 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30248 this.setActivePanel(p);
30250 panel.setRegion(null);
30251 if(this.activePanel == panel){
30252 this.activePanel = null;
30254 if(this.config.autoDestroy !== false && preservePanel !== true){
30255 try{panel.destroy();}catch(e){}
30257 this.fireEvent("panelremoved", this, panel);
30262 * Returns the TabPanel component used by this region
30263 * @return {Roo.TabPanel}
30265 getTabs : function(){
30269 createTool : function(parentEl, className){
30270 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30271 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30272 btn.addClassOnOver("x-layout-tools-button-over");
30277 * Ext JS Library 1.1.1
30278 * Copyright(c) 2006-2007, Ext JS, LLC.
30280 * Originally Released Under LGPL - original licence link has changed is not relivant.
30283 * <script type="text/javascript">
30289 * @class Roo.SplitLayoutRegion
30290 * @extends Roo.LayoutRegion
30291 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30293 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30294 this.cursor = cursor;
30295 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30298 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30299 splitTip : "Drag to resize.",
30300 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30301 useSplitTips : false,
30303 applyConfig : function(config){
30304 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30307 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30308 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30309 /** The SplitBar for this region
30310 * @type Roo.SplitBar */
30311 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30312 this.split.on("moved", this.onSplitMove, this);
30313 this.split.useShim = config.useShim === true;
30314 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30315 if(this.useSplitTips){
30316 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30318 if(config.collapsible){
30319 this.split.el.on("dblclick", this.collapse, this);
30322 if(typeof config.minSize != "undefined"){
30323 this.split.minSize = config.minSize;
30325 if(typeof config.maxSize != "undefined"){
30326 this.split.maxSize = config.maxSize;
30328 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30329 this.hideSplitter();
30334 getHMaxSize : function(){
30335 var cmax = this.config.maxSize || 10000;
30336 var center = this.mgr.getRegion("center");
30337 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30340 getVMaxSize : function(){
30341 var cmax = this.config.maxSize || 10000;
30342 var center = this.mgr.getRegion("center");
30343 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30346 onSplitMove : function(split, newSize){
30347 this.fireEvent("resized", this, newSize);
30351 * Returns the {@link Roo.SplitBar} for this region.
30352 * @return {Roo.SplitBar}
30354 getSplitBar : function(){
30359 this.hideSplitter();
30360 Roo.SplitLayoutRegion.superclass.hide.call(this);
30363 hideSplitter : function(){
30365 this.split.el.setLocation(-2000,-2000);
30366 this.split.el.hide();
30372 this.split.el.show();
30374 Roo.SplitLayoutRegion.superclass.show.call(this);
30377 beforeSlide: function(){
30378 if(Roo.isGecko){// firefox overflow auto bug workaround
30379 this.bodyEl.clip();
30380 if(this.tabs) this.tabs.bodyEl.clip();
30381 if(this.activePanel){
30382 this.activePanel.getEl().clip();
30384 if(this.activePanel.beforeSlide){
30385 this.activePanel.beforeSlide();
30391 afterSlide : function(){
30392 if(Roo.isGecko){// firefox overflow auto bug workaround
30393 this.bodyEl.unclip();
30394 if(this.tabs) this.tabs.bodyEl.unclip();
30395 if(this.activePanel){
30396 this.activePanel.getEl().unclip();
30397 if(this.activePanel.afterSlide){
30398 this.activePanel.afterSlide();
30404 initAutoHide : function(){
30405 if(this.autoHide !== false){
30406 if(!this.autoHideHd){
30407 var st = new Roo.util.DelayedTask(this.slideIn, this);
30408 this.autoHideHd = {
30409 "mouseout": function(e){
30410 if(!e.within(this.el, true)){
30414 "mouseover" : function(e){
30420 this.el.on(this.autoHideHd);
30424 clearAutoHide : function(){
30425 if(this.autoHide !== false){
30426 this.el.un("mouseout", this.autoHideHd.mouseout);
30427 this.el.un("mouseover", this.autoHideHd.mouseover);
30431 clearMonitor : function(){
30432 Roo.get(document).un("click", this.slideInIf, this);
30435 // these names are backwards but not changed for compat
30436 slideOut : function(){
30437 if(this.isSlid || this.el.hasActiveFx()){
30440 this.isSlid = true;
30441 if(this.collapseBtn){
30442 this.collapseBtn.hide();
30444 this.closeBtnState = this.closeBtn.getStyle('display');
30445 this.closeBtn.hide();
30447 this.stickBtn.show();
30450 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30451 this.beforeSlide();
30452 this.el.setStyle("z-index", 10001);
30453 this.el.slideIn(this.getSlideAnchor(), {
30454 callback: function(){
30456 this.initAutoHide();
30457 Roo.get(document).on("click", this.slideInIf, this);
30458 this.fireEvent("slideshow", this);
30465 afterSlideIn : function(){
30466 this.clearAutoHide();
30467 this.isSlid = false;
30468 this.clearMonitor();
30469 this.el.setStyle("z-index", "");
30470 if(this.collapseBtn){
30471 this.collapseBtn.show();
30473 this.closeBtn.setStyle('display', this.closeBtnState);
30475 this.stickBtn.hide();
30477 this.fireEvent("slidehide", this);
30480 slideIn : function(cb){
30481 if(!this.isSlid || this.el.hasActiveFx()){
30485 this.isSlid = false;
30486 this.beforeSlide();
30487 this.el.slideOut(this.getSlideAnchor(), {
30488 callback: function(){
30489 this.el.setLeftTop(-10000, -10000);
30491 this.afterSlideIn();
30499 slideInIf : function(e){
30500 if(!e.within(this.el)){
30505 animateCollapse : function(){
30506 this.beforeSlide();
30507 this.el.setStyle("z-index", 20000);
30508 var anchor = this.getSlideAnchor();
30509 this.el.slideOut(anchor, {
30510 callback : function(){
30511 this.el.setStyle("z-index", "");
30512 this.collapsedEl.slideIn(anchor, {duration:.3});
30514 this.el.setLocation(-10000,-10000);
30516 this.fireEvent("collapsed", this);
30523 animateExpand : function(){
30524 this.beforeSlide();
30525 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30526 this.el.setStyle("z-index", 20000);
30527 this.collapsedEl.hide({
30530 this.el.slideIn(this.getSlideAnchor(), {
30531 callback : function(){
30532 this.el.setStyle("z-index", "");
30535 this.split.el.show();
30537 this.fireEvent("invalidated", this);
30538 this.fireEvent("expanded", this);
30566 getAnchor : function(){
30567 return this.anchors[this.position];
30570 getCollapseAnchor : function(){
30571 return this.canchors[this.position];
30574 getSlideAnchor : function(){
30575 return this.sanchors[this.position];
30578 getAlignAdj : function(){
30579 var cm = this.cmargins;
30580 switch(this.position){
30596 getExpandAdj : function(){
30597 var c = this.collapsedEl, cm = this.cmargins;
30598 switch(this.position){
30600 return [-(cm.right+c.getWidth()+cm.left), 0];
30603 return [cm.right+c.getWidth()+cm.left, 0];
30606 return [0, -(cm.top+cm.bottom+c.getHeight())];
30609 return [0, cm.top+cm.bottom+c.getHeight()];
30615 * Ext JS Library 1.1.1
30616 * Copyright(c) 2006-2007, Ext JS, LLC.
30618 * Originally Released Under LGPL - original licence link has changed is not relivant.
30621 * <script type="text/javascript">
30624 * These classes are private internal classes
30626 Roo.CenterLayoutRegion = function(mgr, config){
30627 Roo.LayoutRegion.call(this, mgr, config, "center");
30628 this.visible = true;
30629 this.minWidth = config.minWidth || 20;
30630 this.minHeight = config.minHeight || 20;
30633 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30635 // center panel can't be hidden
30639 // center panel can't be hidden
30642 getMinWidth: function(){
30643 return this.minWidth;
30646 getMinHeight: function(){
30647 return this.minHeight;
30652 Roo.NorthLayoutRegion = function(mgr, config){
30653 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30655 this.split.placement = Roo.SplitBar.TOP;
30656 this.split.orientation = Roo.SplitBar.VERTICAL;
30657 this.split.el.addClass("x-layout-split-v");
30659 var size = config.initialSize || config.height;
30660 if(typeof size != "undefined"){
30661 this.el.setHeight(size);
30664 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30665 orientation: Roo.SplitBar.VERTICAL,
30666 getBox : function(){
30667 if(this.collapsed){
30668 return this.collapsedEl.getBox();
30670 var box = this.el.getBox();
30672 box.height += this.split.el.getHeight();
30677 updateBox : function(box){
30678 if(this.split && !this.collapsed){
30679 box.height -= this.split.el.getHeight();
30680 this.split.el.setLeft(box.x);
30681 this.split.el.setTop(box.y+box.height);
30682 this.split.el.setWidth(box.width);
30684 if(this.collapsed){
30685 this.updateBody(box.width, null);
30687 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30691 Roo.SouthLayoutRegion = function(mgr, config){
30692 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30694 this.split.placement = Roo.SplitBar.BOTTOM;
30695 this.split.orientation = Roo.SplitBar.VERTICAL;
30696 this.split.el.addClass("x-layout-split-v");
30698 var size = config.initialSize || config.height;
30699 if(typeof size != "undefined"){
30700 this.el.setHeight(size);
30703 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30704 orientation: Roo.SplitBar.VERTICAL,
30705 getBox : function(){
30706 if(this.collapsed){
30707 return this.collapsedEl.getBox();
30709 var box = this.el.getBox();
30711 var sh = this.split.el.getHeight();
30718 updateBox : function(box){
30719 if(this.split && !this.collapsed){
30720 var sh = this.split.el.getHeight();
30723 this.split.el.setLeft(box.x);
30724 this.split.el.setTop(box.y-sh);
30725 this.split.el.setWidth(box.width);
30727 if(this.collapsed){
30728 this.updateBody(box.width, null);
30730 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30734 Roo.EastLayoutRegion = function(mgr, config){
30735 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
30737 this.split.placement = Roo.SplitBar.RIGHT;
30738 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30739 this.split.el.addClass("x-layout-split-h");
30741 var size = config.initialSize || config.width;
30742 if(typeof size != "undefined"){
30743 this.el.setWidth(size);
30746 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
30747 orientation: Roo.SplitBar.HORIZONTAL,
30748 getBox : function(){
30749 if(this.collapsed){
30750 return this.collapsedEl.getBox();
30752 var box = this.el.getBox();
30754 var sw = this.split.el.getWidth();
30761 updateBox : function(box){
30762 if(this.split && !this.collapsed){
30763 var sw = this.split.el.getWidth();
30765 this.split.el.setLeft(box.x);
30766 this.split.el.setTop(box.y);
30767 this.split.el.setHeight(box.height);
30770 if(this.collapsed){
30771 this.updateBody(null, box.height);
30773 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30777 Roo.WestLayoutRegion = function(mgr, config){
30778 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
30780 this.split.placement = Roo.SplitBar.LEFT;
30781 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30782 this.split.el.addClass("x-layout-split-h");
30784 var size = config.initialSize || config.width;
30785 if(typeof size != "undefined"){
30786 this.el.setWidth(size);
30789 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
30790 orientation: Roo.SplitBar.HORIZONTAL,
30791 getBox : function(){
30792 if(this.collapsed){
30793 return this.collapsedEl.getBox();
30795 var box = this.el.getBox();
30797 box.width += this.split.el.getWidth();
30802 updateBox : function(box){
30803 if(this.split && !this.collapsed){
30804 var sw = this.split.el.getWidth();
30806 this.split.el.setLeft(box.x+box.width);
30807 this.split.el.setTop(box.y);
30808 this.split.el.setHeight(box.height);
30810 if(this.collapsed){
30811 this.updateBody(null, box.height);
30813 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30818 * Ext JS Library 1.1.1
30819 * Copyright(c) 2006-2007, Ext JS, LLC.
30821 * Originally Released Under LGPL - original licence link has changed is not relivant.
30824 * <script type="text/javascript">
30829 * Private internal class for reading and applying state
30831 Roo.LayoutStateManager = function(layout){
30832 // default empty state
30841 Roo.LayoutStateManager.prototype = {
30842 init : function(layout, provider){
30843 this.provider = provider;
30844 var state = provider.get(layout.id+"-layout-state");
30846 var wasUpdating = layout.isUpdating();
30848 layout.beginUpdate();
30850 for(var key in state){
30851 if(typeof state[key] != "function"){
30852 var rstate = state[key];
30853 var r = layout.getRegion(key);
30856 r.resizeTo(rstate.size);
30858 if(rstate.collapsed == true){
30861 r.expand(null, true);
30867 layout.endUpdate();
30869 this.state = state;
30871 this.layout = layout;
30872 layout.on("regionresized", this.onRegionResized, this);
30873 layout.on("regioncollapsed", this.onRegionCollapsed, this);
30874 layout.on("regionexpanded", this.onRegionExpanded, this);
30877 storeState : function(){
30878 this.provider.set(this.layout.id+"-layout-state", this.state);
30881 onRegionResized : function(region, newSize){
30882 this.state[region.getPosition()].size = newSize;
30886 onRegionCollapsed : function(region){
30887 this.state[region.getPosition()].collapsed = true;
30891 onRegionExpanded : function(region){
30892 this.state[region.getPosition()].collapsed = false;
30897 * Ext JS Library 1.1.1
30898 * Copyright(c) 2006-2007, Ext JS, LLC.
30900 * Originally Released Under LGPL - original licence link has changed is not relivant.
30903 * <script type="text/javascript">
30906 * @class Roo.ContentPanel
30907 * @extends Roo.util.Observable
30908 * A basic ContentPanel element.
30909 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
30910 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
30911 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
30912 * @cfg {Boolean} closable True if the panel can be closed/removed
30913 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
30914 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
30915 * @cfg {Toolbar} toolbar A toolbar for this panel
30916 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
30917 * @cfg {String} title The title for this panel
30918 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
30919 * @cfg {String} url Calls {@link #setUrl} with this value
30920 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
30921 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
30922 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
30924 * Create a new ContentPanel.
30925 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
30926 * @param {String/Object} config A string to set only the title or a config object
30927 * @param {String} content (optional) Set the HTML content for this panel
30928 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
30930 Roo.ContentPanel = function(el, config, content){
30934 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
30938 if (config && config.parentLayout) {
30939 el = config.parentLayout.el.createChild();
30942 if(el.autoCreate){ // xtype is available if this is called from factory
30946 this.el = Roo.get(el);
30947 if(!this.el && config && config.autoCreate){
30948 if(typeof config.autoCreate == "object"){
30949 if(!config.autoCreate.id){
30950 config.autoCreate.id = config.id||el;
30952 this.el = Roo.DomHelper.append(document.body,
30953 config.autoCreate, true);
30955 this.el = Roo.DomHelper.append(document.body,
30956 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
30959 this.closable = false;
30960 this.loaded = false;
30961 this.active = false;
30962 if(typeof config == "string"){
30963 this.title = config;
30965 Roo.apply(this, config);
30968 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
30969 this.wrapEl = this.el.wrap();
30970 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
30977 this.resizeEl = Roo.get(this.resizeEl, true);
30979 this.resizeEl = this.el;
30984 * Fires when this panel is activated.
30985 * @param {Roo.ContentPanel} this
30989 * @event deactivate
30990 * Fires when this panel is activated.
30991 * @param {Roo.ContentPanel} this
30993 "deactivate" : true,
30997 * Fires when this panel is resized if fitToFrame is true.
30998 * @param {Roo.ContentPanel} this
30999 * @param {Number} width The width after any component adjustments
31000 * @param {Number} height The height after any component adjustments
31004 if(this.autoScroll){
31005 this.resizeEl.setStyle("overflow", "auto");
31007 // fix randome scrolling
31008 this.el.on('scroll', function() {
31009 this.scrollTo('top',0);
31012 content = content || this.content;
31014 this.setContent(content);
31016 if(config && config.url){
31017 this.setUrl(this.url, this.params, this.loadOnce);
31022 Roo.ContentPanel.superclass.constructor.call(this);
31025 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31027 setRegion : function(region){
31028 this.region = region;
31030 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31032 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31037 * Returns the toolbar for this Panel if one was configured.
31038 * @return {Roo.Toolbar}
31040 getToolbar : function(){
31041 return this.toolbar;
31044 setActiveState : function(active){
31045 this.active = active;
31047 this.fireEvent("deactivate", this);
31049 this.fireEvent("activate", this);
31053 * Updates this panel's element
31054 * @param {String} content The new content
31055 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31057 setContent : function(content, loadScripts){
31058 this.el.update(content, loadScripts);
31061 ignoreResize : function(w, h){
31062 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31065 this.lastSize = {width: w, height: h};
31070 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31071 * @return {Roo.UpdateManager} The UpdateManager
31073 getUpdateManager : function(){
31074 return this.el.getUpdateManager();
31077 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31078 * @param {Object/String/Function} url The url for this request or a function to call to get the url or a config object containing any of the following options:
31081 url: "your-url.php",
31082 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31083 callback: yourFunction,
31084 scope: yourObject, //(optional scope)
31087 text: "Loading...",
31092 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31093 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
31094 * @param {String/Object} params (optional) The parameters to pass as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
31095 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31096 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
31097 * @return {Roo.ContentPanel} this
31100 var um = this.el.getUpdateManager();
31101 um.update.apply(um, arguments);
31107 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
31108 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31109 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
31110 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
31111 * @return {Roo.UpdateManager} The UpdateManager
31113 setUrl : function(url, params, loadOnce){
31114 if(this.refreshDelegate){
31115 this.removeListener("activate", this.refreshDelegate);
31117 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31118 this.on("activate", this.refreshDelegate);
31119 return this.el.getUpdateManager();
31122 _handleRefresh : function(url, params, loadOnce){
31123 if(!loadOnce || !this.loaded){
31124 var updater = this.el.getUpdateManager();
31125 updater.update(url, params, this._setLoaded.createDelegate(this));
31129 _setLoaded : function(){
31130 this.loaded = true;
31134 * Returns this panel's id
31137 getId : function(){
31142 * Returns this panel's element - used by regiosn to add.
31143 * @return {Roo.Element}
31145 getEl : function(){
31146 return this.wrapEl || this.el;
31149 adjustForComponents : function(width, height){
31150 if(this.resizeEl != this.el){
31151 width -= this.el.getFrameWidth('lr');
31152 height -= this.el.getFrameWidth('tb');
31155 var te = this.toolbar.getEl();
31156 height -= te.getHeight();
31157 te.setWidth(width);
31159 if(this.adjustments){
31160 width += this.adjustments[0];
31161 height += this.adjustments[1];
31163 return {"width": width, "height": height};
31166 setSize : function(width, height){
31167 if(this.fitToFrame && !this.ignoreResize(width, height)){
31168 if(this.fitContainer && this.resizeEl != this.el){
31169 this.el.setSize(width, height);
31171 var size = this.adjustForComponents(width, height);
31172 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31173 this.fireEvent('resize', this, size.width, size.height);
31178 * Returns this panel's title
31181 getTitle : function(){
31186 * Set this panel's title
31187 * @param {String} title
31189 setTitle : function(title){
31190 this.title = title;
31192 this.region.updatePanelTitle(this, title);
31197 * Returns true is this panel was configured to be closable
31198 * @return {Boolean}
31200 isClosable : function(){
31201 return this.closable;
31204 beforeSlide : function(){
31206 this.resizeEl.clip();
31209 afterSlide : function(){
31211 this.resizeEl.unclip();
31215 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31216 * Will fail silently if the {@link #setUrl} method has not been called.
31217 * This does not activate the panel, just updates its content.
31219 refresh : function(){
31220 if(this.refreshDelegate){
31221 this.loaded = false;
31222 this.refreshDelegate();
31227 * Destroys this panel
31229 destroy : function(){
31230 this.el.removeAllListeners();
31231 var tempEl = document.createElement("span");
31232 tempEl.appendChild(this.el.dom);
31233 tempEl.innerHTML = "";
31239 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31249 * @param {Object} cfg Xtype definition of item to add.
31252 addxtype : function(cfg) {
31254 if (cfg.xtype.match(/^Form$/)) {
31255 var el = this.el.createChild();
31257 this.form = new Roo.form.Form(cfg);
31260 if ( this.form.allItems.length) this.form.render(el.dom);
31263 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
31265 cfg.el = this.el.appendChild(document.createElement("div"));
31267 var ret = new Roo[cfg.xtype](cfg);
31268 ret.render(false, ''); // render blank..
31278 * @class Roo.GridPanel
31279 * @extends Roo.ContentPanel
31281 * Create a new GridPanel.
31282 * @param {Roo.grid.Grid} grid The grid for this panel
31283 * @param {String/Object} config A string to set only the panel's title, or a config object
31285 Roo.GridPanel = function(grid, config){
31288 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31289 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31291 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31293 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31296 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31298 // xtype created footer. - not sure if will work as we normally have to render first..
31299 if (this.footer && !this.footer.el && this.footer.xtype) {
31301 this.footer.container = this.grid.getView().getFooterPanel(true);
31302 this.footer.dataSource = this.grid.dataSource;
31303 this.footer = Roo.factory(this.footer, Roo);
31307 grid.monitorWindowResize = false; // turn off autosizing
31308 grid.autoHeight = false;
31309 grid.autoWidth = false;
31311 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31314 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31315 getId : function(){
31316 return this.grid.id;
31320 * Returns the grid for this panel
31321 * @return {Roo.grid.Grid}
31323 getGrid : function(){
31327 setSize : function(width, height){
31328 if(!this.ignoreResize(width, height)){
31329 var grid = this.grid;
31330 var size = this.adjustForComponents(width, height);
31331 grid.getGridEl().setSize(size.width, size.height);
31336 beforeSlide : function(){
31337 this.grid.getView().scroller.clip();
31340 afterSlide : function(){
31341 this.grid.getView().scroller.unclip();
31344 destroy : function(){
31345 this.grid.destroy();
31347 Roo.GridPanel.superclass.destroy.call(this);
31353 * @class Roo.NestedLayoutPanel
31354 * @extends Roo.ContentPanel
31356 * Create a new NestedLayoutPanel.
31359 * @param {Roo.BorderLayout} layout The layout for this panel
31360 * @param {String/Object} config A string to set only the title or a config object
31362 Roo.NestedLayoutPanel = function(layout, config)
31364 // construct with only one argument..
31365 /* FIXME - implement nicer consturctors
31366 if (layout.layout) {
31368 layout = config.layout;
31369 delete config.layout;
31371 if (layout.xtype && !layout.getEl) {
31372 // then layout needs constructing..
31373 layout = Roo.factory(layout, Roo);
31378 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31380 layout.monitorWindowResize = false; // turn off autosizing
31381 this.layout = layout;
31382 this.layout.getEl().addClass("x-layout-nested-layout");
31389 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31391 setSize : function(width, height){
31392 if(!this.ignoreResize(width, height)){
31393 var size = this.adjustForComponents(width, height);
31394 var el = this.layout.getEl();
31395 el.setSize(size.width, size.height);
31396 var touch = el.dom.offsetWidth;
31397 this.layout.layout();
31398 // ie requires a double layout on the first pass
31399 if(Roo.isIE && !this.initialized){
31400 this.initialized = true;
31401 this.layout.layout();
31406 // activate all subpanels if not currently active..
31408 setActiveState : function(active){
31409 this.active = active;
31411 this.fireEvent("deactivate", this);
31415 this.fireEvent("activate", this);
31416 // not sure if this should happen before or after..
31417 if (!this.layout) {
31418 return; // should not happen..
31421 for (var r in this.layout.regions) {
31422 reg = this.layout.getRegion(r);
31423 if (reg.getActivePanel()) {
31424 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31425 reg.setActivePanel(reg.getActivePanel());
31428 if (!reg.panels.length) {
31431 reg.showPanel(reg.getPanel(0));
31440 * Returns the nested BorderLayout for this panel
31441 * @return {Roo.BorderLayout}
31443 getLayout : function(){
31444 return this.layout;
31448 * Adds a xtype elements to the layout of the nested panel
31452 xtype : 'ContentPanel',
31459 xtype : 'NestedLayoutPanel',
31465 items : [ ... list of content panels or nested layout panels.. ]
31469 * @param {Object} cfg Xtype definition of item to add.
31471 addxtype : function(cfg) {
31472 return this.layout.addxtype(cfg);
31477 Roo.ScrollPanel = function(el, config, content){
31478 config = config || {};
31479 config.fitToFrame = true;
31480 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31482 this.el.dom.style.overflow = "hidden";
31483 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31484 this.el.removeClass("x-layout-inactive-content");
31485 this.el.on("mousewheel", this.onWheel, this);
31487 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31488 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31489 up.unselectable(); down.unselectable();
31490 up.on("click", this.scrollUp, this);
31491 down.on("click", this.scrollDown, this);
31492 up.addClassOnOver("x-scroller-btn-over");
31493 down.addClassOnOver("x-scroller-btn-over");
31494 up.addClassOnClick("x-scroller-btn-click");
31495 down.addClassOnClick("x-scroller-btn-click");
31496 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31498 this.resizeEl = this.el;
31499 this.el = wrap; this.up = up; this.down = down;
31502 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31504 wheelIncrement : 5,
31505 scrollUp : function(){
31506 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31509 scrollDown : function(){
31510 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31513 afterScroll : function(){
31514 var el = this.resizeEl;
31515 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31516 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31517 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31520 setSize : function(){
31521 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31522 this.afterScroll();
31525 onWheel : function(e){
31526 var d = e.getWheelDelta();
31527 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31528 this.afterScroll();
31532 setContent : function(content, loadScripts){
31533 this.resizeEl.update(content, loadScripts);
31547 * @class Roo.TreePanel
31548 * @extends Roo.ContentPanel
31550 * Create a new TreePanel. - defaults to fit/scoll contents.
31551 * @param {String/Object} config A string to set only the panel's title, or a config object
31552 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31554 Roo.TreePanel = function(config){
31555 var el = config.el;
31556 var tree = config.tree;
31557 delete config.tree;
31558 delete config.el; // hopefull!
31560 // wrapper for IE7 strict & safari scroll issue
31562 var treeEl = el.createChild();
31563 config.resizeEl = treeEl;
31567 Roo.TreePanel.superclass.constructor.call(this, el, config);
31570 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31571 //console.log(tree);
31572 this.on('activate', function()
31574 if (this.tree.rendered) {
31577 //console.log('render tree');
31578 this.tree.render();
31581 this.on('resize', function (cp, w, h) {
31582 this.tree.innerCt.setWidth(w);
31583 this.tree.innerCt.setHeight(h);
31584 this.tree.innerCt.setStyle('overflow-y', 'auto');
31591 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31608 * Ext JS Library 1.1.1
31609 * Copyright(c) 2006-2007, Ext JS, LLC.
31611 * Originally Released Under LGPL - original licence link has changed is not relivant.
31614 * <script type="text/javascript">
31619 * @class Roo.ReaderLayout
31620 * @extends Roo.BorderLayout
31621 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31622 * center region containing two nested regions (a top one for a list view and one for item preview below),
31623 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31624 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31625 * expedites the setup of the overall layout and regions for this common application style.
31628 var reader = new Roo.ReaderLayout();
31629 var CP = Roo.ContentPanel; // shortcut for adding
31631 reader.beginUpdate();
31632 reader.add("north", new CP("north", "North"));
31633 reader.add("west", new CP("west", {title: "West"}));
31634 reader.add("east", new CP("east", {title: "East"}));
31636 reader.regions.listView.add(new CP("listView", "List"));
31637 reader.regions.preview.add(new CP("preview", "Preview"));
31638 reader.endUpdate();
31641 * Create a new ReaderLayout
31642 * @param {Object} config Configuration options
31643 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31644 * document.body if omitted)
31646 Roo.ReaderLayout = function(config, renderTo){
31647 var c = config || {size:{}};
31648 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31649 north: c.north !== false ? Roo.apply({
31653 }, c.north) : false,
31654 west: c.west !== false ? Roo.apply({
31662 margins:{left:5,right:0,bottom:5,top:5},
31663 cmargins:{left:5,right:5,bottom:5,top:5}
31664 }, c.west) : false,
31665 east: c.east !== false ? Roo.apply({
31673 margins:{left:0,right:5,bottom:5,top:5},
31674 cmargins:{left:5,right:5,bottom:5,top:5}
31675 }, c.east) : false,
31676 center: Roo.apply({
31677 tabPosition: 'top',
31681 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31685 this.el.addClass('x-reader');
31687 this.beginUpdate();
31689 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31690 south: c.preview !== false ? Roo.apply({
31697 cmargins:{top:5,left:0, right:0, bottom:0}
31698 }, c.preview) : false,
31699 center: Roo.apply({
31705 this.add('center', new Roo.NestedLayoutPanel(inner,
31706 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31710 this.regions.preview = inner.getRegion('south');
31711 this.regions.listView = inner.getRegion('center');
31714 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31716 * Ext JS Library 1.1.1
31717 * Copyright(c) 2006-2007, Ext JS, LLC.
31719 * Originally Released Under LGPL - original licence link has changed is not relivant.
31722 * <script type="text/javascript">
31726 * @class Roo.grid.Grid
31727 * @extends Roo.util.Observable
31728 * This class represents the primary interface of a component based grid control.
31729 * <br><br>Usage:<pre><code>
31730 var grid = new Roo.grid.Grid("my-container-id", {
31733 selModel: mySelectionModel,
31734 autoSizeColumns: true,
31735 monitorWindowResize: false,
31736 trackMouseOver: true
31741 * <b>Common Problems:</b><br/>
31742 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
31743 * element will correct this<br/>
31744 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
31745 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
31746 * are unpredictable.<br/>
31747 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
31748 * grid to calculate dimensions/offsets.<br/>
31750 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
31751 * The container MUST have some type of size defined for the grid to fill. The container will be
31752 * automatically set to position relative if it isn't already.
31753 * @param {Object} config A config object that sets properties on this grid.
31755 Roo.grid.Grid = function(container, config){
31756 // initialize the container
31757 this.container = Roo.get(container);
31758 this.container.update("");
31759 this.container.setStyle("overflow", "hidden");
31760 this.container.addClass('x-grid-container');
31762 this.id = this.container.id;
31764 Roo.apply(this, config);
31765 // check and correct shorthanded configs
31767 this.dataSource = this.ds;
31771 this.colModel = this.cm;
31775 this.selModel = this.sm;
31779 if (this.selModel) {
31780 this.selModel = Roo.factory(this.selModel, Roo.grid);
31781 this.sm = this.selModel;
31782 this.sm.xmodule = this.xmodule || false;
31784 if (typeof(this.colModel.config) == 'undefined') {
31785 this.colModel = new Roo.grid.ColumnModel(this.colModel);
31786 this.cm = this.colModel;
31787 this.cm.xmodule = this.xmodule || false;
31789 if (this.dataSource) {
31790 this.dataSource= Roo.factory(this.dataSource, Roo.data);
31791 this.ds = this.dataSource;
31792 this.ds.xmodule = this.xmodule || false;
31799 this.container.setWidth(this.width);
31803 this.container.setHeight(this.height);
31810 * The raw click event for the entire grid.
31811 * @param {Roo.EventObject} e
31816 * The raw dblclick event for the entire grid.
31817 * @param {Roo.EventObject} e
31821 * @event contextmenu
31822 * The raw contextmenu event for the entire grid.
31823 * @param {Roo.EventObject} e
31825 "contextmenu" : true,
31828 * The raw mousedown event for the entire grid.
31829 * @param {Roo.EventObject} e
31831 "mousedown" : true,
31834 * The raw mouseup event for the entire grid.
31835 * @param {Roo.EventObject} e
31840 * The raw mouseover event for the entire grid.
31841 * @param {Roo.EventObject} e
31843 "mouseover" : true,
31846 * The raw mouseout event for the entire grid.
31847 * @param {Roo.EventObject} e
31852 * The raw keypress event for the entire grid.
31853 * @param {Roo.EventObject} e
31858 * The raw keydown event for the entire grid.
31859 * @param {Roo.EventObject} e
31867 * Fires when a cell is clicked
31868 * @param {Grid} this
31869 * @param {Number} rowIndex
31870 * @param {Number} columnIndex
31871 * @param {Roo.EventObject} e
31873 "cellclick" : true,
31875 * @event celldblclick
31876 * Fires when a cell is double clicked
31877 * @param {Grid} this
31878 * @param {Number} rowIndex
31879 * @param {Number} columnIndex
31880 * @param {Roo.EventObject} e
31882 "celldblclick" : true,
31885 * Fires when a row is clicked
31886 * @param {Grid} this
31887 * @param {Number} rowIndex
31888 * @param {Roo.EventObject} e
31892 * @event rowdblclick
31893 * Fires when a row is double clicked
31894 * @param {Grid} this
31895 * @param {Number} rowIndex
31896 * @param {Roo.EventObject} e
31898 "rowdblclick" : true,
31900 * @event headerclick
31901 * Fires when a header is clicked
31902 * @param {Grid} this
31903 * @param {Number} columnIndex
31904 * @param {Roo.EventObject} e
31906 "headerclick" : true,
31908 * @event headerdblclick
31909 * Fires when a header cell is double clicked
31910 * @param {Grid} this
31911 * @param {Number} columnIndex
31912 * @param {Roo.EventObject} e
31914 "headerdblclick" : true,
31916 * @event rowcontextmenu
31917 * Fires when a row is right clicked
31918 * @param {Grid} this
31919 * @param {Number} rowIndex
31920 * @param {Roo.EventObject} e
31922 "rowcontextmenu" : true,
31924 * @event cellcontextmenu
31925 * Fires when a cell is right clicked
31926 * @param {Grid} this
31927 * @param {Number} rowIndex
31928 * @param {Number} cellIndex
31929 * @param {Roo.EventObject} e
31931 "cellcontextmenu" : true,
31933 * @event headercontextmenu
31934 * Fires when a header is right clicked
31935 * @param {Grid} this
31936 * @param {Number} columnIndex
31937 * @param {Roo.EventObject} e
31939 "headercontextmenu" : true,
31941 * @event bodyscroll
31942 * Fires when the body element is scrolled
31943 * @param {Number} scrollLeft
31944 * @param {Number} scrollTop
31946 "bodyscroll" : true,
31948 * @event columnresize
31949 * Fires when the user resizes a column
31950 * @param {Number} columnIndex
31951 * @param {Number} newSize
31953 "columnresize" : true,
31955 * @event columnmove
31956 * Fires when the user moves a column
31957 * @param {Number} oldIndex
31958 * @param {Number} newIndex
31960 "columnmove" : true,
31963 * Fires when row(s) start being dragged
31964 * @param {Grid} this
31965 * @param {Roo.GridDD} dd The drag drop object
31966 * @param {event} e The raw browser event
31968 "startdrag" : true,
31971 * Fires when a drag operation is complete
31972 * @param {Grid} this
31973 * @param {Roo.GridDD} dd The drag drop object
31974 * @param {event} e The raw browser event
31979 * Fires when dragged row(s) are dropped on a valid DD target
31980 * @param {Grid} this
31981 * @param {Roo.GridDD} dd The drag drop object
31982 * @param {String} targetId The target drag drop object
31983 * @param {event} e The raw browser event
31988 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
31989 * @param {Grid} this
31990 * @param {Roo.GridDD} dd The drag drop object
31991 * @param {String} targetId The target drag drop object
31992 * @param {event} e The raw browser event
31997 * Fires when the dragged row(s) first cross another DD target while being dragged
31998 * @param {Grid} this
31999 * @param {Roo.GridDD} dd The drag drop object
32000 * @param {String} targetId The target drag drop object
32001 * @param {event} e The raw browser event
32003 "dragenter" : true,
32006 * Fires when the dragged row(s) leave another DD target while being dragged
32007 * @param {Grid} this
32008 * @param {Roo.GridDD} dd The drag drop object
32009 * @param {String} targetId The target drag drop object
32010 * @param {event} e The raw browser event
32015 * Fires when the grid is rendered
32016 * @param {Grid} grid
32021 Roo.grid.Grid.superclass.constructor.call(this);
32023 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32026 * @cfg {String} ddGroup - drag drop group.
32030 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32032 minColumnWidth : 25,
32035 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32036 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32037 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32039 autoSizeColumns : false,
32042 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32044 autoSizeHeaders : true,
32047 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32049 monitorWindowResize : true,
32052 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32053 * rows measured to get a columns size. Default is 0 (all rows).
32055 maxRowsToMeasure : 0,
32058 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32060 trackMouseOver : true,
32063 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32067 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32069 enableDragDrop : false,
32072 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32074 enableColumnMove : true,
32077 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32079 enableColumnHide : true,
32082 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32084 enableRowHeightSync : false,
32087 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32092 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32094 autoHeight : false,
32097 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
32099 autoExpandColumn : false,
32102 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32105 autoExpandMin : 50,
32108 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32110 autoExpandMax : 1000,
32113 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32118 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32122 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
32129 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32130 * of a fixed width. Default is false.
32133 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32136 * Called once after all setup has been completed and the grid is ready to be rendered.
32137 * @return {Roo.grid.Grid} this
32139 render : function(){
32140 var c = this.container;
32141 // try to detect autoHeight/width mode
32142 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32143 this.autoHeight = true;
32145 var view = this.getView();
32148 c.on("click", this.onClick, this);
32149 c.on("dblclick", this.onDblClick, this);
32150 c.on("contextmenu", this.onContextMenu, this);
32151 c.on("keydown", this.onKeyDown, this);
32153 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32155 this.getSelectionModel().init(this);
32160 this.loadMask = new Roo.LoadMask(this.container,
32161 Roo.apply({store:this.dataSource}, this.loadMask));
32165 if (this.toolbar && this.toolbar.xtype) {
32166 this.toolbar.container = this.getView().getHeaderPanel(true);
32167 this.toolbar = new Ext.Toolbar(this.toolbar);
32169 if (this.footer && this.footer.xtype) {
32170 this.footer.dataSource = this.getDataSource();
32171 this.footer.container = this.getView().getFooterPanel(true);
32172 this.footer = Roo.factory(this.footer, Roo);
32174 if (this.dropTarget && this.dropTarget.xtype) {
32175 delete this.dropTarget.xtype;
32176 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
32180 this.rendered = true;
32181 this.fireEvent('render', this);
32186 * Reconfigures the grid to use a different Store and Column Model.
32187 * The View will be bound to the new objects and refreshed.
32188 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32189 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32191 reconfigure : function(dataSource, colModel){
32193 this.loadMask.destroy();
32194 this.loadMask = new Roo.LoadMask(this.container,
32195 Roo.apply({store:dataSource}, this.loadMask));
32197 this.view.bind(dataSource, colModel);
32198 this.dataSource = dataSource;
32199 this.colModel = colModel;
32200 this.view.refresh(true);
32204 onKeyDown : function(e){
32205 this.fireEvent("keydown", e);
32209 * Destroy this grid.
32210 * @param {Boolean} removeEl True to remove the element
32212 destroy : function(removeEl, keepListeners){
32214 this.loadMask.destroy();
32216 var c = this.container;
32217 c.removeAllListeners();
32218 this.view.destroy();
32219 this.colModel.purgeListeners();
32220 if(!keepListeners){
32221 this.purgeListeners();
32224 if(removeEl === true){
32230 processEvent : function(name, e){
32231 this.fireEvent(name, e);
32232 var t = e.getTarget();
32234 var header = v.findHeaderIndex(t);
32235 if(header !== false){
32236 this.fireEvent("header" + name, this, header, e);
32238 var row = v.findRowIndex(t);
32239 var cell = v.findCellIndex(t);
32241 this.fireEvent("row" + name, this, row, e);
32242 if(cell !== false){
32243 this.fireEvent("cell" + name, this, row, cell, e);
32250 onClick : function(e){
32251 this.processEvent("click", e);
32255 onContextMenu : function(e, t){
32256 this.processEvent("contextmenu", e);
32260 onDblClick : function(e){
32261 this.processEvent("dblclick", e);
32265 walkCells : function(row, col, step, fn, scope){
32266 var cm = this.colModel, clen = cm.getColumnCount();
32267 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32279 if(fn.call(scope || this, row, col, cm) === true){
32297 if(fn.call(scope || this, row, col, cm) === true){
32309 getSelections : function(){
32310 return this.selModel.getSelections();
32314 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32315 * but if manual update is required this method will initiate it.
32317 autoSize : function(){
32319 this.view.layout();
32320 if(this.view.adjustForScroll){
32321 this.view.adjustForScroll();
32327 * Returns the grid's underlying element.
32328 * @return {Element} The element
32330 getGridEl : function(){
32331 return this.container;
32334 // private for compatibility, overridden by editor grid
32335 stopEditing : function(){},
32338 * Returns the grid's SelectionModel.
32339 * @return {SelectionModel}
32341 getSelectionModel : function(){
32342 if(!this.selModel){
32343 this.selModel = new Roo.grid.RowSelectionModel();
32345 return this.selModel;
32349 * Returns the grid's DataSource.
32350 * @return {DataSource}
32352 getDataSource : function(){
32353 return this.dataSource;
32357 * Returns the grid's ColumnModel.
32358 * @return {ColumnModel}
32360 getColumnModel : function(){
32361 return this.colModel;
32365 * Returns the grid's GridView object.
32366 * @return {GridView}
32368 getView : function(){
32370 this.view = new Roo.grid.GridView(this.viewConfig);
32375 * Called to get grid's drag proxy text, by default returns this.ddText.
32378 getDragDropText : function(){
32379 var count = this.selModel.getCount();
32380 return String.format(this.ddText, count, count == 1 ? '' : 's');
32384 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32385 * %0 is replaced with the number of selected rows.
32388 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32390 * Ext JS Library 1.1.1
32391 * Copyright(c) 2006-2007, Ext JS, LLC.
32393 * Originally Released Under LGPL - original licence link has changed is not relivant.
32396 * <script type="text/javascript">
32399 Roo.grid.AbstractGridView = function(){
32403 "beforerowremoved" : true,
32404 "beforerowsinserted" : true,
32405 "beforerefresh" : true,
32406 "rowremoved" : true,
32407 "rowsinserted" : true,
32408 "rowupdated" : true,
32411 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32414 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32415 rowClass : "x-grid-row",
32416 cellClass : "x-grid-cell",
32417 tdClass : "x-grid-td",
32418 hdClass : "x-grid-hd",
32419 splitClass : "x-grid-hd-split",
32421 init: function(grid){
32423 var cid = this.grid.getGridEl().id;
32424 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32425 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32426 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32427 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32430 getColumnRenderers : function(){
32431 var renderers = [];
32432 var cm = this.grid.colModel;
32433 var colCount = cm.getColumnCount();
32434 for(var i = 0; i < colCount; i++){
32435 renderers[i] = cm.getRenderer(i);
32440 getColumnIds : function(){
32442 var cm = this.grid.colModel;
32443 var colCount = cm.getColumnCount();
32444 for(var i = 0; i < colCount; i++){
32445 ids[i] = cm.getColumnId(i);
32450 getDataIndexes : function(){
32451 if(!this.indexMap){
32452 this.indexMap = this.buildIndexMap();
32454 return this.indexMap.colToData;
32457 getColumnIndexByDataIndex : function(dataIndex){
32458 if(!this.indexMap){
32459 this.indexMap = this.buildIndexMap();
32461 return this.indexMap.dataToCol[dataIndex];
32465 * Set a css style for a column dynamically.
32466 * @param {Number} colIndex The index of the column
32467 * @param {String} name The css property name
32468 * @param {String} value The css value
32470 setCSSStyle : function(colIndex, name, value){
32471 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32472 Roo.util.CSS.updateRule(selector, name, value);
32475 generateRules : function(cm){
32476 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32477 Roo.util.CSS.removeStyleSheet(rulesId);
32478 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32479 var cid = cm.getColumnId(i);
32480 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32481 this.tdSelector, cid, " {\n}\n",
32482 this.hdSelector, cid, " {\n}\n",
32483 this.splitSelector, cid, " {\n}\n");
32485 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32489 * Ext JS Library 1.1.1
32490 * Copyright(c) 2006-2007, Ext JS, LLC.
32492 * Originally Released Under LGPL - original licence link has changed is not relivant.
32495 * <script type="text/javascript">
32499 // This is a support class used internally by the Grid components
32500 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32502 this.view = grid.getView();
32503 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32504 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32506 this.setHandleElId(Roo.id(hd));
32507 this.setOuterHandleElId(Roo.id(hd2));
32509 this.scroll = false;
32511 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32513 getDragData : function(e){
32514 var t = Roo.lib.Event.getTarget(e);
32515 var h = this.view.findHeaderCell(t);
32517 return {ddel: h.firstChild, header:h};
32522 onInitDrag : function(e){
32523 this.view.headersDisabled = true;
32524 var clone = this.dragData.ddel.cloneNode(true);
32525 clone.id = Roo.id();
32526 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32527 this.proxy.update(clone);
32531 afterValidDrop : function(){
32533 setTimeout(function(){
32534 v.headersDisabled = false;
32538 afterInvalidDrop : function(){
32540 setTimeout(function(){
32541 v.headersDisabled = false;
32547 * Ext JS Library 1.1.1
32548 * Copyright(c) 2006-2007, Ext JS, LLC.
32550 * Originally Released Under LGPL - original licence link has changed is not relivant.
32553 * <script type="text/javascript">
32556 // This is a support class used internally by the Grid components
32557 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32559 this.view = grid.getView();
32560 // split the proxies so they don't interfere with mouse events
32561 this.proxyTop = Roo.DomHelper.append(document.body, {
32562 cls:"col-move-top", html:" "
32564 this.proxyBottom = Roo.DomHelper.append(document.body, {
32565 cls:"col-move-bottom", html:" "
32567 this.proxyTop.hide = this.proxyBottom.hide = function(){
32568 this.setLeftTop(-100,-100);
32569 this.setStyle("visibility", "hidden");
32571 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32572 // temporarily disabled
32573 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32574 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32576 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32577 proxyOffsets : [-4, -9],
32578 fly: Roo.Element.fly,
32580 getTargetFromEvent : function(e){
32581 var t = Roo.lib.Event.getTarget(e);
32582 var cindex = this.view.findCellIndex(t);
32583 if(cindex !== false){
32584 return this.view.getHeaderCell(cindex);
32588 nextVisible : function(h){
32589 var v = this.view, cm = this.grid.colModel;
32592 if(!cm.isHidden(v.getCellIndex(h))){
32600 prevVisible : function(h){
32601 var v = this.view, cm = this.grid.colModel;
32604 if(!cm.isHidden(v.getCellIndex(h))){
32612 positionIndicator : function(h, n, e){
32613 var x = Roo.lib.Event.getPageX(e);
32614 var r = Roo.lib.Dom.getRegion(n.firstChild);
32615 var px, pt, py = r.top + this.proxyOffsets[1];
32616 if((r.right - x) <= (r.right-r.left)/2){
32617 px = r.right+this.view.borderWidth;
32623 var oldIndex = this.view.getCellIndex(h);
32624 var newIndex = this.view.getCellIndex(n);
32626 if(this.grid.colModel.isFixed(newIndex)){
32630 var locked = this.grid.colModel.isLocked(newIndex);
32635 if(oldIndex < newIndex){
32638 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32641 px += this.proxyOffsets[0];
32642 this.proxyTop.setLeftTop(px, py);
32643 this.proxyTop.show();
32644 if(!this.bottomOffset){
32645 this.bottomOffset = this.view.mainHd.getHeight();
32647 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32648 this.proxyBottom.show();
32652 onNodeEnter : function(n, dd, e, data){
32653 if(data.header != n){
32654 this.positionIndicator(data.header, n, e);
32658 onNodeOver : function(n, dd, e, data){
32659 var result = false;
32660 if(data.header != n){
32661 result = this.positionIndicator(data.header, n, e);
32664 this.proxyTop.hide();
32665 this.proxyBottom.hide();
32667 return result ? this.dropAllowed : this.dropNotAllowed;
32670 onNodeOut : function(n, dd, e, data){
32671 this.proxyTop.hide();
32672 this.proxyBottom.hide();
32675 onNodeDrop : function(n, dd, e, data){
32676 var h = data.header;
32678 var cm = this.grid.colModel;
32679 var x = Roo.lib.Event.getPageX(e);
32680 var r = Roo.lib.Dom.getRegion(n.firstChild);
32681 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32682 var oldIndex = this.view.getCellIndex(h);
32683 var newIndex = this.view.getCellIndex(n);
32684 var locked = cm.isLocked(newIndex);
32688 if(oldIndex < newIndex){
32691 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32694 cm.setLocked(oldIndex, locked, true);
32695 cm.moveColumn(oldIndex, newIndex);
32696 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32704 * Ext JS Library 1.1.1
32705 * Copyright(c) 2006-2007, Ext JS, LLC.
32707 * Originally Released Under LGPL - original licence link has changed is not relivant.
32710 * <script type="text/javascript">
32714 * @class Roo.grid.GridView
32715 * @extends Roo.util.Observable
32718 * @param {Object} config
32720 Roo.grid.GridView = function(config){
32721 Roo.grid.GridView.superclass.constructor.call(this);
32724 Roo.apply(this, config);
32727 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
32730 * Override this function to apply custom css classes to rows during rendering
32731 * @param {Record} record The record
32732 * @param {Number} index
32733 * @method getRowClass
32735 rowClass : "x-grid-row",
32737 cellClass : "x-grid-col",
32739 tdClass : "x-grid-td",
32741 hdClass : "x-grid-hd",
32743 splitClass : "x-grid-split",
32745 sortClasses : ["sort-asc", "sort-desc"],
32747 enableMoveAnim : false,
32751 dh : Roo.DomHelper,
32753 fly : Roo.Element.fly,
32755 css : Roo.util.CSS,
32761 scrollIncrement : 22,
32763 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
32765 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
32767 bind : function(ds, cm){
32769 this.ds.un("load", this.onLoad, this);
32770 this.ds.un("datachanged", this.onDataChange, this);
32771 this.ds.un("add", this.onAdd, this);
32772 this.ds.un("remove", this.onRemove, this);
32773 this.ds.un("update", this.onUpdate, this);
32774 this.ds.un("clear", this.onClear, this);
32777 ds.on("load", this.onLoad, this);
32778 ds.on("datachanged", this.onDataChange, this);
32779 ds.on("add", this.onAdd, this);
32780 ds.on("remove", this.onRemove, this);
32781 ds.on("update", this.onUpdate, this);
32782 ds.on("clear", this.onClear, this);
32787 this.cm.un("widthchange", this.onColWidthChange, this);
32788 this.cm.un("headerchange", this.onHeaderChange, this);
32789 this.cm.un("hiddenchange", this.onHiddenChange, this);
32790 this.cm.un("columnmoved", this.onColumnMove, this);
32791 this.cm.un("columnlockchange", this.onColumnLock, this);
32794 this.generateRules(cm);
32795 cm.on("widthchange", this.onColWidthChange, this);
32796 cm.on("headerchange", this.onHeaderChange, this);
32797 cm.on("hiddenchange", this.onHiddenChange, this);
32798 cm.on("columnmoved", this.onColumnMove, this);
32799 cm.on("columnlockchange", this.onColumnLock, this);
32804 init: function(grid){
32805 Roo.grid.GridView.superclass.init.call(this, grid);
32807 this.bind(grid.dataSource, grid.colModel);
32809 grid.on("headerclick", this.handleHeaderClick, this);
32811 if(grid.trackMouseOver){
32812 grid.on("mouseover", this.onRowOver, this);
32813 grid.on("mouseout", this.onRowOut, this);
32815 grid.cancelTextSelection = function(){};
32816 this.gridId = grid.id;
32818 var tpls = this.templates || {};
32821 tpls.master = new Roo.Template(
32822 '<div class="x-grid" hidefocus="true">',
32823 '<div class="x-grid-topbar"></div>',
32824 '<div class="x-grid-scroller"><div></div></div>',
32825 '<div class="x-grid-locked">',
32826 '<div class="x-grid-header">{lockedHeader}</div>',
32827 '<div class="x-grid-body">{lockedBody}</div>',
32829 '<div class="x-grid-viewport">',
32830 '<div class="x-grid-header">{header}</div>',
32831 '<div class="x-grid-body">{body}</div>',
32833 '<div class="x-grid-bottombar"></div>',
32834 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
32835 '<div class="x-grid-resize-proxy"> </div>',
32838 tpls.master.disableformats = true;
32842 tpls.header = new Roo.Template(
32843 '<table border="0" cellspacing="0" cellpadding="0">',
32844 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
32847 tpls.header.disableformats = true;
32849 tpls.header.compile();
32852 tpls.hcell = new Roo.Template(
32853 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
32854 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
32857 tpls.hcell.disableFormats = true;
32859 tpls.hcell.compile();
32862 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
32863 tpls.hsplit.disableFormats = true;
32865 tpls.hsplit.compile();
32868 tpls.body = new Roo.Template(
32869 '<table border="0" cellspacing="0" cellpadding="0">',
32870 "<tbody>{rows}</tbody>",
32873 tpls.body.disableFormats = true;
32875 tpls.body.compile();
32878 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
32879 tpls.row.disableFormats = true;
32881 tpls.row.compile();
32884 tpls.cell = new Roo.Template(
32885 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
32886 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
32889 tpls.cell.disableFormats = true;
32891 tpls.cell.compile();
32893 this.templates = tpls;
32896 // remap these for backwards compat
32897 onColWidthChange : function(){
32898 this.updateColumns.apply(this, arguments);
32900 onHeaderChange : function(){
32901 this.updateHeaders.apply(this, arguments);
32903 onHiddenChange : function(){
32904 this.handleHiddenChange.apply(this, arguments);
32906 onColumnMove : function(){
32907 this.handleColumnMove.apply(this, arguments);
32909 onColumnLock : function(){
32910 this.handleLockChange.apply(this, arguments);
32913 onDataChange : function(){
32915 this.updateHeaderSortState();
32918 onClear : function(){
32922 onUpdate : function(ds, record){
32923 this.refreshRow(record);
32926 refreshRow : function(record){
32927 var ds = this.ds, index;
32928 if(typeof record == 'number'){
32930 record = ds.getAt(index);
32932 index = ds.indexOf(record);
32934 this.insertRows(ds, index, index, true);
32935 this.onRemove(ds, record, index+1, true);
32936 this.syncRowHeights(index, index);
32938 this.fireEvent("rowupdated", this, index, record);
32941 onAdd : function(ds, records, index){
32942 this.insertRows(ds, index, index + (records.length-1));
32945 onRemove : function(ds, record, index, isUpdate){
32946 if(isUpdate !== true){
32947 this.fireEvent("beforerowremoved", this, index, record);
32949 var bt = this.getBodyTable(), lt = this.getLockedTable();
32950 if(bt.rows[index]){
32951 bt.firstChild.removeChild(bt.rows[index]);
32953 if(lt.rows[index]){
32954 lt.firstChild.removeChild(lt.rows[index]);
32956 if(isUpdate !== true){
32957 this.stripeRows(index);
32958 this.syncRowHeights(index, index);
32960 this.fireEvent("rowremoved", this, index, record);
32964 onLoad : function(){
32965 this.scrollToTop();
32969 * Scrolls the grid to the top
32971 scrollToTop : function(){
32973 this.scroller.dom.scrollTop = 0;
32979 * Gets a panel in the header of the grid that can be used for toolbars etc.
32980 * After modifying the contents of this panel a call to grid.autoSize() may be
32981 * required to register any changes in size.
32982 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
32983 * @return Roo.Element
32985 getHeaderPanel : function(doShow){
32987 this.headerPanel.show();
32989 return this.headerPanel;
32993 * Gets a panel in the footer of the grid that can be used for toolbars etc.
32994 * After modifying the contents of this panel a call to grid.autoSize() may be
32995 * required to register any changes in size.
32996 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
32997 * @return Roo.Element
32999 getFooterPanel : function(doShow){
33001 this.footerPanel.show();
33003 return this.footerPanel;
33006 initElements : function(){
33007 var E = Roo.Element;
33008 var el = this.grid.getGridEl().dom.firstChild;
33009 var cs = el.childNodes;
33011 this.el = new E(el);
33012 this.headerPanel = new E(el.firstChild);
33013 this.headerPanel.enableDisplayMode("block");
33015 this.scroller = new E(cs[1]);
33016 this.scrollSizer = new E(this.scroller.dom.firstChild);
33018 this.lockedWrap = new E(cs[2]);
33019 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33020 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33022 this.mainWrap = new E(cs[3]);
33023 this.mainHd = new E(this.mainWrap.dom.firstChild);
33024 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33026 this.footerPanel = new E(cs[4]);
33027 this.footerPanel.enableDisplayMode("block");
33029 this.focusEl = new E(cs[5]);
33030 this.focusEl.swallowEvent("click", true);
33031 this.resizeProxy = new E(cs[6]);
33033 this.headerSelector = String.format(
33034 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33035 this.lockedHd.id, this.mainHd.id
33038 this.splitterSelector = String.format(
33039 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33040 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33043 idToCssName : function(s)
33045 return s.replace(/[^a-z0-9]+/ig, '-');
33048 getHeaderCell : function(index){
33049 return Roo.DomQuery.select(this.headerSelector)[index];
33052 getHeaderCellMeasure : function(index){
33053 return this.getHeaderCell(index).firstChild;
33056 getHeaderCellText : function(index){
33057 return this.getHeaderCell(index).firstChild.firstChild;
33060 getLockedTable : function(){
33061 return this.lockedBody.dom.firstChild;
33064 getBodyTable : function(){
33065 return this.mainBody.dom.firstChild;
33068 getLockedRow : function(index){
33069 return this.getLockedTable().rows[index];
33072 getRow : function(index){
33073 return this.getBodyTable().rows[index];
33076 getRowComposite : function(index){
33078 this.rowEl = new Roo.CompositeElementLite();
33080 var els = [], lrow, mrow;
33081 if(lrow = this.getLockedRow(index)){
33084 if(mrow = this.getRow(index)){
33087 this.rowEl.elements = els;
33091 getCell : function(rowIndex, colIndex){
33092 var locked = this.cm.getLockedCount();
33094 if(colIndex < locked){
33095 source = this.lockedBody.dom.firstChild;
33097 source = this.mainBody.dom.firstChild;
33098 colIndex -= locked;
33100 return source.rows[rowIndex].childNodes[colIndex];
33103 getCellText : function(rowIndex, colIndex){
33104 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33107 getCellBox : function(cell){
33108 var b = this.fly(cell).getBox();
33109 if(Roo.isOpera){ // opera fails to report the Y
33110 b.y = cell.offsetTop + this.mainBody.getY();
33115 getCellIndex : function(cell){
33116 var id = String(cell.className).match(this.cellRE);
33118 return parseInt(id[1], 10);
33123 findHeaderIndex : function(n){
33124 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33125 return r ? this.getCellIndex(r) : false;
33128 findHeaderCell : function(n){
33129 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33130 return r ? r : false;
33133 findRowIndex : function(n){
33137 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33138 return r ? r.rowIndex : false;
33141 findCellIndex : function(node){
33142 var stop = this.el.dom;
33143 while(node && node != stop){
33144 if(this.findRE.test(node.className)){
33145 return this.getCellIndex(node);
33147 node = node.parentNode;
33152 getColumnId : function(index){
33153 return this.cm.getColumnId(index);
33156 getSplitters : function(){
33157 if(this.splitterSelector){
33158 return Roo.DomQuery.select(this.splitterSelector);
33164 getSplitter : function(index){
33165 return this.getSplitters()[index];
33168 onRowOver : function(e, t){
33170 if((row = this.findRowIndex(t)) !== false){
33171 this.getRowComposite(row).addClass("x-grid-row-over");
33175 onRowOut : function(e, t){
33177 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33178 this.getRowComposite(row).removeClass("x-grid-row-over");
33182 renderHeaders : function(){
33184 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33185 var cb = [], lb = [], sb = [], lsb = [], p = {};
33186 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33187 p.cellId = "x-grid-hd-0-" + i;
33188 p.splitId = "x-grid-csplit-0-" + i;
33189 p.id = cm.getColumnId(i);
33190 p.title = cm.getColumnTooltip(i) || "";
33191 p.value = cm.getColumnHeader(i) || "";
33192 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33193 if(!cm.isLocked(i)){
33194 cb[cb.length] = ct.apply(p);
33195 sb[sb.length] = st.apply(p);
33197 lb[lb.length] = ct.apply(p);
33198 lsb[lsb.length] = st.apply(p);
33201 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33202 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33205 updateHeaders : function(){
33206 var html = this.renderHeaders();
33207 this.lockedHd.update(html[0]);
33208 this.mainHd.update(html[1]);
33212 * Focuses the specified row.
33213 * @param {Number} row The row index
33215 focusRow : function(row){
33216 var x = this.scroller.dom.scrollLeft;
33217 this.focusCell(row, 0, false);
33218 this.scroller.dom.scrollLeft = x;
33222 * Focuses the specified cell.
33223 * @param {Number} row The row index
33224 * @param {Number} col The column index
33225 * @param {Boolean} hscroll false to disable horizontal scrolling
33227 focusCell : function(row, col, hscroll){
33228 var el = this.ensureVisible(row, col, hscroll);
33229 this.focusEl.alignTo(el, "tl-tl");
33231 this.focusEl.focus();
33233 this.focusEl.focus.defer(1, this.focusEl);
33238 * Scrolls the specified cell into view
33239 * @param {Number} row The row index
33240 * @param {Number} col The column index
33241 * @param {Boolean} hscroll false to disable horizontal scrolling
33243 ensureVisible : function(row, col, hscroll){
33244 if(typeof row != "number"){
33245 row = row.rowIndex;
33247 if(row < 0 && row >= this.ds.getCount()){
33250 col = (col !== undefined ? col : 0);
33251 var cm = this.grid.colModel;
33252 while(cm.isHidden(col)){
33256 var el = this.getCell(row, col);
33260 var c = this.scroller.dom;
33262 var ctop = parseInt(el.offsetTop, 10);
33263 var cleft = parseInt(el.offsetLeft, 10);
33264 var cbot = ctop + el.offsetHeight;
33265 var cright = cleft + el.offsetWidth;
33267 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33268 var stop = parseInt(c.scrollTop, 10);
33269 var sleft = parseInt(c.scrollLeft, 10);
33270 var sbot = stop + ch;
33271 var sright = sleft + c.clientWidth;
33274 c.scrollTop = ctop;
33275 }else if(cbot > sbot){
33276 c.scrollTop = cbot-ch;
33279 if(hscroll !== false){
33281 c.scrollLeft = cleft;
33282 }else if(cright > sright){
33283 c.scrollLeft = cright-c.clientWidth;
33289 updateColumns : function(){
33290 this.grid.stopEditing();
33291 var cm = this.grid.colModel, colIds = this.getColumnIds();
33292 //var totalWidth = cm.getTotalWidth();
33294 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33295 //if(cm.isHidden(i)) continue;
33296 var w = cm.getColumnWidth(i);
33297 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33298 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33300 this.updateSplitters();
33303 generateRules : function(cm){
33304 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33305 Roo.util.CSS.removeStyleSheet(rulesId);
33306 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33307 var cid = cm.getColumnId(i);
33309 if(cm.config[i].align){
33310 align = 'text-align:'+cm.config[i].align+';';
33313 if(cm.isHidden(i)){
33314 hidden = 'display:none;';
33316 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33318 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33319 this.hdSelector, cid, " {\n", align, width, "}\n",
33320 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33321 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33323 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33326 updateSplitters : function(){
33327 var cm = this.cm, s = this.getSplitters();
33328 if(s){ // splitters not created yet
33329 var pos = 0, locked = true;
33330 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33331 if(cm.isHidden(i)) continue;
33332 var w = cm.getColumnWidth(i);
33333 if(!cm.isLocked(i) && locked){
33338 s[i].style.left = (pos-this.splitOffset) + "px";
33343 handleHiddenChange : function(colModel, colIndex, hidden){
33345 this.hideColumn(colIndex);
33347 this.unhideColumn(colIndex);
33351 hideColumn : function(colIndex){
33352 var cid = this.getColumnId(colIndex);
33353 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33354 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33356 this.updateHeaders();
33358 this.updateSplitters();
33362 unhideColumn : function(colIndex){
33363 var cid = this.getColumnId(colIndex);
33364 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33365 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33368 this.updateHeaders();
33370 this.updateSplitters();
33374 insertRows : function(dm, firstRow, lastRow, isUpdate){
33375 if(firstRow == 0 && lastRow == dm.getCount()-1){
33379 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33381 var s = this.getScrollState();
33382 var markup = this.renderRows(firstRow, lastRow);
33383 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33384 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33385 this.restoreScroll(s);
33387 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33388 this.syncRowHeights(firstRow, lastRow);
33389 this.stripeRows(firstRow);
33395 bufferRows : function(markup, target, index){
33396 var before = null, trows = target.rows, tbody = target.tBodies[0];
33397 if(index < trows.length){
33398 before = trows[index];
33400 var b = document.createElement("div");
33401 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33402 var rows = b.firstChild.rows;
33403 for(var i = 0, len = rows.length; i < len; i++){
33405 tbody.insertBefore(rows[0], before);
33407 tbody.appendChild(rows[0]);
33414 deleteRows : function(dm, firstRow, lastRow){
33415 if(dm.getRowCount()<1){
33416 this.fireEvent("beforerefresh", this);
33417 this.mainBody.update("");
33418 this.lockedBody.update("");
33419 this.fireEvent("refresh", this);
33421 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33422 var bt = this.getBodyTable();
33423 var tbody = bt.firstChild;
33424 var rows = bt.rows;
33425 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33426 tbody.removeChild(rows[firstRow]);
33428 this.stripeRows(firstRow);
33429 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33433 updateRows : function(dataSource, firstRow, lastRow){
33434 var s = this.getScrollState();
33436 this.restoreScroll(s);
33439 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33443 this.updateHeaderSortState();
33446 getScrollState : function(){
33447 var sb = this.scroller.dom;
33448 return {left: sb.scrollLeft, top: sb.scrollTop};
33451 stripeRows : function(startRow){
33452 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33455 startRow = startRow || 0;
33456 var rows = this.getBodyTable().rows;
33457 var lrows = this.getLockedTable().rows;
33458 var cls = ' x-grid-row-alt ';
33459 for(var i = startRow, len = rows.length; i < len; i++){
33460 var row = rows[i], lrow = lrows[i];
33461 var isAlt = ((i+1) % 2 == 0);
33462 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33463 if(isAlt == hasAlt){
33467 row.className += " x-grid-row-alt";
33469 row.className = row.className.replace("x-grid-row-alt", "");
33472 lrow.className = row.className;
33477 restoreScroll : function(state){
33478 var sb = this.scroller.dom;
33479 sb.scrollLeft = state.left;
33480 sb.scrollTop = state.top;
33484 syncScroll : function(){
33485 var sb = this.scroller.dom;
33486 var sh = this.mainHd.dom;
33487 var bs = this.mainBody.dom;
33488 var lv = this.lockedBody.dom;
33489 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33490 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33493 handleScroll : function(e){
33495 var sb = this.scroller.dom;
33496 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33500 handleWheel : function(e){
33501 var d = e.getWheelDelta();
33502 this.scroller.dom.scrollTop -= d*22;
33503 // set this here to prevent jumpy scrolling on large tables
33504 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33508 renderRows : function(startRow, endRow){
33509 // pull in all the crap needed to render rows
33510 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33511 var colCount = cm.getColumnCount();
33513 if(ds.getCount() < 1){
33517 // build a map for all the columns
33519 for(var i = 0; i < colCount; i++){
33520 var name = cm.getDataIndex(i);
33522 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33523 renderer : cm.getRenderer(i),
33524 id : cm.getColumnId(i),
33525 locked : cm.isLocked(i)
33529 startRow = startRow || 0;
33530 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33532 // records to render
33533 var rs = ds.getRange(startRow, endRow);
33535 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33538 // As much as I hate to duplicate code, this was branched because FireFox really hates
33539 // [].join("") on strings. The performance difference was substantial enough to
33540 // branch this function
33541 doRender : Roo.isGecko ?
33542 function(cs, rs, ds, startRow, colCount, stripe){
33543 var ts = this.templates, ct = ts.cell, rt = ts.row;
33545 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33546 for(var j = 0, len = rs.length; j < len; j++){
33547 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33548 for(var i = 0; i < colCount; i++){
33550 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33552 p.css = p.attr = "";
33553 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33554 if(p.value == undefined || p.value === "") p.value = " ";
33555 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33556 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33558 var markup = ct.apply(p);
33566 if(stripe && ((rowIndex+1) % 2 == 0)){
33567 alt[0] = "x-grid-row-alt";
33570 alt[1] = " x-grid-dirty-row";
33573 if(this.getRowClass){
33574 alt[2] = this.getRowClass(r, rowIndex);
33576 rp.alt = alt.join(" ");
33577 lbuf+= rt.apply(rp);
33579 buf+= rt.apply(rp);
33581 return [lbuf, buf];
33583 function(cs, rs, ds, startRow, colCount, stripe){
33584 var ts = this.templates, ct = ts.cell, rt = ts.row;
33586 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33587 for(var j = 0, len = rs.length; j < len; j++){
33588 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33589 for(var i = 0; i < colCount; i++){
33591 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33593 p.css = p.attr = "";
33594 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33595 if(p.value == undefined || p.value === "") p.value = " ";
33596 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33597 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33599 var markup = ct.apply(p);
33601 cb[cb.length] = markup;
33603 lcb[lcb.length] = markup;
33607 if(stripe && ((rowIndex+1) % 2 == 0)){
33608 alt[0] = "x-grid-row-alt";
33611 alt[1] = " x-grid-dirty-row";
33614 if(this.getRowClass){
33615 alt[2] = this.getRowClass(r, rowIndex);
33617 rp.alt = alt.join(" ");
33618 rp.cells = lcb.join("");
33619 lbuf[lbuf.length] = rt.apply(rp);
33620 rp.cells = cb.join("");
33621 buf[buf.length] = rt.apply(rp);
33623 return [lbuf.join(""), buf.join("")];
33626 renderBody : function(){
33627 var markup = this.renderRows();
33628 var bt = this.templates.body;
33629 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33633 * Refreshes the grid
33634 * @param {Boolean} headersToo
33636 refresh : function(headersToo){
33637 this.fireEvent("beforerefresh", this);
33638 this.grid.stopEditing();
33639 var result = this.renderBody();
33640 this.lockedBody.update(result[0]);
33641 this.mainBody.update(result[1]);
33642 if(headersToo === true){
33643 this.updateHeaders();
33644 this.updateColumns();
33645 this.updateSplitters();
33646 this.updateHeaderSortState();
33648 this.syncRowHeights();
33650 this.fireEvent("refresh", this);
33653 handleColumnMove : function(cm, oldIndex, newIndex){
33654 this.indexMap = null;
33655 var s = this.getScrollState();
33656 this.refresh(true);
33657 this.restoreScroll(s);
33658 this.afterMove(newIndex);
33661 afterMove : function(colIndex){
33662 if(this.enableMoveAnim && Roo.enableFx){
33663 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
33667 updateCell : function(dm, rowIndex, dataIndex){
33668 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
33669 if(typeof colIndex == "undefined"){ // not present in grid
33672 var cm = this.grid.colModel;
33673 var cell = this.getCell(rowIndex, colIndex);
33674 var cellText = this.getCellText(rowIndex, colIndex);
33677 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
33678 id : cm.getColumnId(colIndex),
33679 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
33681 var renderer = cm.getRenderer(colIndex);
33682 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
33683 if(typeof val == "undefined" || val === "") val = " ";
33684 cellText.innerHTML = val;
33685 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
33686 this.syncRowHeights(rowIndex, rowIndex);
33689 calcColumnWidth : function(colIndex, maxRowsToMeasure){
33691 if(this.grid.autoSizeHeaders){
33692 var h = this.getHeaderCellMeasure(colIndex);
33693 maxWidth = Math.max(maxWidth, h.scrollWidth);
33696 if(this.cm.isLocked(colIndex)){
33697 tb = this.getLockedTable();
33700 tb = this.getBodyTable();
33701 index = colIndex - this.cm.getLockedCount();
33704 var rows = tb.rows;
33705 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
33706 for(var i = 0; i < stopIndex; i++){
33707 var cell = rows[i].childNodes[index].firstChild;
33708 maxWidth = Math.max(maxWidth, cell.scrollWidth);
33711 return maxWidth + /*margin for error in IE*/ 5;
33714 * Autofit a column to its content.
33715 * @param {Number} colIndex
33716 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
33718 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
33719 if(this.cm.isHidden(colIndex)){
33720 return; // can't calc a hidden column
33723 var cid = this.cm.getColumnId(colIndex);
33724 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
33725 if(this.grid.autoSizeHeaders){
33726 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
33729 var newWidth = this.calcColumnWidth(colIndex);
33730 this.cm.setColumnWidth(colIndex,
33731 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
33732 if(!suppressEvent){
33733 this.grid.fireEvent("columnresize", colIndex, newWidth);
33738 * Autofits all columns to their content and then expands to fit any extra space in the grid
33740 autoSizeColumns : function(){
33741 var cm = this.grid.colModel;
33742 var colCount = cm.getColumnCount();
33743 for(var i = 0; i < colCount; i++){
33744 this.autoSizeColumn(i, true, true);
33746 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
33749 this.updateColumns();
33755 * Autofits all columns to the grid's width proportionate with their current size
33756 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
33758 fitColumns : function(reserveScrollSpace){
33759 var cm = this.grid.colModel;
33760 var colCount = cm.getColumnCount();
33764 for (i = 0; i < colCount; i++){
33765 if(!cm.isHidden(i) && !cm.isFixed(i)){
33766 w = cm.getColumnWidth(i);
33772 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
33773 if(reserveScrollSpace){
33776 var frac = (avail - cm.getTotalWidth())/width;
33777 while (cols.length){
33780 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
33782 this.updateColumns();
33786 onRowSelect : function(rowIndex){
33787 var row = this.getRowComposite(rowIndex);
33788 row.addClass("x-grid-row-selected");
33791 onRowDeselect : function(rowIndex){
33792 var row = this.getRowComposite(rowIndex);
33793 row.removeClass("x-grid-row-selected");
33796 onCellSelect : function(row, col){
33797 var cell = this.getCell(row, col);
33799 Roo.fly(cell).addClass("x-grid-cell-selected");
33803 onCellDeselect : function(row, col){
33804 var cell = this.getCell(row, col);
33806 Roo.fly(cell).removeClass("x-grid-cell-selected");
33810 updateHeaderSortState : function(){
33811 var state = this.ds.getSortState();
33815 this.sortState = state;
33816 var sortColumn = this.cm.findColumnIndex(state.field);
33817 if(sortColumn != -1){
33818 var sortDir = state.direction;
33819 var sc = this.sortClasses;
33820 var hds = this.el.select(this.headerSelector).removeClass(sc);
33821 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
33825 handleHeaderClick : function(g, index){
33826 if(this.headersDisabled){
33829 var dm = g.dataSource, cm = g.colModel;
33830 if(!cm.isSortable(index)){
33834 dm.sort(cm.getDataIndex(index));
33838 destroy : function(){
33840 this.colMenu.removeAll();
33841 Roo.menu.MenuMgr.unregister(this.colMenu);
33842 this.colMenu.getEl().remove();
33843 delete this.colMenu;
33846 this.hmenu.removeAll();
33847 Roo.menu.MenuMgr.unregister(this.hmenu);
33848 this.hmenu.getEl().remove();
33851 if(this.grid.enableColumnMove){
33852 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33854 for(var dd in dds){
33855 if(!dds[dd].config.isTarget && dds[dd].dragElId){
33856 var elid = dds[dd].dragElId;
33858 Roo.get(elid).remove();
33859 } else if(dds[dd].config.isTarget){
33860 dds[dd].proxyTop.remove();
33861 dds[dd].proxyBottom.remove();
33864 if(Roo.dd.DDM.locationCache[dd]){
33865 delete Roo.dd.DDM.locationCache[dd];
33868 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33871 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
33872 this.bind(null, null);
33873 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
33876 handleLockChange : function(){
33877 this.refresh(true);
33880 onDenyColumnLock : function(){
33884 onDenyColumnHide : function(){
33888 handleHdMenuClick : function(item){
33889 var index = this.hdCtxIndex;
33890 var cm = this.cm, ds = this.ds;
33893 ds.sort(cm.getDataIndex(index), "ASC");
33896 ds.sort(cm.getDataIndex(index), "DESC");
33899 var lc = cm.getLockedCount();
33900 if(cm.getColumnCount(true) <= lc+1){
33901 this.onDenyColumnLock();
33905 cm.setLocked(index, true, true);
33906 cm.moveColumn(index, lc);
33907 this.grid.fireEvent("columnmove", index, lc);
33909 cm.setLocked(index, true);
33913 var lc = cm.getLockedCount();
33914 if((lc-1) != index){
33915 cm.setLocked(index, false, true);
33916 cm.moveColumn(index, lc-1);
33917 this.grid.fireEvent("columnmove", index, lc-1);
33919 cm.setLocked(index, false);
33923 index = cm.getIndexById(item.id.substr(4));
33925 if(item.checked && cm.getColumnCount(true) <= 1){
33926 this.onDenyColumnHide();
33929 cm.setHidden(index, item.checked);
33935 beforeColMenuShow : function(){
33936 var cm = this.cm, colCount = cm.getColumnCount();
33937 this.colMenu.removeAll();
33938 for(var i = 0; i < colCount; i++){
33939 this.colMenu.add(new Roo.menu.CheckItem({
33940 id: "col-"+cm.getColumnId(i),
33941 text: cm.getColumnHeader(i),
33942 checked: !cm.isHidden(i),
33948 handleHdCtx : function(g, index, e){
33950 var hd = this.getHeaderCell(index);
33951 this.hdCtxIndex = index;
33952 var ms = this.hmenu.items, cm = this.cm;
33953 ms.get("asc").setDisabled(!cm.isSortable(index));
33954 ms.get("desc").setDisabled(!cm.isSortable(index));
33955 if(this.grid.enableColLock !== false){
33956 ms.get("lock").setDisabled(cm.isLocked(index));
33957 ms.get("unlock").setDisabled(!cm.isLocked(index));
33959 this.hmenu.show(hd, "tl-bl");
33962 handleHdOver : function(e){
33963 var hd = this.findHeaderCell(e.getTarget());
33964 if(hd && !this.headersDisabled){
33965 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
33966 this.fly(hd).addClass("x-grid-hd-over");
33971 handleHdOut : function(e){
33972 var hd = this.findHeaderCell(e.getTarget());
33974 this.fly(hd).removeClass("x-grid-hd-over");
33978 handleSplitDblClick : function(e, t){
33979 var i = this.getCellIndex(t);
33980 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
33981 this.autoSizeColumn(i, true);
33986 render : function(){
33989 var colCount = cm.getColumnCount();
33991 if(this.grid.monitorWindowResize === true){
33992 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33994 var header = this.renderHeaders();
33995 var body = this.templates.body.apply({rows:""});
33996 var html = this.templates.master.apply({
33999 lockedHeader: header[0],
34003 //this.updateColumns();
34005 this.grid.getGridEl().dom.innerHTML = html;
34007 this.initElements();
34009 // a kludge to fix the random scolling effect in webkit
34010 this.el.on("scroll", function() {
34011 this.el.dom.scrollTop=0; // hopefully not recursive..
34014 this.scroller.on("scroll", this.handleScroll, this);
34015 this.lockedBody.on("mousewheel", this.handleWheel, this);
34016 this.mainBody.on("mousewheel", this.handleWheel, this);
34018 this.mainHd.on("mouseover", this.handleHdOver, this);
34019 this.mainHd.on("mouseout", this.handleHdOut, this);
34020 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34021 {delegate: "."+this.splitClass});
34023 this.lockedHd.on("mouseover", this.handleHdOver, this);
34024 this.lockedHd.on("mouseout", this.handleHdOut, this);
34025 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34026 {delegate: "."+this.splitClass});
34028 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34029 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34032 this.updateSplitters();
34034 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34035 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34036 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34039 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34040 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34042 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34043 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34045 if(this.grid.enableColLock !== false){
34046 this.hmenu.add('-',
34047 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34048 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34051 if(this.grid.enableColumnHide !== false){
34053 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34054 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34055 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34057 this.hmenu.add('-',
34058 {id:"columns", text: this.columnsText, menu: this.colMenu}
34061 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34063 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34066 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34067 this.dd = new Roo.grid.GridDragZone(this.grid, {
34068 ddGroup : this.grid.ddGroup || 'GridDD'
34073 for(var i = 0; i < colCount; i++){
34074 if(cm.isHidden(i)){
34075 this.hideColumn(i);
34077 if(cm.config[i].align){
34078 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34079 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34083 this.updateHeaderSortState();
34085 this.beforeInitialResize();
34088 // two part rendering gives faster view to the user
34089 this.renderPhase2.defer(1, this);
34092 renderPhase2 : function(){
34093 // render the rows now
34095 if(this.grid.autoSizeColumns){
34096 this.autoSizeColumns();
34100 beforeInitialResize : function(){
34104 onColumnSplitterMoved : function(i, w){
34105 this.userResized = true;
34106 var cm = this.grid.colModel;
34107 cm.setColumnWidth(i, w, true);
34108 var cid = cm.getColumnId(i);
34109 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34110 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34111 this.updateSplitters();
34113 this.grid.fireEvent("columnresize", i, w);
34116 syncRowHeights : function(startIndex, endIndex){
34117 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34118 startIndex = startIndex || 0;
34119 var mrows = this.getBodyTable().rows;
34120 var lrows = this.getLockedTable().rows;
34121 var len = mrows.length-1;
34122 endIndex = Math.min(endIndex || len, len);
34123 for(var i = startIndex; i <= endIndex; i++){
34124 var m = mrows[i], l = lrows[i];
34125 var h = Math.max(m.offsetHeight, l.offsetHeight);
34126 m.style.height = l.style.height = h + "px";
34131 layout : function(initialRender, is2ndPass){
34133 var auto = g.autoHeight;
34134 var scrollOffset = 16;
34135 var c = g.getGridEl(), cm = this.cm,
34136 expandCol = g.autoExpandColumn,
34138 //c.beginMeasure();
34140 if(!c.dom.offsetWidth){ // display:none?
34142 this.lockedWrap.show();
34143 this.mainWrap.show();
34148 var hasLock = this.cm.isLocked(0);
34150 var tbh = this.headerPanel.getHeight();
34151 var bbh = this.footerPanel.getHeight();
34154 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34155 var newHeight = ch + c.getBorderWidth("tb");
34157 newHeight = Math.min(g.maxHeight, newHeight);
34159 c.setHeight(newHeight);
34163 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34166 var s = this.scroller;
34168 var csize = c.getSize(true);
34170 this.el.setSize(csize.width, csize.height);
34172 this.headerPanel.setWidth(csize.width);
34173 this.footerPanel.setWidth(csize.width);
34175 var hdHeight = this.mainHd.getHeight();
34176 var vw = csize.width;
34177 var vh = csize.height - (tbh + bbh);
34181 var bt = this.getBodyTable();
34182 var ltWidth = hasLock ?
34183 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34185 var scrollHeight = bt.offsetHeight;
34186 var scrollWidth = ltWidth + bt.offsetWidth;
34187 var vscroll = false, hscroll = false;
34189 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34191 var lw = this.lockedWrap, mw = this.mainWrap;
34192 var lb = this.lockedBody, mb = this.mainBody;
34194 setTimeout(function(){
34195 var t = s.dom.offsetTop;
34196 var w = s.dom.clientWidth,
34197 h = s.dom.clientHeight;
34200 lw.setSize(ltWidth, h);
34202 mw.setLeftTop(ltWidth, t);
34203 mw.setSize(w-ltWidth, h);
34205 lb.setHeight(h-hdHeight);
34206 mb.setHeight(h-hdHeight);
34208 if(is2ndPass !== true && !gv.userResized && expandCol){
34209 // high speed resize without full column calculation
34211 var ci = cm.getIndexById(expandCol);
34213 ci = cm.findColumnIndex(expandCol);
34215 ci = Math.max(0, ci); // make sure it's got at least the first col.
34216 var expandId = cm.getColumnId(ci);
34217 var tw = cm.getTotalWidth(false);
34218 var currentWidth = cm.getColumnWidth(ci);
34219 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34220 if(currentWidth != cw){
34221 cm.setColumnWidth(ci, cw, true);
34222 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34223 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34224 gv.updateSplitters();
34225 gv.layout(false, true);
34237 onWindowResize : function(){
34238 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34244 appendFooter : function(parentEl){
34248 sortAscText : "Sort Ascending",
34249 sortDescText : "Sort Descending",
34250 lockText : "Lock Column",
34251 unlockText : "Unlock Column",
34252 columnsText : "Columns"
34256 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34257 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34258 this.proxy.el.addClass('x-grid3-col-dd');
34261 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34262 handleMouseDown : function(e){
34266 callHandleMouseDown : function(e){
34267 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34272 * Ext JS Library 1.1.1
34273 * Copyright(c) 2006-2007, Ext JS, LLC.
34275 * Originally Released Under LGPL - original licence link has changed is not relivant.
34278 * <script type="text/javascript">
34282 // This is a support class used internally by the Grid components
34283 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34285 this.view = grid.getView();
34286 this.proxy = this.view.resizeProxy;
34287 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34288 "gridSplitters" + this.grid.getGridEl().id, {
34289 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34291 this.setHandleElId(Roo.id(hd));
34292 this.setOuterHandleElId(Roo.id(hd2));
34293 this.scroll = false;
34295 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34296 fly: Roo.Element.fly,
34298 b4StartDrag : function(x, y){
34299 this.view.headersDisabled = true;
34300 this.proxy.setHeight(this.view.mainWrap.getHeight());
34301 var w = this.cm.getColumnWidth(this.cellIndex);
34302 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34303 this.resetConstraints();
34304 this.setXConstraint(minw, 1000);
34305 this.setYConstraint(0, 0);
34306 this.minX = x - minw;
34307 this.maxX = x + 1000;
34309 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34313 handleMouseDown : function(e){
34314 ev = Roo.EventObject.setEvent(e);
34315 var t = this.fly(ev.getTarget());
34316 if(t.hasClass("x-grid-split")){
34317 this.cellIndex = this.view.getCellIndex(t.dom);
34318 this.split = t.dom;
34319 this.cm = this.grid.colModel;
34320 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34321 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34326 endDrag : function(e){
34327 this.view.headersDisabled = false;
34328 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34329 var diff = endX - this.startPos;
34330 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34333 autoOffset : function(){
34334 this.setDelta(0,0);
34338 * Ext JS Library 1.1.1
34339 * Copyright(c) 2006-2007, Ext JS, LLC.
34341 * Originally Released Under LGPL - original licence link has changed is not relivant.
34344 * <script type="text/javascript">
34348 // This is a support class used internally by the Grid components
34349 Roo.grid.GridDragZone = function(grid, config){
34350 this.view = grid.getView();
34351 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34352 if(this.view.lockedBody){
34353 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34354 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34356 this.scroll = false;
34358 this.ddel = document.createElement('div');
34359 this.ddel.className = 'x-grid-dd-wrap';
34362 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34363 ddGroup : "GridDD",
34365 getDragData : function(e){
34366 var t = Roo.lib.Event.getTarget(e);
34367 var rowIndex = this.view.findRowIndex(t);
34368 if(rowIndex !== false){
34369 var sm = this.grid.selModel;
34370 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34371 // sm.mouseDown(e, t);
34373 if (e.hasModifier()){
34374 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34376 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34381 onInitDrag : function(e){
34382 var data = this.dragData;
34383 this.ddel.innerHTML = this.grid.getDragDropText();
34384 this.proxy.update(this.ddel);
34385 // fire start drag?
34388 afterRepair : function(){
34389 this.dragging = false;
34392 getRepairXY : function(e, data){
34396 onEndDrag : function(data, e){
34400 onValidDrop : function(dd, e, id){
34405 beforeInvalidDrop : function(e, id){
34410 * Ext JS Library 1.1.1
34411 * Copyright(c) 2006-2007, Ext JS, LLC.
34413 * Originally Released Under LGPL - original licence link has changed is not relivant.
34416 * <script type="text/javascript">
34421 * @class Roo.grid.ColumnModel
34422 * @extends Roo.util.Observable
34423 * This is the default implementation of a ColumnModel used by the Grid. It defines
34424 * the columns in the grid.
34427 var colModel = new Roo.grid.ColumnModel([
34428 {header: "Ticker", width: 60, sortable: true, locked: true},
34429 {header: "Company Name", width: 150, sortable: true},
34430 {header: "Market Cap.", width: 100, sortable: true},
34431 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34432 {header: "Employees", width: 100, sortable: true, resizable: false}
34437 * The config options listed for this class are options which may appear in each
34438 * individual column definition.
34439 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34441 * @param {Object} config An Array of column config objects. See this class's
34442 * config objects for details.
34444 Roo.grid.ColumnModel = function(config){
34446 * The config passed into the constructor
34448 this.config = config;
34451 // if no id, create one
34452 // if the column does not have a dataIndex mapping,
34453 // map it to the order it is in the config
34454 for(var i = 0, len = config.length; i < len; i++){
34456 if(typeof c.dataIndex == "undefined"){
34459 if(typeof c.renderer == "string"){
34460 c.renderer = Roo.util.Format[c.renderer];
34462 if(typeof c.id == "undefined"){
34465 if(c.editor && c.editor.xtype){
34466 c.editor = Roo.factory(c.editor, Roo.grid);
34468 if(c.editor && c.editor.isFormField){
34469 c.editor = new Roo.grid.GridEditor(c.editor);
34471 this.lookup[c.id] = c;
34475 * The width of columns which have no width specified (defaults to 100)
34478 this.defaultWidth = 100;
34481 * Default sortable of columns which have no sortable specified (defaults to false)
34484 this.defaultSortable = false;
34488 * @event widthchange
34489 * Fires when the width of a column changes.
34490 * @param {ColumnModel} this
34491 * @param {Number} columnIndex The column index
34492 * @param {Number} newWidth The new width
34494 "widthchange": true,
34496 * @event headerchange
34497 * Fires when the text of a header changes.
34498 * @param {ColumnModel} this
34499 * @param {Number} columnIndex The column index
34500 * @param {Number} newText The new header text
34502 "headerchange": true,
34504 * @event hiddenchange
34505 * Fires when a column is hidden or "unhidden".
34506 * @param {ColumnModel} this
34507 * @param {Number} columnIndex The column index
34508 * @param {Boolean} hidden true if hidden, false otherwise
34510 "hiddenchange": true,
34512 * @event columnmoved
34513 * Fires when a column is moved.
34514 * @param {ColumnModel} this
34515 * @param {Number} oldIndex
34516 * @param {Number} newIndex
34518 "columnmoved" : true,
34520 * @event columlockchange
34521 * Fires when a column's locked state is changed
34522 * @param {ColumnModel} this
34523 * @param {Number} colIndex
34524 * @param {Boolean} locked true if locked
34526 "columnlockchange" : true
34528 Roo.grid.ColumnModel.superclass.constructor.call(this);
34530 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34532 * @cfg {String} header The header text to display in the Grid view.
34535 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34536 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34537 * specified, the column's index is used as an index into the Record's data Array.
34540 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34541 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34544 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34545 * Defaults to the value of the {@link #defaultSortable} property.
34546 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34549 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34552 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34555 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34558 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34561 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34562 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34563 * default renderer uses the raw data value.
34566 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34569 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34573 * Returns the id of the column at the specified index.
34574 * @param {Number} index The column index
34575 * @return {String} the id
34577 getColumnId : function(index){
34578 return this.config[index].id;
34582 * Returns the column for a specified id.
34583 * @param {String} id The column id
34584 * @return {Object} the column
34586 getColumnById : function(id){
34587 return this.lookup[id];
34592 * Returns the column for a specified dataIndex.
34593 * @param {String} dataIndex The column dataIndex
34594 * @return {Object|Boolean} the column or false if not found
34596 getColumnByDataIndex: function(dataIndex){
34597 var index = this.findColumnIndex(dataIndex);
34598 return index > -1 ? this.config[index] : false;
34602 * Returns the index for a specified column id.
34603 * @param {String} id The column id
34604 * @return {Number} the index, or -1 if not found
34606 getIndexById : function(id){
34607 for(var i = 0, len = this.config.length; i < len; i++){
34608 if(this.config[i].id == id){
34616 * Returns the index for a specified column dataIndex.
34617 * @param {String} dataIndex The column dataIndex
34618 * @return {Number} the index, or -1 if not found
34621 findColumnIndex : function(dataIndex){
34622 for(var i = 0, len = this.config.length; i < len; i++){
34623 if(this.config[i].dataIndex == dataIndex){
34631 moveColumn : function(oldIndex, newIndex){
34632 var c = this.config[oldIndex];
34633 this.config.splice(oldIndex, 1);
34634 this.config.splice(newIndex, 0, c);
34635 this.dataMap = null;
34636 this.fireEvent("columnmoved", this, oldIndex, newIndex);
34639 isLocked : function(colIndex){
34640 return this.config[colIndex].locked === true;
34643 setLocked : function(colIndex, value, suppressEvent){
34644 if(this.isLocked(colIndex) == value){
34647 this.config[colIndex].locked = value;
34648 if(!suppressEvent){
34649 this.fireEvent("columnlockchange", this, colIndex, value);
34653 getTotalLockedWidth : function(){
34654 var totalWidth = 0;
34655 for(var i = 0; i < this.config.length; i++){
34656 if(this.isLocked(i) && !this.isHidden(i)){
34657 this.totalWidth += this.getColumnWidth(i);
34663 getLockedCount : function(){
34664 for(var i = 0, len = this.config.length; i < len; i++){
34665 if(!this.isLocked(i)){
34672 * Returns the number of columns.
34675 getColumnCount : function(visibleOnly){
34676 if(visibleOnly === true){
34678 for(var i = 0, len = this.config.length; i < len; i++){
34679 if(!this.isHidden(i)){
34685 return this.config.length;
34689 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
34690 * @param {Function} fn
34691 * @param {Object} scope (optional)
34692 * @return {Array} result
34694 getColumnsBy : function(fn, scope){
34696 for(var i = 0, len = this.config.length; i < len; i++){
34697 var c = this.config[i];
34698 if(fn.call(scope||this, c, i) === true){
34706 * Returns true if the specified column is sortable.
34707 * @param {Number} col The column index
34708 * @return {Boolean}
34710 isSortable : function(col){
34711 if(typeof this.config[col].sortable == "undefined"){
34712 return this.defaultSortable;
34714 return this.config[col].sortable;
34718 * Returns the rendering (formatting) function defined for the column.
34719 * @param {Number} col The column index.
34720 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
34722 getRenderer : function(col){
34723 if(!this.config[col].renderer){
34724 return Roo.grid.ColumnModel.defaultRenderer;
34726 return this.config[col].renderer;
34730 * Sets the rendering (formatting) function for a column.
34731 * @param {Number} col The column index
34732 * @param {Function} fn The function to use to process the cell's raw data
34733 * to return HTML markup for the grid view. The render function is called with
34734 * the following parameters:<ul>
34735 * <li>Data value.</li>
34736 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
34737 * <li>css A CSS style string to apply to the table cell.</li>
34738 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
34739 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
34740 * <li>Row index</li>
34741 * <li>Column index</li>
34742 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
34744 setRenderer : function(col, fn){
34745 this.config[col].renderer = fn;
34749 * Returns the width for the specified column.
34750 * @param {Number} col The column index
34753 getColumnWidth : function(col){
34754 return this.config[col].width || this.defaultWidth;
34758 * Sets the width for a column.
34759 * @param {Number} col The column index
34760 * @param {Number} width The new width
34762 setColumnWidth : function(col, width, suppressEvent){
34763 this.config[col].width = width;
34764 this.totalWidth = null;
34765 if(!suppressEvent){
34766 this.fireEvent("widthchange", this, col, width);
34771 * Returns the total width of all columns.
34772 * @param {Boolean} includeHidden True to include hidden column widths
34775 getTotalWidth : function(includeHidden){
34776 if(!this.totalWidth){
34777 this.totalWidth = 0;
34778 for(var i = 0, len = this.config.length; i < len; i++){
34779 if(includeHidden || !this.isHidden(i)){
34780 this.totalWidth += this.getColumnWidth(i);
34784 return this.totalWidth;
34788 * Returns the header for the specified column.
34789 * @param {Number} col The column index
34792 getColumnHeader : function(col){
34793 return this.config[col].header;
34797 * Sets the header for a column.
34798 * @param {Number} col The column index
34799 * @param {String} header The new header
34801 setColumnHeader : function(col, header){
34802 this.config[col].header = header;
34803 this.fireEvent("headerchange", this, col, header);
34807 * Returns the tooltip for the specified column.
34808 * @param {Number} col The column index
34811 getColumnTooltip : function(col){
34812 return this.config[col].tooltip;
34815 * Sets the tooltip for a column.
34816 * @param {Number} col The column index
34817 * @param {String} tooltip The new tooltip
34819 setColumnTooltip : function(col, tooltip){
34820 this.config[col].tooltip = tooltip;
34824 * Returns the dataIndex for the specified column.
34825 * @param {Number} col The column index
34828 getDataIndex : function(col){
34829 return this.config[col].dataIndex;
34833 * Sets the dataIndex for a column.
34834 * @param {Number} col The column index
34835 * @param {Number} dataIndex The new dataIndex
34837 setDataIndex : function(col, dataIndex){
34838 this.config[col].dataIndex = dataIndex;
34844 * Returns true if the cell is editable.
34845 * @param {Number} colIndex The column index
34846 * @param {Number} rowIndex The row index
34847 * @return {Boolean}
34849 isCellEditable : function(colIndex, rowIndex){
34850 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
34854 * Returns the editor defined for the cell/column.
34855 * return false or null to disable editing.
34856 * @param {Number} colIndex The column index
34857 * @param {Number} rowIndex The row index
34860 getCellEditor : function(colIndex, rowIndex){
34861 return this.config[colIndex].editor;
34865 * Sets if a column is editable.
34866 * @param {Number} col The column index
34867 * @param {Boolean} editable True if the column is editable
34869 setEditable : function(col, editable){
34870 this.config[col].editable = editable;
34875 * Returns true if the column is hidden.
34876 * @param {Number} colIndex The column index
34877 * @return {Boolean}
34879 isHidden : function(colIndex){
34880 return this.config[colIndex].hidden;
34885 * Returns true if the column width cannot be changed
34887 isFixed : function(colIndex){
34888 return this.config[colIndex].fixed;
34892 * Returns true if the column can be resized
34893 * @return {Boolean}
34895 isResizable : function(colIndex){
34896 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
34899 * Sets if a column is hidden.
34900 * @param {Number} colIndex The column index
34901 * @param {Boolean} hidden True if the column is hidden
34903 setHidden : function(colIndex, hidden){
34904 this.config[colIndex].hidden = hidden;
34905 this.totalWidth = null;
34906 this.fireEvent("hiddenchange", this, colIndex, hidden);
34910 * Sets the editor for a column.
34911 * @param {Number} col The column index
34912 * @param {Object} editor The editor object
34914 setEditor : function(col, editor){
34915 this.config[col].editor = editor;
34919 Roo.grid.ColumnModel.defaultRenderer = function(value){
34920 if(typeof value == "string" && value.length < 1){
34926 // Alias for backwards compatibility
34927 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
34930 * Ext JS Library 1.1.1
34931 * Copyright(c) 2006-2007, Ext JS, LLC.
34933 * Originally Released Under LGPL - original licence link has changed is not relivant.
34936 * <script type="text/javascript">
34940 * @class Roo.grid.AbstractSelectionModel
34941 * @extends Roo.util.Observable
34942 * Abstract base class for grid SelectionModels. It provides the interface that should be
34943 * implemented by descendant classes. This class should not be directly instantiated.
34946 Roo.grid.AbstractSelectionModel = function(){
34947 this.locked = false;
34948 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
34951 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
34952 /** @ignore Called by the grid automatically. Do not call directly. */
34953 init : function(grid){
34959 * Locks the selections.
34962 this.locked = true;
34966 * Unlocks the selections.
34968 unlock : function(){
34969 this.locked = false;
34973 * Returns true if the selections are locked.
34974 * @return {Boolean}
34976 isLocked : function(){
34977 return this.locked;
34981 * Ext JS Library 1.1.1
34982 * Copyright(c) 2006-2007, Ext JS, LLC.
34984 * Originally Released Under LGPL - original licence link has changed is not relivant.
34987 * <script type="text/javascript">
34990 * @extends Roo.grid.AbstractSelectionModel
34991 * @class Roo.grid.RowSelectionModel
34992 * The default SelectionModel used by {@link Roo.grid.Grid}.
34993 * It supports multiple selections and keyboard selection/navigation.
34995 * @param {Object} config
34997 Roo.grid.RowSelectionModel = function(config){
34998 Roo.apply(this, config);
34999 this.selections = new Roo.util.MixedCollection(false, function(o){
35004 this.lastActive = false;
35008 * @event selectionchange
35009 * Fires when the selection changes
35010 * @param {SelectionModel} this
35012 "selectionchange" : true,
35014 * @event afterselectionchange
35015 * Fires after the selection changes (eg. by key press or clicking)
35016 * @param {SelectionModel} this
35018 "afterselectionchange" : true,
35020 * @event beforerowselect
35021 * Fires when a row is selected being selected, return false to cancel.
35022 * @param {SelectionModel} this
35023 * @param {Number} rowIndex The selected index
35024 * @param {Boolean} keepExisting False if other selections will be cleared
35026 "beforerowselect" : true,
35029 * Fires when a row is selected.
35030 * @param {SelectionModel} this
35031 * @param {Number} rowIndex The selected index
35032 * @param {Roo.data.Record} r The record
35034 "rowselect" : true,
35036 * @event rowdeselect
35037 * Fires when a row is deselected.
35038 * @param {SelectionModel} this
35039 * @param {Number} rowIndex The selected index
35041 "rowdeselect" : true
35043 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35044 this.locked = false;
35047 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35049 * @cfg {Boolean} singleSelect
35050 * True to allow selection of only one row at a time (defaults to false)
35052 singleSelect : false,
35055 initEvents : function(){
35057 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35058 this.grid.on("mousedown", this.handleMouseDown, this);
35059 }else{ // allow click to work like normal
35060 this.grid.on("rowclick", this.handleDragableRowClick, this);
35063 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35064 "up" : function(e){
35066 this.selectPrevious(e.shiftKey);
35067 }else if(this.last !== false && this.lastActive !== false){
35068 var last = this.last;
35069 this.selectRange(this.last, this.lastActive-1);
35070 this.grid.getView().focusRow(this.lastActive);
35071 if(last !== false){
35075 this.selectFirstRow();
35077 this.fireEvent("afterselectionchange", this);
35079 "down" : function(e){
35081 this.selectNext(e.shiftKey);
35082 }else if(this.last !== false && this.lastActive !== false){
35083 var last = this.last;
35084 this.selectRange(this.last, this.lastActive+1);
35085 this.grid.getView().focusRow(this.lastActive);
35086 if(last !== false){
35090 this.selectFirstRow();
35092 this.fireEvent("afterselectionchange", this);
35097 var view = this.grid.view;
35098 view.on("refresh", this.onRefresh, this);
35099 view.on("rowupdated", this.onRowUpdated, this);
35100 view.on("rowremoved", this.onRemove, this);
35104 onRefresh : function(){
35105 var ds = this.grid.dataSource, i, v = this.grid.view;
35106 var s = this.selections;
35107 s.each(function(r){
35108 if((i = ds.indexOfId(r.id)) != -1){
35117 onRemove : function(v, index, r){
35118 this.selections.remove(r);
35122 onRowUpdated : function(v, index, r){
35123 if(this.isSelected(r)){
35124 v.onRowSelect(index);
35130 * @param {Array} records The records to select
35131 * @param {Boolean} keepExisting (optional) True to keep existing selections
35133 selectRecords : function(records, keepExisting){
35135 this.clearSelections();
35137 var ds = this.grid.dataSource;
35138 for(var i = 0, len = records.length; i < len; i++){
35139 this.selectRow(ds.indexOf(records[i]), true);
35144 * Gets the number of selected rows.
35147 getCount : function(){
35148 return this.selections.length;
35152 * Selects the first row in the grid.
35154 selectFirstRow : function(){
35159 * Select the last row.
35160 * @param {Boolean} keepExisting (optional) True to keep existing selections
35162 selectLastRow : function(keepExisting){
35163 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35167 * Selects the row immediately following the last selected row.
35168 * @param {Boolean} keepExisting (optional) True to keep existing selections
35170 selectNext : function(keepExisting){
35171 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35172 this.selectRow(this.last+1, keepExisting);
35173 this.grid.getView().focusRow(this.last);
35178 * Selects the row that precedes the last selected row.
35179 * @param {Boolean} keepExisting (optional) True to keep existing selections
35181 selectPrevious : function(keepExisting){
35183 this.selectRow(this.last-1, keepExisting);
35184 this.grid.getView().focusRow(this.last);
35189 * Returns the selected records
35190 * @return {Array} Array of selected records
35192 getSelections : function(){
35193 return [].concat(this.selections.items);
35197 * Returns the first selected record.
35200 getSelected : function(){
35201 return this.selections.itemAt(0);
35206 * Clears all selections.
35208 clearSelections : function(fast){
35209 if(this.locked) return;
35211 var ds = this.grid.dataSource;
35212 var s = this.selections;
35213 s.each(function(r){
35214 this.deselectRow(ds.indexOfId(r.id));
35218 this.selections.clear();
35225 * Selects all rows.
35227 selectAll : function(){
35228 if(this.locked) return;
35229 this.selections.clear();
35230 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35231 this.selectRow(i, true);
35236 * Returns True if there is a selection.
35237 * @return {Boolean}
35239 hasSelection : function(){
35240 return this.selections.length > 0;
35244 * Returns True if the specified row is selected.
35245 * @param {Number/Record} record The record or index of the record to check
35246 * @return {Boolean}
35248 isSelected : function(index){
35249 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35250 return (r && this.selections.key(r.id) ? true : false);
35254 * Returns True if the specified record id is selected.
35255 * @param {String} id The id of record to check
35256 * @return {Boolean}
35258 isIdSelected : function(id){
35259 return (this.selections.key(id) ? true : false);
35263 handleMouseDown : function(e, t){
35264 var view = this.grid.getView(), rowIndex;
35265 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35268 if(e.shiftKey && this.last !== false){
35269 var last = this.last;
35270 this.selectRange(last, rowIndex, e.ctrlKey);
35271 this.last = last; // reset the last
35272 view.focusRow(rowIndex);
35274 var isSelected = this.isSelected(rowIndex);
35275 if(e.button !== 0 && isSelected){
35276 view.focusRow(rowIndex);
35277 }else if(e.ctrlKey && isSelected){
35278 this.deselectRow(rowIndex);
35279 }else if(!isSelected){
35280 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35281 view.focusRow(rowIndex);
35284 this.fireEvent("afterselectionchange", this);
35287 handleDragableRowClick : function(grid, rowIndex, e)
35289 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35290 this.selectRow(rowIndex, false);
35291 grid.view.focusRow(rowIndex);
35292 this.fireEvent("afterselectionchange", this);
35297 * Selects multiple rows.
35298 * @param {Array} rows Array of the indexes of the row to select
35299 * @param {Boolean} keepExisting (optional) True to keep existing selections
35301 selectRows : function(rows, keepExisting){
35303 this.clearSelections();
35305 for(var i = 0, len = rows.length; i < len; i++){
35306 this.selectRow(rows[i], true);
35311 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35312 * @param {Number} startRow The index of the first row in the range
35313 * @param {Number} endRow The index of the last row in the range
35314 * @param {Boolean} keepExisting (optional) True to retain existing selections
35316 selectRange : function(startRow, endRow, keepExisting){
35317 if(this.locked) return;
35319 this.clearSelections();
35321 if(startRow <= endRow){
35322 for(var i = startRow; i <= endRow; i++){
35323 this.selectRow(i, true);
35326 for(var i = startRow; i >= endRow; i--){
35327 this.selectRow(i, true);
35333 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35334 * @param {Number} startRow The index of the first row in the range
35335 * @param {Number} endRow The index of the last row in the range
35337 deselectRange : function(startRow, endRow, preventViewNotify){
35338 if(this.locked) return;
35339 for(var i = startRow; i <= endRow; i++){
35340 this.deselectRow(i, preventViewNotify);
35346 * @param {Number} row The index of the row to select
35347 * @param {Boolean} keepExisting (optional) True to keep existing selections
35349 selectRow : function(index, keepExisting, preventViewNotify){
35350 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35351 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35352 if(!keepExisting || this.singleSelect){
35353 this.clearSelections();
35355 var r = this.grid.dataSource.getAt(index);
35356 this.selections.add(r);
35357 this.last = this.lastActive = index;
35358 if(!preventViewNotify){
35359 this.grid.getView().onRowSelect(index);
35361 this.fireEvent("rowselect", this, index, r);
35362 this.fireEvent("selectionchange", this);
35368 * @param {Number} row The index of the row to deselect
35370 deselectRow : function(index, preventViewNotify){
35371 if(this.locked) return;
35372 if(this.last == index){
35375 if(this.lastActive == index){
35376 this.lastActive = false;
35378 var r = this.grid.dataSource.getAt(index);
35379 this.selections.remove(r);
35380 if(!preventViewNotify){
35381 this.grid.getView().onRowDeselect(index);
35383 this.fireEvent("rowdeselect", this, index);
35384 this.fireEvent("selectionchange", this);
35388 restoreLast : function(){
35390 this.last = this._last;
35395 acceptsNav : function(row, col, cm){
35396 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35400 onEditorKey : function(field, e){
35401 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35406 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35408 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35410 }else if(k == e.ENTER && !e.ctrlKey){
35414 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35416 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35418 }else if(k == e.ESC){
35422 g.startEditing(newCell[0], newCell[1]);
35427 * Ext JS Library 1.1.1
35428 * Copyright(c) 2006-2007, Ext JS, LLC.
35430 * Originally Released Under LGPL - original licence link has changed is not relivant.
35433 * <script type="text/javascript">
35436 * @class Roo.grid.CellSelectionModel
35437 * @extends Roo.grid.AbstractSelectionModel
35438 * This class provides the basic implementation for cell selection in a grid.
35440 * @param {Object} config The object containing the configuration of this model.
35442 Roo.grid.CellSelectionModel = function(config){
35443 Roo.apply(this, config);
35445 this.selection = null;
35449 * @event beforerowselect
35450 * Fires before a cell is selected.
35451 * @param {SelectionModel} this
35452 * @param {Number} rowIndex The selected row index
35453 * @param {Number} colIndex The selected cell index
35455 "beforecellselect" : true,
35457 * @event cellselect
35458 * Fires when a cell is selected.
35459 * @param {SelectionModel} this
35460 * @param {Number} rowIndex The selected row index
35461 * @param {Number} colIndex The selected cell index
35463 "cellselect" : true,
35465 * @event selectionchange
35466 * Fires when the active selection changes.
35467 * @param {SelectionModel} this
35468 * @param {Object} selection null for no selection or an object (o) with two properties
35470 <li>o.record: the record object for the row the selection is in</li>
35471 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35474 "selectionchange" : true
35476 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35479 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35482 initEvents : function(){
35483 this.grid.on("mousedown", this.handleMouseDown, this);
35484 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35485 var view = this.grid.view;
35486 view.on("refresh", this.onViewChange, this);
35487 view.on("rowupdated", this.onRowUpdated, this);
35488 view.on("beforerowremoved", this.clearSelections, this);
35489 view.on("beforerowsinserted", this.clearSelections, this);
35490 if(this.grid.isEditor){
35491 this.grid.on("beforeedit", this.beforeEdit, this);
35496 beforeEdit : function(e){
35497 this.select(e.row, e.column, false, true, e.record);
35501 onRowUpdated : function(v, index, r){
35502 if(this.selection && this.selection.record == r){
35503 v.onCellSelect(index, this.selection.cell[1]);
35508 onViewChange : function(){
35509 this.clearSelections(true);
35513 * Returns the currently selected cell,.
35514 * @return {Array} The selected cell (row, column) or null if none selected.
35516 getSelectedCell : function(){
35517 return this.selection ? this.selection.cell : null;
35521 * Clears all selections.
35522 * @param {Boolean} true to prevent the gridview from being notified about the change.
35524 clearSelections : function(preventNotify){
35525 var s = this.selection;
35527 if(preventNotify !== true){
35528 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35530 this.selection = null;
35531 this.fireEvent("selectionchange", this, null);
35536 * Returns true if there is a selection.
35537 * @return {Boolean}
35539 hasSelection : function(){
35540 return this.selection ? true : false;
35544 handleMouseDown : function(e, t){
35545 var v = this.grid.getView();
35546 if(this.isLocked()){
35549 var row = v.findRowIndex(t);
35550 var cell = v.findCellIndex(t);
35551 if(row !== false && cell !== false){
35552 this.select(row, cell);
35558 * @param {Number} rowIndex
35559 * @param {Number} collIndex
35561 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35562 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35563 this.clearSelections();
35564 r = r || this.grid.dataSource.getAt(rowIndex);
35567 cell : [rowIndex, colIndex]
35569 if(!preventViewNotify){
35570 var v = this.grid.getView();
35571 v.onCellSelect(rowIndex, colIndex);
35572 if(preventFocus !== true){
35573 v.focusCell(rowIndex, colIndex);
35576 this.fireEvent("cellselect", this, rowIndex, colIndex);
35577 this.fireEvent("selectionchange", this, this.selection);
35582 isSelectable : function(rowIndex, colIndex, cm){
35583 return !cm.isHidden(colIndex);
35587 handleKeyDown : function(e){
35588 Roo.log('Cell Sel Model handleKeyDown');
35589 if(!e.isNavKeyPress()){
35592 var g = this.grid, s = this.selection;
35595 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35597 this.select(cell[0], cell[1]);
35602 var walk = function(row, col, step){
35603 return g.walkCells(row, col, step, sm.isSelectable, sm);
35605 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
35610 // handled by onEditorKey
35611 if (g.isEditor && g.editing) {
35615 newCell = walk(r, c-1, -1);
35617 newCell = walk(r, c+1, 1);
35621 newCell = walk(r+1, c, 1);
35624 newCell = walk(r-1, c, -1);
35627 newCell = walk(r, c+1, 1);
35630 newCell = walk(r, c-1, -1);
35633 if(g.isEditor && !g.editing){
35634 g.startEditing(r, c);
35641 this.select(newCell[0], newCell[1]);
35646 acceptsNav : function(row, col, cm){
35647 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35650 onEditorKey : function(field, e){
35652 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35653 ///Roo.log('onEditorKey' + k);
35657 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35659 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35662 }else if(k == e.ENTER && !e.ctrlKey){
35665 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35666 }else if(k == e.ESC){
35672 //Roo.log('next cell after edit');
35673 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
35678 * Ext JS Library 1.1.1
35679 * Copyright(c) 2006-2007, Ext JS, LLC.
35681 * Originally Released Under LGPL - original licence link has changed is not relivant.
35684 * <script type="text/javascript">
35688 * @class Roo.grid.EditorGrid
35689 * @extends Roo.grid.Grid
35690 * Class for creating and editable grid.
35691 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35692 * The container MUST have some type of size defined for the grid to fill. The container will be
35693 * automatically set to position relative if it isn't already.
35694 * @param {Object} dataSource The data model to bind to
35695 * @param {Object} colModel The column model with info about this grid's columns
35697 Roo.grid.EditorGrid = function(container, config){
35698 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
35699 this.getGridEl().addClass("xedit-grid");
35701 if(!this.selModel){
35702 this.selModel = new Roo.grid.CellSelectionModel();
35705 this.activeEditor = null;
35709 * @event beforeedit
35710 * Fires before cell editing is triggered. The edit event object has the following properties <br />
35711 * <ul style="padding:5px;padding-left:16px;">
35712 * <li>grid - This grid</li>
35713 * <li>record - The record being edited</li>
35714 * <li>field - The field name being edited</li>
35715 * <li>value - The value for the field being edited.</li>
35716 * <li>row - The grid row index</li>
35717 * <li>column - The grid column index</li>
35718 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35720 * @param {Object} e An edit event (see above for description)
35722 "beforeedit" : true,
35725 * Fires after a cell is edited. <br />
35726 * <ul style="padding:5px;padding-left:16px;">
35727 * <li>grid - This grid</li>
35728 * <li>record - The record being edited</li>
35729 * <li>field - The field name being edited</li>
35730 * <li>value - The value being set</li>
35731 * <li>originalValue - The original value for the field, before the edit.</li>
35732 * <li>row - The grid row index</li>
35733 * <li>column - The grid column index</li>
35735 * @param {Object} e An edit event (see above for description)
35737 "afteredit" : true,
35739 * @event validateedit
35740 * Fires after a cell is edited, but before the value is set in the record.
35741 * You can use this to modify the value being set in the field, Return false
35742 * to cancel the change. The edit event object has the following properties <br />
35743 * <ul style="padding:5px;padding-left:16px;">
35744 * <li>editor - This editor</li>
35745 * <li>grid - This grid</li>
35746 * <li>record - The record being edited</li>
35747 * <li>field - The field name being edited</li>
35748 * <li>value - The value being set</li>
35749 * <li>originalValue - The original value for the field, before the edit.</li>
35750 * <li>row - The grid row index</li>
35751 * <li>column - The grid column index</li>
35752 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35754 * @param {Object} e An edit event (see above for description)
35756 "validateedit" : true
35758 this.on("bodyscroll", this.stopEditing, this);
35759 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
35762 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
35764 * @cfg {Number} clicksToEdit
35765 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
35772 trackMouseOver: false, // causes very odd FF errors
35774 onCellDblClick : function(g, row, col){
35775 this.startEditing(row, col);
35778 onEditComplete : function(ed, value, startValue){
35779 this.editing = false;
35780 this.activeEditor = null;
35781 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
35783 var field = this.colModel.getDataIndex(ed.col);
35788 originalValue: startValue,
35795 if(String(value) !== String(startValue)){
35797 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
35798 r.set(field, e.value);
35799 // if we are dealing with a combo box..
35800 // then we also set the 'name' colum to be the displayField
35801 if (ed.field.displayField && ed.field.name) {
35802 r.set(ed.field.name, ed.field.el.dom.value);
35805 delete e.cancel; //?? why!!!
35806 this.fireEvent("afteredit", e);
35809 this.fireEvent("afteredit", e); // always fire it!
35811 this.view.focusCell(ed.row, ed.col);
35815 * Starts editing the specified for the specified row/column
35816 * @param {Number} rowIndex
35817 * @param {Number} colIndex
35819 startEditing : function(row, col){
35820 this.stopEditing();
35821 if(this.colModel.isCellEditable(col, row)){
35822 this.view.ensureVisible(row, col, true);
35823 var r = this.dataSource.getAt(row);
35824 var field = this.colModel.getDataIndex(col);
35829 value: r.data[field],
35834 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
35835 this.editing = true;
35836 var ed = this.colModel.getCellEditor(col, row);
35842 ed.render(ed.parentEl || document.body);
35845 (function(){ // complex but required for focus issues in safari, ie and opera
35849 ed.on("complete", this.onEditComplete, this, {single: true});
35850 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
35851 this.activeEditor = ed;
35852 var v = r.data[field];
35853 ed.startEdit(this.view.getCell(row, col), v);
35854 // combo's with 'displayField and name set
35855 if (ed.field.displayField && ed.field.name) {
35856 ed.field.el.dom.value = r.data[ed.field.name];
35860 }).defer(50, this);
35866 * Stops any active editing
35868 stopEditing : function(){
35869 if(this.activeEditor){
35870 this.activeEditor.completeEdit();
35872 this.activeEditor = null;
35876 * Ext JS Library 1.1.1
35877 * Copyright(c) 2006-2007, Ext JS, LLC.
35879 * Originally Released Under LGPL - original licence link has changed is not relivant.
35882 * <script type="text/javascript">
35885 // private - not really -- you end up using it !
35886 // This is a support class used internally by the Grid components
35889 * @class Roo.grid.GridEditor
35890 * @extends Roo.Editor
35891 * Class for creating and editable grid elements.
35892 * @param {Object} config any settings (must include field)
35894 Roo.grid.GridEditor = function(field, config){
35895 if (!config && field.field) {
35897 field = Roo.factory(config.field, Roo.form);
35899 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
35900 field.monitorTab = false;
35903 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
35906 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
35909 alignment: "tl-tl",
35912 cls: "x-small-editor x-grid-editor",
35917 * Ext JS Library 1.1.1
35918 * Copyright(c) 2006-2007, Ext JS, LLC.
35920 * Originally Released Under LGPL - original licence link has changed is not relivant.
35923 * <script type="text/javascript">
35928 Roo.grid.PropertyRecord = Roo.data.Record.create([
35929 {name:'name',type:'string'}, 'value'
35933 Roo.grid.PropertyStore = function(grid, source){
35935 this.store = new Roo.data.Store({
35936 recordType : Roo.grid.PropertyRecord
35938 this.store.on('update', this.onUpdate, this);
35940 this.setSource(source);
35942 Roo.grid.PropertyStore.superclass.constructor.call(this);
35947 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
35948 setSource : function(o){
35950 this.store.removeAll();
35953 if(this.isEditableValue(o[k])){
35954 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
35957 this.store.loadRecords({records: data}, {}, true);
35960 onUpdate : function(ds, record, type){
35961 if(type == Roo.data.Record.EDIT){
35962 var v = record.data['value'];
35963 var oldValue = record.modified['value'];
35964 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
35965 this.source[record.id] = v;
35967 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
35974 getProperty : function(row){
35975 return this.store.getAt(row);
35978 isEditableValue: function(val){
35979 if(val && val instanceof Date){
35981 }else if(typeof val == 'object' || typeof val == 'function'){
35987 setValue : function(prop, value){
35988 this.source[prop] = value;
35989 this.store.getById(prop).set('value', value);
35992 getSource : function(){
35993 return this.source;
35997 Roo.grid.PropertyColumnModel = function(grid, store){
36000 g.PropertyColumnModel.superclass.constructor.call(this, [
36001 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
36002 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
36004 this.store = store;
36005 this.bselect = Roo.DomHelper.append(document.body, {
36006 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
36007 {tag: 'option', value: 'true', html: 'true'},
36008 {tag: 'option', value: 'false', html: 'false'}
36011 Roo.id(this.bselect);
36014 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
36015 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
36016 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
36017 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
36018 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36020 this.renderCellDelegate = this.renderCell.createDelegate(this);
36021 this.renderPropDelegate = this.renderProp.createDelegate(this);
36024 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36028 valueText : 'Value',
36030 dateFormat : 'm/j/Y',
36033 renderDate : function(dateVal){
36034 return dateVal.dateFormat(this.dateFormat);
36037 renderBool : function(bVal){
36038 return bVal ? 'true' : 'false';
36041 isCellEditable : function(colIndex, rowIndex){
36042 return colIndex == 1;
36045 getRenderer : function(col){
36047 this.renderCellDelegate : this.renderPropDelegate;
36050 renderProp : function(v){
36051 return this.getPropertyName(v);
36054 renderCell : function(val){
36056 if(val instanceof Date){
36057 rv = this.renderDate(val);
36058 }else if(typeof val == 'boolean'){
36059 rv = this.renderBool(val);
36061 return Roo.util.Format.htmlEncode(rv);
36064 getPropertyName : function(name){
36065 var pn = this.grid.propertyNames;
36066 return pn && pn[name] ? pn[name] : name;
36069 getCellEditor : function(colIndex, rowIndex){
36070 var p = this.store.getProperty(rowIndex);
36071 var n = p.data['name'], val = p.data['value'];
36073 if(typeof(this.grid.customEditors[n]) == 'string'){
36074 return this.editors[this.grid.customEditors[n]];
36076 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36077 return this.grid.customEditors[n];
36079 if(val instanceof Date){
36080 return this.editors['date'];
36081 }else if(typeof val == 'number'){
36082 return this.editors['number'];
36083 }else if(typeof val == 'boolean'){
36084 return this.editors['boolean'];
36086 return this.editors['string'];
36092 * @class Roo.grid.PropertyGrid
36093 * @extends Roo.grid.EditorGrid
36094 * This class represents the interface of a component based property grid control.
36095 * <br><br>Usage:<pre><code>
36096 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36104 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36105 * The container MUST have some type of size defined for the grid to fill. The container will be
36106 * automatically set to position relative if it isn't already.
36107 * @param {Object} config A config object that sets properties on this grid.
36109 Roo.grid.PropertyGrid = function(container, config){
36110 config = config || {};
36111 var store = new Roo.grid.PropertyStore(this);
36112 this.store = store;
36113 var cm = new Roo.grid.PropertyColumnModel(this, store);
36114 store.store.sort('name', 'ASC');
36115 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36118 enableColLock:false,
36119 enableColumnMove:false,
36121 trackMouseOver: false,
36124 this.getGridEl().addClass('x-props-grid');
36125 this.lastEditRow = null;
36126 this.on('columnresize', this.onColumnResize, this);
36129 * @event beforepropertychange
36130 * Fires before a property changes (return false to stop?)
36131 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36132 * @param {String} id Record Id
36133 * @param {String} newval New Value
36134 * @param {String} oldval Old Value
36136 "beforepropertychange": true,
36138 * @event propertychange
36139 * Fires after a property changes
36140 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36141 * @param {String} id Record Id
36142 * @param {String} newval New Value
36143 * @param {String} oldval Old Value
36145 "propertychange": true
36147 this.customEditors = this.customEditors || {};
36149 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36152 * @cfg {Object} customEditors map of colnames=> custom editors.
36153 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36154 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36155 * false disables editing of the field.
36159 * @cfg {Object} propertyNames map of property Names to their displayed value
36162 render : function(){
36163 Roo.grid.PropertyGrid.superclass.render.call(this);
36164 this.autoSize.defer(100, this);
36167 autoSize : function(){
36168 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36170 this.view.fitColumns();
36174 onColumnResize : function(){
36175 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36179 * Sets the data for the Grid
36180 * accepts a Key => Value object of all the elements avaiable.
36181 * @param {Object} data to appear in grid.
36183 setSource : function(source){
36184 this.store.setSource(source);
36188 * Gets all the data from the grid.
36189 * @return {Object} data data stored in grid
36191 getSource : function(){
36192 return this.store.getSource();
36196 * Ext JS Library 1.1.1
36197 * Copyright(c) 2006-2007, Ext JS, LLC.
36199 * Originally Released Under LGPL - original licence link has changed is not relivant.
36202 * <script type="text/javascript">
36206 * @class Roo.LoadMask
36207 * A simple utility class for generically masking elements while loading data. If the element being masked has
36208 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36209 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36210 * element's UpdateManager load indicator and will be destroyed after the initial load.
36212 * Create a new LoadMask
36213 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36214 * @param {Object} config The config object
36216 Roo.LoadMask = function(el, config){
36217 this.el = Roo.get(el);
36218 Roo.apply(this, config);
36220 this.store.on('beforeload', this.onBeforeLoad, this);
36221 this.store.on('load', this.onLoad, this);
36222 this.store.on('loadexception', this.onLoad, this);
36223 this.removeMask = false;
36225 var um = this.el.getUpdateManager();
36226 um.showLoadIndicator = false; // disable the default indicator
36227 um.on('beforeupdate', this.onBeforeLoad, this);
36228 um.on('update', this.onLoad, this);
36229 um.on('failure', this.onLoad, this);
36230 this.removeMask = true;
36234 Roo.LoadMask.prototype = {
36236 * @cfg {Boolean} removeMask
36237 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36238 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36241 * @cfg {String} msg
36242 * The text to display in a centered loading message box (defaults to 'Loading...')
36244 msg : 'Loading...',
36246 * @cfg {String} msgCls
36247 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36249 msgCls : 'x-mask-loading',
36252 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36258 * Disables the mask to prevent it from being displayed
36260 disable : function(){
36261 this.disabled = true;
36265 * Enables the mask so that it can be displayed
36267 enable : function(){
36268 this.disabled = false;
36272 onLoad : function(){
36273 this.el.unmask(this.removeMask);
36277 onBeforeLoad : function(){
36278 if(!this.disabled){
36279 this.el.mask(this.msg, this.msgCls);
36284 destroy : function(){
36286 this.store.un('beforeload', this.onBeforeLoad, this);
36287 this.store.un('load', this.onLoad, this);
36288 this.store.un('loadexception', this.onLoad, this);
36290 var um = this.el.getUpdateManager();
36291 um.un('beforeupdate', this.onBeforeLoad, this);
36292 um.un('update', this.onLoad, this);
36293 um.un('failure', this.onLoad, this);
36298 * Ext JS Library 1.1.1
36299 * Copyright(c) 2006-2007, Ext JS, LLC.
36301 * Originally Released Under LGPL - original licence link has changed is not relivant.
36304 * <script type="text/javascript">
36306 Roo.XTemplate = function(){
36307 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36310 s = ['<tpl>', s, '</tpl>'].join('');
36312 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36314 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36315 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36316 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36320 while(m = s.match(re)){
36321 var m2 = m[0].match(nameRe);
36322 var m3 = m[0].match(ifRe);
36323 var m4 = m[0].match(execRe);
36324 var exp = null, fn = null, exec = null;
36325 var name = m2 && m2[1] ? m2[1] : '';
36327 exp = m3 && m3[1] ? m3[1] : null;
36329 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36333 exp = m4 && m4[1] ? m4[1] : null;
36335 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36340 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36341 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36342 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36352 s = s.replace(m[0], '{xtpl'+ id + '}');
36355 for(var i = tpls.length-1; i >= 0; --i){
36356 this.compileTpl(tpls[i]);
36358 this.master = tpls[tpls.length-1];
36361 Roo.extend(Roo.XTemplate, Roo.Template, {
36363 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36365 applySubTemplate : function(id, values, parent){
36366 var t = this.tpls[id];
36367 if(t.test && !t.test.call(this, values, parent)){
36370 if(t.exec && t.exec.call(this, values, parent)){
36373 var vs = t.target ? t.target.call(this, values, parent) : values;
36374 parent = t.target ? values : parent;
36375 if(t.target && vs instanceof Array){
36377 for(var i = 0, len = vs.length; i < len; i++){
36378 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36380 return buf.join('');
36382 return t.compiled.call(this, vs, parent);
36385 compileTpl : function(tpl){
36386 var fm = Roo.util.Format;
36387 var useF = this.disableFormats !== true;
36388 var sep = Roo.isGecko ? "+" : ",";
36389 var fn = function(m, name, format, args){
36390 if(name.substr(0, 4) == 'xtpl'){
36391 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36394 if(name.indexOf('.') != -1){
36397 v = "values['" + name + "']";
36399 if(format && useF){
36400 args = args ? ',' + args : "";
36401 if(format.substr(0, 5) != "this."){
36402 format = "fm." + format + '(';
36404 format = 'this.call("'+ format.substr(5) + '", ';
36408 args= ''; format = "("+v+" === undefined ? '' : ";
36410 return "'"+ sep + format + v + args + ")"+sep+"'";
36413 // branched to use + in gecko and [].join() in others
36415 body = "tpl.compiled = function(values, parent){ return '" +
36416 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36419 body = ["tpl.compiled = function(values, parent){ return ['"];
36420 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36421 body.push("'].join('');};");
36422 body = body.join('');
36424 /** eval:var:zzzzzzz */
36429 applyTemplate : function(values){
36430 return this.master.compiled.call(this, values, {});
36434 apply : function(){
36435 return this.applyTemplate.apply(this, arguments);
36438 compile : function(){return this;}
36441 Roo.XTemplate.from = function(el){
36442 el = Roo.getDom(el);
36443 return new Roo.XTemplate(el.value || el.innerHTML);
36445 * Original code for Roojs - LGPL
36446 * <script type="text/javascript">
36450 * @class Roo.XComponent
36451 * A delayed Element creator...
36453 * Mypart.xyx = new Roo.XComponent({
36455 parent : 'Mypart.xyz', // empty == document.element.!!
36459 disabled : function() {}
36461 tree : function() { // return an tree of xtype declared components
36465 xtype : 'NestedLayoutPanel',
36470 * @extends Roo.util.Observable
36472 * @param cfg {Object} configuration of component
36475 Roo.XComponent = function(cfg) {
36476 Roo.apply(this, cfg);
36480 * Fires when this the componnt is built
36481 * @param {Roo.XComponent} c the component
36485 * @event buildcomplete
36486 * Fires on the top level element when all elements have been built
36487 * @param {Roo.XComponent} c the top level component.
36489 'buildcomplete' : true
36493 Roo.XComponent.register(this);
36494 this.modules = false;
36495 this.el = false; // where the layout goes..
36499 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36502 * The created element (with Roo.factory())
36503 * @type {Roo.Layout}
36509 * for BC - use el in new code
36510 * @type {Roo.Layout}
36516 * for BC - use el in new code
36517 * @type {Roo.Layout}
36522 * @cfg {Function|boolean} disabled
36523 * If this module is disabled by some rule, return true from the funtion
36528 * @cfg {String} parent
36529 * Name of parent element which it get xtype added to..
36534 * @cfg {String} order
36535 * Used to set the order in which elements are created (usefull for multiple tabs)
36540 * @cfg {String} name
36541 * String to display while loading.
36545 * @cfg {Array} items
36546 * A single item array - the first element is the root of the tree..
36547 * It's done this way to stay compatible with the Xtype system...
36555 Roo.apply(Roo.XComponent, {
36558 * @property buildCompleted
36559 * True when the builder has completed building the interface.
36562 buildCompleted : false,
36565 * @property topModule
36566 * the upper most module - uses document.element as it's constructor.
36573 * @property modules
36574 * array of modules to be created by registration system.
36575 * @type Roo.XComponent
36582 * Register components to be built later.
36584 * This solves the following issues
36585 * - Building is not done on page load, but after an authentication process has occured.
36586 * - Interface elements are registered on page load
36587 * - Parent Interface elements may not be loaded before child, so this handles that..
36594 module : 'Pman.Tab.projectMgr',
36596 parent : 'Pman.layout',
36597 disabled : false, // or use a function..
36600 * * @param {Object} details about module
36602 register : function(obj) {
36603 this.modules.push(obj);
36607 * convert a string to an object..
36611 toObject : function(str)
36613 if (!str || typeof(str) == 'object') {
36616 var ar = str.split('.');
36620 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
36622 throw "Module not found : " + str;
36624 Roo.each(ar, function(e) {
36625 if (typeof(o[e]) == 'undefined') {
36626 throw "Module not found : " + str;
36636 * move modules into their correct place in the tree..
36639 preBuild : function ()
36642 Roo.each(this.modules , function (obj)
36644 obj.parent = this.toObject(obj.parent);
36647 this.topModule = obj;
36651 if (!obj.parent.modules) {
36652 obj.parent.modules = new Roo.util.MixedCollection(false,
36653 function(o) { return o.order + '' }
36657 obj.parent.modules.add(obj);
36662 * make a list of modules to build.
36663 * @return {Array} list of modules.
36666 buildOrder : function()
36669 var cmp = function(a,b) {
36670 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
36673 if (!this.topModule || !this.topModule.modules) {
36674 throw "No top level modules to build";
36677 // make a flat list in order of modules to build.
36678 var mods = [ this.topModule ];
36681 // add modules to their parents..
36682 var addMod = function(m) {
36683 // Roo.debug && Roo.log(m.modKey);
36687 m.modules.keySort('ASC', cmp );
36688 m.modules.each(addMod);
36690 // not sure if this is used any more..
36692 m.finalize.name = m.name + " (clean up) ";
36693 mods.push(m.finalize);
36697 this.topModule.modules.keySort('ASC', cmp );
36698 this.topModule.modules.each(addMod);
36703 * Build the registered modules.
36704 * @param {Object} parent element.
36705 * @param {Function} optional method to call after module has been added.
36713 var mods = this.buildOrder();
36715 //this.allmods = mods;
36716 //Roo.debug && Roo.log(mods);
36718 if (!mods.length) { // should not happen
36719 throw "NO modules!!!";
36724 // flash it up as modal - so we store the mask!?
36725 Roo.MessageBox.show({ title: 'loading' });
36726 Roo.MessageBox.show({
36727 title: "Please wait...",
36728 msg: "Building Interface...",
36735 var total = mods.length;
36738 var progressRun = function() {
36739 if (!mods.length) {
36740 Roo.debug && Roo.log('hide?');
36741 Roo.MessageBox.hide();
36742 _this.topModule.fireEvent('buildcomplete', _this.topModule);
36746 var m = mods.shift();
36747 Roo.debug && Roo.log(m);
36748 if (typeof(m) == 'function') { // not sure if this is supported any more..
36750 return progressRun.defer(10, _this);
36753 Roo.MessageBox.updateProgress(
36754 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
36756 (m.name ? (' - ' + m.name) : '')
36761 var disabled = (typeof(m.disabled) == 'function') ?
36762 m.disabled.call(m.module.disabled) : m.disabled;
36766 return progressRun(); // we do not update the display!
36770 // it's a top level one..
36771 var layoutbase = new Ext.BorderLayout(document.body, {
36777 tabPosition: 'top',
36778 //resizeTabs: true,
36779 alwaysShowTabs: true,
36783 var tree = m.tree();
36784 tree.region = 'center';
36785 m.el = layoutbase.addxtype(tree);
36787 m.layout = m.panel.layout;
36788 return progressRun.defer(10, _this);
36791 var tree = m.tree();
36792 tree.region = tree.region || m.region;
36793 m.el = m.parent.el.addxtype(tree);
36794 m.fireEvent('built', m);
36796 m.layout = m.panel.layout;
36797 progressRun.defer(10, _this);
36800 progressRun.defer(1, _this);
36810 //<script type="text/javascript">
36815 * @extends Roo.LayoutDialog
36816 * A generic Login Dialog..... - only one needed in theory!?!?
36818 * Fires XComponent builder on success...
36821 * username,password, lang = for login actions.
36822 * check = 1 for periodic checking that sesion is valid.
36823 * passwordRequest = email request password
36824 * logout = 1 = to logout
36826 * Affects: (this id="????" elements)
36827 * loading (removed) (used to indicate application is loading)
36828 * loading-mask (hides) (used to hide application when it's building loading)
36834 * Myapp.login = Roo.Login({
36850 Roo.Login = function(cfg)
36856 Roo.apply(this,cfg);
36858 Roo.onReady(function() {
36864 Roo.Login.superclass.constructor.call(this, this);
36865 //this.addxtype(this.items[0]);
36871 Roo.extend(Roo.Login, Roo.LayoutDialog, {
36874 * @cfg {String} method
36875 * Method used to query for login details.
36880 * @cfg {String} url
36881 * URL to query login data. - eg. baseURL + '/Login.php'
36887 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
36892 * @property checkFails
36893 * Number of times we have attempted to get authentication check, and failed.
36898 * @property intervalID
36899 * The window interval that does the constant login checking.
36905 onLoad : function() // called on page load...
36909 if (Roo.get('loading')) { // clear any loading indicator..
36910 Roo.get('loading').remove();
36913 //this.switchLang('en'); // set the language to english..
36916 success: function(response, opts) { // check successfull...
36918 var res = this.processResponse(response);
36919 this.checkFails =0;
36920 if (!res.success) { // error!
36921 this.checkFails = 5;
36922 //console.log('call failure');
36923 return this.failure(response,opts);
36926 if (!res.data.id) { // id=0 == login failure.
36927 return this.show();
36931 //console.log(success);
36932 this.fillAuth(res.data);
36933 this.checkFails =0;
36934 Roo.XComponent.build();
36936 failure : this.show
36942 check: function(cfg) // called every so often to refresh cookie etc..
36944 if (cfg.again) { // could be undefined..
36947 this.checkFails = 0;
36950 if (this.sending) {
36951 if ( this.checkFails > 4) {
36952 Roo.MessageBox.alert("Error",
36953 "Error getting authentication status. - try reloading, or wait a while", function() {
36954 _this.sending = false;
36959 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
36962 this.sending = true;
36969 method: this.method,
36970 success: cfg.success || this.success,
36971 failure : cfg.failure || this.failure,
36981 window.onbeforeunload = function() { }; // false does not work for IE..
36991 failure : function() {
36992 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
36993 document.location = document.location.toString() + '?ts=' + Math.random();
36997 success : function() {
36998 _this.user = false;
36999 this.checkFails =0;
37001 document.location = document.location.toString() + '?ts=' + Math.random();
37008 processResponse : function (response)
37012 res = Roo.decode(response.responseText);
37014 if (typeof(res) != 'object') {
37015 res = { success : false, errorMsg : res, errors : true };
37017 if (typeof(res.success) == 'undefined') {
37018 res.success = false;
37022 res = { success : false, errorMsg : response.responseText, errors : true };
37027 success : function(response, opts) // check successfull...
37029 this.sending = false;
37030 var res = this.processResponse(response);
37031 if (!res.success) {
37032 return this.failure(response, opts);
37034 if (!res.data || !res.data.id) {
37035 return this.failure(response,opts);
37037 //console.log(res);
37038 this.fillAuth(res.data);
37040 this.checkFails =0;
37045 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37047 this.authUser = -1;
37048 this.sending = false;
37049 var res = this.processResponse(response);
37050 //console.log(res);
37051 if ( this.checkFails > 2) {
37053 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37054 "Error getting authentication status. - try reloading");
37057 opts.callCfg.again = true;
37058 this.check.defer(1000, this, [ opts.callCfg ]);
37064 fillAuth: function(au) {
37065 this.startAuthCheck();
37066 this.authUserId = au.id;
37067 this.authUser = au;
37068 this.lastChecked = new Date();
37069 this.fireEvent('refreshed', au);
37070 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37071 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37072 au.lang = au.lang || 'en';
37073 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37074 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37075 this.switchLang(au.lang );
37078 // open system... - -on setyp..
37079 if (this.authUserId < 0) {
37080 Roo.MessageBox.alert("Warning",
37081 "This is an open system - please set up a admin user with a password.");
37084 //Pman.onload(); // which should do nothing if it's a re-auth result...
37089 startAuthCheck : function() // starter for timeout checking..
37091 if (this.intervalID) { // timer already in place...
37095 this.intervalID = window.setInterval(function() {
37096 _this.check(false);
37097 }, 120000); // every 120 secs = 2mins..
37103 switchLang : function (lang)
37105 _T = typeof(_T) == 'undefined' ? false : _T;
37106 if (!_T || !lang.length) {
37110 if (!_T && lang != 'en') {
37111 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37115 if (typeof(_T.en) == 'undefined') {
37117 Roo.apply(_T.en, _T);
37120 if (typeof(_T[lang]) == 'undefined') {
37121 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37126 Roo.apply(_T, _T[lang]);
37127 // just need to set the text values for everything...
37129 /* this will not work ...
37133 function formLabel(name, val) {
37134 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37137 formLabel('password', "Password"+':');
37138 formLabel('username', "Email Address"+':');
37139 formLabel('lang', "Language"+':');
37140 this.dialog.setTitle("Login");
37141 this.dialog.buttons[0].setText("Forgot Password");
37142 this.dialog.buttons[1].setText("Login");
37161 collapsible: false,
37163 center: { // needed??
37166 // tabPosition: 'top',
37169 alwaysShowTabs: false
37173 show : function(dlg)
37175 //console.log(this);
37176 this.form = this.layout.getRegion('center').activePanel.form;
37177 this.form.dialog = dlg;
37178 this.buttons[0].form = this.form;
37179 this.buttons[0].dialog = dlg;
37180 this.buttons[1].form = this.form;
37181 this.buttons[1].dialog = dlg;
37183 //this.resizeToLogo.defer(1000,this);
37184 // this is all related to resizing for logos..
37185 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37187 // this.resizeToLogo.defer(1000,this);
37190 //var w = Ext.lib.Dom.getViewWidth() - 100;
37191 //var h = Ext.lib.Dom.getViewHeight() - 100;
37192 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37194 if (this.disabled) {
37199 if (this.user.id < 0) { // used for inital setup situations.
37203 if (this.intervalID) {
37204 // remove the timer
37205 window.clearInterval(this.intervalID);
37206 this.intervalID = false;
37210 if (Roo.get('loading')) {
37211 Roo.get('loading').remove();
37213 if (Roo.get('loading-mask')) {
37214 Roo.get('loading-mask').hide();
37217 //incomming._node = tnode;
37219 //this.dialog.modal = !modal;
37220 //this.dialog.show();
37224 this.form.setValues({
37225 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37226 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37229 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37230 if (this.form.findField('username').getValue().length > 0 ){
37231 this.form.findField('password').focus();
37233 this.form.findField('username').focus();
37241 xtype : 'ContentPanel',
37253 style : 'margin: 10px;',
37256 actionfailed : function(f, act) {
37257 // form can return { errors: .... }
37259 //act.result.errors // invalid form element list...
37260 //act.result.errorMsg// invalid form element list...
37262 this.dialog.el.unmask();
37263 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37264 "Login failed - communication error - try again.");
37267 actioncomplete: function(re, act) {
37269 Roo.state.Manager.set(
37270 this.dialog.realm + '.username',
37271 this.findField('username').getValue()
37273 Roo.state.Manager.set(
37274 this.dialog.realm + '.lang',
37275 this.findField('lang').getValue()
37278 this.dialog.fillAuth(act.result.data);
37280 this.dialog.hide();
37282 if (Roo.get('loading-mask')) {
37283 Roo.get('loading-mask').show();
37285 Roo.XComponent.build();
37293 xtype : 'TextField',
37295 fieldLabel: "Email Address",
37298 autoCreate : {tag: "input", type: "text", size: "20"}
37301 xtype : 'TextField',
37303 fieldLabel: "Password",
37304 inputType: 'password',
37307 autoCreate : {tag: "input", type: "text", size: "20"},
37309 specialkey : function(e,ev) {
37310 if (ev.keyCode == 13) {
37311 this.form.dialog.el.mask("Logging in");
37312 this.form.doAction('submit', {
37313 url: this.form.dialog.url,
37314 method: this.form.dialog.method
37321 xtype : 'ComboBox',
37323 fieldLabel: "Language",
37326 xtype : 'SimpleStore',
37327 fields: ['lang', 'ldisp'],
37329 [ 'en', 'English' ],
37330 [ 'zh_HK' , '\u7E41\u4E2D' ],
37331 [ 'zh_CN', '\u7C21\u4E2D' ]
37335 valueField : 'lang',
37336 hiddenName: 'lang',
37338 displayField:'ldisp',
37342 triggerAction: 'all',
37343 emptyText:'Select a Language...',
37344 selectOnFocus:true,
37346 select : function(cb, rec, ix) {
37347 this.form.switchLang(rec.data.lang);
37363 text : "Forgot Password",
37365 click : function() {
37366 //console.log(this);
37367 var n = this.form.findField('username').getValue();
37369 Roo.MessageBox.alert("Error", "Fill in your email address");
37373 url: this.dialog.url,
37377 method: this.dialog.method,
37378 success: function(response, opts) { // check successfull...
37380 var res = this.dialog.processResponse(response);
37381 if (!res.success) { // error!
37382 Roo.MessageBox.alert("Error" ,
37383 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37386 Roo.MessageBox.alert("Notice" ,
37387 "Please check you email for the Password Reset message");
37389 failure : function() {
37390 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37403 click : function () {
37405 this.dialog.el.mask("Logging in");
37406 this.form.doAction('submit', {
37407 url: this.dialog.url,
37408 method: this.dialog.method