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= [