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 * @extends Roo.util.Observable
30 * Defines the interface and base operation of items that that can be
31 * dragged or can be drop targets. It was designed to be extended, overriding
32 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
33 * Up to three html elements can be associated with a DragDrop instance:
35 * <li>linked element: the element that is passed into the constructor.
36 * This is the element which defines the boundaries for interaction with
37 * other DragDrop objects.</li>
38 * <li>handle element(s): The drag operation only occurs if the element that
39 * was clicked matches a handle element. By default this is the linked
40 * element, but there are times that you will want only a portion of the
41 * linked element to initiate the drag operation, and the setHandleElId()
42 * method provides a way to define this.</li>
43 * <li>drag element: this represents the element that would be moved along
44 * with the cursor during a drag operation. By default, this is the linked
45 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
46 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
49 * This class should not be instantiated until the onload event to ensure that
50 * the associated elements are available.
51 * The following would define a DragDrop obj that would interact with any
52 * other DragDrop obj in the "group1" group:
54 * dd = new Roo.dd.DragDrop("div1", "group1");
56 * Since none of the event handlers have been implemented, nothing would
57 * actually happen if you were to run the code above. Normally you would
58 * override this class or one of the default implementations, but you can
59 * also override the methods you want on an instance of the class...
61 * dd.onDragDrop = function(e, id) {
62 * alert("dd was dropped on " + id);
66 * @param {String} id of the element that is linked to this instance
67 * @param {String} sGroup the group of related DragDrop objects
68 * @param {object} config an object containing configurable attributes
69 * Valid properties for DragDrop:
70 * padding, isTarget, maintainOffset, primaryButtonOnly
72 Roo.dd.DragDrop = function(id, sGroup, config) {
74 this.init(id, sGroup, config);
79 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
82 * The id of the element associated with this object. This is what we
83 * refer to as the "linked element" because the size and position of
84 * this element is used to determine when the drag and drop objects have
92 * Configuration attributes passed into the constructor
99 * The id of the element that will be dragged. By default this is same
100 * as the linked element , but could be changed to another element. Ex:
109 * the id of the element that initiates the drag operation. By default
110 * this is the linked element, but could be changed to be a child of this
111 * element. This lets us do things like only starting the drag when the
112 * header element within the linked html element is clicked.
113 * @property handleElId
120 * An associative array of HTML tags that will be ignored if clicked.
121 * @property invalidHandleTypes
122 * @type {string: string}
124 invalidHandleTypes: null,
127 * An associative array of ids for elements that will be ignored if clicked
128 * @property invalidHandleIds
129 * @type {string: string}
131 invalidHandleIds: null,
134 * An indexted array of css class names for elements that will be ignored
136 * @property invalidHandleClasses
139 invalidHandleClasses: null,
142 * The linked element's absolute X position at the time the drag was
144 * @property startPageX
151 * The linked element's absolute X position at the time the drag was
153 * @property startPageY
160 * The group defines a logical collection of DragDrop objects that are
161 * related. Instances only get events when interacting with other
162 * DragDrop object in the same group. This lets us define multiple
163 * groups using a single DragDrop subclass if we want.
165 * @type {string: string}
170 * Individual drag/drop instances can be locked. This will prevent
171 * onmousedown start drag.
182 lock: function() { this.locked = true; },
185 * Unlock this instace
188 unlock: function() { this.locked = false; },
191 * By default, all insances can be a drop target. This can be disabled by
192 * setting isTarget to false.
199 * The padding configured for this drag and drop object for calculating
200 * the drop zone intersection with this object.
207 * Cached reference to the linked element
214 * Internal typeof flag
215 * @property __ygDragDrop
221 * Set to true when horizontal contraints are applied
222 * @property constrainX
229 * Set to true when vertical contraints are applied
230 * @property constrainY
237 * The left constraint
245 * The right constraint
262 * The down constraint
270 * Maintain offsets when we resetconstraints. Set to true when you want
271 * the position of the element relative to its parent to stay the same
272 * when the page changes
274 * @property maintainOffset
277 maintainOffset: false,
280 * Array of pixel locations the element will snap to if we specified a
281 * horizontal graduation/interval. This array is generated automatically
282 * when you define a tick interval.
289 * Array of pixel locations the element will snap to if we specified a
290 * vertical graduation/interval. This array is generated automatically
291 * when you define a tick interval.
298 * By default the drag and drop instance will only respond to the primary
299 * button click (left button for a right-handed mouse). Set to true to
300 * allow drag and drop to start with any mouse click that is propogated
302 * @property primaryButtonOnly
305 primaryButtonOnly: true,
308 * The availabe property is false until the linked dom element is accessible.
309 * @property available
315 * By default, drags can only be initiated if the mousedown occurs in the
316 * region the linked element is. This is done in part to work around a
317 * bug in some browsers that mis-report the mousedown if the previous
318 * mouseup happened outside of the window. This property is set to true
319 * if outer handles are defined.
321 * @property hasOuterHandles
325 hasOuterHandles: false,
328 * Code that executes immediately before the startDrag event
329 * @method b4StartDrag
332 b4StartDrag: function(x, y) { },
335 * Abstract method called after a drag/drop object is clicked
336 * and the drag or mousedown time thresholds have beeen met.
338 * @param {int} X click location
339 * @param {int} Y click location
341 startDrag: function(x, y) { /* override this */ },
344 * Code that executes immediately before the onDrag event
348 b4Drag: function(e) { },
351 * Abstract method called during the onMouseMove event while dragging an
354 * @param {Event} e the mousemove event
356 onDrag: function(e) { /* override this */ },
359 * Abstract method called when this element fist begins hovering over
360 * another DragDrop obj
361 * @method onDragEnter
362 * @param {Event} e the mousemove event
363 * @param {String|DragDrop[]} id In POINT mode, the element
364 * id this is hovering over. In INTERSECT mode, an array of one or more
365 * dragdrop items being hovered over.
367 onDragEnter: function(e, id) { /* override this */ },
370 * Code that executes immediately before the onDragOver event
374 b4DragOver: function(e) { },
377 * Abstract method called when this element is hovering over another
380 * @param {Event} e the mousemove event
381 * @param {String|DragDrop[]} id In POINT mode, the element
382 * id this is hovering over. In INTERSECT mode, an array of dd items
383 * being hovered over.
385 onDragOver: function(e, id) { /* override this */ },
388 * Code that executes immediately before the onDragOut event
392 b4DragOut: function(e) { },
395 * Abstract method called when we are no longer hovering over an element
397 * @param {Event} e the mousemove event
398 * @param {String|DragDrop[]} id In POINT mode, the element
399 * id this was hovering over. In INTERSECT mode, an array of dd items
400 * that the mouse is no longer over.
402 onDragOut: function(e, id) { /* override this */ },
405 * Code that executes immediately before the onDragDrop event
409 b4DragDrop: function(e) { },
412 * Abstract method called when this item is dropped on another DragDrop
415 * @param {Event} e the mouseup event
416 * @param {String|DragDrop[]} id In POINT mode, the element
417 * id this was dropped on. In INTERSECT mode, an array of dd items this
420 onDragDrop: function(e, id) { /* override this */ },
423 * Abstract method called when this item is dropped on an area with no
425 * @method onInvalidDrop
426 * @param {Event} e the mouseup event
428 onInvalidDrop: function(e) { /* override this */ },
431 * Code that executes immediately before the endDrag event
435 b4EndDrag: function(e) { },
438 * Fired when we are done dragging the object
440 * @param {Event} e the mouseup event
442 endDrag: function(e) { /* override this */ },
445 * Code executed immediately before the onMouseDown event
446 * @method b4MouseDown
447 * @param {Event} e the mousedown event
450 b4MouseDown: function(e) { },
453 * Event handler that fires when a drag/drop obj gets a mousedown
454 * @method onMouseDown
455 * @param {Event} e the mousedown event
457 onMouseDown: function(e) { /* override this */ },
460 * Event handler that fires when a drag/drop obj gets a mouseup
462 * @param {Event} e the mouseup event
464 onMouseUp: function(e) { /* override this */ },
467 * Override the onAvailable method to do what is needed after the initial
468 * position was determined.
469 * @method onAvailable
471 onAvailable: function () {
475 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
478 defaultPadding : {left:0, right:0, top:0, bottom:0},
481 * Initializes the drag drop object's constraints to restrict movement to a certain element.
485 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
486 { dragElId: "existingProxyDiv" });
487 dd.startDrag = function(){
488 this.constrainTo("parent-id");
491 * Or you can initalize it using the {@link Roo.Element} object:
493 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
494 startDrag : function(){
495 this.constrainTo("parent-id");
499 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
500 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
501 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
502 * an object containing the sides to pad. For example: {right:10, bottom:10}
503 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
505 constrainTo : function(constrainTo, pad, inContent){
506 if(typeof pad == "number"){
507 pad = {left: pad, right:pad, top:pad, bottom:pad};
509 pad = pad || this.defaultPadding;
510 var b = Roo.get(this.getEl()).getBox();
511 var ce = Roo.get(constrainTo);
512 var s = ce.getScroll();
514 if(cd == document.body){
515 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
518 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
522 var topSpace = b.y - c.y;
523 var leftSpace = b.x - c.x;
525 this.resetConstraints();
526 this.setXConstraint(leftSpace - (pad.left||0), // left
527 c.width - leftSpace - b.width - (pad.right||0) //right
529 this.setYConstraint(topSpace - (pad.top||0), //top
530 c.height - topSpace - b.height - (pad.bottom||0) //bottom
535 * Returns a reference to the linked element
537 * @return {HTMLElement} the html element
541 this._domRef = Roo.getDom(this.id);
548 * Returns a reference to the actual element to drag. By default this is
549 * the same as the html element, but it can be assigned to another
550 * element. An example of this can be found in Roo.dd.DDProxy
552 * @return {HTMLElement} the html element
554 getDragEl: function() {
555 return Roo.getDom(this.dragElId);
559 * Sets up the DragDrop object. Must be called in the constructor of any
560 * Roo.dd.DragDrop subclass
562 * @param id the id of the linked element
563 * @param {String} sGroup the group of related items
564 * @param {object} config configuration attributes
566 init: function(id, sGroup, config) {
567 this.initTarget(id, sGroup, config);
568 Event.on(this.id, "mousedown", this.handleMouseDown, this);
569 // Event.on(this.id, "selectstart", Event.preventDefault);
573 * Initializes Targeting functionality only... the object does not
574 * get a mousedown handler.
576 * @param id the id of the linked element
577 * @param {String} sGroup the group of related items
578 * @param {object} config configuration attributes
580 initTarget: function(id, sGroup, config) {
582 // configuration attributes
583 this.config = config || {};
585 // create a local reference to the drag and drop manager
586 this.DDM = Roo.dd.DDM;
587 // initialize the groups array
590 // assume that we have an element reference instead of an id if the
591 // parameter is not a string
592 if (typeof id !== "string") {
599 // add to an interaction group
600 this.addToGroup((sGroup) ? sGroup : "default");
602 // We don't want to register this as the handle with the manager
603 // so we just set the id rather than calling the setter.
604 this.handleElId = id;
606 // the linked element is the element that gets dragged by default
607 this.setDragElId(id);
609 // by default, clicked anchors will not start drag operations.
610 this.invalidHandleTypes = { A: "A" };
611 this.invalidHandleIds = {};
612 this.invalidHandleClasses = [];
616 this.handleOnAvailable();
620 * Applies the configuration parameters that were passed into the constructor.
621 * This is supposed to happen at each level through the inheritance chain. So
622 * a DDProxy implentation will execute apply config on DDProxy, DD, and
623 * DragDrop in order to get all of the parameters that are available in
625 * @method applyConfig
627 applyConfig: function() {
629 // configurable properties:
630 // padding, isTarget, maintainOffset, primaryButtonOnly
631 this.padding = this.config.padding || [0, 0, 0, 0];
632 this.isTarget = (this.config.isTarget !== false);
633 this.maintainOffset = (this.config.maintainOffset);
634 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
639 * Executed when the linked element is available
640 * @method handleOnAvailable
643 handleOnAvailable: function() {
644 this.available = true;
645 this.resetConstraints();
650 * Configures the padding for the target zone in px. Effectively expands
651 * (or reduces) the virtual object size for targeting calculations.
652 * Supports css-style shorthand; if only one parameter is passed, all sides
653 * will have that padding, and if only two are passed, the top and bottom
654 * will have the first param, the left and right the second.
656 * @param {int} iTop Top pad
657 * @param {int} iRight Right pad
658 * @param {int} iBot Bot pad
659 * @param {int} iLeft Left pad
661 setPadding: function(iTop, iRight, iBot, iLeft) {
662 // this.padding = [iLeft, iRight, iTop, iBot];
663 if (!iRight && 0 !== iRight) {
664 this.padding = [iTop, iTop, iTop, iTop];
665 } else if (!iBot && 0 !== iBot) {
666 this.padding = [iTop, iRight, iTop, iRight];
668 this.padding = [iTop, iRight, iBot, iLeft];
673 * Stores the initial placement of the linked element.
674 * @method setInitialPosition
675 * @param {int} diffX the X offset, default 0
676 * @param {int} diffY the Y offset, default 0
678 setInitPosition: function(diffX, diffY) {
679 var el = this.getEl();
681 if (!this.DDM.verifyEl(el)) {
688 var p = Dom.getXY( el );
690 this.initPageX = p[0] - dx;
691 this.initPageY = p[1] - dy;
693 this.lastPageX = p[0];
694 this.lastPageY = p[1];
697 this.setStartPosition(p);
701 * Sets the start position of the element. This is set when the obj
702 * is initialized, the reset when a drag is started.
703 * @method setStartPosition
704 * @param pos current position (from previous lookup)
707 setStartPosition: function(pos) {
708 var p = pos || Dom.getXY( this.getEl() );
709 this.deltaSetXY = null;
711 this.startPageX = p[0];
712 this.startPageY = p[1];
716 * Add this instance to a group of related drag/drop objects. All
717 * instances belong to at least one group, and can belong to as many
720 * @param sGroup {string} the name of the group
722 addToGroup: function(sGroup) {
723 this.groups[sGroup] = true;
724 this.DDM.regDragDrop(this, sGroup);
728 * Remove's this instance from the supplied interaction group
729 * @method removeFromGroup
730 * @param {string} sGroup The group to drop
732 removeFromGroup: function(sGroup) {
733 if (this.groups[sGroup]) {
734 delete this.groups[sGroup];
737 this.DDM.removeDDFromGroup(this, sGroup);
741 * Allows you to specify that an element other than the linked element
742 * will be moved with the cursor during a drag
743 * @method setDragElId
744 * @param id {string} the id of the element that will be used to initiate the drag
746 setDragElId: function(id) {
751 * Allows you to specify a child of the linked element that should be
752 * used to initiate the drag operation. An example of this would be if
753 * you have a content div with text and links. Clicking anywhere in the
754 * content area would normally start the drag operation. Use this method
755 * to specify that an element inside of the content div is the element
756 * that starts the drag operation.
757 * @method setHandleElId
758 * @param id {string} the id of the element that will be used to
761 setHandleElId: function(id) {
762 if (typeof id !== "string") {
765 this.handleElId = id;
766 this.DDM.regHandle(this.id, id);
770 * Allows you to set an element outside of the linked element as a drag
772 * @method setOuterHandleElId
773 * @param id the id of the element that will be used to initiate the drag
775 setOuterHandleElId: function(id) {
776 if (typeof id !== "string") {
779 Event.on(id, "mousedown",
780 this.handleMouseDown, this);
781 this.setHandleElId(id);
783 this.hasOuterHandles = true;
787 * Remove all drag and drop hooks for this element
791 Event.un(this.id, "mousedown",
792 this.handleMouseDown);
794 this.DDM._remove(this);
797 destroy : function(){
802 * Returns true if this instance is locked, or the drag drop mgr is locked
803 * (meaning that all drag/drop is disabled on the page.)
805 * @return {boolean} true if this obj or all drag/drop is locked, else
808 isLocked: function() {
809 return (this.DDM.isLocked() || this.locked);
813 * Fired when this object is clicked
814 * @method handleMouseDown
816 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
819 handleMouseDown: function(e, oDD){
820 if (this.primaryButtonOnly && e.button != 0) {
824 if (this.isLocked()) {
828 this.DDM.refreshCache(this.groups);
830 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
831 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
833 if (this.clickValidator(e)) {
835 // set the initial element position
836 this.setStartPosition();
842 this.DDM.handleMouseDown(e, this);
844 this.DDM.stopEvent(e);
852 clickValidator: function(e) {
853 var target = e.getTarget();
854 return ( this.isValidHandleChild(target) &&
855 (this.id == this.handleElId ||
856 this.DDM.handleWasClicked(target, this.id)) );
860 * Allows you to specify a tag name that should not start a drag operation
861 * when clicked. This is designed to facilitate embedding links within a
862 * drag handle that do something other than start the drag.
863 * @method addInvalidHandleType
864 * @param {string} tagName the type of element to exclude
866 addInvalidHandleType: function(tagName) {
867 var type = tagName.toUpperCase();
868 this.invalidHandleTypes[type] = type;
872 * Lets you to specify an element id for a child of a drag handle
873 * that should not initiate a drag
874 * @method addInvalidHandleId
875 * @param {string} id the element id of the element you wish to ignore
877 addInvalidHandleId: function(id) {
878 if (typeof id !== "string") {
881 this.invalidHandleIds[id] = id;
885 * Lets you specify a css class of elements that will not initiate a drag
886 * @method addInvalidHandleClass
887 * @param {string} cssClass the class of the elements you wish to ignore
889 addInvalidHandleClass: function(cssClass) {
890 this.invalidHandleClasses.push(cssClass);
894 * Unsets an excluded tag name set by addInvalidHandleType
895 * @method removeInvalidHandleType
896 * @param {string} tagName the type of element to unexclude
898 removeInvalidHandleType: function(tagName) {
899 var type = tagName.toUpperCase();
900 // this.invalidHandleTypes[type] = null;
901 delete this.invalidHandleTypes[type];
905 * Unsets an invalid handle id
906 * @method removeInvalidHandleId
907 * @param {string} id the id of the element to re-enable
909 removeInvalidHandleId: function(id) {
910 if (typeof id !== "string") {
913 delete this.invalidHandleIds[id];
917 * Unsets an invalid css class
918 * @method removeInvalidHandleClass
919 * @param {string} cssClass the class of the element(s) you wish to
922 removeInvalidHandleClass: function(cssClass) {
923 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
924 if (this.invalidHandleClasses[i] == cssClass) {
925 delete this.invalidHandleClasses[i];
931 * Checks the tag exclusion list to see if this click should be ignored
932 * @method isValidHandleChild
933 * @param {HTMLElement} node the HTMLElement to evaluate
934 * @return {boolean} true if this is a valid tag type, false if not
936 isValidHandleChild: function(node) {
939 // var n = (node.nodeName == "#text") ? node.parentNode : node;
942 nodeName = node.nodeName.toUpperCase();
944 nodeName = node.nodeName;
946 valid = valid && !this.invalidHandleTypes[nodeName];
947 valid = valid && !this.invalidHandleIds[node.id];
949 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
950 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
959 * Create the array of horizontal tick marks if an interval was specified
960 * in setXConstraint().
964 setXTicks: function(iStartX, iTickSize) {
966 this.xTickSize = iTickSize;
970 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
972 this.xTicks[this.xTicks.length] = i;
977 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
979 this.xTicks[this.xTicks.length] = i;
984 this.xTicks.sort(this.DDM.numericSort) ;
988 * Create the array of vertical tick marks if an interval was specified in
993 setYTicks: function(iStartY, iTickSize) {
995 this.yTickSize = iTickSize;
999 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1001 this.yTicks[this.yTicks.length] = i;
1006 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1008 this.yTicks[this.yTicks.length] = i;
1013 this.yTicks.sort(this.DDM.numericSort) ;
1017 * By default, the element can be dragged any place on the screen. Use
1018 * this method to limit the horizontal travel of the element. Pass in
1019 * 0,0 for the parameters if you want to lock the drag to the y axis.
1020 * @method setXConstraint
1021 * @param {int} iLeft the number of pixels the element can move to the left
1022 * @param {int} iRight the number of pixels the element can move to the
1024 * @param {int} iTickSize optional parameter for specifying that the
1026 * should move iTickSize pixels at a time.
1028 setXConstraint: function(iLeft, iRight, iTickSize) {
1029 this.leftConstraint = iLeft;
1030 this.rightConstraint = iRight;
1032 this.minX = this.initPageX - iLeft;
1033 this.maxX = this.initPageX + iRight;
1034 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1036 this.constrainX = true;
1040 * Clears any constraints applied to this instance. Also clears ticks
1041 * since they can't exist independent of a constraint at this time.
1042 * @method clearConstraints
1044 clearConstraints: function() {
1045 this.constrainX = false;
1046 this.constrainY = false;
1051 * Clears any tick interval defined for this instance
1052 * @method clearTicks
1054 clearTicks: function() {
1062 * By default, the element can be dragged any place on the screen. Set
1063 * this to limit the vertical travel of the element. Pass in 0,0 for the
1064 * parameters if you want to lock the drag to the x axis.
1065 * @method setYConstraint
1066 * @param {int} iUp the number of pixels the element can move up
1067 * @param {int} iDown the number of pixels the element can move down
1068 * @param {int} iTickSize optional parameter for specifying that the
1069 * element should move iTickSize pixels at a time.
1071 setYConstraint: function(iUp, iDown, iTickSize) {
1072 this.topConstraint = iUp;
1073 this.bottomConstraint = iDown;
1075 this.minY = this.initPageY - iUp;
1076 this.maxY = this.initPageY + iDown;
1077 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1079 this.constrainY = true;
1084 * resetConstraints must be called if you manually reposition a dd element.
1085 * @method resetConstraints
1086 * @param {boolean} maintainOffset
1088 resetConstraints: function() {
1091 // Maintain offsets if necessary
1092 if (this.initPageX || this.initPageX === 0) {
1093 // figure out how much this thing has moved
1094 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1095 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1097 this.setInitPosition(dx, dy);
1099 // This is the first time we have detected the element's position
1101 this.setInitPosition();
1104 if (this.constrainX) {
1105 this.setXConstraint( this.leftConstraint,
1106 this.rightConstraint,
1110 if (this.constrainY) {
1111 this.setYConstraint( this.topConstraint,
1112 this.bottomConstraint,
1118 * Normally the drag element is moved pixel by pixel, but we can specify
1119 * that it move a number of pixels at a time. This method resolves the
1120 * location when we have it set up like this.
1122 * @param {int} val where we want to place the object
1123 * @param {int[]} tickArray sorted array of valid points
1124 * @return {int} the closest tick
1127 getTick: function(val, tickArray) {
1130 // If tick interval is not defined, it is effectively 1 pixel,
1131 // so we return the value passed to us.
1133 } else if (tickArray[0] >= val) {
1134 // The value is lower than the first tick, so we return the first
1136 return tickArray[0];
1138 for (var i=0, len=tickArray.length; i<len; ++i) {
1140 if (tickArray[next] && tickArray[next] >= val) {
1141 var diff1 = val - tickArray[i];
1142 var diff2 = tickArray[next] - val;
1143 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1147 // The value is larger than the last tick, so we return the last
1149 return tickArray[tickArray.length - 1];
1156 * @return {string} string representation of the dd obj
1158 toString: function() {
1159 return ("DragDrop " + this.id);
1167 * Ext JS Library 1.1.1
1168 * Copyright(c) 2006-2007, Ext JS, LLC.
1170 * Originally Released Under LGPL - original licence link has changed is not relivant.
1173 * <script type="text/javascript">
1178 * The drag and drop utility provides a framework for building drag and drop
1179 * applications. In addition to enabling drag and drop for specific elements,
1180 * the drag and drop elements are tracked by the manager class, and the
1181 * interactions between the various elements are tracked during the drag and
1182 * the implementing code is notified about these important moments.
1185 // Only load the library once. Rewriting the manager class would orphan
1186 // existing drag and drop instances.
1187 if (!Roo.dd.DragDropMgr) {
1190 * @class Roo.dd.DragDropMgr
1191 * DragDropMgr is a singleton that tracks the element interaction for
1192 * all DragDrop items in the window. Generally, you will not call
1193 * this class directly, but it does have helper methods that could
1194 * be useful in your DragDrop implementations.
1197 Roo.dd.DragDropMgr = function() {
1199 var Event = Roo.EventManager;
1204 * Two dimensional Array of registered DragDrop objects. The first
1205 * dimension is the DragDrop item group, the second the DragDrop
1208 * @type {string: string}
1215 * Array of element ids defined as drag handles. Used to determine
1216 * if the element that generated the mousedown event is actually the
1217 * handle and not the html element itself.
1218 * @property handleIds
1219 * @type {string: string}
1226 * the DragDrop object that is currently being dragged
1227 * @property dragCurrent
1235 * the DragDrop object(s) that are being hovered over
1236 * @property dragOvers
1244 * the X distance between the cursor and the object being dragged
1253 * the Y distance between the cursor and the object being dragged
1262 * Flag to determine if we should prevent the default behavior of the
1263 * events we define. By default this is true, but this can be set to
1264 * false if you need the default behavior (not recommended)
1265 * @property preventDefault
1269 preventDefault: true,
1272 * Flag to determine if we should stop the propagation of the events
1273 * we generate. This is true by default but you may want to set it to
1274 * false if the html element contains other features that require the
1276 * @property stopPropagation
1280 stopPropagation: true,
1283 * Internal flag that is set to true when drag and drop has been
1285 * @property initialized
1292 * All drag and drop can be disabled.
1300 * Called the first time an element is registered.
1306 this.initialized = true;
1310 * In point mode, drag and drop interaction is defined by the
1311 * location of the cursor during the drag/drop
1319 * In intersect mode, drag and drop interactio nis defined by the
1320 * overlap of two or more drag and drop objects.
1321 * @property INTERSECT
1328 * The current drag and drop mode. Default: POINT
1336 * Runs method on all drag and drop objects
1337 * @method _execOnAll
1341 _execOnAll: function(sMethod, args) {
1342 for (var i in this.ids) {
1343 for (var j in this.ids[i]) {
1344 var oDD = this.ids[i][j];
1345 if (! this.isTypeOfDD(oDD)) {
1348 oDD[sMethod].apply(oDD, args);
1354 * Drag and drop initialization. Sets up the global event handlers
1359 _onLoad: function() {
1364 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1365 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1366 Event.on(window, "unload", this._onUnload, this, true);
1367 Event.on(window, "resize", this._onResize, this, true);
1368 // Event.on(window, "mouseout", this._test);
1373 * Reset constraints on all drag and drop objs
1378 _onResize: function(e) {
1379 this._execOnAll("resetConstraints", []);
1383 * Lock all drag and drop functionality
1387 lock: function() { this.locked = true; },
1390 * Unlock all drag and drop functionality
1394 unlock: function() { this.locked = false; },
1397 * Is drag and drop locked?
1399 * @return {boolean} True if drag and drop is locked, false otherwise.
1402 isLocked: function() { return this.locked; },
1405 * Location cache that is set for all drag drop objects when a drag is
1406 * initiated, cleared when the drag is finished.
1407 * @property locationCache
1414 * Set useCache to false if you want to force object the lookup of each
1415 * drag and drop linked element constantly during a drag.
1416 * @property useCache
1423 * The number of pixels that the mouse needs to move after the
1424 * mousedown before the drag is initiated. Default=3;
1425 * @property clickPixelThresh
1429 clickPixelThresh: 3,
1432 * The number of milliseconds after the mousedown event to initiate the
1433 * drag if we don't get a mouseup event. Default=1000
1434 * @property clickTimeThresh
1438 clickTimeThresh: 350,
1441 * Flag that indicates that either the drag pixel threshold or the
1442 * mousdown time threshold has been met
1443 * @property dragThreshMet
1448 dragThreshMet: false,
1451 * Timeout used for the click time threshold
1452 * @property clickTimeout
1460 * The X position of the mousedown event stored for later use when a
1461 * drag threshold is met.
1470 * The Y position of the mousedown event stored for later use when a
1471 * drag threshold is met.
1480 * Each DragDrop instance must be registered with the DragDropMgr.
1481 * This is executed in DragDrop.init()
1482 * @method regDragDrop
1483 * @param {DragDrop} oDD the DragDrop object to register
1484 * @param {String} sGroup the name of the group this element belongs to
1487 regDragDrop: function(oDD, sGroup) {
1488 if (!this.initialized) { this.init(); }
1490 if (!this.ids[sGroup]) {
1491 this.ids[sGroup] = {};
1493 this.ids[sGroup][oDD.id] = oDD;
1497 * Removes the supplied dd instance from the supplied group. Executed
1498 * by DragDrop.removeFromGroup, so don't call this function directly.
1499 * @method removeDDFromGroup
1503 removeDDFromGroup: function(oDD, sGroup) {
1504 if (!this.ids[sGroup]) {
1505 this.ids[sGroup] = {};
1508 var obj = this.ids[sGroup];
1509 if (obj && obj[oDD.id]) {
1515 * Unregisters a drag and drop item. This is executed in
1516 * DragDrop.unreg, use that method instead of calling this directly.
1521 _remove: function(oDD) {
1522 for (var g in oDD.groups) {
1523 if (g && this.ids[g][oDD.id]) {
1524 delete this.ids[g][oDD.id];
1527 delete this.handleIds[oDD.id];
1531 * Each DragDrop handle element must be registered. This is done
1532 * automatically when executing DragDrop.setHandleElId()
1534 * @param {String} sDDId the DragDrop id this element is a handle for
1535 * @param {String} sHandleId the id of the element that is the drag
1539 regHandle: function(sDDId, sHandleId) {
1540 if (!this.handleIds[sDDId]) {
1541 this.handleIds[sDDId] = {};
1543 this.handleIds[sDDId][sHandleId] = sHandleId;
1547 * Utility function to determine if a given element has been
1548 * registered as a drag drop item.
1549 * @method isDragDrop
1550 * @param {String} id the element id to check
1551 * @return {boolean} true if this element is a DragDrop item,
1555 isDragDrop: function(id) {
1556 return ( this.getDDById(id) ) ? true : false;
1560 * Returns the drag and drop instances that are in all groups the
1561 * passed in instance belongs to.
1562 * @method getRelated
1563 * @param {DragDrop} p_oDD the obj to get related data for
1564 * @param {boolean} bTargetsOnly if true, only return targetable objs
1565 * @return {DragDrop[]} the related instances
1568 getRelated: function(p_oDD, bTargetsOnly) {
1570 for (var i in p_oDD.groups) {
1571 for (j in this.ids[i]) {
1572 var dd = this.ids[i][j];
1573 if (! this.isTypeOfDD(dd)) {
1576 if (!bTargetsOnly || dd.isTarget) {
1577 oDDs[oDDs.length] = dd;
1586 * Returns true if the specified dd target is a legal target for
1587 * the specifice drag obj
1588 * @method isLegalTarget
1589 * @param {DragDrop} the drag obj
1590 * @param {DragDrop} the target
1591 * @return {boolean} true if the target is a legal target for the
1595 isLegalTarget: function (oDD, oTargetDD) {
1596 var targets = this.getRelated(oDD, true);
1597 for (var i=0, len=targets.length;i<len;++i) {
1598 if (targets[i].id == oTargetDD.id) {
1607 * My goal is to be able to transparently determine if an object is
1608 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1609 * returns "object", oDD.constructor.toString() always returns
1610 * "DragDrop" and not the name of the subclass. So for now it just
1611 * evaluates a well-known variable in DragDrop.
1612 * @method isTypeOfDD
1613 * @param {Object} the object to evaluate
1614 * @return {boolean} true if typeof oDD = DragDrop
1617 isTypeOfDD: function (oDD) {
1618 return (oDD && oDD.__ygDragDrop);
1622 * Utility function to determine if a given element has been
1623 * registered as a drag drop handle for the given Drag Drop object.
1625 * @param {String} id the element id to check
1626 * @return {boolean} true if this element is a DragDrop handle, false
1630 isHandle: function(sDDId, sHandleId) {
1631 return ( this.handleIds[sDDId] &&
1632 this.handleIds[sDDId][sHandleId] );
1636 * Returns the DragDrop instance for a given id
1638 * @param {String} id the id of the DragDrop object
1639 * @return {DragDrop} the drag drop object, null if it is not found
1642 getDDById: function(id) {
1643 for (var i in this.ids) {
1644 if (this.ids[i][id]) {
1645 return this.ids[i][id];
1652 * Fired after a registered DragDrop object gets the mousedown event.
1653 * Sets up the events required to track the object being dragged
1654 * @method handleMouseDown
1655 * @param {Event} e the event
1656 * @param oDD the DragDrop object being dragged
1660 handleMouseDown: function(e, oDD) {
1662 Roo.QuickTips.disable();
1664 this.currentTarget = e.getTarget();
1666 this.dragCurrent = oDD;
1668 var el = oDD.getEl();
1670 // track start position
1671 this.startX = e.getPageX();
1672 this.startY = e.getPageY();
1674 this.deltaX = this.startX - el.offsetLeft;
1675 this.deltaY = this.startY - el.offsetTop;
1677 this.dragThreshMet = false;
1679 this.clickTimeout = setTimeout(
1681 var DDM = Roo.dd.DDM;
1682 DDM.startDrag(DDM.startX, DDM.startY);
1684 this.clickTimeThresh );
1688 * Fired when either the drag pixel threshol or the mousedown hold
1689 * time threshold has been met.
1691 * @param x {int} the X position of the original mousedown
1692 * @param y {int} the Y position of the original mousedown
1695 startDrag: function(x, y) {
1696 clearTimeout(this.clickTimeout);
1697 if (this.dragCurrent) {
1698 this.dragCurrent.b4StartDrag(x, y);
1699 this.dragCurrent.startDrag(x, y);
1701 this.dragThreshMet = true;
1705 * Internal function to handle the mouseup event. Will be invoked
1706 * from the context of the document.
1707 * @method handleMouseUp
1708 * @param {Event} e the event
1712 handleMouseUp: function(e) {
1715 Roo.QuickTips.enable();
1717 if (! this.dragCurrent) {
1721 clearTimeout(this.clickTimeout);
1723 if (this.dragThreshMet) {
1724 this.fireEvents(e, true);
1734 * Utility to stop event propagation and event default, if these
1735 * features are turned on.
1737 * @param {Event} e the event as returned by this.getEvent()
1740 stopEvent: function(e){
1741 if(this.stopPropagation) {
1742 e.stopPropagation();
1745 if (this.preventDefault) {
1751 * Internal function to clean up event handlers after the drag
1752 * operation is complete
1754 * @param {Event} e the event
1758 stopDrag: function(e) {
1759 // Fire the drag end event for the item that was dragged
1760 if (this.dragCurrent) {
1761 if (this.dragThreshMet) {
1762 this.dragCurrent.b4EndDrag(e);
1763 this.dragCurrent.endDrag(e);
1766 this.dragCurrent.onMouseUp(e);
1769 this.dragCurrent = null;
1770 this.dragOvers = {};
1774 * Internal function to handle the mousemove event. Will be invoked
1775 * from the context of the html element.
1777 * @TODO figure out what we can do about mouse events lost when the
1778 * user drags objects beyond the window boundary. Currently we can
1779 * detect this in internet explorer by verifying that the mouse is
1780 * down during the mousemove event. Firefox doesn't give us the
1781 * button state on the mousemove event.
1782 * @method handleMouseMove
1783 * @param {Event} e the event
1787 handleMouseMove: function(e) {
1788 if (! this.dragCurrent) {
1792 // var button = e.which || e.button;
1794 // check for IE mouseup outside of page boundary
1795 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1797 return this.handleMouseUp(e);
1800 if (!this.dragThreshMet) {
1801 var diffX = Math.abs(this.startX - e.getPageX());
1802 var diffY = Math.abs(this.startY - e.getPageY());
1803 if (diffX > this.clickPixelThresh ||
1804 diffY > this.clickPixelThresh) {
1805 this.startDrag(this.startX, this.startY);
1809 if (this.dragThreshMet) {
1810 this.dragCurrent.b4Drag(e);
1811 this.dragCurrent.onDrag(e);
1812 if(!this.dragCurrent.moveOnly){
1813 this.fireEvents(e, false);
1823 * Iterates over all of the DragDrop elements to find ones we are
1824 * hovering over or dropping on
1825 * @method fireEvents
1826 * @param {Event} e the event
1827 * @param {boolean} isDrop is this a drop op or a mouseover op?
1831 fireEvents: function(e, isDrop) {
1832 var dc = this.dragCurrent;
1834 // If the user did the mouse up outside of the window, we could
1835 // get here even though we have ended the drag.
1836 if (!dc || dc.isLocked()) {
1840 var pt = e.getPoint();
1842 // cache the previous dragOver array
1850 // Check to see if the object(s) we were hovering over is no longer
1851 // being hovered over so we can fire the onDragOut event
1852 for (var i in this.dragOvers) {
1854 var ddo = this.dragOvers[i];
1856 if (! this.isTypeOfDD(ddo)) {
1860 if (! this.isOverTarget(pt, ddo, this.mode)) {
1861 outEvts.push( ddo );
1865 delete this.dragOvers[i];
1868 for (var sGroup in dc.groups) {
1870 if ("string" != typeof sGroup) {
1874 for (i in this.ids[sGroup]) {
1875 var oDD = this.ids[sGroup][i];
1876 if (! this.isTypeOfDD(oDD)) {
1880 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1881 if (this.isOverTarget(pt, oDD, this.mode)) {
1882 // look for drop interactions
1884 dropEvts.push( oDD );
1885 // look for drag enter and drag over interactions
1888 // initial drag over: dragEnter fires
1889 if (!oldOvers[oDD.id]) {
1890 enterEvts.push( oDD );
1891 // subsequent drag overs: dragOver fires
1893 overEvts.push( oDD );
1896 this.dragOvers[oDD.id] = oDD;
1904 if (outEvts.length) {
1905 dc.b4DragOut(e, outEvts);
1906 dc.onDragOut(e, outEvts);
1909 if (enterEvts.length) {
1910 dc.onDragEnter(e, enterEvts);
1913 if (overEvts.length) {
1914 dc.b4DragOver(e, overEvts);
1915 dc.onDragOver(e, overEvts);
1918 if (dropEvts.length) {
1919 dc.b4DragDrop(e, dropEvts);
1920 dc.onDragDrop(e, dropEvts);
1924 // fire dragout events
1926 for (i=0, len=outEvts.length; i<len; ++i) {
1927 dc.b4DragOut(e, outEvts[i].id);
1928 dc.onDragOut(e, outEvts[i].id);
1931 // fire enter events
1932 for (i=0,len=enterEvts.length; i<len; ++i) {
1933 // dc.b4DragEnter(e, oDD.id);
1934 dc.onDragEnter(e, enterEvts[i].id);
1938 for (i=0,len=overEvts.length; i<len; ++i) {
1939 dc.b4DragOver(e, overEvts[i].id);
1940 dc.onDragOver(e, overEvts[i].id);
1944 for (i=0, len=dropEvts.length; i<len; ++i) {
1945 dc.b4DragDrop(e, dropEvts[i].id);
1946 dc.onDragDrop(e, dropEvts[i].id);
1951 // notify about a drop that did not find a target
1952 if (isDrop && !dropEvts.length) {
1953 dc.onInvalidDrop(e);
1959 * Helper function for getting the best match from the list of drag
1960 * and drop objects returned by the drag and drop events when we are
1961 * in INTERSECT mode. It returns either the first object that the
1962 * cursor is over, or the object that has the greatest overlap with
1963 * the dragged element.
1964 * @method getBestMatch
1965 * @param {DragDrop[]} dds The array of drag and drop objects
1967 * @return {DragDrop} The best single match
1970 getBestMatch: function(dds) {
1972 // Return null if the input is not what we expect
1973 //if (!dds || !dds.length || dds.length == 0) {
1975 // If there is only one item, it wins
1976 //} else if (dds.length == 1) {
1978 var len = dds.length;
1983 // Loop through the targeted items
1984 for (var i=0; i<len; ++i) {
1986 // If the cursor is over the object, it wins. If the
1987 // cursor is over multiple matches, the first one we come
1989 if (dd.cursorIsOver) {
1992 // Otherwise the object with the most overlap wins
1995 winner.overlap.getArea() < dd.overlap.getArea()) {
2006 * Refreshes the cache of the top-left and bottom-right points of the
2007 * drag and drop objects in the specified group(s). This is in the
2008 * format that is stored in the drag and drop instance, so typical
2011 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2015 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2017 * @TODO this really should be an indexed array. Alternatively this
2018 * method could accept both.
2019 * @method refreshCache
2020 * @param {Object} groups an associative array of groups to refresh
2023 refreshCache: function(groups) {
2024 for (var sGroup in groups) {
2025 if ("string" != typeof sGroup) {
2028 for (var i in this.ids[sGroup]) {
2029 var oDD = this.ids[sGroup][i];
2031 if (this.isTypeOfDD(oDD)) {
2032 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2033 var loc = this.getLocation(oDD);
2035 this.locationCache[oDD.id] = loc;
2037 delete this.locationCache[oDD.id];
2038 // this will unregister the drag and drop object if
2039 // the element is not in a usable state
2048 * This checks to make sure an element exists and is in the DOM. The
2049 * main purpose is to handle cases where innerHTML is used to remove
2050 * drag and drop objects from the DOM. IE provides an 'unspecified
2051 * error' when trying to access the offsetParent of such an element
2053 * @param {HTMLElement} el the element to check
2054 * @return {boolean} true if the element looks usable
2057 verifyEl: function(el) {
2062 parent = el.offsetParent;
2065 parent = el.offsetParent;
2076 * Returns a Region object containing the drag and drop element's position
2077 * and size, including the padding configured for it
2078 * @method getLocation
2079 * @param {DragDrop} oDD the drag and drop object to get the
2081 * @return {Roo.lib.Region} a Region object representing the total area
2082 * the element occupies, including any padding
2083 * the instance is configured for.
2086 getLocation: function(oDD) {
2087 if (! this.isTypeOfDD(oDD)) {
2091 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2094 pos= Roo.lib.Dom.getXY(el);
2102 x2 = x1 + el.offsetWidth;
2104 y2 = y1 + el.offsetHeight;
2106 t = y1 - oDD.padding[0];
2107 r = x2 + oDD.padding[1];
2108 b = y2 + oDD.padding[2];
2109 l = x1 - oDD.padding[3];
2111 return new Roo.lib.Region( t, r, b, l );
2115 * Checks the cursor location to see if it over the target
2116 * @method isOverTarget
2117 * @param {Roo.lib.Point} pt The point to evaluate
2118 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2119 * @return {boolean} true if the mouse is over the target
2123 isOverTarget: function(pt, oTarget, intersect) {
2124 // use cache if available
2125 var loc = this.locationCache[oTarget.id];
2126 if (!loc || !this.useCache) {
2127 loc = this.getLocation(oTarget);
2128 this.locationCache[oTarget.id] = loc;
2136 oTarget.cursorIsOver = loc.contains( pt );
2138 // DragDrop is using this as a sanity check for the initial mousedown
2139 // in this case we are done. In POINT mode, if the drag obj has no
2140 // contraints, we are also done. Otherwise we need to evaluate the
2141 // location of the target as related to the actual location of the
2143 var dc = this.dragCurrent;
2144 if (!dc || !dc.getTargetCoord ||
2145 (!intersect && !dc.constrainX && !dc.constrainY)) {
2146 return oTarget.cursorIsOver;
2149 oTarget.overlap = null;
2151 // Get the current location of the drag element, this is the
2152 // location of the mouse event less the delta that represents
2153 // where the original mousedown happened on the element. We
2154 // need to consider constraints and ticks as well.
2155 var pos = dc.getTargetCoord(pt.x, pt.y);
2157 var el = dc.getDragEl();
2158 var curRegion = new Roo.lib.Region( pos.y,
2159 pos.x + el.offsetWidth,
2160 pos.y + el.offsetHeight,
2163 var overlap = curRegion.intersect(loc);
2166 oTarget.overlap = overlap;
2167 return (intersect) ? true : oTarget.cursorIsOver;
2174 * unload event handler
2179 _onUnload: function(e, me) {
2180 Roo.dd.DragDropMgr.unregAll();
2184 * Cleans up the drag and drop events and objects.
2189 unregAll: function() {
2191 if (this.dragCurrent) {
2193 this.dragCurrent = null;
2196 this._execOnAll("unreg", []);
2198 for (i in this.elementCache) {
2199 delete this.elementCache[i];
2202 this.elementCache = {};
2207 * A cache of DOM elements
2208 * @property elementCache
2215 * Get the wrapper for the DOM element specified
2216 * @method getElWrapper
2217 * @param {String} id the id of the element to get
2218 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2220 * @deprecated This wrapper isn't that useful
2223 getElWrapper: function(id) {
2224 var oWrapper = this.elementCache[id];
2225 if (!oWrapper || !oWrapper.el) {
2226 oWrapper = this.elementCache[id] =
2227 new this.ElementWrapper(Roo.getDom(id));
2233 * Returns the actual DOM element
2234 * @method getElement
2235 * @param {String} id the id of the elment to get
2236 * @return {Object} The element
2237 * @deprecated use Roo.getDom instead
2240 getElement: function(id) {
2241 return Roo.getDom(id);
2245 * Returns the style property for the DOM element (i.e.,
2246 * document.getElById(id).style)
2248 * @param {String} id the id of the elment to get
2249 * @return {Object} The style property of the element
2250 * @deprecated use Roo.getDom instead
2253 getCss: function(id) {
2254 var el = Roo.getDom(id);
2255 return (el) ? el.style : null;
2259 * Inner class for cached elements
2260 * @class DragDropMgr.ElementWrapper
2265 ElementWrapper: function(el) {
2270 this.el = el || null;
2275 this.id = this.el && el.id;
2277 * A reference to the style property
2280 this.css = this.el && el.style;
2284 * Returns the X position of an html element
2286 * @param el the element for which to get the position
2287 * @return {int} the X coordinate
2289 * @deprecated use Roo.lib.Dom.getX instead
2292 getPosX: function(el) {
2293 return Roo.lib.Dom.getX(el);
2297 * Returns the Y position of an html element
2299 * @param el the element for which to get the position
2300 * @return {int} the Y coordinate
2301 * @deprecated use Roo.lib.Dom.getY instead
2304 getPosY: function(el) {
2305 return Roo.lib.Dom.getY(el);
2309 * Swap two nodes. In IE, we use the native method, for others we
2310 * emulate the IE behavior
2312 * @param n1 the first node to swap
2313 * @param n2 the other node to swap
2316 swapNode: function(n1, n2) {
2320 var p = n2.parentNode;
2321 var s = n2.nextSibling;
2324 p.insertBefore(n1, n2);
2325 } else if (n2 == n1.nextSibling) {
2326 p.insertBefore(n2, n1);
2328 n1.parentNode.replaceChild(n2, n1);
2329 p.insertBefore(n1, s);
2335 * Returns the current scroll position
2340 getScroll: function () {
2341 var t, l, dde=document.documentElement, db=document.body;
2342 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2351 return { top: t, left: l };
2355 * Returns the specified element style property
2357 * @param {HTMLElement} el the element
2358 * @param {string} styleProp the style property
2359 * @return {string} The value of the style property
2360 * @deprecated use Roo.lib.Dom.getStyle
2363 getStyle: function(el, styleProp) {
2364 return Roo.fly(el).getStyle(styleProp);
2368 * Gets the scrollTop
2369 * @method getScrollTop
2370 * @return {int} the document's scrollTop
2373 getScrollTop: function () { return this.getScroll().top; },
2376 * Gets the scrollLeft
2377 * @method getScrollLeft
2378 * @return {int} the document's scrollTop
2381 getScrollLeft: function () { return this.getScroll().left; },
2384 * Sets the x/y position of an element to the location of the
2387 * @param {HTMLElement} moveEl The element to move
2388 * @param {HTMLElement} targetEl The position reference element
2391 moveToEl: function (moveEl, targetEl) {
2392 var aCoord = Roo.lib.Dom.getXY(targetEl);
2393 Roo.lib.Dom.setXY(moveEl, aCoord);
2397 * Numeric array sort function
2398 * @method numericSort
2401 numericSort: function(a, b) { return (a - b); },
2405 * @property _timeoutCount
2412 * Trying to make the load order less important. Without this we get
2413 * an error if this file is loaded before the Event Utility.
2414 * @method _addListeners
2418 _addListeners: function() {
2419 var DDM = Roo.dd.DDM;
2420 if ( Roo.lib.Event && document ) {
2423 if (DDM._timeoutCount > 2000) {
2425 setTimeout(DDM._addListeners, 10);
2426 if (document && document.body) {
2427 DDM._timeoutCount += 1;
2434 * Recursively searches the immediate parent and all child nodes for
2435 * the handle element in order to determine wheter or not it was
2437 * @method handleWasClicked
2438 * @param node the html element to inspect
2441 handleWasClicked: function(node, id) {
2442 if (this.isHandle(id, node.id)) {
2445 // check to see if this is a text node child of the one we want
2446 var p = node.parentNode;
2449 if (this.isHandle(id, p.id)) {
2464 // shorter alias, save a few bytes
2465 Roo.dd.DDM = Roo.dd.DragDropMgr;
2466 Roo.dd.DDM._addListeners();
2470 * Ext JS Library 1.1.1
2471 * Copyright(c) 2006-2007, Ext JS, LLC.
2473 * Originally Released Under LGPL - original licence link has changed is not relivant.
2476 * <script type="text/javascript">
2481 * A DragDrop implementation where the linked element follows the
2482 * mouse cursor during a drag.
2483 * @extends Roo.dd.DragDrop
2485 * @param {String} id the id of the linked element
2486 * @param {String} sGroup the group of related DragDrop items
2487 * @param {object} config an object containing configurable attributes
2488 * Valid properties for DD:
2491 Roo.dd.DD = function(id, sGroup, config) {
2493 this.init(id, sGroup, config);
2497 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2500 * When set to true, the utility automatically tries to scroll the browser
2501 * window wehn a drag and drop element is dragged near the viewport boundary.
2509 * Sets the pointer offset to the distance between the linked element's top
2510 * left corner and the location the element was clicked
2511 * @method autoOffset
2512 * @param {int} iPageX the X coordinate of the click
2513 * @param {int} iPageY the Y coordinate of the click
2515 autoOffset: function(iPageX, iPageY) {
2516 var x = iPageX - this.startPageX;
2517 var y = iPageY - this.startPageY;
2518 this.setDelta(x, y);
2522 * Sets the pointer offset. You can call this directly to force the
2523 * offset to be in a particular location (e.g., pass in 0,0 to set it
2524 * to the center of the object)
2526 * @param {int} iDeltaX the distance from the left
2527 * @param {int} iDeltaY the distance from the top
2529 setDelta: function(iDeltaX, iDeltaY) {
2530 this.deltaX = iDeltaX;
2531 this.deltaY = iDeltaY;
2535 * Sets the drag element to the location of the mousedown or click event,
2536 * maintaining the cursor location relative to the location on the element
2537 * that was clicked. Override this if you want to place the element in a
2538 * location other than where the cursor is.
2539 * @method setDragElPos
2540 * @param {int} iPageX the X coordinate of the mousedown or drag event
2541 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2543 setDragElPos: function(iPageX, iPageY) {
2544 // the first time we do this, we are going to check to make sure
2545 // the element has css positioning
2547 var el = this.getDragEl();
2548 this.alignElWithMouse(el, iPageX, iPageY);
2552 * Sets the element to the location of the mousedown or click event,
2553 * maintaining the cursor location relative to the location on the element
2554 * that was clicked. Override this if you want to place the element in a
2555 * location other than where the cursor is.
2556 * @method alignElWithMouse
2557 * @param {HTMLElement} el the element to move
2558 * @param {int} iPageX the X coordinate of the mousedown or drag event
2559 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2561 alignElWithMouse: function(el, iPageX, iPageY) {
2562 var oCoord = this.getTargetCoord(iPageX, iPageY);
2563 var fly = el.dom ? el : Roo.fly(el);
2564 if (!this.deltaSetXY) {
2565 var aCoord = [oCoord.x, oCoord.y];
2567 var newLeft = fly.getLeft(true);
2568 var newTop = fly.getTop(true);
2569 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2571 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2574 this.cachePosition(oCoord.x, oCoord.y);
2575 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2580 * Saves the most recent position so that we can reset the constraints and
2581 * tick marks on-demand. We need to know this so that we can calculate the
2582 * number of pixels the element is offset from its original position.
2583 * @method cachePosition
2584 * @param iPageX the current x position (optional, this just makes it so we
2585 * don't have to look it up again)
2586 * @param iPageY the current y position (optional, this just makes it so we
2587 * don't have to look it up again)
2589 cachePosition: function(iPageX, iPageY) {
2591 this.lastPageX = iPageX;
2592 this.lastPageY = iPageY;
2594 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2595 this.lastPageX = aCoord[0];
2596 this.lastPageY = aCoord[1];
2601 * Auto-scroll the window if the dragged object has been moved beyond the
2602 * visible window boundary.
2603 * @method autoScroll
2604 * @param {int} x the drag element's x position
2605 * @param {int} y the drag element's y position
2606 * @param {int} h the height of the drag element
2607 * @param {int} w the width of the drag element
2610 autoScroll: function(x, y, h, w) {
2613 // The client height
2614 var clientH = Roo.lib.Dom.getViewWidth();
2617 var clientW = Roo.lib.Dom.getViewHeight();
2619 // The amt scrolled down
2620 var st = this.DDM.getScrollTop();
2622 // The amt scrolled right
2623 var sl = this.DDM.getScrollLeft();
2625 // Location of the bottom of the element
2628 // Location of the right of the element
2631 // The distance from the cursor to the bottom of the visible area,
2632 // adjusted so that we don't scroll if the cursor is beyond the
2633 // element drag constraints
2634 var toBot = (clientH + st - y - this.deltaY);
2636 // The distance from the cursor to the right of the visible area
2637 var toRight = (clientW + sl - x - this.deltaX);
2640 // How close to the edge the cursor must be before we scroll
2641 // var thresh = (document.all) ? 100 : 40;
2644 // How many pixels to scroll per autoscroll op. This helps to reduce
2645 // clunky scrolling. IE is more sensitive about this ... it needs this
2646 // value to be higher.
2647 var scrAmt = (document.all) ? 80 : 30;
2649 // Scroll down if we are near the bottom of the visible page and the
2650 // obj extends below the crease
2651 if ( bot > clientH && toBot < thresh ) {
2652 window.scrollTo(sl, st + scrAmt);
2655 // Scroll up if the window is scrolled down and the top of the object
2656 // goes above the top border
2657 if ( y < st && st > 0 && y - st < thresh ) {
2658 window.scrollTo(sl, st - scrAmt);
2661 // Scroll right if the obj is beyond the right border and the cursor is
2663 if ( right > clientW && toRight < thresh ) {
2664 window.scrollTo(sl + scrAmt, st);
2667 // Scroll left if the window has been scrolled to the right and the obj
2668 // extends past the left border
2669 if ( x < sl && sl > 0 && x - sl < thresh ) {
2670 window.scrollTo(sl - scrAmt, st);
2676 * Finds the location the element should be placed if we want to move
2677 * it to where the mouse location less the click offset would place us.
2678 * @method getTargetCoord
2679 * @param {int} iPageX the X coordinate of the click
2680 * @param {int} iPageY the Y coordinate of the click
2681 * @return an object that contains the coordinates (Object.x and Object.y)
2684 getTargetCoord: function(iPageX, iPageY) {
2687 var x = iPageX - this.deltaX;
2688 var y = iPageY - this.deltaY;
2690 if (this.constrainX) {
2691 if (x < this.minX) { x = this.minX; }
2692 if (x > this.maxX) { x = this.maxX; }
2695 if (this.constrainY) {
2696 if (y < this.minY) { y = this.minY; }
2697 if (y > this.maxY) { y = this.maxY; }
2700 x = this.getTick(x, this.xTicks);
2701 y = this.getTick(y, this.yTicks);
2708 * Sets up config options specific to this class. Overrides
2709 * Roo.dd.DragDrop, but all versions of this method through the
2710 * inheritance chain are called
2712 applyConfig: function() {
2713 Roo.dd.DD.superclass.applyConfig.call(this);
2714 this.scroll = (this.config.scroll !== false);
2718 * Event that fires prior to the onMouseDown event. Overrides
2721 b4MouseDown: function(e) {
2722 // this.resetConstraints();
2723 this.autoOffset(e.getPageX(),
2728 * Event that fires prior to the onDrag event. Overrides
2731 b4Drag: function(e) {
2732 this.setDragElPos(e.getPageX(),
2736 toString: function() {
2737 return ("DD " + this.id);
2740 //////////////////////////////////////////////////////////////////////////
2741 // Debugging ygDragDrop events that can be overridden
2742 //////////////////////////////////////////////////////////////////////////
2744 startDrag: function(x, y) {
2747 onDrag: function(e) {
2750 onDragEnter: function(e, id) {
2753 onDragOver: function(e, id) {
2756 onDragOut: function(e, id) {
2759 onDragDrop: function(e, id) {
2762 endDrag: function(e) {
2769 * Ext JS Library 1.1.1
2770 * Copyright(c) 2006-2007, Ext JS, LLC.
2772 * Originally Released Under LGPL - original licence link has changed is not relivant.
2775 * <script type="text/javascript">
2779 * @class Roo.dd.DDProxy
2780 * A DragDrop implementation that inserts an empty, bordered div into
2781 * the document that follows the cursor during drag operations. At the time of
2782 * the click, the frame div is resized to the dimensions of the linked html
2783 * element, and moved to the exact location of the linked element.
2785 * References to the "frame" element refer to the single proxy element that
2786 * was created to be dragged in place of all DDProxy elements on the
2789 * @extends Roo.dd.DD
2791 * @param {String} id the id of the linked html element
2792 * @param {String} sGroup the group of related DragDrop objects
2793 * @param {object} config an object containing configurable attributes
2794 * Valid properties for DDProxy in addition to those in DragDrop:
2795 * resizeFrame, centerFrame, dragElId
2797 Roo.dd.DDProxy = function(id, sGroup, config) {
2799 this.init(id, sGroup, config);
2805 * The default drag frame div id
2806 * @property Roo.dd.DDProxy.dragElId
2810 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2812 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2815 * By default we resize the drag frame to be the same size as the element
2816 * we want to drag (this is to get the frame effect). We can turn it off
2817 * if we want a different behavior.
2818 * @property resizeFrame
2824 * By default the frame is positioned exactly where the drag element is, so
2825 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2826 * you do not have constraints on the obj is to have the drag frame centered
2827 * around the cursor. Set centerFrame to true for this effect.
2828 * @property centerFrame
2834 * Creates the proxy element if it does not yet exist
2835 * @method createFrame
2837 createFrame: function() {
2839 var body = document.body;
2841 if (!body || !body.firstChild) {
2842 setTimeout( function() { self.createFrame(); }, 50 );
2846 var div = this.getDragEl();
2849 div = document.createElement("div");
2850 div.id = this.dragElId;
2853 s.position = "absolute";
2854 s.visibility = "hidden";
2856 s.border = "2px solid #aaa";
2859 // appendChild can blow up IE if invoked prior to the window load event
2860 // while rendering a table. It is possible there are other scenarios
2861 // that would cause this to happen as well.
2862 body.insertBefore(div, body.firstChild);
2867 * Initialization for the drag frame element. Must be called in the
2868 * constructor of all subclasses
2871 initFrame: function() {
2875 applyConfig: function() {
2876 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2878 this.resizeFrame = (this.config.resizeFrame !== false);
2879 this.centerFrame = (this.config.centerFrame);
2880 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2884 * Resizes the drag frame to the dimensions of the clicked object, positions
2885 * it over the object, and finally displays it
2887 * @param {int} iPageX X click position
2888 * @param {int} iPageY Y click position
2891 showFrame: function(iPageX, iPageY) {
2892 var el = this.getEl();
2893 var dragEl = this.getDragEl();
2894 var s = dragEl.style;
2896 this._resizeProxy();
2898 if (this.centerFrame) {
2899 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2900 Math.round(parseInt(s.height, 10)/2) );
2903 this.setDragElPos(iPageX, iPageY);
2905 Roo.fly(dragEl).show();
2909 * The proxy is automatically resized to the dimensions of the linked
2910 * element when a drag is initiated, unless resizeFrame is set to false
2911 * @method _resizeProxy
2914 _resizeProxy: function() {
2915 if (this.resizeFrame) {
2916 var el = this.getEl();
2917 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2921 // overrides Roo.dd.DragDrop
2922 b4MouseDown: function(e) {
2923 var x = e.getPageX();
2924 var y = e.getPageY();
2925 this.autoOffset(x, y);
2926 this.setDragElPos(x, y);
2929 // overrides Roo.dd.DragDrop
2930 b4StartDrag: function(x, y) {
2931 // show the drag frame
2932 this.showFrame(x, y);
2935 // overrides Roo.dd.DragDrop
2936 b4EndDrag: function(e) {
2937 Roo.fly(this.getDragEl()).hide();
2940 // overrides Roo.dd.DragDrop
2941 // By default we try to move the element to the last location of the frame.
2942 // This is so that the default behavior mirrors that of Roo.dd.DD.
2943 endDrag: function(e) {
2945 var lel = this.getEl();
2946 var del = this.getDragEl();
2948 // Show the drag frame briefly so we can get its position
2949 del.style.visibility = "";
2952 // Hide the linked element before the move to get around a Safari
2954 lel.style.visibility = "hidden";
2955 Roo.dd.DDM.moveToEl(lel, del);
2956 del.style.visibility = "hidden";
2957 lel.style.visibility = "";
2962 beforeMove : function(){
2966 afterDrag : function(){
2970 toString: function() {
2971 return ("DDProxy " + this.id);
2977 * Ext JS Library 1.1.1
2978 * Copyright(c) 2006-2007, Ext JS, LLC.
2980 * Originally Released Under LGPL - original licence link has changed is not relivant.
2983 * <script type="text/javascript">
2987 * @class Roo.dd.DDTarget
2988 * A DragDrop implementation that does not move, but can be a drop
2989 * target. You would get the same result by simply omitting implementation
2990 * for the event callbacks, but this way we reduce the processing cost of the
2991 * event listener and the callbacks.
2992 * @extends Roo.dd.DragDrop
2994 * @param {String} id the id of the element that is a drop target
2995 * @param {String} sGroup the group of related DragDrop objects
2996 * @param {object} config an object containing configurable attributes
2997 * Valid properties for DDTarget in addition to those in
3001 Roo.dd.DDTarget = function(id, sGroup, config) {
3003 this.initTarget(id, sGroup, config);
3005 if (config.listeners || config.events) {
3006 Roo.dd.DragDrop.superclass.constructor.call(this, {
3007 listeners : config.listeners || {},
3008 events : config.events || {}
3013 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3014 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3015 toString: function() {
3016 return ("DDTarget " + this.id);
3021 * Ext JS Library 1.1.1
3022 * Copyright(c) 2006-2007, Ext JS, LLC.
3024 * Originally Released Under LGPL - original licence link has changed is not relivant.
3027 * <script type="text/javascript">
3032 * @class Roo.dd.ScrollManager
3033 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3034 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3037 Roo.dd.ScrollManager = function(){
3038 var ddm = Roo.dd.DragDropMgr;
3043 var onStop = function(e){
3048 var triggerRefresh = function(){
3049 if(ddm.dragCurrent){
3050 ddm.refreshCache(ddm.dragCurrent.groups);
3054 var doScroll = function(){
3055 if(ddm.dragCurrent){
3056 var dds = Roo.dd.ScrollManager;
3058 if(proc.el.scroll(proc.dir, dds.increment)){
3062 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3067 var clearProc = function(){
3069 clearInterval(proc.id);
3076 var startProc = function(el, dir){
3080 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3083 var onFire = function(e, isDrop){
3084 if(isDrop || !ddm.dragCurrent){ return; }
3085 var dds = Roo.dd.ScrollManager;
3086 if(!dragEl || dragEl != ddm.dragCurrent){
3087 dragEl = ddm.dragCurrent;
3088 // refresh regions on drag start
3092 var xy = Roo.lib.Event.getXY(e);
3093 var pt = new Roo.lib.Point(xy[0], xy[1]);
3095 var el = els[id], r = el._region;
3096 if(r && r.contains(pt) && el.isScrollable()){
3097 if(r.bottom - pt.y <= dds.thresh){
3099 startProc(el, "down");
3102 }else if(r.right - pt.x <= dds.thresh){
3104 startProc(el, "left");
3107 }else if(pt.y - r.top <= dds.thresh){
3109 startProc(el, "up");
3112 }else if(pt.x - r.left <= dds.thresh){
3114 startProc(el, "right");
3123 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3124 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3128 * Registers new overflow element(s) to auto scroll
3129 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3131 register : function(el){
3132 if(el instanceof Array){
3133 for(var i = 0, len = el.length; i < len; i++) {
3134 this.register(el[i]);
3143 * Unregisters overflow element(s) so they are no longer scrolled
3144 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3146 unregister : function(el){
3147 if(el instanceof Array){
3148 for(var i = 0, len = el.length; i < len; i++) {
3149 this.unregister(el[i]);
3158 * The number of pixels from the edge of a container the pointer needs to be to
3159 * trigger scrolling (defaults to 25)
3165 * The number of pixels to scroll in each scroll increment (defaults to 50)
3171 * The frequency of scrolls in milliseconds (defaults to 500)
3177 * True to animate the scroll (defaults to true)
3183 * The animation duration in seconds -
3184 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3190 * Manually trigger a cache refresh.
3192 refreshCache : function(){
3194 if(typeof els[id] == 'object'){ // for people extending the object prototype
3195 els[id]._region = els[id].getRegion();
3202 * Ext JS Library 1.1.1
3203 * Copyright(c) 2006-2007, Ext JS, LLC.
3205 * Originally Released Under LGPL - original licence link has changed is not relivant.
3208 * <script type="text/javascript">
3213 * @class Roo.dd.Registry
3214 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3215 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3218 Roo.dd.Registry = function(){
3223 var getId = function(el, autogen){
3224 if(typeof el == "string"){
3228 if(!id && autogen !== false){
3229 id = "roodd-" + (++autoIdSeed);
3237 * Register a drag drop element
3238 * @param {String|HTMLElement} element The id or DOM node to register
3239 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3240 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3241 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3242 * populated in the data object (if applicable):
3244 Value Description<br />
3245 --------- ------------------------------------------<br />
3246 handles Array of DOM nodes that trigger dragging<br />
3247 for the element being registered<br />
3248 isHandle True if the element passed in triggers<br />
3249 dragging itself, else false
3252 register : function(el, data){
3254 if(typeof el == "string"){
3255 el = document.getElementById(el);
3258 elements[getId(el)] = data;
3259 if(data.isHandle !== false){
3260 handles[data.ddel.id] = data;
3263 var hs = data.handles;
3264 for(var i = 0, len = hs.length; i < len; i++){
3265 handles[getId(hs[i])] = data;
3271 * Unregister a drag drop element
3272 * @param {String|HTMLElement} element The id or DOM node to unregister
3274 unregister : function(el){
3275 var id = getId(el, false);
3276 var data = elements[id];
3278 delete elements[id];
3280 var hs = data.handles;
3281 for(var i = 0, len = hs.length; i < len; i++){
3282 delete handles[getId(hs[i], false)];
3289 * Returns the handle registered for a DOM Node by id
3290 * @param {String|HTMLElement} id The DOM node or id to look up
3291 * @return {Object} handle The custom handle data
3293 getHandle : function(id){
3294 if(typeof id != "string"){ // must be element?
3301 * Returns the handle that is registered for the DOM node that is the target of the event
3302 * @param {Event} e The event
3303 * @return {Object} handle The custom handle data
3305 getHandleFromEvent : function(e){
3306 var t = Roo.lib.Event.getTarget(e);
3307 return t ? handles[t.id] : null;
3311 * Returns a custom data object that is registered for a DOM node by id
3312 * @param {String|HTMLElement} id The DOM node or id to look up
3313 * @return {Object} data The custom data
3315 getTarget : function(id){
3316 if(typeof id != "string"){ // must be element?
3319 return elements[id];
3323 * Returns a custom data object that is registered for the DOM node that is the target of the event
3324 * @param {Event} e The event
3325 * @return {Object} data The custom data
3327 getTargetFromEvent : function(e){
3328 var t = Roo.lib.Event.getTarget(e);
3329 return t ? elements[t.id] || handles[t.id] : null;
3334 * Ext JS Library 1.1.1
3335 * Copyright(c) 2006-2007, Ext JS, LLC.
3337 * Originally Released Under LGPL - original licence link has changed is not relivant.
3340 * <script type="text/javascript">
3345 * @class Roo.dd.StatusProxy
3346 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3347 * default drag proxy used by all Roo.dd components.
3349 * @param {Object} config
3351 Roo.dd.StatusProxy = function(config){
3352 Roo.apply(this, config);
3353 this.id = this.id || Roo.id();
3354 this.el = new Roo.Layer({
3356 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3357 {tag: "div", cls: "x-dd-drop-icon"},
3358 {tag: "div", cls: "x-dd-drag-ghost"}
3361 shadow: !config || config.shadow !== false
3363 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3364 this.dropStatus = this.dropNotAllowed;
3367 Roo.dd.StatusProxy.prototype = {
3369 * @cfg {String} dropAllowed
3370 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3372 dropAllowed : "x-dd-drop-ok",
3374 * @cfg {String} dropNotAllowed
3375 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3377 dropNotAllowed : "x-dd-drop-nodrop",
3380 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3381 * over the current target element.
3382 * @param {String} cssClass The css class for the new drop status indicator image
3384 setStatus : function(cssClass){
3385 cssClass = cssClass || this.dropNotAllowed;
3386 if(this.dropStatus != cssClass){
3387 this.el.replaceClass(this.dropStatus, cssClass);
3388 this.dropStatus = cssClass;
3393 * Resets the status indicator to the default dropNotAllowed value
3394 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3396 reset : function(clearGhost){
3397 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3398 this.dropStatus = this.dropNotAllowed;
3400 this.ghost.update("");
3405 * Updates the contents of the ghost element
3406 * @param {String} html The html that will replace the current innerHTML of the ghost element
3408 update : function(html){
3409 if(typeof html == "string"){
3410 this.ghost.update(html);
3412 this.ghost.update("");
3413 html.style.margin = "0";
3414 this.ghost.dom.appendChild(html);
3416 // ensure float = none set?? cant remember why though.
3417 var el = this.ghost.dom.firstChild;
3419 Roo.fly(el).setStyle('float', 'none');
3424 * Returns the underlying proxy {@link Roo.Layer}
3425 * @return {Roo.Layer} el
3432 * Returns the ghost element
3433 * @return {Roo.Element} el
3435 getGhost : function(){
3441 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3443 hide : function(clear){
3451 * Stops the repair animation if it's currently running
3454 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3460 * Displays this proxy
3467 * Force the Layer to sync its shadow and shim positions to the element
3474 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3475 * invalid drop operation by the item being dragged.
3476 * @param {Array} xy The XY position of the element ([x, y])
3477 * @param {Function} callback The function to call after the repair is complete
3478 * @param {Object} scope The scope in which to execute the callback
3480 repair : function(xy, callback, scope){
3481 this.callback = callback;
3483 if(xy && this.animRepair !== false){
3484 this.el.addClass("x-dd-drag-repair");
3485 this.el.hideUnders(true);
3486 this.anim = this.el.shift({
3487 duration: this.repairDuration || .5,
3491 callback: this.afterRepair,
3500 afterRepair : function(){
3502 if(typeof this.callback == "function"){
3503 this.callback.call(this.scope || this);
3505 this.callback = null;
3510 * Ext JS Library 1.1.1
3511 * Copyright(c) 2006-2007, Ext JS, LLC.
3513 * Originally Released Under LGPL - original licence link has changed is not relivant.
3516 * <script type="text/javascript">
3520 * @class Roo.dd.DragSource
3521 * @extends Roo.dd.DDProxy
3522 * A simple class that provides the basic implementation needed to make any element draggable.
3524 * @param {String/HTMLElement/Element} el The container element
3525 * @param {Object} config
3527 Roo.dd.DragSource = function(el, config){
3528 this.el = Roo.get(el);
3531 Roo.apply(this, config);
3534 this.proxy = new Roo.dd.StatusProxy();
3537 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3538 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3540 this.dragging = false;
3543 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3545 * @cfg {String} dropAllowed
3546 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3548 dropAllowed : "x-dd-drop-ok",
3550 * @cfg {String} dropNotAllowed
3551 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3553 dropNotAllowed : "x-dd-drop-nodrop",
3556 * Returns the data object associated with this drag source
3557 * @return {Object} data An object containing arbitrary data
3559 getDragData : function(e){
3560 return this.dragData;
3564 onDragEnter : function(e, id){
3565 var target = Roo.dd.DragDropMgr.getDDById(id);
3566 this.cachedTarget = target;
3567 if(this.beforeDragEnter(target, e, id) !== false){
3568 if(target.isNotifyTarget){
3569 var status = target.notifyEnter(this, e, this.dragData);
3570 this.proxy.setStatus(status);
3572 this.proxy.setStatus(this.dropAllowed);
3575 if(this.afterDragEnter){
3577 * An empty function by default, but provided so that you can perform a custom action
3578 * when the dragged item enters the drop target by providing an implementation.
3579 * @param {Roo.dd.DragDrop} target The drop target
3580 * @param {Event} e The event object
3581 * @param {String} id The id of the dragged element
3582 * @method afterDragEnter
3584 this.afterDragEnter(target, e, id);
3590 * An empty function by default, but provided so that you can perform a custom action
3591 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3592 * @param {Roo.dd.DragDrop} target The drop target
3593 * @param {Event} e The event object
3594 * @param {String} id The id of the dragged element
3595 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3597 beforeDragEnter : function(target, e, id){
3602 alignElWithMouse: function() {
3603 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3608 onDragOver : function(e, id){
3609 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3610 if(this.beforeDragOver(target, e, id) !== false){
3611 if(target.isNotifyTarget){
3612 var status = target.notifyOver(this, e, this.dragData);
3613 this.proxy.setStatus(status);
3616 if(this.afterDragOver){
3618 * An empty function by default, but provided so that you can perform a custom action
3619 * while the dragged item is over the drop target by providing an implementation.
3620 * @param {Roo.dd.DragDrop} target The drop target
3621 * @param {Event} e The event object
3622 * @param {String} id The id of the dragged element
3623 * @method afterDragOver
3625 this.afterDragOver(target, e, id);
3631 * An empty function by default, but provided so that you can perform a custom action
3632 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3633 * @param {Roo.dd.DragDrop} target The drop target
3634 * @param {Event} e The event object
3635 * @param {String} id The id of the dragged element
3636 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3638 beforeDragOver : function(target, e, id){
3643 onDragOut : function(e, id){
3644 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3645 if(this.beforeDragOut(target, e, id) !== false){
3646 if(target.isNotifyTarget){
3647 target.notifyOut(this, e, this.dragData);
3650 if(this.afterDragOut){
3652 * An empty function by default, but provided so that you can perform a custom action
3653 * after the dragged item is dragged out of the target without dropping.
3654 * @param {Roo.dd.DragDrop} target The drop target
3655 * @param {Event} e The event object
3656 * @param {String} id The id of the dragged element
3657 * @method afterDragOut
3659 this.afterDragOut(target, e, id);
3662 this.cachedTarget = null;
3666 * An empty function by default, but provided so that you can perform a custom action before the dragged
3667 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3668 * @param {Roo.dd.DragDrop} target The drop target
3669 * @param {Event} e The event object
3670 * @param {String} id The id of the dragged element
3671 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3673 beforeDragOut : function(target, e, id){
3678 onDragDrop : function(e, id){
3679 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3680 if(this.beforeDragDrop(target, e, id) !== false){
3681 if(target.isNotifyTarget){
3682 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3683 this.onValidDrop(target, e, id);
3685 this.onInvalidDrop(target, e, id);
3688 this.onValidDrop(target, e, id);
3691 if(this.afterDragDrop){
3693 * An empty function by default, but provided so that you can perform a custom action
3694 * after a valid drag drop has occurred by providing an implementation.
3695 * @param {Roo.dd.DragDrop} target The drop target
3696 * @param {Event} e The event object
3697 * @param {String} id The id of the dropped element
3698 * @method afterDragDrop
3700 this.afterDragDrop(target, e, id);
3703 delete this.cachedTarget;
3707 * An empty function by default, but provided so that you can perform a custom action before the dragged
3708 * item is dropped onto the target and optionally cancel the onDragDrop.
3709 * @param {Roo.dd.DragDrop} target The drop target
3710 * @param {Event} e The event object
3711 * @param {String} id The id of the dragged element
3712 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3714 beforeDragDrop : function(target, e, id){
3719 onValidDrop : function(target, e, id){
3721 if(this.afterValidDrop){
3723 * An empty function by default, but provided so that you can perform a custom action
3724 * after a valid drop has occurred by providing an implementation.
3725 * @param {Object} target The target DD
3726 * @param {Event} e The event object
3727 * @param {String} id The id of the dropped element
3728 * @method afterInvalidDrop
3730 this.afterValidDrop(target, e, id);
3735 getRepairXY : function(e, data){
3736 return this.el.getXY();
3740 onInvalidDrop : function(target, e, id){
3741 this.beforeInvalidDrop(target, e, id);
3742 if(this.cachedTarget){
3743 if(this.cachedTarget.isNotifyTarget){
3744 this.cachedTarget.notifyOut(this, e, this.dragData);
3746 this.cacheTarget = null;
3748 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3750 if(this.afterInvalidDrop){
3752 * An empty function by default, but provided so that you can perform a custom action
3753 * after an invalid drop has occurred by providing an implementation.
3754 * @param {Event} e The event object
3755 * @param {String} id The id of the dropped element
3756 * @method afterInvalidDrop
3758 this.afterInvalidDrop(e, id);
3763 afterRepair : function(){
3765 this.el.highlight(this.hlColor || "c3daf9");
3767 this.dragging = false;
3771 * An empty function by default, but provided so that you can perform a custom action after an invalid
3772 * drop has occurred.
3773 * @param {Roo.dd.DragDrop} target The drop target
3774 * @param {Event} e The event object
3775 * @param {String} id The id of the dragged element
3776 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3778 beforeInvalidDrop : function(target, e, id){
3783 handleMouseDown : function(e){
3787 var data = this.getDragData(e);
3788 if(data && this.onBeforeDrag(data, e) !== false){
3789 this.dragData = data;
3791 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3796 * An empty function by default, but provided so that you can perform a custom action before the initial
3797 * drag event begins and optionally cancel it.
3798 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3799 * @param {Event} e The event object
3800 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3802 onBeforeDrag : function(data, e){
3807 * An empty function by default, but provided so that you can perform a custom action once the initial
3808 * drag event has begun. The drag cannot be canceled from this function.
3809 * @param {Number} x The x position of the click on the dragged object
3810 * @param {Number} y The y position of the click on the dragged object
3812 onStartDrag : Roo.emptyFn,
3814 // private - YUI override
3815 startDrag : function(x, y){
3817 this.dragging = true;
3818 this.proxy.update("");
3819 this.onInitDrag(x, y);
3824 onInitDrag : function(x, y){
3825 var clone = this.el.dom.cloneNode(true);
3826 clone.id = Roo.id(); // prevent duplicate ids
3827 this.proxy.update(clone);
3828 this.onStartDrag(x, y);
3833 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3834 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3836 getProxy : function(){
3841 * Hides the drag source's {@link Roo.dd.StatusProxy}
3843 hideProxy : function(){
3845 this.proxy.reset(true);
3846 this.dragging = false;
3850 triggerCacheRefresh : function(){
3851 Roo.dd.DDM.refreshCache(this.groups);
3854 // private - override to prevent hiding
3855 b4EndDrag: function(e) {
3858 // private - override to prevent moving
3859 endDrag : function(e){
3860 this.onEndDrag(this.dragData, e);
3864 onEndDrag : function(data, e){
3867 // private - pin to cursor
3868 autoOffset : function(x, y) {
3869 this.setDelta(-12, -20);
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.dd.DropTarget
3885 * @extends Roo.dd.DDTarget
3886 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3887 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3889 * @param {String/HTMLElement/Element} el The container element
3890 * @param {Object} config
3892 Roo.dd.DropTarget = function(el, config){
3893 this.el = Roo.get(el);
3895 var listeners = false; ;
3896 if (config && config.listeners) {
3897 listeners= config.listeners;
3898 delete config.listeners;
3900 Roo.apply(this, config);
3902 if(this.containerScroll){
3903 Roo.dd.ScrollManager.register(this.el);
3907 * @scope Roo.dd.DropTarget
3912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3916 * IMPORTANT : it should set this.overClass and this.dropAllowed
3918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919 * @param {Event} e The event
3920 * @param {Object} data An object containing arbitrary data supplied by the drag source
3926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927 * This method will be called on every mouse movement while the drag source is over the drop target.
3928 * This default implementation simply returns the dropAllowed config value.
3930 * IMPORTANT : it should set this.dropAllowed
3932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933 * @param {Event} e The event
3934 * @param {Object} data An object containing arbitrary data supplied by the drag source
3940 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3942 * overClass (if any) from the drop element.
3943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944 * @param {Event} e The event
3945 * @param {Object} data An object containing arbitrary data supplied by the drag source
3951 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3953 * implementation that does something to process the drop event and returns true so that the drag source's
3954 * repair action does not run.
3956 * IMPORTANT : it should set this.success
3958 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959 * @param {Event} e The event
3960 * @param {Object} data An object containing arbitrary data supplied by the drag source
3966 Roo.dd.DropTarget.superclass.constructor.call( this,
3968 this.ddGroup || this.group,
3971 listeners : listeners || {}
3979 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3981 * @cfg {String} overClass
3982 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3985 * @cfg {String} ddGroup
3986 * The drag drop group to handle drop events for
3990 * @cfg {String} dropAllowed
3991 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3993 dropAllowed : "x-dd-drop-ok",
3995 * @cfg {String} dropNotAllowed
3996 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3998 dropNotAllowed : "x-dd-drop-nodrop",
4000 * @cfg {boolean} success
4001 * set this after drop listener..
4005 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
4006 * if the drop point is valid for over/enter..
4013 isNotifyTarget : true,
4018 notifyEnter : function(dd, e, data)
4021 this.fireEvent('enter', dd, e, data);
4023 this.el.addClass(this.overClass);
4025 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4026 this.valid ? this.dropAllowed : this.dropNotAllowed
4033 notifyOver : function(dd, e, data)
4036 this.fireEvent('over', dd, e, data);
4037 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4038 this.valid ? this.dropAllowed : this.dropNotAllowed
4045 notifyOut : function(dd, e, data)
4047 this.fireEvent('out', dd, e, data);
4049 this.el.removeClass(this.overClass);
4056 notifyDrop : function(dd, e, data)
4058 this.success = false;
4059 this.fireEvent('drop', dd, e, data);
4060 return this.success;
4064 * Ext JS Library 1.1.1
4065 * Copyright(c) 2006-2007, Ext JS, LLC.
4067 * Originally Released Under LGPL - original licence link has changed is not relivant.
4070 * <script type="text/javascript">
4075 * @class Roo.dd.DragZone
4076 * @extends Roo.dd.DragSource
4077 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4078 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4080 * @param {String/HTMLElement/Element} el The container element
4081 * @param {Object} config
4083 Roo.dd.DragZone = function(el, config){
4084 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4085 if(this.containerScroll){
4086 Roo.dd.ScrollManager.register(this.el);
4090 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4092 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4093 * for auto scrolling during drag operations.
4096 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4097 * method after a failed drop (defaults to "c3daf9" - light blue)
4101 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4102 * for a valid target to drag based on the mouse down. Override this method
4103 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4104 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4105 * @param {EventObject} e The mouse down event
4106 * @return {Object} The dragData
4108 getDragData : function(e){
4109 return Roo.dd.Registry.getHandleFromEvent(e);
4113 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4114 * this.dragData.ddel
4115 * @param {Number} x The x position of the click on the dragged object
4116 * @param {Number} y The y position of the click on the dragged object
4117 * @return {Boolean} true to continue the drag, false to cancel
4119 onInitDrag : function(x, y){
4120 this.proxy.update(this.dragData.ddel.cloneNode(true));
4121 this.onStartDrag(x, y);
4126 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4128 afterRepair : function(){
4130 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4132 this.dragging = false;
4136 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4137 * the XY of this.dragData.ddel
4138 * @param {EventObject} e The mouse up event
4139 * @return {Array} The xy location (e.g. [100, 200])
4141 getRepairXY : function(e){
4142 return Roo.Element.fly(this.dragData.ddel).getXY();
4146 * Ext JS Library 1.1.1
4147 * Copyright(c) 2006-2007, Ext JS, LLC.
4149 * Originally Released Under LGPL - original licence link has changed is not relivant.
4152 * <script type="text/javascript">
4155 * @class Roo.dd.DropZone
4156 * @extends Roo.dd.DropTarget
4157 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4158 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4160 * @param {String/HTMLElement/Element} el The container element
4161 * @param {Object} config
4163 Roo.dd.DropZone = function(el, config){
4164 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4167 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4169 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4170 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4171 * provide your own custom lookup.
4172 * @param {Event} e The event
4173 * @return {Object} data The custom data
4175 getTargetFromEvent : function(e){
4176 return Roo.dd.Registry.getTargetFromEvent(e);
4180 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4181 * that it has registered. This method has no default implementation and should be overridden to provide
4182 * node-specific processing if necessary.
4183 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4184 * {@link #getTargetFromEvent} for this node)
4185 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4186 * @param {Event} e The event
4187 * @param {Object} data An object containing arbitrary data supplied by the drag source
4189 onNodeEnter : function(n, dd, e, data){
4194 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4195 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4196 * overridden to provide the proper feedback.
4197 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4198 * {@link #getTargetFromEvent} for this node)
4199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4200 * @param {Event} e The event
4201 * @param {Object} data An object containing arbitrary data supplied by the drag source
4202 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4203 * underlying {@link Roo.dd.StatusProxy} can be updated
4205 onNodeOver : function(n, dd, e, data){
4206 return this.dropAllowed;
4210 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4211 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4212 * node-specific processing if necessary.
4213 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4214 * {@link #getTargetFromEvent} for this node)
4215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216 * @param {Event} e The event
4217 * @param {Object} data An object containing arbitrary data supplied by the drag source
4219 onNodeOut : function(n, dd, e, data){
4224 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4225 * the drop node. The default implementation returns false, so it should be overridden to provide the
4226 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4227 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4228 * {@link #getTargetFromEvent} for this node)
4229 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4230 * @param {Event} e The event
4231 * @param {Object} data An object containing arbitrary data supplied by the drag source
4232 * @return {Boolean} True if the drop was valid, else false
4234 onNodeDrop : function(n, dd, e, data){
4239 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4240 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4241 * it should be overridden to provide the proper feedback if necessary.
4242 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4243 * @param {Event} e The event
4244 * @param {Object} data An object containing arbitrary data supplied by the drag source
4245 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4246 * underlying {@link Roo.dd.StatusProxy} can be updated
4248 onContainerOver : function(dd, e, data){
4249 return this.dropNotAllowed;
4253 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4254 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4255 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4256 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4257 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4258 * @param {Event} e The event
4259 * @param {Object} data An object containing arbitrary data supplied by the drag source
4260 * @return {Boolean} True if the drop was valid, else false
4262 onContainerDrop : function(dd, e, data){
4267 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4268 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4269 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4270 * you should override this method and provide a custom implementation.
4271 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4272 * @param {Event} e The event
4273 * @param {Object} data An object containing arbitrary data supplied by the drag source
4274 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4275 * underlying {@link Roo.dd.StatusProxy} can be updated
4277 notifyEnter : function(dd, e, data){
4278 return this.dropNotAllowed;
4282 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4283 * This method will be called on every mouse movement while the drag source is over the drop zone.
4284 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4285 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4286 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4287 * registered node, it will call {@link #onContainerOver}.
4288 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4289 * @param {Event} e The event
4290 * @param {Object} data An object containing arbitrary data supplied by the drag source
4291 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4292 * underlying {@link Roo.dd.StatusProxy} can be updated
4294 notifyOver : function(dd, e, data){
4295 var n = this.getTargetFromEvent(e);
4296 if(!n){ // not over valid drop target
4297 if(this.lastOverNode){
4298 this.onNodeOut(this.lastOverNode, dd, e, data);
4299 this.lastOverNode = null;
4301 return this.onContainerOver(dd, e, data);
4303 if(this.lastOverNode != n){
4304 if(this.lastOverNode){
4305 this.onNodeOut(this.lastOverNode, dd, e, data);
4307 this.onNodeEnter(n, dd, e, data);
4308 this.lastOverNode = n;
4310 return this.onNodeOver(n, dd, e, data);
4314 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4315 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4316 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4317 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4318 * @param {Event} e The event
4319 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4321 notifyOut : function(dd, e, data){
4322 if(this.lastOverNode){
4323 this.onNodeOut(this.lastOverNode, dd, e, data);
4324 this.lastOverNode = null;
4329 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4330 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4331 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4332 * otherwise it will call {@link #onContainerDrop}.
4333 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4334 * @param {Event} e The event
4335 * @param {Object} data An object containing arbitrary data supplied by the drag source
4336 * @return {Boolean} True if the drop was valid, else false
4338 notifyDrop : function(dd, e, data){
4339 if(this.lastOverNode){
4340 this.onNodeOut(this.lastOverNode, dd, e, data);
4341 this.lastOverNode = null;
4343 var n = this.getTargetFromEvent(e);
4345 this.onNodeDrop(n, dd, e, data) :
4346 this.onContainerDrop(dd, e, data);
4350 triggerCacheRefresh : function(){
4351 Roo.dd.DDM.refreshCache(this.groups);
4355 * Ext JS Library 1.1.1
4356 * Copyright(c) 2006-2007, Ext JS, LLC.
4358 * Originally Released Under LGPL - original licence link has changed is not relivant.
4361 * <script type="text/javascript">
4366 * @class Roo.data.SortTypes
4368 * Defines the default sorting (casting?) comparison functions used when sorting data.
4370 Roo.data.SortTypes = {
4372 * Default sort that does nothing
4373 * @param {Mixed} s The value being converted
4374 * @return {Mixed} The comparison value
4381 * The regular expression used to strip tags
4385 stripTagsRE : /<\/?[^>]+>/gi,
4388 * Strips all HTML tags to sort on text only
4389 * @param {Mixed} s The value being converted
4390 * @return {String} The comparison value
4392 asText : function(s){
4393 return String(s).replace(this.stripTagsRE, "");
4397 * Strips all HTML tags to sort on text only - Case insensitive
4398 * @param {Mixed} s The value being converted
4399 * @return {String} The comparison value
4401 asUCText : function(s){
4402 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4406 * Case insensitive string
4407 * @param {Mixed} s The value being converted
4408 * @return {String} The comparison value
4410 asUCString : function(s) {
4411 return String(s).toUpperCase();
4416 * @param {Mixed} s The value being converted
4417 * @return {Number} The comparison value
4419 asDate : function(s) {
4423 if(s instanceof Date){
4426 return Date.parse(String(s));
4431 * @param {Mixed} s The value being converted
4432 * @return {Float} The comparison value
4434 asFloat : function(s) {
4435 var val = parseFloat(String(s).replace(/,/g, ""));
4436 if(isNaN(val)) val = 0;
4442 * @param {Mixed} s The value being converted
4443 * @return {Number} The comparison value
4445 asInt : function(s) {
4446 var val = parseInt(String(s).replace(/,/g, ""));
4447 if(isNaN(val)) val = 0;
4452 * Ext JS Library 1.1.1
4453 * Copyright(c) 2006-2007, Ext JS, LLC.
4455 * Originally Released Under LGPL - original licence link has changed is not relivant.
4458 * <script type="text/javascript">
4462 * @class Roo.data.Record
4463 * Instances of this class encapsulate both record <em>definition</em> information, and record
4464 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4465 * to access Records cached in an {@link Roo.data.Store} object.<br>
4467 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4468 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4471 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4473 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4474 * {@link #create}. The parameters are the same.
4475 * @param {Array} data An associative Array of data values keyed by the field name.
4476 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4477 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4478 * not specified an integer id is generated.
4480 Roo.data.Record = function(data, id){
4481 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4486 * Generate a constructor for a specific record layout.
4487 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4488 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4489 * Each field definition object may contain the following properties: <ul>
4490 * <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,
4491 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4492 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4493 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4494 * is being used, then this is a string containing the javascript expression to reference the data relative to
4495 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4496 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4497 * this may be omitted.</p></li>
4498 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4499 * <ul><li>auto (Default, implies no conversion)</li>
4504 * <li>date</li></ul></p></li>
4505 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4506 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4507 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4508 * by the Reader into an object that will be stored in the Record. It is passed the
4509 * following parameters:<ul>
4510 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4512 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4514 * <br>usage:<br><pre><code>
4515 var TopicRecord = Roo.data.Record.create(
4516 {name: 'title', mapping: 'topic_title'},
4517 {name: 'author', mapping: 'username'},
4518 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4519 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4520 {name: 'lastPoster', mapping: 'user2'},
4521 {name: 'excerpt', mapping: 'post_text'}
4524 var myNewRecord = new TopicRecord({
4525 title: 'Do my job please',
4528 lastPost: new Date(),
4529 lastPoster: 'Animal',
4530 excerpt: 'No way dude!'
4532 myStore.add(myNewRecord);
4537 Roo.data.Record.create = function(o){
4539 f.superclass.constructor.apply(this, arguments);
4541 Roo.extend(f, Roo.data.Record);
4542 var p = f.prototype;
4543 p.fields = new Roo.util.MixedCollection(false, function(field){
4546 for(var i = 0, len = o.length; i < len; i++){
4547 p.fields.add(new Roo.data.Field(o[i]));
4549 f.getField = function(name){
4550 return p.fields.get(name);
4555 Roo.data.Record.AUTO_ID = 1000;
4556 Roo.data.Record.EDIT = 'edit';
4557 Roo.data.Record.REJECT = 'reject';
4558 Roo.data.Record.COMMIT = 'commit';
4560 Roo.data.Record.prototype = {
4562 * Readonly flag - true if this record has been modified.
4571 join : function(store){
4576 * Set the named field to the specified value.
4577 * @param {String} name The name of the field to set.
4578 * @param {Object} value The value to set the field to.
4580 set : function(name, value){
4581 if(this.data[name] == value){
4588 if(typeof this.modified[name] == 'undefined'){
4589 this.modified[name] = this.data[name];
4591 this.data[name] = value;
4593 this.store.afterEdit(this);
4598 * Get the value of the named field.
4599 * @param {String} name The name of the field to get the value of.
4600 * @return {Object} The value of the field.
4602 get : function(name){
4603 return this.data[name];
4607 beginEdit : function(){
4608 this.editing = true;
4613 cancelEdit : function(){
4614 this.editing = false;
4615 delete this.modified;
4619 endEdit : function(){
4620 this.editing = false;
4621 if(this.dirty && this.store){
4622 this.store.afterEdit(this);
4627 * Usually called by the {@link Roo.data.Store} which owns the Record.
4628 * Rejects all changes made to the Record since either creation, or the last commit operation.
4629 * Modified fields are reverted to their original values.
4631 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4632 * of reject operations.
4634 reject : function(){
4635 var m = this.modified;
4637 if(typeof m[n] != "function"){
4638 this.data[n] = m[n];
4642 delete this.modified;
4643 this.editing = false;
4645 this.store.afterReject(this);
4650 * Usually called by the {@link Roo.data.Store} which owns the Record.
4651 * Commits all changes made to the Record since either creation, or the last commit operation.
4653 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4654 * of commit operations.
4656 commit : function(){
4658 delete this.modified;
4659 this.editing = false;
4661 this.store.afterCommit(this);
4666 hasError : function(){
4667 return this.error != null;
4671 clearError : function(){
4676 * Creates a copy of this record.
4677 * @param {String} id (optional) A new record id if you don't want to use this record's id
4680 copy : function(newId) {
4681 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4685 * Ext JS Library 1.1.1
4686 * Copyright(c) 2006-2007, Ext JS, LLC.
4688 * Originally Released Under LGPL - original licence link has changed is not relivant.
4691 * <script type="text/javascript">
4697 * @class Roo.data.Store
4698 * @extends Roo.util.Observable
4699 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4700 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4702 * 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
4703 * has no knowledge of the format of the data returned by the Proxy.<br>
4705 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4706 * instances from the data object. These records are cached and made available through accessor functions.
4708 * Creates a new Store.
4709 * @param {Object} config A config object containing the objects needed for the Store to access data,
4710 * and read the data into Records.
4712 Roo.data.Store = function(config){
4713 this.data = new Roo.util.MixedCollection(false);
4714 this.data.getKey = function(o){
4717 this.baseParams = {};
4724 "multisort" : "_multisort"
4727 if(config && config.data){
4728 this.inlineData = config.data;
4732 Roo.apply(this, config);
4734 if(this.reader){ // reader passed
4735 this.reader = Roo.factory(this.reader, Roo.data);
4736 this.reader.xmodule = this.xmodule || false;
4737 if(!this.recordType){
4738 this.recordType = this.reader.recordType;
4740 if(this.reader.onMetaChange){
4741 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4745 if(this.recordType){
4746 this.fields = this.recordType.prototype.fields;
4752 * @event datachanged
4753 * Fires when the data cache has changed, and a widget which is using this Store
4754 * as a Record cache should refresh its view.
4755 * @param {Store} this
4760 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4761 * @param {Store} this
4762 * @param {Object} meta The JSON metadata
4767 * Fires when Records have been added to the Store
4768 * @param {Store} this
4769 * @param {Roo.data.Record[]} records The array of Records added
4770 * @param {Number} index The index at which the record(s) were added
4775 * Fires when a Record has been removed from the Store
4776 * @param {Store} this
4777 * @param {Roo.data.Record} record The Record that was removed
4778 * @param {Number} index The index at which the record was removed
4783 * Fires when a Record has been updated
4784 * @param {Store} this
4785 * @param {Roo.data.Record} record The Record that was updated
4786 * @param {String} operation The update operation being performed. Value may be one of:
4788 Roo.data.Record.EDIT
4789 Roo.data.Record.REJECT
4790 Roo.data.Record.COMMIT
4796 * Fires when the data cache has been cleared.
4797 * @param {Store} this
4802 * Fires before a request is made for a new data object. If the beforeload handler returns false
4803 * the load action will be canceled.
4804 * @param {Store} this
4805 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4810 * Fires after a new set of Records has been loaded.
4811 * @param {Store} this
4812 * @param {Roo.data.Record[]} records The Records that were loaded
4813 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4817 * @event loadexception
4818 * Fires if an exception occurs in the Proxy during loading.
4819 * Called with the signature of the Proxy's "loadexception" event.
4820 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4823 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4824 * @param {Object} load options
4825 * @param {Object} jsonData from your request (normally this contains the Exception)
4827 loadexception : true
4831 this.proxy = Roo.factory(this.proxy, Roo.data);
4832 this.proxy.xmodule = this.xmodule || false;
4833 this.relayEvents(this.proxy, ["loadexception"]);
4835 this.sortToggle = {};
4836 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4838 Roo.data.Store.superclass.constructor.call(this);
4840 if(this.inlineData){
4841 this.loadData(this.inlineData);
4842 delete this.inlineData;
4845 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4847 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4848 * without a remote query - used by combo/forms at present.
4852 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4855 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4858 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4859 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4862 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4863 * on any HTTP request
4866 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4869 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4873 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4874 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4879 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4880 * loaded or when a record is removed. (defaults to false).
4882 pruneModifiedRecords : false,
4888 * Add Records to the Store and fires the add event.
4889 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4891 add : function(records){
4892 records = [].concat(records);
4893 for(var i = 0, len = records.length; i < len; i++){
4894 records[i].join(this);
4896 var index = this.data.length;
4897 this.data.addAll(records);
4898 this.fireEvent("add", this, records, index);
4902 * Remove a Record from the Store and fires the remove event.
4903 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4905 remove : function(record){
4906 var index = this.data.indexOf(record);
4907 this.data.removeAt(index);
4908 if(this.pruneModifiedRecords){
4909 this.modified.remove(record);
4911 this.fireEvent("remove", this, record, index);
4915 * Remove all Records from the Store and fires the clear event.
4917 removeAll : function(){
4919 if(this.pruneModifiedRecords){
4922 this.fireEvent("clear", this);
4926 * Inserts Records to the Store at the given index and fires the add event.
4927 * @param {Number} index The start index at which to insert the passed Records.
4928 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4930 insert : function(index, records){
4931 records = [].concat(records);
4932 for(var i = 0, len = records.length; i < len; i++){
4933 this.data.insert(index, records[i]);
4934 records[i].join(this);
4936 this.fireEvent("add", this, records, index);
4940 * Get the index within the cache of the passed Record.
4941 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4942 * @return {Number} The index of the passed Record. Returns -1 if not found.
4944 indexOf : function(record){
4945 return this.data.indexOf(record);
4949 * Get the index within the cache of the Record with the passed id.
4950 * @param {String} id The id of the Record to find.
4951 * @return {Number} The index of the Record. Returns -1 if not found.
4953 indexOfId : function(id){
4954 return this.data.indexOfKey(id);
4958 * Get the Record with the specified id.
4959 * @param {String} id The id of the Record to find.
4960 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4962 getById : function(id){
4963 return this.data.key(id);
4967 * Get the Record at the specified index.
4968 * @param {Number} index The index of the Record to find.
4969 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4971 getAt : function(index){
4972 return this.data.itemAt(index);
4976 * Returns a range of Records between specified indices.
4977 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4978 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4979 * @return {Roo.data.Record[]} An array of Records
4981 getRange : function(start, end){
4982 return this.data.getRange(start, end);
4986 storeOptions : function(o){
4987 o = Roo.apply({}, o);
4990 this.lastOptions = o;
4994 * Loads the Record cache from the configured Proxy using the configured Reader.
4996 * If using remote paging, then the first load call must specify the <em>start</em>
4997 * and <em>limit</em> properties in the options.params property to establish the initial
4998 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5000 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5001 * and this call will return before the new data has been loaded. Perform any post-processing
5002 * in a callback function, or in a "load" event handler.</strong>
5004 * @param {Object} options An object containing properties which control loading options:<ul>
5005 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5006 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5007 * passed the following arguments:<ul>
5008 * <li>r : Roo.data.Record[]</li>
5009 * <li>options: Options object from the load call</li>
5010 * <li>success: Boolean success indicator</li></ul></li>
5011 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5012 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5015 load : function(options){
5016 options = options || {};
5017 if(this.fireEvent("beforeload", this, options) !== false){
5018 this.storeOptions(options);
5019 var p = Roo.apply(options.params || {}, this.baseParams);
5020 // if meta was not loaded from remote source.. try requesting it.
5021 if (!this.reader.metaFromRemote) {
5024 if(this.sortInfo && this.remoteSort){
5025 var pn = this.paramNames;
5026 p[pn["sort"]] = this.sortInfo.field;
5027 p[pn["dir"]] = this.sortInfo.direction;
5029 if (this.multiSort) {
5030 var pn = this.paramNames;
5031 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5034 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5039 * Reloads the Record cache from the configured Proxy using the configured Reader and
5040 * the options from the last load operation performed.
5041 * @param {Object} options (optional) An object containing properties which may override the options
5042 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5043 * the most recently used options are reused).
5045 reload : function(options){
5046 this.load(Roo.applyIf(options||{}, this.lastOptions));
5050 // Called as a callback by the Reader during a load operation.
5051 loadRecords : function(o, options, success){
5052 if(!o || success === false){
5053 if(success !== false){
5054 this.fireEvent("load", this, [], options);
5056 if(options.callback){
5057 options.callback.call(options.scope || this, [], options, false);
5061 // if data returned failure - throw an exception.
5062 if (o.success === false) {
5063 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5066 var r = o.records, t = o.totalRecords || r.length;
5067 if(!options || options.add !== true){
5068 if(this.pruneModifiedRecords){
5071 for(var i = 0, len = r.length; i < len; i++){
5075 this.data = this.snapshot;
5076 delete this.snapshot;
5079 this.data.addAll(r);
5080 this.totalLength = t;
5082 this.fireEvent("datachanged", this);
5084 this.totalLength = Math.max(t, this.data.length+r.length);
5087 this.fireEvent("load", this, r, options);
5088 if(options.callback){
5089 options.callback.call(options.scope || this, r, options, true);
5094 * Loads data from a passed data block. A Reader which understands the format of the data
5095 * must have been configured in the constructor.
5096 * @param {Object} data The data block from which to read the Records. The format of the data expected
5097 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5098 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5100 loadData : function(o, append){
5101 var r = this.reader.readRecords(o);
5102 this.loadRecords(r, {add: append}, true);
5106 * Gets the number of cached records.
5108 * <em>If using paging, this may not be the total size of the dataset. If the data object
5109 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5110 * the data set size</em>
5112 getCount : function(){
5113 return this.data.length || 0;
5117 * Gets the total number of records in the dataset as returned by the server.
5119 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5120 * the dataset size</em>
5122 getTotalCount : function(){
5123 return this.totalLength || 0;
5127 * Returns the sort state of the Store as an object with two properties:
5129 field {String} The name of the field by which the Records are sorted
5130 direction {String} The sort order, "ASC" or "DESC"
5133 getSortState : function(){
5134 return this.sortInfo;
5138 applySort : function(){
5139 if(this.sortInfo && !this.remoteSort){
5140 var s = this.sortInfo, f = s.field;
5141 var st = this.fields.get(f).sortType;
5142 var fn = function(r1, r2){
5143 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5144 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5146 this.data.sort(s.direction, fn);
5147 if(this.snapshot && this.snapshot != this.data){
5148 this.snapshot.sort(s.direction, fn);
5154 * Sets the default sort column and order to be used by the next load operation.
5155 * @param {String} fieldName The name of the field to sort by.
5156 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5158 setDefaultSort : function(field, dir){
5159 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5164 * If remote sorting is used, the sort is performed on the server, and the cache is
5165 * reloaded. If local sorting is used, the cache is sorted internally.
5166 * @param {String} fieldName The name of the field to sort by.
5167 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5169 sort : function(fieldName, dir){
5170 var f = this.fields.get(fieldName);
5172 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5174 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5175 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5180 this.sortToggle[f.name] = dir;
5181 this.sortInfo = {field: f.name, direction: dir};
5182 if(!this.remoteSort){
5184 this.fireEvent("datachanged", this);
5186 this.load(this.lastOptions);
5191 * Calls the specified function for each of the Records in the cache.
5192 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5193 * Returning <em>false</em> aborts and exits the iteration.
5194 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5196 each : function(fn, scope){
5197 this.data.each(fn, scope);
5201 * Gets all records modified since the last commit. Modified records are persisted across load operations
5202 * (e.g., during paging).
5203 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5205 getModifiedRecords : function(){
5206 return this.modified;
5210 createFilterFn : function(property, value, anyMatch){
5211 if(!value.exec){ // not a regex
5212 value = String(value);
5213 if(value.length == 0){
5216 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5219 return value.test(r.data[property]);
5224 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5225 * @param {String} property A field on your records
5226 * @param {Number} start The record index to start at (defaults to 0)
5227 * @param {Number} end The last record index to include (defaults to length - 1)
5228 * @return {Number} The sum
5230 sum : function(property, start, end){
5231 var rs = this.data.items, v = 0;
5233 end = (end || end === 0) ? end : rs.length-1;
5235 for(var i = start; i <= end; i++){
5236 v += (rs[i].data[property] || 0);
5242 * Filter the records by a specified property.
5243 * @param {String} field A field on your records
5244 * @param {String/RegExp} value Either a string that the field
5245 * should start with or a RegExp to test against the field
5246 * @param {Boolean} anyMatch True to match any part not just the beginning
5248 filter : function(property, value, anyMatch){
5249 var fn = this.createFilterFn(property, value, anyMatch);
5250 return fn ? this.filterBy(fn) : this.clearFilter();
5254 * Filter by a function. The specified function will be called with each
5255 * record in this data source. If the function returns true the record is included,
5256 * otherwise it is filtered.
5257 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5258 * @param {Object} scope (optional) The scope of the function (defaults to this)
5260 filterBy : function(fn, scope){
5261 this.snapshot = this.snapshot || this.data;
5262 this.data = this.queryBy(fn, scope||this);
5263 this.fireEvent("datachanged", this);
5267 * Query the records by a specified property.
5268 * @param {String} field A field on your records
5269 * @param {String/RegExp} value Either a string that the field
5270 * should start with or a RegExp to test against the field
5271 * @param {Boolean} anyMatch True to match any part not just the beginning
5272 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5274 query : function(property, value, anyMatch){
5275 var fn = this.createFilterFn(property, value, anyMatch);
5276 return fn ? this.queryBy(fn) : this.data.clone();
5280 * Query by a function. The specified function will be called with each
5281 * record in this data source. If the function returns true the record is included
5283 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5284 * @param {Object} scope (optional) The scope of the function (defaults to this)
5285 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5287 queryBy : function(fn, scope){
5288 var data = this.snapshot || this.data;
5289 return data.filterBy(fn, scope||this);
5293 * Collects unique values for a particular dataIndex from this store.
5294 * @param {String} dataIndex The property to collect
5295 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5296 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5297 * @return {Array} An array of the unique values
5299 collect : function(dataIndex, allowNull, bypassFilter){
5300 var d = (bypassFilter === true && this.snapshot) ?
5301 this.snapshot.items : this.data.items;
5302 var v, sv, r = [], l = {};
5303 for(var i = 0, len = d.length; i < len; i++){
5304 v = d[i].data[dataIndex];
5306 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5315 * Revert to a view of the Record cache with no filtering applied.
5316 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5318 clearFilter : function(suppressEvent){
5319 if(this.snapshot && this.snapshot != this.data){
5320 this.data = this.snapshot;
5321 delete this.snapshot;
5322 if(suppressEvent !== true){
5323 this.fireEvent("datachanged", this);
5329 afterEdit : function(record){
5330 if(this.modified.indexOf(record) == -1){
5331 this.modified.push(record);
5333 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5337 afterReject : function(record){
5338 this.modified.remove(record);
5339 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5343 afterCommit : function(record){
5344 this.modified.remove(record);
5345 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5349 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5350 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5352 commitChanges : function(){
5353 var m = this.modified.slice(0);
5355 for(var i = 0, len = m.length; i < len; i++){
5361 * Cancel outstanding changes on all changed records.
5363 rejectChanges : function(){
5364 var m = this.modified.slice(0);
5366 for(var i = 0, len = m.length; i < len; i++){
5371 onMetaChange : function(meta, rtype, o){
5372 this.recordType = rtype;
5373 this.fields = rtype.prototype.fields;
5374 delete this.snapshot;
5375 this.sortInfo = meta.sortInfo || this.sortInfo;
5377 this.fireEvent('metachange', this, this.reader.meta);
5381 * Ext JS Library 1.1.1
5382 * Copyright(c) 2006-2007, Ext JS, LLC.
5384 * Originally Released Under LGPL - original licence link has changed is not relivant.
5387 * <script type="text/javascript">
5391 * @class Roo.data.SimpleStore
5392 * @extends Roo.data.Store
5393 * Small helper class to make creating Stores from Array data easier.
5394 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5395 * @cfg {Array} fields An array of field definition objects, or field name strings.
5396 * @cfg {Array} data The multi-dimensional array of data
5398 * @param {Object} config
5400 Roo.data.SimpleStore = function(config){
5401 Roo.data.SimpleStore.superclass.constructor.call(this, {
5403 reader: new Roo.data.ArrayReader({
5406 Roo.data.Record.create(config.fields)
5408 proxy : new Roo.data.MemoryProxy(config.data)
5412 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5414 * Ext JS Library 1.1.1
5415 * Copyright(c) 2006-2007, Ext JS, LLC.
5417 * Originally Released Under LGPL - original licence link has changed is not relivant.
5420 * <script type="text/javascript">
5425 * @extends Roo.data.Store
5426 * @class Roo.data.JsonStore
5427 * Small helper class to make creating Stores for JSON data easier. <br/>
5429 var store = new Roo.data.JsonStore({
5430 url: 'get-images.php',
5432 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5435 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5436 * JsonReader and HttpProxy (unless inline data is provided).</b>
5437 * @cfg {Array} fields An array of field definition objects, or field name strings.
5439 * @param {Object} config
5441 Roo.data.JsonStore = function(c){
5442 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5443 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5444 reader: new Roo.data.JsonReader(c, c.fields)
5447 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5449 * Ext JS Library 1.1.1
5450 * Copyright(c) 2006-2007, Ext JS, LLC.
5452 * Originally Released Under LGPL - original licence link has changed is not relivant.
5455 * <script type="text/javascript">
5459 Roo.data.Field = function(config){
5460 if(typeof config == "string"){
5461 config = {name: config};
5463 Roo.apply(this, config);
5469 var st = Roo.data.SortTypes;
5470 // named sortTypes are supported, here we look them up
5471 if(typeof this.sortType == "string"){
5472 this.sortType = st[this.sortType];
5475 // set default sortType for strings and dates
5479 this.sortType = st.asUCString;
5482 this.sortType = st.asDate;
5485 this.sortType = st.none;
5490 var stripRe = /[\$,%]/g;
5492 // prebuilt conversion function for this field, instead of
5493 // switching every time we're reading a value
5495 var cv, dateFormat = this.dateFormat;
5500 cv = function(v){ return v; };
5503 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5507 return v !== undefined && v !== null && v !== '' ?
5508 parseInt(String(v).replace(stripRe, ""), 10) : '';
5513 return v !== undefined && v !== null && v !== '' ?
5514 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5519 cv = function(v){ return v === true || v === "true" || v == 1; };
5526 if(v instanceof Date){
5530 if(dateFormat == "timestamp"){
5531 return new Date(v*1000);
5533 return Date.parseDate(v, dateFormat);
5535 var parsed = Date.parse(v);
5536 return parsed ? new Date(parsed) : null;
5545 Roo.data.Field.prototype = {
5553 * Ext JS Library 1.1.1
5554 * Copyright(c) 2006-2007, Ext JS, LLC.
5556 * Originally Released Under LGPL - original licence link has changed is not relivant.
5559 * <script type="text/javascript">
5562 // Base class for reading structured data from a data source. This class is intended to be
5563 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5566 * @class Roo.data.DataReader
5567 * Base class for reading structured data from a data source. This class is intended to be
5568 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5571 Roo.data.DataReader = function(meta, recordType){
5575 this.recordType = recordType instanceof Array ?
5576 Roo.data.Record.create(recordType) : recordType;
5579 Roo.data.DataReader.prototype = {
5581 * Create an empty record
5582 * @param {Object} data (optional) - overlay some values
5583 * @return {Roo.data.Record} record created.
5585 newRow : function(d) {
5587 this.recordType.prototype.fields.each(function(c) {
5589 case 'int' : da[c.name] = 0; break;
5590 case 'date' : da[c.name] = new Date(); break;
5591 case 'float' : da[c.name] = 0.0; break;
5592 case 'boolean' : da[c.name] = false; break;
5593 default : da[c.name] = ""; break;
5597 return new this.recordType(Roo.apply(da, d));
5602 * Ext JS Library 1.1.1
5603 * Copyright(c) 2006-2007, Ext JS, LLC.
5605 * Originally Released Under LGPL - original licence link has changed is not relivant.
5608 * <script type="text/javascript">
5612 * @class Roo.data.DataProxy
5613 * @extends Roo.data.Observable
5614 * This class is an abstract base class for implementations which provide retrieval of
5615 * unformatted data objects.<br>
5617 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5618 * (of the appropriate type which knows how to parse the data object) to provide a block of
5619 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5621 * Custom implementations must implement the load method as described in
5622 * {@link Roo.data.HttpProxy#load}.
5624 Roo.data.DataProxy = function(){
5628 * Fires before a network request is made to retrieve a data object.
5629 * @param {Object} This DataProxy object.
5630 * @param {Object} params The params parameter to the load function.
5635 * Fires before the load method's callback is called.
5636 * @param {Object} This DataProxy object.
5637 * @param {Object} o The data object.
5638 * @param {Object} arg The callback argument object passed to the load function.
5642 * @event loadexception
5643 * Fires if an Exception occurs during data retrieval.
5644 * @param {Object} This DataProxy object.
5645 * @param {Object} o The data object.
5646 * @param {Object} arg The callback argument object passed to the load function.
5647 * @param {Object} e The Exception.
5649 loadexception : true
5651 Roo.data.DataProxy.superclass.constructor.call(this);
5654 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5657 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5661 * Ext JS Library 1.1.1
5662 * Copyright(c) 2006-2007, Ext JS, LLC.
5664 * Originally Released Under LGPL - original licence link has changed is not relivant.
5667 * <script type="text/javascript">
5670 * @class Roo.data.MemoryProxy
5671 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5672 * to the Reader when its load method is called.
5674 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5676 Roo.data.MemoryProxy = function(data){
5680 Roo.data.MemoryProxy.superclass.constructor.call(this);
5684 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5686 * Load data from the requested source (in this case an in-memory
5687 * data object passed to the constructor), read the data object into
5688 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5689 * process that block using the passed callback.
5690 * @param {Object} params This parameter is not used by the MemoryProxy class.
5691 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5692 * object into a block of Roo.data.Records.
5693 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5694 * The function must be passed <ul>
5695 * <li>The Record block object</li>
5696 * <li>The "arg" argument from the load function</li>
5697 * <li>A boolean success indicator</li>
5699 * @param {Object} scope The scope in which to call the callback
5700 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5702 load : function(params, reader, callback, scope, arg){
5703 params = params || {};
5706 result = reader.readRecords(this.data);
5708 this.fireEvent("loadexception", this, arg, null, e);
5709 callback.call(scope, null, arg, false);
5712 callback.call(scope, result, arg, true);
5716 update : function(params, records){
5721 * Ext JS Library 1.1.1
5722 * Copyright(c) 2006-2007, Ext JS, LLC.
5724 * Originally Released Under LGPL - original licence link has changed is not relivant.
5727 * <script type="text/javascript">
5730 * @class Roo.data.HttpProxy
5731 * @extends Roo.data.DataProxy
5732 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5733 * configured to reference a certain URL.<br><br>
5735 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5736 * from which the running page was served.<br><br>
5738 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5740 * Be aware that to enable the browser to parse an XML document, the server must set
5741 * the Content-Type header in the HTTP response to "text/xml".
5743 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5744 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5745 * will be used to make the request.
5747 Roo.data.HttpProxy = function(conn){
5748 Roo.data.HttpProxy.superclass.constructor.call(this);
5749 // is conn a conn config or a real conn?
5751 this.useAjax = !conn || !conn.events;
5755 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5756 // thse are take from connection...
5759 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5762 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5763 * extra parameters to each request made by this object. (defaults to undefined)
5766 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5767 * to each request made by this object. (defaults to undefined)
5770 * @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)
5773 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5776 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5782 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5786 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5787 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5788 * a finer-grained basis than the DataProxy events.
5790 getConnection : function(){
5791 return this.useAjax ? Roo.Ajax : this.conn;
5795 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5796 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5797 * process that block using the passed callback.
5798 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5799 * for the request to the remote server.
5800 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5801 * object into a block of Roo.data.Records.
5802 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5803 * The function must be passed <ul>
5804 * <li>The Record block object</li>
5805 * <li>The "arg" argument from the load function</li>
5806 * <li>A boolean success indicator</li>
5808 * @param {Object} scope The scope in which to call the callback
5809 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5811 load : function(params, reader, callback, scope, arg){
5812 if(this.fireEvent("beforeload", this, params) !== false){
5814 params : params || {},
5816 callback : callback,
5821 callback : this.loadResponse,
5825 Roo.applyIf(o, this.conn);
5826 if(this.activeRequest){
5827 Roo.Ajax.abort(this.activeRequest);
5829 this.activeRequest = Roo.Ajax.request(o);
5831 this.conn.request(o);
5834 callback.call(scope||this, null, arg, false);
5839 loadResponse : function(o, success, response){
5840 delete this.activeRequest;
5842 this.fireEvent("loadexception", this, o, response);
5843 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5848 result = o.reader.read(response);
5850 this.fireEvent("loadexception", this, o, response, e);
5851 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5855 this.fireEvent("load", this, o, o.request.arg);
5856 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5860 update : function(dataSet){
5865 updateResponse : function(dataSet){
5870 * Ext JS Library 1.1.1
5871 * Copyright(c) 2006-2007, Ext JS, LLC.
5873 * Originally Released Under LGPL - original licence link has changed is not relivant.
5876 * <script type="text/javascript">
5880 * @class Roo.data.ScriptTagProxy
5881 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5882 * other than the originating domain of the running page.<br><br>
5884 * <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
5885 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5887 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5888 * source code that is used as the source inside a <script> tag.<br><br>
5890 * In order for the browser to process the returned data, the server must wrap the data object
5891 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5892 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5893 * depending on whether the callback name was passed:
5896 boolean scriptTag = false;
5897 String cb = request.getParameter("callback");
5900 response.setContentType("text/javascript");
5902 response.setContentType("application/x-json");
5904 Writer out = response.getWriter();
5906 out.write(cb + "(");
5908 out.print(dataBlock.toJsonString());
5915 * @param {Object} config A configuration object.
5917 Roo.data.ScriptTagProxy = function(config){
5918 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5919 Roo.apply(this, config);
5920 this.head = document.getElementsByTagName("head")[0];
5923 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5925 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5927 * @cfg {String} url The URL from which to request the data object.
5930 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5934 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5935 * the server the name of the callback function set up by the load call to process the returned data object.
5936 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5937 * javascript output which calls this named function passing the data object as its only parameter.
5939 callbackParam : "callback",
5941 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5942 * name to the request.
5947 * Load data from the configured URL, read the data object into
5948 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5949 * process that block using the passed callback.
5950 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5951 * for the request to the remote server.
5952 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5953 * object into a block of Roo.data.Records.
5954 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5955 * The function must be passed <ul>
5956 * <li>The Record block object</li>
5957 * <li>The "arg" argument from the load function</li>
5958 * <li>A boolean success indicator</li>
5960 * @param {Object} scope The scope in which to call the callback
5961 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5963 load : function(params, reader, callback, scope, arg){
5964 if(this.fireEvent("beforeload", this, params) !== false){
5966 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5969 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5971 url += "&_dc=" + (new Date().getTime());
5973 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5976 cb : "stcCallback"+transId,
5977 scriptId : "stcScript"+transId,
5981 callback : callback,
5987 window[trans.cb] = function(o){
5988 conn.handleResponse(o, trans);
5991 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5993 if(this.autoAbort !== false){
5997 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5999 var script = document.createElement("script");
6000 script.setAttribute("src", url);
6001 script.setAttribute("type", "text/javascript");
6002 script.setAttribute("id", trans.scriptId);
6003 this.head.appendChild(script);
6007 callback.call(scope||this, null, arg, false);
6012 isLoading : function(){
6013 return this.trans ? true : false;
6017 * Abort the current server request.
6020 if(this.isLoading()){
6021 this.destroyTrans(this.trans);
6026 destroyTrans : function(trans, isLoaded){
6027 this.head.removeChild(document.getElementById(trans.scriptId));
6028 clearTimeout(trans.timeoutId);
6030 window[trans.cb] = undefined;
6032 delete window[trans.cb];
6035 // if hasn't been loaded, wait for load to remove it to prevent script error
6036 window[trans.cb] = function(){
6037 window[trans.cb] = undefined;
6039 delete window[trans.cb];
6046 handleResponse : function(o, trans){
6048 this.destroyTrans(trans, true);
6051 result = trans.reader.readRecords(o);
6053 this.fireEvent("loadexception", this, o, trans.arg, e);
6054 trans.callback.call(trans.scope||window, null, trans.arg, false);
6057 this.fireEvent("load", this, o, trans.arg);
6058 trans.callback.call(trans.scope||window, result, trans.arg, true);
6062 handleFailure : function(trans){
6064 this.destroyTrans(trans, false);
6065 this.fireEvent("loadexception", this, null, trans.arg);
6066 trans.callback.call(trans.scope||window, null, trans.arg, false);
6070 * Ext JS Library 1.1.1
6071 * Copyright(c) 2006-2007, Ext JS, LLC.
6073 * Originally Released Under LGPL - original licence link has changed is not relivant.
6076 * <script type="text/javascript">
6080 * @class Roo.data.JsonReader
6081 * @extends Roo.data.DataReader
6082 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6083 * based on mappings in a provided Roo.data.Record constructor.
6085 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6086 * in the reply previously.
6091 var RecordDef = Roo.data.Record.create([
6092 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6093 {name: 'occupation'} // This field will use "occupation" as the mapping.
6095 var myReader = new Roo.data.JsonReader({
6096 totalProperty: "results", // The property which contains the total dataset size (optional)
6097 root: "rows", // The property which contains an Array of row objects
6098 id: "id" // The property within each row object that provides an ID for the record (optional)
6102 * This would consume a JSON file like this:
6104 { 'results': 2, 'rows': [
6105 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6106 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6109 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6110 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6111 * paged from the remote server.
6112 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6113 * @cfg {String} root name of the property which contains the Array of row objects.
6114 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6116 * Create a new JsonReader
6117 * @param {Object} meta Metadata configuration options
6118 * @param {Object} recordType Either an Array of field definition objects,
6119 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6121 Roo.data.JsonReader = function(meta, recordType){
6124 // set some defaults:
6126 totalProperty: 'total',
6127 successProperty : 'success',
6132 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6134 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6137 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6138 * Used by Store query builder to append _requestMeta to params.
6141 metaFromRemote : false,
6143 * This method is only used by a DataProxy which has retrieved data from a remote server.
6144 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6145 * @return {Object} data A data block which is used by an Roo.data.Store object as
6146 * a cache of Roo.data.Records.
6148 read : function(response){
6149 var json = response.responseText;
6151 var o = /* eval:var:o */ eval("("+json+")");
6153 throw {message: "JsonReader.read: Json object not found"};
6159 this.metaFromRemote = true;
6160 this.meta = o.metaData;
6161 this.recordType = Roo.data.Record.create(o.metaData.fields);
6162 this.onMetaChange(this.meta, this.recordType, o);
6164 return this.readRecords(o);
6167 // private function a store will implement
6168 onMetaChange : function(meta, recordType, o){
6175 simpleAccess: function(obj, subsc) {
6182 getJsonAccessor: function(){
6184 return function(expr) {
6186 return(re.test(expr))
6187 ? new Function("obj", "return obj." + expr)
6197 * Create a data block containing Roo.data.Records from an XML document.
6198 * @param {Object} o An object which contains an Array of row objects in the property specified
6199 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6200 * which contains the total size of the dataset.
6201 * @return {Object} data A data block which is used by an Roo.data.Store object as
6202 * a cache of Roo.data.Records.
6204 readRecords : function(o){
6206 * After any data loads, the raw JSON data is available for further custom processing.
6210 var s = this.meta, Record = this.recordType,
6211 f = Record.prototype.fields, fi = f.items, fl = f.length;
6213 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6215 if(s.totalProperty) {
6216 this.getTotal = this.getJsonAccessor(s.totalProperty);
6218 if(s.successProperty) {
6219 this.getSuccess = this.getJsonAccessor(s.successProperty);
6221 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6223 var g = this.getJsonAccessor(s.id);
6224 this.getId = function(rec) {
6226 return (r === undefined || r === "") ? null : r;
6229 this.getId = function(){return null;};
6232 for(var jj = 0; jj < fl; jj++){
6234 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6235 this.ef[jj] = this.getJsonAccessor(map);
6239 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6240 if(s.totalProperty){
6241 var vt = parseInt(this.getTotal(o), 10);
6246 if(s.successProperty){
6247 var vs = this.getSuccess(o);
6248 if(vs === false || vs === 'false'){
6253 for(var i = 0; i < c; i++){
6256 var id = this.getId(n);
6257 for(var j = 0; j < fl; j++){
6259 var v = this.ef[j](n);
6261 Roo.log('missing convert for ' + f.name);
6265 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6267 var record = new Record(values, id);
6269 records[i] = record;
6274 totalRecords : totalRecords
6279 * Ext JS Library 1.1.1
6280 * Copyright(c) 2006-2007, Ext JS, LLC.
6282 * Originally Released Under LGPL - original licence link has changed is not relivant.
6285 * <script type="text/javascript">
6289 * @class Roo.data.XmlReader
6290 * @extends Roo.data.DataReader
6291 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6292 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6294 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6295 * header in the HTTP response must be set to "text/xml".</em>
6299 var RecordDef = Roo.data.Record.create([
6300 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6301 {name: 'occupation'} // This field will use "occupation" as the mapping.
6303 var myReader = new Roo.data.XmlReader({
6304 totalRecords: "results", // The element which contains the total dataset size (optional)
6305 record: "row", // The repeated element which contains row information
6306 id: "id" // The element within the row that provides an ID for the record (optional)
6310 * This would consume an XML file like this:
6314 <results>2</results>
6317 <name>Bill</name>
6318 <occupation>Gardener</occupation>
6322 <name>Ben</name>
6323 <occupation>Horticulturalist</occupation>
6327 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6328 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6329 * paged from the remote server.
6330 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6331 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6332 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6333 * a record identifier value.
6335 * Create a new XmlReader
6336 * @param {Object} meta Metadata configuration options
6337 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6338 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6339 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6341 Roo.data.XmlReader = function(meta, recordType){
6343 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6345 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6347 * This method is only used by a DataProxy which has retrieved data from a remote server.
6348 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6349 * to contain a method called 'responseXML' that returns an XML document object.
6350 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6351 * a cache of Roo.data.Records.
6353 read : function(response){
6354 var doc = response.responseXML;
6356 throw {message: "XmlReader.read: XML Document not available"};
6358 return this.readRecords(doc);
6362 * Create a data block containing Roo.data.Records from an XML document.
6363 * @param {Object} doc A parsed XML document.
6364 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6365 * a cache of Roo.data.Records.
6367 readRecords : function(doc){
6369 * After any data loads/reads, the raw XML Document is available for further custom processing.
6373 var root = doc.documentElement || doc;
6374 var q = Roo.DomQuery;
6375 var recordType = this.recordType, fields = recordType.prototype.fields;
6376 var sid = this.meta.id;
6377 var totalRecords = 0, success = true;
6378 if(this.meta.totalRecords){
6379 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6382 if(this.meta.success){
6383 var sv = q.selectValue(this.meta.success, root, true);
6384 success = sv !== false && sv !== 'false';
6387 var ns = q.select(this.meta.record, root);
6388 for(var i = 0, len = ns.length; i < len; i++) {
6391 var id = sid ? q.selectValue(sid, n) : undefined;
6392 for(var j = 0, jlen = fields.length; j < jlen; j++){
6393 var f = fields.items[j];
6394 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6398 var record = new recordType(values, id);
6400 records[records.length] = record;
6406 totalRecords : totalRecords || records.length
6411 * Ext JS Library 1.1.1
6412 * Copyright(c) 2006-2007, Ext JS, LLC.
6414 * Originally Released Under LGPL - original licence link has changed is not relivant.
6417 * <script type="text/javascript">
6421 * @class Roo.data.ArrayReader
6422 * @extends Roo.data.DataReader
6423 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6424 * Each element of that Array represents a row of data fields. The
6425 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6426 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6430 var RecordDef = Roo.data.Record.create([
6431 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6432 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6434 var myReader = new Roo.data.ArrayReader({
6435 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6439 * This would consume an Array like this:
6441 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6443 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6445 * Create a new JsonReader
6446 * @param {Object} meta Metadata configuration options.
6447 * @param {Object} recordType Either an Array of field definition objects
6448 * as specified to {@link Roo.data.Record#create},
6449 * or an {@link Roo.data.Record} object
6450 * created using {@link Roo.data.Record#create}.
6452 Roo.data.ArrayReader = function(meta, recordType){
6453 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6456 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6458 * Create a data block containing Roo.data.Records from an XML document.
6459 * @param {Object} o An Array of row objects which represents the dataset.
6460 * @return {Object} data A data block which is used by an Roo.data.Store object as
6461 * a cache of Roo.data.Records.
6463 readRecords : function(o){
6464 var sid = this.meta ? this.meta.id : null;
6465 var recordType = this.recordType, fields = recordType.prototype.fields;
6468 for(var i = 0; i < root.length; i++){
6471 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6472 for(var j = 0, jlen = fields.length; j < jlen; j++){
6473 var f = fields.items[j];
6474 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6475 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6479 var record = new recordType(values, id);
6481 records[records.length] = record;
6485 totalRecords : records.length
6490 * Ext JS Library 1.1.1
6491 * Copyright(c) 2006-2007, Ext JS, LLC.
6493 * Originally Released Under LGPL - original licence link has changed is not relivant.
6496 * <script type="text/javascript">
6501 * @class Roo.data.Tree
6502 * @extends Roo.util.Observable
6503 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6504 * in the tree have most standard DOM functionality.
6506 * @param {Node} root (optional) The root node
6508 Roo.data.Tree = function(root){
6511 * The root node for this tree
6516 this.setRootNode(root);
6521 * Fires when a new child node is appended to a node in this tree.
6522 * @param {Tree} tree The owner tree
6523 * @param {Node} parent The parent node
6524 * @param {Node} node The newly appended node
6525 * @param {Number} index The index of the newly appended node
6530 * Fires when a child node is removed from a node in this tree.
6531 * @param {Tree} tree The owner tree
6532 * @param {Node} parent The parent node
6533 * @param {Node} node The child node removed
6538 * Fires when a node is moved to a new location in the tree
6539 * @param {Tree} tree The owner tree
6540 * @param {Node} node The node moved
6541 * @param {Node} oldParent The old parent of this node
6542 * @param {Node} newParent The new parent of this node
6543 * @param {Number} index The index it was moved to
6548 * Fires when a new child node is inserted in a node in this tree.
6549 * @param {Tree} tree The owner tree
6550 * @param {Node} parent The parent node
6551 * @param {Node} node The child node inserted
6552 * @param {Node} refNode The child node the node was inserted before
6556 * @event beforeappend
6557 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6558 * @param {Tree} tree The owner tree
6559 * @param {Node} parent The parent node
6560 * @param {Node} node The child node to be appended
6562 "beforeappend" : true,
6564 * @event beforeremove
6565 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6566 * @param {Tree} tree The owner tree
6567 * @param {Node} parent The parent node
6568 * @param {Node} node The child node to be removed
6570 "beforeremove" : true,
6573 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6574 * @param {Tree} tree The owner tree
6575 * @param {Node} node The node being moved
6576 * @param {Node} oldParent The parent of the node
6577 * @param {Node} newParent The new parent the node is moving to
6578 * @param {Number} index The index it is being moved to
6580 "beforemove" : true,
6582 * @event beforeinsert
6583 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6584 * @param {Tree} tree The owner tree
6585 * @param {Node} parent The parent node
6586 * @param {Node} node The child node to be inserted
6587 * @param {Node} refNode The child node the node is being inserted before
6589 "beforeinsert" : true
6592 Roo.data.Tree.superclass.constructor.call(this);
6595 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6598 proxyNodeEvent : function(){
6599 return this.fireEvent.apply(this, arguments);
6603 * Returns the root node for this tree.
6606 getRootNode : function(){
6611 * Sets the root node for this tree.
6612 * @param {Node} node
6615 setRootNode : function(node){
6617 node.ownerTree = this;
6619 this.registerNode(node);
6624 * Gets a node in this tree by its id.
6625 * @param {String} id
6628 getNodeById : function(id){
6629 return this.nodeHash[id];
6632 registerNode : function(node){
6633 this.nodeHash[node.id] = node;
6636 unregisterNode : function(node){
6637 delete this.nodeHash[node.id];
6640 toString : function(){
6641 return "[Tree"+(this.id?" "+this.id:"")+"]";
6646 * @class Roo.data.Node
6647 * @extends Roo.util.Observable
6648 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6649 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6651 * @param {Object} attributes The attributes/config for the node
6653 Roo.data.Node = function(attributes){
6655 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6658 this.attributes = attributes || {};
6659 this.leaf = this.attributes.leaf;
6661 * The node id. @type String
6663 this.id = this.attributes.id;
6665 this.id = Roo.id(null, "ynode-");
6666 this.attributes.id = this.id;
6669 * All child nodes of this node. @type Array
6671 this.childNodes = [];
6672 if(!this.childNodes.indexOf){ // indexOf is a must
6673 this.childNodes.indexOf = function(o){
6674 for(var i = 0, len = this.length; i < len; i++){
6683 * The parent node for this node. @type Node
6685 this.parentNode = null;
6687 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6689 this.firstChild = null;
6691 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6693 this.lastChild = null;
6695 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6697 this.previousSibling = null;
6699 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6701 this.nextSibling = null;
6706 * Fires when a new child node is appended
6707 * @param {Tree} tree The owner tree
6708 * @param {Node} this This node
6709 * @param {Node} node The newly appended node
6710 * @param {Number} index The index of the newly appended node
6715 * Fires when a child node is removed
6716 * @param {Tree} tree The owner tree
6717 * @param {Node} this This node
6718 * @param {Node} node The removed node
6723 * Fires when this node is moved to a new location in the tree
6724 * @param {Tree} tree The owner tree
6725 * @param {Node} this This node
6726 * @param {Node} oldParent The old parent of this node
6727 * @param {Node} newParent The new parent of this node
6728 * @param {Number} index The index it was moved to
6733 * Fires when a new child node is inserted.
6734 * @param {Tree} tree The owner tree
6735 * @param {Node} this This node
6736 * @param {Node} node The child node inserted
6737 * @param {Node} refNode The child node the node was inserted before
6741 * @event beforeappend
6742 * Fires before a new child is appended, return false to cancel the append.
6743 * @param {Tree} tree The owner tree
6744 * @param {Node} this This node
6745 * @param {Node} node The child node to be appended
6747 "beforeappend" : true,
6749 * @event beforeremove
6750 * Fires before a child is removed, return false to cancel the remove.
6751 * @param {Tree} tree The owner tree
6752 * @param {Node} this This node
6753 * @param {Node} node The child node to be removed
6755 "beforeremove" : true,
6758 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6759 * @param {Tree} tree The owner tree
6760 * @param {Node} this This node
6761 * @param {Node} oldParent The parent of this node
6762 * @param {Node} newParent The new parent this node is moving to
6763 * @param {Number} index The index it is being moved to
6765 "beforemove" : true,
6767 * @event beforeinsert
6768 * Fires before a new child is inserted, return false to cancel the insert.
6769 * @param {Tree} tree The owner tree
6770 * @param {Node} this This node
6771 * @param {Node} node The child node to be inserted
6772 * @param {Node} refNode The child node the node is being inserted before
6774 "beforeinsert" : true
6776 this.listeners = this.attributes.listeners;
6777 Roo.data.Node.superclass.constructor.call(this);
6780 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6781 fireEvent : function(evtName){
6782 // first do standard event for this node
6783 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6786 // then bubble it up to the tree if the event wasn't cancelled
6787 var ot = this.getOwnerTree();
6789 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6797 * Returns true if this node is a leaf
6800 isLeaf : function(){
6801 return this.leaf === true;
6805 setFirstChild : function(node){
6806 this.firstChild = node;
6810 setLastChild : function(node){
6811 this.lastChild = node;
6816 * Returns true if this node is the last child of its parent
6819 isLast : function(){
6820 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6824 * Returns true if this node is the first child of its parent
6827 isFirst : function(){
6828 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6831 hasChildNodes : function(){
6832 return !this.isLeaf() && this.childNodes.length > 0;
6836 * Insert node(s) as the last child node of this node.
6837 * @param {Node/Array} node The node or Array of nodes to append
6838 * @return {Node} The appended node if single append, or null if an array was passed
6840 appendChild : function(node){
6842 if(node instanceof Array){
6844 }else if(arguments.length > 1){
6847 // if passed an array or multiple args do them one by one
6849 for(var i = 0, len = multi.length; i < len; i++) {
6850 this.appendChild(multi[i]);
6853 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6856 var index = this.childNodes.length;
6857 var oldParent = node.parentNode;
6858 // it's a move, make sure we move it cleanly
6860 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6863 oldParent.removeChild(node);
6865 index = this.childNodes.length;
6867 this.setFirstChild(node);
6869 this.childNodes.push(node);
6870 node.parentNode = this;
6871 var ps = this.childNodes[index-1];
6873 node.previousSibling = ps;
6874 ps.nextSibling = node;
6876 node.previousSibling = null;
6878 node.nextSibling = null;
6879 this.setLastChild(node);
6880 node.setOwnerTree(this.getOwnerTree());
6881 this.fireEvent("append", this.ownerTree, this, node, index);
6883 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6890 * Removes a child node from this node.
6891 * @param {Node} node The node to remove
6892 * @return {Node} The removed node
6894 removeChild : function(node){
6895 var index = this.childNodes.indexOf(node);
6899 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6903 // remove it from childNodes collection
6904 this.childNodes.splice(index, 1);
6907 if(node.previousSibling){
6908 node.previousSibling.nextSibling = node.nextSibling;
6910 if(node.nextSibling){
6911 node.nextSibling.previousSibling = node.previousSibling;
6914 // update child refs
6915 if(this.firstChild == node){
6916 this.setFirstChild(node.nextSibling);
6918 if(this.lastChild == node){
6919 this.setLastChild(node.previousSibling);
6922 node.setOwnerTree(null);
6923 // clear any references from the node
6924 node.parentNode = null;
6925 node.previousSibling = null;
6926 node.nextSibling = null;
6927 this.fireEvent("remove", this.ownerTree, this, node);
6932 * Inserts the first node before the second node in this nodes childNodes collection.
6933 * @param {Node} node The node to insert
6934 * @param {Node} refNode The node to insert before (if null the node is appended)
6935 * @return {Node} The inserted node
6937 insertBefore : function(node, refNode){
6938 if(!refNode){ // like standard Dom, refNode can be null for append
6939 return this.appendChild(node);
6942 if(node == refNode){
6946 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6949 var index = this.childNodes.indexOf(refNode);
6950 var oldParent = node.parentNode;
6951 var refIndex = index;
6953 // when moving internally, indexes will change after remove
6954 if(oldParent == this && this.childNodes.indexOf(node) < index){
6958 // it's a move, make sure we move it cleanly
6960 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6963 oldParent.removeChild(node);
6966 this.setFirstChild(node);
6968 this.childNodes.splice(refIndex, 0, node);
6969 node.parentNode = this;
6970 var ps = this.childNodes[refIndex-1];
6972 node.previousSibling = ps;
6973 ps.nextSibling = node;
6975 node.previousSibling = null;
6977 node.nextSibling = refNode;
6978 refNode.previousSibling = node;
6979 node.setOwnerTree(this.getOwnerTree());
6980 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6982 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6988 * Returns the child node at the specified index.
6989 * @param {Number} index
6992 item : function(index){
6993 return this.childNodes[index];
6997 * Replaces one child node in this node with another.
6998 * @param {Node} newChild The replacement node
6999 * @param {Node} oldChild The node to replace
7000 * @return {Node} The replaced node
7002 replaceChild : function(newChild, oldChild){
7003 this.insertBefore(newChild, oldChild);
7004 this.removeChild(oldChild);
7009 * Returns the index of a child node
7010 * @param {Node} node
7011 * @return {Number} The index of the node or -1 if it was not found
7013 indexOf : function(child){
7014 return this.childNodes.indexOf(child);
7018 * Returns the tree this node is in.
7021 getOwnerTree : function(){
7022 // if it doesn't have one, look for one
7023 if(!this.ownerTree){
7027 this.ownerTree = p.ownerTree;
7033 return this.ownerTree;
7037 * Returns depth of this node (the root node has a depth of 0)
7040 getDepth : function(){
7043 while(p.parentNode){
7051 setOwnerTree : function(tree){
7052 // if it's move, we need to update everyone
7053 if(tree != this.ownerTree){
7055 this.ownerTree.unregisterNode(this);
7057 this.ownerTree = tree;
7058 var cs = this.childNodes;
7059 for(var i = 0, len = cs.length; i < len; i++) {
7060 cs[i].setOwnerTree(tree);
7063 tree.registerNode(this);
7069 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7070 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7071 * @return {String} The path
7073 getPath : function(attr){
7074 attr = attr || "id";
7075 var p = this.parentNode;
7076 var b = [this.attributes[attr]];
7078 b.unshift(p.attributes[attr]);
7081 var sep = this.getOwnerTree().pathSeparator;
7082 return sep + b.join(sep);
7086 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7087 * function call will be the scope provided or the current node. The arguments to the function
7088 * will be the args provided or the current node. If the function returns false at any point,
7089 * the bubble is stopped.
7090 * @param {Function} fn The function to call
7091 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7092 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7094 bubble : function(fn, scope, args){
7097 if(fn.call(scope || p, args || p) === false){
7105 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7106 * function call will be the scope provided or the current node. The arguments to the function
7107 * will be the args provided or the current node. If the function returns false at any point,
7108 * the cascade is stopped on that branch.
7109 * @param {Function} fn The function to call
7110 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7111 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7113 cascade : function(fn, scope, args){
7114 if(fn.call(scope || this, args || this) !== false){
7115 var cs = this.childNodes;
7116 for(var i = 0, len = cs.length; i < len; i++) {
7117 cs[i].cascade(fn, scope, args);
7123 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7124 * function call will be the scope provided or the current node. The arguments to the function
7125 * will be the args provided or the current node. If the function returns false at any point,
7126 * the iteration stops.
7127 * @param {Function} fn The function to call
7128 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7129 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7131 eachChild : function(fn, scope, args){
7132 var cs = this.childNodes;
7133 for(var i = 0, len = cs.length; i < len; i++) {
7134 if(fn.call(scope || this, args || cs[i]) === false){
7141 * Finds the first child that has the attribute with the specified value.
7142 * @param {String} attribute The attribute name
7143 * @param {Mixed} value The value to search for
7144 * @return {Node} The found child or null if none was found
7146 findChild : function(attribute, value){
7147 var cs = this.childNodes;
7148 for(var i = 0, len = cs.length; i < len; i++) {
7149 if(cs[i].attributes[attribute] == value){
7157 * Finds the first child by a custom function. The child matches if the function passed
7159 * @param {Function} fn
7160 * @param {Object} scope (optional)
7161 * @return {Node} The found child or null if none was found
7163 findChildBy : function(fn, scope){
7164 var cs = this.childNodes;
7165 for(var i = 0, len = cs.length; i < len; i++) {
7166 if(fn.call(scope||cs[i], cs[i]) === true){
7174 * Sorts this nodes children using the supplied sort function
7175 * @param {Function} fn
7176 * @param {Object} scope (optional)
7178 sort : function(fn, scope){
7179 var cs = this.childNodes;
7180 var len = cs.length;
7182 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7184 for(var i = 0; i < len; i++){
7186 n.previousSibling = cs[i-1];
7187 n.nextSibling = cs[i+1];
7189 this.setFirstChild(n);
7192 this.setLastChild(n);
7199 * Returns true if this node is an ancestor (at any point) of the passed node.
7200 * @param {Node} node
7203 contains : function(node){
7204 return node.isAncestor(this);
7208 * Returns true if the passed node is an ancestor (at any point) of this node.
7209 * @param {Node} node
7212 isAncestor : function(node){
7213 var p = this.parentNode;
7223 toString : function(){
7224 return "[Node"+(this.id?" "+this.id:"")+"]";
7228 * Ext JS Library 1.1.1
7229 * Copyright(c) 2006-2007, Ext JS, LLC.
7231 * Originally Released Under LGPL - original licence link has changed is not relivant.
7234 * <script type="text/javascript">
7239 * @class Roo.ComponentMgr
7240 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7243 Roo.ComponentMgr = function(){
7244 var all = new Roo.util.MixedCollection();
7248 * Registers a component.
7249 * @param {Roo.Component} c The component
7251 register : function(c){
7256 * Unregisters a component.
7257 * @param {Roo.Component} c The component
7259 unregister : function(c){
7264 * Returns a component by id
7265 * @param {String} id The component id
7272 * Registers a function that will be called when a specified component is added to ComponentMgr
7273 * @param {String} id The component id
7274 * @param {Funtction} fn The callback function
7275 * @param {Object} scope The scope of the callback
7277 onAvailable : function(id, fn, scope){
7278 all.on("add", function(index, o){
7280 fn.call(scope || o, o);
7281 all.un("add", fn, scope);
7288 * Ext JS Library 1.1.1
7289 * Copyright(c) 2006-2007, Ext JS, LLC.
7291 * Originally Released Under LGPL - original licence link has changed is not relivant.
7294 * <script type="text/javascript">
7298 * @class Roo.Component
7299 * @extends Roo.util.Observable
7300 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7301 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7302 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7303 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7304 * All visual components (widgets) that require rendering into a layout should subclass Component.
7306 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7307 * 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
7308 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7310 Roo.Component = function(config){
7311 config = config || {};
7312 if(config.tagName || config.dom || typeof config == "string"){ // element object
7313 config = {el: config, id: config.id || config};
7315 this.initialConfig = config;
7317 Roo.apply(this, config);
7321 * Fires after the component is disabled.
7322 * @param {Roo.Component} this
7327 * Fires after the component is enabled.
7328 * @param {Roo.Component} this
7333 * Fires before the component is shown. Return false to stop the show.
7334 * @param {Roo.Component} this
7339 * Fires after the component is shown.
7340 * @param {Roo.Component} this
7345 * Fires before the component is hidden. Return false to stop the hide.
7346 * @param {Roo.Component} this
7351 * Fires after the component is hidden.
7352 * @param {Roo.Component} this
7356 * @event beforerender
7357 * Fires before the component is rendered. Return false to stop the render.
7358 * @param {Roo.Component} this
7360 beforerender : true,
7363 * Fires after the component is rendered.
7364 * @param {Roo.Component} this
7368 * @event beforedestroy
7369 * Fires before the component is destroyed. Return false to stop the destroy.
7370 * @param {Roo.Component} this
7372 beforedestroy : true,
7375 * Fires after the component is destroyed.
7376 * @param {Roo.Component} this
7381 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7383 Roo.ComponentMgr.register(this);
7384 Roo.Component.superclass.constructor.call(this);
7385 this.initComponent();
7386 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7387 this.render(this.renderTo);
7388 delete this.renderTo;
7393 Roo.Component.AUTO_ID = 1000;
7395 Roo.extend(Roo.Component, Roo.util.Observable, {
7397 * @property {Boolean} hidden
7398 * true if this component is hidden. Read-only.
7402 * true if this component is disabled. Read-only.
7406 * true if this component has been rendered. Read-only.
7410 /** @cfg {String} disableClass
7411 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7413 disabledClass : "x-item-disabled",
7414 /** @cfg {Boolean} allowDomMove
7415 * Whether the component can move the Dom node when rendering (defaults to true).
7417 allowDomMove : true,
7418 /** @cfg {String} hideMode
7419 * How this component should hidden. Supported values are
7420 * "visibility" (css visibility), "offsets" (negative offset position) and
7421 * "display" (css display) - defaults to "display".
7423 hideMode: 'display',
7426 ctype : "Roo.Component",
7428 /** @cfg {String} actionMode
7429 * which property holds the element that used for hide() / show() / disable() / enable()
7435 getActionEl : function(){
7436 return this[this.actionMode];
7439 initComponent : Roo.emptyFn,
7441 * If this is a lazy rendering component, render it to its container element.
7442 * @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.
7444 render : function(container, position){
7445 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7446 if(!container && this.el){
7447 this.el = Roo.get(this.el);
7448 container = this.el.dom.parentNode;
7449 this.allowDomMove = false;
7451 this.container = Roo.get(container);
7452 this.rendered = true;
7453 if(position !== undefined){
7454 if(typeof position == 'number'){
7455 position = this.container.dom.childNodes[position];
7457 position = Roo.getDom(position);
7460 this.onRender(this.container, position || null);
7462 this.el.addClass(this.cls);
7466 this.el.applyStyles(this.style);
7469 this.fireEvent("render", this);
7470 this.afterRender(this.container);
7482 // default function is not really useful
7483 onRender : function(ct, position){
7485 this.el = Roo.get(this.el);
7486 if(this.allowDomMove !== false){
7487 ct.dom.insertBefore(this.el.dom, position);
7493 getAutoCreate : function(){
7494 var cfg = typeof this.autoCreate == "object" ?
7495 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7496 if(this.id && !cfg.id){
7503 afterRender : Roo.emptyFn,
7506 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7507 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7509 destroy : function(){
7510 if(this.fireEvent("beforedestroy", this) !== false){
7511 this.purgeListeners();
7512 this.beforeDestroy();
7514 this.el.removeAllListeners();
7516 if(this.actionMode == "container"){
7517 this.container.remove();
7521 Roo.ComponentMgr.unregister(this);
7522 this.fireEvent("destroy", this);
7527 beforeDestroy : function(){
7532 onDestroy : function(){
7537 * Returns the underlying {@link Roo.Element}.
7538 * @return {Roo.Element} The element
7545 * Returns the id of this component.
7553 * Try to focus this component.
7554 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7555 * @return {Roo.Component} this
7557 focus : function(selectText){
7560 if(selectText === true){
7561 this.el.dom.select();
7576 * Disable this component.
7577 * @return {Roo.Component} this
7579 disable : function(){
7583 this.disabled = true;
7584 this.fireEvent("disable", this);
7589 onDisable : function(){
7590 this.getActionEl().addClass(this.disabledClass);
7591 this.el.dom.disabled = true;
7595 * Enable this component.
7596 * @return {Roo.Component} this
7598 enable : function(){
7602 this.disabled = false;
7603 this.fireEvent("enable", this);
7608 onEnable : function(){
7609 this.getActionEl().removeClass(this.disabledClass);
7610 this.el.dom.disabled = false;
7614 * Convenience function for setting disabled/enabled by boolean.
7615 * @param {Boolean} disabled
7617 setDisabled : function(disabled){
7618 this[disabled ? "disable" : "enable"]();
7622 * Show this component.
7623 * @return {Roo.Component} this
7626 if(this.fireEvent("beforeshow", this) !== false){
7627 this.hidden = false;
7631 this.fireEvent("show", this);
7637 onShow : function(){
7638 var ae = this.getActionEl();
7639 if(this.hideMode == 'visibility'){
7640 ae.dom.style.visibility = "visible";
7641 }else if(this.hideMode == 'offsets'){
7642 ae.removeClass('x-hidden');
7644 ae.dom.style.display = "";
7649 * Hide this component.
7650 * @return {Roo.Component} this
7653 if(this.fireEvent("beforehide", this) !== false){
7658 this.fireEvent("hide", this);
7664 onHide : function(){
7665 var ae = this.getActionEl();
7666 if(this.hideMode == 'visibility'){
7667 ae.dom.style.visibility = "hidden";
7668 }else if(this.hideMode == 'offsets'){
7669 ae.addClass('x-hidden');
7671 ae.dom.style.display = "none";
7676 * Convenience function to hide or show this component by boolean.
7677 * @param {Boolean} visible True to show, false to hide
7678 * @return {Roo.Component} this
7680 setVisible: function(visible){
7690 * Returns true if this component is visible.
7692 isVisible : function(){
7693 return this.getActionEl().isVisible();
7696 cloneConfig : function(overrides){
7697 overrides = overrides || {};
7698 var id = overrides.id || Roo.id();
7699 var cfg = Roo.applyIf(overrides, this.initialConfig);
7700 cfg.id = id; // prevent dup id
7701 return new this.constructor(cfg);
7705 * Ext JS Library 1.1.1
7706 * Copyright(c) 2006-2007, Ext JS, LLC.
7708 * Originally Released Under LGPL - original licence link has changed is not relivant.
7711 * <script type="text/javascript">
7716 * @extends Roo.Element
7717 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7718 * automatic maintaining of shadow/shim positions.
7719 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7720 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7721 * you can pass a string with a CSS class name. False turns off the shadow.
7722 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7723 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7724 * @cfg {String} cls CSS class to add to the element
7725 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7726 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7728 * @param {Object} config An object with config options.
7729 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7732 Roo.Layer = function(config, existingEl){
7733 config = config || {};
7734 var dh = Roo.DomHelper;
7735 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7737 this.dom = Roo.getDom(existingEl);
7740 var o = config.dh || {tag: "div", cls: "x-layer"};
7741 this.dom = dh.append(pel, o);
7744 this.addClass(config.cls);
7746 this.constrain = config.constrain !== false;
7747 this.visibilityMode = Roo.Element.VISIBILITY;
7749 this.id = this.dom.id = config.id;
7751 this.id = Roo.id(this.dom);
7753 this.zindex = config.zindex || this.getZIndex();
7754 this.position("absolute", this.zindex);
7756 this.shadowOffset = config.shadowOffset || 4;
7757 this.shadow = new Roo.Shadow({
7758 offset : this.shadowOffset,
7759 mode : config.shadow
7762 this.shadowOffset = 0;
7764 this.useShim = config.shim !== false && Roo.useShims;
7765 this.useDisplay = config.useDisplay;
7769 var supr = Roo.Element.prototype;
7771 // shims are shared among layer to keep from having 100 iframes
7774 Roo.extend(Roo.Layer, Roo.Element, {
7776 getZIndex : function(){
7777 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7780 getShim : function(){
7787 var shim = shims.shift();
7789 shim = this.createShim();
7790 shim.enableDisplayMode('block');
7791 shim.dom.style.display = 'none';
7792 shim.dom.style.visibility = 'visible';
7794 var pn = this.dom.parentNode;
7795 if(shim.dom.parentNode != pn){
7796 pn.insertBefore(shim.dom, this.dom);
7798 shim.setStyle('z-index', this.getZIndex()-2);
7803 hideShim : function(){
7805 this.shim.setDisplayed(false);
7806 shims.push(this.shim);
7811 disableShadow : function(){
7813 this.shadowDisabled = true;
7815 this.lastShadowOffset = this.shadowOffset;
7816 this.shadowOffset = 0;
7820 enableShadow : function(show){
7822 this.shadowDisabled = false;
7823 this.shadowOffset = this.lastShadowOffset;
7824 delete this.lastShadowOffset;
7832 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7833 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7834 sync : function(doShow){
7835 var sw = this.shadow;
7836 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7837 var sh = this.getShim();
7839 var w = this.getWidth(),
7840 h = this.getHeight();
7842 var l = this.getLeft(true),
7843 t = this.getTop(true);
7845 if(sw && !this.shadowDisabled){
7846 if(doShow && !sw.isVisible()){
7849 sw.realign(l, t, w, h);
7855 // fit the shim behind the shadow, so it is shimmed too
7856 var a = sw.adjusts, s = sh.dom.style;
7857 s.left = (Math.min(l, l+a.l))+"px";
7858 s.top = (Math.min(t, t+a.t))+"px";
7859 s.width = (w+a.w)+"px";
7860 s.height = (h+a.h)+"px";
7867 sh.setLeftTop(l, t);
7874 destroy : function(){
7879 this.removeAllListeners();
7880 var pn = this.dom.parentNode;
7882 pn.removeChild(this.dom);
7884 Roo.Element.uncache(this.id);
7887 remove : function(){
7892 beginUpdate : function(){
7893 this.updating = true;
7897 endUpdate : function(){
7898 this.updating = false;
7903 hideUnders : function(negOffset){
7911 constrainXY : function(){
7913 var vw = Roo.lib.Dom.getViewWidth(),
7914 vh = Roo.lib.Dom.getViewHeight();
7915 var s = Roo.get(document).getScroll();
7917 var xy = this.getXY();
7918 var x = xy[0], y = xy[1];
7919 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7920 // only move it if it needs it
7922 // first validate right/bottom
7923 if((x + w) > vw+s.left){
7924 x = vw - w - this.shadowOffset;
7927 if((y + h) > vh+s.top){
7928 y = vh - h - this.shadowOffset;
7931 // then make sure top/left isn't negative
7942 var ay = this.avoidY;
7943 if(y <= ay && (y+h) >= ay){
7949 supr.setXY.call(this, xy);
7955 isVisible : function(){
7956 return this.visible;
7960 showAction : function(){
7961 this.visible = true; // track visibility to prevent getStyle calls
7962 if(this.useDisplay === true){
7963 this.setDisplayed("");
7964 }else if(this.lastXY){
7965 supr.setXY.call(this, this.lastXY);
7966 }else if(this.lastLT){
7967 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7972 hideAction : function(){
7973 this.visible = false;
7974 if(this.useDisplay === true){
7975 this.setDisplayed(false);
7977 this.setLeftTop(-10000,-10000);
7981 // overridden Element method
7982 setVisible : function(v, a, d, c, e){
7987 var cb = function(){
7992 }.createDelegate(this);
7993 supr.setVisible.call(this, true, true, d, cb, e);
7996 this.hideUnders(true);
8005 }.createDelegate(this);
8007 supr.setVisible.call(this, v, a, d, cb, e);
8016 storeXY : function(xy){
8021 storeLeftTop : function(left, top){
8023 this.lastLT = [left, top];
8027 beforeFx : function(){
8028 this.beforeAction();
8029 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8033 afterFx : function(){
8034 Roo.Layer.superclass.afterFx.apply(this, arguments);
8035 this.sync(this.isVisible());
8039 beforeAction : function(){
8040 if(!this.updating && this.shadow){
8045 // overridden Element method
8046 setLeft : function(left){
8047 this.storeLeftTop(left, this.getTop(true));
8048 supr.setLeft.apply(this, arguments);
8052 setTop : function(top){
8053 this.storeLeftTop(this.getLeft(true), top);
8054 supr.setTop.apply(this, arguments);
8058 setLeftTop : function(left, top){
8059 this.storeLeftTop(left, top);
8060 supr.setLeftTop.apply(this, arguments);
8064 setXY : function(xy, a, d, c, e){
8066 this.beforeAction();
8068 var cb = this.createCB(c);
8069 supr.setXY.call(this, xy, a, d, cb, e);
8076 createCB : function(c){
8087 // overridden Element method
8088 setX : function(x, a, d, c, e){
8089 this.setXY([x, this.getY()], a, d, c, e);
8092 // overridden Element method
8093 setY : function(y, a, d, c, e){
8094 this.setXY([this.getX(), y], a, d, c, e);
8097 // overridden Element method
8098 setSize : function(w, h, a, d, c, e){
8099 this.beforeAction();
8100 var cb = this.createCB(c);
8101 supr.setSize.call(this, w, h, a, d, cb, e);
8107 // overridden Element method
8108 setWidth : function(w, a, d, c, e){
8109 this.beforeAction();
8110 var cb = this.createCB(c);
8111 supr.setWidth.call(this, w, a, d, cb, e);
8117 // overridden Element method
8118 setHeight : function(h, a, d, c, e){
8119 this.beforeAction();
8120 var cb = this.createCB(c);
8121 supr.setHeight.call(this, h, a, d, cb, e);
8127 // overridden Element method
8128 setBounds : function(x, y, w, h, a, d, c, e){
8129 this.beforeAction();
8130 var cb = this.createCB(c);
8132 this.storeXY([x, y]);
8133 supr.setXY.call(this, [x, y]);
8134 supr.setSize.call(this, w, h, a, d, cb, e);
8137 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8143 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8144 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8145 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8146 * @param {Number} zindex The new z-index to set
8147 * @return {this} The Layer
8149 setZIndex : function(zindex){
8150 this.zindex = zindex;
8151 this.setStyle("z-index", zindex + 2);
8153 this.shadow.setZIndex(zindex + 1);
8156 this.shim.setStyle("z-index", zindex);
8162 * Ext JS Library 1.1.1
8163 * Copyright(c) 2006-2007, Ext JS, LLC.
8165 * Originally Released Under LGPL - original licence link has changed is not relivant.
8168 * <script type="text/javascript">
8174 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8175 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8176 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8178 * Create a new Shadow
8179 * @param {Object} config The config object
8181 Roo.Shadow = function(config){
8182 Roo.apply(this, config);
8183 if(typeof this.mode != "string"){
8184 this.mode = this.defaultMode;
8186 var o = this.offset, a = {h: 0};
8187 var rad = Math.floor(this.offset/2);
8188 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8194 a.l -= this.offset + rad;
8195 a.t -= this.offset + rad;
8206 a.l -= (this.offset - rad);
8207 a.t -= this.offset + rad;
8209 a.w -= (this.offset - rad)*2;
8220 a.l -= (this.offset - rad);
8221 a.t -= (this.offset - rad);
8223 a.w -= (this.offset + rad + 1);
8224 a.h -= (this.offset + rad);
8233 Roo.Shadow.prototype = {
8235 * @cfg {String} mode
8236 * The shadow display mode. Supports the following options:<br />
8237 * sides: Shadow displays on both sides and bottom only<br />
8238 * frame: Shadow displays equally on all four sides<br />
8239 * drop: Traditional bottom-right drop shadow (default)
8242 * @cfg {String} offset
8243 * The number of pixels to offset the shadow from the element (defaults to 4)
8248 defaultMode: "drop",
8251 * Displays the shadow under the target element
8252 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8254 show : function(target){
8255 target = Roo.get(target);
8257 this.el = Roo.Shadow.Pool.pull();
8258 if(this.el.dom.nextSibling != target.dom){
8259 this.el.insertBefore(target);
8262 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8264 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8267 target.getLeft(true),
8268 target.getTop(true),
8272 this.el.dom.style.display = "block";
8276 * Returns true if the shadow is visible, else false
8278 isVisible : function(){
8279 return this.el ? true : false;
8283 * Direct alignment when values are already available. Show must be called at least once before
8284 * calling this method to ensure it is initialized.
8285 * @param {Number} left The target element left position
8286 * @param {Number} top The target element top position
8287 * @param {Number} width The target element width
8288 * @param {Number} height The target element height
8290 realign : function(l, t, w, h){
8294 var a = this.adjusts, d = this.el.dom, s = d.style;
8296 s.left = (l+a.l)+"px";
8297 s.top = (t+a.t)+"px";
8298 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8300 if(s.width != sws || s.height != shs){
8304 var cn = d.childNodes;
8305 var sww = Math.max(0, (sw-12))+"px";
8306 cn[0].childNodes[1].style.width = sww;
8307 cn[1].childNodes[1].style.width = sww;
8308 cn[2].childNodes[1].style.width = sww;
8309 cn[1].style.height = Math.max(0, (sh-12))+"px";
8319 this.el.dom.style.display = "none";
8320 Roo.Shadow.Pool.push(this.el);
8326 * Adjust the z-index of this shadow
8327 * @param {Number} zindex The new z-index
8329 setZIndex : function(z){
8332 this.el.setStyle("z-index", z);
8337 // Private utility class that manages the internal Shadow cache
8338 Roo.Shadow.Pool = function(){
8340 var markup = Roo.isIE ?
8341 '<div class="x-ie-shadow"></div>' :
8342 '<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>';
8347 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8348 sh.autoBoxAdjust = false;
8353 push : function(sh){
8359 * Ext JS Library 1.1.1
8360 * Copyright(c) 2006-2007, Ext JS, LLC.
8362 * Originally Released Under LGPL - original licence link has changed is not relivant.
8365 * <script type="text/javascript">
8369 * @class Roo.BoxComponent
8370 * @extends Roo.Component
8371 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8372 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8373 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8374 * layout containers.
8376 * @param {Roo.Element/String/Object} config The configuration options.
8378 Roo.BoxComponent = function(config){
8379 Roo.Component.call(this, config);
8383 * Fires after the component is resized.
8384 * @param {Roo.Component} this
8385 * @param {Number} adjWidth The box-adjusted width that was set
8386 * @param {Number} adjHeight The box-adjusted height that was set
8387 * @param {Number} rawWidth The width that was originally specified
8388 * @param {Number} rawHeight The height that was originally specified
8393 * Fires after the component is moved.
8394 * @param {Roo.Component} this
8395 * @param {Number} x The new x position
8396 * @param {Number} y The new y position
8402 Roo.extend(Roo.BoxComponent, Roo.Component, {
8403 // private, set in afterRender to signify that the component has been rendered
8405 // private, used to defer height settings to subclasses
8407 /** @cfg {Number} width
8408 * width (optional) size of component
8410 /** @cfg {Number} height
8411 * height (optional) size of component
8415 * Sets the width and height of the component. This method fires the resize event. This method can accept
8416 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8417 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8418 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8419 * @return {Roo.BoxComponent} this
8421 setSize : function(w, h){
8422 // support for standard size objects
8423 if(typeof w == 'object'){
8434 // prevent recalcs when not needed
8435 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8438 this.lastSize = {width: w, height: h};
8440 var adj = this.adjustSize(w, h);
8441 var aw = adj.width, ah = adj.height;
8442 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8443 var rz = this.getResizeEl();
8444 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8446 }else if(!this.deferHeight && ah !== undefined){
8448 }else if(aw !== undefined){
8451 this.onResize(aw, ah, w, h);
8452 this.fireEvent('resize', this, aw, ah, w, h);
8458 * Gets the current size of the component's underlying element.
8459 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8461 getSize : function(){
8462 return this.el.getSize();
8466 * Gets the current XY position of the component's underlying element.
8467 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8468 * @return {Array} The XY position of the element (e.g., [100, 200])
8470 getPosition : function(local){
8472 return [this.el.getLeft(true), this.el.getTop(true)];
8474 return this.xy || this.el.getXY();
8478 * Gets the current box measurements of the component's underlying element.
8479 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8480 * @returns {Object} box An object in the format {x, y, width, height}
8482 getBox : function(local){
8483 var s = this.el.getSize();
8485 s.x = this.el.getLeft(true);
8486 s.y = this.el.getTop(true);
8488 var xy = this.xy || this.el.getXY();
8496 * Sets the current box measurements of the component's underlying element.
8497 * @param {Object} box An object in the format {x, y, width, height}
8498 * @returns {Roo.BoxComponent} this
8500 updateBox : function(box){
8501 this.setSize(box.width, box.height);
8502 this.setPagePosition(box.x, box.y);
8507 getResizeEl : function(){
8508 return this.resizeEl || this.el;
8512 getPositionEl : function(){
8513 return this.positionEl || this.el;
8517 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8518 * This method fires the move event.
8519 * @param {Number} left The new left
8520 * @param {Number} top The new top
8521 * @returns {Roo.BoxComponent} this
8523 setPosition : function(x, y){
8529 var adj = this.adjustPosition(x, y);
8530 var ax = adj.x, ay = adj.y;
8532 var el = this.getPositionEl();
8533 if(ax !== undefined || ay !== undefined){
8534 if(ax !== undefined && ay !== undefined){
8535 el.setLeftTop(ax, ay);
8536 }else if(ax !== undefined){
8538 }else if(ay !== undefined){
8541 this.onPosition(ax, ay);
8542 this.fireEvent('move', this, ax, ay);
8548 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8549 * This method fires the move event.
8550 * @param {Number} x The new x position
8551 * @param {Number} y The new y position
8552 * @returns {Roo.BoxComponent} this
8554 setPagePosition : function(x, y){
8560 if(x === undefined || y === undefined){ // cannot translate undefined points
8563 var p = this.el.translatePoints(x, y);
8564 this.setPosition(p.left, p.top);
8569 onRender : function(ct, position){
8570 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8572 this.resizeEl = Roo.get(this.resizeEl);
8574 if(this.positionEl){
8575 this.positionEl = Roo.get(this.positionEl);
8580 afterRender : function(){
8581 Roo.BoxComponent.superclass.afterRender.call(this);
8582 this.boxReady = true;
8583 this.setSize(this.width, this.height);
8584 if(this.x || this.y){
8585 this.setPosition(this.x, this.y);
8587 if(this.pageX || this.pageY){
8588 this.setPagePosition(this.pageX, this.pageY);
8593 * Force the component's size to recalculate based on the underlying element's current height and width.
8594 * @returns {Roo.BoxComponent} this
8596 syncSize : function(){
8597 delete this.lastSize;
8598 this.setSize(this.el.getWidth(), this.el.getHeight());
8603 * Called after the component is resized, this method is empty by default but can be implemented by any
8604 * subclass that needs to perform custom logic after a resize occurs.
8605 * @param {Number} adjWidth The box-adjusted width that was set
8606 * @param {Number} adjHeight The box-adjusted height that was set
8607 * @param {Number} rawWidth The width that was originally specified
8608 * @param {Number} rawHeight The height that was originally specified
8610 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8615 * Called after the component is moved, this method is empty by default but can be implemented by any
8616 * subclass that needs to perform custom logic after a move occurs.
8617 * @param {Number} x The new x position
8618 * @param {Number} y The new y position
8620 onPosition : function(x, y){
8625 adjustSize : function(w, h){
8629 if(this.autoHeight){
8632 return {width : w, height: h};
8636 adjustPosition : function(x, y){
8637 return {x : x, y: y};
8641 * Ext JS Library 1.1.1
8642 * Copyright(c) 2006-2007, Ext JS, LLC.
8644 * Originally Released Under LGPL - original licence link has changed is not relivant.
8647 * <script type="text/javascript">
8652 * @class Roo.SplitBar
8653 * @extends Roo.util.Observable
8654 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8658 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8659 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8660 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8661 split.minSize = 100;
8662 split.maxSize = 600;
8663 split.animate = true;
8664 split.on('moved', splitterMoved);
8667 * Create a new SplitBar
8668 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8669 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8670 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8671 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8672 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8673 position of the SplitBar).
8675 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8678 this.el = Roo.get(dragElement, true);
8679 this.el.dom.unselectable = "on";
8681 this.resizingEl = Roo.get(resizingElement, true);
8685 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8686 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8689 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8692 * The minimum size of the resizing element. (Defaults to 0)
8698 * The maximum size of the resizing element. (Defaults to 2000)
8701 this.maxSize = 2000;
8704 * Whether to animate the transition to the new size
8707 this.animate = false;
8710 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8713 this.useShim = false;
8720 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8722 this.proxy = Roo.get(existingProxy).dom;
8725 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8728 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8731 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8734 this.dragSpecs = {};
8737 * @private The adapter to use to positon and resize elements
8739 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8740 this.adapter.init(this);
8742 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8744 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8745 this.el.addClass("x-splitbar-h");
8748 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8749 this.el.addClass("x-splitbar-v");
8755 * Fires when the splitter is moved (alias for {@link #event-moved})
8756 * @param {Roo.SplitBar} this
8757 * @param {Number} newSize the new width or height
8762 * Fires when the splitter is moved
8763 * @param {Roo.SplitBar} this
8764 * @param {Number} newSize the new width or height
8768 * @event beforeresize
8769 * Fires before the splitter is dragged
8770 * @param {Roo.SplitBar} this
8772 "beforeresize" : true,
8774 "beforeapply" : true
8777 Roo.util.Observable.call(this);
8780 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8781 onStartProxyDrag : function(x, y){
8782 this.fireEvent("beforeresize", this);
8784 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8786 o.enableDisplayMode("block");
8787 // all splitbars share the same overlay
8788 Roo.SplitBar.prototype.overlay = o;
8790 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8791 this.overlay.show();
8792 Roo.get(this.proxy).setDisplayed("block");
8793 var size = this.adapter.getElementSize(this);
8794 this.activeMinSize = this.getMinimumSize();;
8795 this.activeMaxSize = this.getMaximumSize();;
8796 var c1 = size - this.activeMinSize;
8797 var c2 = Math.max(this.activeMaxSize - size, 0);
8798 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8799 this.dd.resetConstraints();
8800 this.dd.setXConstraint(
8801 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8802 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8804 this.dd.setYConstraint(0, 0);
8806 this.dd.resetConstraints();
8807 this.dd.setXConstraint(0, 0);
8808 this.dd.setYConstraint(
8809 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8810 this.placement == Roo.SplitBar.TOP ? c2 : c1
8813 this.dragSpecs.startSize = size;
8814 this.dragSpecs.startPoint = [x, y];
8815 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8819 * @private Called after the drag operation by the DDProxy
8821 onEndProxyDrag : function(e){
8822 Roo.get(this.proxy).setDisplayed(false);
8823 var endPoint = Roo.lib.Event.getXY(e);
8825 this.overlay.hide();
8828 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8829 newSize = this.dragSpecs.startSize +
8830 (this.placement == Roo.SplitBar.LEFT ?
8831 endPoint[0] - this.dragSpecs.startPoint[0] :
8832 this.dragSpecs.startPoint[0] - endPoint[0]
8835 newSize = this.dragSpecs.startSize +
8836 (this.placement == Roo.SplitBar.TOP ?
8837 endPoint[1] - this.dragSpecs.startPoint[1] :
8838 this.dragSpecs.startPoint[1] - endPoint[1]
8841 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8842 if(newSize != this.dragSpecs.startSize){
8843 if(this.fireEvent('beforeapply', this, newSize) !== false){
8844 this.adapter.setElementSize(this, newSize);
8845 this.fireEvent("moved", this, newSize);
8846 this.fireEvent("resize", this, newSize);
8852 * Get the adapter this SplitBar uses
8853 * @return The adapter object
8855 getAdapter : function(){
8856 return this.adapter;
8860 * Set the adapter this SplitBar uses
8861 * @param {Object} adapter A SplitBar adapter object
8863 setAdapter : function(adapter){
8864 this.adapter = adapter;
8865 this.adapter.init(this);
8869 * Gets the minimum size for the resizing element
8870 * @return {Number} The minimum size
8872 getMinimumSize : function(){
8873 return this.minSize;
8877 * Sets the minimum size for the resizing element
8878 * @param {Number} minSize The minimum size
8880 setMinimumSize : function(minSize){
8881 this.minSize = minSize;
8885 * Gets the maximum size for the resizing element
8886 * @return {Number} The maximum size
8888 getMaximumSize : function(){
8889 return this.maxSize;
8893 * Sets the maximum size for the resizing element
8894 * @param {Number} maxSize The maximum size
8896 setMaximumSize : function(maxSize){
8897 this.maxSize = maxSize;
8901 * Sets the initialize size for the resizing element
8902 * @param {Number} size The initial size
8904 setCurrentSize : function(size){
8905 var oldAnimate = this.animate;
8906 this.animate = false;
8907 this.adapter.setElementSize(this, size);
8908 this.animate = oldAnimate;
8912 * Destroy this splitbar.
8913 * @param {Boolean} removeEl True to remove the element
8915 destroy : function(removeEl){
8920 this.proxy.parentNode.removeChild(this.proxy);
8928 * @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.
8930 Roo.SplitBar.createProxy = function(dir){
8931 var proxy = new Roo.Element(document.createElement("div"));
8932 proxy.unselectable();
8933 var cls = 'x-splitbar-proxy';
8934 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8935 document.body.appendChild(proxy.dom);
8940 * @class Roo.SplitBar.BasicLayoutAdapter
8941 * Default Adapter. It assumes the splitter and resizing element are not positioned
8942 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8944 Roo.SplitBar.BasicLayoutAdapter = function(){
8947 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8948 // do nothing for now
8953 * Called before drag operations to get the current size of the resizing element.
8954 * @param {Roo.SplitBar} s The SplitBar using this adapter
8956 getElementSize : function(s){
8957 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8958 return s.resizingEl.getWidth();
8960 return s.resizingEl.getHeight();
8965 * Called after drag operations to set the size of the resizing element.
8966 * @param {Roo.SplitBar} s The SplitBar using this adapter
8967 * @param {Number} newSize The new size to set
8968 * @param {Function} onComplete A function to be invoked when resizing is complete
8970 setElementSize : function(s, newSize, onComplete){
8971 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8973 s.resizingEl.setWidth(newSize);
8975 onComplete(s, newSize);
8978 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8983 s.resizingEl.setHeight(newSize);
8985 onComplete(s, newSize);
8988 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8995 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8996 * @extends Roo.SplitBar.BasicLayoutAdapter
8997 * Adapter that moves the splitter element to align with the resized sizing element.
8998 * Used with an absolute positioned SplitBar.
8999 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
9000 * document.body, make sure you assign an id to the body element.
9002 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
9003 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
9004 this.container = Roo.get(container);
9007 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
9012 getElementSize : function(s){
9013 return this.basic.getElementSize(s);
9016 setElementSize : function(s, newSize, onComplete){
9017 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9020 moveSplitter : function(s){
9021 var yes = Roo.SplitBar;
9022 switch(s.placement){
9024 s.el.setX(s.resizingEl.getRight());
9027 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9030 s.el.setY(s.resizingEl.getBottom());
9033 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9040 * Orientation constant - Create a vertical SplitBar
9044 Roo.SplitBar.VERTICAL = 1;
9047 * Orientation constant - Create a horizontal SplitBar
9051 Roo.SplitBar.HORIZONTAL = 2;
9054 * Placement constant - The resizing element is to the left of the splitter element
9058 Roo.SplitBar.LEFT = 1;
9061 * Placement constant - The resizing element is to the right of the splitter element
9065 Roo.SplitBar.RIGHT = 2;
9068 * Placement constant - The resizing element is positioned above the splitter element
9072 Roo.SplitBar.TOP = 3;
9075 * Placement constant - The resizing element is positioned under splitter element
9079 Roo.SplitBar.BOTTOM = 4;
9082 * Ext JS Library 1.1.1
9083 * Copyright(c) 2006-2007, Ext JS, LLC.
9085 * Originally Released Under LGPL - original licence link has changed is not relivant.
9088 * <script type="text/javascript">
9093 * @extends Roo.util.Observable
9094 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9095 * This class also supports single and multi selection modes. <br>
9096 * Create a data model bound view:
9098 var store = new Roo.data.Store(...);
9100 var view = new Roo.View({
9102 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9105 selectedClass: "ydataview-selected",
9109 // listen for node click?
9110 view.on("click", function(vw, index, node, e){
9111 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9115 dataModel.load("foobar.xml");
9117 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9119 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9120 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9122 * Note: old style constructor is still suported (container, template, config)
9126 * @param {Object} config The config object
9129 Roo.View = function(config, depreciated_tpl, depreciated_config){
9131 if (typeof(depreciated_tpl) == 'undefined') {
9132 // new way.. - universal constructor.
9133 Roo.apply(this, config);
9134 this.el = Roo.get(this.el);
9137 this.el = Roo.get(config);
9138 this.tpl = depreciated_tpl;
9139 Roo.apply(this, depreciated_config);
9143 if(typeof(this.tpl) == "string"){
9144 this.tpl = new Roo.Template(this.tpl);
9146 // support xtype ctors..
9147 this.tpl = new Roo.factory(this.tpl, Roo);
9158 * @event beforeclick
9159 * Fires before a click is processed. Returns false to cancel the default action.
9160 * @param {Roo.View} this
9161 * @param {Number} index The index of the target node
9162 * @param {HTMLElement} node The target node
9163 * @param {Roo.EventObject} e The raw event object
9165 "beforeclick" : true,
9168 * Fires when a template node is clicked.
9169 * @param {Roo.View} this
9170 * @param {Number} index The index of the target node
9171 * @param {HTMLElement} node The target node
9172 * @param {Roo.EventObject} e The raw event object
9177 * Fires when a template node is double clicked.
9178 * @param {Roo.View} this
9179 * @param {Number} index The index of the target node
9180 * @param {HTMLElement} node The target node
9181 * @param {Roo.EventObject} e The raw event object
9185 * @event contextmenu
9186 * Fires when a template node is right clicked.
9187 * @param {Roo.View} this
9188 * @param {Number} index The index of the target node
9189 * @param {HTMLElement} node The target node
9190 * @param {Roo.EventObject} e The raw event object
9192 "contextmenu" : true,
9194 * @event selectionchange
9195 * Fires when the selected nodes change.
9196 * @param {Roo.View} this
9197 * @param {Array} selections Array of the selected nodes
9199 "selectionchange" : true,
9202 * @event beforeselect
9203 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9204 * @param {Roo.View} this
9205 * @param {HTMLElement} node The node to be selected
9206 * @param {Array} selections Array of currently selected nodes
9208 "beforeselect" : true
9212 "click": this.onClick,
9213 "dblclick": this.onDblClick,
9214 "contextmenu": this.onContextMenu,
9218 this.selections = [];
9220 this.cmp = new Roo.CompositeElementLite([]);
9222 this.store = Roo.factory(this.store, Roo.data);
9223 this.setStore(this.store, true);
9225 Roo.View.superclass.constructor.call(this);
9228 Roo.extend(Roo.View, Roo.util.Observable, {
9231 * @cfg {Roo.data.Store} store Data store to load data from.
9236 * @cfg {String|Roo.Element} el The container element.
9241 * @cfg {String|Roo.Template} tpl The template used by this View
9246 * @cfg {String} selectedClass The css class to add to selected nodes
9248 selectedClass : "x-view-selected",
9250 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9254 * @cfg {Boolean} multiSelect Allow multiple selection
9257 multiSelect : false,
9259 * @cfg {Boolean} singleSelect Allow single selection
9261 singleSelect: false,
9264 * Returns the element this view is bound to.
9265 * @return {Roo.Element}
9272 * Refreshes the view.
9274 refresh : function(){
9276 this.clearSelections();
9279 var records = this.store.getRange();
9280 if(records.length < 1){
9281 this.el.update(this.emptyText);
9284 for(var i = 0, len = records.length; i < len; i++){
9285 var data = this.prepareData(records[i].data, i, records[i]);
9286 html[html.length] = t.apply(data);
9288 this.el.update(html.join(""));
9289 this.nodes = this.el.dom.childNodes;
9290 this.updateIndexes(0);
9294 * Function to override to reformat the data that is sent to
9295 * the template for each node.
9296 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9297 * a JSON object for an UpdateManager bound view).
9299 prepareData : function(data){
9303 onUpdate : function(ds, record){
9304 this.clearSelections();
9305 var index = this.store.indexOf(record);
9306 var n = this.nodes[index];
9307 this.tpl.insertBefore(n, this.prepareData(record.data));
9308 n.parentNode.removeChild(n);
9309 this.updateIndexes(index, index);
9312 onAdd : function(ds, records, index){
9313 this.clearSelections();
9314 if(this.nodes.length == 0){
9318 var n = this.nodes[index];
9319 for(var i = 0, len = records.length; i < len; i++){
9320 var d = this.prepareData(records[i].data);
9322 this.tpl.insertBefore(n, d);
9324 this.tpl.append(this.el, d);
9327 this.updateIndexes(index);
9330 onRemove : function(ds, record, index){
9331 this.clearSelections();
9332 this.el.dom.removeChild(this.nodes[index]);
9333 this.updateIndexes(index);
9337 * Refresh an individual node.
9338 * @param {Number} index
9340 refreshNode : function(index){
9341 this.onUpdate(this.store, this.store.getAt(index));
9344 updateIndexes : function(startIndex, endIndex){
9345 var ns = this.nodes;
9346 startIndex = startIndex || 0;
9347 endIndex = endIndex || ns.length - 1;
9348 for(var i = startIndex; i <= endIndex; i++){
9349 ns[i].nodeIndex = i;
9354 * Changes the data store this view uses and refresh the view.
9355 * @param {Store} store
9357 setStore : function(store, initial){
9358 if(!initial && this.store){
9359 this.store.un("datachanged", this.refresh);
9360 this.store.un("add", this.onAdd);
9361 this.store.un("remove", this.onRemove);
9362 this.store.un("update", this.onUpdate);
9363 this.store.un("clear", this.refresh);
9367 store.on("datachanged", this.refresh, this);
9368 store.on("add", this.onAdd, this);
9369 store.on("remove", this.onRemove, this);
9370 store.on("update", this.onUpdate, this);
9371 store.on("clear", this.refresh, this);
9380 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9381 * @param {HTMLElement} node
9382 * @return {HTMLElement} The template node
9384 findItemFromChild : function(node){
9385 var el = this.el.dom;
9386 if(!node || node.parentNode == el){
9389 var p = node.parentNode;
9390 while(p && p != el){
9391 if(p.parentNode == el){
9400 onClick : function(e){
9401 var item = this.findItemFromChild(e.getTarget());
9403 var index = this.indexOf(item);
9404 if(this.onItemClick(item, index, e) !== false){
9405 this.fireEvent("click", this, index, item, e);
9408 this.clearSelections();
9413 onContextMenu : function(e){
9414 var item = this.findItemFromChild(e.getTarget());
9416 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9421 onDblClick : function(e){
9422 var item = this.findItemFromChild(e.getTarget());
9424 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9428 onItemClick : function(item, index, e){
9429 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9432 if(this.multiSelect || this.singleSelect){
9433 if(this.multiSelect && e.shiftKey && this.lastSelection){
9434 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9436 this.select(item, this.multiSelect && e.ctrlKey);
9437 this.lastSelection = item;
9445 * Get the number of selected nodes.
9448 getSelectionCount : function(){
9449 return this.selections.length;
9453 * Get the currently selected nodes.
9454 * @return {Array} An array of HTMLElements
9456 getSelectedNodes : function(){
9457 return this.selections;
9461 * Get the indexes of the selected nodes.
9464 getSelectedIndexes : function(){
9465 var indexes = [], s = this.selections;
9466 for(var i = 0, len = s.length; i < len; i++){
9467 indexes.push(s[i].nodeIndex);
9473 * Clear all selections
9474 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9476 clearSelections : function(suppressEvent){
9477 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9478 this.cmp.elements = this.selections;
9479 this.cmp.removeClass(this.selectedClass);
9480 this.selections = [];
9482 this.fireEvent("selectionchange", this, this.selections);
9488 * Returns true if the passed node is selected
9489 * @param {HTMLElement/Number} node The node or node index
9492 isSelected : function(node){
9493 var s = this.selections;
9497 node = this.getNode(node);
9498 return s.indexOf(node) !== -1;
9503 * @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
9504 * @param {Boolean} keepExisting (optional) true to keep existing selections
9505 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9507 select : function(nodeInfo, keepExisting, suppressEvent){
9508 if(nodeInfo instanceof Array){
9510 this.clearSelections(true);
9512 for(var i = 0, len = nodeInfo.length; i < len; i++){
9513 this.select(nodeInfo[i], true, true);
9516 var node = this.getNode(nodeInfo);
9517 if(node && !this.isSelected(node)){
9519 this.clearSelections(true);
9521 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9522 Roo.fly(node).addClass(this.selectedClass);
9523 this.selections.push(node);
9525 this.fireEvent("selectionchange", this, this.selections);
9533 * Gets a template node.
9534 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9535 * @return {HTMLElement} The node or null if it wasn't found
9537 getNode : function(nodeInfo){
9538 if(typeof nodeInfo == "string"){
9539 return document.getElementById(nodeInfo);
9540 }else if(typeof nodeInfo == "number"){
9541 return this.nodes[nodeInfo];
9547 * Gets a range template nodes.
9548 * @param {Number} startIndex
9549 * @param {Number} endIndex
9550 * @return {Array} An array of nodes
9552 getNodes : function(start, end){
9553 var ns = this.nodes;
9555 end = typeof end == "undefined" ? ns.length - 1 : end;
9558 for(var i = start; i <= end; i++){
9562 for(var i = start; i >= end; i--){
9570 * Finds the index of the passed node
9571 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9572 * @return {Number} The index of the node or -1
9574 indexOf : function(node){
9575 node = this.getNode(node);
9576 if(typeof node.nodeIndex == "number"){
9577 return node.nodeIndex;
9579 var ns = this.nodes;
9580 for(var i = 0, len = ns.length; i < len; i++){
9590 * Ext JS Library 1.1.1
9591 * Copyright(c) 2006-2007, Ext JS, LLC.
9593 * Originally Released Under LGPL - original licence link has changed is not relivant.
9596 * <script type="text/javascript">
9600 * @class Roo.JsonView
9602 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9604 var view = new Roo.JsonView({
9605 container: "my-element",
9606 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9611 // listen for node click?
9612 view.on("click", function(vw, index, node, e){
9613 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9616 // direct load of JSON data
9617 view.load("foobar.php");
9619 // Example from my blog list
9620 var tpl = new Roo.Template(
9621 '<div class="entry">' +
9622 '<a class="entry-title" href="{link}">{title}</a>' +
9623 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9624 "</div><hr />"
9627 var moreView = new Roo.JsonView({
9628 container : "entry-list",
9632 moreView.on("beforerender", this.sortEntries, this);
9634 url: "/blog/get-posts.php",
9635 params: "allposts=true",
9636 text: "Loading Blog Entries..."
9640 * Note: old code is supported with arguments : (container, template, config)
9644 * Create a new JsonView
9646 * @param {Object} config The config object
9649 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9652 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9654 var um = this.el.getUpdateManager();
9655 um.setRenderer(this);
9656 um.on("update", this.onLoad, this);
9657 um.on("failure", this.onLoadException, this);
9660 * @event beforerender
9661 * Fires before rendering of the downloaded JSON data.
9662 * @param {Roo.JsonView} this
9663 * @param {Object} data The JSON data loaded
9667 * Fires when data is loaded.
9668 * @param {Roo.JsonView} this
9669 * @param {Object} data The JSON data loaded
9670 * @param {Object} response The raw Connect response object
9673 * @event loadexception
9674 * Fires when loading fails.
9675 * @param {Roo.JsonView} this
9676 * @param {Object} response The raw Connect response object
9679 'beforerender' : true,
9681 'loadexception' : true
9684 Roo.extend(Roo.JsonView, Roo.View, {
9686 * @type {String} The root property in the loaded JSON object that contains the data
9691 * Refreshes the view.
9693 refresh : function(){
9694 this.clearSelections();
9697 var o = this.jsonData;
9698 if(o && o.length > 0){
9699 for(var i = 0, len = o.length; i < len; i++){
9700 var data = this.prepareData(o[i], i, o);
9701 html[html.length] = this.tpl.apply(data);
9704 html.push(this.emptyText);
9706 this.el.update(html.join(""));
9707 this.nodes = this.el.dom.childNodes;
9708 this.updateIndexes(0);
9712 * 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.
9713 * @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:
9716 url: "your-url.php",
9717 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9718 callback: yourFunction,
9719 scope: yourObject, //(optional scope)
9727 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9728 * 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.
9729 * @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}
9730 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9731 * @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.
9734 var um = this.el.getUpdateManager();
9735 um.update.apply(um, arguments);
9738 render : function(el, response){
9739 this.clearSelections();
9743 o = Roo.util.JSON.decode(response.responseText);
9746 o = o[this.jsonRoot];
9751 * The current JSON data or null
9754 this.beforeRender();
9759 * Get the number of records in the current JSON dataset
9762 getCount : function(){
9763 return this.jsonData ? this.jsonData.length : 0;
9767 * Returns the JSON object for the specified node(s)
9768 * @param {HTMLElement/Array} node The node or an array of nodes
9769 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9770 * you get the JSON object for the node
9772 getNodeData : function(node){
9773 if(node instanceof Array){
9775 for(var i = 0, len = node.length; i < len; i++){
9776 data.push(this.getNodeData(node[i]));
9780 return this.jsonData[this.indexOf(node)] || null;
9783 beforeRender : function(){
9784 this.snapshot = this.jsonData;
9786 this.sort.apply(this, this.sortInfo);
9788 this.fireEvent("beforerender", this, this.jsonData);
9791 onLoad : function(el, o){
9792 this.fireEvent("load", this, this.jsonData, o);
9795 onLoadException : function(el, o){
9796 this.fireEvent("loadexception", this, o);
9800 * Filter the data by a specific property.
9801 * @param {String} property A property on your JSON objects
9802 * @param {String/RegExp} value Either string that the property values
9803 * should start with, or a RegExp to test against the property
9805 filter : function(property, value){
9808 var ss = this.snapshot;
9809 if(typeof value == "string"){
9810 var vlen = value.length;
9815 value = value.toLowerCase();
9816 for(var i = 0, len = ss.length; i < len; i++){
9818 if(o[property].substr(0, vlen).toLowerCase() == value){
9822 } else if(value.exec){ // regex?
9823 for(var i = 0, len = ss.length; i < len; i++){
9825 if(value.test(o[property])){
9832 this.jsonData = data;
9838 * Filter by a function. The passed function will be called with each
9839 * object in the current dataset. If the function returns true the value is kept,
9840 * otherwise it is filtered.
9841 * @param {Function} fn
9842 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9844 filterBy : function(fn, scope){
9847 var ss = this.snapshot;
9848 for(var i = 0, len = ss.length; i < len; i++){
9850 if(fn.call(scope || this, o)){
9854 this.jsonData = data;
9860 * Clears the current filter.
9862 clearFilter : function(){
9863 if(this.snapshot && this.jsonData != this.snapshot){
9864 this.jsonData = this.snapshot;
9871 * Sorts the data for this view and refreshes it.
9872 * @param {String} property A property on your JSON objects to sort on
9873 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9874 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9876 sort : function(property, dir, sortType){
9877 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9880 var dsc = dir && dir.toLowerCase() == "desc";
9881 var f = function(o1, o2){
9882 var v1 = sortType ? sortType(o1[p]) : o1[p];
9883 var v2 = sortType ? sortType(o2[p]) : o2[p];
9886 return dsc ? +1 : -1;
9888 return dsc ? -1 : +1;
9893 this.jsonData.sort(f);
9895 if(this.jsonData != this.snapshot){
9896 this.snapshot.sort(f);
9902 * Ext JS Library 1.1.1
9903 * Copyright(c) 2006-2007, Ext JS, LLC.
9905 * Originally Released Under LGPL - original licence link has changed is not relivant.
9908 * <script type="text/javascript">
9913 * @class Roo.ColorPalette
9914 * @extends Roo.Component
9915 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9916 * Here's an example of typical usage:
9918 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9919 cp.render('my-div');
9921 cp.on('select', function(palette, selColor){
9922 // do something with selColor
9926 * Create a new ColorPalette
9927 * @param {Object} config The config object
9929 Roo.ColorPalette = function(config){
9930 Roo.ColorPalette.superclass.constructor.call(this, config);
9934 * Fires when a color is selected
9935 * @param {ColorPalette} this
9936 * @param {String} color The 6-digit color hex code (without the # symbol)
9942 this.on("select", this.handler, this.scope, true);
9945 Roo.extend(Roo.ColorPalette, Roo.Component, {
9947 * @cfg {String} itemCls
9948 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9950 itemCls : "x-color-palette",
9952 * @cfg {String} value
9953 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9954 * the hex codes are case-sensitive.
9959 ctype: "Roo.ColorPalette",
9962 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9964 allowReselect : false,
9967 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9968 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9969 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9970 * of colors with the width setting until the box is symmetrical.</p>
9971 * <p>You can override individual colors if needed:</p>
9973 var cp = new Roo.ColorPalette();
9974 cp.colors[0] = "FF0000"; // change the first box to red
9977 Or you can provide a custom array of your own for complete control:
9979 var cp = new Roo.ColorPalette();
9980 cp.colors = ["000000", "993300", "333300"];
9985 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9986 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9987 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9988 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9989 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9993 onRender : function(container, position){
9994 var t = new Roo.MasterTemplate(
9995 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9997 var c = this.colors;
9998 for(var i = 0, len = c.length; i < len; i++){
10001 var el = document.createElement("div");
10002 el.className = this.itemCls;
10004 container.dom.insertBefore(el, position);
10005 this.el = Roo.get(el);
10006 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
10007 if(this.clickEvent != 'click'){
10008 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
10013 afterRender : function(){
10014 Roo.ColorPalette.superclass.afterRender.call(this);
10016 var s = this.value;
10023 handleClick : function(e, t){
10024 e.preventDefault();
10025 if(!this.disabled){
10026 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10027 this.select(c.toUpperCase());
10032 * Selects the specified color in the palette (fires the select event)
10033 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10035 select : function(color){
10036 color = color.replace("#", "");
10037 if(color != this.value || this.allowReselect){
10040 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10042 el.child("a.color-"+color).addClass("x-color-palette-sel");
10043 this.value = color;
10044 this.fireEvent("select", this, color);
10049 * Ext JS Library 1.1.1
10050 * Copyright(c) 2006-2007, Ext JS, LLC.
10052 * Originally Released Under LGPL - original licence link has changed is not relivant.
10055 * <script type="text/javascript">
10059 * @class Roo.DatePicker
10060 * @extends Roo.Component
10061 * Simple date picker class.
10063 * Create a new DatePicker
10064 * @param {Object} config The config object
10066 Roo.DatePicker = function(config){
10067 Roo.DatePicker.superclass.constructor.call(this, config);
10069 this.value = config && config.value ?
10070 config.value.clearTime() : new Date().clearTime();
10075 * Fires when a date is selected
10076 * @param {DatePicker} this
10077 * @param {Date} date The selected date
10083 this.on("select", this.handler, this.scope || this);
10085 // build the disabledDatesRE
10086 if(!this.disabledDatesRE && this.disabledDates){
10087 var dd = this.disabledDates;
10089 for(var i = 0; i < dd.length; i++){
10091 if(i != dd.length-1) re += "|";
10093 this.disabledDatesRE = new RegExp(re + ")");
10097 Roo.extend(Roo.DatePicker, Roo.Component, {
10099 * @cfg {String} todayText
10100 * The text to display on the button that selects the current date (defaults to "Today")
10102 todayText : "Today",
10104 * @cfg {String} okText
10105 * The text to display on the ok button
10107 okText : " OK ", //   to give the user extra clicking room
10109 * @cfg {String} cancelText
10110 * The text to display on the cancel button
10112 cancelText : "Cancel",
10114 * @cfg {String} todayTip
10115 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10117 todayTip : "{0} (Spacebar)",
10119 * @cfg {Date} minDate
10120 * Minimum allowable date (JavaScript date object, defaults to null)
10124 * @cfg {Date} maxDate
10125 * Maximum allowable date (JavaScript date object, defaults to null)
10129 * @cfg {String} minText
10130 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10132 minText : "This date is before the minimum date",
10134 * @cfg {String} maxText
10135 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10137 maxText : "This date is after the maximum date",
10139 * @cfg {String} format
10140 * The default date format string which can be overriden for localization support. The format must be
10141 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10145 * @cfg {Array} disabledDays
10146 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10148 disabledDays : null,
10150 * @cfg {String} disabledDaysText
10151 * The tooltip to display when the date falls on a disabled day (defaults to "")
10153 disabledDaysText : "",
10155 * @cfg {RegExp} disabledDatesRE
10156 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10158 disabledDatesRE : null,
10160 * @cfg {String} disabledDatesText
10161 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10163 disabledDatesText : "",
10165 * @cfg {Boolean} constrainToViewport
10166 * True to constrain the date picker to the viewport (defaults to true)
10168 constrainToViewport : true,
10170 * @cfg {Array} monthNames
10171 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10173 monthNames : Date.monthNames,
10175 * @cfg {Array} dayNames
10176 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10178 dayNames : Date.dayNames,
10180 * @cfg {String} nextText
10181 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10183 nextText: 'Next Month (Control+Right)',
10185 * @cfg {String} prevText
10186 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10188 prevText: 'Previous Month (Control+Left)',
10190 * @cfg {String} monthYearText
10191 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10193 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10195 * @cfg {Number} startDay
10196 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10200 * @cfg {Bool} showClear
10201 * Show a clear button (usefull for date form elements that can be blank.)
10207 * Sets the value of the date field
10208 * @param {Date} value The date to set
10210 setValue : function(value){
10211 var old = this.value;
10212 this.value = value.clearTime(true);
10214 this.update(this.value);
10219 * Gets the current selected value of the date field
10220 * @return {Date} The selected date
10222 getValue : function(){
10227 focus : function(){
10229 this.update(this.activeDate);
10234 onRender : function(container, position){
10236 '<table cellspacing="0">',
10237 '<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>',
10238 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10239 var dn = this.dayNames;
10240 for(var i = 0; i < 7; i++){
10241 var d = this.startDay+i;
10245 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10247 m[m.length] = "</tr></thead><tbody><tr>";
10248 for(var i = 0; i < 42; i++) {
10249 if(i % 7 == 0 && i != 0){
10250 m[m.length] = "</tr><tr>";
10252 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10254 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10255 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10257 var el = document.createElement("div");
10258 el.className = "x-date-picker";
10259 el.innerHTML = m.join("");
10261 container.dom.insertBefore(el, position);
10263 this.el = Roo.get(el);
10264 this.eventEl = Roo.get(el.firstChild);
10266 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10267 handler: this.showPrevMonth,
10269 preventDefault:true,
10273 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10274 handler: this.showNextMonth,
10276 preventDefault:true,
10280 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10282 this.monthPicker = this.el.down('div.x-date-mp');
10283 this.monthPicker.enableDisplayMode('block');
10285 var kn = new Roo.KeyNav(this.eventEl, {
10286 "left" : function(e){
10288 this.showPrevMonth() :
10289 this.update(this.activeDate.add("d", -1));
10292 "right" : function(e){
10294 this.showNextMonth() :
10295 this.update(this.activeDate.add("d", 1));
10298 "up" : function(e){
10300 this.showNextYear() :
10301 this.update(this.activeDate.add("d", -7));
10304 "down" : function(e){
10306 this.showPrevYear() :
10307 this.update(this.activeDate.add("d", 7));
10310 "pageUp" : function(e){
10311 this.showNextMonth();
10314 "pageDown" : function(e){
10315 this.showPrevMonth();
10318 "enter" : function(e){
10319 e.stopPropagation();
10326 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10328 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10330 this.el.unselectable();
10332 this.cells = this.el.select("table.x-date-inner tbody td");
10333 this.textNodes = this.el.query("table.x-date-inner tbody span");
10335 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10337 tooltip: this.monthYearText
10340 this.mbtn.on('click', this.showMonthPicker, this);
10341 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10344 var today = (new Date()).dateFormat(this.format);
10346 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10347 if (this.showClear) {
10348 baseTb.add( new Roo.Toolbar.Fill());
10351 text: String.format(this.todayText, today),
10352 tooltip: String.format(this.todayTip, today),
10353 handler: this.selectToday,
10357 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10360 if (this.showClear) {
10362 baseTb.add( new Roo.Toolbar.Fill());
10365 cls: 'x-btn-icon x-btn-clear',
10366 handler: function() {
10368 this.fireEvent("select", this, '');
10378 this.update(this.value);
10381 createMonthPicker : function(){
10382 if(!this.monthPicker.dom.firstChild){
10383 var buf = ['<table border="0" cellspacing="0">'];
10384 for(var i = 0; i < 6; i++){
10386 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10387 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10389 '<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>' :
10390 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10394 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10396 '</button><button type="button" class="x-date-mp-cancel">',
10398 '</button></td></tr>',
10401 this.monthPicker.update(buf.join(''));
10402 this.monthPicker.on('click', this.onMonthClick, this);
10403 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10405 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10406 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10408 this.mpMonths.each(function(m, a, i){
10411 m.dom.xmonth = 5 + Math.round(i * .5);
10413 m.dom.xmonth = Math.round((i-1) * .5);
10419 showMonthPicker : function(){
10420 this.createMonthPicker();
10421 var size = this.el.getSize();
10422 this.monthPicker.setSize(size);
10423 this.monthPicker.child('table').setSize(size);
10425 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10426 this.updateMPMonth(this.mpSelMonth);
10427 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10428 this.updateMPYear(this.mpSelYear);
10430 this.monthPicker.slideIn('t', {duration:.2});
10433 updateMPYear : function(y){
10435 var ys = this.mpYears.elements;
10436 for(var i = 1; i <= 10; i++){
10437 var td = ys[i-1], y2;
10439 y2 = y + Math.round(i * .5);
10440 td.firstChild.innerHTML = y2;
10443 y2 = y - (5-Math.round(i * .5));
10444 td.firstChild.innerHTML = y2;
10447 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10451 updateMPMonth : function(sm){
10452 this.mpMonths.each(function(m, a, i){
10453 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10457 selectMPMonth: function(m){
10461 onMonthClick : function(e, t){
10463 var el = new Roo.Element(t), pn;
10464 if(el.is('button.x-date-mp-cancel')){
10465 this.hideMonthPicker();
10467 else if(el.is('button.x-date-mp-ok')){
10468 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10469 this.hideMonthPicker();
10471 else if(pn = el.up('td.x-date-mp-month', 2)){
10472 this.mpMonths.removeClass('x-date-mp-sel');
10473 pn.addClass('x-date-mp-sel');
10474 this.mpSelMonth = pn.dom.xmonth;
10476 else if(pn = el.up('td.x-date-mp-year', 2)){
10477 this.mpYears.removeClass('x-date-mp-sel');
10478 pn.addClass('x-date-mp-sel');
10479 this.mpSelYear = pn.dom.xyear;
10481 else if(el.is('a.x-date-mp-prev')){
10482 this.updateMPYear(this.mpyear-10);
10484 else if(el.is('a.x-date-mp-next')){
10485 this.updateMPYear(this.mpyear+10);
10489 onMonthDblClick : function(e, t){
10491 var el = new Roo.Element(t), pn;
10492 if(pn = el.up('td.x-date-mp-month', 2)){
10493 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10494 this.hideMonthPicker();
10496 else if(pn = el.up('td.x-date-mp-year', 2)){
10497 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10498 this.hideMonthPicker();
10502 hideMonthPicker : function(disableAnim){
10503 if(this.monthPicker){
10504 if(disableAnim === true){
10505 this.monthPicker.hide();
10507 this.monthPicker.slideOut('t', {duration:.2});
10513 showPrevMonth : function(e){
10514 this.update(this.activeDate.add("mo", -1));
10518 showNextMonth : function(e){
10519 this.update(this.activeDate.add("mo", 1));
10523 showPrevYear : function(){
10524 this.update(this.activeDate.add("y", -1));
10528 showNextYear : function(){
10529 this.update(this.activeDate.add("y", 1));
10533 handleMouseWheel : function(e){
10534 var delta = e.getWheelDelta();
10536 this.showPrevMonth();
10538 } else if(delta < 0){
10539 this.showNextMonth();
10545 handleDateClick : function(e, t){
10547 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10548 this.setValue(new Date(t.dateValue));
10549 this.fireEvent("select", this, this.value);
10554 selectToday : function(){
10555 this.setValue(new Date().clearTime());
10556 this.fireEvent("select", this, this.value);
10560 update : function(date){
10561 var vd = this.activeDate;
10562 this.activeDate = date;
10564 var t = date.getTime();
10565 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10566 this.cells.removeClass("x-date-selected");
10567 this.cells.each(function(c){
10568 if(c.dom.firstChild.dateValue == t){
10569 c.addClass("x-date-selected");
10570 setTimeout(function(){
10571 try{c.dom.firstChild.focus();}catch(e){}
10579 var days = date.getDaysInMonth();
10580 var firstOfMonth = date.getFirstDateOfMonth();
10581 var startingPos = firstOfMonth.getDay()-this.startDay;
10583 if(startingPos <= this.startDay){
10587 var pm = date.add("mo", -1);
10588 var prevStart = pm.getDaysInMonth()-startingPos;
10590 var cells = this.cells.elements;
10591 var textEls = this.textNodes;
10592 days += startingPos;
10594 // convert everything to numbers so it's fast
10595 var day = 86400000;
10596 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10597 var today = new Date().clearTime().getTime();
10598 var sel = date.clearTime().getTime();
10599 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10600 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10601 var ddMatch = this.disabledDatesRE;
10602 var ddText = this.disabledDatesText;
10603 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10604 var ddaysText = this.disabledDaysText;
10605 var format = this.format;
10607 var setCellClass = function(cal, cell){
10609 var t = d.getTime();
10610 cell.firstChild.dateValue = t;
10612 cell.className += " x-date-today";
10613 cell.title = cal.todayText;
10616 cell.className += " x-date-selected";
10617 setTimeout(function(){
10618 try{cell.firstChild.focus();}catch(e){}
10623 cell.className = " x-date-disabled";
10624 cell.title = cal.minText;
10628 cell.className = " x-date-disabled";
10629 cell.title = cal.maxText;
10633 if(ddays.indexOf(d.getDay()) != -1){
10634 cell.title = ddaysText;
10635 cell.className = " x-date-disabled";
10638 if(ddMatch && format){
10639 var fvalue = d.dateFormat(format);
10640 if(ddMatch.test(fvalue)){
10641 cell.title = ddText.replace("%0", fvalue);
10642 cell.className = " x-date-disabled";
10648 for(; i < startingPos; i++) {
10649 textEls[i].innerHTML = (++prevStart);
10650 d.setDate(d.getDate()+1);
10651 cells[i].className = "x-date-prevday";
10652 setCellClass(this, cells[i]);
10654 for(; i < days; i++){
10655 intDay = i - startingPos + 1;
10656 textEls[i].innerHTML = (intDay);
10657 d.setDate(d.getDate()+1);
10658 cells[i].className = "x-date-active";
10659 setCellClass(this, cells[i]);
10662 for(; i < 42; i++) {
10663 textEls[i].innerHTML = (++extraDays);
10664 d.setDate(d.getDate()+1);
10665 cells[i].className = "x-date-nextday";
10666 setCellClass(this, cells[i]);
10669 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10671 if(!this.internalRender){
10672 var main = this.el.dom.firstChild;
10673 var w = main.offsetWidth;
10674 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10675 Roo.fly(main).setWidth(w);
10676 this.internalRender = true;
10677 // opera does not respect the auto grow header center column
10678 // then, after it gets a width opera refuses to recalculate
10679 // without a second pass
10680 if(Roo.isOpera && !this.secondPass){
10681 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10682 this.secondPass = true;
10683 this.update.defer(10, this, [date]);
10689 * Ext JS Library 1.1.1
10690 * Copyright(c) 2006-2007, Ext JS, LLC.
10692 * Originally Released Under LGPL - original licence link has changed is not relivant.
10695 * <script type="text/javascript">
10698 * @class Roo.TabPanel
10699 * @extends Roo.util.Observable
10700 * A lightweight tab container.
10704 // basic tabs 1, built from existing content
10705 var tabs = new Roo.TabPanel("tabs1");
10706 tabs.addTab("script", "View Script");
10707 tabs.addTab("markup", "View Markup");
10708 tabs.activate("script");
10710 // more advanced tabs, built from javascript
10711 var jtabs = new Roo.TabPanel("jtabs");
10712 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10714 // set up the UpdateManager
10715 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10716 var updater = tab2.getUpdateManager();
10717 updater.setDefaultUrl("ajax1.htm");
10718 tab2.on('activate', updater.refresh, updater, true);
10720 // Use setUrl for Ajax loading
10721 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10722 tab3.setUrl("ajax2.htm", null, true);
10725 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10728 jtabs.activate("jtabs-1");
10731 * Create a new TabPanel.
10732 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10733 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10735 Roo.TabPanel = function(container, config){
10737 * The container element for this TabPanel.
10738 * @type Roo.Element
10740 this.el = Roo.get(container, true);
10742 if(typeof config == "boolean"){
10743 this.tabPosition = config ? "bottom" : "top";
10745 Roo.apply(this, config);
10748 if(this.tabPosition == "bottom"){
10749 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10750 this.el.addClass("x-tabs-bottom");
10752 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10753 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10754 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10756 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10758 if(this.tabPosition != "bottom"){
10759 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10760 * @type Roo.Element
10762 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10763 this.el.addClass("x-tabs-top");
10767 this.bodyEl.setStyle("position", "relative");
10769 this.active = null;
10770 this.activateDelegate = this.activate.createDelegate(this);
10775 * Fires when the active tab changes
10776 * @param {Roo.TabPanel} this
10777 * @param {Roo.TabPanelItem} activePanel The new active tab
10781 * @event beforetabchange
10782 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10783 * @param {Roo.TabPanel} this
10784 * @param {Object} e Set cancel to true on this object to cancel the tab change
10785 * @param {Roo.TabPanelItem} tab The tab being changed to
10787 "beforetabchange" : true
10790 Roo.EventManager.onWindowResize(this.onResize, this);
10791 this.cpad = this.el.getPadding("lr");
10792 this.hiddenCount = 0;
10794 Roo.TabPanel.superclass.constructor.call(this);
10797 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10799 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10801 tabPosition : "top",
10803 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10805 currentTabWidth : 0,
10807 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10811 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10815 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10817 preferredTabWidth : 175,
10819 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10821 resizeTabs : false,
10823 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10825 monitorResize : true,
10828 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10829 * @param {String} id The id of the div to use <b>or create</b>
10830 * @param {String} text The text for the tab
10831 * @param {String} content (optional) Content to put in the TabPanelItem body
10832 * @param {Boolean} closable (optional) True to create a close icon on the tab
10833 * @return {Roo.TabPanelItem} The created TabPanelItem
10835 addTab : function(id, text, content, closable){
10836 var item = new Roo.TabPanelItem(this, id, text, closable);
10837 this.addTabItem(item);
10839 item.setContent(content);
10845 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10846 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10847 * @return {Roo.TabPanelItem}
10849 getTab : function(id){
10850 return this.items[id];
10854 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10855 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10857 hideTab : function(id){
10858 var t = this.items[id];
10861 this.hiddenCount++;
10862 this.autoSizeTabs();
10867 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10868 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10870 unhideTab : function(id){
10871 var t = this.items[id];
10873 t.setHidden(false);
10874 this.hiddenCount--;
10875 this.autoSizeTabs();
10880 * Adds an existing {@link Roo.TabPanelItem}.
10881 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10883 addTabItem : function(item){
10884 this.items[item.id] = item;
10885 this.items.push(item);
10886 if(this.resizeTabs){
10887 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10888 this.autoSizeTabs();
10895 * Removes a {@link Roo.TabPanelItem}.
10896 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10898 removeTab : function(id){
10899 var items = this.items;
10900 var tab = items[id];
10901 if(!tab) { return; }
10902 var index = items.indexOf(tab);
10903 if(this.active == tab && items.length > 1){
10904 var newTab = this.getNextAvailable(index);
10909 this.stripEl.dom.removeChild(tab.pnode.dom);
10910 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10911 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10913 items.splice(index, 1);
10914 delete this.items[tab.id];
10915 tab.fireEvent("close", tab);
10916 tab.purgeListeners();
10917 this.autoSizeTabs();
10920 getNextAvailable : function(start){
10921 var items = this.items;
10923 // look for a next tab that will slide over to
10924 // replace the one being removed
10925 while(index < items.length){
10926 var item = items[++index];
10927 if(item && !item.isHidden()){
10931 // if one isn't found select the previous tab (on the left)
10934 var item = items[--index];
10935 if(item && !item.isHidden()){
10943 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10944 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10946 disableTab : function(id){
10947 var tab = this.items[id];
10948 if(tab && this.active != tab){
10954 * Enables a {@link Roo.TabPanelItem} that is disabled.
10955 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10957 enableTab : function(id){
10958 var tab = this.items[id];
10963 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10964 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10965 * @return {Roo.TabPanelItem} The TabPanelItem.
10967 activate : function(id){
10968 var tab = this.items[id];
10972 if(tab == this.active || tab.disabled){
10976 this.fireEvent("beforetabchange", this, e, tab);
10977 if(e.cancel !== true && !tab.disabled){
10979 this.active.hide();
10981 this.active = this.items[id];
10982 this.active.show();
10983 this.fireEvent("tabchange", this, this.active);
10989 * Gets the active {@link Roo.TabPanelItem}.
10990 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10992 getActiveTab : function(){
10993 return this.active;
10997 * Updates the tab body element to fit the height of the container element
10998 * for overflow scrolling
10999 * @param {Number} targetHeight (optional) Override the starting height from the elements height
11001 syncHeight : function(targetHeight){
11002 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
11003 var bm = this.bodyEl.getMargins();
11004 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
11005 this.bodyEl.setHeight(newHeight);
11009 onResize : function(){
11010 if(this.monitorResize){
11011 this.autoSizeTabs();
11016 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11018 beginUpdate : function(){
11019 this.updating = true;
11023 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11025 endUpdate : function(){
11026 this.updating = false;
11027 this.autoSizeTabs();
11031 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11033 autoSizeTabs : function(){
11034 var count = this.items.length;
11035 var vcount = count - this.hiddenCount;
11036 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11037 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11038 var availWidth = Math.floor(w / vcount);
11039 var b = this.stripBody;
11040 if(b.getWidth() > w){
11041 var tabs = this.items;
11042 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11043 if(availWidth < this.minTabWidth){
11044 /*if(!this.sleft){ // incomplete scrolling code
11045 this.createScrollButtons();
11048 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11051 if(this.currentTabWidth < this.preferredTabWidth){
11052 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11058 * Returns the number of tabs in this TabPanel.
11061 getCount : function(){
11062 return this.items.length;
11066 * Resizes all the tabs to the passed width
11067 * @param {Number} The new width
11069 setTabWidth : function(width){
11070 this.currentTabWidth = width;
11071 for(var i = 0, len = this.items.length; i < len; i++) {
11072 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11077 * Destroys this TabPanel
11078 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11080 destroy : function(removeEl){
11081 Roo.EventManager.removeResizeListener(this.onResize, this);
11082 for(var i = 0, len = this.items.length; i < len; i++){
11083 this.items[i].purgeListeners();
11085 if(removeEl === true){
11086 this.el.update("");
11093 * @class Roo.TabPanelItem
11094 * @extends Roo.util.Observable
11095 * Represents an individual item (tab plus body) in a TabPanel.
11096 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11097 * @param {String} id The id of this TabPanelItem
11098 * @param {String} text The text for the tab of this TabPanelItem
11099 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11101 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11103 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11104 * @type Roo.TabPanel
11106 this.tabPanel = tabPanel;
11108 * The id for this TabPanelItem
11113 this.disabled = false;
11117 this.loaded = false;
11118 this.closable = closable;
11121 * The body element for this TabPanelItem.
11122 * @type Roo.Element
11124 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11125 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11126 this.bodyEl.setStyle("display", "block");
11127 this.bodyEl.setStyle("zoom", "1");
11130 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11132 this.el = Roo.get(els.el, true);
11133 this.inner = Roo.get(els.inner, true);
11134 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11135 this.pnode = Roo.get(els.el.parentNode, true);
11136 this.el.on("mousedown", this.onTabMouseDown, this);
11137 this.el.on("click", this.onTabClick, this);
11140 var c = Roo.get(els.close, true);
11141 c.dom.title = this.closeText;
11142 c.addClassOnOver("close-over");
11143 c.on("click", this.closeClick, this);
11149 * Fires when this tab becomes the active tab.
11150 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11151 * @param {Roo.TabPanelItem} this
11155 * @event beforeclose
11156 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11157 * @param {Roo.TabPanelItem} this
11158 * @param {Object} e Set cancel to true on this object to cancel the close.
11160 "beforeclose": true,
11163 * Fires when this tab is closed.
11164 * @param {Roo.TabPanelItem} this
11168 * @event deactivate
11169 * Fires when this tab is no longer the active tab.
11170 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11171 * @param {Roo.TabPanelItem} this
11173 "deactivate" : true
11175 this.hidden = false;
11177 Roo.TabPanelItem.superclass.constructor.call(this);
11180 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11181 purgeListeners : function(){
11182 Roo.util.Observable.prototype.purgeListeners.call(this);
11183 this.el.removeAllListeners();
11186 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11189 this.pnode.addClass("on");
11192 this.tabPanel.stripWrap.repaint();
11194 this.fireEvent("activate", this.tabPanel, this);
11198 * Returns true if this tab is the active tab.
11199 * @return {Boolean}
11201 isActive : function(){
11202 return this.tabPanel.getActiveTab() == this;
11206 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11209 this.pnode.removeClass("on");
11211 this.fireEvent("deactivate", this.tabPanel, this);
11214 hideAction : function(){
11215 this.bodyEl.hide();
11216 this.bodyEl.setStyle("position", "absolute");
11217 this.bodyEl.setLeft("-20000px");
11218 this.bodyEl.setTop("-20000px");
11221 showAction : function(){
11222 this.bodyEl.setStyle("position", "relative");
11223 this.bodyEl.setTop("");
11224 this.bodyEl.setLeft("");
11225 this.bodyEl.show();
11229 * Set the tooltip for the tab.
11230 * @param {String} tooltip The tab's tooltip
11232 setTooltip : function(text){
11233 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11234 this.textEl.dom.qtip = text;
11235 this.textEl.dom.removeAttribute('title');
11237 this.textEl.dom.title = text;
11241 onTabClick : function(e){
11242 e.preventDefault();
11243 this.tabPanel.activate(this.id);
11246 onTabMouseDown : function(e){
11247 e.preventDefault();
11248 this.tabPanel.activate(this.id);
11251 getWidth : function(){
11252 return this.inner.getWidth();
11255 setWidth : function(width){
11256 var iwidth = width - this.pnode.getPadding("lr");
11257 this.inner.setWidth(iwidth);
11258 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11259 this.pnode.setWidth(width);
11263 * Show or hide the tab
11264 * @param {Boolean} hidden True to hide or false to show.
11266 setHidden : function(hidden){
11267 this.hidden = hidden;
11268 this.pnode.setStyle("display", hidden ? "none" : "");
11272 * Returns true if this tab is "hidden"
11273 * @return {Boolean}
11275 isHidden : function(){
11276 return this.hidden;
11280 * Returns the text for this tab
11283 getText : function(){
11287 autoSize : function(){
11288 //this.el.beginMeasure();
11289 this.textEl.setWidth(1);
11290 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11291 //this.el.endMeasure();
11295 * Sets the text for the tab (Note: this also sets the tooltip text)
11296 * @param {String} text The tab's text and tooltip
11298 setText : function(text){
11300 this.textEl.update(text);
11301 this.setTooltip(text);
11302 if(!this.tabPanel.resizeTabs){
11307 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11309 activate : function(){
11310 this.tabPanel.activate(this.id);
11314 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11316 disable : function(){
11317 if(this.tabPanel.active != this){
11318 this.disabled = true;
11319 this.pnode.addClass("disabled");
11324 * Enables this TabPanelItem if it was previously disabled.
11326 enable : function(){
11327 this.disabled = false;
11328 this.pnode.removeClass("disabled");
11332 * Sets the content for this TabPanelItem.
11333 * @param {String} content The content
11334 * @param {Boolean} loadScripts true to look for and load scripts
11336 setContent : function(content, loadScripts){
11337 this.bodyEl.update(content, loadScripts);
11341 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11342 * @return {Roo.UpdateManager} The UpdateManager
11344 getUpdateManager : function(){
11345 return this.bodyEl.getUpdateManager();
11349 * Set a URL to be used to load the content for this TabPanelItem.
11350 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11351 * @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)
11352 * @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)
11353 * @return {Roo.UpdateManager} The UpdateManager
11355 setUrl : function(url, params, loadOnce){
11356 if(this.refreshDelegate){
11357 this.un('activate', this.refreshDelegate);
11359 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11360 this.on("activate", this.refreshDelegate);
11361 return this.bodyEl.getUpdateManager();
11365 _handleRefresh : function(url, params, loadOnce){
11366 if(!loadOnce || !this.loaded){
11367 var updater = this.bodyEl.getUpdateManager();
11368 updater.update(url, params, this._setLoaded.createDelegate(this));
11373 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11374 * Will fail silently if the setUrl method has not been called.
11375 * This does not activate the panel, just updates its content.
11377 refresh : function(){
11378 if(this.refreshDelegate){
11379 this.loaded = false;
11380 this.refreshDelegate();
11385 _setLoaded : function(){
11386 this.loaded = true;
11390 closeClick : function(e){
11393 this.fireEvent("beforeclose", this, o);
11394 if(o.cancel !== true){
11395 this.tabPanel.removeTab(this.id);
11399 * The text displayed in the tooltip for the close icon.
11402 closeText : "Close this tab"
11406 Roo.TabPanel.prototype.createStrip = function(container){
11407 var strip = document.createElement("div");
11408 strip.className = "x-tabs-wrap";
11409 container.appendChild(strip);
11413 Roo.TabPanel.prototype.createStripList = function(strip){
11414 // div wrapper for retard IE
11415 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>';
11416 return strip.firstChild.firstChild.firstChild.firstChild;
11419 Roo.TabPanel.prototype.createBody = function(container){
11420 var body = document.createElement("div");
11421 Roo.id(body, "tab-body");
11422 Roo.fly(body).addClass("x-tabs-body");
11423 container.appendChild(body);
11427 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11428 var body = Roo.getDom(id);
11430 body = document.createElement("div");
11433 Roo.fly(body).addClass("x-tabs-item-body");
11434 bodyEl.insertBefore(body, bodyEl.firstChild);
11438 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11439 var td = document.createElement("td");
11440 stripEl.appendChild(td);
11442 td.className = "x-tabs-closable";
11443 if(!this.closeTpl){
11444 this.closeTpl = new Roo.Template(
11445 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11446 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11447 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11450 var el = this.closeTpl.overwrite(td, {"text": text});
11451 var close = el.getElementsByTagName("div")[0];
11452 var inner = el.getElementsByTagName("em")[0];
11453 return {"el": el, "close": close, "inner": inner};
11456 this.tabTpl = new Roo.Template(
11457 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11458 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11461 var el = this.tabTpl.overwrite(td, {"text": text});
11462 var inner = el.getElementsByTagName("em")[0];
11463 return {"el": el, "inner": inner};
11467 * Ext JS Library 1.1.1
11468 * Copyright(c) 2006-2007, Ext JS, LLC.
11470 * Originally Released Under LGPL - original licence link has changed is not relivant.
11473 * <script type="text/javascript">
11477 * @class Roo.Button
11478 * @extends Roo.util.Observable
11479 * Simple Button class
11480 * @cfg {String} text The button text
11481 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11482 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11483 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11484 * @cfg {Object} scope The scope of the handler
11485 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11486 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11487 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11488 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11489 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11490 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11491 applies if enableToggle = true)
11492 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11493 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11494 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11496 * Create a new button
11497 * @param {Object} config The config object
11499 Roo.Button = function(renderTo, config)
11503 renderTo = config.renderTo || false;
11506 Roo.apply(this, config);
11510 * Fires when this button is clicked
11511 * @param {Button} this
11512 * @param {EventObject} e The click event
11517 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11518 * @param {Button} this
11519 * @param {Boolean} pressed
11524 * Fires when the mouse hovers over the button
11525 * @param {Button} this
11526 * @param {Event} e The event object
11528 'mouseover' : true,
11531 * Fires when the mouse exits the button
11532 * @param {Button} this
11533 * @param {Event} e The event object
11538 * Fires when the button is rendered
11539 * @param {Button} this
11544 this.menu = Roo.menu.MenuMgr.get(this.menu);
11546 // register listeners first!! - so render can be captured..
11547 Roo.util.Observable.call(this);
11549 this.render(renderTo);
11555 Roo.extend(Roo.Button, Roo.util.Observable, {
11561 * Read-only. True if this button is hidden
11566 * Read-only. True if this button is disabled
11571 * Read-only. True if this button is pressed (only if enableToggle = true)
11577 * @cfg {Number} tabIndex
11578 * The DOM tabIndex for this button (defaults to undefined)
11580 tabIndex : undefined,
11583 * @cfg {Boolean} enableToggle
11584 * True to enable pressed/not pressed toggling (defaults to false)
11586 enableToggle: false,
11588 * @cfg {Mixed} menu
11589 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11593 * @cfg {String} menuAlign
11594 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11596 menuAlign : "tl-bl?",
11599 * @cfg {String} iconCls
11600 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11602 iconCls : undefined,
11604 * @cfg {String} type
11605 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11610 menuClassTarget: 'tr',
11613 * @cfg {String} clickEvent
11614 * The type of event to map to the button's event handler (defaults to 'click')
11616 clickEvent : 'click',
11619 * @cfg {Boolean} handleMouseEvents
11620 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11622 handleMouseEvents : true,
11625 * @cfg {String} tooltipType
11626 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11628 tooltipType : 'qtip',
11631 * @cfg {String} cls
11632 * A CSS class to apply to the button's main element.
11636 * @cfg {Roo.Template} template (Optional)
11637 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11638 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11639 * require code modifications if required elements (e.g. a button) aren't present.
11643 render : function(renderTo){
11645 if(this.hideParent){
11646 this.parentEl = Roo.get(renderTo);
11648 if(!this.dhconfig){
11649 if(!this.template){
11650 if(!Roo.Button.buttonTemplate){
11651 // hideous table template
11652 Roo.Button.buttonTemplate = new Roo.Template(
11653 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11654 '<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>',
11655 "</tr></tbody></table>");
11657 this.template = Roo.Button.buttonTemplate;
11659 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11660 var btnEl = btn.child("button:first");
11661 btnEl.on('focus', this.onFocus, this);
11662 btnEl.on('blur', this.onBlur, this);
11664 btn.addClass(this.cls);
11667 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11670 btnEl.addClass(this.iconCls);
11672 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11675 if(this.tabIndex !== undefined){
11676 btnEl.dom.tabIndex = this.tabIndex;
11679 if(typeof this.tooltip == 'object'){
11680 Roo.QuickTips.tips(Roo.apply({
11684 btnEl.dom[this.tooltipType] = this.tooltip;
11688 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11692 this.el.dom.id = this.el.id = this.id;
11695 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11696 this.menu.on("show", this.onMenuShow, this);
11697 this.menu.on("hide", this.onMenuHide, this);
11699 btn.addClass("x-btn");
11700 if(Roo.isIE && !Roo.isIE7){
11701 this.autoWidth.defer(1, this);
11705 if(this.handleMouseEvents){
11706 btn.on("mouseover", this.onMouseOver, this);
11707 btn.on("mouseout", this.onMouseOut, this);
11708 btn.on("mousedown", this.onMouseDown, this);
11710 btn.on(this.clickEvent, this.onClick, this);
11711 //btn.on("mouseup", this.onMouseUp, this);
11718 Roo.ButtonToggleMgr.register(this);
11720 this.el.addClass("x-btn-pressed");
11723 var repeater = new Roo.util.ClickRepeater(btn,
11724 typeof this.repeat == "object" ? this.repeat : {}
11726 repeater.on("click", this.onClick, this);
11729 this.fireEvent('render', this);
11733 * Returns the button's underlying element
11734 * @return {Roo.Element} The element
11736 getEl : function(){
11741 * Destroys this Button and removes any listeners.
11743 destroy : function(){
11744 Roo.ButtonToggleMgr.unregister(this);
11745 this.el.removeAllListeners();
11746 this.purgeListeners();
11751 autoWidth : function(){
11753 this.el.setWidth("auto");
11754 if(Roo.isIE7 && Roo.isStrict){
11755 var ib = this.el.child('button');
11756 if(ib && ib.getWidth() > 20){
11758 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11763 this.el.beginMeasure();
11765 if(this.el.getWidth() < this.minWidth){
11766 this.el.setWidth(this.minWidth);
11769 this.el.endMeasure();
11776 * Assigns this button's click handler
11777 * @param {Function} handler The function to call when the button is clicked
11778 * @param {Object} scope (optional) Scope for the function passed in
11780 setHandler : function(handler, scope){
11781 this.handler = handler;
11782 this.scope = scope;
11786 * Sets this button's text
11787 * @param {String} text The button text
11789 setText : function(text){
11792 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11798 * Gets the text for this button
11799 * @return {String} The button text
11801 getText : function(){
11809 this.hidden = false;
11811 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11819 this.hidden = true;
11821 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11826 * Convenience function for boolean show/hide
11827 * @param {Boolean} visible True to show, false to hide
11829 setVisible: function(visible){
11838 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11839 * @param {Boolean} state (optional) Force a particular state
11841 toggle : function(state){
11842 state = state === undefined ? !this.pressed : state;
11843 if(state != this.pressed){
11845 this.el.addClass("x-btn-pressed");
11846 this.pressed = true;
11847 this.fireEvent("toggle", this, true);
11849 this.el.removeClass("x-btn-pressed");
11850 this.pressed = false;
11851 this.fireEvent("toggle", this, false);
11853 if(this.toggleHandler){
11854 this.toggleHandler.call(this.scope || this, this, state);
11862 focus : function(){
11863 this.el.child('button:first').focus();
11867 * Disable this button
11869 disable : function(){
11871 this.el.addClass("x-btn-disabled");
11873 this.disabled = true;
11877 * Enable this button
11879 enable : function(){
11881 this.el.removeClass("x-btn-disabled");
11883 this.disabled = false;
11887 * Convenience function for boolean enable/disable
11888 * @param {Boolean} enabled True to enable, false to disable
11890 setDisabled : function(v){
11891 this[v !== true ? "enable" : "disable"]();
11895 onClick : function(e){
11897 e.preventDefault();
11902 if(!this.disabled){
11903 if(this.enableToggle){
11906 if(this.menu && !this.menu.isVisible()){
11907 this.menu.show(this.el, this.menuAlign);
11909 this.fireEvent("click", this, e);
11911 this.el.removeClass("x-btn-over");
11912 this.handler.call(this.scope || this, this, e);
11917 onMouseOver : function(e){
11918 if(!this.disabled){
11919 this.el.addClass("x-btn-over");
11920 this.fireEvent('mouseover', this, e);
11924 onMouseOut : function(e){
11925 if(!e.within(this.el, true)){
11926 this.el.removeClass("x-btn-over");
11927 this.fireEvent('mouseout', this, e);
11931 onFocus : function(e){
11932 if(!this.disabled){
11933 this.el.addClass("x-btn-focus");
11937 onBlur : function(e){
11938 this.el.removeClass("x-btn-focus");
11941 onMouseDown : function(e){
11942 if(!this.disabled && e.button == 0){
11943 this.el.addClass("x-btn-click");
11944 Roo.get(document).on('mouseup', this.onMouseUp, this);
11948 onMouseUp : function(e){
11950 this.el.removeClass("x-btn-click");
11951 Roo.get(document).un('mouseup', this.onMouseUp, this);
11955 onMenuShow : function(e){
11956 this.el.addClass("x-btn-menu-active");
11959 onMenuHide : function(e){
11960 this.el.removeClass("x-btn-menu-active");
11964 // Private utility class used by Button
11965 Roo.ButtonToggleMgr = function(){
11968 function toggleGroup(btn, state){
11970 var g = groups[btn.toggleGroup];
11971 for(var i = 0, l = g.length; i < l; i++){
11973 g[i].toggle(false);
11980 register : function(btn){
11981 if(!btn.toggleGroup){
11984 var g = groups[btn.toggleGroup];
11986 g = groups[btn.toggleGroup] = [];
11989 btn.on("toggle", toggleGroup);
11992 unregister : function(btn){
11993 if(!btn.toggleGroup){
11996 var g = groups[btn.toggleGroup];
11999 btn.un("toggle", toggleGroup);
12005 * Ext JS Library 1.1.1
12006 * Copyright(c) 2006-2007, Ext JS, LLC.
12008 * Originally Released Under LGPL - original licence link has changed is not relivant.
12011 * <script type="text/javascript">
12015 * @class Roo.SplitButton
12016 * @extends Roo.Button
12017 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12018 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
12019 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12020 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12021 * @cfg {String} arrowTooltip The title attribute of the arrow
12023 * Create a new menu button
12024 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12025 * @param {Object} config The config object
12027 Roo.SplitButton = function(renderTo, config){
12028 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12030 * @event arrowclick
12031 * Fires when this button's arrow is clicked
12032 * @param {SplitButton} this
12033 * @param {EventObject} e The click event
12035 this.addEvents({"arrowclick":true});
12038 Roo.extend(Roo.SplitButton, Roo.Button, {
12039 render : function(renderTo){
12040 // this is one sweet looking template!
12041 var tpl = new Roo.Template(
12042 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12043 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12044 '<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>',
12045 "</tbody></table></td><td>",
12046 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12047 '<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>',
12048 "</tbody></table></td></tr></table>"
12050 var btn = tpl.append(renderTo, [this.text, this.type], true);
12051 var btnEl = btn.child("button");
12053 btn.addClass(this.cls);
12056 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12059 btnEl.addClass(this.iconCls);
12061 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12065 if(this.handleMouseEvents){
12066 btn.on("mouseover", this.onMouseOver, this);
12067 btn.on("mouseout", this.onMouseOut, this);
12068 btn.on("mousedown", this.onMouseDown, this);
12069 btn.on("mouseup", this.onMouseUp, this);
12071 btn.on(this.clickEvent, this.onClick, this);
12073 if(typeof this.tooltip == 'object'){
12074 Roo.QuickTips.tips(Roo.apply({
12078 btnEl.dom[this.tooltipType] = this.tooltip;
12081 if(this.arrowTooltip){
12082 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12091 this.el.addClass("x-btn-pressed");
12093 if(Roo.isIE && !Roo.isIE7){
12094 this.autoWidth.defer(1, this);
12099 this.menu.on("show", this.onMenuShow, this);
12100 this.menu.on("hide", this.onMenuHide, this);
12102 this.fireEvent('render', this);
12106 autoWidth : function(){
12108 var tbl = this.el.child("table:first");
12109 var tbl2 = this.el.child("table:last");
12110 this.el.setWidth("auto");
12111 tbl.setWidth("auto");
12112 if(Roo.isIE7 && Roo.isStrict){
12113 var ib = this.el.child('button:first');
12114 if(ib && ib.getWidth() > 20){
12116 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12121 this.el.beginMeasure();
12123 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12124 tbl.setWidth(this.minWidth-tbl2.getWidth());
12127 this.el.endMeasure();
12130 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12134 * Sets this button's click handler
12135 * @param {Function} handler The function to call when the button is clicked
12136 * @param {Object} scope (optional) Scope for the function passed above
12138 setHandler : function(handler, scope){
12139 this.handler = handler;
12140 this.scope = scope;
12144 * Sets this button's arrow click handler
12145 * @param {Function} handler The function to call when the arrow is clicked
12146 * @param {Object} scope (optional) Scope for the function passed above
12148 setArrowHandler : function(handler, scope){
12149 this.arrowHandler = handler;
12150 this.scope = scope;
12156 focus : function(){
12158 this.el.child("button:first").focus();
12163 onClick : function(e){
12164 e.preventDefault();
12165 if(!this.disabled){
12166 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12167 if(this.menu && !this.menu.isVisible()){
12168 this.menu.show(this.el, this.menuAlign);
12170 this.fireEvent("arrowclick", this, e);
12171 if(this.arrowHandler){
12172 this.arrowHandler.call(this.scope || this, this, e);
12175 this.fireEvent("click", this, e);
12177 this.handler.call(this.scope || this, this, e);
12183 onMouseDown : function(e){
12184 if(!this.disabled){
12185 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12189 onMouseUp : function(e){
12190 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12195 // backwards compat
12196 Roo.MenuButton = Roo.SplitButton;/*
12198 * Ext JS Library 1.1.1
12199 * Copyright(c) 2006-2007, Ext JS, LLC.
12201 * Originally Released Under LGPL - original licence link has changed is not relivant.
12204 * <script type="text/javascript">
12208 * @class Roo.Toolbar
12209 * Basic Toolbar class.
12211 * Creates a new Toolbar
12212 * @param {Object} config The config object
12214 Roo.Toolbar = function(container, buttons, config)
12216 /// old consturctor format still supported..
12217 if(container instanceof Array){ // omit the container for later rendering
12218 buttons = container;
12222 if (typeof(container) == 'object' && container.xtype) {
12223 config = container;
12224 container = config.container;
12225 buttons = config.buttons; // not really - use items!!
12228 if (config && config.items) {
12229 xitems = config.items;
12230 delete config.items;
12232 Roo.apply(this, config);
12233 this.buttons = buttons;
12236 this.render(container);
12238 Roo.each(xitems, function(b) {
12244 Roo.Toolbar.prototype = {
12246 * @cfg {Roo.data.Store} items
12247 * array of button configs or elements to add
12251 * @cfg {String/HTMLElement/Element} container
12252 * The id or element that will contain the toolbar
12255 render : function(ct){
12256 this.el = Roo.get(ct);
12258 this.el.addClass(this.cls);
12260 // using a table allows for vertical alignment
12261 // 100% width is needed by Safari...
12262 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12263 this.tr = this.el.child("tr", true);
12265 this.items = new Roo.util.MixedCollection(false, function(o){
12266 return o.id || ("item" + (++autoId));
12269 this.add.apply(this, this.buttons);
12270 delete this.buttons;
12275 * Adds element(s) to the toolbar -- this function takes a variable number of
12276 * arguments of mixed type and adds them to the toolbar.
12277 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12279 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12280 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12281 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12282 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12283 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12284 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12285 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12286 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12287 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12289 * @param {Mixed} arg2
12290 * @param {Mixed} etc.
12293 var a = arguments, l = a.length;
12294 for(var i = 0; i < l; i++){
12299 _add : function(el) {
12302 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12305 if (el.applyTo){ // some kind of form field
12306 return this.addField(el);
12308 if (el.render){ // some kind of Toolbar.Item
12309 return this.addItem(el);
12311 if (typeof el == "string"){ // string
12312 if(el == "separator" || el == "-"){
12313 return this.addSeparator();
12316 return this.addSpacer();
12319 return this.addFill();
12321 return this.addText(el);
12324 if(el.tagName){ // element
12325 return this.addElement(el);
12327 if(typeof el == "object"){ // must be button config?
12328 return this.addButton(el);
12330 // and now what?!?!
12336 * Add an Xtype element
12337 * @param {Object} xtype Xtype Object
12338 * @return {Object} created Object
12340 addxtype : function(e){
12341 return this.add(e);
12345 * Returns the Element for this toolbar.
12346 * @return {Roo.Element}
12348 getEl : function(){
12354 * @return {Roo.Toolbar.Item} The separator item
12356 addSeparator : function(){
12357 return this.addItem(new Roo.Toolbar.Separator());
12361 * Adds a spacer element
12362 * @return {Roo.Toolbar.Spacer} The spacer item
12364 addSpacer : function(){
12365 return this.addItem(new Roo.Toolbar.Spacer());
12369 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12370 * @return {Roo.Toolbar.Fill} The fill item
12372 addFill : function(){
12373 return this.addItem(new Roo.Toolbar.Fill());
12377 * Adds any standard HTML element to the toolbar
12378 * @param {String/HTMLElement/Element} el The element or id of the element to add
12379 * @return {Roo.Toolbar.Item} The element's item
12381 addElement : function(el){
12382 return this.addItem(new Roo.Toolbar.Item(el));
12385 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12386 * @type Roo.util.MixedCollection
12391 * Adds any Toolbar.Item or subclass
12392 * @param {Roo.Toolbar.Item} item
12393 * @return {Roo.Toolbar.Item} The item
12395 addItem : function(item){
12396 var td = this.nextBlock();
12398 this.items.add(item);
12403 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12404 * @param {Object/Array} config A button config or array of configs
12405 * @return {Roo.Toolbar.Button/Array}
12407 addButton : function(config){
12408 if(config instanceof Array){
12410 for(var i = 0, len = config.length; i < len; i++) {
12411 buttons.push(this.addButton(config[i]));
12416 if(!(config instanceof Roo.Toolbar.Button)){
12418 new Roo.Toolbar.SplitButton(config) :
12419 new Roo.Toolbar.Button(config);
12421 var td = this.nextBlock();
12428 * Adds text to the toolbar
12429 * @param {String} text The text to add
12430 * @return {Roo.Toolbar.Item} The element's item
12432 addText : function(text){
12433 return this.addItem(new Roo.Toolbar.TextItem(text));
12437 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12438 * @param {Number} index The index where the item is to be inserted
12439 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12440 * @return {Roo.Toolbar.Button/Item}
12442 insertButton : function(index, item){
12443 if(item instanceof Array){
12445 for(var i = 0, len = item.length; i < len; i++) {
12446 buttons.push(this.insertButton(index + i, item[i]));
12450 if (!(item instanceof Roo.Toolbar.Button)){
12451 item = new Roo.Toolbar.Button(item);
12453 var td = document.createElement("td");
12454 this.tr.insertBefore(td, this.tr.childNodes[index]);
12456 this.items.insert(index, item);
12461 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12462 * @param {Object} config
12463 * @return {Roo.Toolbar.Item} The element's item
12465 addDom : function(config, returnEl){
12466 var td = this.nextBlock();
12467 Roo.DomHelper.overwrite(td, config);
12468 var ti = new Roo.Toolbar.Item(td.firstChild);
12470 this.items.add(ti);
12475 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12476 * @type Roo.util.MixedCollection
12481 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12482 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12483 * @param {Roo.form.Field} field
12484 * @return {Roo.ToolbarItem}
12488 addField : function(field) {
12489 if (!this.fields) {
12491 this.fields = new Roo.util.MixedCollection(false, function(o){
12492 return o.id || ("item" + (++autoId));
12497 var td = this.nextBlock();
12499 var ti = new Roo.Toolbar.Item(td.firstChild);
12501 this.items.add(ti);
12502 this.fields.add(field);
12513 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12514 this.el.child('div').hide();
12522 this.el.child('div').show();
12526 nextBlock : function(){
12527 var td = document.createElement("td");
12528 this.tr.appendChild(td);
12533 destroy : function(){
12534 if(this.items){ // rendered?
12535 Roo.destroy.apply(Roo, this.items.items);
12537 if(this.fields){ // rendered?
12538 Roo.destroy.apply(Roo, this.fields.items);
12540 Roo.Element.uncache(this.el, this.tr);
12545 * @class Roo.Toolbar.Item
12546 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12548 * Creates a new Item
12549 * @param {HTMLElement} el
12551 Roo.Toolbar.Item = function(el){
12552 this.el = Roo.getDom(el);
12553 this.id = Roo.id(this.el);
12554 this.hidden = false;
12557 Roo.Toolbar.Item.prototype = {
12560 * Get this item's HTML Element
12561 * @return {HTMLElement}
12563 getEl : function(){
12568 render : function(td){
12570 td.appendChild(this.el);
12574 * Removes and destroys this item.
12576 destroy : function(){
12577 this.td.parentNode.removeChild(this.td);
12584 this.hidden = false;
12585 this.td.style.display = "";
12592 this.hidden = true;
12593 this.td.style.display = "none";
12597 * Convenience function for boolean show/hide.
12598 * @param {Boolean} visible true to show/false to hide
12600 setVisible: function(visible){
12609 * Try to focus this item.
12611 focus : function(){
12612 Roo.fly(this.el).focus();
12616 * Disables this item.
12618 disable : function(){
12619 Roo.fly(this.td).addClass("x-item-disabled");
12620 this.disabled = true;
12621 this.el.disabled = true;
12625 * Enables this item.
12627 enable : function(){
12628 Roo.fly(this.td).removeClass("x-item-disabled");
12629 this.disabled = false;
12630 this.el.disabled = false;
12636 * @class Roo.Toolbar.Separator
12637 * @extends Roo.Toolbar.Item
12638 * A simple toolbar separator class
12640 * Creates a new Separator
12642 Roo.Toolbar.Separator = function(){
12643 var s = document.createElement("span");
12644 s.className = "ytb-sep";
12645 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12647 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12648 enable:Roo.emptyFn,
12649 disable:Roo.emptyFn,
12654 * @class Roo.Toolbar.Spacer
12655 * @extends Roo.Toolbar.Item
12656 * A simple element that adds extra horizontal space to a toolbar.
12658 * Creates a new Spacer
12660 Roo.Toolbar.Spacer = function(){
12661 var s = document.createElement("div");
12662 s.className = "ytb-spacer";
12663 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12665 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12666 enable:Roo.emptyFn,
12667 disable:Roo.emptyFn,
12672 * @class Roo.Toolbar.Fill
12673 * @extends Roo.Toolbar.Spacer
12674 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12676 * Creates a new Spacer
12678 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12680 render : function(td){
12681 td.style.width = '100%';
12682 Roo.Toolbar.Fill.superclass.render.call(this, td);
12687 * @class Roo.Toolbar.TextItem
12688 * @extends Roo.Toolbar.Item
12689 * A simple class that renders text directly into a toolbar.
12691 * Creates a new TextItem
12692 * @param {String} text
12694 Roo.Toolbar.TextItem = function(text){
12695 if (typeof(text) == 'object') {
12698 var s = document.createElement("span");
12699 s.className = "ytb-text";
12700 s.innerHTML = text;
12701 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12703 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12704 enable:Roo.emptyFn,
12705 disable:Roo.emptyFn,
12710 * @class Roo.Toolbar.Button
12711 * @extends Roo.Button
12712 * A button that renders into a toolbar.
12714 * Creates a new Button
12715 * @param {Object} config A standard {@link Roo.Button} config object
12717 Roo.Toolbar.Button = function(config){
12718 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12720 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12721 render : function(td){
12723 Roo.Toolbar.Button.superclass.render.call(this, td);
12727 * Removes and destroys this button
12729 destroy : function(){
12730 Roo.Toolbar.Button.superclass.destroy.call(this);
12731 this.td.parentNode.removeChild(this.td);
12735 * Shows this button
12738 this.hidden = false;
12739 this.td.style.display = "";
12743 * Hides this button
12746 this.hidden = true;
12747 this.td.style.display = "none";
12751 * Disables this item
12753 disable : function(){
12754 Roo.fly(this.td).addClass("x-item-disabled");
12755 this.disabled = true;
12759 * Enables this item
12761 enable : function(){
12762 Roo.fly(this.td).removeClass("x-item-disabled");
12763 this.disabled = false;
12766 // backwards compat
12767 Roo.ToolbarButton = Roo.Toolbar.Button;
12770 * @class Roo.Toolbar.SplitButton
12771 * @extends Roo.SplitButton
12772 * A menu button that renders into a toolbar.
12774 * Creates a new SplitButton
12775 * @param {Object} config A standard {@link Roo.SplitButton} config object
12777 Roo.Toolbar.SplitButton = function(config){
12778 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12780 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12781 render : function(td){
12783 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12787 * Removes and destroys this button
12789 destroy : function(){
12790 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12791 this.td.parentNode.removeChild(this.td);
12795 * Shows this button
12798 this.hidden = false;
12799 this.td.style.display = "";
12803 * Hides this button
12806 this.hidden = true;
12807 this.td.style.display = "none";
12811 // backwards compat
12812 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12814 * Ext JS Library 1.1.1
12815 * Copyright(c) 2006-2007, Ext JS, LLC.
12817 * Originally Released Under LGPL - original licence link has changed is not relivant.
12820 * <script type="text/javascript">
12824 * @class Roo.PagingToolbar
12825 * @extends Roo.Toolbar
12826 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12828 * Create a new PagingToolbar
12829 * @param {Object} config The config object
12831 Roo.PagingToolbar = function(el, ds, config)
12833 // old args format still supported... - xtype is prefered..
12834 if (typeof(el) == 'object' && el.xtype) {
12835 // created from xtype...
12837 ds = el.dataSource;
12838 el = config.container;
12841 if (config.items) {
12842 items = config.items;
12846 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12849 this.renderButtons(this.el);
12852 // supprot items array.
12854 Roo.each(items, function(e) {
12855 this.add(Roo.factory(e));
12860 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12862 * @cfg {Roo.data.Store} dataSource
12863 * The underlying data store providing the paged data
12866 * @cfg {String/HTMLElement/Element} container
12867 * container The id or element that will contain the toolbar
12870 * @cfg {Boolean} displayInfo
12871 * True to display the displayMsg (defaults to false)
12874 * @cfg {Number} pageSize
12875 * The number of records to display per page (defaults to 20)
12879 * @cfg {String} displayMsg
12880 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12882 displayMsg : 'Displaying {0} - {1} of {2}',
12884 * @cfg {String} emptyMsg
12885 * The message to display when no records are found (defaults to "No data to display")
12887 emptyMsg : 'No data to display',
12889 * Customizable piece of the default paging text (defaults to "Page")
12892 beforePageText : "Page",
12894 * Customizable piece of the default paging text (defaults to "of %0")
12897 afterPageText : "of {0}",
12899 * Customizable piece of the default paging text (defaults to "First Page")
12902 firstText : "First Page",
12904 * Customizable piece of the default paging text (defaults to "Previous Page")
12907 prevText : "Previous Page",
12909 * Customizable piece of the default paging text (defaults to "Next Page")
12912 nextText : "Next Page",
12914 * Customizable piece of the default paging text (defaults to "Last Page")
12917 lastText : "Last Page",
12919 * Customizable piece of the default paging text (defaults to "Refresh")
12922 refreshText : "Refresh",
12925 renderButtons : function(el){
12926 Roo.PagingToolbar.superclass.render.call(this, el);
12927 this.first = this.addButton({
12928 tooltip: this.firstText,
12929 cls: "x-btn-icon x-grid-page-first",
12931 handler: this.onClick.createDelegate(this, ["first"])
12933 this.prev = this.addButton({
12934 tooltip: this.prevText,
12935 cls: "x-btn-icon x-grid-page-prev",
12937 handler: this.onClick.createDelegate(this, ["prev"])
12939 //this.addSeparator();
12940 this.add(this.beforePageText);
12941 this.field = Roo.get(this.addDom({
12946 cls: "x-grid-page-number"
12948 this.field.on("keydown", this.onPagingKeydown, this);
12949 this.field.on("focus", function(){this.dom.select();});
12950 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12951 this.field.setHeight(18);
12952 //this.addSeparator();
12953 this.next = this.addButton({
12954 tooltip: this.nextText,
12955 cls: "x-btn-icon x-grid-page-next",
12957 handler: this.onClick.createDelegate(this, ["next"])
12959 this.last = this.addButton({
12960 tooltip: this.lastText,
12961 cls: "x-btn-icon x-grid-page-last",
12963 handler: this.onClick.createDelegate(this, ["last"])
12965 //this.addSeparator();
12966 this.loading = this.addButton({
12967 tooltip: this.refreshText,
12968 cls: "x-btn-icon x-grid-loading",
12969 handler: this.onClick.createDelegate(this, ["refresh"])
12972 if(this.displayInfo){
12973 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12978 updateInfo : function(){
12979 if(this.displayEl){
12980 var count = this.ds.getCount();
12981 var msg = count == 0 ?
12985 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12987 this.displayEl.update(msg);
12992 onLoad : function(ds, r, o){
12993 this.cursor = o.params ? o.params.start : 0;
12994 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12996 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12997 this.field.dom.value = ap;
12998 this.first.setDisabled(ap == 1);
12999 this.prev.setDisabled(ap == 1);
13000 this.next.setDisabled(ap == ps);
13001 this.last.setDisabled(ap == ps);
13002 this.loading.enable();
13007 getPageData : function(){
13008 var total = this.ds.getTotalCount();
13011 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
13012 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13017 onLoadError : function(){
13018 this.loading.enable();
13022 onPagingKeydown : function(e){
13023 var k = e.getKey();
13024 var d = this.getPageData();
13026 var v = this.field.dom.value, pageNum;
13027 if(!v || isNaN(pageNum = parseInt(v, 10))){
13028 this.field.dom.value = d.activePage;
13031 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13032 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13035 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))
13037 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13038 this.field.dom.value = pageNum;
13039 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13042 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13044 var v = this.field.dom.value, pageNum;
13045 var increment = (e.shiftKey) ? 10 : 1;
13046 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13048 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13049 this.field.dom.value = d.activePage;
13052 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13054 this.field.dom.value = parseInt(v, 10) + increment;
13055 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13056 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13063 beforeLoad : function(){
13065 this.loading.disable();
13070 onClick : function(which){
13074 ds.load({params:{start: 0, limit: this.pageSize}});
13077 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13080 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13083 var total = ds.getTotalCount();
13084 var extra = total % this.pageSize;
13085 var lastStart = extra ? (total - extra) : total-this.pageSize;
13086 ds.load({params:{start: lastStart, limit: this.pageSize}});
13089 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13095 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13096 * @param {Roo.data.Store} store The data store to unbind
13098 unbind : function(ds){
13099 ds.un("beforeload", this.beforeLoad, this);
13100 ds.un("load", this.onLoad, this);
13101 ds.un("loadexception", this.onLoadError, this);
13102 ds.un("remove", this.updateInfo, this);
13103 ds.un("add", this.updateInfo, this);
13104 this.ds = undefined;
13108 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13109 * @param {Roo.data.Store} store The data store to bind
13111 bind : function(ds){
13112 ds.on("beforeload", this.beforeLoad, this);
13113 ds.on("load", this.onLoad, this);
13114 ds.on("loadexception", this.onLoadError, this);
13115 ds.on("remove", this.updateInfo, this);
13116 ds.on("add", this.updateInfo, this);
13121 * Ext JS Library 1.1.1
13122 * Copyright(c) 2006-2007, Ext JS, LLC.
13124 * Originally Released Under LGPL - original licence link has changed is not relivant.
13127 * <script type="text/javascript">
13131 * @class Roo.Resizable
13132 * @extends Roo.util.Observable
13133 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13134 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13135 * 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
13136 * the element will be wrapped for you automatically.</p>
13137 * <p>Here is the list of valid resize handles:</p>
13140 ------ -------------------
13149 'hd' horizontal drag
13152 * <p>Here's an example showing the creation of a typical Resizable:</p>
13154 var resizer = new Roo.Resizable("element-id", {
13162 resizer.on("resize", myHandler);
13164 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13165 * resizer.east.setDisplayed(false);</p>
13166 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13167 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13168 * resize operation's new size (defaults to [0, 0])
13169 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13170 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13171 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13172 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13173 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13174 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13175 * @cfg {Number} width The width of the element in pixels (defaults to null)
13176 * @cfg {Number} height The height of the element in pixels (defaults to null)
13177 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13178 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13179 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13180 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13181 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13182 * in favor of the handles config option (defaults to false)
13183 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13184 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13185 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13186 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13187 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13188 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13189 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13190 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13191 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13192 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13193 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13195 * Create a new resizable component
13196 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13197 * @param {Object} config configuration options
13199 Roo.Resizable = function(el, config)
13201 this.el = Roo.get(el);
13203 if(config && config.wrap){
13204 config.resizeChild = this.el;
13205 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13206 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13207 this.el.setStyle("overflow", "hidden");
13208 this.el.setPositioning(config.resizeChild.getPositioning());
13209 config.resizeChild.clearPositioning();
13210 if(!config.width || !config.height){
13211 var csize = config.resizeChild.getSize();
13212 this.el.setSize(csize.width, csize.height);
13214 if(config.pinned && !config.adjustments){
13215 config.adjustments = "auto";
13219 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13220 this.proxy.unselectable();
13221 this.proxy.enableDisplayMode('block');
13223 Roo.apply(this, config);
13226 this.disableTrackOver = true;
13227 this.el.addClass("x-resizable-pinned");
13229 // if the element isn't positioned, make it relative
13230 var position = this.el.getStyle("position");
13231 if(position != "absolute" && position != "fixed"){
13232 this.el.setStyle("position", "relative");
13234 if(!this.handles){ // no handles passed, must be legacy style
13235 this.handles = 's,e,se';
13236 if(this.multiDirectional){
13237 this.handles += ',n,w';
13240 if(this.handles == "all"){
13241 this.handles = "n s e w ne nw se sw";
13243 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13244 var ps = Roo.Resizable.positions;
13245 for(var i = 0, len = hs.length; i < len; i++){
13246 if(hs[i] && ps[hs[i]]){
13247 var pos = ps[hs[i]];
13248 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13252 this.corner = this.southeast;
13254 // updateBox = the box can move..
13255 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13256 this.updateBox = true;
13259 this.activeHandle = null;
13261 if(this.resizeChild){
13262 if(typeof this.resizeChild == "boolean"){
13263 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13265 this.resizeChild = Roo.get(this.resizeChild, true);
13269 if(this.adjustments == "auto"){
13270 var rc = this.resizeChild;
13271 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13272 if(rc && (hw || hn)){
13273 rc.position("relative");
13274 rc.setLeft(hw ? hw.el.getWidth() : 0);
13275 rc.setTop(hn ? hn.el.getHeight() : 0);
13277 this.adjustments = [
13278 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13279 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13283 if(this.draggable){
13284 this.dd = this.dynamic ?
13285 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13286 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13292 * @event beforeresize
13293 * Fired before resize is allowed. Set enabled to false to cancel resize.
13294 * @param {Roo.Resizable} this
13295 * @param {Roo.EventObject} e The mousedown event
13297 "beforeresize" : true,
13300 * Fired after a resize.
13301 * @param {Roo.Resizable} this
13302 * @param {Number} width The new width
13303 * @param {Number} height The new height
13304 * @param {Roo.EventObject} e The mouseup event
13309 if(this.width !== null && this.height !== null){
13310 this.resizeTo(this.width, this.height);
13312 this.updateChildSize();
13315 this.el.dom.style.zoom = 1;
13317 Roo.Resizable.superclass.constructor.call(this);
13320 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13321 resizeChild : false,
13322 adjustments : [0, 0],
13332 multiDirectional : false,
13333 disableTrackOver : false,
13334 easing : 'easeOutStrong',
13335 widthIncrement : 0,
13336 heightIncrement : 0,
13340 preserveRatio : false,
13341 transparent: false,
13347 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13349 constrainTo: undefined,
13351 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13353 resizeRegion: undefined,
13357 * Perform a manual resize
13358 * @param {Number} width
13359 * @param {Number} height
13361 resizeTo : function(width, height){
13362 this.el.setSize(width, height);
13363 this.updateChildSize();
13364 this.fireEvent("resize", this, width, height, null);
13368 startSizing : function(e, handle){
13369 this.fireEvent("beforeresize", this, e);
13370 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13373 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13374 this.overlay.unselectable();
13375 this.overlay.enableDisplayMode("block");
13376 this.overlay.on("mousemove", this.onMouseMove, this);
13377 this.overlay.on("mouseup", this.onMouseUp, this);
13379 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13381 this.resizing = true;
13382 this.startBox = this.el.getBox();
13383 this.startPoint = e.getXY();
13384 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13385 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13387 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13388 this.overlay.show();
13390 if(this.constrainTo) {
13391 var ct = Roo.get(this.constrainTo);
13392 this.resizeRegion = ct.getRegion().adjust(
13393 ct.getFrameWidth('t'),
13394 ct.getFrameWidth('l'),
13395 -ct.getFrameWidth('b'),
13396 -ct.getFrameWidth('r')
13400 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13402 this.proxy.setBox(this.startBox);
13404 this.proxy.setStyle('visibility', 'visible');
13410 onMouseDown : function(handle, e){
13413 this.activeHandle = handle;
13414 this.startSizing(e, handle);
13419 onMouseUp : function(e){
13420 var size = this.resizeElement();
13421 this.resizing = false;
13423 this.overlay.hide();
13425 this.fireEvent("resize", this, size.width, size.height, e);
13429 updateChildSize : function(){
13430 if(this.resizeChild){
13432 var child = this.resizeChild;
13433 var adj = this.adjustments;
13434 if(el.dom.offsetWidth){
13435 var b = el.getSize(true);
13436 child.setSize(b.width+adj[0], b.height+adj[1]);
13438 // Second call here for IE
13439 // The first call enables instant resizing and
13440 // the second call corrects scroll bars if they
13443 setTimeout(function(){
13444 if(el.dom.offsetWidth){
13445 var b = el.getSize(true);
13446 child.setSize(b.width+adj[0], b.height+adj[1]);
13454 snap : function(value, inc, min){
13455 if(!inc || !value) return value;
13456 var newValue = value;
13457 var m = value % inc;
13460 newValue = value + (inc-m);
13462 newValue = value - m;
13465 return Math.max(min, newValue);
13469 resizeElement : function(){
13470 var box = this.proxy.getBox();
13471 if(this.updateBox){
13472 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13474 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13476 this.updateChildSize();
13484 constrain : function(v, diff, m, mx){
13487 }else if(v - diff > mx){
13494 onMouseMove : function(e){
13496 try{// try catch so if something goes wrong the user doesn't get hung
13498 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13502 //var curXY = this.startPoint;
13503 var curSize = this.curSize || this.startBox;
13504 var x = this.startBox.x, y = this.startBox.y;
13505 var ox = x, oy = y;
13506 var w = curSize.width, h = curSize.height;
13507 var ow = w, oh = h;
13508 var mw = this.minWidth, mh = this.minHeight;
13509 var mxw = this.maxWidth, mxh = this.maxHeight;
13510 var wi = this.widthIncrement;
13511 var hi = this.heightIncrement;
13513 var eventXY = e.getXY();
13514 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13515 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13517 var pos = this.activeHandle.position;
13522 w = Math.min(Math.max(mw, w), mxw);
13527 h = Math.min(Math.max(mh, h), mxh);
13532 w = Math.min(Math.max(mw, w), mxw);
13533 h = Math.min(Math.max(mh, h), mxh);
13536 diffY = this.constrain(h, diffY, mh, mxh);
13543 var adiffX = Math.abs(diffX);
13544 var sub = (adiffX % wi); // how much
13545 if (sub > (wi/2)) { // far enough to snap
13546 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13548 // remove difference..
13549 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13553 x = Math.max(this.minX, x);
13556 diffX = this.constrain(w, diffX, mw, mxw);
13562 w = Math.min(Math.max(mw, w), mxw);
13563 diffY = this.constrain(h, diffY, mh, mxh);
13568 diffX = this.constrain(w, diffX, mw, mxw);
13569 diffY = this.constrain(h, diffY, mh, mxh);
13576 diffX = this.constrain(w, diffX, mw, mxw);
13578 h = Math.min(Math.max(mh, h), mxh);
13584 var sw = this.snap(w, wi, mw);
13585 var sh = this.snap(h, hi, mh);
13586 if(sw != w || sh != h){
13609 if(this.preserveRatio){
13614 h = Math.min(Math.max(mh, h), mxh);
13619 w = Math.min(Math.max(mw, w), mxw);
13624 w = Math.min(Math.max(mw, w), mxw);
13630 w = Math.min(Math.max(mw, w), mxw);
13636 h = Math.min(Math.max(mh, h), mxh);
13644 h = Math.min(Math.max(mh, h), mxh);
13654 h = Math.min(Math.max(mh, h), mxh);
13662 if (pos == 'hdrag') {
13665 this.proxy.setBounds(x, y, w, h);
13667 this.resizeElement();
13674 handleOver : function(){
13676 this.el.addClass("x-resizable-over");
13681 handleOut : function(){
13682 if(!this.resizing){
13683 this.el.removeClass("x-resizable-over");
13688 * Returns the element this component is bound to.
13689 * @return {Roo.Element}
13691 getEl : function(){
13696 * Returns the resizeChild element (or null).
13697 * @return {Roo.Element}
13699 getResizeChild : function(){
13700 return this.resizeChild;
13704 * Destroys this resizable. If the element was wrapped and
13705 * removeEl is not true then the element remains.
13706 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13708 destroy : function(removeEl){
13709 this.proxy.remove();
13711 this.overlay.removeAllListeners();
13712 this.overlay.remove();
13714 var ps = Roo.Resizable.positions;
13716 if(typeof ps[k] != "function" && this[ps[k]]){
13717 var h = this[ps[k]];
13718 h.el.removeAllListeners();
13723 this.el.update("");
13730 // hash to map config positions to true positions
13731 Roo.Resizable.positions = {
13732 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13737 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13739 // only initialize the template if resizable is used
13740 var tpl = Roo.DomHelper.createTemplate(
13741 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13744 Roo.Resizable.Handle.prototype.tpl = tpl;
13746 this.position = pos;
13748 // show north drag fro topdra
13749 var handlepos = pos == 'hdrag' ? 'north' : pos;
13751 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13752 if (pos == 'hdrag') {
13753 this.el.setStyle('cursor', 'pointer');
13755 this.el.unselectable();
13757 this.el.setOpacity(0);
13759 this.el.on("mousedown", this.onMouseDown, this);
13760 if(!disableTrackOver){
13761 this.el.on("mouseover", this.onMouseOver, this);
13762 this.el.on("mouseout", this.onMouseOut, this);
13767 Roo.Resizable.Handle.prototype = {
13768 afterResize : function(rz){
13772 onMouseDown : function(e){
13773 this.rz.onMouseDown(this, e);
13776 onMouseOver : function(e){
13777 this.rz.handleOver(this, e);
13780 onMouseOut : function(e){
13781 this.rz.handleOut(this, e);
13785 * Ext JS Library 1.1.1
13786 * Copyright(c) 2006-2007, Ext JS, LLC.
13788 * Originally Released Under LGPL - original licence link has changed is not relivant.
13791 * <script type="text/javascript">
13795 * @class Roo.Editor
13796 * @extends Roo.Component
13797 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13799 * Create a new Editor
13800 * @param {Roo.form.Field} field The Field object (or descendant)
13801 * @param {Object} config The config object
13803 Roo.Editor = function(field, config){
13804 Roo.Editor.superclass.constructor.call(this, config);
13805 this.field = field;
13808 * @event beforestartedit
13809 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13810 * false from the handler of this event.
13811 * @param {Editor} this
13812 * @param {Roo.Element} boundEl The underlying element bound to this editor
13813 * @param {Mixed} value The field value being set
13815 "beforestartedit" : true,
13818 * Fires when this editor is displayed
13819 * @param {Roo.Element} boundEl The underlying element bound to this editor
13820 * @param {Mixed} value The starting field value
13822 "startedit" : true,
13824 * @event beforecomplete
13825 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13826 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13827 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13828 * event will not fire since no edit actually occurred.
13829 * @param {Editor} this
13830 * @param {Mixed} value The current field value
13831 * @param {Mixed} startValue The original field value
13833 "beforecomplete" : true,
13836 * Fires after editing is complete and any changed value has been written to the underlying field.
13837 * @param {Editor} this
13838 * @param {Mixed} value The current field value
13839 * @param {Mixed} startValue The original field value
13843 * @event specialkey
13844 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13845 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13846 * @param {Roo.form.Field} this
13847 * @param {Roo.EventObject} e The event object
13849 "specialkey" : true
13853 Roo.extend(Roo.Editor, Roo.Component, {
13855 * @cfg {Boolean/String} autosize
13856 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13857 * or "height" to adopt the height only (defaults to false)
13860 * @cfg {Boolean} revertInvalid
13861 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13862 * validation fails (defaults to true)
13865 * @cfg {Boolean} ignoreNoChange
13866 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13867 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13868 * will never be ignored.
13871 * @cfg {Boolean} hideEl
13872 * False to keep the bound element visible while the editor is displayed (defaults to true)
13875 * @cfg {Mixed} value
13876 * The data value of the underlying field (defaults to "")
13880 * @cfg {String} alignment
13881 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13885 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13886 * for bottom-right shadow (defaults to "frame")
13890 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13894 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13896 completeOnEnter : false,
13898 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13900 cancelOnEsc : false,
13902 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13907 onRender : function(ct, position){
13908 this.el = new Roo.Layer({
13909 shadow: this.shadow,
13915 constrain: this.constrain
13917 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13918 if(this.field.msgTarget != 'title'){
13919 this.field.msgTarget = 'qtip';
13921 this.field.render(this.el);
13923 this.field.el.dom.setAttribute('autocomplete', 'off');
13925 this.field.on("specialkey", this.onSpecialKey, this);
13926 if(this.swallowKeys){
13927 this.field.el.swallowEvent(['keydown','keypress']);
13930 this.field.on("blur", this.onBlur, this);
13931 if(this.field.grow){
13932 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13936 onSpecialKey : function(field, e)
13938 //Roo.log('editor onSpecialKey');
13939 if(this.completeOnEnter && e.getKey() == e.ENTER){
13941 this.completeEdit();
13944 // do not fire special key otherwise it might hide close the editor...
13945 if(e.getKey() == e.ENTER){
13948 if(this.cancelOnEsc && e.getKey() == e.ESC){
13952 this.fireEvent('specialkey', field, e);
13957 * Starts the editing process and shows the editor.
13958 * @param {String/HTMLElement/Element} el The element to edit
13959 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13960 * to the innerHTML of el.
13962 startEdit : function(el, value){
13964 this.completeEdit();
13966 this.boundEl = Roo.get(el);
13967 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13968 if(!this.rendered){
13969 this.render(this.parentEl || document.body);
13971 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13974 this.startValue = v;
13975 this.field.setValue(v);
13977 var sz = this.boundEl.getSize();
13978 switch(this.autoSize){
13980 this.setSize(sz.width, "");
13983 this.setSize("", sz.height);
13986 this.setSize(sz.width, sz.height);
13989 this.el.alignTo(this.boundEl, this.alignment);
13990 this.editing = true;
13992 Roo.QuickTips.disable();
13998 * Sets the height and width of this editor.
13999 * @param {Number} width The new width
14000 * @param {Number} height The new height
14002 setSize : function(w, h){
14003 this.field.setSize(w, h);
14010 * Realigns the editor to the bound field based on the current alignment config value.
14012 realign : function(){
14013 this.el.alignTo(this.boundEl, this.alignment);
14017 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
14018 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
14020 completeEdit : function(remainVisible){
14024 var v = this.getValue();
14025 if(this.revertInvalid !== false && !this.field.isValid()){
14026 v = this.startValue;
14027 this.cancelEdit(true);
14029 if(String(v) === String(this.startValue) && this.ignoreNoChange){
14030 this.editing = false;
14034 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
14035 this.editing = false;
14036 if(this.updateEl && this.boundEl){
14037 this.boundEl.update(v);
14039 if(remainVisible !== true){
14042 this.fireEvent("complete", this, v, this.startValue);
14047 onShow : function(){
14049 if(this.hideEl !== false){
14050 this.boundEl.hide();
14053 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14054 this.fixIEFocus = true;
14055 this.deferredFocus.defer(50, this);
14057 this.field.focus();
14059 this.fireEvent("startedit", this.boundEl, this.startValue);
14062 deferredFocus : function(){
14064 this.field.focus();
14069 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14070 * reverted to the original starting value.
14071 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14072 * cancel (defaults to false)
14074 cancelEdit : function(remainVisible){
14076 this.setValue(this.startValue);
14077 if(remainVisible !== true){
14084 onBlur : function(){
14085 if(this.allowBlur !== true && this.editing){
14086 this.completeEdit();
14091 onHide : function(){
14093 this.completeEdit();
14097 if(this.field.collapse){
14098 this.field.collapse();
14101 if(this.hideEl !== false){
14102 this.boundEl.show();
14105 Roo.QuickTips.enable();
14110 * Sets the data value of the editor
14111 * @param {Mixed} value Any valid value supported by the underlying field
14113 setValue : function(v){
14114 this.field.setValue(v);
14118 * Gets the data value of the editor
14119 * @return {Mixed} The data value
14121 getValue : function(){
14122 return this.field.getValue();
14126 * Ext JS Library 1.1.1
14127 * Copyright(c) 2006-2007, Ext JS, LLC.
14129 * Originally Released Under LGPL - original licence link has changed is not relivant.
14132 * <script type="text/javascript">
14136 * @class Roo.BasicDialog
14137 * @extends Roo.util.Observable
14138 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14140 var dlg = new Roo.BasicDialog("my-dlg", {
14149 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14150 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14151 dlg.addButton('Cancel', dlg.hide, dlg);
14154 <b>A Dialog should always be a direct child of the body element.</b>
14155 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14156 * @cfg {String} title Default text to display in the title bar (defaults to null)
14157 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14158 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14159 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14160 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14161 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14162 * (defaults to null with no animation)
14163 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14164 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14165 * property for valid values (defaults to 'all')
14166 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14167 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14168 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14169 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14170 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14171 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14172 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14173 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14174 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14175 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14176 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14177 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14178 * draggable = true (defaults to false)
14179 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14180 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14181 * shadow (defaults to false)
14182 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14183 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14184 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14185 * @cfg {Array} buttons Array of buttons
14186 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14188 * Create a new BasicDialog.
14189 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14190 * @param {Object} config Configuration options
14192 Roo.BasicDialog = function(el, config){
14193 this.el = Roo.get(el);
14194 var dh = Roo.DomHelper;
14195 if(!this.el && config && config.autoCreate){
14196 if(typeof config.autoCreate == "object"){
14197 if(!config.autoCreate.id){
14198 config.autoCreate.id = el;
14200 this.el = dh.append(document.body,
14201 config.autoCreate, true);
14203 this.el = dh.append(document.body,
14204 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14208 el.setDisplayed(true);
14209 el.hide = this.hideAction;
14211 el.addClass("x-dlg");
14213 Roo.apply(this, config);
14215 this.proxy = el.createProxy("x-dlg-proxy");
14216 this.proxy.hide = this.hideAction;
14217 this.proxy.setOpacity(.5);
14221 el.setWidth(config.width);
14224 el.setHeight(config.height);
14226 this.size = el.getSize();
14227 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14228 this.xy = [config.x,config.y];
14230 this.xy = el.getCenterXY(true);
14232 /** The header element @type Roo.Element */
14233 this.header = el.child("> .x-dlg-hd");
14234 /** The body element @type Roo.Element */
14235 this.body = el.child("> .x-dlg-bd");
14236 /** The footer element @type Roo.Element */
14237 this.footer = el.child("> .x-dlg-ft");
14240 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14243 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14246 this.header.unselectable();
14248 this.header.update(this.title);
14250 // this element allows the dialog to be focused for keyboard event
14251 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14252 this.focusEl.swallowEvent("click", true);
14254 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14256 // wrap the body and footer for special rendering
14257 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14259 this.bwrap.dom.appendChild(this.footer.dom);
14262 this.bg = this.el.createChild({
14263 tag: "div", cls:"x-dlg-bg",
14264 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14266 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14269 if(this.autoScroll !== false && !this.autoTabs){
14270 this.body.setStyle("overflow", "auto");
14273 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14275 if(this.closable !== false){
14276 this.el.addClass("x-dlg-closable");
14277 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14278 this.close.on("click", this.closeClick, this);
14279 this.close.addClassOnOver("x-dlg-close-over");
14281 if(this.collapsible !== false){
14282 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14283 this.collapseBtn.on("click", this.collapseClick, this);
14284 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14285 this.header.on("dblclick", this.collapseClick, this);
14287 if(this.resizable !== false){
14288 this.el.addClass("x-dlg-resizable");
14289 this.resizer = new Roo.Resizable(el, {
14290 minWidth: this.minWidth || 80,
14291 minHeight:this.minHeight || 80,
14292 handles: this.resizeHandles || "all",
14295 this.resizer.on("beforeresize", this.beforeResize, this);
14296 this.resizer.on("resize", this.onResize, this);
14298 if(this.draggable !== false){
14299 el.addClass("x-dlg-draggable");
14300 if (!this.proxyDrag) {
14301 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14304 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14306 dd.setHandleElId(this.header.id);
14307 dd.endDrag = this.endMove.createDelegate(this);
14308 dd.startDrag = this.startMove.createDelegate(this);
14309 dd.onDrag = this.onDrag.createDelegate(this);
14314 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14315 this.mask.enableDisplayMode("block");
14317 this.el.addClass("x-dlg-modal");
14320 this.shadow = new Roo.Shadow({
14321 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14322 offset : this.shadowOffset
14325 this.shadowOffset = 0;
14327 if(Roo.useShims && this.shim !== false){
14328 this.shim = this.el.createShim();
14329 this.shim.hide = this.hideAction;
14337 if (this.buttons) {
14338 var bts= this.buttons;
14340 Roo.each(bts, function(b) {
14349 * Fires when a key is pressed
14350 * @param {Roo.BasicDialog} this
14351 * @param {Roo.EventObject} e
14356 * Fires when this dialog is moved by the user.
14357 * @param {Roo.BasicDialog} this
14358 * @param {Number} x The new page X
14359 * @param {Number} y The new page Y
14364 * Fires when this dialog is resized by the user.
14365 * @param {Roo.BasicDialog} this
14366 * @param {Number} width The new width
14367 * @param {Number} height The new height
14371 * @event beforehide
14372 * Fires before this dialog is hidden.
14373 * @param {Roo.BasicDialog} this
14375 "beforehide" : true,
14378 * Fires when this dialog is hidden.
14379 * @param {Roo.BasicDialog} this
14383 * @event beforeshow
14384 * Fires before this dialog is shown.
14385 * @param {Roo.BasicDialog} this
14387 "beforeshow" : true,
14390 * Fires when this dialog is shown.
14391 * @param {Roo.BasicDialog} this
14395 el.on("keydown", this.onKeyDown, this);
14396 el.on("mousedown", this.toFront, this);
14397 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14399 Roo.DialogManager.register(this);
14400 Roo.BasicDialog.superclass.constructor.call(this);
14403 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14404 shadowOffset: Roo.isIE ? 6 : 5,
14407 minButtonWidth: 75,
14408 defaultButton: null,
14409 buttonAlign: "right",
14414 * Sets the dialog title text
14415 * @param {String} text The title text to display
14416 * @return {Roo.BasicDialog} this
14418 setTitle : function(text){
14419 this.header.update(text);
14424 closeClick : function(){
14429 collapseClick : function(){
14430 this[this.collapsed ? "expand" : "collapse"]();
14434 * Collapses the dialog to its minimized state (only the title bar is visible).
14435 * Equivalent to the user clicking the collapse dialog button.
14437 collapse : function(){
14438 if(!this.collapsed){
14439 this.collapsed = true;
14440 this.el.addClass("x-dlg-collapsed");
14441 this.restoreHeight = this.el.getHeight();
14442 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14447 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14448 * clicking the expand dialog button.
14450 expand : function(){
14451 if(this.collapsed){
14452 this.collapsed = false;
14453 this.el.removeClass("x-dlg-collapsed");
14454 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14459 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14460 * @return {Roo.TabPanel} The tabs component
14462 initTabs : function(){
14463 var tabs = this.getTabs();
14464 while(tabs.getTab(0)){
14467 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14469 tabs.addTab(Roo.id(dom), dom.title);
14477 beforeResize : function(){
14478 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14482 onResize : function(){
14483 this.refreshSize();
14484 this.syncBodyHeight();
14485 this.adjustAssets();
14487 this.fireEvent("resize", this, this.size.width, this.size.height);
14491 onKeyDown : function(e){
14492 if(this.isVisible()){
14493 this.fireEvent("keydown", this, e);
14498 * Resizes the dialog.
14499 * @param {Number} width
14500 * @param {Number} height
14501 * @return {Roo.BasicDialog} this
14503 resizeTo : function(width, height){
14504 this.el.setSize(width, height);
14505 this.size = {width: width, height: height};
14506 this.syncBodyHeight();
14507 if(this.fixedcenter){
14510 if(this.isVisible()){
14511 this.constrainXY();
14512 this.adjustAssets();
14514 this.fireEvent("resize", this, width, height);
14520 * Resizes the dialog to fit the specified content size.
14521 * @param {Number} width
14522 * @param {Number} height
14523 * @return {Roo.BasicDialog} this
14525 setContentSize : function(w, h){
14526 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14527 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14528 //if(!this.el.isBorderBox()){
14529 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14530 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14533 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14534 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14536 this.resizeTo(w, h);
14541 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14542 * executed in response to a particular key being pressed while the dialog is active.
14543 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14544 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14545 * @param {Function} fn The function to call
14546 * @param {Object} scope (optional) The scope of the function
14547 * @return {Roo.BasicDialog} this
14549 addKeyListener : function(key, fn, scope){
14550 var keyCode, shift, ctrl, alt;
14551 if(typeof key == "object" && !(key instanceof Array)){
14552 keyCode = key["key"];
14553 shift = key["shift"];
14554 ctrl = key["ctrl"];
14559 var handler = function(dlg, e){
14560 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14561 var k = e.getKey();
14562 if(keyCode instanceof Array){
14563 for(var i = 0, len = keyCode.length; i < len; i++){
14564 if(keyCode[i] == k){
14565 fn.call(scope || window, dlg, k, e);
14571 fn.call(scope || window, dlg, k, e);
14576 this.on("keydown", handler);
14581 * Returns the TabPanel component (creates it if it doesn't exist).
14582 * Note: If you wish to simply check for the existence of tabs without creating them,
14583 * check for a null 'tabs' property.
14584 * @return {Roo.TabPanel} The tabs component
14586 getTabs : function(){
14588 this.el.addClass("x-dlg-auto-tabs");
14589 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14590 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14596 * Adds a button to the footer section of the dialog.
14597 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14598 * object or a valid Roo.DomHelper element config
14599 * @param {Function} handler The function called when the button is clicked
14600 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14601 * @return {Roo.Button} The new button
14603 addButton : function(config, handler, scope){
14604 var dh = Roo.DomHelper;
14606 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14608 if(!this.btnContainer){
14609 var tb = this.footer.createChild({
14611 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14612 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14614 this.btnContainer = tb.firstChild.firstChild.firstChild;
14619 minWidth: this.minButtonWidth,
14622 if(typeof config == "string"){
14623 bconfig.text = config;
14626 bconfig.dhconfig = config;
14628 Roo.apply(bconfig, config);
14632 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14633 bconfig.position = Math.max(0, bconfig.position);
14634 fc = this.btnContainer.childNodes[bconfig.position];
14637 var btn = new Roo.Button(
14639 this.btnContainer.insertBefore(document.createElement("td"),fc)
14640 : this.btnContainer.appendChild(document.createElement("td")),
14641 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14644 this.syncBodyHeight();
14647 * Array of all the buttons that have been added to this dialog via addButton
14652 this.buttons.push(btn);
14657 * Sets the default button to be focused when the dialog is displayed.
14658 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14659 * @return {Roo.BasicDialog} this
14661 setDefaultButton : function(btn){
14662 this.defaultButton = btn;
14667 getHeaderFooterHeight : function(safe){
14670 height += this.header.getHeight();
14673 var fm = this.footer.getMargins();
14674 height += (this.footer.getHeight()+fm.top+fm.bottom);
14676 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14677 height += this.centerBg.getPadding("tb");
14682 syncBodyHeight : function(){
14683 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14684 var height = this.size.height - this.getHeaderFooterHeight(false);
14685 bd.setHeight(height-bd.getMargins("tb"));
14686 var hh = this.header.getHeight();
14687 var h = this.size.height-hh;
14689 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14690 bw.setHeight(h-cb.getPadding("tb"));
14691 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14692 bd.setWidth(bw.getWidth(true));
14694 this.tabs.syncHeight();
14696 this.tabs.el.repaint();
14702 * Restores the previous state of the dialog if Roo.state is configured.
14703 * @return {Roo.BasicDialog} this
14705 restoreState : function(){
14706 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14707 if(box && box.width){
14708 this.xy = [box.x, box.y];
14709 this.resizeTo(box.width, box.height);
14715 beforeShow : function(){
14717 if(this.fixedcenter){
14718 this.xy = this.el.getCenterXY(true);
14721 Roo.get(document.body).addClass("x-body-masked");
14722 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14725 this.constrainXY();
14729 animShow : function(){
14730 var b = Roo.get(this.animateTarget).getBox();
14731 this.proxy.setSize(b.width, b.height);
14732 this.proxy.setLocation(b.x, b.y);
14734 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14735 true, .35, this.showEl.createDelegate(this));
14739 * Shows the dialog.
14740 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14741 * @return {Roo.BasicDialog} this
14743 show : function(animateTarget){
14744 if (this.fireEvent("beforeshow", this) === false){
14747 if(this.syncHeightBeforeShow){
14748 this.syncBodyHeight();
14749 }else if(this.firstShow){
14750 this.firstShow = false;
14751 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14753 this.animateTarget = animateTarget || this.animateTarget;
14754 if(!this.el.isVisible()){
14756 if(this.animateTarget && Roo.get(this.animateTarget)){
14766 showEl : function(){
14768 this.el.setXY(this.xy);
14770 this.adjustAssets(true);
14773 // IE peekaboo bug - fix found by Dave Fenwick
14777 this.fireEvent("show", this);
14781 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14782 * dialog itself will receive focus.
14784 focus : function(){
14785 if(this.defaultButton){
14786 this.defaultButton.focus();
14788 this.focusEl.focus();
14793 constrainXY : function(){
14794 if(this.constraintoviewport !== false){
14795 if(!this.viewSize){
14796 if(this.container){
14797 var s = this.container.getSize();
14798 this.viewSize = [s.width, s.height];
14800 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14803 var s = Roo.get(this.container||document).getScroll();
14805 var x = this.xy[0], y = this.xy[1];
14806 var w = this.size.width, h = this.size.height;
14807 var vw = this.viewSize[0], vh = this.viewSize[1];
14808 // only move it if it needs it
14810 // first validate right/bottom
14811 if(x + w > vw+s.left){
14815 if(y + h > vh+s.top){
14819 // then make sure top/left isn't negative
14831 if(this.isVisible()){
14832 this.el.setLocation(x, y);
14833 this.adjustAssets();
14840 onDrag : function(){
14841 if(!this.proxyDrag){
14842 this.xy = this.el.getXY();
14843 this.adjustAssets();
14848 adjustAssets : function(doShow){
14849 var x = this.xy[0], y = this.xy[1];
14850 var w = this.size.width, h = this.size.height;
14851 if(doShow === true){
14853 this.shadow.show(this.el);
14859 if(this.shadow && this.shadow.isVisible()){
14860 this.shadow.show(this.el);
14862 if(this.shim && this.shim.isVisible()){
14863 this.shim.setBounds(x, y, w, h);
14868 adjustViewport : function(w, h){
14870 w = Roo.lib.Dom.getViewWidth();
14871 h = Roo.lib.Dom.getViewHeight();
14874 this.viewSize = [w, h];
14875 if(this.modal && this.mask.isVisible()){
14876 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14877 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14879 if(this.isVisible()){
14880 this.constrainXY();
14885 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14886 * shadow, proxy, mask, etc.) Also removes all event listeners.
14887 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14889 destroy : function(removeEl){
14890 if(this.isVisible()){
14891 this.animateTarget = null;
14894 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14896 this.tabs.destroy(removeEl);
14909 for(var i = 0, len = this.buttons.length; i < len; i++){
14910 this.buttons[i].destroy();
14913 this.el.removeAllListeners();
14914 if(removeEl === true){
14915 this.el.update("");
14918 Roo.DialogManager.unregister(this);
14922 startMove : function(){
14923 if(this.proxyDrag){
14926 if(this.constraintoviewport !== false){
14927 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14932 endMove : function(){
14933 if(!this.proxyDrag){
14934 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14936 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14939 this.refreshSize();
14940 this.adjustAssets();
14942 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14946 * Brings this dialog to the front of any other visible dialogs
14947 * @return {Roo.BasicDialog} this
14949 toFront : function(){
14950 Roo.DialogManager.bringToFront(this);
14955 * Sends this dialog to the back (under) of any other visible dialogs
14956 * @return {Roo.BasicDialog} this
14958 toBack : function(){
14959 Roo.DialogManager.sendToBack(this);
14964 * Centers this dialog in the viewport
14965 * @return {Roo.BasicDialog} this
14967 center : function(){
14968 var xy = this.el.getCenterXY(true);
14969 this.moveTo(xy[0], xy[1]);
14974 * Moves the dialog's top-left corner to the specified point
14975 * @param {Number} x
14976 * @param {Number} y
14977 * @return {Roo.BasicDialog} this
14979 moveTo : function(x, y){
14981 if(this.isVisible()){
14982 this.el.setXY(this.xy);
14983 this.adjustAssets();
14989 * Aligns the dialog to the specified element
14990 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14991 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14992 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14993 * @return {Roo.BasicDialog} this
14995 alignTo : function(element, position, offsets){
14996 this.xy = this.el.getAlignToXY(element, position, offsets);
14997 if(this.isVisible()){
14998 this.el.setXY(this.xy);
14999 this.adjustAssets();
15005 * Anchors an element to another element and realigns it when the window is resized.
15006 * @param {String/HTMLElement/Roo.Element} element The element to align to.
15007 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
15008 * @param {Array} offsets (optional) Offset the positioning by [x, y]
15009 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
15010 * is a number, it is used as the buffer delay (defaults to 50ms).
15011 * @return {Roo.BasicDialog} this
15013 anchorTo : function(el, alignment, offsets, monitorScroll){
15014 var action = function(){
15015 this.alignTo(el, alignment, offsets);
15017 Roo.EventManager.onWindowResize(action, this);
15018 var tm = typeof monitorScroll;
15019 if(tm != 'undefined'){
15020 Roo.EventManager.on(window, 'scroll', action, this,
15021 {buffer: tm == 'number' ? monitorScroll : 50});
15028 * Returns true if the dialog is visible
15029 * @return {Boolean}
15031 isVisible : function(){
15032 return this.el.isVisible();
15036 animHide : function(callback){
15037 var b = Roo.get(this.animateTarget).getBox();
15039 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15041 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15042 this.hideEl.createDelegate(this, [callback]));
15046 * Hides the dialog.
15047 * @param {Function} callback (optional) Function to call when the dialog is hidden
15048 * @return {Roo.BasicDialog} this
15050 hide : function(callback){
15051 if (this.fireEvent("beforehide", this) === false){
15055 this.shadow.hide();
15060 // sometimes animateTarget seems to get set.. causing problems...
15061 // this just double checks..
15062 if(this.animateTarget && Roo.get(this.animateTarget)) {
15063 this.animHide(callback);
15066 this.hideEl(callback);
15072 hideEl : function(callback){
15076 Roo.get(document.body).removeClass("x-body-masked");
15078 this.fireEvent("hide", this);
15079 if(typeof callback == "function"){
15085 hideAction : function(){
15086 this.setLeft("-10000px");
15087 this.setTop("-10000px");
15088 this.setStyle("visibility", "hidden");
15092 refreshSize : function(){
15093 this.size = this.el.getSize();
15094 this.xy = this.el.getXY();
15095 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15099 // z-index is managed by the DialogManager and may be overwritten at any time
15100 setZIndex : function(index){
15102 this.mask.setStyle("z-index", index);
15105 this.shim.setStyle("z-index", ++index);
15108 this.shadow.setZIndex(++index);
15110 this.el.setStyle("z-index", ++index);
15112 this.proxy.setStyle("z-index", ++index);
15115 this.resizer.proxy.setStyle("z-index", ++index);
15118 this.lastZIndex = index;
15122 * Returns the element for this dialog
15123 * @return {Roo.Element} The underlying dialog Element
15125 getEl : function(){
15131 * @class Roo.DialogManager
15132 * Provides global access to BasicDialogs that have been created and
15133 * support for z-indexing (layering) multiple open dialogs.
15135 Roo.DialogManager = function(){
15137 var accessList = [];
15141 var sortDialogs = function(d1, d2){
15142 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15146 var orderDialogs = function(){
15147 accessList.sort(sortDialogs);
15148 var seed = Roo.DialogManager.zseed;
15149 for(var i = 0, len = accessList.length; i < len; i++){
15150 var dlg = accessList[i];
15152 dlg.setZIndex(seed + (i*10));
15159 * The starting z-index for BasicDialogs (defaults to 9000)
15160 * @type Number The z-index value
15165 register : function(dlg){
15166 list[dlg.id] = dlg;
15167 accessList.push(dlg);
15171 unregister : function(dlg){
15172 delete list[dlg.id];
15175 if(!accessList.indexOf){
15176 for( i = 0, len = accessList.length; i < len; i++){
15177 if(accessList[i] == dlg){
15178 accessList.splice(i, 1);
15183 i = accessList.indexOf(dlg);
15185 accessList.splice(i, 1);
15191 * Gets a registered dialog by id
15192 * @param {String/Object} id The id of the dialog or a dialog
15193 * @return {Roo.BasicDialog} this
15195 get : function(id){
15196 return typeof id == "object" ? id : list[id];
15200 * Brings the specified dialog to the front
15201 * @param {String/Object} dlg The id of the dialog or a dialog
15202 * @return {Roo.BasicDialog} this
15204 bringToFront : function(dlg){
15205 dlg = this.get(dlg);
15208 dlg._lastAccess = new Date().getTime();
15215 * Sends the specified dialog to the back
15216 * @param {String/Object} dlg The id of the dialog or a dialog
15217 * @return {Roo.BasicDialog} this
15219 sendToBack : function(dlg){
15220 dlg = this.get(dlg);
15221 dlg._lastAccess = -(new Date().getTime());
15227 * Hides all dialogs
15229 hideAll : function(){
15230 for(var id in list){
15231 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15240 * @class Roo.LayoutDialog
15241 * @extends Roo.BasicDialog
15242 * Dialog which provides adjustments for working with a layout in a Dialog.
15243 * Add your necessary layout config options to the dialog's config.<br>
15244 * Example usage (including a nested layout):
15247 dialog = new Roo.LayoutDialog("download-dlg", {
15256 // layout config merges with the dialog config
15258 tabPosition: "top",
15259 alwaysShowTabs: true
15262 dialog.addKeyListener(27, dialog.hide, dialog);
15263 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15264 dialog.addButton("Build It!", this.getDownload, this);
15266 // we can even add nested layouts
15267 var innerLayout = new Roo.BorderLayout("dl-inner", {
15277 innerLayout.beginUpdate();
15278 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15279 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15280 innerLayout.endUpdate(true);
15282 var layout = dialog.getLayout();
15283 layout.beginUpdate();
15284 layout.add("center", new Roo.ContentPanel("standard-panel",
15285 {title: "Download the Source", fitToFrame:true}));
15286 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15287 {title: "Build your own roo.js"}));
15288 layout.getRegion("center").showPanel(sp);
15289 layout.endUpdate();
15293 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15294 * @param {Object} config configuration options
15296 Roo.LayoutDialog = function(el, cfg){
15299 if (typeof(cfg) == 'undefined') {
15300 config = Roo.apply({}, el);
15301 // not sure why we use documentElement here.. - it should always be body.
15302 // IE7 borks horribly if we use documentElement.
15303 // webkit also does not like documentElement - it creates a body element...
15304 el = Roo.get( document.body || document.documentElement ).createChild();
15305 //config.autoCreate = true;
15309 config.autoTabs = false;
15310 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15311 this.body.setStyle({overflow:"hidden", position:"relative"});
15312 this.layout = new Roo.BorderLayout(this.body.dom, config);
15313 this.layout.monitorWindowResize = false;
15314 this.el.addClass("x-dlg-auto-layout");
15315 // fix case when center region overwrites center function
15316 this.center = Roo.BasicDialog.prototype.center;
15317 this.on("show", this.layout.layout, this.layout, true);
15318 if (config.items) {
15319 var xitems = config.items;
15320 delete config.items;
15321 Roo.each(xitems, this.addxtype, this);
15326 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15328 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15331 endUpdate : function(){
15332 this.layout.endUpdate();
15336 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15339 beginUpdate : function(){
15340 this.layout.beginUpdate();
15344 * Get the BorderLayout for this dialog
15345 * @return {Roo.BorderLayout}
15347 getLayout : function(){
15348 return this.layout;
15351 showEl : function(){
15352 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15354 this.layout.layout();
15359 // Use the syncHeightBeforeShow config option to control this automatically
15360 syncBodyHeight : function(){
15361 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15362 if(this.layout){this.layout.layout();}
15366 * Add an xtype element (actually adds to the layout.)
15367 * @return {Object} xdata xtype object data.
15370 addxtype : function(c) {
15371 return this.layout.addxtype(c);
15375 * Ext JS Library 1.1.1
15376 * Copyright(c) 2006-2007, Ext JS, LLC.
15378 * Originally Released Under LGPL - original licence link has changed is not relivant.
15381 * <script type="text/javascript">
15385 * @class Roo.MessageBox
15386 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15390 Roo.Msg.alert('Status', 'Changes saved successfully.');
15392 // Prompt for user data:
15393 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15395 // process text value...
15399 // Show a dialog using config options:
15401 title:'Save Changes?',
15402 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15403 buttons: Roo.Msg.YESNOCANCEL,
15410 Roo.MessageBox = function(){
15411 var dlg, opt, mask, waitTimer;
15412 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15413 var buttons, activeTextEl, bwidth;
15416 var handleButton = function(button){
15418 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15422 var handleHide = function(){
15423 if(opt && opt.cls){
15424 dlg.el.removeClass(opt.cls);
15427 Roo.TaskMgr.stop(waitTimer);
15433 var updateButtons = function(b){
15436 buttons["ok"].hide();
15437 buttons["cancel"].hide();
15438 buttons["yes"].hide();
15439 buttons["no"].hide();
15440 dlg.footer.dom.style.display = 'none';
15443 dlg.footer.dom.style.display = '';
15444 for(var k in buttons){
15445 if(typeof buttons[k] != "function"){
15448 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15449 width += buttons[k].el.getWidth()+15;
15459 var handleEsc = function(d, k, e){
15460 if(opt && opt.closable !== false){
15470 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15471 * @return {Roo.BasicDialog} The BasicDialog element
15473 getDialog : function(){
15475 dlg = new Roo.BasicDialog("x-msg-box", {
15480 constraintoviewport:false,
15482 collapsible : false,
15485 width:400, height:100,
15486 buttonAlign:"center",
15487 closeClick : function(){
15488 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15489 handleButton("no");
15491 handleButton("cancel");
15495 dlg.on("hide", handleHide);
15497 dlg.addKeyListener(27, handleEsc);
15499 var bt = this.buttonText;
15500 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15501 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15502 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15503 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15504 bodyEl = dlg.body.createChild({
15506 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>'
15508 msgEl = bodyEl.dom.firstChild;
15509 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15510 textboxEl.enableDisplayMode();
15511 textboxEl.addKeyListener([10,13], function(){
15512 if(dlg.isVisible() && opt && opt.buttons){
15513 if(opt.buttons.ok){
15514 handleButton("ok");
15515 }else if(opt.buttons.yes){
15516 handleButton("yes");
15520 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15521 textareaEl.enableDisplayMode();
15522 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15523 progressEl.enableDisplayMode();
15524 var pf = progressEl.dom.firstChild;
15526 pp = Roo.get(pf.firstChild);
15527 pp.setHeight(pf.offsetHeight);
15535 * Updates the message box body text
15536 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15537 * the XHTML-compliant non-breaking space character '&#160;')
15538 * @return {Roo.MessageBox} This message box
15540 updateText : function(text){
15541 if(!dlg.isVisible() && !opt.width){
15542 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15544 msgEl.innerHTML = text || ' ';
15545 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15546 Math.max(opt.minWidth || this.minWidth, bwidth));
15548 activeTextEl.setWidth(w);
15550 if(dlg.isVisible()){
15551 dlg.fixedcenter = false;
15553 dlg.setContentSize(w, bodyEl.getHeight());
15554 if(dlg.isVisible()){
15555 dlg.fixedcenter = true;
15561 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15562 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15563 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15564 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15565 * @return {Roo.MessageBox} This message box
15567 updateProgress : function(value, text){
15569 this.updateText(text);
15571 if (pp) { // weird bug on my firefox - for some reason this is not defined
15572 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15578 * Returns true if the message box is currently displayed
15579 * @return {Boolean} True if the message box is visible, else false
15581 isVisible : function(){
15582 return dlg && dlg.isVisible();
15586 * Hides the message box if it is displayed
15589 if(this.isVisible()){
15595 * Displays a new message box, or reinitializes an existing message box, based on the config options
15596 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15597 * The following config object properties are supported:
15599 Property Type Description
15600 ---------- --------------- ------------------------------------------------------------------------------------
15601 animEl String/Element An id or Element from which the message box should animate as it opens and
15602 closes (defaults to undefined)
15603 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15604 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15605 closable Boolean False to hide the top-right close button (defaults to true). Note that
15606 progress and wait dialogs will ignore this property and always hide the
15607 close button as they can only be closed programmatically.
15608 cls String A custom CSS class to apply to the message box element
15609 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15610 displayed (defaults to 75)
15611 fn Function A callback function to execute after closing the dialog. The arguments to the
15612 function will be btn (the name of the button that was clicked, if applicable,
15613 e.g. "ok"), and text (the value of the active text field, if applicable).
15614 Progress and wait dialogs will ignore this option since they do not respond to
15615 user actions and can only be closed programmatically, so any required function
15616 should be called by the same code after it closes the dialog.
15617 icon String A CSS class that provides a background image to be used as an icon for
15618 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15619 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15620 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15621 modal Boolean False to allow user interaction with the page while the message box is
15622 displayed (defaults to true)
15623 msg String A string that will replace the existing message box body text (defaults
15624 to the XHTML-compliant non-breaking space character ' ')
15625 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15626 progress Boolean True to display a progress bar (defaults to false)
15627 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15628 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15629 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15630 title String The title text
15631 value String The string value to set into the active textbox element if displayed
15632 wait Boolean True to display a progress bar (defaults to false)
15633 width Number The width of the dialog in pixels
15640 msg: 'Please enter your address:',
15642 buttons: Roo.MessageBox.OKCANCEL,
15645 animEl: 'addAddressBtn'
15648 * @param {Object} config Configuration options
15649 * @return {Roo.MessageBox} This message box
15651 show : function(options){
15652 if(this.isVisible()){
15655 var d = this.getDialog();
15657 d.setTitle(opt.title || " ");
15658 d.close.setDisplayed(opt.closable !== false);
15659 activeTextEl = textboxEl;
15660 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15665 textareaEl.setHeight(typeof opt.multiline == "number" ?
15666 opt.multiline : this.defaultTextHeight);
15667 activeTextEl = textareaEl;
15676 progressEl.setDisplayed(opt.progress === true);
15677 this.updateProgress(0);
15678 activeTextEl.dom.value = opt.value || "";
15680 dlg.setDefaultButton(activeTextEl);
15682 var bs = opt.buttons;
15685 db = buttons["ok"];
15686 }else if(bs && bs.yes){
15687 db = buttons["yes"];
15689 dlg.setDefaultButton(db);
15691 bwidth = updateButtons(opt.buttons);
15692 this.updateText(opt.msg);
15694 d.el.addClass(opt.cls);
15696 d.proxyDrag = opt.proxyDrag === true;
15697 d.modal = opt.modal !== false;
15698 d.mask = opt.modal !== false ? mask : false;
15699 if(!d.isVisible()){
15700 // force it to the end of the z-index stack so it gets a cursor in FF
15701 document.body.appendChild(dlg.el.dom);
15702 d.animateTarget = null;
15703 d.show(options.animEl);
15709 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15710 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15711 * and closing the message box when the process is complete.
15712 * @param {String} title The title bar text
15713 * @param {String} msg The message box body text
15714 * @return {Roo.MessageBox} This message box
15716 progress : function(title, msg){
15723 minWidth: this.minProgressWidth,
15730 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15731 * If a callback function is passed it will be called after the user clicks the button, and the
15732 * id of the button that was clicked will be passed as the only parameter to the callback
15733 * (could also be the top-right close button).
15734 * @param {String} title The title bar text
15735 * @param {String} msg The message box body text
15736 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15737 * @param {Object} scope (optional) The scope of the callback function
15738 * @return {Roo.MessageBox} This message box
15740 alert : function(title, msg, fn, scope){
15753 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15754 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15755 * You are responsible for closing the message box when the process is complete.
15756 * @param {String} msg The message box body text
15757 * @param {String} title (optional) The title bar text
15758 * @return {Roo.MessageBox} This message box
15760 wait : function(msg, title){
15771 waitTimer = Roo.TaskMgr.start({
15773 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15781 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15782 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15783 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15784 * @param {String} title The title bar text
15785 * @param {String} msg The message box body text
15786 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15787 * @param {Object} scope (optional) The scope of the callback function
15788 * @return {Roo.MessageBox} This message box
15790 confirm : function(title, msg, fn, scope){
15794 buttons: this.YESNO,
15803 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15804 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15805 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15806 * (could also be the top-right close button) and the text that was entered will be passed as the two
15807 * parameters to the callback.
15808 * @param {String} title The title bar text
15809 * @param {String} msg The message box body text
15810 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15811 * @param {Object} scope (optional) The scope of the callback function
15812 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15813 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15814 * @return {Roo.MessageBox} This message box
15816 prompt : function(title, msg, fn, scope, multiline){
15820 buttons: this.OKCANCEL,
15825 multiline: multiline,
15832 * Button config that displays a single OK button
15837 * Button config that displays Yes and No buttons
15840 YESNO : {yes:true, no:true},
15842 * Button config that displays OK and Cancel buttons
15845 OKCANCEL : {ok:true, cancel:true},
15847 * Button config that displays Yes, No and Cancel buttons
15850 YESNOCANCEL : {yes:true, no:true, cancel:true},
15853 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15856 defaultTextHeight : 75,
15858 * The maximum width in pixels of the message box (defaults to 600)
15863 * The minimum width in pixels of the message box (defaults to 100)
15868 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15869 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15872 minProgressWidth : 250,
15874 * An object containing the default button text strings that can be overriden for localized language support.
15875 * Supported properties are: ok, cancel, yes and no.
15876 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15889 * Shorthand for {@link Roo.MessageBox}
15891 Roo.Msg = Roo.MessageBox;/*
15893 * Ext JS Library 1.1.1
15894 * Copyright(c) 2006-2007, Ext JS, LLC.
15896 * Originally Released Under LGPL - original licence link has changed is not relivant.
15899 * <script type="text/javascript">
15902 * @class Roo.QuickTips
15903 * Provides attractive and customizable tooltips for any element.
15906 Roo.QuickTips = function(){
15907 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15908 var ce, bd, xy, dd;
15909 var visible = false, disabled = true, inited = false;
15910 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15912 var onOver = function(e){
15916 var t = e.getTarget();
15917 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15920 if(ce && t == ce.el){
15921 clearTimeout(hideProc);
15924 if(t && tagEls[t.id]){
15925 tagEls[t.id].el = t;
15926 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15929 var ttp, et = Roo.fly(t);
15930 var ns = cfg.namespace;
15931 if(tm.interceptTitles && t.title){
15934 t.removeAttribute("title");
15935 e.preventDefault();
15937 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15940 showProc = show.defer(tm.showDelay, tm, [{
15943 width: et.getAttributeNS(ns, cfg.width),
15944 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15945 title: et.getAttributeNS(ns, cfg.title),
15946 cls: et.getAttributeNS(ns, cfg.cls)
15951 var onOut = function(e){
15952 clearTimeout(showProc);
15953 var t = e.getTarget();
15954 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15955 hideProc = setTimeout(hide, tm.hideDelay);
15959 var onMove = function(e){
15965 if(tm.trackMouse && ce){
15970 var onDown = function(e){
15971 clearTimeout(showProc);
15972 clearTimeout(hideProc);
15974 if(tm.hideOnClick){
15977 tm.enable.defer(100, tm);
15982 var getPad = function(){
15983 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15986 var show = function(o){
15990 clearTimeout(dismissProc);
15992 if(removeCls){ // in case manually hidden
15993 el.removeClass(removeCls);
15997 el.addClass(ce.cls);
15998 removeCls = ce.cls;
16001 tipTitle.update(ce.title);
16004 tipTitle.update('');
16007 el.dom.style.width = tm.maxWidth+'px';
16008 //tipBody.dom.style.width = '';
16009 tipBodyText.update(o.text);
16010 var p = getPad(), w = ce.width;
16012 var td = tipBodyText.dom;
16013 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
16014 if(aw > tm.maxWidth){
16016 }else if(aw < tm.minWidth){
16022 //tipBody.setWidth(w);
16023 el.setWidth(parseInt(w, 10) + p);
16024 if(ce.autoHide === false){
16025 close.setDisplayed(true);
16030 close.setDisplayed(false);
16036 el.avoidY = xy[1]-18;
16041 el.setStyle("visibility", "visible");
16042 el.fadeIn({callback: afterShow});
16048 var afterShow = function(){
16052 if(tm.autoDismiss && ce.autoHide !== false){
16053 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16058 var hide = function(noanim){
16059 clearTimeout(dismissProc);
16060 clearTimeout(hideProc);
16062 if(el.isVisible()){
16064 if(noanim !== true && tm.animate){
16065 el.fadeOut({callback: afterHide});
16072 var afterHide = function(){
16075 el.removeClass(removeCls);
16082 * @cfg {Number} minWidth
16083 * The minimum width of the quick tip (defaults to 40)
16087 * @cfg {Number} maxWidth
16088 * The maximum width of the quick tip (defaults to 300)
16092 * @cfg {Boolean} interceptTitles
16093 * True to automatically use the element's DOM title value if available (defaults to false)
16095 interceptTitles : false,
16097 * @cfg {Boolean} trackMouse
16098 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16100 trackMouse : false,
16102 * @cfg {Boolean} hideOnClick
16103 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16105 hideOnClick : true,
16107 * @cfg {Number} showDelay
16108 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16112 * @cfg {Number} hideDelay
16113 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16117 * @cfg {Boolean} autoHide
16118 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16119 * Used in conjunction with hideDelay.
16124 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16125 * (defaults to true). Used in conjunction with autoDismissDelay.
16127 autoDismiss : true,
16130 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16132 autoDismissDelay : 5000,
16134 * @cfg {Boolean} animate
16135 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16140 * @cfg {String} title
16141 * Title text to display (defaults to ''). This can be any valid HTML markup.
16145 * @cfg {String} text
16146 * Body text to display (defaults to ''). This can be any valid HTML markup.
16150 * @cfg {String} cls
16151 * A CSS class to apply to the base quick tip element (defaults to '').
16155 * @cfg {Number} width
16156 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16157 * minWidth or maxWidth.
16162 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16163 * or display QuickTips in a page.
16166 tm = Roo.QuickTips;
16167 cfg = tm.tagConfig;
16169 if(!Roo.isReady){ // allow calling of init() before onReady
16170 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16173 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16174 el.fxDefaults = {stopFx: true};
16175 // maximum custom styling
16176 //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>');
16177 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>');
16178 tipTitle = el.child('h3');
16179 tipTitle.enableDisplayMode("block");
16180 tipBody = el.child('div.x-tip-bd');
16181 tipBodyText = el.child('div.x-tip-bd-inner');
16182 //bdLeft = el.child('div.x-tip-bd-left');
16183 //bdRight = el.child('div.x-tip-bd-right');
16184 close = el.child('div.x-tip-close');
16185 close.enableDisplayMode("block");
16186 close.on("click", hide);
16187 var d = Roo.get(document);
16188 d.on("mousedown", onDown);
16189 d.on("mouseover", onOver);
16190 d.on("mouseout", onOut);
16191 d.on("mousemove", onMove);
16192 esc = d.addKeyListener(27, hide);
16195 dd = el.initDD("default", null, {
16196 onDrag : function(){
16200 dd.setHandleElId(tipTitle.id);
16209 * Configures a new quick tip instance and assigns it to a target element. The following config options
16212 Property Type Description
16213 ---------- --------------------- ------------------------------------------------------------------------
16214 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16216 * @param {Object} config The config object
16218 register : function(config){
16219 var cs = config instanceof Array ? config : arguments;
16220 for(var i = 0, len = cs.length; i < len; i++) {
16222 var target = c.target;
16224 if(target instanceof Array){
16225 for(var j = 0, jlen = target.length; j < jlen; j++){
16226 tagEls[target[j]] = c;
16229 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16236 * Removes this quick tip from its element and destroys it.
16237 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16239 unregister : function(el){
16240 delete tagEls[Roo.id(el)];
16244 * Enable this quick tip.
16246 enable : function(){
16247 if(inited && disabled){
16249 if(locks.length < 1){
16256 * Disable this quick tip.
16258 disable : function(){
16260 clearTimeout(showProc);
16261 clearTimeout(hideProc);
16262 clearTimeout(dismissProc);
16270 * Returns true if the quick tip is enabled, else false.
16272 isEnabled : function(){
16279 attribute : "qtip",
16289 // backwards compat
16290 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16292 * Ext JS Library 1.1.1
16293 * Copyright(c) 2006-2007, Ext JS, LLC.
16295 * Originally Released Under LGPL - original licence link has changed is not relivant.
16298 * <script type="text/javascript">
16303 * @class Roo.tree.TreePanel
16304 * @extends Roo.data.Tree
16306 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16307 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16308 * @cfg {Boolean} enableDD true to enable drag and drop
16309 * @cfg {Boolean} enableDrag true to enable just drag
16310 * @cfg {Boolean} enableDrop true to enable just drop
16311 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16312 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16313 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16314 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16315 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16316 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16317 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16318 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16319 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16320 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16321 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16322 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16323 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16324 * @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>
16325 * @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>
16328 * @param {String/HTMLElement/Element} el The container element
16329 * @param {Object} config
16331 Roo.tree.TreePanel = function(el, config){
16333 var loader = false;
16335 root = config.root;
16336 delete config.root;
16338 if (config.loader) {
16339 loader = config.loader;
16340 delete config.loader;
16343 Roo.apply(this, config);
16344 Roo.tree.TreePanel.superclass.constructor.call(this);
16345 this.el = Roo.get(el);
16346 this.el.addClass('x-tree');
16347 //console.log(root);
16349 this.setRootNode( Roo.factory(root, Roo.tree));
16352 this.loader = Roo.factory(loader, Roo.tree);
16355 * Read-only. The id of the container element becomes this TreePanel's id.
16357 this.id = this.el.id;
16360 * @event beforeload
16361 * Fires before a node is loaded, return false to cancel
16362 * @param {Node} node The node being loaded
16364 "beforeload" : true,
16367 * Fires when a node is loaded
16368 * @param {Node} node The node that was loaded
16372 * @event textchange
16373 * Fires when the text for a node is changed
16374 * @param {Node} node The node
16375 * @param {String} text The new text
16376 * @param {String} oldText The old text
16378 "textchange" : true,
16380 * @event beforeexpand
16381 * Fires before a node is expanded, return false to cancel.
16382 * @param {Node} node The node
16383 * @param {Boolean} deep
16384 * @param {Boolean} anim
16386 "beforeexpand" : true,
16388 * @event beforecollapse
16389 * Fires before a node is collapsed, return false to cancel.
16390 * @param {Node} node The node
16391 * @param {Boolean} deep
16392 * @param {Boolean} anim
16394 "beforecollapse" : true,
16397 * Fires when a node is expanded
16398 * @param {Node} node The node
16402 * @event disabledchange
16403 * Fires when the disabled status of a node changes
16404 * @param {Node} node The node
16405 * @param {Boolean} disabled
16407 "disabledchange" : true,
16410 * Fires when a node is collapsed
16411 * @param {Node} node The node
16415 * @event beforeclick
16416 * Fires before click processing on a node. Return false to cancel the default action.
16417 * @param {Node} node The node
16418 * @param {Roo.EventObject} e The event object
16420 "beforeclick":true,
16422 * @event checkchange
16423 * Fires when a node with a checkbox's checked property changes
16424 * @param {Node} this This node
16425 * @param {Boolean} checked
16427 "checkchange":true,
16430 * Fires when a node is clicked
16431 * @param {Node} node The node
16432 * @param {Roo.EventObject} e The event object
16437 * Fires when a node is double clicked
16438 * @param {Node} node The node
16439 * @param {Roo.EventObject} e The event object
16443 * @event contextmenu
16444 * Fires when a node is right clicked
16445 * @param {Node} node The node
16446 * @param {Roo.EventObject} e The event object
16448 "contextmenu":true,
16450 * @event beforechildrenrendered
16451 * Fires right before the child nodes for a node are rendered
16452 * @param {Node} node The node
16454 "beforechildrenrendered":true,
16457 * Fires when a node starts being dragged
16458 * @param {Roo.tree.TreePanel} this
16459 * @param {Roo.tree.TreeNode} node
16460 * @param {event} e The raw browser event
16462 "startdrag" : true,
16465 * Fires when a drag operation is complete
16466 * @param {Roo.tree.TreePanel} this
16467 * @param {Roo.tree.TreeNode} node
16468 * @param {event} e The raw browser event
16473 * Fires when a dragged node is dropped on a valid DD target
16474 * @param {Roo.tree.TreePanel} this
16475 * @param {Roo.tree.TreeNode} node
16476 * @param {DD} dd The dd it was dropped on
16477 * @param {event} e The raw browser event
16481 * @event beforenodedrop
16482 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16483 * passed to handlers has the following properties:<br />
16484 * <ul style="padding:5px;padding-left:16px;">
16485 * <li>tree - The TreePanel</li>
16486 * <li>target - The node being targeted for the drop</li>
16487 * <li>data - The drag data from the drag source</li>
16488 * <li>point - The point of the drop - append, above or below</li>
16489 * <li>source - The drag source</li>
16490 * <li>rawEvent - Raw mouse event</li>
16491 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16492 * to be inserted by setting them on this object.</li>
16493 * <li>cancel - Set this to true to cancel the drop.</li>
16495 * @param {Object} dropEvent
16497 "beforenodedrop" : true,
16500 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16501 * passed to handlers has the following properties:<br />
16502 * <ul style="padding:5px;padding-left:16px;">
16503 * <li>tree - The TreePanel</li>
16504 * <li>target - The node being targeted for the drop</li>
16505 * <li>data - The drag data from the drag source</li>
16506 * <li>point - The point of the drop - append, above or below</li>
16507 * <li>source - The drag source</li>
16508 * <li>rawEvent - Raw mouse event</li>
16509 * <li>dropNode - Dropped node(s).</li>
16511 * @param {Object} dropEvent
16515 * @event nodedragover
16516 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16517 * passed to handlers has the following properties:<br />
16518 * <ul style="padding:5px;padding-left:16px;">
16519 * <li>tree - The TreePanel</li>
16520 * <li>target - The node being targeted for the drop</li>
16521 * <li>data - The drag data from the drag source</li>
16522 * <li>point - The point of the drop - append, above or below</li>
16523 * <li>source - The drag source</li>
16524 * <li>rawEvent - Raw mouse event</li>
16525 * <li>dropNode - Drop node(s) provided by the source.</li>
16526 * <li>cancel - Set this to true to signal drop not allowed.</li>
16528 * @param {Object} dragOverEvent
16530 "nodedragover" : true
16533 if(this.singleExpand){
16534 this.on("beforeexpand", this.restrictExpand, this);
16537 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16538 rootVisible : true,
16539 animate: Roo.enableFx,
16542 hlDrop : Roo.enableFx,
16546 rendererTip: false,
16548 restrictExpand : function(node){
16549 var p = node.parentNode;
16551 if(p.expandedChild && p.expandedChild.parentNode == p){
16552 p.expandedChild.collapse();
16554 p.expandedChild = node;
16558 // private override
16559 setRootNode : function(node){
16560 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16561 if(!this.rootVisible){
16562 node.ui = new Roo.tree.RootTreeNodeUI(node);
16568 * Returns the container element for this TreePanel
16570 getEl : function(){
16575 * Returns the default TreeLoader for this TreePanel
16577 getLoader : function(){
16578 return this.loader;
16584 expandAll : function(){
16585 this.root.expand(true);
16589 * Collapse all nodes
16591 collapseAll : function(){
16592 this.root.collapse(true);
16596 * Returns the selection model used by this TreePanel
16598 getSelectionModel : function(){
16599 if(!this.selModel){
16600 this.selModel = new Roo.tree.DefaultSelectionModel();
16602 return this.selModel;
16606 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16607 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16608 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16611 getChecked : function(a, startNode){
16612 startNode = startNode || this.root;
16614 var f = function(){
16615 if(this.attributes.checked){
16616 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16619 startNode.cascade(f);
16624 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16625 * @param {String} path
16626 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16627 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16628 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16630 expandPath : function(path, attr, callback){
16631 attr = attr || "id";
16632 var keys = path.split(this.pathSeparator);
16633 var curNode = this.root;
16634 if(curNode.attributes[attr] != keys[1]){ // invalid root
16636 callback(false, null);
16641 var f = function(){
16642 if(++index == keys.length){
16644 callback(true, curNode);
16648 var c = curNode.findChild(attr, keys[index]);
16651 callback(false, curNode);
16656 c.expand(false, false, f);
16658 curNode.expand(false, false, f);
16662 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16663 * @param {String} path
16664 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16665 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16666 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16668 selectPath : function(path, attr, callback){
16669 attr = attr || "id";
16670 var keys = path.split(this.pathSeparator);
16671 var v = keys.pop();
16672 if(keys.length > 0){
16673 var f = function(success, node){
16674 if(success && node){
16675 var n = node.findChild(attr, v);
16681 }else if(callback){
16682 callback(false, n);
16686 callback(false, n);
16690 this.expandPath(keys.join(this.pathSeparator), attr, f);
16692 this.root.select();
16694 callback(true, this.root);
16699 getTreeEl : function(){
16704 * Trigger rendering of this TreePanel
16706 render : function(){
16707 if (this.innerCt) {
16708 return this; // stop it rendering more than once!!
16711 this.innerCt = this.el.createChild({tag:"ul",
16712 cls:"x-tree-root-ct " +
16713 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16715 if(this.containerScroll){
16716 Roo.dd.ScrollManager.register(this.el);
16718 if((this.enableDD || this.enableDrop) && !this.dropZone){
16720 * The dropZone used by this tree if drop is enabled
16721 * @type Roo.tree.TreeDropZone
16723 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16724 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16727 if((this.enableDD || this.enableDrag) && !this.dragZone){
16729 * The dragZone used by this tree if drag is enabled
16730 * @type Roo.tree.TreeDragZone
16732 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16733 ddGroup: this.ddGroup || "TreeDD",
16734 scroll: this.ddScroll
16737 this.getSelectionModel().init(this);
16739 console.log("ROOT not set in tree");
16742 this.root.render();
16743 if(!this.rootVisible){
16744 this.root.renderChildren();
16750 * Ext JS Library 1.1.1
16751 * Copyright(c) 2006-2007, Ext JS, LLC.
16753 * Originally Released Under LGPL - original licence link has changed is not relivant.
16756 * <script type="text/javascript">
16761 * @class Roo.tree.DefaultSelectionModel
16762 * @extends Roo.util.Observable
16763 * The default single selection for a TreePanel.
16765 Roo.tree.DefaultSelectionModel = function(){
16766 this.selNode = null;
16770 * @event selectionchange
16771 * Fires when the selected node changes
16772 * @param {DefaultSelectionModel} this
16773 * @param {TreeNode} node the new selection
16775 "selectionchange" : true,
16778 * @event beforeselect
16779 * Fires before the selected node changes, return false to cancel the change
16780 * @param {DefaultSelectionModel} this
16781 * @param {TreeNode} node the new selection
16782 * @param {TreeNode} node the old selection
16784 "beforeselect" : true
16788 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16789 init : function(tree){
16791 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16792 tree.on("click", this.onNodeClick, this);
16795 onNodeClick : function(node, e){
16796 if (e.ctrlKey && this.selNode == node) {
16797 this.unselect(node);
16805 * @param {TreeNode} node The node to select
16806 * @return {TreeNode} The selected node
16808 select : function(node){
16809 var last = this.selNode;
16810 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16812 last.ui.onSelectedChange(false);
16814 this.selNode = node;
16815 node.ui.onSelectedChange(true);
16816 this.fireEvent("selectionchange", this, node, last);
16823 * @param {TreeNode} node The node to unselect
16825 unselect : function(node){
16826 if(this.selNode == node){
16827 this.clearSelections();
16832 * Clear all selections
16834 clearSelections : function(){
16835 var n = this.selNode;
16837 n.ui.onSelectedChange(false);
16838 this.selNode = null;
16839 this.fireEvent("selectionchange", this, null);
16845 * Get the selected node
16846 * @return {TreeNode} The selected node
16848 getSelectedNode : function(){
16849 return this.selNode;
16853 * Returns true if the node is selected
16854 * @param {TreeNode} node The node to check
16855 * @return {Boolean}
16857 isSelected : function(node){
16858 return this.selNode == node;
16862 * Selects the node above the selected node in the tree, intelligently walking the nodes
16863 * @return TreeNode The new selection
16865 selectPrevious : function(){
16866 var s = this.selNode || this.lastSelNode;
16870 var ps = s.previousSibling;
16872 if(!ps.isExpanded() || ps.childNodes.length < 1){
16873 return this.select(ps);
16875 var lc = ps.lastChild;
16876 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16879 return this.select(lc);
16881 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16882 return this.select(s.parentNode);
16888 * Selects the node above the selected node in the tree, intelligently walking the nodes
16889 * @return TreeNode The new selection
16891 selectNext : function(){
16892 var s = this.selNode || this.lastSelNode;
16896 if(s.firstChild && s.isExpanded()){
16897 return this.select(s.firstChild);
16898 }else if(s.nextSibling){
16899 return this.select(s.nextSibling);
16900 }else if(s.parentNode){
16902 s.parentNode.bubble(function(){
16903 if(this.nextSibling){
16904 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16913 onKeyDown : function(e){
16914 var s = this.selNode || this.lastSelNode;
16915 // undesirable, but required
16920 var k = e.getKey();
16928 this.selectPrevious();
16931 e.preventDefault();
16932 if(s.hasChildNodes()){
16933 if(!s.isExpanded()){
16935 }else if(s.firstChild){
16936 this.select(s.firstChild, e);
16941 e.preventDefault();
16942 if(s.hasChildNodes() && s.isExpanded()){
16944 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16945 this.select(s.parentNode, e);
16953 * @class Roo.tree.MultiSelectionModel
16954 * @extends Roo.util.Observable
16955 * Multi selection for a TreePanel.
16957 Roo.tree.MultiSelectionModel = function(){
16958 this.selNodes = [];
16962 * @event selectionchange
16963 * Fires when the selected nodes change
16964 * @param {MultiSelectionModel} this
16965 * @param {Array} nodes Array of the selected nodes
16967 "selectionchange" : true
16971 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16972 init : function(tree){
16974 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16975 tree.on("click", this.onNodeClick, this);
16978 onNodeClick : function(node, e){
16979 this.select(node, e, e.ctrlKey);
16984 * @param {TreeNode} node The node to select
16985 * @param {EventObject} e (optional) An event associated with the selection
16986 * @param {Boolean} keepExisting True to retain existing selections
16987 * @return {TreeNode} The selected node
16989 select : function(node, e, keepExisting){
16990 if(keepExisting !== true){
16991 this.clearSelections(true);
16993 if(this.isSelected(node)){
16994 this.lastSelNode = node;
16997 this.selNodes.push(node);
16998 this.selMap[node.id] = node;
16999 this.lastSelNode = node;
17000 node.ui.onSelectedChange(true);
17001 this.fireEvent("selectionchange", this, this.selNodes);
17007 * @param {TreeNode} node The node to unselect
17009 unselect : function(node){
17010 if(this.selMap[node.id]){
17011 node.ui.onSelectedChange(false);
17012 var sn = this.selNodes;
17015 index = sn.indexOf(node);
17017 for(var i = 0, len = sn.length; i < len; i++){
17025 this.selNodes.splice(index, 1);
17027 delete this.selMap[node.id];
17028 this.fireEvent("selectionchange", this, this.selNodes);
17033 * Clear all selections
17035 clearSelections : function(suppressEvent){
17036 var sn = this.selNodes;
17038 for(var i = 0, len = sn.length; i < len; i++){
17039 sn[i].ui.onSelectedChange(false);
17041 this.selNodes = [];
17043 if(suppressEvent !== true){
17044 this.fireEvent("selectionchange", this, this.selNodes);
17050 * Returns true if the node is selected
17051 * @param {TreeNode} node The node to check
17052 * @return {Boolean}
17054 isSelected : function(node){
17055 return this.selMap[node.id] ? true : false;
17059 * Returns an array of the selected nodes
17062 getSelectedNodes : function(){
17063 return this.selNodes;
17066 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17068 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17070 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17073 * Ext JS Library 1.1.1
17074 * Copyright(c) 2006-2007, Ext JS, LLC.
17076 * Originally Released Under LGPL - original licence link has changed is not relivant.
17079 * <script type="text/javascript">
17083 * @class Roo.tree.TreeNode
17084 * @extends Roo.data.Node
17085 * @cfg {String} text The text for this node
17086 * @cfg {Boolean} expanded true to start the node expanded
17087 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17088 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17089 * @cfg {Boolean} disabled true to start the node disabled
17090 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17091 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17092 * @cfg {String} cls A css class to be added to the node
17093 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17094 * @cfg {String} href URL of the link used for the node (defaults to #)
17095 * @cfg {String} hrefTarget target frame for the link
17096 * @cfg {String} qtip An Ext QuickTip for the node
17097 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17098 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17099 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17100 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17101 * (defaults to undefined with no checkbox rendered)
17103 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17105 Roo.tree.TreeNode = function(attributes){
17106 attributes = attributes || {};
17107 if(typeof attributes == "string"){
17108 attributes = {text: attributes};
17110 this.childrenRendered = false;
17111 this.rendered = false;
17112 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17113 this.expanded = attributes.expanded === true;
17114 this.isTarget = attributes.isTarget !== false;
17115 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17116 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17119 * Read-only. The text for this node. To change it use setText().
17122 this.text = attributes.text;
17124 * True if this node is disabled.
17127 this.disabled = attributes.disabled === true;
17131 * @event textchange
17132 * Fires when the text for this node is changed
17133 * @param {Node} this This node
17134 * @param {String} text The new text
17135 * @param {String} oldText The old text
17137 "textchange" : true,
17139 * @event beforeexpand
17140 * Fires before this node is expanded, return false to cancel.
17141 * @param {Node} this This node
17142 * @param {Boolean} deep
17143 * @param {Boolean} anim
17145 "beforeexpand" : true,
17147 * @event beforecollapse
17148 * Fires before this node is collapsed, return false to cancel.
17149 * @param {Node} this This node
17150 * @param {Boolean} deep
17151 * @param {Boolean} anim
17153 "beforecollapse" : true,
17156 * Fires when this node is expanded
17157 * @param {Node} this This node
17161 * @event disabledchange
17162 * Fires when the disabled status of this node changes
17163 * @param {Node} this This node
17164 * @param {Boolean} disabled
17166 "disabledchange" : true,
17169 * Fires when this node is collapsed
17170 * @param {Node} this This node
17174 * @event beforeclick
17175 * Fires before click processing. Return false to cancel the default action.
17176 * @param {Node} this This node
17177 * @param {Roo.EventObject} e The event object
17179 "beforeclick":true,
17181 * @event checkchange
17182 * Fires when a node with a checkbox's checked property changes
17183 * @param {Node} this This node
17184 * @param {Boolean} checked
17186 "checkchange":true,
17189 * Fires when this node is clicked
17190 * @param {Node} this This node
17191 * @param {Roo.EventObject} e The event object
17196 * Fires when this node is double clicked
17197 * @param {Node} this This node
17198 * @param {Roo.EventObject} e The event object
17202 * @event contextmenu
17203 * Fires when this node is right clicked
17204 * @param {Node} this This node
17205 * @param {Roo.EventObject} e The event object
17207 "contextmenu":true,
17209 * @event beforechildrenrendered
17210 * Fires right before the child nodes for this node are rendered
17211 * @param {Node} this This node
17213 "beforechildrenrendered":true
17216 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17219 * Read-only. The UI for this node
17222 this.ui = new uiClass(this);
17224 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17225 preventHScroll: true,
17227 * Returns true if this node is expanded
17228 * @return {Boolean}
17230 isExpanded : function(){
17231 return this.expanded;
17235 * Returns the UI object for this node
17236 * @return {TreeNodeUI}
17238 getUI : function(){
17242 // private override
17243 setFirstChild : function(node){
17244 var of = this.firstChild;
17245 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17246 if(this.childrenRendered && of && node != of){
17247 of.renderIndent(true, true);
17250 this.renderIndent(true, true);
17254 // private override
17255 setLastChild : function(node){
17256 var ol = this.lastChild;
17257 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17258 if(this.childrenRendered && ol && node != ol){
17259 ol.renderIndent(true, true);
17262 this.renderIndent(true, true);
17266 // these methods are overridden to provide lazy rendering support
17267 // private override
17268 appendChild : function(){
17269 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17270 if(node && this.childrenRendered){
17273 this.ui.updateExpandIcon();
17277 // private override
17278 removeChild : function(node){
17279 this.ownerTree.getSelectionModel().unselect(node);
17280 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17281 // if it's been rendered remove dom node
17282 if(this.childrenRendered){
17285 if(this.childNodes.length < 1){
17286 this.collapse(false, false);
17288 this.ui.updateExpandIcon();
17290 if(!this.firstChild) {
17291 this.childrenRendered = false;
17296 // private override
17297 insertBefore : function(node, refNode){
17298 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17299 if(newNode && refNode && this.childrenRendered){
17302 this.ui.updateExpandIcon();
17307 * Sets the text for this node
17308 * @param {String} text
17310 setText : function(text){
17311 var oldText = this.text;
17313 this.attributes.text = text;
17314 if(this.rendered){ // event without subscribing
17315 this.ui.onTextChange(this, text, oldText);
17317 this.fireEvent("textchange", this, text, oldText);
17321 * Triggers selection of this node
17323 select : function(){
17324 this.getOwnerTree().getSelectionModel().select(this);
17328 * Triggers deselection of this node
17330 unselect : function(){
17331 this.getOwnerTree().getSelectionModel().unselect(this);
17335 * Returns true if this node is selected
17336 * @return {Boolean}
17338 isSelected : function(){
17339 return this.getOwnerTree().getSelectionModel().isSelected(this);
17343 * Expand this node.
17344 * @param {Boolean} deep (optional) True to expand all children as well
17345 * @param {Boolean} anim (optional) false to cancel the default animation
17346 * @param {Function} callback (optional) A callback to be called when
17347 * expanding this node completes (does not wait for deep expand to complete).
17348 * Called with 1 parameter, this node.
17350 expand : function(deep, anim, callback){
17351 if(!this.expanded){
17352 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17355 if(!this.childrenRendered){
17356 this.renderChildren();
17358 this.expanded = true;
17359 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17360 this.ui.animExpand(function(){
17361 this.fireEvent("expand", this);
17362 if(typeof callback == "function"){
17366 this.expandChildNodes(true);
17368 }.createDelegate(this));
17372 this.fireEvent("expand", this);
17373 if(typeof callback == "function"){
17378 if(typeof callback == "function"){
17383 this.expandChildNodes(true);
17387 isHiddenRoot : function(){
17388 return this.isRoot && !this.getOwnerTree().rootVisible;
17392 * Collapse this node.
17393 * @param {Boolean} deep (optional) True to collapse all children as well
17394 * @param {Boolean} anim (optional) false to cancel the default animation
17396 collapse : function(deep, anim){
17397 if(this.expanded && !this.isHiddenRoot()){
17398 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17401 this.expanded = false;
17402 if((this.getOwnerTree().animate && anim !== false) || anim){
17403 this.ui.animCollapse(function(){
17404 this.fireEvent("collapse", this);
17406 this.collapseChildNodes(true);
17408 }.createDelegate(this));
17411 this.ui.collapse();
17412 this.fireEvent("collapse", this);
17416 var cs = this.childNodes;
17417 for(var i = 0, len = cs.length; i < len; i++) {
17418 cs[i].collapse(true, false);
17424 delayedExpand : function(delay){
17425 if(!this.expandProcId){
17426 this.expandProcId = this.expand.defer(delay, this);
17431 cancelExpand : function(){
17432 if(this.expandProcId){
17433 clearTimeout(this.expandProcId);
17435 this.expandProcId = false;
17439 * Toggles expanded/collapsed state of the node
17441 toggle : function(){
17450 * Ensures all parent nodes are expanded
17452 ensureVisible : function(callback){
17453 var tree = this.getOwnerTree();
17454 tree.expandPath(this.parentNode.getPath(), false, function(){
17455 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17456 Roo.callback(callback);
17457 }.createDelegate(this));
17461 * Expand all child nodes
17462 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17464 expandChildNodes : function(deep){
17465 var cs = this.childNodes;
17466 for(var i = 0, len = cs.length; i < len; i++) {
17467 cs[i].expand(deep);
17472 * Collapse all child nodes
17473 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17475 collapseChildNodes : function(deep){
17476 var cs = this.childNodes;
17477 for(var i = 0, len = cs.length; i < len; i++) {
17478 cs[i].collapse(deep);
17483 * Disables this node
17485 disable : function(){
17486 this.disabled = true;
17488 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17489 this.ui.onDisableChange(this, true);
17491 this.fireEvent("disabledchange", this, true);
17495 * Enables this node
17497 enable : function(){
17498 this.disabled = false;
17499 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17500 this.ui.onDisableChange(this, false);
17502 this.fireEvent("disabledchange", this, false);
17506 renderChildren : function(suppressEvent){
17507 if(suppressEvent !== false){
17508 this.fireEvent("beforechildrenrendered", this);
17510 var cs = this.childNodes;
17511 for(var i = 0, len = cs.length; i < len; i++){
17512 cs[i].render(true);
17514 this.childrenRendered = true;
17518 sort : function(fn, scope){
17519 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17520 if(this.childrenRendered){
17521 var cs = this.childNodes;
17522 for(var i = 0, len = cs.length; i < len; i++){
17523 cs[i].render(true);
17529 render : function(bulkRender){
17530 this.ui.render(bulkRender);
17531 if(!this.rendered){
17532 this.rendered = true;
17534 this.expanded = false;
17535 this.expand(false, false);
17541 renderIndent : function(deep, refresh){
17543 this.ui.childIndent = null;
17545 this.ui.renderIndent();
17546 if(deep === true && this.childrenRendered){
17547 var cs = this.childNodes;
17548 for(var i = 0, len = cs.length; i < len; i++){
17549 cs[i].renderIndent(true, refresh);
17555 * Ext JS Library 1.1.1
17556 * Copyright(c) 2006-2007, Ext JS, LLC.
17558 * Originally Released Under LGPL - original licence link has changed is not relivant.
17561 * <script type="text/javascript">
17565 * @class Roo.tree.AsyncTreeNode
17566 * @extends Roo.tree.TreeNode
17567 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17569 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17571 Roo.tree.AsyncTreeNode = function(config){
17572 this.loaded = false;
17573 this.loading = false;
17574 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17576 * @event beforeload
17577 * Fires before this node is loaded, return false to cancel
17578 * @param {Node} this This node
17580 this.addEvents({'beforeload':true, 'load': true});
17583 * Fires when this node is loaded
17584 * @param {Node} this This node
17587 * The loader used by this node (defaults to using the tree's defined loader)
17592 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17593 expand : function(deep, anim, callback){
17594 if(this.loading){ // if an async load is already running, waiting til it's done
17596 var f = function(){
17597 if(!this.loading){ // done loading
17598 clearInterval(timer);
17599 this.expand(deep, anim, callback);
17601 }.createDelegate(this);
17602 timer = setInterval(f, 200);
17606 if(this.fireEvent("beforeload", this) === false){
17609 this.loading = true;
17610 this.ui.beforeLoad(this);
17611 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17613 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17617 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17621 * Returns true if this node is currently loading
17622 * @return {Boolean}
17624 isLoading : function(){
17625 return this.loading;
17628 loadComplete : function(deep, anim, callback){
17629 this.loading = false;
17630 this.loaded = true;
17631 this.ui.afterLoad(this);
17632 this.fireEvent("load", this);
17633 this.expand(deep, anim, callback);
17637 * Returns true if this node has been loaded
17638 * @return {Boolean}
17640 isLoaded : function(){
17641 return this.loaded;
17644 hasChildNodes : function(){
17645 if(!this.isLeaf() && !this.loaded){
17648 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17653 * Trigger a reload for this node
17654 * @param {Function} callback
17656 reload : function(callback){
17657 this.collapse(false, false);
17658 while(this.firstChild){
17659 this.removeChild(this.firstChild);
17661 this.childrenRendered = false;
17662 this.loaded = false;
17663 if(this.isHiddenRoot()){
17664 this.expanded = false;
17666 this.expand(false, false, callback);
17670 * Ext JS Library 1.1.1
17671 * Copyright(c) 2006-2007, Ext JS, LLC.
17673 * Originally Released Under LGPL - original licence link has changed is not relivant.
17676 * <script type="text/javascript">
17680 * @class Roo.tree.TreeNodeUI
17682 * @param {Object} node The node to render
17683 * The TreeNode UI implementation is separate from the
17684 * tree implementation. Unless you are customizing the tree UI,
17685 * you should never have to use this directly.
17687 Roo.tree.TreeNodeUI = function(node){
17689 this.rendered = false;
17690 this.animating = false;
17691 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17694 Roo.tree.TreeNodeUI.prototype = {
17695 removeChild : function(node){
17697 this.ctNode.removeChild(node.ui.getEl());
17701 beforeLoad : function(){
17702 this.addClass("x-tree-node-loading");
17705 afterLoad : function(){
17706 this.removeClass("x-tree-node-loading");
17709 onTextChange : function(node, text, oldText){
17711 this.textNode.innerHTML = text;
17715 onDisableChange : function(node, state){
17716 this.disabled = state;
17718 this.addClass("x-tree-node-disabled");
17720 this.removeClass("x-tree-node-disabled");
17724 onSelectedChange : function(state){
17727 this.addClass("x-tree-selected");
17730 this.removeClass("x-tree-selected");
17734 onMove : function(tree, node, oldParent, newParent, index, refNode){
17735 this.childIndent = null;
17737 var targetNode = newParent.ui.getContainer();
17738 if(!targetNode){//target not rendered
17739 this.holder = document.createElement("div");
17740 this.holder.appendChild(this.wrap);
17743 var insertBefore = refNode ? refNode.ui.getEl() : null;
17745 targetNode.insertBefore(this.wrap, insertBefore);
17747 targetNode.appendChild(this.wrap);
17749 this.node.renderIndent(true);
17753 addClass : function(cls){
17755 Roo.fly(this.elNode).addClass(cls);
17759 removeClass : function(cls){
17761 Roo.fly(this.elNode).removeClass(cls);
17765 remove : function(){
17767 this.holder = document.createElement("div");
17768 this.holder.appendChild(this.wrap);
17772 fireEvent : function(){
17773 return this.node.fireEvent.apply(this.node, arguments);
17776 initEvents : function(){
17777 this.node.on("move", this.onMove, this);
17778 var E = Roo.EventManager;
17779 var a = this.anchor;
17781 var el = Roo.fly(a, '_treeui');
17783 if(Roo.isOpera){ // opera render bug ignores the CSS
17784 el.setStyle("text-decoration", "none");
17787 el.on("click", this.onClick, this);
17788 el.on("dblclick", this.onDblClick, this);
17791 Roo.EventManager.on(this.checkbox,
17792 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17795 el.on("contextmenu", this.onContextMenu, this);
17797 var icon = Roo.fly(this.iconNode);
17798 icon.on("click", this.onClick, this);
17799 icon.on("dblclick", this.onDblClick, this);
17800 icon.on("contextmenu", this.onContextMenu, this);
17801 E.on(this.ecNode, "click", this.ecClick, this, true);
17803 if(this.node.disabled){
17804 this.addClass("x-tree-node-disabled");
17806 if(this.node.hidden){
17807 this.addClass("x-tree-node-disabled");
17809 var ot = this.node.getOwnerTree();
17810 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17811 if(dd && (!this.node.isRoot || ot.rootVisible)){
17812 Roo.dd.Registry.register(this.elNode, {
17814 handles: this.getDDHandles(),
17820 getDDHandles : function(){
17821 return [this.iconNode, this.textNode];
17826 this.wrap.style.display = "none";
17832 this.wrap.style.display = "";
17836 onContextMenu : function(e){
17837 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17838 e.preventDefault();
17840 this.fireEvent("contextmenu", this.node, e);
17844 onClick : function(e){
17849 if(this.fireEvent("beforeclick", this.node, e) !== false){
17850 if(!this.disabled && this.node.attributes.href){
17851 this.fireEvent("click", this.node, e);
17854 e.preventDefault();
17859 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17860 this.node.toggle();
17863 this.fireEvent("click", this.node, e);
17869 onDblClick : function(e){
17870 e.preventDefault();
17875 this.toggleCheck();
17877 if(!this.animating && this.node.hasChildNodes()){
17878 this.node.toggle();
17880 this.fireEvent("dblclick", this.node, e);
17883 onCheckChange : function(){
17884 var checked = this.checkbox.checked;
17885 this.node.attributes.checked = checked;
17886 this.fireEvent('checkchange', this.node, checked);
17889 ecClick : function(e){
17890 if(!this.animating && this.node.hasChildNodes()){
17891 this.node.toggle();
17895 startDrop : function(){
17896 this.dropping = true;
17899 // delayed drop so the click event doesn't get fired on a drop
17900 endDrop : function(){
17901 setTimeout(function(){
17902 this.dropping = false;
17903 }.createDelegate(this), 50);
17906 expand : function(){
17907 this.updateExpandIcon();
17908 this.ctNode.style.display = "";
17911 focus : function(){
17912 if(!this.node.preventHScroll){
17913 try{this.anchor.focus();
17915 }else if(!Roo.isIE){
17917 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17918 var l = noscroll.scrollLeft;
17919 this.anchor.focus();
17920 noscroll.scrollLeft = l;
17925 toggleCheck : function(value){
17926 var cb = this.checkbox;
17928 cb.checked = (value === undefined ? !cb.checked : value);
17934 this.anchor.blur();
17938 animExpand : function(callback){
17939 var ct = Roo.get(this.ctNode);
17941 if(!this.node.hasChildNodes()){
17942 this.updateExpandIcon();
17943 this.ctNode.style.display = "";
17944 Roo.callback(callback);
17947 this.animating = true;
17948 this.updateExpandIcon();
17951 callback : function(){
17952 this.animating = false;
17953 Roo.callback(callback);
17956 duration: this.node.ownerTree.duration || .25
17960 highlight : function(){
17961 var tree = this.node.getOwnerTree();
17962 Roo.fly(this.wrap).highlight(
17963 tree.hlColor || "C3DAF9",
17964 {endColor: tree.hlBaseColor}
17968 collapse : function(){
17969 this.updateExpandIcon();
17970 this.ctNode.style.display = "none";
17973 animCollapse : function(callback){
17974 var ct = Roo.get(this.ctNode);
17975 ct.enableDisplayMode('block');
17978 this.animating = true;
17979 this.updateExpandIcon();
17982 callback : function(){
17983 this.animating = false;
17984 Roo.callback(callback);
17987 duration: this.node.ownerTree.duration || .25
17991 getContainer : function(){
17992 return this.ctNode;
17995 getEl : function(){
17999 appendDDGhost : function(ghostNode){
18000 ghostNode.appendChild(this.elNode.cloneNode(true));
18003 getDDRepairXY : function(){
18004 return Roo.lib.Dom.getXY(this.iconNode);
18007 onRender : function(){
18011 render : function(bulkRender){
18012 var n = this.node, a = n.attributes;
18013 var targetNode = n.parentNode ?
18014 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
18016 if(!this.rendered){
18017 this.rendered = true;
18019 this.renderElements(n, a, targetNode, bulkRender);
18022 if(this.textNode.setAttributeNS){
18023 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
18025 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
18028 this.textNode.setAttribute("ext:qtip", a.qtip);
18030 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
18033 }else if(a.qtipCfg){
18034 a.qtipCfg.target = Roo.id(this.textNode);
18035 Roo.QuickTips.register(a.qtipCfg);
18038 if(!this.node.expanded){
18039 this.updateExpandIcon();
18042 if(bulkRender === true) {
18043 targetNode.appendChild(this.wrap);
18048 renderElements : function(n, a, targetNode, bulkRender){
18049 // add some indent caching, this helps performance when rendering a large tree
18050 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18051 var t = n.getOwnerTree();
18052 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18053 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18054 var cb = typeof a.checked == 'boolean';
18055 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18056 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18057 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18058 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18059 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18060 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18061 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18062 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18063 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18064 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18067 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18068 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18069 n.nextSibling.ui.getEl(), buf.join(""));
18071 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18074 this.elNode = this.wrap.childNodes[0];
18075 this.ctNode = this.wrap.childNodes[1];
18076 var cs = this.elNode.childNodes;
18077 this.indentNode = cs[0];
18078 this.ecNode = cs[1];
18079 this.iconNode = cs[2];
18082 this.checkbox = cs[3];
18085 this.anchor = cs[index];
18086 this.textNode = cs[index].firstChild;
18089 getAnchor : function(){
18090 return this.anchor;
18093 getTextEl : function(){
18094 return this.textNode;
18097 getIconEl : function(){
18098 return this.iconNode;
18101 isChecked : function(){
18102 return this.checkbox ? this.checkbox.checked : false;
18105 updateExpandIcon : function(){
18107 var n = this.node, c1, c2;
18108 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18109 var hasChild = n.hasChildNodes();
18113 c1 = "x-tree-node-collapsed";
18114 c2 = "x-tree-node-expanded";
18117 c1 = "x-tree-node-expanded";
18118 c2 = "x-tree-node-collapsed";
18121 this.removeClass("x-tree-node-leaf");
18122 this.wasLeaf = false;
18124 if(this.c1 != c1 || this.c2 != c2){
18125 Roo.fly(this.elNode).replaceClass(c1, c2);
18126 this.c1 = c1; this.c2 = c2;
18130 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18133 this.wasLeaf = true;
18136 var ecc = "x-tree-ec-icon "+cls;
18137 if(this.ecc != ecc){
18138 this.ecNode.className = ecc;
18144 getChildIndent : function(){
18145 if(!this.childIndent){
18149 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18151 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18153 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18158 this.childIndent = buf.join("");
18160 return this.childIndent;
18163 renderIndent : function(){
18166 var p = this.node.parentNode;
18168 indent = p.ui.getChildIndent();
18170 if(this.indentMarkup != indent){ // don't rerender if not required
18171 this.indentNode.innerHTML = indent;
18172 this.indentMarkup = indent;
18174 this.updateExpandIcon();
18179 Roo.tree.RootTreeNodeUI = function(){
18180 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18182 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18183 render : function(){
18184 if(!this.rendered){
18185 var targetNode = this.node.ownerTree.innerCt.dom;
18186 this.node.expanded = true;
18187 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18188 this.wrap = this.ctNode = targetNode.firstChild;
18191 collapse : function(){
18193 expand : function(){
18197 * Ext JS Library 1.1.1
18198 * Copyright(c) 2006-2007, Ext JS, LLC.
18200 * Originally Released Under LGPL - original licence link has changed is not relivant.
18203 * <script type="text/javascript">
18206 * @class Roo.tree.TreeLoader
18207 * @extends Roo.util.Observable
18208 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18209 * nodes from a specified URL. The response must be a javascript Array definition
18210 * who's elements are node definition objects. eg:
18212 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18213 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18216 * A server request is sent, and child nodes are loaded only when a node is expanded.
18217 * The loading node's id is passed to the server under the parameter name "node" to
18218 * enable the server to produce the correct child nodes.
18220 * To pass extra parameters, an event handler may be attached to the "beforeload"
18221 * event, and the parameters specified in the TreeLoader's baseParams property:
18223 myTreeLoader.on("beforeload", function(treeLoader, node) {
18224 this.baseParams.category = node.attributes.category;
18227 * This would pass an HTTP parameter called "category" to the server containing
18228 * the value of the Node's "category" attribute.
18230 * Creates a new Treeloader.
18231 * @param {Object} config A config object containing config properties.
18233 Roo.tree.TreeLoader = function(config){
18234 this.baseParams = {};
18235 this.requestMethod = "POST";
18236 Roo.apply(this, config);
18241 * @event beforeload
18242 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18243 * @param {Object} This TreeLoader object.
18244 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18245 * @param {Object} callback The callback function specified in the {@link #load} call.
18250 * Fires when the node has been successfuly loaded.
18251 * @param {Object} This TreeLoader object.
18252 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18253 * @param {Object} response The response object containing the data from the server.
18257 * @event loadexception
18258 * Fires if the network request failed.
18259 * @param {Object} This TreeLoader object.
18260 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18261 * @param {Object} response The response object containing the data from the server.
18263 loadexception : true,
18266 * Fires before a node is created, enabling you to return custom Node types
18267 * @param {Object} This TreeLoader object.
18268 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18273 Roo.tree.TreeLoader.superclass.constructor.call(this);
18276 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18278 * @cfg {String} dataUrl The URL from which to request a Json string which
18279 * specifies an array of node definition object representing the child nodes
18283 * @cfg {Object} baseParams (optional) An object containing properties which
18284 * specify HTTP parameters to be passed to each request for child nodes.
18287 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18288 * created by this loader. If the attributes sent by the server have an attribute in this object,
18289 * they take priority.
18292 * @cfg {Object} uiProviders (optional) An object containing properties which
18294 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18295 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18296 * <i>uiProvider</i> attribute of a returned child node is a string rather
18297 * than a reference to a TreeNodeUI implementation, this that string value
18298 * is used as a property name in the uiProviders object. You can define the provider named
18299 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18304 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18305 * child nodes before loading.
18307 clearOnLoad : true,
18310 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18311 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18312 * Grid query { data : [ .....] }
18317 * @cfg {String} queryParam (optional)
18318 * Name of the query as it will be passed on the querystring (defaults to 'node')
18319 * eg. the request will be ?node=[id]
18326 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18327 * This is called automatically when a node is expanded, but may be used to reload
18328 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18329 * @param {Roo.tree.TreeNode} node
18330 * @param {Function} callback
18332 load : function(node, callback){
18333 if(this.clearOnLoad){
18334 while(node.firstChild){
18335 node.removeChild(node.firstChild);
18338 if(node.attributes.children){ // preloaded json children
18339 var cs = node.attributes.children;
18340 for(var i = 0, len = cs.length; i < len; i++){
18341 node.appendChild(this.createNode(cs[i]));
18343 if(typeof callback == "function"){
18346 }else if(this.dataUrl){
18347 this.requestData(node, callback);
18351 getParams: function(node){
18352 var buf = [], bp = this.baseParams;
18353 for(var key in bp){
18354 if(typeof bp[key] != "function"){
18355 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18358 var n = this.queryParam === false ? 'node' : this.queryParam;
18359 buf.push(n + "=", encodeURIComponent(node.id));
18360 return buf.join("");
18363 requestData : function(node, callback){
18364 if(this.fireEvent("beforeload", this, node, callback) !== false){
18365 this.transId = Roo.Ajax.request({
18366 method:this.requestMethod,
18367 url: this.dataUrl||this.url,
18368 success: this.handleResponse,
18369 failure: this.handleFailure,
18371 argument: {callback: callback, node: node},
18372 params: this.getParams(node)
18375 // if the load is cancelled, make sure we notify
18376 // the node that we are done
18377 if(typeof callback == "function"){
18383 isLoading : function(){
18384 return this.transId ? true : false;
18387 abort : function(){
18388 if(this.isLoading()){
18389 Roo.Ajax.abort(this.transId);
18394 createNode : function(attr){
18395 // apply baseAttrs, nice idea Corey!
18396 if(this.baseAttrs){
18397 Roo.applyIf(attr, this.baseAttrs);
18399 if(this.applyLoader !== false){
18400 attr.loader = this;
18402 // uiProvider = depreciated..
18404 if(typeof(attr.uiProvider) == 'string'){
18405 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18406 /** eval:var:attr */ eval(attr.uiProvider);
18408 if(typeof(this.uiProviders['default']) != 'undefined') {
18409 attr.uiProvider = this.uiProviders['default'];
18412 this.fireEvent('create', this, attr);
18414 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18416 new Roo.tree.TreeNode(attr) :
18417 new Roo.tree.AsyncTreeNode(attr));
18420 processResponse : function(response, node, callback){
18421 var json = response.responseText;
18424 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18425 if (this.root !== false) {
18429 for(var i = 0, len = o.length; i < len; i++){
18430 var n = this.createNode(o[i]);
18432 node.appendChild(n);
18435 if(typeof callback == "function"){
18436 callback(this, node);
18439 this.handleFailure(response);
18443 handleResponse : function(response){
18444 this.transId = false;
18445 var a = response.argument;
18446 this.processResponse(response, a.node, a.callback);
18447 this.fireEvent("load", this, a.node, response);
18450 handleFailure : function(response){
18451 this.transId = false;
18452 var a = response.argument;
18453 this.fireEvent("loadexception", this, a.node, response);
18454 if(typeof a.callback == "function"){
18455 a.callback(this, a.node);
18460 * Ext JS Library 1.1.1
18461 * Copyright(c) 2006-2007, Ext JS, LLC.
18463 * Originally Released Under LGPL - original licence link has changed is not relivant.
18466 * <script type="text/javascript">
18470 * @class Roo.tree.TreeFilter
18471 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18472 * @param {TreePanel} tree
18473 * @param {Object} config (optional)
18475 Roo.tree.TreeFilter = function(tree, config){
18477 this.filtered = {};
18478 Roo.apply(this, config);
18481 Roo.tree.TreeFilter.prototype = {
18488 * Filter the data by a specific attribute.
18489 * @param {String/RegExp} value Either string that the attribute value
18490 * should start with or a RegExp to test against the attribute
18491 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18492 * @param {TreeNode} startNode (optional) The node to start the filter at.
18494 filter : function(value, attr, startNode){
18495 attr = attr || "text";
18497 if(typeof value == "string"){
18498 var vlen = value.length;
18499 // auto clear empty filter
18500 if(vlen == 0 && this.clearBlank){
18504 value = value.toLowerCase();
18506 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18508 }else if(value.exec){ // regex?
18510 return value.test(n.attributes[attr]);
18513 throw 'Illegal filter type, must be string or regex';
18515 this.filterBy(f, null, startNode);
18519 * Filter by a function. The passed function will be called with each
18520 * node in the tree (or from the startNode). If the function returns true, the node is kept
18521 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18522 * @param {Function} fn The filter function
18523 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18525 filterBy : function(fn, scope, startNode){
18526 startNode = startNode || this.tree.root;
18527 if(this.autoClear){
18530 var af = this.filtered, rv = this.reverse;
18531 var f = function(n){
18532 if(n == startNode){
18538 var m = fn.call(scope || n, n);
18546 startNode.cascade(f);
18549 if(typeof id != "function"){
18551 if(n && n.parentNode){
18552 n.parentNode.removeChild(n);
18560 * Clears the current filter. Note: with the "remove" option
18561 * set a filter cannot be cleared.
18563 clear : function(){
18565 var af = this.filtered;
18567 if(typeof id != "function"){
18574 this.filtered = {};
18579 * Ext JS Library 1.1.1
18580 * Copyright(c) 2006-2007, Ext JS, LLC.
18582 * Originally Released Under LGPL - original licence link has changed is not relivant.
18585 * <script type="text/javascript">
18590 * @class Roo.tree.TreeSorter
18591 * Provides sorting of nodes in a TreePanel
18593 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18594 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18595 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18596 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18597 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18598 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18600 * @param {TreePanel} tree
18601 * @param {Object} config
18603 Roo.tree.TreeSorter = function(tree, config){
18604 Roo.apply(this, config);
18605 tree.on("beforechildrenrendered", this.doSort, this);
18606 tree.on("append", this.updateSort, this);
18607 tree.on("insert", this.updateSort, this);
18609 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18610 var p = this.property || "text";
18611 var sortType = this.sortType;
18612 var fs = this.folderSort;
18613 var cs = this.caseSensitive === true;
18614 var leafAttr = this.leafAttr || 'leaf';
18616 this.sortFn = function(n1, n2){
18618 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18621 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18625 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18626 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18628 return dsc ? +1 : -1;
18630 return dsc ? -1 : +1;
18637 Roo.tree.TreeSorter.prototype = {
18638 doSort : function(node){
18639 node.sort(this.sortFn);
18642 compareNodes : function(n1, n2){
18643 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18646 updateSort : function(tree, node){
18647 if(node.childrenRendered){
18648 this.doSort.defer(1, this, [node]);
18653 * Ext JS Library 1.1.1
18654 * Copyright(c) 2006-2007, Ext JS, LLC.
18656 * Originally Released Under LGPL - original licence link has changed is not relivant.
18659 * <script type="text/javascript">
18662 if(Roo.dd.DropZone){
18664 Roo.tree.TreeDropZone = function(tree, config){
18665 this.allowParentInsert = false;
18666 this.allowContainerDrop = false;
18667 this.appendOnly = false;
18668 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18670 this.lastInsertClass = "x-tree-no-status";
18671 this.dragOverData = {};
18674 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18675 ddGroup : "TreeDD",
18677 expandDelay : 1000,
18679 expandNode : function(node){
18680 if(node.hasChildNodes() && !node.isExpanded()){
18681 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18685 queueExpand : function(node){
18686 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18689 cancelExpand : function(){
18690 if(this.expandProcId){
18691 clearTimeout(this.expandProcId);
18692 this.expandProcId = false;
18696 isValidDropPoint : function(n, pt, dd, e, data){
18697 if(!n || !data){ return false; }
18698 var targetNode = n.node;
18699 var dropNode = data.node;
18700 // default drop rules
18701 if(!(targetNode && targetNode.isTarget && pt)){
18704 if(pt == "append" && targetNode.allowChildren === false){
18707 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18710 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18713 // reuse the object
18714 var overEvent = this.dragOverData;
18715 overEvent.tree = this.tree;
18716 overEvent.target = targetNode;
18717 overEvent.data = data;
18718 overEvent.point = pt;
18719 overEvent.source = dd;
18720 overEvent.rawEvent = e;
18721 overEvent.dropNode = dropNode;
18722 overEvent.cancel = false;
18723 var result = this.tree.fireEvent("nodedragover", overEvent);
18724 return overEvent.cancel === false && result !== false;
18727 getDropPoint : function(e, n, dd){
18730 return tn.allowChildren !== false ? "append" : false; // always append for root
18732 var dragEl = n.ddel;
18733 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18734 var y = Roo.lib.Event.getPageY(e);
18735 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18737 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18738 var noAppend = tn.allowChildren === false;
18739 if(this.appendOnly || tn.parentNode.allowChildren === false){
18740 return noAppend ? false : "append";
18742 var noBelow = false;
18743 if(!this.allowParentInsert){
18744 noBelow = tn.hasChildNodes() && tn.isExpanded();
18746 var q = (b - t) / (noAppend ? 2 : 3);
18747 if(y >= t && y < (t + q)){
18749 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18756 onNodeEnter : function(n, dd, e, data){
18757 this.cancelExpand();
18760 onNodeOver : function(n, dd, e, data){
18761 var pt = this.getDropPoint(e, n, dd);
18764 // auto node expand check
18765 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18766 this.queueExpand(node);
18767 }else if(pt != "append"){
18768 this.cancelExpand();
18771 // set the insert point style on the target node
18772 var returnCls = this.dropNotAllowed;
18773 if(this.isValidDropPoint(n, pt, dd, e, data)){
18778 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18779 cls = "x-tree-drag-insert-above";
18780 }else if(pt == "below"){
18781 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18782 cls = "x-tree-drag-insert-below";
18784 returnCls = "x-tree-drop-ok-append";
18785 cls = "x-tree-drag-append";
18787 if(this.lastInsertClass != cls){
18788 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18789 this.lastInsertClass = cls;
18796 onNodeOut : function(n, dd, e, data){
18797 this.cancelExpand();
18798 this.removeDropIndicators(n);
18801 onNodeDrop : function(n, dd, e, data){
18802 var point = this.getDropPoint(e, n, dd);
18803 var targetNode = n.node;
18804 targetNode.ui.startDrop();
18805 if(!this.isValidDropPoint(n, point, dd, e, data)){
18806 targetNode.ui.endDrop();
18809 // first try to find the drop node
18810 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18813 target: targetNode,
18818 dropNode: dropNode,
18821 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18822 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18823 targetNode.ui.endDrop();
18826 // allow target changing
18827 targetNode = dropEvent.target;
18828 if(point == "append" && !targetNode.isExpanded()){
18829 targetNode.expand(false, null, function(){
18830 this.completeDrop(dropEvent);
18831 }.createDelegate(this));
18833 this.completeDrop(dropEvent);
18838 completeDrop : function(de){
18839 var ns = de.dropNode, p = de.point, t = de.target;
18840 if(!(ns instanceof Array)){
18844 for(var i = 0, len = ns.length; i < len; i++){
18847 t.parentNode.insertBefore(n, t);
18848 }else if(p == "below"){
18849 t.parentNode.insertBefore(n, t.nextSibling);
18855 if(this.tree.hlDrop){
18859 this.tree.fireEvent("nodedrop", de);
18862 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18863 if(this.tree.hlDrop){
18864 dropNode.ui.focus();
18865 dropNode.ui.highlight();
18867 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18870 getTree : function(){
18874 removeDropIndicators : function(n){
18877 Roo.fly(el).removeClass([
18878 "x-tree-drag-insert-above",
18879 "x-tree-drag-insert-below",
18880 "x-tree-drag-append"]);
18881 this.lastInsertClass = "_noclass";
18885 beforeDragDrop : function(target, e, id){
18886 this.cancelExpand();
18890 afterRepair : function(data){
18891 if(data && Roo.enableFx){
18892 data.node.ui.highlight();
18901 * Ext JS Library 1.1.1
18902 * Copyright(c) 2006-2007, Ext JS, LLC.
18904 * Originally Released Under LGPL - original licence link has changed is not relivant.
18907 * <script type="text/javascript">
18911 if(Roo.dd.DragZone){
18912 Roo.tree.TreeDragZone = function(tree, config){
18913 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18917 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18918 ddGroup : "TreeDD",
18920 onBeforeDrag : function(data, e){
18922 return n && n.draggable && !n.disabled;
18925 onInitDrag : function(e){
18926 var data = this.dragData;
18927 this.tree.getSelectionModel().select(data.node);
18928 this.proxy.update("");
18929 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18930 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18933 getRepairXY : function(e, data){
18934 return data.node.ui.getDDRepairXY();
18937 onEndDrag : function(data, e){
18938 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18941 onValidDrop : function(dd, e, id){
18942 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18946 beforeInvalidDrop : function(e, id){
18947 // this scrolls the original position back into view
18948 var sm = this.tree.getSelectionModel();
18949 sm.clearSelections();
18950 sm.select(this.dragData.node);
18955 * Ext JS Library 1.1.1
18956 * Copyright(c) 2006-2007, Ext JS, LLC.
18958 * Originally Released Under LGPL - original licence link has changed is not relivant.
18961 * <script type="text/javascript">
18964 * @class Roo.tree.TreeEditor
18965 * @extends Roo.Editor
18966 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18967 * as the editor field.
18969 * @param {TreePanel} tree
18970 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18972 Roo.tree.TreeEditor = function(tree, config){
18973 config = config || {};
18974 var field = config.events ? config : new Roo.form.TextField(config);
18975 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18979 tree.on('beforeclick', this.beforeNodeClick, this);
18980 tree.getTreeEl().on('mousedown', this.hide, this);
18981 this.on('complete', this.updateNode, this);
18982 this.on('beforestartedit', this.fitToTree, this);
18983 this.on('startedit', this.bindScroll, this, {delay:10});
18984 this.on('specialkey', this.onSpecialKey, this);
18987 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18989 * @cfg {String} alignment
18990 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18996 * @cfg {Boolean} hideEl
18997 * True to hide the bound element while the editor is displayed (defaults to false)
19001 * @cfg {String} cls
19002 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
19004 cls: "x-small-editor x-tree-editor",
19006 * @cfg {Boolean} shim
19007 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
19013 * @cfg {Number} maxWidth
19014 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
19015 * the containing tree element's size, it will be automatically limited for you to the container width, taking
19016 * scroll and client offsets into account prior to each edit.
19023 fitToTree : function(ed, el){
19024 var td = this.tree.getTreeEl().dom, nd = el.dom;
19025 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
19026 td.scrollLeft = nd.offsetLeft;
19030 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
19031 this.setSize(w, '');
19035 triggerEdit : function(node){
19036 this.completeEdit();
19037 this.editNode = node;
19038 this.startEdit(node.ui.textNode, node.text);
19042 bindScroll : function(){
19043 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19047 beforeNodeClick : function(node, e){
19048 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19049 this.lastClick = new Date();
19050 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19052 this.triggerEdit(node);
19058 updateNode : function(ed, value){
19059 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19060 this.editNode.setText(value);
19064 onHide : function(){
19065 Roo.tree.TreeEditor.superclass.onHide.call(this);
19067 this.editNode.ui.focus();
19072 onSpecialKey : function(field, e){
19073 var k = e.getKey();
19077 }else if(k == e.ENTER && !e.hasModifier()){
19079 this.completeEdit();
19082 });//<Script type="text/javascript">
19085 * Ext JS Library 1.1.1
19086 * Copyright(c) 2006-2007, Ext JS, LLC.
19088 * Originally Released Under LGPL - original licence link has changed is not relivant.
19091 * <script type="text/javascript">
19095 * Not documented??? - probably should be...
19098 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19099 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19101 renderElements : function(n, a, targetNode, bulkRender){
19102 //consel.log("renderElements?");
19103 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19105 var t = n.getOwnerTree();
19106 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19108 var cols = t.columns;
19109 var bw = t.borderWidth;
19111 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19112 var cb = typeof a.checked == "boolean";
19113 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19114 var colcls = 'x-t-' + tid + '-c0';
19116 '<li class="x-tree-node">',
19119 '<div class="x-tree-node-el ', a.cls,'">',
19121 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19124 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19125 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19126 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19127 (a.icon ? ' x-tree-node-inline-icon' : ''),
19128 (a.iconCls ? ' '+a.iconCls : ''),
19129 '" unselectable="on" />',
19130 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19131 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19133 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19134 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19135 '<span unselectable="on" qtip="' + tx + '">',
19139 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19140 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19142 for(var i = 1, len = cols.length; i < len; i++){
19144 colcls = 'x-t-' + tid + '-c' +i;
19145 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19146 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19147 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19153 '<div class="x-clear"></div></div>',
19154 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19157 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19158 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19159 n.nextSibling.ui.getEl(), buf.join(""));
19161 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19163 var el = this.wrap.firstChild;
19165 this.elNode = el.firstChild;
19166 this.ranchor = el.childNodes[1];
19167 this.ctNode = this.wrap.childNodes[1];
19168 var cs = el.firstChild.childNodes;
19169 this.indentNode = cs[0];
19170 this.ecNode = cs[1];
19171 this.iconNode = cs[2];
19174 this.checkbox = cs[3];
19177 this.anchor = cs[index];
19179 this.textNode = cs[index].firstChild;
19181 //el.on("click", this.onClick, this);
19182 //el.on("dblclick", this.onDblClick, this);
19185 // console.log(this);
19187 initEvents : function(){
19188 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19191 var a = this.ranchor;
19193 var el = Roo.get(a);
19195 if(Roo.isOpera){ // opera render bug ignores the CSS
19196 el.setStyle("text-decoration", "none");
19199 el.on("click", this.onClick, this);
19200 el.on("dblclick", this.onDblClick, this);
19201 el.on("contextmenu", this.onContextMenu, this);
19205 /*onSelectedChange : function(state){
19208 this.addClass("x-tree-selected");
19211 this.removeClass("x-tree-selected");
19214 addClass : function(cls){
19216 Roo.fly(this.elRow).addClass(cls);
19222 removeClass : function(cls){
19224 Roo.fly(this.elRow).removeClass(cls);
19230 });//<Script type="text/javascript">
19234 * Ext JS Library 1.1.1
19235 * Copyright(c) 2006-2007, Ext JS, LLC.
19237 * Originally Released Under LGPL - original licence link has changed is not relivant.
19240 * <script type="text/javascript">
19245 * @class Roo.tree.ColumnTree
19246 * @extends Roo.data.TreePanel
19247 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19248 * @cfg {int} borderWidth compined right/left border allowance
19250 * @param {String/HTMLElement/Element} el The container element
19251 * @param {Object} config
19253 Roo.tree.ColumnTree = function(el, config)
19255 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19259 * Fire this event on a container when it resizes
19260 * @param {int} w Width
19261 * @param {int} h Height
19265 this.on('resize', this.onResize, this);
19268 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19272 borderWidth: Roo.isBorderBox ? 0 : 2,
19275 render : function(){
19276 // add the header.....
19278 Roo.tree.ColumnTree.superclass.render.apply(this);
19280 this.el.addClass('x-column-tree');
19282 this.headers = this.el.createChild(
19283 {cls:'x-tree-headers'},this.innerCt.dom);
19285 var cols = this.columns, c;
19286 var totalWidth = 0;
19288 var len = cols.length;
19289 for(var i = 0; i < len; i++){
19291 totalWidth += c.width;
19292 this.headEls.push(this.headers.createChild({
19293 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19295 cls:'x-tree-hd-text',
19298 style:'width:'+(c.width-this.borderWidth)+'px;'
19301 this.headers.createChild({cls:'x-clear'});
19302 // prevent floats from wrapping when clipped
19303 this.headers.setWidth(totalWidth);
19304 //this.innerCt.setWidth(totalWidth);
19305 this.innerCt.setStyle({ overflow: 'auto' });
19306 this.onResize(this.width, this.height);
19310 onResize : function(w,h)
19315 this.innerCt.setWidth(this.width);
19316 this.innerCt.setHeight(this.height-20);
19319 var cols = this.columns, c;
19320 var totalWidth = 0;
19322 var len = cols.length;
19323 for(var i = 0; i < len; i++){
19325 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19326 // it's the expander..
19327 expEl = this.headEls[i];
19330 totalWidth += c.width;
19334 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19336 this.headers.setWidth(w-20);
19345 * Ext JS Library 1.1.1
19346 * Copyright(c) 2006-2007, Ext JS, LLC.
19348 * Originally Released Under LGPL - original licence link has changed is not relivant.
19351 * <script type="text/javascript">
19355 * @class Roo.menu.Menu
19356 * @extends Roo.util.Observable
19357 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19358 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19360 * Creates a new Menu
19361 * @param {Object} config Configuration options
19363 Roo.menu.Menu = function(config){
19364 Roo.apply(this, config);
19365 this.id = this.id || Roo.id();
19368 * @event beforeshow
19369 * Fires before this menu is displayed
19370 * @param {Roo.menu.Menu} this
19374 * @event beforehide
19375 * Fires before this menu is hidden
19376 * @param {Roo.menu.Menu} this
19381 * Fires after this menu is displayed
19382 * @param {Roo.menu.Menu} this
19387 * Fires after this menu is hidden
19388 * @param {Roo.menu.Menu} this
19393 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19394 * @param {Roo.menu.Menu} this
19395 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19396 * @param {Roo.EventObject} e
19401 * Fires when the mouse is hovering over this menu
19402 * @param {Roo.menu.Menu} this
19403 * @param {Roo.EventObject} e
19404 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19409 * Fires when the mouse exits this menu
19410 * @param {Roo.menu.Menu} this
19411 * @param {Roo.EventObject} e
19412 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19417 * Fires when a menu item contained in this menu is clicked
19418 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19419 * @param {Roo.EventObject} e
19423 if (this.registerMenu) {
19424 Roo.menu.MenuMgr.register(this);
19427 var mis = this.items;
19428 this.items = new Roo.util.MixedCollection();
19430 this.add.apply(this, mis);
19434 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19436 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19440 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19441 * for bottom-right shadow (defaults to "sides")
19445 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19446 * this menu (defaults to "tl-tr?")
19448 subMenuAlign : "tl-tr?",
19450 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19451 * relative to its element of origin (defaults to "tl-bl?")
19453 defaultAlign : "tl-bl?",
19455 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19457 allowOtherMenus : false,
19459 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19461 registerMenu : true,
19466 render : function(){
19470 var el = this.el = new Roo.Layer({
19472 shadow:this.shadow,
19474 parentEl: this.parentEl || document.body,
19478 this.keyNav = new Roo.menu.MenuNav(this);
19481 el.addClass("x-menu-plain");
19484 el.addClass(this.cls);
19486 // generic focus element
19487 this.focusEl = el.createChild({
19488 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19490 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19491 ul.on("click", this.onClick, this);
19492 ul.on("mouseover", this.onMouseOver, this);
19493 ul.on("mouseout", this.onMouseOut, this);
19494 this.items.each(function(item){
19495 var li = document.createElement("li");
19496 li.className = "x-menu-list-item";
19497 ul.dom.appendChild(li);
19498 item.render(li, this);
19505 autoWidth : function(){
19506 var el = this.el, ul = this.ul;
19510 var w = this.width;
19513 }else if(Roo.isIE){
19514 el.setWidth(this.minWidth);
19515 var t = el.dom.offsetWidth; // force recalc
19516 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19521 delayAutoWidth : function(){
19524 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19526 this.awTask.delay(20);
19531 findTargetItem : function(e){
19532 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19533 if(t && t.menuItemId){
19534 return this.items.get(t.menuItemId);
19539 onClick : function(e){
19541 if(t = this.findTargetItem(e)){
19543 this.fireEvent("click", this, t, e);
19548 setActiveItem : function(item, autoExpand){
19549 if(item != this.activeItem){
19550 if(this.activeItem){
19551 this.activeItem.deactivate();
19553 this.activeItem = item;
19554 item.activate(autoExpand);
19555 }else if(autoExpand){
19561 tryActivate : function(start, step){
19562 var items = this.items;
19563 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19564 var item = items.get(i);
19565 if(!item.disabled && item.canActivate){
19566 this.setActiveItem(item, false);
19574 onMouseOver : function(e){
19576 if(t = this.findTargetItem(e)){
19577 if(t.canActivate && !t.disabled){
19578 this.setActiveItem(t, true);
19581 this.fireEvent("mouseover", this, e, t);
19585 onMouseOut : function(e){
19587 if(t = this.findTargetItem(e)){
19588 if(t == this.activeItem && t.shouldDeactivate(e)){
19589 this.activeItem.deactivate();
19590 delete this.activeItem;
19593 this.fireEvent("mouseout", this, e, t);
19597 * Read-only. Returns true if the menu is currently displayed, else false.
19600 isVisible : function(){
19601 return this.el && !this.hidden;
19605 * Displays this menu relative to another element
19606 * @param {String/HTMLElement/Roo.Element} element The element to align to
19607 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19608 * the element (defaults to this.defaultAlign)
19609 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19611 show : function(el, pos, parentMenu){
19612 this.parentMenu = parentMenu;
19616 this.fireEvent("beforeshow", this);
19617 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19621 * Displays this menu at a specific xy position
19622 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19623 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19625 showAt : function(xy, parentMenu, /* private: */_e){
19626 this.parentMenu = parentMenu;
19631 this.fireEvent("beforeshow", this);
19632 xy = this.el.adjustForConstraints(xy);
19636 this.hidden = false;
19638 this.fireEvent("show", this);
19641 focus : function(){
19643 this.doFocus.defer(50, this);
19647 doFocus : function(){
19649 this.focusEl.focus();
19654 * Hides this menu and optionally all parent menus
19655 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19657 hide : function(deep){
19658 if(this.el && this.isVisible()){
19659 this.fireEvent("beforehide", this);
19660 if(this.activeItem){
19661 this.activeItem.deactivate();
19662 this.activeItem = null;
19665 this.hidden = true;
19666 this.fireEvent("hide", this);
19668 if(deep === true && this.parentMenu){
19669 this.parentMenu.hide(true);
19674 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19675 * Any of the following are valid:
19677 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19678 * <li>An HTMLElement object which will be converted to a menu item</li>
19679 * <li>A menu item config object that will be created as a new menu item</li>
19680 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19681 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19686 var menu = new Roo.menu.Menu();
19688 // Create a menu item to add by reference
19689 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19691 // Add a bunch of items at once using different methods.
19692 // Only the last item added will be returned.
19693 var item = menu.add(
19694 menuItem, // add existing item by ref
19695 'Dynamic Item', // new TextItem
19696 '-', // new separator
19697 { text: 'Config Item' } // new item by config
19700 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19701 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19704 var a = arguments, l = a.length, item;
19705 for(var i = 0; i < l; i++){
19707 if ((typeof(el) == "object") && el.xtype && el.xns) {
19708 el = Roo.factory(el, Roo.menu);
19711 if(el.render){ // some kind of Item
19712 item = this.addItem(el);
19713 }else if(typeof el == "string"){ // string
19714 if(el == "separator" || el == "-"){
19715 item = this.addSeparator();
19717 item = this.addText(el);
19719 }else if(el.tagName || el.el){ // element
19720 item = this.addElement(el);
19721 }else if(typeof el == "object"){ // must be menu item config?
19722 item = this.addMenuItem(el);
19729 * Returns this menu's underlying {@link Roo.Element} object
19730 * @return {Roo.Element} The element
19732 getEl : function(){
19740 * Adds a separator bar to the menu
19741 * @return {Roo.menu.Item} The menu item that was added
19743 addSeparator : function(){
19744 return this.addItem(new Roo.menu.Separator());
19748 * Adds an {@link Roo.Element} object to the menu
19749 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19750 * @return {Roo.menu.Item} The menu item that was added
19752 addElement : function(el){
19753 return this.addItem(new Roo.menu.BaseItem(el));
19757 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19758 * @param {Roo.menu.Item} item The menu item to add
19759 * @return {Roo.menu.Item} The menu item that was added
19761 addItem : function(item){
19762 this.items.add(item);
19764 var li = document.createElement("li");
19765 li.className = "x-menu-list-item";
19766 this.ul.dom.appendChild(li);
19767 item.render(li, this);
19768 this.delayAutoWidth();
19774 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19775 * @param {Object} config A MenuItem config object
19776 * @return {Roo.menu.Item} The menu item that was added
19778 addMenuItem : function(config){
19779 if(!(config instanceof Roo.menu.Item)){
19780 if(typeof config.checked == "boolean"){ // must be check menu item config?
19781 config = new Roo.menu.CheckItem(config);
19783 config = new Roo.menu.Item(config);
19786 return this.addItem(config);
19790 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19791 * @param {String} text The text to display in the menu item
19792 * @return {Roo.menu.Item} The menu item that was added
19794 addText : function(text){
19795 return this.addItem(new Roo.menu.TextItem({ text : text }));
19799 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19800 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19801 * @param {Roo.menu.Item} item The menu item to add
19802 * @return {Roo.menu.Item} The menu item that was added
19804 insert : function(index, item){
19805 this.items.insert(index, item);
19807 var li = document.createElement("li");
19808 li.className = "x-menu-list-item";
19809 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19810 item.render(li, this);
19811 this.delayAutoWidth();
19817 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19818 * @param {Roo.menu.Item} item The menu item to remove
19820 remove : function(item){
19821 this.items.removeKey(item.id);
19826 * Removes and destroys all items in the menu
19828 removeAll : function(){
19830 while(f = this.items.first()){
19836 // MenuNav is a private utility class used internally by the Menu
19837 Roo.menu.MenuNav = function(menu){
19838 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19839 this.scope = this.menu = menu;
19842 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19843 doRelay : function(e, h){
19844 var k = e.getKey();
19845 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19846 this.menu.tryActivate(0, 1);
19849 return h.call(this.scope || this, e, this.menu);
19852 up : function(e, m){
19853 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19854 m.tryActivate(m.items.length-1, -1);
19858 down : function(e, m){
19859 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19860 m.tryActivate(0, 1);
19864 right : function(e, m){
19866 m.activeItem.expandMenu(true);
19870 left : function(e, m){
19872 if(m.parentMenu && m.parentMenu.activeItem){
19873 m.parentMenu.activeItem.activate();
19877 enter : function(e, m){
19879 e.stopPropagation();
19880 m.activeItem.onClick(e);
19881 m.fireEvent("click", this, m.activeItem);
19887 * Ext JS Library 1.1.1
19888 * Copyright(c) 2006-2007, Ext JS, LLC.
19890 * Originally Released Under LGPL - original licence link has changed is not relivant.
19893 * <script type="text/javascript">
19897 * @class Roo.menu.MenuMgr
19898 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19901 Roo.menu.MenuMgr = function(){
19902 var menus, active, groups = {}, attached = false, lastShow = new Date();
19904 // private - called when first menu is created
19907 active = new Roo.util.MixedCollection();
19908 Roo.get(document).addKeyListener(27, function(){
19909 if(active.length > 0){
19916 function hideAll(){
19917 if(active && active.length > 0){
19918 var c = active.clone();
19919 c.each(function(m){
19926 function onHide(m){
19928 if(active.length < 1){
19929 Roo.get(document).un("mousedown", onMouseDown);
19935 function onShow(m){
19936 var last = active.last();
19937 lastShow = new Date();
19940 Roo.get(document).on("mousedown", onMouseDown);
19944 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19945 m.parentMenu.activeChild = m;
19946 }else if(last && last.isVisible()){
19947 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19952 function onBeforeHide(m){
19954 m.activeChild.hide();
19956 if(m.autoHideTimer){
19957 clearTimeout(m.autoHideTimer);
19958 delete m.autoHideTimer;
19963 function onBeforeShow(m){
19964 var pm = m.parentMenu;
19965 if(!pm && !m.allowOtherMenus){
19967 }else if(pm && pm.activeChild && active != m){
19968 pm.activeChild.hide();
19973 function onMouseDown(e){
19974 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19980 function onBeforeCheck(mi, state){
19982 var g = groups[mi.group];
19983 for(var i = 0, l = g.length; i < l; i++){
19985 g[i].setChecked(false);
19994 * Hides all menus that are currently visible
19996 hideAll : function(){
20001 register : function(menu){
20005 menus[menu.id] = menu;
20006 menu.on("beforehide", onBeforeHide);
20007 menu.on("hide", onHide);
20008 menu.on("beforeshow", onBeforeShow);
20009 menu.on("show", onShow);
20010 var g = menu.group;
20011 if(g && menu.events["checkchange"]){
20015 groups[g].push(menu);
20016 menu.on("checkchange", onCheck);
20021 * Returns a {@link Roo.menu.Menu} object
20022 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
20023 * be used to generate and return a new Menu instance.
20025 get : function(menu){
20026 if(typeof menu == "string"){ // menu id
20027 return menus[menu];
20028 }else if(menu.events){ // menu instance
20030 }else if(typeof menu.length == 'number'){ // array of menu items?
20031 return new Roo.menu.Menu({items:menu});
20032 }else{ // otherwise, must be a config
20033 return new Roo.menu.Menu(menu);
20038 unregister : function(menu){
20039 delete menus[menu.id];
20040 menu.un("beforehide", onBeforeHide);
20041 menu.un("hide", onHide);
20042 menu.un("beforeshow", onBeforeShow);
20043 menu.un("show", onShow);
20044 var g = menu.group;
20045 if(g && menu.events["checkchange"]){
20046 groups[g].remove(menu);
20047 menu.un("checkchange", onCheck);
20052 registerCheckable : function(menuItem){
20053 var g = menuItem.group;
20058 groups[g].push(menuItem);
20059 menuItem.on("beforecheckchange", onBeforeCheck);
20064 unregisterCheckable : function(menuItem){
20065 var g = menuItem.group;
20067 groups[g].remove(menuItem);
20068 menuItem.un("beforecheckchange", onBeforeCheck);
20074 * Ext JS Library 1.1.1
20075 * Copyright(c) 2006-2007, Ext JS, LLC.
20077 * Originally Released Under LGPL - original licence link has changed is not relivant.
20080 * <script type="text/javascript">
20085 * @class Roo.menu.BaseItem
20086 * @extends Roo.Component
20087 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20088 * management and base configuration options shared by all menu components.
20090 * Creates a new BaseItem
20091 * @param {Object} config Configuration options
20093 Roo.menu.BaseItem = function(config){
20094 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20099 * Fires when this item is clicked
20100 * @param {Roo.menu.BaseItem} this
20101 * @param {Roo.EventObject} e
20106 * Fires when this item is activated
20107 * @param {Roo.menu.BaseItem} this
20111 * @event deactivate
20112 * Fires when this item is deactivated
20113 * @param {Roo.menu.BaseItem} this
20119 this.on("click", this.handler, this.scope, true);
20123 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20125 * @cfg {Function} handler
20126 * A function that will handle the click event of this menu item (defaults to undefined)
20129 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20131 canActivate : false,
20133 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20135 activeClass : "x-menu-item-active",
20137 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20139 hideOnClick : true,
20141 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20146 ctype: "Roo.menu.BaseItem",
20149 actionMode : "container",
20152 render : function(container, parentMenu){
20153 this.parentMenu = parentMenu;
20154 Roo.menu.BaseItem.superclass.render.call(this, container);
20155 this.container.menuItemId = this.id;
20159 onRender : function(container, position){
20160 this.el = Roo.get(this.el);
20161 container.dom.appendChild(this.el.dom);
20165 onClick : function(e){
20166 if(!this.disabled && this.fireEvent("click", this, e) !== false
20167 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20168 this.handleClick(e);
20175 activate : function(){
20179 var li = this.container;
20180 li.addClass(this.activeClass);
20181 this.region = li.getRegion().adjust(2, 2, -2, -2);
20182 this.fireEvent("activate", this);
20187 deactivate : function(){
20188 this.container.removeClass(this.activeClass);
20189 this.fireEvent("deactivate", this);
20193 shouldDeactivate : function(e){
20194 return !this.region || !this.region.contains(e.getPoint());
20198 handleClick : function(e){
20199 if(this.hideOnClick){
20200 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20205 expandMenu : function(autoActivate){
20210 hideMenu : function(){
20215 * Ext JS Library 1.1.1
20216 * Copyright(c) 2006-2007, Ext JS, LLC.
20218 * Originally Released Under LGPL - original licence link has changed is not relivant.
20221 * <script type="text/javascript">
20225 * @class Roo.menu.Adapter
20226 * @extends Roo.menu.BaseItem
20227 * 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.
20228 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20230 * Creates a new Adapter
20231 * @param {Object} config Configuration options
20233 Roo.menu.Adapter = function(component, config){
20234 Roo.menu.Adapter.superclass.constructor.call(this, config);
20235 this.component = component;
20237 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20239 canActivate : true,
20242 onRender : function(container, position){
20243 this.component.render(container);
20244 this.el = this.component.getEl();
20248 activate : function(){
20252 this.component.focus();
20253 this.fireEvent("activate", this);
20258 deactivate : function(){
20259 this.fireEvent("deactivate", this);
20263 disable : function(){
20264 this.component.disable();
20265 Roo.menu.Adapter.superclass.disable.call(this);
20269 enable : function(){
20270 this.component.enable();
20271 Roo.menu.Adapter.superclass.enable.call(this);
20275 * Ext JS Library 1.1.1
20276 * Copyright(c) 2006-2007, Ext JS, LLC.
20278 * Originally Released Under LGPL - original licence link has changed is not relivant.
20281 * <script type="text/javascript">
20285 * @class Roo.menu.TextItem
20286 * @extends Roo.menu.BaseItem
20287 * Adds a static text string to a menu, usually used as either a heading or group separator.
20288 * Note: old style constructor with text is still supported.
20291 * Creates a new TextItem
20292 * @param {Object} cfg Configuration
20294 Roo.menu.TextItem = function(cfg){
20295 if (typeof(cfg) == 'string') {
20298 Roo.apply(this,cfg);
20301 Roo.menu.TextItem.superclass.constructor.call(this);
20304 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20306 * @cfg {Boolean} text Text to show on item.
20311 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20313 hideOnClick : false,
20315 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20317 itemCls : "x-menu-text",
20320 onRender : function(){
20321 var s = document.createElement("span");
20322 s.className = this.itemCls;
20323 s.innerHTML = this.text;
20325 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20329 * Ext JS Library 1.1.1
20330 * Copyright(c) 2006-2007, Ext JS, LLC.
20332 * Originally Released Under LGPL - original licence link has changed is not relivant.
20335 * <script type="text/javascript">
20339 * @class Roo.menu.Separator
20340 * @extends Roo.menu.BaseItem
20341 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20342 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20344 * @param {Object} config Configuration options
20346 Roo.menu.Separator = function(config){
20347 Roo.menu.Separator.superclass.constructor.call(this, config);
20350 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20352 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20354 itemCls : "x-menu-sep",
20356 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20358 hideOnClick : false,
20361 onRender : function(li){
20362 var s = document.createElement("span");
20363 s.className = this.itemCls;
20364 s.innerHTML = " ";
20366 li.addClass("x-menu-sep-li");
20367 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20371 * Ext JS Library 1.1.1
20372 * Copyright(c) 2006-2007, Ext JS, LLC.
20374 * Originally Released Under LGPL - original licence link has changed is not relivant.
20377 * <script type="text/javascript">
20380 * @class Roo.menu.Item
20381 * @extends Roo.menu.BaseItem
20382 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20383 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20384 * activation and click handling.
20386 * Creates a new Item
20387 * @param {Object} config Configuration options
20389 Roo.menu.Item = function(config){
20390 Roo.menu.Item.superclass.constructor.call(this, config);
20392 this.menu = Roo.menu.MenuMgr.get(this.menu);
20395 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20398 * @cfg {String} text
20399 * The text to show on the menu item.
20403 * @cfg {String} HTML to render in menu
20404 * The text to show on the menu item (HTML version).
20408 * @cfg {String} icon
20409 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20413 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20415 itemCls : "x-menu-item",
20417 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20419 canActivate : true,
20421 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20424 // doc'd in BaseItem
20428 ctype: "Roo.menu.Item",
20431 onRender : function(container, position){
20432 var el = document.createElement("a");
20433 el.hideFocus = true;
20434 el.unselectable = "on";
20435 el.href = this.href || "#";
20436 if(this.hrefTarget){
20437 el.target = this.hrefTarget;
20439 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20441 var html = this.html.length ? this.html : String.format('{0}',this.text);
20443 el.innerHTML = String.format(
20444 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20445 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20447 Roo.menu.Item.superclass.onRender.call(this, container, position);
20451 * Sets the text to display in this menu item
20452 * @param {String} text The text to display
20453 * @param {Boolean} isHTML true to indicate text is pure html.
20455 setText : function(text, isHTML){
20463 var html = this.html.length ? this.html : String.format('{0}',this.text);
20465 this.el.update(String.format(
20466 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20467 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20468 this.parentMenu.autoWidth();
20473 handleClick : function(e){
20474 if(!this.href){ // if no link defined, stop the event automatically
20477 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20481 activate : function(autoExpand){
20482 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20492 shouldDeactivate : function(e){
20493 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20494 if(this.menu && this.menu.isVisible()){
20495 return !this.menu.getEl().getRegion().contains(e.getPoint());
20503 deactivate : function(){
20504 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20509 expandMenu : function(autoActivate){
20510 if(!this.disabled && this.menu){
20511 clearTimeout(this.hideTimer);
20512 delete this.hideTimer;
20513 if(!this.menu.isVisible() && !this.showTimer){
20514 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20515 }else if (this.menu.isVisible() && autoActivate){
20516 this.menu.tryActivate(0, 1);
20522 deferExpand : function(autoActivate){
20523 delete this.showTimer;
20524 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20526 this.menu.tryActivate(0, 1);
20531 hideMenu : function(){
20532 clearTimeout(this.showTimer);
20533 delete this.showTimer;
20534 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20535 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20540 deferHide : function(){
20541 delete this.hideTimer;
20546 * Ext JS Library 1.1.1
20547 * Copyright(c) 2006-2007, Ext JS, LLC.
20549 * Originally Released Under LGPL - original licence link has changed is not relivant.
20552 * <script type="text/javascript">
20556 * @class Roo.menu.CheckItem
20557 * @extends Roo.menu.Item
20558 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20560 * Creates a new CheckItem
20561 * @param {Object} config Configuration options
20563 Roo.menu.CheckItem = function(config){
20564 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20567 * @event beforecheckchange
20568 * Fires before the checked value is set, providing an opportunity to cancel if needed
20569 * @param {Roo.menu.CheckItem} this
20570 * @param {Boolean} checked The new checked value that will be set
20572 "beforecheckchange" : true,
20574 * @event checkchange
20575 * Fires after the checked value has been set
20576 * @param {Roo.menu.CheckItem} this
20577 * @param {Boolean} checked The checked value that was set
20579 "checkchange" : true
20581 if(this.checkHandler){
20582 this.on('checkchange', this.checkHandler, this.scope);
20585 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20587 * @cfg {String} group
20588 * All check items with the same group name will automatically be grouped into a single-select
20589 * radio button group (defaults to '')
20592 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20594 itemCls : "x-menu-item x-menu-check-item",
20596 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20598 groupClass : "x-menu-group-item",
20601 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20602 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20603 * initialized with checked = true will be rendered as checked.
20608 ctype: "Roo.menu.CheckItem",
20611 onRender : function(c){
20612 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20614 this.el.addClass(this.groupClass);
20616 Roo.menu.MenuMgr.registerCheckable(this);
20618 this.checked = false;
20619 this.setChecked(true, true);
20624 destroy : function(){
20626 Roo.menu.MenuMgr.unregisterCheckable(this);
20628 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20632 * Set the checked state of this item
20633 * @param {Boolean} checked The new checked value
20634 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20636 setChecked : function(state, suppressEvent){
20637 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20638 if(this.container){
20639 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20641 this.checked = state;
20642 if(suppressEvent !== true){
20643 this.fireEvent("checkchange", this, state);
20649 handleClick : function(e){
20650 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20651 this.setChecked(!this.checked);
20653 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20657 * Ext JS Library 1.1.1
20658 * Copyright(c) 2006-2007, Ext JS, LLC.
20660 * Originally Released Under LGPL - original licence link has changed is not relivant.
20663 * <script type="text/javascript">
20667 * @class Roo.menu.DateItem
20668 * @extends Roo.menu.Adapter
20669 * A menu item that wraps the {@link Roo.DatPicker} component.
20671 * Creates a new DateItem
20672 * @param {Object} config Configuration options
20674 Roo.menu.DateItem = function(config){
20675 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20676 /** The Roo.DatePicker object @type Roo.DatePicker */
20677 this.picker = this.component;
20678 this.addEvents({select: true});
20680 this.picker.on("render", function(picker){
20681 picker.getEl().swallowEvent("click");
20682 picker.container.addClass("x-menu-date-item");
20685 this.picker.on("select", this.onSelect, this);
20688 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20690 onSelect : function(picker, date){
20691 this.fireEvent("select", this, date, picker);
20692 Roo.menu.DateItem.superclass.handleClick.call(this);
20696 * Ext JS Library 1.1.1
20697 * Copyright(c) 2006-2007, Ext JS, LLC.
20699 * Originally Released Under LGPL - original licence link has changed is not relivant.
20702 * <script type="text/javascript">
20706 * @class Roo.menu.ColorItem
20707 * @extends Roo.menu.Adapter
20708 * A menu item that wraps the {@link Roo.ColorPalette} component.
20710 * Creates a new ColorItem
20711 * @param {Object} config Configuration options
20713 Roo.menu.ColorItem = function(config){
20714 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20715 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20716 this.palette = this.component;
20717 this.relayEvents(this.palette, ["select"]);
20718 if(this.selectHandler){
20719 this.on('select', this.selectHandler, this.scope);
20722 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20724 * Ext JS Library 1.1.1
20725 * Copyright(c) 2006-2007, Ext JS, LLC.
20727 * Originally Released Under LGPL - original licence link has changed is not relivant.
20730 * <script type="text/javascript">
20735 * @class Roo.menu.DateMenu
20736 * @extends Roo.menu.Menu
20737 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20739 * Creates a new DateMenu
20740 * @param {Object} config Configuration options
20742 Roo.menu.DateMenu = function(config){
20743 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20745 var di = new Roo.menu.DateItem(config);
20748 * The {@link Roo.DatePicker} instance for this DateMenu
20751 this.picker = di.picker;
20754 * @param {DatePicker} picker
20755 * @param {Date} date
20757 this.relayEvents(di, ["select"]);
20759 this.on('beforeshow', function(){
20761 this.picker.hideMonthPicker(true);
20765 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20769 * Ext JS Library 1.1.1
20770 * Copyright(c) 2006-2007, Ext JS, LLC.
20772 * Originally Released Under LGPL - original licence link has changed is not relivant.
20775 * <script type="text/javascript">
20780 * @class Roo.menu.ColorMenu
20781 * @extends Roo.menu.Menu
20782 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20784 * Creates a new ColorMenu
20785 * @param {Object} config Configuration options
20787 Roo.menu.ColorMenu = function(config){
20788 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20790 var ci = new Roo.menu.ColorItem(config);
20793 * The {@link Roo.ColorPalette} instance for this ColorMenu
20794 * @type ColorPalette
20796 this.palette = ci.palette;
20799 * @param {ColorPalette} palette
20800 * @param {String} color
20802 this.relayEvents(ci, ["select"]);
20804 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20806 * Ext JS Library 1.1.1
20807 * Copyright(c) 2006-2007, Ext JS, LLC.
20809 * Originally Released Under LGPL - original licence link has changed is not relivant.
20812 * <script type="text/javascript">
20816 * @class Roo.form.Field
20817 * @extends Roo.BoxComponent
20818 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20820 * Creates a new Field
20821 * @param {Object} config Configuration options
20823 Roo.form.Field = function(config){
20824 Roo.form.Field.superclass.constructor.call(this, config);
20827 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20829 * @cfg {String} fieldLabel Label to use when rendering a form.
20832 * @cfg {String} qtip Mouse over tip
20836 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20838 invalidClass : "x-form-invalid",
20840 * @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")
20842 invalidText : "The value in this field is invalid",
20844 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20846 focusClass : "x-form-focus",
20848 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20849 automatic validation (defaults to "keyup").
20851 validationEvent : "keyup",
20853 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20855 validateOnBlur : true,
20857 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20859 validationDelay : 250,
20861 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20862 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20864 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20866 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20868 fieldClass : "x-form-field",
20870 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20873 ----------- ----------------------------------------------------------------------
20874 qtip Display a quick tip when the user hovers over the field
20875 title Display a default browser title attribute popup
20876 under Add a block div beneath the field containing the error text
20877 side Add an error icon to the right of the field with a popup on hover
20878 [element id] Add the error text directly to the innerHTML of the specified element
20881 msgTarget : 'qtip',
20883 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20888 * @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.
20893 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20898 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20900 inputType : undefined,
20903 * @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).
20905 tabIndex : undefined,
20908 isFormField : true,
20913 * @property {Roo.Element} fieldEl
20914 * Element Containing the rendered Field (with label etc.)
20917 * @cfg {Mixed} value A value to initialize this field with.
20922 * @cfg {String} name The field's HTML name attribute.
20925 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20929 initComponent : function(){
20930 Roo.form.Field.superclass.initComponent.call(this);
20934 * Fires when this field receives input focus.
20935 * @param {Roo.form.Field} this
20940 * Fires when this field loses input focus.
20941 * @param {Roo.form.Field} this
20945 * @event specialkey
20946 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20947 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20948 * @param {Roo.form.Field} this
20949 * @param {Roo.EventObject} e The event object
20954 * Fires just before the field blurs if the field value has changed.
20955 * @param {Roo.form.Field} this
20956 * @param {Mixed} newValue The new value
20957 * @param {Mixed} oldValue The original value
20962 * Fires after the field has been marked as invalid.
20963 * @param {Roo.form.Field} this
20964 * @param {String} msg The validation message
20969 * Fires after the field has been validated with no errors.
20970 * @param {Roo.form.Field} this
20975 * Fires after the key up
20976 * @param {Roo.form.Field} this
20977 * @param {Roo.EventObject} e The event Object
20984 * Returns the name attribute of the field if available
20985 * @return {String} name The field name
20987 getName: function(){
20988 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20992 onRender : function(ct, position){
20993 Roo.form.Field.superclass.onRender.call(this, ct, position);
20995 var cfg = this.getAutoCreate();
20997 cfg.name = this.name || this.id;
20999 if(this.inputType){
21000 cfg.type = this.inputType;
21002 this.el = ct.createChild(cfg, position);
21004 var type = this.el.dom.type;
21006 if(type == 'password'){
21009 this.el.addClass('x-form-'+type);
21012 this.el.dom.readOnly = true;
21014 if(this.tabIndex !== undefined){
21015 this.el.dom.setAttribute('tabIndex', this.tabIndex);
21018 this.el.addClass([this.fieldClass, this.cls]);
21023 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
21024 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
21025 * @return {Roo.form.Field} this
21027 applyTo : function(target){
21028 this.allowDomMove = false;
21029 this.el = Roo.get(target);
21030 this.render(this.el.dom.parentNode);
21035 initValue : function(){
21036 if(this.value !== undefined){
21037 this.setValue(this.value);
21038 }else if(this.el.dom.value.length > 0){
21039 this.setValue(this.el.dom.value);
21044 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21046 isDirty : function() {
21047 if(this.disabled) {
21050 return String(this.getValue()) !== String(this.originalValue);
21054 afterRender : function(){
21055 Roo.form.Field.superclass.afterRender.call(this);
21060 fireKey : function(e){
21061 //Roo.log('field ' + e.getKey());
21062 if(e.isNavKeyPress()){
21063 this.fireEvent("specialkey", this, e);
21068 * Resets the current field value to the originally loaded value and clears any validation messages
21070 reset : function(){
21071 this.setValue(this.originalValue);
21072 this.clearInvalid();
21076 initEvents : function(){
21077 // safari killled keypress - so keydown is now used..
21078 this.el.on("keydown" , this.fireKey, this);
21079 this.el.on("focus", this.onFocus, this);
21080 this.el.on("blur", this.onBlur, this);
21081 this.el.relayEvent('keyup', this);
21083 // reference to original value for reset
21084 this.originalValue = this.getValue();
21088 onFocus : function(){
21089 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21090 this.el.addClass(this.focusClass);
21092 if(!this.hasFocus){
21093 this.hasFocus = true;
21094 this.startValue = this.getValue();
21095 this.fireEvent("focus", this);
21099 beforeBlur : Roo.emptyFn,
21102 onBlur : function(){
21104 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21105 this.el.removeClass(this.focusClass);
21107 this.hasFocus = false;
21108 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21111 var v = this.getValue();
21112 if(String(v) !== String(this.startValue)){
21113 this.fireEvent('change', this, v, this.startValue);
21115 this.fireEvent("blur", this);
21119 * Returns whether or not the field value is currently valid
21120 * @param {Boolean} preventMark True to disable marking the field invalid
21121 * @return {Boolean} True if the value is valid, else false
21123 isValid : function(preventMark){
21127 var restore = this.preventMark;
21128 this.preventMark = preventMark === true;
21129 var v = this.validateValue(this.processValue(this.getRawValue()));
21130 this.preventMark = restore;
21135 * Validates the field value
21136 * @return {Boolean} True if the value is valid, else false
21138 validate : function(){
21139 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21140 this.clearInvalid();
21146 processValue : function(value){
21151 // Subclasses should provide the validation implementation by overriding this
21152 validateValue : function(value){
21157 * Mark this field as invalid
21158 * @param {String} msg The validation message
21160 markInvalid : function(msg){
21161 if(!this.rendered || this.preventMark){ // not rendered
21164 this.el.addClass(this.invalidClass);
21165 msg = msg || this.invalidText;
21166 switch(this.msgTarget){
21168 this.el.dom.qtip = msg;
21169 this.el.dom.qclass = 'x-form-invalid-tip';
21170 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21171 Roo.QuickTips.enable();
21175 this.el.dom.title = msg;
21179 var elp = this.el.findParent('.x-form-element', 5, true);
21180 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21181 this.errorEl.setWidth(elp.getWidth(true)-20);
21183 this.errorEl.update(msg);
21184 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21187 if(!this.errorIcon){
21188 var elp = this.el.findParent('.x-form-element', 5, true);
21189 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21191 this.alignErrorIcon();
21192 this.errorIcon.dom.qtip = msg;
21193 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21194 this.errorIcon.show();
21195 this.on('resize', this.alignErrorIcon, this);
21198 var t = Roo.getDom(this.msgTarget);
21200 t.style.display = this.msgDisplay;
21203 this.fireEvent('invalid', this, msg);
21207 alignErrorIcon : function(){
21208 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21212 * Clear any invalid styles/messages for this field
21214 clearInvalid : function(){
21215 if(!this.rendered || this.preventMark){ // not rendered
21218 this.el.removeClass(this.invalidClass);
21219 switch(this.msgTarget){
21221 this.el.dom.qtip = '';
21224 this.el.dom.title = '';
21228 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21232 if(this.errorIcon){
21233 this.errorIcon.dom.qtip = '';
21234 this.errorIcon.hide();
21235 this.un('resize', this.alignErrorIcon, this);
21239 var t = Roo.getDom(this.msgTarget);
21241 t.style.display = 'none';
21244 this.fireEvent('valid', this);
21248 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21249 * @return {Mixed} value The field value
21251 getRawValue : function(){
21252 var v = this.el.getValue();
21253 if(v === this.emptyText){
21260 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21261 * @return {Mixed} value The field value
21263 getValue : function(){
21264 var v = this.el.getValue();
21265 if(v === this.emptyText || v === undefined){
21272 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21273 * @param {Mixed} value The value to set
21275 setRawValue : function(v){
21276 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21280 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21281 * @param {Mixed} value The value to set
21283 setValue : function(v){
21286 this.el.dom.value = (v === null || v === undefined ? '' : v);
21291 adjustSize : function(w, h){
21292 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21293 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21297 adjustWidth : function(tag, w){
21298 tag = tag.toLowerCase();
21299 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21300 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21301 if(tag == 'input'){
21304 if(tag = 'textarea'){
21307 }else if(Roo.isOpera){
21308 if(tag == 'input'){
21311 if(tag = 'textarea'){
21321 // anything other than normal should be considered experimental
21322 Roo.form.Field.msgFx = {
21324 show: function(msgEl, f){
21325 msgEl.setDisplayed('block');
21328 hide : function(msgEl, f){
21329 msgEl.setDisplayed(false).update('');
21334 show: function(msgEl, f){
21335 msgEl.slideIn('t', {stopFx:true});
21338 hide : function(msgEl, f){
21339 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21344 show: function(msgEl, f){
21345 msgEl.fixDisplay();
21346 msgEl.alignTo(f.el, 'tl-tr');
21347 msgEl.slideIn('l', {stopFx:true});
21350 hide : function(msgEl, f){
21351 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21356 * Ext JS Library 1.1.1
21357 * Copyright(c) 2006-2007, Ext JS, LLC.
21359 * Originally Released Under LGPL - original licence link has changed is not relivant.
21362 * <script type="text/javascript">
21367 * @class Roo.form.TextField
21368 * @extends Roo.form.Field
21369 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21370 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21372 * Creates a new TextField
21373 * @param {Object} config Configuration options
21375 Roo.form.TextField = function(config){
21376 Roo.form.TextField.superclass.constructor.call(this, config);
21380 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21381 * according to the default logic, but this event provides a hook for the developer to apply additional
21382 * logic at runtime to resize the field if needed.
21383 * @param {Roo.form.Field} this This text field
21384 * @param {Number} width The new field width
21390 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21392 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21396 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21400 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21404 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21408 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21412 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21414 disableKeyFilter : false,
21416 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21420 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21424 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21426 maxLength : Number.MAX_VALUE,
21428 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21430 minLengthText : "The minimum length for this field is {0}",
21432 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21434 maxLengthText : "The maximum length for this field is {0}",
21436 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21438 selectOnFocus : false,
21440 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21442 blankText : "This field is required",
21444 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21445 * If available, this function will be called only after the basic validators all return true, and will be passed the
21446 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21450 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21451 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21452 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21456 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21460 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21464 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21465 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21467 emptyClass : 'x-form-empty-field',
21470 initEvents : function(){
21471 Roo.form.TextField.superclass.initEvents.call(this);
21472 if(this.validationEvent == 'keyup'){
21473 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21474 this.el.on('keyup', this.filterValidation, this);
21476 else if(this.validationEvent !== false){
21477 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21479 if(this.selectOnFocus || this.emptyText){
21480 this.on("focus", this.preFocus, this);
21481 if(this.emptyText){
21482 this.on('blur', this.postBlur, this);
21483 this.applyEmptyText();
21486 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21487 this.el.on("keypress", this.filterKeys, this);
21490 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21491 this.el.on("click", this.autoSize, this);
21495 processValue : function(value){
21496 if(this.stripCharsRe){
21497 var newValue = value.replace(this.stripCharsRe, '');
21498 if(newValue !== value){
21499 this.setRawValue(newValue);
21506 filterValidation : function(e){
21507 if(!e.isNavKeyPress()){
21508 this.validationTask.delay(this.validationDelay);
21513 onKeyUp : function(e){
21514 if(!e.isNavKeyPress()){
21520 * Resets the current field value to the originally-loaded value and clears any validation messages.
21521 * Also adds emptyText and emptyClass if the original value was blank.
21523 reset : function(){
21524 Roo.form.TextField.superclass.reset.call(this);
21525 this.applyEmptyText();
21528 applyEmptyText : function(){
21529 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21530 this.setRawValue(this.emptyText);
21531 this.el.addClass(this.emptyClass);
21536 preFocus : function(){
21537 if(this.emptyText){
21538 if(this.el.dom.value == this.emptyText){
21539 this.setRawValue('');
21541 this.el.removeClass(this.emptyClass);
21543 if(this.selectOnFocus){
21544 this.el.dom.select();
21549 postBlur : function(){
21550 this.applyEmptyText();
21554 filterKeys : function(e){
21555 var k = e.getKey();
21556 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21559 var c = e.getCharCode(), cc = String.fromCharCode(c);
21560 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21563 if(!this.maskRe.test(cc)){
21568 setValue : function(v){
21569 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21570 this.el.removeClass(this.emptyClass);
21572 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21573 this.applyEmptyText();
21578 * Validates a value according to the field's validation rules and marks the field as invalid
21579 * if the validation fails
21580 * @param {Mixed} value The value to validate
21581 * @return {Boolean} True if the value is valid, else false
21583 validateValue : function(value){
21584 if(value.length < 1 || value === this.emptyText){ // if it's blank
21585 if(this.allowBlank){
21586 this.clearInvalid();
21589 this.markInvalid(this.blankText);
21593 if(value.length < this.minLength){
21594 this.markInvalid(String.format(this.minLengthText, this.minLength));
21597 if(value.length > this.maxLength){
21598 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21602 var vt = Roo.form.VTypes;
21603 if(!vt[this.vtype](value, this)){
21604 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21608 if(typeof this.validator == "function"){
21609 var msg = this.validator(value);
21611 this.markInvalid(msg);
21615 if(this.regex && !this.regex.test(value)){
21616 this.markInvalid(this.regexText);
21623 * Selects text in this field
21624 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21625 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21627 selectText : function(start, end){
21628 var v = this.getRawValue();
21630 start = start === undefined ? 0 : start;
21631 end = end === undefined ? v.length : end;
21632 var d = this.el.dom;
21633 if(d.setSelectionRange){
21634 d.setSelectionRange(start, end);
21635 }else if(d.createTextRange){
21636 var range = d.createTextRange();
21637 range.moveStart("character", start);
21638 range.moveEnd("character", v.length-end);
21645 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21646 * This only takes effect if grow = true, and fires the autosize event.
21648 autoSize : function(){
21649 if(!this.grow || !this.rendered){
21653 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21656 var v = el.dom.value;
21657 var d = document.createElement('div');
21658 d.appendChild(document.createTextNode(v));
21662 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21663 this.el.setWidth(w);
21664 this.fireEvent("autosize", this, w);
21668 * Ext JS Library 1.1.1
21669 * Copyright(c) 2006-2007, Ext JS, LLC.
21671 * Originally Released Under LGPL - original licence link has changed is not relivant.
21674 * <script type="text/javascript">
21678 * @class Roo.form.Hidden
21679 * @extends Roo.form.TextField
21680 * Simple Hidden element used on forms
21682 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21685 * Creates a new Hidden form element.
21686 * @param {Object} config Configuration options
21691 // easy hidden field...
21692 Roo.form.Hidden = function(config){
21693 Roo.form.Hidden.superclass.constructor.call(this, config);
21696 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21698 inputType: 'hidden',
21701 labelSeparator: '',
21703 itemCls : 'x-form-item-display-none'
21711 * Ext JS Library 1.1.1
21712 * Copyright(c) 2006-2007, Ext JS, LLC.
21714 * Originally Released Under LGPL - original licence link has changed is not relivant.
21717 * <script type="text/javascript">
21721 * @class Roo.form.TriggerField
21722 * @extends Roo.form.TextField
21723 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21724 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21725 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21726 * for which you can provide a custom implementation. For example:
21728 var trigger = new Roo.form.TriggerField();
21729 trigger.onTriggerClick = myTriggerFn;
21730 trigger.applyTo('my-field');
21733 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21734 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21735 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21736 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21738 * Create a new TriggerField.
21739 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21740 * to the base TextField)
21742 Roo.form.TriggerField = function(config){
21743 this.mimicing = false;
21744 Roo.form.TriggerField.superclass.constructor.call(this, config);
21747 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21749 * @cfg {String} triggerClass A CSS class to apply to the trigger
21752 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21753 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21755 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21757 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21761 /** @cfg {Boolean} grow @hide */
21762 /** @cfg {Number} growMin @hide */
21763 /** @cfg {Number} growMax @hide */
21769 autoSize: Roo.emptyFn,
21773 deferHeight : true,
21776 actionMode : 'wrap',
21778 onResize : function(w, h){
21779 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21780 if(typeof w == 'number'){
21781 var x = w - this.trigger.getWidth();
21782 this.el.setWidth(this.adjustWidth('input', x));
21783 this.trigger.setStyle('left', x+'px');
21788 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21791 getResizeEl : function(){
21796 getPositionEl : function(){
21801 alignErrorIcon : function(){
21802 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21806 onRender : function(ct, position){
21807 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21808 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21809 this.trigger = this.wrap.createChild(this.triggerConfig ||
21810 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21811 if(this.hideTrigger){
21812 this.trigger.setDisplayed(false);
21814 this.initTrigger();
21816 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21821 initTrigger : function(){
21822 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21823 this.trigger.addClassOnOver('x-form-trigger-over');
21824 this.trigger.addClassOnClick('x-form-trigger-click');
21828 onDestroy : function(){
21830 this.trigger.removeAllListeners();
21831 this.trigger.remove();
21834 this.wrap.remove();
21836 Roo.form.TriggerField.superclass.onDestroy.call(this);
21840 onFocus : function(){
21841 Roo.form.TriggerField.superclass.onFocus.call(this);
21842 if(!this.mimicing){
21843 this.wrap.addClass('x-trigger-wrap-focus');
21844 this.mimicing = true;
21845 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21846 if(this.monitorTab){
21847 this.el.on("keydown", this.checkTab, this);
21853 checkTab : function(e){
21854 if(e.getKey() == e.TAB){
21855 this.triggerBlur();
21860 onBlur : function(){
21865 mimicBlur : function(e, t){
21866 if(!this.wrap.contains(t) && this.validateBlur()){
21867 this.triggerBlur();
21872 triggerBlur : function(){
21873 this.mimicing = false;
21874 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21875 if(this.monitorTab){
21876 this.el.un("keydown", this.checkTab, this);
21878 this.wrap.removeClass('x-trigger-wrap-focus');
21879 Roo.form.TriggerField.superclass.onBlur.call(this);
21883 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21884 validateBlur : function(e, t){
21889 onDisable : function(){
21890 Roo.form.TriggerField.superclass.onDisable.call(this);
21892 this.wrap.addClass('x-item-disabled');
21897 onEnable : function(){
21898 Roo.form.TriggerField.superclass.onEnable.call(this);
21900 this.wrap.removeClass('x-item-disabled');
21905 onShow : function(){
21906 var ae = this.getActionEl();
21909 ae.dom.style.display = '';
21910 ae.dom.style.visibility = 'visible';
21916 onHide : function(){
21917 var ae = this.getActionEl();
21918 ae.dom.style.display = 'none';
21922 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21923 * by an implementing function.
21925 * @param {EventObject} e
21927 onTriggerClick : Roo.emptyFn
21930 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21931 // to be extended by an implementing class. For an example of implementing this class, see the custom
21932 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21933 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21934 initComponent : function(){
21935 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21937 this.triggerConfig = {
21938 tag:'span', cls:'x-form-twin-triggers', cn:[
21939 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21940 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21944 getTrigger : function(index){
21945 return this.triggers[index];
21948 initTrigger : function(){
21949 var ts = this.trigger.select('.x-form-trigger', true);
21950 this.wrap.setStyle('overflow', 'hidden');
21951 var triggerField = this;
21952 ts.each(function(t, all, index){
21953 t.hide = function(){
21954 var w = triggerField.wrap.getWidth();
21955 this.dom.style.display = 'none';
21956 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21958 t.show = function(){
21959 var w = triggerField.wrap.getWidth();
21960 this.dom.style.display = '';
21961 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21963 var triggerIndex = 'Trigger'+(index+1);
21965 if(this['hide'+triggerIndex]){
21966 t.dom.style.display = 'none';
21968 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21969 t.addClassOnOver('x-form-trigger-over');
21970 t.addClassOnClick('x-form-trigger-click');
21972 this.triggers = ts.elements;
21975 onTrigger1Click : Roo.emptyFn,
21976 onTrigger2Click : Roo.emptyFn
21979 * Ext JS Library 1.1.1
21980 * Copyright(c) 2006-2007, Ext JS, LLC.
21982 * Originally Released Under LGPL - original licence link has changed is not relivant.
21985 * <script type="text/javascript">
21989 * @class Roo.form.TextArea
21990 * @extends Roo.form.TextField
21991 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21992 * support for auto-sizing.
21994 * Creates a new TextArea
21995 * @param {Object} config Configuration options
21997 Roo.form.TextArea = function(config){
21998 Roo.form.TextArea.superclass.constructor.call(this, config);
21999 // these are provided exchanges for backwards compat
22000 // minHeight/maxHeight were replaced by growMin/growMax to be
22001 // compatible with TextField growing config values
22002 if(this.minHeight !== undefined){
22003 this.growMin = this.minHeight;
22005 if(this.maxHeight !== undefined){
22006 this.growMax = this.maxHeight;
22010 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
22012 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
22016 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
22020 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
22021 * in the field (equivalent to setting overflow: hidden, defaults to false)
22023 preventScrollbars: false,
22025 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
22026 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
22030 onRender : function(ct, position){
22032 this.defaultAutoCreate = {
22034 style:"width:300px;height:60px;",
22035 autocomplete: "off"
22038 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22040 this.textSizeEl = Roo.DomHelper.append(document.body, {
22041 tag: "pre", cls: "x-form-grow-sizer"
22043 if(this.preventScrollbars){
22044 this.el.setStyle("overflow", "hidden");
22046 this.el.setHeight(this.growMin);
22050 onDestroy : function(){
22051 if(this.textSizeEl){
22052 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22054 Roo.form.TextArea.superclass.onDestroy.call(this);
22058 onKeyUp : function(e){
22059 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22065 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22066 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22068 autoSize : function(){
22069 if(!this.grow || !this.textSizeEl){
22073 var v = el.dom.value;
22074 var ts = this.textSizeEl;
22077 ts.appendChild(document.createTextNode(v));
22080 Roo.fly(ts).setWidth(this.el.getWidth());
22082 v = "  ";
22085 v = v.replace(/\n/g, '<p> </p>');
22087 v += " \n ";
22090 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22091 if(h != this.lastHeight){
22092 this.lastHeight = h;
22093 this.el.setHeight(h);
22094 this.fireEvent("autosize", this, h);
22099 * Ext JS Library 1.1.1
22100 * Copyright(c) 2006-2007, Ext JS, LLC.
22102 * Originally Released Under LGPL - original licence link has changed is not relivant.
22105 * <script type="text/javascript">
22110 * @class Roo.form.NumberField
22111 * @extends Roo.form.TextField
22112 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22114 * Creates a new NumberField
22115 * @param {Object} config Configuration options
22117 Roo.form.NumberField = function(config){
22118 Roo.form.NumberField.superclass.constructor.call(this, config);
22121 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22123 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22125 fieldClass: "x-form-field x-form-num-field",
22127 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22129 allowDecimals : true,
22131 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22133 decimalSeparator : ".",
22135 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22137 decimalPrecision : 2,
22139 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22141 allowNegative : true,
22143 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22145 minValue : Number.NEGATIVE_INFINITY,
22147 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22149 maxValue : Number.MAX_VALUE,
22151 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22153 minText : "The minimum value for this field is {0}",
22155 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22157 maxText : "The maximum value for this field is {0}",
22159 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22160 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22162 nanText : "{0} is not a valid number",
22165 initEvents : function(){
22166 Roo.form.NumberField.superclass.initEvents.call(this);
22167 var allowed = "0123456789";
22168 if(this.allowDecimals){
22169 allowed += this.decimalSeparator;
22171 if(this.allowNegative){
22174 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22175 var keyPress = function(e){
22176 var k = e.getKey();
22177 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22180 var c = e.getCharCode();
22181 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22185 this.el.on("keypress", keyPress, this);
22189 validateValue : function(value){
22190 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22193 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22196 var num = this.parseValue(value);
22198 this.markInvalid(String.format(this.nanText, value));
22201 if(num < this.minValue){
22202 this.markInvalid(String.format(this.minText, this.minValue));
22205 if(num > this.maxValue){
22206 this.markInvalid(String.format(this.maxText, this.maxValue));
22212 getValue : function(){
22213 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22217 parseValue : function(value){
22218 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22219 return isNaN(value) ? '' : value;
22223 fixPrecision : function(value){
22224 var nan = isNaN(value);
22225 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22226 return nan ? '' : value;
22228 return parseFloat(value).toFixed(this.decimalPrecision);
22231 setValue : function(v){
22232 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22236 decimalPrecisionFcn : function(v){
22237 return Math.floor(v);
22240 beforeBlur : function(){
22241 var v = this.parseValue(this.getRawValue());
22243 this.setValue(this.fixPrecision(v));
22248 * Ext JS Library 1.1.1
22249 * Copyright(c) 2006-2007, Ext JS, LLC.
22251 * Originally Released Under LGPL - original licence link has changed is not relivant.
22254 * <script type="text/javascript">
22258 * @class Roo.form.DateField
22259 * @extends Roo.form.TriggerField
22260 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22262 * Create a new DateField
22263 * @param {Object} config
22265 Roo.form.DateField = function(config){
22266 Roo.form.DateField.superclass.constructor.call(this, config);
22272 * Fires when a date is selected
22273 * @param {Roo.form.DateField} combo This combo box
22274 * @param {Date} date The date selected
22281 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22282 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22283 this.ddMatch = null;
22284 if(this.disabledDates){
22285 var dd = this.disabledDates;
22287 for(var i = 0; i < dd.length; i++){
22289 if(i != dd.length-1) re += "|";
22291 this.ddMatch = new RegExp(re + ")");
22295 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22297 * @cfg {String} format
22298 * The default date format string which can be overriden for localization support. The format must be
22299 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22303 * @cfg {String} altFormats
22304 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22305 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22307 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22309 * @cfg {Array} disabledDays
22310 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22312 disabledDays : null,
22314 * @cfg {String} disabledDaysText
22315 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22317 disabledDaysText : "Disabled",
22319 * @cfg {Array} disabledDates
22320 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22321 * expression so they are very powerful. Some examples:
22323 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22324 * <li>["03/08", "09/16"] would disable those days for every year</li>
22325 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22326 * <li>["03/../2006"] would disable every day in March 2006</li>
22327 * <li>["^03"] would disable every day in every March</li>
22329 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22330 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22332 disabledDates : null,
22334 * @cfg {String} disabledDatesText
22335 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22337 disabledDatesText : "Disabled",
22339 * @cfg {Date/String} minValue
22340 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22341 * valid format (defaults to null).
22345 * @cfg {Date/String} maxValue
22346 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22347 * valid format (defaults to null).
22351 * @cfg {String} minText
22352 * The error text to display when the date in the cell is before minValue (defaults to
22353 * 'The date in this field must be after {minValue}').
22355 minText : "The date in this field must be equal to or after {0}",
22357 * @cfg {String} maxText
22358 * The error text to display when the date in the cell is after maxValue (defaults to
22359 * 'The date in this field must be before {maxValue}').
22361 maxText : "The date in this field must be equal to or before {0}",
22363 * @cfg {String} invalidText
22364 * The error text to display when the date in the field is invalid (defaults to
22365 * '{value} is not a valid date - it must be in the format {format}').
22367 invalidText : "{0} is not a valid date - it must be in the format {1}",
22369 * @cfg {String} triggerClass
22370 * An additional CSS class used to style the trigger button. The trigger will always get the
22371 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22372 * which displays a calendar icon).
22374 triggerClass : 'x-form-date-trigger',
22378 * @cfg {bool} useIso
22379 * if enabled, then the date field will use a hidden field to store the
22380 * real value as iso formated date. default (false)
22384 * @cfg {String/Object} autoCreate
22385 * A DomHelper element spec, or true for a default element spec (defaults to
22386 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22389 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22392 hiddenField: false,
22394 onRender : function(ct, position)
22396 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22398 this.el.dom.removeAttribute('name');
22399 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22401 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22402 // prevent input submission
22403 this.hiddenName = this.name;
22410 validateValue : function(value)
22412 value = this.formatDate(value);
22413 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22416 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22419 var svalue = value;
22420 value = this.parseDate(value);
22422 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22425 var time = value.getTime();
22426 if(this.minValue && time < this.minValue.getTime()){
22427 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22430 if(this.maxValue && time > this.maxValue.getTime()){
22431 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22434 if(this.disabledDays){
22435 var day = value.getDay();
22436 for(var i = 0; i < this.disabledDays.length; i++) {
22437 if(day === this.disabledDays[i]){
22438 this.markInvalid(this.disabledDaysText);
22443 var fvalue = this.formatDate(value);
22444 if(this.ddMatch && this.ddMatch.test(fvalue)){
22445 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22452 // Provides logic to override the default TriggerField.validateBlur which just returns true
22453 validateBlur : function(){
22454 return !this.menu || !this.menu.isVisible();
22458 * Returns the current date value of the date field.
22459 * @return {Date} The date value
22461 getValue : function(){
22463 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22467 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22468 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22469 * (the default format used is "m/d/y").
22472 //All of these calls set the same date value (May 4, 2006)
22474 //Pass a date object:
22475 var dt = new Date('5/4/06');
22476 dateField.setValue(dt);
22478 //Pass a date string (default format):
22479 dateField.setValue('5/4/06');
22481 //Pass a date string (custom format):
22482 dateField.format = 'Y-m-d';
22483 dateField.setValue('2006-5-4');
22485 * @param {String/Date} date The date or valid date string
22487 setValue : function(date){
22488 if (this.hiddenField) {
22489 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22491 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22495 parseDate : function(value){
22496 if(!value || value instanceof Date){
22499 var v = Date.parseDate(value, this.format);
22500 if(!v && this.altFormats){
22501 if(!this.altFormatsArray){
22502 this.altFormatsArray = this.altFormats.split("|");
22504 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22505 v = Date.parseDate(value, this.altFormatsArray[i]);
22512 formatDate : function(date, fmt){
22513 return (!date || !(date instanceof Date)) ?
22514 date : date.dateFormat(fmt || this.format);
22519 select: function(m, d){
22521 this.fireEvent('select', this, d);
22523 show : function(){ // retain focus styling
22527 this.focus.defer(10, this);
22528 var ml = this.menuListeners;
22529 this.menu.un("select", ml.select, this);
22530 this.menu.un("show", ml.show, this);
22531 this.menu.un("hide", ml.hide, this);
22536 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22537 onTriggerClick : function(){
22541 if(this.menu == null){
22542 this.menu = new Roo.menu.DateMenu();
22544 Roo.apply(this.menu.picker, {
22545 showClear: this.allowBlank,
22546 minDate : this.minValue,
22547 maxDate : this.maxValue,
22548 disabledDatesRE : this.ddMatch,
22549 disabledDatesText : this.disabledDatesText,
22550 disabledDays : this.disabledDays,
22551 disabledDaysText : this.disabledDaysText,
22552 format : this.format,
22553 minText : String.format(this.minText, this.formatDate(this.minValue)),
22554 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22556 this.menu.on(Roo.apply({}, this.menuListeners, {
22559 this.menu.picker.setValue(this.getValue() || new Date());
22560 this.menu.show(this.el, "tl-bl?");
22563 beforeBlur : function(){
22564 var v = this.parseDate(this.getRawValue());
22570 /** @cfg {Boolean} grow @hide */
22571 /** @cfg {Number} growMin @hide */
22572 /** @cfg {Number} growMax @hide */
22579 * Ext JS Library 1.1.1
22580 * Copyright(c) 2006-2007, Ext JS, LLC.
22582 * Originally Released Under LGPL - original licence link has changed is not relivant.
22585 * <script type="text/javascript">
22590 * @class Roo.form.ComboBox
22591 * @extends Roo.form.TriggerField
22592 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22594 * Create a new ComboBox.
22595 * @param {Object} config Configuration options
22597 Roo.form.ComboBox = function(config){
22598 Roo.form.ComboBox.superclass.constructor.call(this, config);
22602 * Fires when the dropdown list is expanded
22603 * @param {Roo.form.ComboBox} combo This combo box
22608 * Fires when the dropdown list is collapsed
22609 * @param {Roo.form.ComboBox} combo This combo box
22613 * @event beforeselect
22614 * Fires before a list item is selected. Return false to cancel the selection.
22615 * @param {Roo.form.ComboBox} combo This combo box
22616 * @param {Roo.data.Record} record The data record returned from the underlying store
22617 * @param {Number} index The index of the selected item in the dropdown list
22619 'beforeselect' : true,
22622 * Fires when a list item is selected
22623 * @param {Roo.form.ComboBox} combo This combo box
22624 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22625 * @param {Number} index The index of the selected item in the dropdown list
22629 * @event beforequery
22630 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22631 * The event object passed has these properties:
22632 * @param {Roo.form.ComboBox} combo This combo box
22633 * @param {String} query The query
22634 * @param {Boolean} forceAll true to force "all" query
22635 * @param {Boolean} cancel true to cancel the query
22636 * @param {Object} e The query event object
22638 'beforequery': true,
22641 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22642 * @param {Roo.form.ComboBox} combo This combo box
22647 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22648 * @param {Roo.form.ComboBox} combo This combo box
22649 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22655 if(this.transform){
22656 this.allowDomMove = false;
22657 var s = Roo.getDom(this.transform);
22658 if(!this.hiddenName){
22659 this.hiddenName = s.name;
22662 this.mode = 'local';
22663 var d = [], opts = s.options;
22664 for(var i = 0, len = opts.length;i < len; i++){
22666 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22668 this.value = value;
22670 d.push([value, o.text]);
22672 this.store = new Roo.data.SimpleStore({
22674 fields: ['value', 'text'],
22677 this.valueField = 'value';
22678 this.displayField = 'text';
22680 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22681 if(!this.lazyRender){
22682 this.target = true;
22683 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22684 s.parentNode.removeChild(s); // remove it
22685 this.render(this.el.parentNode);
22687 s.parentNode.removeChild(s); // remove it
22692 this.store = Roo.factory(this.store, Roo.data);
22695 this.selectedIndex = -1;
22696 if(this.mode == 'local'){
22697 if(config.queryDelay === undefined){
22698 this.queryDelay = 10;
22700 if(config.minChars === undefined){
22706 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22708 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22711 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22712 * rendering into an Roo.Editor, defaults to false)
22715 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22716 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22719 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22722 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22723 * the dropdown list (defaults to undefined, with no header element)
22727 * @cfg {String/Roo.Template} tpl The template to use to render the output
22731 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22733 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22735 listWidth: undefined,
22737 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22738 * mode = 'remote' or 'text' if mode = 'local')
22740 displayField: undefined,
22742 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22743 * mode = 'remote' or 'value' if mode = 'local').
22744 * Note: use of a valueField requires the user make a selection
22745 * in order for a value to be mapped.
22747 valueField: undefined,
22749 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22750 * field's data value (defaults to the underlying DOM element's name)
22752 hiddenName: undefined,
22754 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22758 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22760 selectedClass: 'x-combo-selected',
22762 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22763 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22764 * which displays a downward arrow icon).
22766 triggerClass : 'x-form-arrow-trigger',
22768 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22772 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22773 * anchor positions (defaults to 'tl-bl')
22775 listAlign: 'tl-bl?',
22777 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22781 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22782 * query specified by the allQuery config option (defaults to 'query')
22784 triggerAction: 'query',
22786 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22787 * (defaults to 4, does not apply if editable = false)
22791 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22792 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22796 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22797 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22801 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22802 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22806 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22807 * when editable = true (defaults to false)
22809 selectOnFocus:false,
22811 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22813 queryParam: 'query',
22815 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22816 * when mode = 'remote' (defaults to 'Loading...')
22818 loadingText: 'Loading...',
22820 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22824 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22828 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22829 * traditional select (defaults to true)
22833 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22837 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22841 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22842 * listWidth has a higher value)
22846 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22847 * allow the user to set arbitrary text into the field (defaults to false)
22849 forceSelection:false,
22851 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22852 * if typeAhead = true (defaults to 250)
22854 typeAheadDelay : 250,
22856 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22857 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22859 valueNotFoundText : undefined,
22861 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22863 blockFocus : false,
22866 * @cfg {Boolean} disableClear Disable showing of clear button.
22868 disableClear : false,
22870 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22872 alwaysQuery : false,
22880 onRender : function(ct, position){
22881 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22882 if(this.hiddenName){
22883 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22885 this.hiddenField.value =
22886 this.hiddenValue !== undefined ? this.hiddenValue :
22887 this.value !== undefined ? this.value : '';
22889 // prevent input submission
22890 this.el.dom.removeAttribute('name');
22893 this.el.dom.setAttribute('autocomplete', 'off');
22896 var cls = 'x-combo-list';
22898 this.list = new Roo.Layer({
22899 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22902 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22903 this.list.setWidth(lw);
22904 this.list.swallowEvent('mousewheel');
22905 this.assetHeight = 0;
22908 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22909 this.assetHeight += this.header.getHeight();
22912 this.innerList = this.list.createChild({cls:cls+'-inner'});
22913 this.innerList.on('mouseover', this.onViewOver, this);
22914 this.innerList.on('mousemove', this.onViewMove, this);
22915 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22917 if(this.allowBlank && !this.pageSize && !this.disableClear){
22918 this.footer = this.list.createChild({cls:cls+'-ft'});
22919 this.pageTb = new Roo.Toolbar(this.footer);
22923 this.footer = this.list.createChild({cls:cls+'-ft'});
22924 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22925 {pageSize: this.pageSize});
22929 if (this.pageTb && this.allowBlank && !this.disableClear) {
22931 this.pageTb.add(new Roo.Toolbar.Fill(), {
22932 cls: 'x-btn-icon x-btn-clear',
22934 handler: function()
22937 _this.clearValue();
22938 _this.onSelect(false, -1);
22943 this.assetHeight += this.footer.getHeight();
22948 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22951 this.view = new Roo.View(this.innerList, this.tpl, {
22952 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22955 this.view.on('click', this.onViewClick, this);
22957 this.store.on('beforeload', this.onBeforeLoad, this);
22958 this.store.on('load', this.onLoad, this);
22959 this.store.on('loadexception', this.collapse, this);
22961 if(this.resizable){
22962 this.resizer = new Roo.Resizable(this.list, {
22963 pinned:true, handles:'se'
22965 this.resizer.on('resize', function(r, w, h){
22966 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22967 this.listWidth = w;
22968 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22969 this.restrictHeight();
22971 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22973 if(!this.editable){
22974 this.editable = true;
22975 this.setEditable(false);
22979 if (typeof(this.events.add.listeners) != 'undefined') {
22981 this.addicon = this.wrap.createChild(
22982 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22984 this.addicon.on('click', function(e) {
22985 this.fireEvent('add', this);
22988 if (typeof(this.events.edit.listeners) != 'undefined') {
22990 this.editicon = this.wrap.createChild(
22991 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22992 if (this.addicon) {
22993 this.editicon.setStyle('margin-left', '40px');
22995 this.editicon.on('click', function(e) {
22997 // we fire even if inothing is selected..
22998 this.fireEvent('edit', this, this.lastData );
23008 initEvents : function(){
23009 Roo.form.ComboBox.superclass.initEvents.call(this);
23011 this.keyNav = new Roo.KeyNav(this.el, {
23012 "up" : function(e){
23013 this.inKeyMode = true;
23017 "down" : function(e){
23018 if(!this.isExpanded()){
23019 this.onTriggerClick();
23021 this.inKeyMode = true;
23026 "enter" : function(e){
23027 this.onViewClick();
23031 "esc" : function(e){
23035 "tab" : function(e){
23036 this.onViewClick(false);
23042 doRelay : function(foo, bar, hname){
23043 if(hname == 'down' || this.scope.isExpanded()){
23044 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23051 this.queryDelay = Math.max(this.queryDelay || 10,
23052 this.mode == 'local' ? 10 : 250);
23053 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23054 if(this.typeAhead){
23055 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23057 if(this.editable !== false){
23058 this.el.on("keyup", this.onKeyUp, this);
23060 if(this.forceSelection){
23061 this.on('blur', this.doForce, this);
23065 onDestroy : function(){
23067 this.view.setStore(null);
23068 this.view.el.removeAllListeners();
23069 this.view.el.remove();
23070 this.view.purgeListeners();
23073 this.list.destroy();
23076 this.store.un('beforeload', this.onBeforeLoad, this);
23077 this.store.un('load', this.onLoad, this);
23078 this.store.un('loadexception', this.collapse, this);
23080 Roo.form.ComboBox.superclass.onDestroy.call(this);
23084 fireKey : function(e){
23085 if(e.isNavKeyPress() && !this.list.isVisible()){
23086 this.fireEvent("specialkey", this, e);
23091 onResize: function(w, h){
23092 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23094 if(typeof w != 'number'){
23095 // we do not handle it!?!?
23098 var tw = this.trigger.getWidth();
23099 tw += this.addicon ? this.addicon.getWidth() : 0;
23100 tw += this.editicon ? this.editicon.getWidth() : 0;
23102 this.el.setWidth( this.adjustWidth('input', x));
23104 this.trigger.setStyle('left', x+'px');
23106 if(this.list && this.listWidth === undefined){
23107 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23108 this.list.setWidth(lw);
23109 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23117 * Allow or prevent the user from directly editing the field text. If false is passed,
23118 * the user will only be able to select from the items defined in the dropdown list. This method
23119 * is the runtime equivalent of setting the 'editable' config option at config time.
23120 * @param {Boolean} value True to allow the user to directly edit the field text
23122 setEditable : function(value){
23123 if(value == this.editable){
23126 this.editable = value;
23128 this.el.dom.setAttribute('readOnly', true);
23129 this.el.on('mousedown', this.onTriggerClick, this);
23130 this.el.addClass('x-combo-noedit');
23132 this.el.dom.setAttribute('readOnly', false);
23133 this.el.un('mousedown', this.onTriggerClick, this);
23134 this.el.removeClass('x-combo-noedit');
23139 onBeforeLoad : function(){
23140 if(!this.hasFocus){
23143 this.innerList.update(this.loadingText ?
23144 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23145 this.restrictHeight();
23146 this.selectedIndex = -1;
23150 onLoad : function(){
23151 if(!this.hasFocus){
23154 if(this.store.getCount() > 0){
23156 this.restrictHeight();
23157 if(this.lastQuery == this.allQuery){
23159 this.el.dom.select();
23161 if(!this.selectByValue(this.value, true)){
23162 this.select(0, true);
23166 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23167 this.taTask.delay(this.typeAheadDelay);
23171 this.onEmptyResults();
23177 onTypeAhead : function(){
23178 if(this.store.getCount() > 0){
23179 var r = this.store.getAt(0);
23180 var newValue = r.data[this.displayField];
23181 var len = newValue.length;
23182 var selStart = this.getRawValue().length;
23183 if(selStart != len){
23184 this.setRawValue(newValue);
23185 this.selectText(selStart, newValue.length);
23191 onSelect : function(record, index){
23192 if(this.fireEvent('beforeselect', this, record, index) !== false){
23193 this.setFromData(index > -1 ? record.data : false);
23195 this.fireEvent('select', this, record, index);
23200 * Returns the currently selected field value or empty string if no value is set.
23201 * @return {String} value The selected value
23203 getValue : function(){
23204 if(this.valueField){
23205 return typeof this.value != 'undefined' ? this.value : '';
23207 return Roo.form.ComboBox.superclass.getValue.call(this);
23212 * Clears any text/value currently set in the field
23214 clearValue : function(){
23215 if(this.hiddenField){
23216 this.hiddenField.value = '';
23219 this.setRawValue('');
23220 this.lastSelectionText = '';
23221 this.applyEmptyText();
23225 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23226 * will be displayed in the field. If the value does not match the data value of an existing item,
23227 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23228 * Otherwise the field will be blank (although the value will still be set).
23229 * @param {String} value The value to match
23231 setValue : function(v){
23233 if(this.valueField){
23234 var r = this.findRecord(this.valueField, v);
23236 text = r.data[this.displayField];
23237 }else if(this.valueNotFoundText !== undefined){
23238 text = this.valueNotFoundText;
23241 this.lastSelectionText = text;
23242 if(this.hiddenField){
23243 this.hiddenField.value = v;
23245 Roo.form.ComboBox.superclass.setValue.call(this, text);
23249 * @property {Object} the last set data for the element
23254 * Sets the value of the field based on a object which is related to the record format for the store.
23255 * @param {Object} value the value to set as. or false on reset?
23257 setFromData : function(o){
23258 var dv = ''; // display value
23259 var vv = ''; // value value..
23261 if (this.displayField) {
23262 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23264 // this is an error condition!!!
23265 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23268 if(this.valueField){
23269 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23271 if(this.hiddenField){
23272 this.hiddenField.value = vv;
23274 this.lastSelectionText = dv;
23275 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23279 // no hidden field.. - we store the value in 'value', but still display
23280 // display field!!!!
23281 this.lastSelectionText = dv;
23282 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23288 reset : function(){
23289 // overridden so that last data is reset..
23290 this.setValue(this.originalValue);
23291 this.clearInvalid();
23292 this.lastData = false;
23295 findRecord : function(prop, value){
23297 if(this.store.getCount() > 0){
23298 this.store.each(function(r){
23299 if(r.data[prop] == value){
23309 onViewMove : function(e, t){
23310 this.inKeyMode = false;
23314 onViewOver : function(e, t){
23315 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23318 var item = this.view.findItemFromChild(t);
23320 var index = this.view.indexOf(item);
23321 this.select(index, false);
23326 onViewClick : function(doFocus){
23327 var index = this.view.getSelectedIndexes()[0];
23328 var r = this.store.getAt(index);
23330 this.onSelect(r, index);
23332 if(doFocus !== false && !this.blockFocus){
23338 restrictHeight : function(){
23339 this.innerList.dom.style.height = '';
23340 var inner = this.innerList.dom;
23341 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23342 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23343 this.list.beginUpdate();
23344 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23345 this.list.alignTo(this.el, this.listAlign);
23346 this.list.endUpdate();
23350 onEmptyResults : function(){
23355 * Returns true if the dropdown list is expanded, else false.
23357 isExpanded : function(){
23358 return this.list.isVisible();
23362 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23363 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23364 * @param {String} value The data value of the item to select
23365 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23366 * selected item if it is not currently in view (defaults to true)
23367 * @return {Boolean} True if the value matched an item in the list, else false
23369 selectByValue : function(v, scrollIntoView){
23370 if(v !== undefined && v !== null){
23371 var r = this.findRecord(this.valueField || this.displayField, v);
23373 this.select(this.store.indexOf(r), scrollIntoView);
23381 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23382 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23383 * @param {Number} index The zero-based index of the list item to select
23384 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23385 * selected item if it is not currently in view (defaults to true)
23387 select : function(index, scrollIntoView){
23388 this.selectedIndex = index;
23389 this.view.select(index);
23390 if(scrollIntoView !== false){
23391 var el = this.view.getNode(index);
23393 this.innerList.scrollChildIntoView(el, false);
23399 selectNext : function(){
23400 var ct = this.store.getCount();
23402 if(this.selectedIndex == -1){
23404 }else if(this.selectedIndex < ct-1){
23405 this.select(this.selectedIndex+1);
23411 selectPrev : function(){
23412 var ct = this.store.getCount();
23414 if(this.selectedIndex == -1){
23416 }else if(this.selectedIndex != 0){
23417 this.select(this.selectedIndex-1);
23423 onKeyUp : function(e){
23424 if(this.editable !== false && !e.isSpecialKey()){
23425 this.lastKey = e.getKey();
23426 this.dqTask.delay(this.queryDelay);
23431 validateBlur : function(){
23432 return !this.list || !this.list.isVisible();
23436 initQuery : function(){
23437 this.doQuery(this.getRawValue());
23441 doForce : function(){
23442 if(this.el.dom.value.length > 0){
23443 this.el.dom.value =
23444 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23445 this.applyEmptyText();
23450 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23451 * query allowing the query action to be canceled if needed.
23452 * @param {String} query The SQL query to execute
23453 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23454 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23455 * saved in the current store (defaults to false)
23457 doQuery : function(q, forceAll){
23458 if(q === undefined || q === null){
23463 forceAll: forceAll,
23467 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23471 forceAll = qe.forceAll;
23472 if(forceAll === true || (q.length >= this.minChars)){
23473 if(this.lastQuery != q || this.alwaysQuery){
23474 this.lastQuery = q;
23475 if(this.mode == 'local'){
23476 this.selectedIndex = -1;
23478 this.store.clearFilter();
23480 this.store.filter(this.displayField, q);
23484 this.store.baseParams[this.queryParam] = q;
23486 params: this.getParams(q)
23491 this.selectedIndex = -1;
23498 getParams : function(q){
23500 //p[this.queryParam] = q;
23503 p.limit = this.pageSize;
23509 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23511 collapse : function(){
23512 if(!this.isExpanded()){
23516 Roo.get(document).un('mousedown', this.collapseIf, this);
23517 Roo.get(document).un('mousewheel', this.collapseIf, this);
23518 if (!this.editable) {
23519 Roo.get(document).un('keydown', this.listKeyPress, this);
23521 this.fireEvent('collapse', this);
23525 collapseIf : function(e){
23526 if(!e.within(this.wrap) && !e.within(this.list)){
23532 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23534 expand : function(){
23535 if(this.isExpanded() || !this.hasFocus){
23538 this.list.alignTo(this.el, this.listAlign);
23540 Roo.get(document).on('mousedown', this.collapseIf, this);
23541 Roo.get(document).on('mousewheel', this.collapseIf, this);
23542 if (!this.editable) {
23543 Roo.get(document).on('keydown', this.listKeyPress, this);
23546 this.fireEvent('expand', this);
23550 // Implements the default empty TriggerField.onTriggerClick function
23551 onTriggerClick : function(){
23555 if(this.isExpanded()){
23557 if (!this.blockFocus) {
23562 this.hasFocus = true;
23563 if(this.triggerAction == 'all') {
23564 this.doQuery(this.allQuery, true);
23566 this.doQuery(this.getRawValue());
23568 if (!this.blockFocus) {
23573 listKeyPress : function(e)
23575 //Roo.log('listkeypress');
23576 // scroll to first matching element based on key pres..
23577 if (e.isSpecialKey()) {
23580 var k = String.fromCharCode(e.getKey()).toUpperCase();
23583 var csel = this.view.getSelectedNodes();
23584 var cselitem = false;
23586 var ix = this.view.indexOf(csel[0]);
23587 cselitem = this.store.getAt(ix);
23588 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23594 this.store.each(function(v) {
23596 // start at existing selection.
23597 if (cselitem.id == v.id) {
23603 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23604 match = this.store.indexOf(v);
23609 if (match === false) {
23610 return true; // no more action?
23613 this.view.select(match);
23614 var sn = Roo.get(this.view.getSelectedNodes()[0])
23615 sn.scrollIntoView(sn.dom.parentNode, false);
23619 * @cfg {Boolean} grow
23623 * @cfg {Number} growMin
23627 * @cfg {Number} growMax
23636 * Ext JS Library 1.1.1
23637 * Copyright(c) 2006-2007, Ext JS, LLC.
23639 * Originally Released Under LGPL - original licence link has changed is not relivant.
23642 * <script type="text/javascript">
23645 * @class Roo.form.Checkbox
23646 * @extends Roo.form.Field
23647 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23649 * Creates a new Checkbox
23650 * @param {Object} config Configuration options
23652 Roo.form.Checkbox = function(config){
23653 Roo.form.Checkbox.superclass.constructor.call(this, config);
23657 * Fires when the checkbox is checked or unchecked.
23658 * @param {Roo.form.Checkbox} this This checkbox
23659 * @param {Boolean} checked The new checked value
23665 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23667 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23669 focusClass : undefined,
23671 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23673 fieldClass: "x-form-field",
23675 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23679 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23680 * {tag: "input", type: "checkbox", autocomplete: "off"})
23682 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23684 * @cfg {String} boxLabel The text that appears beside the checkbox
23688 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23692 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23694 valueOff: '0', // value when not checked..
23696 actionMode : 'viewEl',
23699 itemCls : 'x-menu-check-item x-form-item',
23700 groupClass : 'x-menu-group-item',
23701 inputType : 'hidden',
23704 inSetChecked: false, // check that we are not calling self...
23706 inputElement: false, // real input element?
23707 basedOn: false, // ????
23709 isFormField: true, // not sure where this is needed!!!!
23711 onResize : function(){
23712 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23713 if(!this.boxLabel){
23714 this.el.alignTo(this.wrap, 'c-c');
23718 initEvents : function(){
23719 Roo.form.Checkbox.superclass.initEvents.call(this);
23720 this.el.on("click", this.onClick, this);
23721 this.el.on("change", this.onClick, this);
23725 getResizeEl : function(){
23729 getPositionEl : function(){
23734 onRender : function(ct, position){
23735 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23737 if(this.inputValue !== undefined){
23738 this.el.dom.value = this.inputValue;
23741 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23742 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23743 var viewEl = this.wrap.createChild({
23744 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23745 this.viewEl = viewEl;
23746 this.wrap.on('click', this.onClick, this);
23748 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23749 this.el.on('propertychange', this.setFromHidden, this); //ie
23754 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23755 // viewEl.on('click', this.onClick, this);
23757 //if(this.checked){
23758 this.setChecked(this.checked);
23760 //this.checked = this.el.dom;
23766 initValue : Roo.emptyFn,
23769 * Returns the checked state of the checkbox.
23770 * @return {Boolean} True if checked, else false
23772 getValue : function(){
23774 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23776 return this.valueOff;
23781 onClick : function(){
23782 this.setChecked(!this.checked);
23784 //if(this.el.dom.checked != this.checked){
23785 // this.setValue(this.el.dom.checked);
23790 * Sets the checked state of the checkbox.
23791 * On is always based on a string comparison between inputValue and the param.
23792 * @param {Boolean/String} value - the value to set
23793 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23795 setValue : function(v,suppressEvent){
23798 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23799 //if(this.el && this.el.dom){
23800 // this.el.dom.checked = this.checked;
23801 // this.el.dom.defaultChecked = this.checked;
23803 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23804 //this.fireEvent("check", this, this.checked);
23807 setChecked : function(state,suppressEvent)
23809 if (this.inSetChecked) {
23810 this.checked = state;
23816 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23818 this.checked = state;
23819 if(suppressEvent !== true){
23820 this.fireEvent('check', this, state);
23822 this.inSetChecked = true;
23823 this.el.dom.value = state ? this.inputValue : this.valueOff;
23824 this.inSetChecked = false;
23827 // handle setting of hidden value by some other method!!?!?
23828 setFromHidden: function()
23833 //console.log("SET FROM HIDDEN");
23834 //alert('setFrom hidden');
23835 this.setValue(this.el.dom.value);
23838 onDestroy : function()
23841 Roo.get(this.viewEl).remove();
23844 Roo.form.Checkbox.superclass.onDestroy.call(this);
23849 * Ext JS Library 1.1.1
23850 * Copyright(c) 2006-2007, Ext JS, LLC.
23852 * Originally Released Under LGPL - original licence link has changed is not relivant.
23855 * <script type="text/javascript">
23859 * @class Roo.form.Radio
23860 * @extends Roo.form.Checkbox
23861 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23862 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23864 * Creates a new Radio
23865 * @param {Object} config Configuration options
23867 Roo.form.Radio = function(){
23868 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23870 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23871 inputType: 'radio',
23874 * If this radio is part of a group, it will return the selected value
23877 getGroupValue : function(){
23878 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23880 });//<script type="text/javascript">
23883 * Ext JS Library 1.1.1
23884 * Copyright(c) 2006-2007, Ext JS, LLC.
23885 * licensing@extjs.com
23887 * http://www.extjs.com/license
23893 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23894 * - IE ? - no idea how much works there.
23902 * @class Ext.form.HtmlEditor
23903 * @extends Ext.form.Field
23904 * Provides a lightweight HTML Editor component.
23905 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23907 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23908 * supported by this editor.</b><br/><br/>
23909 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23910 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23912 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23914 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23918 * @cfg {String} createLinkText The default text for the create link prompt
23920 createLinkText : 'Please enter the URL for the link:',
23922 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23924 defaultLinkValue : 'http:/'+'/',
23930 // private properties
23931 validationEvent : false,
23933 initialized : false,
23935 sourceEditMode : false,
23936 onFocus : Roo.emptyFn,
23938 hideMode:'offsets',
23939 defaultAutoCreate : {
23941 style:"width:500px;height:300px;",
23942 autocomplete: "off"
23946 initComponent : function(){
23949 * @event initialize
23950 * Fires when the editor is fully initialized (including the iframe)
23951 * @param {HtmlEditor} this
23956 * Fires when the editor is first receives the focus. Any insertion must wait
23957 * until after this event.
23958 * @param {HtmlEditor} this
23962 * @event beforesync
23963 * Fires before the textarea is updated with content from the editor iframe. Return false
23964 * to cancel the sync.
23965 * @param {HtmlEditor} this
23966 * @param {String} html
23970 * @event beforepush
23971 * Fires before the iframe editor is updated with content from the textarea. Return false
23972 * to cancel the push.
23973 * @param {HtmlEditor} this
23974 * @param {String} html
23979 * Fires when the textarea is updated with content from the editor iframe.
23980 * @param {HtmlEditor} this
23981 * @param {String} html
23986 * Fires when the iframe editor is updated with content from the textarea.
23987 * @param {HtmlEditor} this
23988 * @param {String} html
23992 * @event editmodechange
23993 * Fires when the editor switches edit modes
23994 * @param {HtmlEditor} this
23995 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23997 editmodechange: true,
23999 * @event editorevent
24000 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24001 * @param {HtmlEditor} this
24008 * Protected method that will not generally be called directly. It
24009 * is called when the editor creates its toolbar. Override this method if you need to
24010 * add custom toolbar buttons.
24011 * @param {HtmlEditor} editor
24013 createToolbar : function(editor){
24014 if (!editor.toolbars || !editor.toolbars.length) {
24015 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
24018 for (var i =0 ; i < editor.toolbars.length;i++) {
24019 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
24020 editor.toolbars[i].init(editor);
24027 * Protected method that will not generally be called directly. It
24028 * is called when the editor initializes the iframe with HTML contents. Override this method if you
24029 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
24031 getDocMarkup : function(){
24032 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
24036 onRender : function(ct, position){
24037 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24038 this.el.dom.style.border = '0 none';
24039 this.el.dom.setAttribute('tabIndex', -1);
24040 this.el.addClass('x-hidden');
24041 if(Roo.isIE){ // fix IE 1px bogus margin
24042 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24044 this.wrap = this.el.wrap({
24045 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24048 this.frameId = Roo.id();
24049 this.createToolbar(this);
24056 var iframe = this.wrap.createChild({
24059 name: this.frameId,
24060 frameBorder : 'no',
24061 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24064 // console.log(iframe);
24065 //this.wrap.dom.appendChild(iframe);
24067 this.iframe = iframe.dom;
24069 this.assignDocWin();
24071 this.doc.designMode = 'on';
24074 this.doc.write(this.getDocMarkup());
24078 var task = { // must defer to wait for browser to be ready
24080 //console.log("run task?" + this.doc.readyState);
24081 this.assignDocWin();
24082 if(this.doc.body || this.doc.readyState == 'complete'){
24084 this.doc.designMode="on";
24088 Roo.TaskMgr.stop(task);
24089 this.initEditor.defer(10, this);
24096 Roo.TaskMgr.start(task);
24099 this.setSize(this.el.getSize());
24104 onResize : function(w, h){
24105 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24106 if(this.el && this.iframe){
24107 if(typeof w == 'number'){
24108 var aw = w - this.wrap.getFrameWidth('lr');
24109 this.el.setWidth(this.adjustWidth('textarea', aw));
24110 this.iframe.style.width = aw + 'px';
24112 if(typeof h == 'number'){
24114 for (var i =0; i < this.toolbars.length;i++) {
24115 // fixme - ask toolbars for heights?
24116 tbh += this.toolbars[i].tb.el.getHeight();
24122 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24123 this.el.setHeight(this.adjustWidth('textarea', ah));
24124 this.iframe.style.height = ah + 'px';
24126 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24133 * Toggles the editor between standard and source edit mode.
24134 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24136 toggleSourceEdit : function(sourceEditMode){
24138 this.sourceEditMode = sourceEditMode === true;
24140 if(this.sourceEditMode){
24143 this.iframe.className = 'x-hidden';
24144 this.el.removeClass('x-hidden');
24145 this.el.dom.removeAttribute('tabIndex');
24150 this.iframe.className = '';
24151 this.el.addClass('x-hidden');
24152 this.el.dom.setAttribute('tabIndex', -1);
24155 this.setSize(this.wrap.getSize());
24156 this.fireEvent('editmodechange', this, this.sourceEditMode);
24159 // private used internally
24160 createLink : function(){
24161 var url = prompt(this.createLinkText, this.defaultLinkValue);
24162 if(url && url != 'http:/'+'/'){
24163 this.relayCmd('createlink', url);
24167 // private (for BoxComponent)
24168 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24170 // private (for BoxComponent)
24171 getResizeEl : function(){
24175 // private (for BoxComponent)
24176 getPositionEl : function(){
24181 initEvents : function(){
24182 this.originalValue = this.getValue();
24186 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24189 markInvalid : Roo.emptyFn,
24191 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24194 clearInvalid : Roo.emptyFn,
24196 setValue : function(v){
24197 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24202 * Protected method that will not generally be called directly. If you need/want
24203 * custom HTML cleanup, this is the method you should override.
24204 * @param {String} html The HTML to be cleaned
24205 * return {String} The cleaned HTML
24207 cleanHtml : function(html){
24208 html = String(html);
24209 if(html.length > 5){
24210 if(Roo.isSafari){ // strip safari nonsense
24211 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24214 if(html == ' '){
24221 * Protected method that will not generally be called directly. Syncs the contents
24222 * of the editor iframe with the textarea.
24224 syncValue : function(){
24225 if(this.initialized){
24226 var bd = (this.doc.body || this.doc.documentElement);
24227 this.cleanUpPaste();
24228 var html = bd.innerHTML;
24230 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24231 var m = bs.match(/text-align:(.*?);/i);
24233 html = '<div style="'+m[0]+'">' + html + '</div>';
24236 html = this.cleanHtml(html);
24237 if(this.fireEvent('beforesync', this, html) !== false){
24238 this.el.dom.value = html;
24239 this.fireEvent('sync', this, html);
24245 * Protected method that will not generally be called directly. Pushes the value of the textarea
24246 * into the iframe editor.
24248 pushValue : function(){
24249 if(this.initialized){
24250 var v = this.el.dom.value;
24255 if(this.fireEvent('beforepush', this, v) !== false){
24256 var d = (this.doc.body || this.doc.documentElement);
24258 this.cleanUpPaste();
24259 this.el.dom.value = d.innerHTML;
24260 this.fireEvent('push', this, v);
24266 deferFocus : function(){
24267 this.focus.defer(10, this);
24271 focus : function(){
24272 if(this.win && !this.sourceEditMode){
24279 assignDocWin: function()
24281 var iframe = this.iframe;
24284 this.doc = iframe.contentWindow.document;
24285 this.win = iframe.contentWindow;
24287 if (!Roo.get(this.frameId)) {
24290 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24291 this.win = Roo.get(this.frameId).dom.contentWindow;
24296 initEditor : function(){
24297 //console.log("INIT EDITOR");
24298 this.assignDocWin();
24302 this.doc.designMode="on";
24304 this.doc.write(this.getDocMarkup());
24307 var dbody = (this.doc.body || this.doc.documentElement);
24308 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24309 // this copies styles from the containing element into thsi one..
24310 // not sure why we need all of this..
24311 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24312 ss['background-attachment'] = 'fixed'; // w3c
24313 dbody.bgProperties = 'fixed'; // ie
24314 Roo.DomHelper.applyStyles(dbody, ss);
24315 Roo.EventManager.on(this.doc, {
24316 'mousedown': this.onEditorEvent,
24317 'dblclick': this.onEditorEvent,
24318 'click': this.onEditorEvent,
24319 'keyup': this.onEditorEvent,
24324 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24326 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24327 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24329 this.initialized = true;
24331 this.fireEvent('initialize', this);
24336 onDestroy : function(){
24342 for (var i =0; i < this.toolbars.length;i++) {
24343 // fixme - ask toolbars for heights?
24344 this.toolbars[i].onDestroy();
24347 this.wrap.dom.innerHTML = '';
24348 this.wrap.remove();
24353 onFirstFocus : function(){
24355 this.assignDocWin();
24358 this.activated = true;
24359 for (var i =0; i < this.toolbars.length;i++) {
24360 this.toolbars[i].onFirstFocus();
24363 if(Roo.isGecko){ // prevent silly gecko errors
24365 var s = this.win.getSelection();
24366 if(!s.focusNode || s.focusNode.nodeType != 3){
24367 var r = s.getRangeAt(0);
24368 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24373 this.execCmd('useCSS', true);
24374 this.execCmd('styleWithCSS', false);
24377 this.fireEvent('activate', this);
24381 adjustFont: function(btn){
24382 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24383 //if(Roo.isSafari){ // safari
24386 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24387 if(Roo.isSafari){ // safari
24388 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24389 v = (v < 10) ? 10 : v;
24390 v = (v > 48) ? 48 : v;
24391 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24396 v = Math.max(1, v+adjust);
24398 this.execCmd('FontSize', v );
24401 onEditorEvent : function(e){
24402 this.fireEvent('editorevent', this, e);
24403 // this.updateToolbar();
24407 insertTag : function(tg)
24409 // could be a bit smarter... -> wrap the current selected tRoo..
24411 this.execCmd("formatblock", tg);
24415 insertText : function(txt)
24419 range = this.createRange();
24420 range.deleteContents();
24421 //alert(Sender.getAttribute('label'));
24423 range.insertNode(this.doc.createTextNode(txt));
24427 relayBtnCmd : function(btn){
24428 this.relayCmd(btn.cmd);
24432 * Executes a Midas editor command on the editor document and performs necessary focus and
24433 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24434 * @param {String} cmd The Midas command
24435 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24437 relayCmd : function(cmd, value){
24439 this.execCmd(cmd, value);
24440 this.fireEvent('editorevent', this);
24441 //this.updateToolbar();
24446 * Executes a Midas editor command directly on the editor document.
24447 * For visual commands, you should use {@link #relayCmd} instead.
24448 * <b>This should only be called after the editor is initialized.</b>
24449 * @param {String} cmd The Midas command
24450 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24452 execCmd : function(cmd, value){
24453 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24459 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24461 * @param {String} text
24463 insertAtCursor : function(text){
24464 if(!this.activated){
24469 var r = this.doc.selection.createRange();
24476 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24478 this.execCmd('InsertHTML', text);
24483 mozKeyPress : function(e){
24485 var c = e.getCharCode(), cmd;
24488 c = String.fromCharCode(c).toLowerCase();
24499 this.cleanUpPaste.defer(100, this);
24507 e.preventDefault();
24515 fixKeys : function(){ // load time branching for fastest keydown performance
24517 return function(e){
24518 var k = e.getKey(), r;
24521 r = this.doc.selection.createRange();
24524 r.pasteHTML('    ');
24531 r = this.doc.selection.createRange();
24533 var target = r.parentElement();
24534 if(!target || target.tagName.toLowerCase() != 'li'){
24536 r.pasteHTML('<br />');
24542 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24543 this.cleanUpPaste.defer(100, this);
24549 }else if(Roo.isOpera){
24550 return function(e){
24551 var k = e.getKey();
24555 this.execCmd('InsertHTML','    ');
24558 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24559 this.cleanUpPaste.defer(100, this);
24564 }else if(Roo.isSafari){
24565 return function(e){
24566 var k = e.getKey();
24570 this.execCmd('InsertText','\t');
24574 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24575 this.cleanUpPaste.defer(100, this);
24583 getAllAncestors: function()
24585 var p = this.getSelectedNode();
24588 a.push(p); // push blank onto stack..
24589 p = this.getParentElement();
24593 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24597 a.push(this.doc.body);
24601 lastSelNode : false,
24604 getSelection : function()
24606 this.assignDocWin();
24607 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24610 getSelectedNode: function()
24612 // this may only work on Gecko!!!
24614 // should we cache this!!!!
24619 var range = this.createRange(this.getSelection());
24622 var parent = range.parentElement();
24624 var testRange = range.duplicate();
24625 testRange.moveToElementText(parent);
24626 if (testRange.inRange(range)) {
24629 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24632 parent = parent.parentElement;
24638 var ar = range.endContainer.childNodes;
24640 ar = range.commonAncestorContainer.childNodes;
24641 //alert(ar.length);
24644 var other_nodes = [];
24645 var has_other_nodes = false;
24646 for (var i=0;i<ar.length;i++) {
24647 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24650 // fullly contained node.
24652 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24657 // probably selected..
24658 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24659 other_nodes.push(ar[i]);
24662 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24667 has_other_nodes = true;
24669 if (!nodes.length && other_nodes.length) {
24670 nodes= other_nodes;
24672 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24678 createRange: function(sel)
24680 // this has strange effects when using with
24681 // top toolbar - not sure if it's a great idea.
24682 //this.editor.contentWindow.focus();
24683 if (typeof sel != "undefined") {
24685 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24687 return this.doc.createRange();
24690 return this.doc.createRange();
24693 getParentElement: function()
24696 this.assignDocWin();
24697 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24699 var range = this.createRange(sel);
24702 var p = range.commonAncestorContainer;
24703 while (p.nodeType == 3) { // text node
24715 // BC Hacks - cause I cant work out what i was trying to do..
24716 rangeIntersectsNode : function(range, node)
24718 var nodeRange = node.ownerDocument.createRange();
24720 nodeRange.selectNode(node);
24723 nodeRange.selectNodeContents(node);
24726 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24727 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24729 rangeCompareNode : function(range, node) {
24730 var nodeRange = node.ownerDocument.createRange();
24732 nodeRange.selectNode(node);
24734 nodeRange.selectNodeContents(node);
24736 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24737 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24739 if (nodeIsBefore && !nodeIsAfter)
24741 if (!nodeIsBefore && nodeIsAfter)
24743 if (nodeIsBefore && nodeIsAfter)
24749 // private? - in a new class?
24750 cleanUpPaste : function()
24752 // cleans up the whole document..
24753 // console.log('cleanuppaste');
24754 this.cleanUpChildren(this.doc.body);
24758 cleanUpChildren : function (n)
24760 if (!n.childNodes.length) {
24763 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24764 this.cleanUpChild(n.childNodes[i]);
24771 cleanUpChild : function (node)
24773 //console.log(node);
24774 if (node.nodeName == "#text") {
24775 // clean up silly Windows -- stuff?
24778 if (node.nodeName == "#comment") {
24779 node.parentNode.removeChild(node);
24780 // clean up silly Windows -- stuff?
24784 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24786 node.parentNode.removeChild(node);
24790 if (!node.attributes || !node.attributes.length) {
24791 this.cleanUpChildren(node);
24795 function cleanAttr(n,v)
24798 if (v.match(/^\./) || v.match(/^\//)) {
24801 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24804 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24805 node.removeAttribute(n);
24809 function cleanStyle(n,v)
24811 if (v.match(/expression/)) { //XSS?? should we even bother..
24812 node.removeAttribute(n);
24817 var parts = v.split(/;/);
24818 Roo.each(parts, function(p) {
24819 p = p.replace(/\s+/g,'');
24823 var l = p.split(':').shift().replace(/\s+/g,'');
24825 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24826 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24827 node.removeAttribute(n);
24836 for (var i = node.attributes.length-1; i > -1 ; i--) {
24837 var a = node.attributes[i];
24839 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24840 node.removeAttribute(a.name);
24843 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24844 cleanAttr(a.name,a.value); // fixme..
24847 if (a.name == 'style') {
24848 cleanStyle(a.name,a.value);
24850 /// clean up MS crap..
24851 if (a.name == 'class') {
24852 if (a.value.match(/^Mso/)) {
24853 node.className = '';
24863 this.cleanUpChildren(node);
24869 // hide stuff that is not compatible
24883 * @event specialkey
24887 * @cfg {String} fieldClass @hide
24890 * @cfg {String} focusClass @hide
24893 * @cfg {String} autoCreate @hide
24896 * @cfg {String} inputType @hide
24899 * @cfg {String} invalidClass @hide
24902 * @cfg {String} invalidText @hide
24905 * @cfg {String} msgFx @hide
24908 * @cfg {String} validateOnBlur @hide
24912 Roo.form.HtmlEditor.white = [
24913 'area', 'br', 'img', 'input', 'hr', 'wbr',
24915 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24916 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24917 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24918 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24919 'table', 'ul', 'xmp',
24921 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24924 'dir', 'menu', 'ol', 'ul', 'dl',
24930 Roo.form.HtmlEditor.black = [
24931 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24933 'base', 'basefont', 'bgsound', 'blink', 'body',
24934 'frame', 'frameset', 'head', 'html', 'ilayer',
24935 'iframe', 'layer', 'link', 'meta', 'object',
24936 'script', 'style' ,'title', 'xml' // clean later..
24938 Roo.form.HtmlEditor.clean = [
24939 'script', 'style', 'title', 'xml'
24944 Roo.form.HtmlEditor.ablack = [
24948 Roo.form.HtmlEditor.aclean = [
24949 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24953 Roo.form.HtmlEditor.pwhite= [
24954 'http', 'https', 'mailto'
24957 Roo.form.HtmlEditor.cwhite= [
24962 // <script type="text/javascript">
24965 * Ext JS Library 1.1.1
24966 * Copyright(c) 2006-2007, Ext JS, LLC.
24972 * @class Roo.form.HtmlEditorToolbar1
24977 new Roo.form.HtmlEditor({
24980 new Roo.form.HtmlEditorToolbar1({
24981 disable : { fonts: 1 , format: 1, ..., ... , ...],
24987 * @cfg {Object} disable List of elements to disable..
24988 * @cfg {Array} btns List of additional buttons.
24992 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24995 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24998 Roo.apply(this, config);
24999 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25000 // dont call parent... till later.
25003 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
25011 * @cfg {Object} disable List of toolbar elements to disable
25016 * @cfg {Array} fontFamilies An array of available font families
25034 // "á" , ?? a acute?
25039 "°" // , // degrees
25041 // "é" , // e ecute
25042 // "ú" , // u ecute?
25045 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25046 "input:submit", "input:button", "select", "textarea", "label" ],
25049 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25051 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25054 * @cfg {String} defaultFont default font to use.
25056 defaultFont: 'tahoma',
25058 fontSelect : false,
25061 formatCombo : false,
25063 init : function(editor)
25065 this.editor = editor;
25068 var fid = editor.frameId;
25070 function btn(id, toggle, handler){
25071 var xid = fid + '-'+ id ;
25075 cls : 'x-btn-icon x-edit-'+id,
25076 enableToggle:toggle !== false,
25077 scope: editor, // was editor...
25078 handler:handler||editor.relayBtnCmd,
25079 clickEvent:'mousedown',
25080 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25087 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25089 // stop form submits
25090 tb.el.on('click', function(e){
25091 e.preventDefault(); // what does this do?
25094 if(!this.disable.font && !Roo.isSafari){
25095 /* why no safari for fonts
25096 editor.fontSelect = tb.el.createChild({
25099 cls:'x-font-select',
25100 html: editor.createFontOptions()
25102 editor.fontSelect.on('change', function(){
25103 var font = editor.fontSelect.dom.value;
25104 editor.relayCmd('fontname', font);
25105 editor.deferFocus();
25108 editor.fontSelect.dom,
25113 if(!this.disable.formats){
25114 this.formatCombo = new Roo.form.ComboBox({
25115 store: new Roo.data.SimpleStore({
25118 data : this.formats // from states.js
25121 //autoCreate : {tag: "div", size: "20"},
25122 displayField:'tag',
25126 triggerAction: 'all',
25127 emptyText:'Add tag',
25128 selectOnFocus:true,
25131 'select': function(c, r, i) {
25132 editor.insertTag(r.get('tag'));
25138 tb.addField(this.formatCombo);
25142 if(!this.disable.format){
25149 if(!this.disable.fontSize){
25154 btn('increasefontsize', false, editor.adjustFont),
25155 btn('decreasefontsize', false, editor.adjustFont)
25160 if(this.disable.colors){
25163 id:editor.frameId +'-forecolor',
25164 cls:'x-btn-icon x-edit-forecolor',
25165 clickEvent:'mousedown',
25166 tooltip: this.buttonTips['forecolor'] || undefined,
25168 menu : new Roo.menu.ColorMenu({
25169 allowReselect: true,
25170 focus: Roo.emptyFn,
25173 selectHandler: function(cp, color){
25174 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25175 editor.deferFocus();
25178 clickEvent:'mousedown'
25181 id:editor.frameId +'backcolor',
25182 cls:'x-btn-icon x-edit-backcolor',
25183 clickEvent:'mousedown',
25184 tooltip: this.buttonTips['backcolor'] || undefined,
25186 menu : new Roo.menu.ColorMenu({
25187 focus: Roo.emptyFn,
25190 allowReselect: true,
25191 selectHandler: function(cp, color){
25193 editor.execCmd('useCSS', false);
25194 editor.execCmd('hilitecolor', color);
25195 editor.execCmd('useCSS', true);
25196 editor.deferFocus();
25198 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25199 Roo.isSafari || Roo.isIE ? '#'+color : color);
25200 editor.deferFocus();
25204 clickEvent:'mousedown'
25209 // now add all the items...
25212 if(!this.disable.alignments){
25215 btn('justifyleft'),
25216 btn('justifycenter'),
25217 btn('justifyright')
25221 //if(!Roo.isSafari){
25222 if(!this.disable.links){
25225 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25229 if(!this.disable.lists){
25232 btn('insertorderedlist'),
25233 btn('insertunorderedlist')
25236 if(!this.disable.sourceEdit){
25239 btn('sourceedit', true, function(btn){
25240 this.toggleSourceEdit(btn.pressed);
25247 // special menu.. - needs to be tidied up..
25248 if (!this.disable.special) {
25251 cls: 'x-edit-none',
25256 for (var i =0; i < this.specialChars.length; i++) {
25257 smenu.menu.items.push({
25259 html: this.specialChars[i],
25260 handler: function(a,b) {
25261 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25274 for(var i =0; i< this.btns.length;i++) {
25275 var b = this.btns[i];
25276 b.cls = 'x-edit-none';
25285 // disable everything...
25287 this.tb.items.each(function(item){
25288 if(item.id != editor.frameId+ '-sourceedit'){
25292 this.rendered = true;
25294 // the all the btns;
25295 editor.on('editorevent', this.updateToolbar, this);
25296 // other toolbars need to implement this..
25297 //editor.on('editmodechange', this.updateToolbar, this);
25303 * Protected method that will not generally be called directly. It triggers
25304 * a toolbar update by reading the markup state of the current selection in the editor.
25306 updateToolbar: function(){
25308 if(!this.editor.activated){
25309 this.editor.onFirstFocus();
25313 var btns = this.tb.items.map,
25314 doc = this.editor.doc,
25315 frameId = this.editor.frameId;
25317 if(!this.disable.font && !Roo.isSafari){
25319 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25320 if(name != this.fontSelect.dom.value){
25321 this.fontSelect.dom.value = name;
25325 if(!this.disable.format){
25326 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25327 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25328 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25330 if(!this.disable.alignments){
25331 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25332 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25333 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25335 if(!Roo.isSafari && !this.disable.lists){
25336 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25337 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25340 var ans = this.editor.getAllAncestors();
25341 if (this.formatCombo) {
25344 var store = this.formatCombo.store;
25345 this.formatCombo.setValue("");
25346 for (var i =0; i < ans.length;i++) {
25347 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25349 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25357 // hides menus... - so this cant be on a menu...
25358 Roo.menu.MenuMgr.hideAll();
25360 //this.editorsyncValue();
25364 createFontOptions : function(){
25365 var buf = [], fs = this.fontFamilies, ff, lc;
25366 for(var i = 0, len = fs.length; i< len; i++){
25368 lc = ff.toLowerCase();
25370 '<option value="',lc,'" style="font-family:',ff,';"',
25371 (this.defaultFont == lc ? ' selected="true">' : '>'),
25376 return buf.join('');
25379 toggleSourceEdit : function(sourceEditMode){
25380 if(sourceEditMode === undefined){
25381 sourceEditMode = !this.sourceEditMode;
25383 this.sourceEditMode = sourceEditMode === true;
25384 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25385 // just toggle the button?
25386 if(btn.pressed !== this.editor.sourceEditMode){
25387 btn.toggle(this.editor.sourceEditMode);
25391 if(this.sourceEditMode){
25392 this.tb.items.each(function(item){
25393 if(item.cmd != 'sourceedit'){
25399 if(this.initialized){
25400 this.tb.items.each(function(item){
25406 // tell the editor that it's been pressed..
25407 this.editor.toggleSourceEdit(sourceEditMode);
25411 * Object collection of toolbar tooltips for the buttons in the editor. The key
25412 * is the command id associated with that button and the value is a valid QuickTips object.
25417 title: 'Bold (Ctrl+B)',
25418 text: 'Make the selected text bold.',
25419 cls: 'x-html-editor-tip'
25422 title: 'Italic (Ctrl+I)',
25423 text: 'Make the selected text italic.',
25424 cls: 'x-html-editor-tip'
25432 title: 'Bold (Ctrl+B)',
25433 text: 'Make the selected text bold.',
25434 cls: 'x-html-editor-tip'
25437 title: 'Italic (Ctrl+I)',
25438 text: 'Make the selected text italic.',
25439 cls: 'x-html-editor-tip'
25442 title: 'Underline (Ctrl+U)',
25443 text: 'Underline the selected text.',
25444 cls: 'x-html-editor-tip'
25446 increasefontsize : {
25447 title: 'Grow Text',
25448 text: 'Increase the font size.',
25449 cls: 'x-html-editor-tip'
25451 decreasefontsize : {
25452 title: 'Shrink Text',
25453 text: 'Decrease the font size.',
25454 cls: 'x-html-editor-tip'
25457 title: 'Text Highlight Color',
25458 text: 'Change the background color of the selected text.',
25459 cls: 'x-html-editor-tip'
25462 title: 'Font Color',
25463 text: 'Change the color of the selected text.',
25464 cls: 'x-html-editor-tip'
25467 title: 'Align Text Left',
25468 text: 'Align text to the left.',
25469 cls: 'x-html-editor-tip'
25472 title: 'Center Text',
25473 text: 'Center text in the editor.',
25474 cls: 'x-html-editor-tip'
25477 title: 'Align Text Right',
25478 text: 'Align text to the right.',
25479 cls: 'x-html-editor-tip'
25481 insertunorderedlist : {
25482 title: 'Bullet List',
25483 text: 'Start a bulleted list.',
25484 cls: 'x-html-editor-tip'
25486 insertorderedlist : {
25487 title: 'Numbered List',
25488 text: 'Start a numbered list.',
25489 cls: 'x-html-editor-tip'
25492 title: 'Hyperlink',
25493 text: 'Make the selected text a hyperlink.',
25494 cls: 'x-html-editor-tip'
25497 title: 'Source Edit',
25498 text: 'Switch to source editing mode.',
25499 cls: 'x-html-editor-tip'
25503 onDestroy : function(){
25506 this.tb.items.each(function(item){
25508 item.menu.removeAll();
25510 item.menu.el.destroy();
25518 onFirstFocus: function() {
25519 this.tb.items.each(function(item){
25528 // <script type="text/javascript">
25531 * Ext JS Library 1.1.1
25532 * Copyright(c) 2006-2007, Ext JS, LLC.
25539 * @class Roo.form.HtmlEditor.ToolbarContext
25544 new Roo.form.HtmlEditor({
25547 new Roo.form.HtmlEditor.ToolbarStandard(),
25548 new Roo.form.HtmlEditor.ToolbarContext()
25553 * @config : {Object} disable List of elements to disable.. (not done yet.)
25558 Roo.form.HtmlEditor.ToolbarContext = function(config)
25561 Roo.apply(this, config);
25562 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25563 // dont call parent... till later.
25565 Roo.form.HtmlEditor.ToolbarContext.types = {
25577 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25639 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25644 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25708 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25716 * @cfg {Object} disable List of toolbar elements to disable
25725 init : function(editor)
25727 this.editor = editor;
25730 var fid = editor.frameId;
25732 function btn(id, toggle, handler){
25733 var xid = fid + '-'+ id ;
25737 cls : 'x-btn-icon x-edit-'+id,
25738 enableToggle:toggle !== false,
25739 scope: editor, // was editor...
25740 handler:handler||editor.relayBtnCmd,
25741 clickEvent:'mousedown',
25742 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25746 // create a new element.
25747 var wdiv = editor.wrap.createChild({
25749 }, editor.wrap.dom.firstChild.nextSibling, true);
25751 // can we do this more than once??
25753 // stop form submits
25756 // disable everything...
25757 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25758 this.toolbars = {};
25760 for (var i in ty) {
25762 this.toolbars[i] = this.buildToolbar(ty[i],i);
25764 this.tb = this.toolbars.BODY;
25768 this.rendered = true;
25770 // the all the btns;
25771 editor.on('editorevent', this.updateToolbar, this);
25772 // other toolbars need to implement this..
25773 //editor.on('editmodechange', this.updateToolbar, this);
25779 * Protected method that will not generally be called directly. It triggers
25780 * a toolbar update by reading the markup state of the current selection in the editor.
25782 updateToolbar: function(){
25784 if(!this.editor.activated){
25785 this.editor.onFirstFocus();
25790 var ans = this.editor.getAllAncestors();
25793 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25794 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25795 sel = sel ? sel : this.editor.doc.body;
25796 sel = sel.tagName.length ? sel : this.editor.doc.body;
25797 var tn = sel.tagName.toUpperCase();
25798 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25799 tn = sel.tagName.toUpperCase();
25800 if (this.tb.name == tn) {
25801 return; // no change
25804 ///console.log("show: " + tn);
25805 this.tb = this.toolbars[tn];
25807 this.tb.fields.each(function(e) {
25808 e.setValue(sel.getAttribute(e.name));
25810 this.tb.selectedNode = sel;
25813 Roo.menu.MenuMgr.hideAll();
25815 //this.editorsyncValue();
25820 onDestroy : function(){
25823 this.tb.items.each(function(item){
25825 item.menu.removeAll();
25827 item.menu.el.destroy();
25835 onFirstFocus: function() {
25836 // need to do this for all the toolbars..
25837 this.tb.items.each(function(item){
25841 buildToolbar: function(tlist, nm)
25843 var editor = this.editor;
25844 // create a new element.
25845 var wdiv = editor.wrap.createChild({
25847 }, editor.wrap.dom.firstChild.nextSibling, true);
25850 var tb = new Roo.Toolbar(wdiv);
25851 tb.add(nm+ ": ");
25852 for (var i in tlist) {
25853 var item = tlist[i];
25854 tb.add(item.title + ": ");
25859 tb.addField( new Roo.form.ComboBox({
25860 store: new Roo.data.SimpleStore({
25863 data : item.opts // from states.js
25866 displayField:'val',
25870 triggerAction: 'all',
25871 emptyText:'Select',
25872 selectOnFocus:true,
25873 width: item.width ? item.width : 130,
25875 'select': function(c, r, i) {
25876 tb.selectedNode.setAttribute(c.name, r.get('val'));
25887 tb.addField( new Roo.form.TextField({
25890 //allowBlank:false,
25895 tb.addField( new Roo.form.TextField({
25901 'change' : function(f, nv, ov) {
25902 tb.selectedNode.setAttribute(f.name, nv);
25908 tb.el.on('click', function(e){
25909 e.preventDefault(); // what does this do?
25911 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25914 // dont need to disable them... as they will get hidden
25931 * Ext JS Library 1.1.1
25932 * Copyright(c) 2006-2007, Ext JS, LLC.
25934 * Originally Released Under LGPL - original licence link has changed is not relivant.
25937 * <script type="text/javascript">
25941 * @class Roo.form.BasicForm
25942 * @extends Roo.util.Observable
25943 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25945 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25946 * @param {Object} config Configuration options
25948 Roo.form.BasicForm = function(el, config){
25949 this.allItems = [];
25950 this.childForms = [];
25951 Roo.apply(this, config);
25953 * The Roo.form.Field items in this form.
25954 * @type MixedCollection
25958 this.items = new Roo.util.MixedCollection(false, function(o){
25959 return o.id || (o.id = Roo.id());
25963 * @event beforeaction
25964 * Fires before any action is performed. Return false to cancel the action.
25965 * @param {Form} this
25966 * @param {Action} action The action to be performed
25968 beforeaction: true,
25970 * @event actionfailed
25971 * Fires when an action fails.
25972 * @param {Form} this
25973 * @param {Action} action The action that failed
25975 actionfailed : true,
25977 * @event actioncomplete
25978 * Fires when an action is completed.
25979 * @param {Form} this
25980 * @param {Action} action The action that completed
25982 actioncomplete : true
25987 Roo.form.BasicForm.superclass.constructor.call(this);
25990 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25992 * @cfg {String} method
25993 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25996 * @cfg {DataReader} reader
25997 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25998 * This is optional as there is built-in support for processing JSON.
26001 * @cfg {DataReader} errorReader
26002 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
26003 * This is completely optional as there is built-in support for processing JSON.
26006 * @cfg {String} url
26007 * The URL to use for form actions if one isn't supplied in the action options.
26010 * @cfg {Boolean} fileUpload
26011 * Set to true if this form is a file upload.
26015 * @cfg {Object} baseParams
26016 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
26021 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
26026 activeAction : null,
26029 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
26030 * or setValues() data instead of when the form was first created.
26032 trackResetOnLoad : false,
26036 * childForms - used for multi-tab forms
26039 childForms : false,
26042 * allItems - full list of fields.
26048 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26049 * element by passing it or its id or mask the form itself by passing in true.
26052 waitMsgTarget : false,
26055 initEl : function(el){
26056 this.el = Roo.get(el);
26057 this.id = this.el.id || Roo.id();
26058 this.el.on('submit', this.onSubmit, this);
26059 this.el.addClass('x-form');
26063 onSubmit : function(e){
26068 * Returns true if client-side validation on the form is successful.
26071 isValid : function(){
26073 this.items.each(function(f){
26082 * Returns true if any fields in this form have changed since their original load.
26085 isDirty : function(){
26087 this.items.each(function(f){
26097 * Performs a predefined action (submit or load) or custom actions you define on this form.
26098 * @param {String} actionName The name of the action type
26099 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26100 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26101 * accept other config options):
26103 Property Type Description
26104 ---------------- --------------- ----------------------------------------------------------------------------------
26105 url String The url for the action (defaults to the form's url)
26106 method String The form method to use (defaults to the form's method, or POST if not defined)
26107 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26108 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26109 validate the form on the client (defaults to false)
26111 * @return {BasicForm} this
26113 doAction : function(action, options){
26114 if(typeof action == 'string'){
26115 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26117 if(this.fireEvent('beforeaction', this, action) !== false){
26118 this.beforeAction(action);
26119 action.run.defer(100, action);
26125 * Shortcut to do a submit action.
26126 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26127 * @return {BasicForm} this
26129 submit : function(options){
26130 this.doAction('submit', options);
26135 * Shortcut to do a load action.
26136 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26137 * @return {BasicForm} this
26139 load : function(options){
26140 this.doAction('load', options);
26145 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26146 * @param {Record} record The record to edit
26147 * @return {BasicForm} this
26149 updateRecord : function(record){
26150 record.beginEdit();
26151 var fs = record.fields;
26152 fs.each(function(f){
26153 var field = this.findField(f.name);
26155 record.set(f.name, field.getValue());
26163 * Loads an Roo.data.Record into this form.
26164 * @param {Record} record The record to load
26165 * @return {BasicForm} this
26167 loadRecord : function(record){
26168 this.setValues(record.data);
26173 beforeAction : function(action){
26174 var o = action.options;
26177 if(this.waitMsgTarget === true){
26178 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
26179 }else if(this.waitMsgTarget){
26180 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26181 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
26183 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
26189 afterAction : function(action, success){
26190 this.activeAction = null;
26191 var o = action.options;
26193 if(this.waitMsgTarget === true){
26195 }else if(this.waitMsgTarget){
26196 this.waitMsgTarget.unmask();
26198 Roo.MessageBox.updateProgress(1);
26199 Roo.MessageBox.hide();
26206 Roo.callback(o.success, o.scope, [this, action]);
26207 this.fireEvent('actioncomplete', this, action);
26210 Roo.callback(o.failure, o.scope, [this, action]);
26211 // show an error message if no failed handler is set..
26212 if (!this.hasListener('actionfailed')) {
26213 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
26216 this.fireEvent('actionfailed', this, action);
26222 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26223 * @param {String} id The value to search for
26226 findField : function(id){
26227 var field = this.items.get(id);
26229 this.items.each(function(f){
26230 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26236 return field || null;
26240 * Add a secondary form to this one,
26241 * Used to provide tabbed forms. One form is primary, with hidden values
26242 * which mirror the elements from the other forms.
26244 * @param {Roo.form.Form} form to add.
26247 addForm : function(form)
26250 if (this.childForms.indexOf(form) > -1) {
26254 this.childForms.push(form);
26256 Roo.each(form.allItems, function (fe) {
26258 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26259 if (this.findField(n)) { // already added..
26262 var add = new Roo.form.Hidden({
26265 add.render(this.el);
26272 * Mark fields in this form invalid in bulk.
26273 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26274 * @return {BasicForm} this
26276 markInvalid : function(errors){
26277 if(errors instanceof Array){
26278 for(var i = 0, len = errors.length; i < len; i++){
26279 var fieldError = errors[i];
26280 var f = this.findField(fieldError.id);
26282 f.markInvalid(fieldError.msg);
26288 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26289 field.markInvalid(errors[id]);
26293 Roo.each(this.childForms || [], function (f) {
26294 f.markInvalid(errors);
26301 * Set values for fields in this form in bulk.
26302 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26303 * @return {BasicForm} this
26305 setValues : function(values){
26306 if(values instanceof Array){ // array of objects
26307 for(var i = 0, len = values.length; i < len; i++){
26309 var f = this.findField(v.id);
26311 f.setValue(v.value);
26312 if(this.trackResetOnLoad){
26313 f.originalValue = f.getValue();
26317 }else{ // object hash
26320 if(typeof values[id] != 'function' && (field = this.findField(id))){
26322 if (field.setFromData &&
26323 field.valueField &&
26324 field.displayField &&
26325 // combos' with local stores can
26326 // be queried via setValue()
26327 // to set their value..
26328 (field.store && !field.store.isLocal)
26332 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26333 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26334 field.setFromData(sd);
26337 field.setValue(values[id]);
26341 if(this.trackResetOnLoad){
26342 field.originalValue = field.getValue();
26348 Roo.each(this.childForms || [], function (f) {
26349 f.setValues(values);
26356 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26357 * they are returned as an array.
26358 * @param {Boolean} asString
26361 getValues : function(asString){
26362 if (this.childForms) {
26363 // copy values from the child forms
26364 Roo.each(this.childForms, function (f) {
26365 this.setValues(f.getValues());
26371 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26372 if(asString === true){
26375 return Roo.urlDecode(fs);
26379 * Returns the fields in this form as an object with key/value pairs.
26380 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26383 getFieldValues : function()
26385 if (this.childForms) {
26386 // copy values from the child forms
26387 Roo.each(this.childForms, function (f) {
26388 this.setValues(f.getValues());
26393 this.items.each(function(f){
26394 if (!f.getName()) {
26397 var v = f.getValue();
26398 if ((typeof(v) == 'object') && f.getRawValue) {
26399 v = f.getRawValue() ; // dates..
26401 ret[f.getName()] = v;
26408 * Clears all invalid messages in this form.
26409 * @return {BasicForm} this
26411 clearInvalid : function(){
26412 this.items.each(function(f){
26416 Roo.each(this.childForms || [], function (f) {
26425 * Resets this form.
26426 * @return {BasicForm} this
26428 reset : function(){
26429 this.items.each(function(f){
26433 Roo.each(this.childForms || [], function (f) {
26442 * Add Roo.form components to this form.
26443 * @param {Field} field1
26444 * @param {Field} field2 (optional)
26445 * @param {Field} etc (optional)
26446 * @return {BasicForm} this
26449 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26455 * Removes a field from the items collection (does NOT remove its markup).
26456 * @param {Field} field
26457 * @return {BasicForm} this
26459 remove : function(field){
26460 this.items.remove(field);
26465 * Looks at the fields in this form, checks them for an id attribute,
26466 * and calls applyTo on the existing dom element with that id.
26467 * @return {BasicForm} this
26469 render : function(){
26470 this.items.each(function(f){
26471 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26479 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26480 * @param {Object} values
26481 * @return {BasicForm} this
26483 applyToFields : function(o){
26484 this.items.each(function(f){
26491 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26492 * @param {Object} values
26493 * @return {BasicForm} this
26495 applyIfToFields : function(o){
26496 this.items.each(function(f){
26504 Roo.BasicForm = Roo.form.BasicForm;/*
26506 * Ext JS Library 1.1.1
26507 * Copyright(c) 2006-2007, Ext JS, LLC.
26509 * Originally Released Under LGPL - original licence link has changed is not relivant.
26512 * <script type="text/javascript">
26516 * @class Roo.form.Form
26517 * @extends Roo.form.BasicForm
26518 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26520 * @param {Object} config Configuration options
26522 Roo.form.Form = function(config){
26524 if (config.items) {
26525 xitems = config.items;
26526 delete config.items;
26530 Roo.form.Form.superclass.constructor.call(this, null, config);
26531 this.url = this.url || this.action;
26533 this.root = new Roo.form.Layout(Roo.applyIf({
26537 this.active = this.root;
26539 * Array of all the buttons that have been added to this form via {@link addButton}
26543 this.allItems = [];
26546 * @event clientvalidation
26547 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26548 * @param {Form} this
26549 * @param {Boolean} valid true if the form has passed client-side validation
26551 clientvalidation: true,
26554 * Fires when the form is rendered
26555 * @param {Roo.form.Form} form
26560 if (this.progressUrl) {
26561 // push a hidden field onto the list of fields..
26565 name : 'UPLOAD_IDENTIFIER'
26570 Roo.each(xitems, this.addxtype, this);
26576 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26578 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26581 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26584 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26586 buttonAlign:'center',
26589 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26594 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26595 * This property cascades to child containers if not set.
26600 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26601 * fires a looping event with that state. This is required to bind buttons to the valid
26602 * state using the config value formBind:true on the button.
26604 monitorValid : false,
26607 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26612 * @cfg {String} progressUrl - Url to return progress data
26615 progressUrl : false,
26618 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26619 * fields are added and the column is closed. If no fields are passed the column remains open
26620 * until end() is called.
26621 * @param {Object} config The config to pass to the column
26622 * @param {Field} field1 (optional)
26623 * @param {Field} field2 (optional)
26624 * @param {Field} etc (optional)
26625 * @return Column The column container object
26627 column : function(c){
26628 var col = new Roo.form.Column(c);
26630 if(arguments.length > 1){ // duplicate code required because of Opera
26631 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26638 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26639 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26640 * until end() is called.
26641 * @param {Object} config The config to pass to the fieldset
26642 * @param {Field} field1 (optional)
26643 * @param {Field} field2 (optional)
26644 * @param {Field} etc (optional)
26645 * @return FieldSet The fieldset container object
26647 fieldset : function(c){
26648 var fs = new Roo.form.FieldSet(c);
26650 if(arguments.length > 1){ // duplicate code required because of Opera
26651 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26658 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26659 * fields are added and the container is closed. If no fields are passed the container remains open
26660 * until end() is called.
26661 * @param {Object} config The config to pass to the Layout
26662 * @param {Field} field1 (optional)
26663 * @param {Field} field2 (optional)
26664 * @param {Field} etc (optional)
26665 * @return Layout The container object
26667 container : function(c){
26668 var l = new Roo.form.Layout(c);
26670 if(arguments.length > 1){ // duplicate code required because of Opera
26671 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26678 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26679 * @param {Object} container A Roo.form.Layout or subclass of Layout
26680 * @return {Form} this
26682 start : function(c){
26683 // cascade label info
26684 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26685 this.active.stack.push(c);
26686 c.ownerCt = this.active;
26692 * Closes the current open container
26693 * @return {Form} this
26696 if(this.active == this.root){
26699 this.active = this.active.ownerCt;
26704 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26705 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26706 * as the label of the field.
26707 * @param {Field} field1
26708 * @param {Field} field2 (optional)
26709 * @param {Field} etc. (optional)
26710 * @return {Form} this
26713 this.active.stack.push.apply(this.active.stack, arguments);
26714 this.allItems.push.apply(this.allItems,arguments);
26716 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26717 if(a[i].isFormField){
26722 Roo.form.Form.superclass.add.apply(this, r);
26732 * Find any element that has been added to a form, using it's ID or name
26733 * This can include framesets, columns etc. along with regular fields..
26734 * @param {String} id - id or name to find.
26736 * @return {Element} e - or false if nothing found.
26738 findbyId : function(id)
26744 Roo.each(this.allItems, function(f){
26745 if (f.id == id || f.name == id ){
26756 * Render this form into the passed container. This should only be called once!
26757 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26758 * @return {Form} this
26760 render : function(ct)
26766 var o = this.autoCreate || {
26768 method : this.method || 'POST',
26769 id : this.id || Roo.id()
26771 this.initEl(ct.createChild(o));
26773 this.root.render(this.el);
26777 this.items.each(function(f){
26778 f.render('x-form-el-'+f.id);
26781 if(this.buttons.length > 0){
26782 // tables are required to maintain order and for correct IE layout
26783 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26784 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26785 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26787 var tr = tb.getElementsByTagName('tr')[0];
26788 for(var i = 0, len = this.buttons.length; i < len; i++) {
26789 var b = this.buttons[i];
26790 var td = document.createElement('td');
26791 td.className = 'x-form-btn-td';
26792 b.render(tr.appendChild(td));
26795 if(this.monitorValid){ // initialize after render
26796 this.startMonitoring();
26798 this.fireEvent('rendered', this);
26803 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26804 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26805 * object or a valid Roo.DomHelper element config
26806 * @param {Function} handler The function called when the button is clicked
26807 * @param {Object} scope (optional) The scope of the handler function
26808 * @return {Roo.Button}
26810 addButton : function(config, handler, scope){
26814 minWidth: this.minButtonWidth,
26817 if(typeof config == "string"){
26820 Roo.apply(bc, config);
26822 var btn = new Roo.Button(null, bc);
26823 this.buttons.push(btn);
26828 * Adds a series of form elements (using the xtype property as the factory method.
26829 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26830 * @param {Object} config
26833 addxtype : function()
26835 var ar = Array.prototype.slice.call(arguments, 0);
26837 for(var i = 0; i < ar.length; i++) {
26839 continue; // skip -- if this happends something invalid got sent, we
26840 // should ignore it, as basically that interface element will not show up
26841 // and that should be pretty obvious!!
26844 if (Roo.form[ar[i].xtype]) {
26846 var fe = Roo.factory(ar[i], Roo.form);
26852 fe.store.form = this;
26857 this.allItems.push(fe);
26858 if (fe.items && fe.addxtype) {
26859 fe.addxtype.apply(fe, fe.items);
26869 // console.log('adding ' + ar[i].xtype);
26871 if (ar[i].xtype == 'Button') {
26872 //console.log('adding button');
26873 //console.log(ar[i]);
26874 this.addButton(ar[i]);
26875 this.allItems.push(fe);
26879 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26880 alert('end is not supported on xtype any more, use items');
26882 // //console.log('adding end');
26890 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26891 * option "monitorValid"
26893 startMonitoring : function(){
26896 Roo.TaskMgr.start({
26897 run : this.bindHandler,
26898 interval : this.monitorPoll || 200,
26905 * Stops monitoring of the valid state of this form
26907 stopMonitoring : function(){
26908 this.bound = false;
26912 bindHandler : function(){
26914 return false; // stops binding
26917 this.items.each(function(f){
26918 if(!f.isValid(true)){
26923 for(var i = 0, len = this.buttons.length; i < len; i++){
26924 var btn = this.buttons[i];
26925 if(btn.formBind === true && btn.disabled === valid){
26926 btn.setDisabled(!valid);
26929 this.fireEvent('clientvalidation', this, valid);
26943 Roo.Form = Roo.form.Form;
26946 * Ext JS Library 1.1.1
26947 * Copyright(c) 2006-2007, Ext JS, LLC.
26949 * Originally Released Under LGPL - original licence link has changed is not relivant.
26952 * <script type="text/javascript">
26956 * @class Roo.form.Action
26957 * Internal Class used to handle form actions
26959 * @param {Roo.form.BasicForm} el The form element or its id
26960 * @param {Object} config Configuration options
26964 // define the action interface
26965 Roo.form.Action = function(form, options){
26967 this.options = options || {};
26970 * Client Validation Failed
26973 Roo.form.Action.CLIENT_INVALID = 'client';
26975 * Server Validation Failed
26978 Roo.form.Action.SERVER_INVALID = 'server';
26980 * Connect to Server Failed
26983 Roo.form.Action.CONNECT_FAILURE = 'connect';
26985 * Reading Data from Server Failed
26988 Roo.form.Action.LOAD_FAILURE = 'load';
26990 Roo.form.Action.prototype = {
26992 failureType : undefined,
26993 response : undefined,
26994 result : undefined,
26996 // interface method
26997 run : function(options){
27001 // interface method
27002 success : function(response){
27006 // interface method
27007 handleResponse : function(response){
27011 // default connection failure
27012 failure : function(response){
27014 this.response = response;
27015 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27016 this.form.afterAction(this, false);
27019 processResponse : function(response){
27020 this.response = response;
27021 if(!response.responseText){
27024 this.result = this.handleResponse(response);
27025 return this.result;
27028 // utility functions used internally
27029 getUrl : function(appendParams){
27030 var url = this.options.url || this.form.url || this.form.el.dom.action;
27032 var p = this.getParams();
27034 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
27040 getMethod : function(){
27041 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
27044 getParams : function(){
27045 var bp = this.form.baseParams;
27046 var p = this.options.params;
27048 if(typeof p == "object"){
27049 p = Roo.urlEncode(Roo.applyIf(p, bp));
27050 }else if(typeof p == 'string' && bp){
27051 p += '&' + Roo.urlEncode(bp);
27054 p = Roo.urlEncode(bp);
27059 createCallback : function(){
27061 success: this.success,
27062 failure: this.failure,
27064 timeout: (this.form.timeout*1000),
27065 upload: this.form.fileUpload ? this.success : undefined
27070 Roo.form.Action.Submit = function(form, options){
27071 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27074 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27077 haveProgress : false,
27078 uploadComplete : false,
27080 // uploadProgress indicator.
27081 uploadProgress : function()
27083 if (!this.form.progressUrl) {
27087 if (!this.haveProgress) {
27088 Roo.MessageBox.progress("Uploading", "Uploading");
27090 if (this.uploadComplete) {
27091 Roo.MessageBox.hide();
27095 this.haveProgress = true;
27097 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27099 var c = new Roo.data.Connection();
27101 url : this.form.progressUrl,
27106 success : function(req){
27107 //console.log(data);
27111 rdata = Roo.decode(req.responseText)
27113 Roo.log("Invalid data from server..");
27117 if (!rdata || !rdata.success) {
27121 var data = rdata.data;
27123 if (this.uploadComplete) {
27124 Roo.MessageBox.hide();
27129 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27130 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27133 this.uploadProgress.defer(2000,this);
27136 failure: function(data) {
27137 Roo.log('progress url failed ');
27148 // run get Values on the form, so it syncs any secondary forms.
27149 this.form.getValues();
27151 var o = this.options;
27152 var method = this.getMethod();
27153 var isPost = method == 'POST';
27154 if(o.clientValidation === false || this.form.isValid()){
27156 if (this.form.progressUrl) {
27157 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27158 (new Date() * 1) + '' + Math.random());
27163 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27164 form:this.form.el.dom,
27165 url:this.getUrl(!isPost),
27167 params:isPost ? this.getParams() : null,
27168 isUpload: this.form.fileUpload
27171 this.uploadProgress();
27173 }else if (o.clientValidation !== false){ // client validation failed
27174 this.failureType = Roo.form.Action.CLIENT_INVALID;
27175 this.form.afterAction(this, false);
27179 success : function(response)
27181 this.uploadComplete= true;
27182 if (this.haveProgress) {
27183 Roo.MessageBox.hide();
27187 var result = this.processResponse(response);
27188 if(result === true || result.success){
27189 this.form.afterAction(this, true);
27193 this.form.markInvalid(result.errors);
27194 this.failureType = Roo.form.Action.SERVER_INVALID;
27196 this.form.afterAction(this, false);
27198 failure : function(response)
27200 this.uploadComplete= true;
27201 if (this.haveProgress) {
27202 Roo.MessageBox.hide();
27206 this.response = response;
27207 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27208 this.form.afterAction(this, false);
27211 handleResponse : function(response){
27212 if(this.form.errorReader){
27213 var rs = this.form.errorReader.read(response);
27216 for(var i = 0, len = rs.records.length; i < len; i++) {
27217 var r = rs.records[i];
27218 errors[i] = r.data;
27221 if(errors.length < 1){
27225 success : rs.success,
27231 ret = Roo.decode(response.responseText);
27235 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27245 Roo.form.Action.Load = function(form, options){
27246 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27247 this.reader = this.form.reader;
27250 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27255 Roo.Ajax.request(Roo.apply(
27256 this.createCallback(), {
27257 method:this.getMethod(),
27258 url:this.getUrl(false),
27259 params:this.getParams()
27263 success : function(response){
27265 var result = this.processResponse(response);
27266 if(result === true || !result.success || !result.data){
27267 this.failureType = Roo.form.Action.LOAD_FAILURE;
27268 this.form.afterAction(this, false);
27271 this.form.clearInvalid();
27272 this.form.setValues(result.data);
27273 this.form.afterAction(this, true);
27276 handleResponse : function(response){
27277 if(this.form.reader){
27278 var rs = this.form.reader.read(response);
27279 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27281 success : rs.success,
27285 return Roo.decode(response.responseText);
27289 Roo.form.Action.ACTION_TYPES = {
27290 'load' : Roo.form.Action.Load,
27291 'submit' : Roo.form.Action.Submit
27294 * Ext JS Library 1.1.1
27295 * Copyright(c) 2006-2007, Ext JS, LLC.
27297 * Originally Released Under LGPL - original licence link has changed is not relivant.
27300 * <script type="text/javascript">
27304 * @class Roo.form.Layout
27305 * @extends Roo.Component
27306 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27308 * @param {Object} config Configuration options
27310 Roo.form.Layout = function(config){
27312 if (config.items) {
27313 xitems = config.items;
27314 delete config.items;
27316 Roo.form.Layout.superclass.constructor.call(this, config);
27318 Roo.each(xitems, this.addxtype, this);
27322 Roo.extend(Roo.form.Layout, Roo.Component, {
27324 * @cfg {String/Object} autoCreate
27325 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27328 * @cfg {String/Object/Function} style
27329 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27330 * a function which returns such a specification.
27333 * @cfg {String} labelAlign
27334 * Valid values are "left," "top" and "right" (defaults to "left")
27337 * @cfg {Number} labelWidth
27338 * Fixed width in pixels of all field labels (defaults to undefined)
27341 * @cfg {Boolean} clear
27342 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27346 * @cfg {String} labelSeparator
27347 * The separator to use after field labels (defaults to ':')
27349 labelSeparator : ':',
27351 * @cfg {Boolean} hideLabels
27352 * True to suppress the display of field labels in this layout (defaults to false)
27354 hideLabels : false,
27357 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27362 onRender : function(ct, position){
27363 if(this.el){ // from markup
27364 this.el = Roo.get(this.el);
27365 }else { // generate
27366 var cfg = this.getAutoCreate();
27367 this.el = ct.createChild(cfg, position);
27370 this.el.applyStyles(this.style);
27372 if(this.labelAlign){
27373 this.el.addClass('x-form-label-'+this.labelAlign);
27375 if(this.hideLabels){
27376 this.labelStyle = "display:none";
27377 this.elementStyle = "padding-left:0;";
27379 if(typeof this.labelWidth == 'number'){
27380 this.labelStyle = "width:"+this.labelWidth+"px;";
27381 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27383 if(this.labelAlign == 'top'){
27384 this.labelStyle = "width:auto;";
27385 this.elementStyle = "padding-left:0;";
27388 var stack = this.stack;
27389 var slen = stack.length;
27391 if(!this.fieldTpl){
27392 var t = new Roo.Template(
27393 '<div class="x-form-item {5}">',
27394 '<label for="{0}" style="{2}">{1}{4}</label>',
27395 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27397 '</div><div class="x-form-clear-left"></div>'
27399 t.disableFormats = true;
27401 Roo.form.Layout.prototype.fieldTpl = t;
27403 for(var i = 0; i < slen; i++) {
27404 if(stack[i].isFormField){
27405 this.renderField(stack[i]);
27407 this.renderComponent(stack[i]);
27412 this.el.createChild({cls:'x-form-clear'});
27417 renderField : function(f){
27418 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27421 f.labelStyle||this.labelStyle||'', //2
27422 this.elementStyle||'', //3
27423 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27424 f.itemCls||this.itemCls||'' //5
27425 ], true).getPrevSibling());
27429 renderComponent : function(c){
27430 c.render(c.isLayout ? this.el : this.el.createChild());
27433 * Adds a object form elements (using the xtype property as the factory method.)
27434 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27435 * @param {Object} config
27437 addxtype : function(o)
27439 // create the lement.
27440 o.form = this.form;
27441 var fe = Roo.factory(o, Roo.form);
27442 this.form.allItems.push(fe);
27443 this.stack.push(fe);
27445 if (fe.isFormField) {
27446 this.form.items.add(fe);
27454 * @class Roo.form.Column
27455 * @extends Roo.form.Layout
27456 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27458 * @param {Object} config Configuration options
27460 Roo.form.Column = function(config){
27461 Roo.form.Column.superclass.constructor.call(this, config);
27464 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27466 * @cfg {Number/String} width
27467 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27470 * @cfg {String/Object} autoCreate
27471 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27475 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27478 onRender : function(ct, position){
27479 Roo.form.Column.superclass.onRender.call(this, ct, position);
27481 this.el.setWidth(this.width);
27488 * @class Roo.form.Row
27489 * @extends Roo.form.Layout
27490 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27492 * @param {Object} config Configuration options
27496 Roo.form.Row = function(config){
27497 Roo.form.Row.superclass.constructor.call(this, config);
27500 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27502 * @cfg {Number/String} width
27503 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27506 * @cfg {Number/String} height
27507 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27509 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27513 onRender : function(ct, position){
27514 //console.log('row render');
27516 var t = new Roo.Template(
27517 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27518 '<label for="{0}" style="{2}">{1}{4}</label>',
27519 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27523 t.disableFormats = true;
27525 Roo.form.Layout.prototype.rowTpl = t;
27527 this.fieldTpl = this.rowTpl;
27529 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27530 var labelWidth = 100;
27532 if ((this.labelAlign != 'top')) {
27533 if (typeof this.labelWidth == 'number') {
27534 labelWidth = this.labelWidth
27536 this.padWidth = 20 + labelWidth;
27540 Roo.form.Column.superclass.onRender.call(this, ct, position);
27542 this.el.setWidth(this.width);
27545 this.el.setHeight(this.height);
27550 renderField : function(f){
27551 f.fieldEl = this.fieldTpl.append(this.el, [
27552 f.id, f.fieldLabel,
27553 f.labelStyle||this.labelStyle||'',
27554 this.elementStyle||'',
27555 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27556 f.itemCls||this.itemCls||'',
27557 f.width ? f.width + this.padWidth : 160 + this.padWidth
27564 * @class Roo.form.FieldSet
27565 * @extends Roo.form.Layout
27566 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27568 * @param {Object} config Configuration options
27570 Roo.form.FieldSet = function(config){
27571 Roo.form.FieldSet.superclass.constructor.call(this, config);
27574 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27576 * @cfg {String} legend
27577 * The text to display as the legend for the FieldSet (defaults to '')
27580 * @cfg {String/Object} autoCreate
27581 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27585 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27588 onRender : function(ct, position){
27589 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27591 this.setLegend(this.legend);
27596 setLegend : function(text){
27598 this.el.child('legend').update(text);
27603 * Ext JS Library 1.1.1
27604 * Copyright(c) 2006-2007, Ext JS, LLC.
27606 * Originally Released Under LGPL - original licence link has changed is not relivant.
27609 * <script type="text/javascript">
27612 * @class Roo.form.VTypes
27613 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27616 Roo.form.VTypes = function(){
27617 // closure these in so they are only created once.
27618 var alpha = /^[a-zA-Z_]+$/;
27619 var alphanum = /^[a-zA-Z0-9_]+$/;
27620 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27621 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27623 // All these messages and functions are configurable
27626 * The function used to validate email addresses
27627 * @param {String} value The email address
27629 'email' : function(v){
27630 return email.test(v);
27633 * The error text to display when the email validation function returns false
27636 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27638 * The keystroke filter mask to be applied on email input
27641 'emailMask' : /[a-z0-9_\.\-@]/i,
27644 * The function used to validate URLs
27645 * @param {String} value The URL
27647 'url' : function(v){
27648 return url.test(v);
27651 * The error text to display when the url validation function returns false
27654 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27657 * The function used to validate alpha values
27658 * @param {String} value The value
27660 'alpha' : function(v){
27661 return alpha.test(v);
27664 * The error text to display when the alpha validation function returns false
27667 'alphaText' : 'This field should only contain letters and _',
27669 * The keystroke filter mask to be applied on alpha input
27672 'alphaMask' : /[a-z_]/i,
27675 * The function used to validate alphanumeric values
27676 * @param {String} value The value
27678 'alphanum' : function(v){
27679 return alphanum.test(v);
27682 * The error text to display when the alphanumeric validation function returns false
27685 'alphanumText' : 'This field should only contain letters, numbers and _',
27687 * The keystroke filter mask to be applied on alphanumeric input
27690 'alphanumMask' : /[a-z0-9_]/i
27692 }();//<script type="text/javascript">
27695 * @class Roo.form.FCKeditor
27696 * @extends Roo.form.TextArea
27697 * Wrapper around the FCKEditor http://www.fckeditor.net
27699 * Creates a new FCKeditor
27700 * @param {Object} config Configuration options
27702 Roo.form.FCKeditor = function(config){
27703 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27706 * @event editorinit
27707 * Fired when the editor is initialized - you can add extra handlers here..
27708 * @param {FCKeditor} this
27709 * @param {Object} the FCK object.
27716 Roo.form.FCKeditor.editors = { };
27717 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27719 //defaultAutoCreate : {
27720 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27724 * @cfg {Object} fck options - see fck manual for details.
27729 * @cfg {Object} fck toolbar set (Basic or Default)
27731 toolbarSet : 'Basic',
27733 * @cfg {Object} fck BasePath
27735 basePath : '/fckeditor/',
27743 onRender : function(ct, position)
27746 this.defaultAutoCreate = {
27748 style:"width:300px;height:60px;",
27749 autocomplete: "off"
27752 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27755 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27756 if(this.preventScrollbars){
27757 this.el.setStyle("overflow", "hidden");
27759 this.el.setHeight(this.growMin);
27762 //console.log('onrender' + this.getId() );
27763 Roo.form.FCKeditor.editors[this.getId()] = this;
27766 this.replaceTextarea() ;
27770 getEditor : function() {
27771 return this.fckEditor;
27774 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27775 * @param {Mixed} value The value to set
27779 setValue : function(value)
27781 //console.log('setValue: ' + value);
27783 if(typeof(value) == 'undefined') { // not sure why this is happending...
27786 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27788 //if(!this.el || !this.getEditor()) {
27789 // this.value = value;
27790 //this.setValue.defer(100,this,[value]);
27794 if(!this.getEditor()) {
27798 this.getEditor().SetData(value);
27805 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27806 * @return {Mixed} value The field value
27808 getValue : function()
27811 if (this.frame && this.frame.dom.style.display == 'none') {
27812 return Roo.form.FCKeditor.superclass.getValue.call(this);
27815 if(!this.el || !this.getEditor()) {
27817 // this.getValue.defer(100,this);
27822 var value=this.getEditor().GetData();
27823 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27824 return Roo.form.FCKeditor.superclass.getValue.call(this);
27830 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27831 * @return {Mixed} value The field value
27833 getRawValue : function()
27835 if (this.frame && this.frame.dom.style.display == 'none') {
27836 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27839 if(!this.el || !this.getEditor()) {
27840 //this.getRawValue.defer(100,this);
27847 var value=this.getEditor().GetData();
27848 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27849 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27853 setSize : function(w,h) {
27857 //if (this.frame && this.frame.dom.style.display == 'none') {
27858 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27861 //if(!this.el || !this.getEditor()) {
27862 // this.setSize.defer(100,this, [w,h]);
27868 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27870 this.frame.dom.setAttribute('width', w);
27871 this.frame.dom.setAttribute('height', h);
27872 this.frame.setSize(w,h);
27876 toggleSourceEdit : function(value) {
27880 this.el.dom.style.display = value ? '' : 'none';
27881 this.frame.dom.style.display = value ? 'none' : '';
27886 focus: function(tag)
27888 if (this.frame.dom.style.display == 'none') {
27889 return Roo.form.FCKeditor.superclass.focus.call(this);
27891 if(!this.el || !this.getEditor()) {
27892 this.focus.defer(100,this, [tag]);
27899 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27900 this.getEditor().Focus();
27902 if (!this.getEditor().Selection.GetSelection()) {
27903 this.focus.defer(100,this, [tag]);
27908 var r = this.getEditor().EditorDocument.createRange();
27909 r.setStart(tgs[0],0);
27910 r.setEnd(tgs[0],0);
27911 this.getEditor().Selection.GetSelection().removeAllRanges();
27912 this.getEditor().Selection.GetSelection().addRange(r);
27913 this.getEditor().Focus();
27920 replaceTextarea : function()
27922 if ( document.getElementById( this.getId() + '___Frame' ) )
27924 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27926 // We must check the elements firstly using the Id and then the name.
27927 var oTextarea = document.getElementById( this.getId() );
27929 var colElementsByName = document.getElementsByName( this.getId() ) ;
27931 oTextarea.style.display = 'none' ;
27933 if ( oTextarea.tabIndex ) {
27934 this.TabIndex = oTextarea.tabIndex ;
27937 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27938 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27939 this.frame = Roo.get(this.getId() + '___Frame')
27942 _getConfigHtml : function()
27946 for ( var o in this.fckconfig ) {
27947 sConfig += sConfig.length > 0 ? '&' : '';
27948 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27951 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27955 _getIFrameHtml : function()
27957 var sFile = 'fckeditor.html' ;
27958 /* no idea what this is about..
27961 if ( (/fcksource=true/i).test( window.top.location.search ) )
27962 sFile = 'fckeditor.original.html' ;
27967 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27968 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27971 var html = '<iframe id="' + this.getId() +
27972 '___Frame" src="' + sLink +
27973 '" width="' + this.width +
27974 '" height="' + this.height + '"' +
27975 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27976 ' frameborder="0" scrolling="no"></iframe>' ;
27981 _insertHtmlBefore : function( html, element )
27983 if ( element.insertAdjacentHTML ) {
27985 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27987 var oRange = document.createRange() ;
27988 oRange.setStartBefore( element ) ;
27989 var oFragment = oRange.createContextualFragment( html );
27990 element.parentNode.insertBefore( oFragment, element ) ;
28003 //Roo.reg('fckeditor', Roo.form.FCKeditor);
28005 function FCKeditor_OnComplete(editorInstance){
28006 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
28007 f.fckEditor = editorInstance;
28008 //console.log("loaded");
28009 f.fireEvent('editorinit', f, editorInstance);
28029 //<script type="text/javascript">
28031 * @class Roo.form.GridField
28032 * @extends Roo.form.Field
28033 * Embed a grid (or editable grid into a form)
28036 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
28038 * xgrid.store = Roo.data.Store
28039 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
28040 * xgrid.store.reader = Roo.data.JsonReader
28044 * Creates a new GridField
28045 * @param {Object} config Configuration options
28047 Roo.form.GridField = function(config){
28048 Roo.form.GridField.superclass.constructor.call(this, config);
28052 Roo.extend(Roo.form.GridField, Roo.form.Field, {
28054 * @cfg {Number} width - used to restrict width of grid..
28058 * @cfg {Number} height - used to restrict height of grid..
28062 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28068 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28069 * {tag: "input", type: "checkbox", autocomplete: "off"})
28071 // defaultAutoCreate : { tag: 'div' },
28072 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28074 * @cfg {String} addTitle Text to include for adding a title.
28078 onResize : function(){
28079 Roo.form.Field.superclass.onResize.apply(this, arguments);
28082 initEvents : function(){
28083 // Roo.form.Checkbox.superclass.initEvents.call(this);
28084 // has no events...
28089 getResizeEl : function(){
28093 getPositionEl : function(){
28098 onRender : function(ct, position){
28100 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28101 var style = this.style;
28104 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28105 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28106 this.viewEl = this.wrap.createChild({ tag: 'div' });
28108 this.viewEl.applyStyles(style);
28111 this.viewEl.setWidth(this.width);
28114 this.viewEl.setHeight(this.height);
28116 //if(this.inputValue !== undefined){
28117 //this.setValue(this.value);
28120 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28123 this.grid.render();
28124 this.grid.getDataSource().on('remove', this.refreshValue, this);
28125 this.grid.getDataSource().on('update', this.refreshValue, this);
28126 this.grid.on('afteredit', this.refreshValue, this);
28132 * Sets the value of the item.
28133 * @param {String} either an object or a string..
28135 setValue : function(v){
28137 v = v || []; // empty set..
28138 // this does not seem smart - it really only affects memoryproxy grids..
28139 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28140 var ds = this.grid.getDataSource();
28141 // assumes a json reader..
28143 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28144 ds.loadData( data);
28146 Roo.form.GridField.superclass.setValue.call(this, v);
28147 this.refreshValue();
28148 // should load data in the grid really....
28152 refreshValue: function() {
28154 this.grid.getDataSource().each(function(r) {
28157 this.el.dom.value = Roo.encode(val);
28165 * Ext JS Library 1.1.1
28166 * Copyright(c) 2006-2007, Ext JS, LLC.
28168 * Originally Released Under LGPL - original licence link has changed is not relivant.
28171 * <script type="text/javascript">
28174 * @class Roo.form.DisplayField
28175 * @extends Roo.form.Field
28176 * A generic Field to display non-editable data.
28178 * Creates a new Display Field item.
28179 * @param {Object} config Configuration options
28181 Roo.form.DisplayField = function(config){
28182 Roo.form.DisplayField.superclass.constructor.call(this, config);
28186 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28187 inputType: 'hidden',
28193 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28195 focusClass : undefined,
28197 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28199 fieldClass: 'x-form-field',
28202 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28204 valueRenderer: undefined,
28208 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28209 * {tag: "input", type: "checkbox", autocomplete: "off"})
28212 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28214 onResize : function(){
28215 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28219 initEvents : function(){
28220 // Roo.form.Checkbox.superclass.initEvents.call(this);
28221 // has no events...
28226 getResizeEl : function(){
28230 getPositionEl : function(){
28235 onRender : function(ct, position){
28237 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28238 //if(this.inputValue !== undefined){
28239 this.wrap = this.el.wrap();
28241 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
28243 if (this.bodyStyle) {
28244 this.viewEl.applyStyles(this.bodyStyle);
28246 //this.viewEl.setStyle('padding', '2px');
28248 this.setValue(this.value);
28253 initValue : Roo.emptyFn,
28258 onClick : function(){
28263 * Sets the checked state of the checkbox.
28264 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28266 setValue : function(v){
28268 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28269 // this might be called before we have a dom element..
28270 if (!this.viewEl) {
28273 this.viewEl.dom.innerHTML = html;
28274 Roo.form.DisplayField.superclass.setValue.call(this, v);
28284 * @class Roo.form.DayPicker
28285 * @extends Roo.form.Field
28286 * A Day picker show [M] [T] [W] ....
28288 * Creates a new Day Picker
28289 * @param {Object} config Configuration options
28291 Roo.form.DayPicker= function(config){
28292 Roo.form.DayPicker.superclass.constructor.call(this, config);
28296 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
28298 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28300 focusClass : undefined,
28302 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28304 fieldClass: "x-form-field",
28307 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28308 * {tag: "input", type: "checkbox", autocomplete: "off"})
28310 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
28313 actionMode : 'viewEl',
28317 inputType : 'hidden',
28320 inputElement: false, // real input element?
28321 basedOn: false, // ????
28323 isFormField: true, // not sure where this is needed!!!!
28325 onResize : function(){
28326 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
28327 if(!this.boxLabel){
28328 this.el.alignTo(this.wrap, 'c-c');
28332 initEvents : function(){
28333 Roo.form.Checkbox.superclass.initEvents.call(this);
28334 this.el.on("click", this.onClick, this);
28335 this.el.on("change", this.onClick, this);
28339 getResizeEl : function(){
28343 getPositionEl : function(){
28349 onRender : function(ct, position){
28350 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
28352 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
28354 var r1 = '<table><tr>';
28355 var r2 = '<tr class="x-form-daypick-icons">';
28356 for (var i=0; i < 7; i++) {
28357 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
28358 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
28361 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
28362 viewEl.select('img').on('click', this.onClick, this);
28363 this.viewEl = viewEl;
28366 // this will not work on Chrome!!!
28367 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
28368 this.el.on('propertychange', this.setFromHidden, this); //ie
28376 initValue : Roo.emptyFn,
28379 * Returns the checked state of the checkbox.
28380 * @return {Boolean} True if checked, else false
28382 getValue : function(){
28383 return this.el.dom.value;
28388 onClick : function(e){
28389 //this.setChecked(!this.checked);
28390 Roo.get(e.target).toggleClass('x-menu-item-checked');
28391 this.refreshValue();
28392 //if(this.el.dom.checked != this.checked){
28393 // this.setValue(this.el.dom.checked);
28398 refreshValue : function()
28401 this.viewEl.select('img',true).each(function(e,i,n) {
28402 val += e.is(".x-menu-item-checked") ? String(n) : '';
28404 this.setValue(val, true);
28408 * Sets the checked state of the checkbox.
28409 * On is always based on a string comparison between inputValue and the param.
28410 * @param {Boolean/String} value - the value to set
28411 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
28413 setValue : function(v,suppressEvent){
28414 if (!this.el.dom) {
28417 var old = this.el.dom.value ;
28418 this.el.dom.value = v;
28419 if (suppressEvent) {
28423 // update display..
28424 this.viewEl.select('img',true).each(function(e,i,n) {
28426 var on = e.is(".x-menu-item-checked");
28427 var newv = v.indexOf(String(n)) > -1;
28429 e.toggleClass('x-menu-item-checked');
28435 this.fireEvent('change', this, v, old);
28440 // handle setting of hidden value by some other method!!?!?
28441 setFromHidden: function()
28446 //console.log("SET FROM HIDDEN");
28447 //alert('setFrom hidden');
28448 this.setValue(this.el.dom.value);
28451 onDestroy : function()
28454 Roo.get(this.viewEl).remove();
28457 Roo.form.DayPicker.superclass.onDestroy.call(this);
28460 });//<script type="text/javasscript">
28464 * @class Roo.DDView
28465 * A DnD enabled version of Roo.View.
28466 * @param {Element/String} container The Element in which to create the View.
28467 * @param {String} tpl The template string used to create the markup for each element of the View
28468 * @param {Object} config The configuration properties. These include all the config options of
28469 * {@link Roo.View} plus some specific to this class.<br>
28471 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28472 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28474 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28475 .x-view-drag-insert-above {
28476 border-top:1px dotted #3366cc;
28478 .x-view-drag-insert-below {
28479 border-bottom:1px dotted #3366cc;
28485 Roo.DDView = function(container, tpl, config) {
28486 Roo.DDView.superclass.constructor.apply(this, arguments);
28487 this.getEl().setStyle("outline", "0px none");
28488 this.getEl().unselectable();
28489 if (this.dragGroup) {
28490 this.setDraggable(this.dragGroup.split(","));
28492 if (this.dropGroup) {
28493 this.setDroppable(this.dropGroup.split(","));
28495 if (this.deletable) {
28496 this.setDeletable();
28498 this.isDirtyFlag = false;
28504 Roo.extend(Roo.DDView, Roo.View, {
28505 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28506 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28507 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28508 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28512 reset: Roo.emptyFn,
28514 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28516 validate: function() {
28520 destroy: function() {
28521 this.purgeListeners();
28522 this.getEl.removeAllListeners();
28523 this.getEl().remove();
28524 if (this.dragZone) {
28525 if (this.dragZone.destroy) {
28526 this.dragZone.destroy();
28529 if (this.dropZone) {
28530 if (this.dropZone.destroy) {
28531 this.dropZone.destroy();
28536 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28537 getName: function() {
28541 /** Loads the View from a JSON string representing the Records to put into the Store. */
28542 setValue: function(v) {
28544 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28547 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28548 this.store.proxy = new Roo.data.MemoryProxy(data);
28552 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28553 getValue: function() {
28555 this.store.each(function(rec) {
28556 result += rec.id + ',';
28558 return result.substr(0, result.length - 1) + ')';
28561 getIds: function() {
28562 var i = 0, result = new Array(this.store.getCount());
28563 this.store.each(function(rec) {
28564 result[i++] = rec.id;
28569 isDirty: function() {
28570 return this.isDirtyFlag;
28574 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28575 * whole Element becomes the target, and this causes the drop gesture to append.
28577 getTargetFromEvent : function(e) {
28578 var target = e.getTarget();
28579 while ((target !== null) && (target.parentNode != this.el.dom)) {
28580 target = target.parentNode;
28583 target = this.el.dom.lastChild || this.el.dom;
28589 * Create the drag data which consists of an object which has the property "ddel" as
28590 * the drag proxy element.
28592 getDragData : function(e) {
28593 var target = this.findItemFromChild(e.getTarget());
28595 this.handleSelection(e);
28596 var selNodes = this.getSelectedNodes();
28599 copy: this.copy || (this.allowCopy && e.ctrlKey),
28603 var selectedIndices = this.getSelectedIndexes();
28604 for (var i = 0; i < selectedIndices.length; i++) {
28605 dragData.records.push(this.store.getAt(selectedIndices[i]));
28607 if (selNodes.length == 1) {
28608 dragData.ddel = target.cloneNode(true); // the div element
28610 var div = document.createElement('div'); // create the multi element drag "ghost"
28611 div.className = 'multi-proxy';
28612 for (var i = 0, len = selNodes.length; i < len; i++) {
28613 div.appendChild(selNodes[i].cloneNode(true));
28615 dragData.ddel = div;
28617 //console.log(dragData)
28618 //console.log(dragData.ddel.innerHTML)
28621 //console.log('nodragData')
28625 /** Specify to which ddGroup items in this DDView may be dragged. */
28626 setDraggable: function(ddGroup) {
28627 if (ddGroup instanceof Array) {
28628 Roo.each(ddGroup, this.setDraggable, this);
28631 if (this.dragZone) {
28632 this.dragZone.addToGroup(ddGroup);
28634 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28635 containerScroll: true,
28639 // Draggability implies selection. DragZone's mousedown selects the element.
28640 if (!this.multiSelect) { this.singleSelect = true; }
28642 // Wire the DragZone's handlers up to methods in *this*
28643 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28647 /** Specify from which ddGroup this DDView accepts drops. */
28648 setDroppable: function(ddGroup) {
28649 if (ddGroup instanceof Array) {
28650 Roo.each(ddGroup, this.setDroppable, this);
28653 if (this.dropZone) {
28654 this.dropZone.addToGroup(ddGroup);
28656 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28657 containerScroll: true,
28661 // Wire the DropZone's handlers up to methods in *this*
28662 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28663 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28664 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28665 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28666 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28670 /** Decide whether to drop above or below a View node. */
28671 getDropPoint : function(e, n, dd){
28672 if (n == this.el.dom) { return "above"; }
28673 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28674 var c = t + (b - t) / 2;
28675 var y = Roo.lib.Event.getPageY(e);
28683 onNodeEnter : function(n, dd, e, data){
28687 onNodeOver : function(n, dd, e, data){
28688 var pt = this.getDropPoint(e, n, dd);
28689 // set the insert point style on the target node
28690 var dragElClass = this.dropNotAllowed;
28693 if (pt == "above"){
28694 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28695 targetElClass = "x-view-drag-insert-above";
28697 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28698 targetElClass = "x-view-drag-insert-below";
28700 if (this.lastInsertClass != targetElClass){
28701 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28702 this.lastInsertClass = targetElClass;
28705 return dragElClass;
28708 onNodeOut : function(n, dd, e, data){
28709 this.removeDropIndicators(n);
28712 onNodeDrop : function(n, dd, e, data){
28713 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28716 var pt = this.getDropPoint(e, n, dd);
28717 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28718 if (pt == "below") { insertAt++; }
28719 for (var i = 0; i < data.records.length; i++) {
28720 var r = data.records[i];
28721 var dup = this.store.getById(r.id);
28722 if (dup && (dd != this.dragZone)) {
28723 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28726 this.store.insert(insertAt++, r.copy());
28728 data.source.isDirtyFlag = true;
28730 this.store.insert(insertAt++, r);
28732 this.isDirtyFlag = true;
28735 this.dragZone.cachedTarget = null;
28739 removeDropIndicators : function(n){
28741 Roo.fly(n).removeClass([
28742 "x-view-drag-insert-above",
28743 "x-view-drag-insert-below"]);
28744 this.lastInsertClass = "_noclass";
28749 * Utility method. Add a delete option to the DDView's context menu.
28750 * @param {String} imageUrl The URL of the "delete" icon image.
28752 setDeletable: function(imageUrl) {
28753 if (!this.singleSelect && !this.multiSelect) {
28754 this.singleSelect = true;
28756 var c = this.getContextMenu();
28757 this.contextMenu.on("itemclick", function(item) {
28760 this.remove(this.getSelectedIndexes());
28764 this.contextMenu.add({
28771 /** Return the context menu for this DDView. */
28772 getContextMenu: function() {
28773 if (!this.contextMenu) {
28774 // Create the View's context menu
28775 this.contextMenu = new Roo.menu.Menu({
28776 id: this.id + "-contextmenu"
28778 this.el.on("contextmenu", this.showContextMenu, this);
28780 return this.contextMenu;
28783 disableContextMenu: function() {
28784 if (this.contextMenu) {
28785 this.el.un("contextmenu", this.showContextMenu, this);
28789 showContextMenu: function(e, item) {
28790 item = this.findItemFromChild(e.getTarget());
28793 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28794 this.contextMenu.showAt(e.getXY());
28799 * Remove {@link Roo.data.Record}s at the specified indices.
28800 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28802 remove: function(selectedIndices) {
28803 selectedIndices = [].concat(selectedIndices);
28804 for (var i = 0; i < selectedIndices.length; i++) {
28805 var rec = this.store.getAt(selectedIndices[i]);
28806 this.store.remove(rec);
28811 * Double click fires the event, but also, if this is draggable, and there is only one other
28812 * related DropZone, it transfers the selected node.
28814 onDblClick : function(e){
28815 var item = this.findItemFromChild(e.getTarget());
28817 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28820 if (this.dragGroup) {
28821 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28822 while (targets.indexOf(this.dropZone) > -1) {
28823 targets.remove(this.dropZone);
28825 if (targets.length == 1) {
28826 this.dragZone.cachedTarget = null;
28827 var el = Roo.get(targets[0].getEl());
28828 var box = el.getBox(true);
28829 targets[0].onNodeDrop(el.dom, {
28831 xy: [box.x, box.y + box.height - 1]
28832 }, null, this.getDragData(e));
28838 handleSelection: function(e) {
28839 this.dragZone.cachedTarget = null;
28840 var item = this.findItemFromChild(e.getTarget());
28842 this.clearSelections(true);
28845 if (item && (this.multiSelect || this.singleSelect)){
28846 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28847 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28848 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28849 this.unselect(item);
28851 this.select(item, this.multiSelect && e.ctrlKey);
28852 this.lastSelection = item;
28857 onItemClick : function(item, index, e){
28858 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28864 unselect : function(nodeInfo, suppressEvent){
28865 var node = this.getNode(nodeInfo);
28866 if(node && this.isSelected(node)){
28867 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28868 Roo.fly(node).removeClass(this.selectedClass);
28869 this.selections.remove(node);
28870 if(!suppressEvent){
28871 this.fireEvent("selectionchange", this, this.selections);
28879 * Ext JS Library 1.1.1
28880 * Copyright(c) 2006-2007, Ext JS, LLC.
28882 * Originally Released Under LGPL - original licence link has changed is not relivant.
28885 * <script type="text/javascript">
28889 * @class Roo.LayoutManager
28890 * @extends Roo.util.Observable
28891 * Base class for layout managers.
28893 Roo.LayoutManager = function(container, config){
28894 Roo.LayoutManager.superclass.constructor.call(this);
28895 this.el = Roo.get(container);
28896 // ie scrollbar fix
28897 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28898 document.body.scroll = "no";
28899 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28900 this.el.position('relative');
28902 this.id = this.el.id;
28903 this.el.addClass("x-layout-container");
28904 /** false to disable window resize monitoring @type Boolean */
28905 this.monitorWindowResize = true;
28910 * Fires when a layout is performed.
28911 * @param {Roo.LayoutManager} this
28915 * @event regionresized
28916 * Fires when the user resizes a region.
28917 * @param {Roo.LayoutRegion} region The resized region
28918 * @param {Number} newSize The new size (width for east/west, height for north/south)
28920 "regionresized" : true,
28922 * @event regioncollapsed
28923 * Fires when a region is collapsed.
28924 * @param {Roo.LayoutRegion} region The collapsed region
28926 "regioncollapsed" : true,
28928 * @event regionexpanded
28929 * Fires when a region is expanded.
28930 * @param {Roo.LayoutRegion} region The expanded region
28932 "regionexpanded" : true
28934 this.updating = false;
28935 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28938 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28940 * Returns true if this layout is currently being updated
28941 * @return {Boolean}
28943 isUpdating : function(){
28944 return this.updating;
28948 * Suspend the LayoutManager from doing auto-layouts while
28949 * making multiple add or remove calls
28951 beginUpdate : function(){
28952 this.updating = true;
28956 * Restore auto-layouts and optionally disable the manager from performing a layout
28957 * @param {Boolean} noLayout true to disable a layout update
28959 endUpdate : function(noLayout){
28960 this.updating = false;
28966 layout: function(){
28970 onRegionResized : function(region, newSize){
28971 this.fireEvent("regionresized", region, newSize);
28975 onRegionCollapsed : function(region){
28976 this.fireEvent("regioncollapsed", region);
28979 onRegionExpanded : function(region){
28980 this.fireEvent("regionexpanded", region);
28984 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28985 * performs box-model adjustments.
28986 * @return {Object} The size as an object {width: (the width), height: (the height)}
28988 getViewSize : function(){
28990 if(this.el.dom != document.body){
28991 size = this.el.getSize();
28993 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28995 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28996 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
29001 * Returns the Element this layout is bound to.
29002 * @return {Roo.Element}
29004 getEl : function(){
29009 * Returns the specified region.
29010 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
29011 * @return {Roo.LayoutRegion}
29013 getRegion : function(target){
29014 return this.regions[target.toLowerCase()];
29017 onWindowResize : function(){
29018 if(this.monitorWindowResize){
29024 * Ext JS Library 1.1.1
29025 * Copyright(c) 2006-2007, Ext JS, LLC.
29027 * Originally Released Under LGPL - original licence link has changed is not relivant.
29030 * <script type="text/javascript">
29033 * @class Roo.BorderLayout
29034 * @extends Roo.LayoutManager
29035 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
29036 * please see: <br><br>
29037 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
29038 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
29041 var layout = new Roo.BorderLayout(document.body, {
29075 preferredTabWidth: 150
29080 var CP = Roo.ContentPanel;
29082 layout.beginUpdate();
29083 layout.add("north", new CP("north", "North"));
29084 layout.add("south", new CP("south", {title: "South", closable: true}));
29085 layout.add("west", new CP("west", {title: "West"}));
29086 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
29087 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
29088 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
29089 layout.getRegion("center").showPanel("center1");
29090 layout.endUpdate();
29093 <b>The container the layout is rendered into can be either the body element or any other element.
29094 If it is not the body element, the container needs to either be an absolute positioned element,
29095 or you will need to add "position:relative" to the css of the container. You will also need to specify
29096 the container size if it is not the body element.</b>
29099 * Create a new BorderLayout
29100 * @param {String/HTMLElement/Element} container The container this layout is bound to
29101 * @param {Object} config Configuration options
29103 Roo.BorderLayout = function(container, config){
29104 config = config || {};
29105 Roo.BorderLayout.superclass.constructor.call(this, container, config);
29106 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
29107 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
29108 var target = this.factory.validRegions[i];
29109 if(config[target]){
29110 this.addRegion(target, config[target]);
29115 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
29117 * Creates and adds a new region if it doesn't already exist.
29118 * @param {String} target The target region key (north, south, east, west or center).
29119 * @param {Object} config The regions config object
29120 * @return {BorderLayoutRegion} The new region
29122 addRegion : function(target, config){
29123 if(!this.regions[target]){
29124 var r = this.factory.create(target, this, config);
29125 this.bindRegion(target, r);
29127 return this.regions[target];
29131 bindRegion : function(name, r){
29132 this.regions[name] = r;
29133 r.on("visibilitychange", this.layout, this);
29134 r.on("paneladded", this.layout, this);
29135 r.on("panelremoved", this.layout, this);
29136 r.on("invalidated", this.layout, this);
29137 r.on("resized", this.onRegionResized, this);
29138 r.on("collapsed", this.onRegionCollapsed, this);
29139 r.on("expanded", this.onRegionExpanded, this);
29143 * Performs a layout update.
29145 layout : function(){
29146 if(this.updating) return;
29147 var size = this.getViewSize();
29148 var w = size.width;
29149 var h = size.height;
29154 //var x = 0, y = 0;
29156 var rs = this.regions;
29157 var north = rs["north"];
29158 var south = rs["south"];
29159 var west = rs["west"];
29160 var east = rs["east"];
29161 var center = rs["center"];
29162 //if(this.hideOnLayout){ // not supported anymore
29163 //c.el.setStyle("display", "none");
29165 if(north && north.isVisible()){
29166 var b = north.getBox();
29167 var m = north.getMargins();
29168 b.width = w - (m.left+m.right);
29171 centerY = b.height + b.y + m.bottom;
29172 centerH -= centerY;
29173 north.updateBox(this.safeBox(b));
29175 if(south && south.isVisible()){
29176 var b = south.getBox();
29177 var m = south.getMargins();
29178 b.width = w - (m.left+m.right);
29180 var totalHeight = (b.height + m.top + m.bottom);
29181 b.y = h - totalHeight + m.top;
29182 centerH -= totalHeight;
29183 south.updateBox(this.safeBox(b));
29185 if(west && west.isVisible()){
29186 var b = west.getBox();
29187 var m = west.getMargins();
29188 b.height = centerH - (m.top+m.bottom);
29190 b.y = centerY + m.top;
29191 var totalWidth = (b.width + m.left + m.right);
29192 centerX += totalWidth;
29193 centerW -= totalWidth;
29194 west.updateBox(this.safeBox(b));
29196 if(east && east.isVisible()){
29197 var b = east.getBox();
29198 var m = east.getMargins();
29199 b.height = centerH - (m.top+m.bottom);
29200 var totalWidth = (b.width + m.left + m.right);
29201 b.x = w - totalWidth + m.left;
29202 b.y = centerY + m.top;
29203 centerW -= totalWidth;
29204 east.updateBox(this.safeBox(b));
29207 var m = center.getMargins();
29209 x: centerX + m.left,
29210 y: centerY + m.top,
29211 width: centerW - (m.left+m.right),
29212 height: centerH - (m.top+m.bottom)
29214 //if(this.hideOnLayout){
29215 //center.el.setStyle("display", "block");
29217 center.updateBox(this.safeBox(centerBox));
29220 this.fireEvent("layout", this);
29224 safeBox : function(box){
29225 box.width = Math.max(0, box.width);
29226 box.height = Math.max(0, box.height);
29231 * Adds a ContentPanel (or subclass) to this layout.
29232 * @param {String} target The target region key (north, south, east, west or center).
29233 * @param {Roo.ContentPanel} panel The panel to add
29234 * @return {Roo.ContentPanel} The added panel
29236 add : function(target, panel){
29238 target = target.toLowerCase();
29239 return this.regions[target].add(panel);
29243 * Remove a ContentPanel (or subclass) to this layout.
29244 * @param {String} target The target region key (north, south, east, west or center).
29245 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29246 * @return {Roo.ContentPanel} The removed panel
29248 remove : function(target, panel){
29249 target = target.toLowerCase();
29250 return this.regions[target].remove(panel);
29254 * Searches all regions for a panel with the specified id
29255 * @param {String} panelId
29256 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29258 findPanel : function(panelId){
29259 var rs = this.regions;
29260 for(var target in rs){
29261 if(typeof rs[target] != "function"){
29262 var p = rs[target].getPanel(panelId);
29272 * Searches all regions for a panel with the specified id and activates (shows) it.
29273 * @param {String/ContentPanel} panelId The panels id or the panel itself
29274 * @return {Roo.ContentPanel} The shown panel or null
29276 showPanel : function(panelId) {
29277 var rs = this.regions;
29278 for(var target in rs){
29279 var r = rs[target];
29280 if(typeof r != "function"){
29281 if(r.hasPanel(panelId)){
29282 return r.showPanel(panelId);
29290 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29291 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29293 restoreState : function(provider){
29295 provider = Roo.state.Manager;
29297 var sm = new Roo.LayoutStateManager();
29298 sm.init(this, provider);
29302 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29303 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29304 * a valid ContentPanel config object. Example:
29306 // Create the main layout
29307 var layout = new Roo.BorderLayout('main-ct', {
29318 // Create and add multiple ContentPanels at once via configs
29321 id: 'source-files',
29323 title:'Ext Source Files',
29336 * @param {Object} regions An object containing ContentPanel configs by region name
29338 batchAdd : function(regions){
29339 this.beginUpdate();
29340 for(var rname in regions){
29341 var lr = this.regions[rname];
29343 this.addTypedPanels(lr, regions[rname]);
29350 addTypedPanels : function(lr, ps){
29351 if(typeof ps == 'string'){
29352 lr.add(new Roo.ContentPanel(ps));
29354 else if(ps instanceof Array){
29355 for(var i =0, len = ps.length; i < len; i++){
29356 this.addTypedPanels(lr, ps[i]);
29359 else if(!ps.events){ // raw config?
29361 delete ps.el; // prevent conflict
29362 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29364 else { // panel object assumed!
29369 * Adds a xtype elements to the layout.
29373 xtype : 'ContentPanel',
29380 xtype : 'NestedLayoutPanel',
29386 items : [ ... list of content panels or nested layout panels.. ]
29390 * @param {Object} cfg Xtype definition of item to add.
29392 addxtype : function(cfg)
29394 // basically accepts a pannel...
29395 // can accept a layout region..!?!?
29396 // console.log('BorderLayout add ' + cfg.xtype)
29398 if (!cfg.xtype.match(/Panel$/)) {
29402 var region = cfg.region;
29408 xitems = cfg.items;
29415 case 'ContentPanel': // ContentPanel (el, cfg)
29416 case 'ScrollPanel': // ContentPanel (el, cfg)
29417 if(cfg.autoCreate) {
29418 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29420 var el = this.el.createChild();
29421 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29424 this.add(region, ret);
29428 case 'TreePanel': // our new panel!
29429 cfg.el = this.el.createChild();
29430 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29431 this.add(region, ret);
29434 case 'NestedLayoutPanel':
29435 // create a new Layout (which is a Border Layout...
29436 var el = this.el.createChild();
29437 var clayout = cfg.layout;
29439 clayout.items = clayout.items || [];
29440 // replace this exitems with the clayout ones..
29441 xitems = clayout.items;
29444 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29445 cfg.background = false;
29447 var layout = new Roo.BorderLayout(el, clayout);
29449 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29450 //console.log('adding nested layout panel ' + cfg.toSource());
29451 this.add(region, ret);
29457 // needs grid and region
29459 //var el = this.getRegion(region).el.createChild();
29460 var el = this.el.createChild();
29461 // create the grid first...
29463 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29465 if (region == 'center' && this.active ) {
29466 cfg.background = false;
29468 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29470 this.add(region, ret);
29471 if (cfg.background) {
29472 ret.on('activate', function(gp) {
29473 if (!gp.grid.rendered) {
29486 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29488 // GridPanel (grid, cfg)
29491 this.beginUpdate();
29493 Roo.each(xitems, function(i) {
29503 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29504 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29505 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29506 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29509 var CP = Roo.ContentPanel;
29511 var layout = Roo.BorderLayout.create({
29515 panels: [new CP("north", "North")]
29524 panels: [new CP("west", {title: "West"})]
29533 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29542 panels: [new CP("south", {title: "South", closable: true})]
29549 preferredTabWidth: 150,
29551 new CP("center1", {title: "Close Me", closable: true}),
29552 new CP("center2", {title: "Center Panel", closable: false})
29557 layout.getRegion("center").showPanel("center1");
29562 Roo.BorderLayout.create = function(config, targetEl){
29563 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29564 layout.beginUpdate();
29565 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29566 for(var j = 0, jlen = regions.length; j < jlen; j++){
29567 var lr = regions[j];
29568 if(layout.regions[lr] && config[lr].panels){
29569 var r = layout.regions[lr];
29570 var ps = config[lr].panels;
29571 layout.addTypedPanels(r, ps);
29574 layout.endUpdate();
29579 Roo.BorderLayout.RegionFactory = {
29581 validRegions : ["north","south","east","west","center"],
29584 create : function(target, mgr, config){
29585 target = target.toLowerCase();
29586 if(config.lightweight || config.basic){
29587 return new Roo.BasicLayoutRegion(mgr, config, target);
29591 return new Roo.NorthLayoutRegion(mgr, config);
29593 return new Roo.SouthLayoutRegion(mgr, config);
29595 return new Roo.EastLayoutRegion(mgr, config);
29597 return new Roo.WestLayoutRegion(mgr, config);
29599 return new Roo.CenterLayoutRegion(mgr, config);
29601 throw 'Layout region "'+target+'" not supported.';
29605 * Ext JS Library 1.1.1
29606 * Copyright(c) 2006-2007, Ext JS, LLC.
29608 * Originally Released Under LGPL - original licence link has changed is not relivant.
29611 * <script type="text/javascript">
29615 * @class Roo.BasicLayoutRegion
29616 * @extends Roo.util.Observable
29617 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29618 * and does not have a titlebar, tabs or any other features. All it does is size and position
29619 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29621 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29623 this.position = pos;
29626 * @scope Roo.BasicLayoutRegion
29630 * @event beforeremove
29631 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29632 * @param {Roo.LayoutRegion} this
29633 * @param {Roo.ContentPanel} panel The panel
29634 * @param {Object} e The cancel event object
29636 "beforeremove" : true,
29638 * @event invalidated
29639 * Fires when the layout for this region is changed.
29640 * @param {Roo.LayoutRegion} this
29642 "invalidated" : true,
29644 * @event visibilitychange
29645 * Fires when this region is shown or hidden
29646 * @param {Roo.LayoutRegion} this
29647 * @param {Boolean} visibility true or false
29649 "visibilitychange" : true,
29651 * @event paneladded
29652 * Fires when a panel is added.
29653 * @param {Roo.LayoutRegion} this
29654 * @param {Roo.ContentPanel} panel The panel
29656 "paneladded" : true,
29658 * @event panelremoved
29659 * Fires when a panel is removed.
29660 * @param {Roo.LayoutRegion} this
29661 * @param {Roo.ContentPanel} panel The panel
29663 "panelremoved" : true,
29666 * Fires when this region is collapsed.
29667 * @param {Roo.LayoutRegion} this
29669 "collapsed" : true,
29672 * Fires when this region is expanded.
29673 * @param {Roo.LayoutRegion} this
29678 * Fires when this region is slid into view.
29679 * @param {Roo.LayoutRegion} this
29681 "slideshow" : true,
29684 * Fires when this region slides out of view.
29685 * @param {Roo.LayoutRegion} this
29687 "slidehide" : true,
29689 * @event panelactivated
29690 * Fires when a panel is activated.
29691 * @param {Roo.LayoutRegion} this
29692 * @param {Roo.ContentPanel} panel The activated panel
29694 "panelactivated" : true,
29697 * Fires when the user resizes this region.
29698 * @param {Roo.LayoutRegion} this
29699 * @param {Number} newSize The new size (width for east/west, height for north/south)
29703 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29704 this.panels = new Roo.util.MixedCollection();
29705 this.panels.getKey = this.getPanelId.createDelegate(this);
29707 this.activePanel = null;
29708 // ensure listeners are added...
29710 if (config.listeners || config.events) {
29711 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29712 listeners : config.listeners || {},
29713 events : config.events || {}
29717 if(skipConfig !== true){
29718 this.applyConfig(config);
29722 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29723 getPanelId : function(p){
29727 applyConfig : function(config){
29728 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29729 this.config = config;
29734 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29735 * the width, for horizontal (north, south) the height.
29736 * @param {Number} newSize The new width or height
29738 resizeTo : function(newSize){
29739 var el = this.el ? this.el :
29740 (this.activePanel ? this.activePanel.getEl() : null);
29742 switch(this.position){
29745 el.setWidth(newSize);
29746 this.fireEvent("resized", this, newSize);
29750 el.setHeight(newSize);
29751 this.fireEvent("resized", this, newSize);
29757 getBox : function(){
29758 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29761 getMargins : function(){
29762 return this.margins;
29765 updateBox : function(box){
29767 var el = this.activePanel.getEl();
29768 el.dom.style.left = box.x + "px";
29769 el.dom.style.top = box.y + "px";
29770 this.activePanel.setSize(box.width, box.height);
29774 * Returns the container element for this region.
29775 * @return {Roo.Element}
29777 getEl : function(){
29778 return this.activePanel;
29782 * Returns true if this region is currently visible.
29783 * @return {Boolean}
29785 isVisible : function(){
29786 return this.activePanel ? true : false;
29789 setActivePanel : function(panel){
29790 panel = this.getPanel(panel);
29791 if(this.activePanel && this.activePanel != panel){
29792 this.activePanel.setActiveState(false);
29793 this.activePanel.getEl().setLeftTop(-10000,-10000);
29795 this.activePanel = panel;
29796 panel.setActiveState(true);
29798 panel.setSize(this.box.width, this.box.height);
29800 this.fireEvent("panelactivated", this, panel);
29801 this.fireEvent("invalidated");
29805 * Show the specified panel.
29806 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29807 * @return {Roo.ContentPanel} The shown panel or null
29809 showPanel : function(panel){
29810 if(panel = this.getPanel(panel)){
29811 this.setActivePanel(panel);
29817 * Get the active panel for this region.
29818 * @return {Roo.ContentPanel} The active panel or null
29820 getActivePanel : function(){
29821 return this.activePanel;
29825 * Add the passed ContentPanel(s)
29826 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29827 * @return {Roo.ContentPanel} The panel added (if only one was added)
29829 add : function(panel){
29830 if(arguments.length > 1){
29831 for(var i = 0, len = arguments.length; i < len; i++) {
29832 this.add(arguments[i]);
29836 if(this.hasPanel(panel)){
29837 this.showPanel(panel);
29840 var el = panel.getEl();
29841 if(el.dom.parentNode != this.mgr.el.dom){
29842 this.mgr.el.dom.appendChild(el.dom);
29844 if(panel.setRegion){
29845 panel.setRegion(this);
29847 this.panels.add(panel);
29848 el.setStyle("position", "absolute");
29849 if(!panel.background){
29850 this.setActivePanel(panel);
29851 if(this.config.initialSize && this.panels.getCount()==1){
29852 this.resizeTo(this.config.initialSize);
29855 this.fireEvent("paneladded", this, panel);
29860 * Returns true if the panel is in this region.
29861 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29862 * @return {Boolean}
29864 hasPanel : function(panel){
29865 if(typeof panel == "object"){ // must be panel obj
29866 panel = panel.getId();
29868 return this.getPanel(panel) ? true : false;
29872 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29873 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29874 * @param {Boolean} preservePanel Overrides the config preservePanel option
29875 * @return {Roo.ContentPanel} The panel that was removed
29877 remove : function(panel, preservePanel){
29878 panel = this.getPanel(panel);
29883 this.fireEvent("beforeremove", this, panel, e);
29884 if(e.cancel === true){
29887 var panelId = panel.getId();
29888 this.panels.removeKey(panelId);
29893 * Returns the panel specified or null if it's not in this region.
29894 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29895 * @return {Roo.ContentPanel}
29897 getPanel : function(id){
29898 if(typeof id == "object"){ // must be panel obj
29901 return this.panels.get(id);
29905 * Returns this regions position (north/south/east/west/center).
29908 getPosition: function(){
29909 return this.position;
29913 * Ext JS Library 1.1.1
29914 * Copyright(c) 2006-2007, Ext JS, LLC.
29916 * Originally Released Under LGPL - original licence link has changed is not relivant.
29919 * <script type="text/javascript">
29923 * @class Roo.LayoutRegion
29924 * @extends Roo.BasicLayoutRegion
29925 * This class represents a region in a layout manager.
29926 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29927 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29928 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29929 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29930 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
29931 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29932 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29933 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29934 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29935 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29936 * @cfg {String} title The title for the region (overrides panel titles)
29937 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29938 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29939 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29940 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29941 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29942 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29943 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29944 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29945 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29946 * @cfg {Boolean} showPin True to show a pin button
29947 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29948 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29949 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29950 * @cfg {Number} width For East/West panels
29951 * @cfg {Number} height For North/South panels
29952 * @cfg {Boolean} split To show the splitter
29954 Roo.LayoutRegion = function(mgr, config, pos){
29955 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29956 var dh = Roo.DomHelper;
29957 /** This region's container element
29958 * @type Roo.Element */
29959 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29960 /** This region's title element
29961 * @type Roo.Element */
29963 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29964 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29965 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29967 this.titleEl.enableDisplayMode();
29968 /** This region's title text element
29969 * @type HTMLElement */
29970 this.titleTextEl = this.titleEl.dom.firstChild;
29971 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29972 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29973 this.closeBtn.enableDisplayMode();
29974 this.closeBtn.on("click", this.closeClicked, this);
29975 this.closeBtn.hide();
29977 this.createBody(config);
29978 this.visible = true;
29979 this.collapsed = false;
29981 if(config.hideWhenEmpty){
29983 this.on("paneladded", this.validateVisibility, this);
29984 this.on("panelremoved", this.validateVisibility, this);
29986 this.applyConfig(config);
29989 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29991 createBody : function(){
29992 /** This region's body element
29993 * @type Roo.Element */
29994 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29997 applyConfig : function(c){
29998 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29999 var dh = Roo.DomHelper;
30000 if(c.titlebar !== false){
30001 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
30002 this.collapseBtn.on("click", this.collapse, this);
30003 this.collapseBtn.enableDisplayMode();
30005 if(c.showPin === true || this.showPin){
30006 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
30007 this.stickBtn.enableDisplayMode();
30008 this.stickBtn.on("click", this.expand, this);
30009 this.stickBtn.hide();
30012 /** This region's collapsed element
30013 * @type Roo.Element */
30014 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
30015 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
30017 if(c.floatable !== false){
30018 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
30019 this.collapsedEl.on("click", this.collapseClick, this);
30022 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
30023 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
30024 id: "message", unselectable: "on", style:{"float":"left"}});
30025 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
30027 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
30028 this.expandBtn.on("click", this.expand, this);
30030 if(this.collapseBtn){
30031 this.collapseBtn.setVisible(c.collapsible == true);
30033 this.cmargins = c.cmargins || this.cmargins ||
30034 (this.position == "west" || this.position == "east" ?
30035 {top: 0, left: 2, right:2, bottom: 0} :
30036 {top: 2, left: 0, right:0, bottom: 2});
30037 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
30038 this.bottomTabs = c.tabPosition != "top";
30039 this.autoScroll = c.autoScroll || false;
30040 if(this.autoScroll){
30041 this.bodyEl.setStyle("overflow", "auto");
30043 this.bodyEl.setStyle("overflow", "hidden");
30045 //if(c.titlebar !== false){
30046 if((!c.titlebar && !c.title) || c.titlebar === false){
30047 this.titleEl.hide();
30049 this.titleEl.show();
30051 this.titleTextEl.innerHTML = c.title;
30055 this.duration = c.duration || .30;
30056 this.slideDuration = c.slideDuration || .45;
30059 this.collapse(true);
30066 * Returns true if this region is currently visible.
30067 * @return {Boolean}
30069 isVisible : function(){
30070 return this.visible;
30074 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
30075 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
30077 setCollapsedTitle : function(title){
30078 title = title || " ";
30079 if(this.collapsedTitleTextEl){
30080 this.collapsedTitleTextEl.innerHTML = title;
30084 getBox : function(){
30086 if(!this.collapsed){
30087 b = this.el.getBox(false, true);
30089 b = this.collapsedEl.getBox(false, true);
30094 getMargins : function(){
30095 return this.collapsed ? this.cmargins : this.margins;
30098 highlight : function(){
30099 this.el.addClass("x-layout-panel-dragover");
30102 unhighlight : function(){
30103 this.el.removeClass("x-layout-panel-dragover");
30106 updateBox : function(box){
30108 if(!this.collapsed){
30109 this.el.dom.style.left = box.x + "px";
30110 this.el.dom.style.top = box.y + "px";
30111 this.updateBody(box.width, box.height);
30113 this.collapsedEl.dom.style.left = box.x + "px";
30114 this.collapsedEl.dom.style.top = box.y + "px";
30115 this.collapsedEl.setSize(box.width, box.height);
30118 this.tabs.autoSizeTabs();
30122 updateBody : function(w, h){
30124 this.el.setWidth(w);
30125 w -= this.el.getBorderWidth("rl");
30126 if(this.config.adjustments){
30127 w += this.config.adjustments[0];
30131 this.el.setHeight(h);
30132 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
30133 h -= this.el.getBorderWidth("tb");
30134 if(this.config.adjustments){
30135 h += this.config.adjustments[1];
30137 this.bodyEl.setHeight(h);
30139 h = this.tabs.syncHeight(h);
30142 if(this.panelSize){
30143 w = w !== null ? w : this.panelSize.width;
30144 h = h !== null ? h : this.panelSize.height;
30146 if(this.activePanel){
30147 var el = this.activePanel.getEl();
30148 w = w !== null ? w : el.getWidth();
30149 h = h !== null ? h : el.getHeight();
30150 this.panelSize = {width: w, height: h};
30151 this.activePanel.setSize(w, h);
30153 if(Roo.isIE && this.tabs){
30154 this.tabs.el.repaint();
30159 * Returns the container element for this region.
30160 * @return {Roo.Element}
30162 getEl : function(){
30167 * Hides this region.
30170 if(!this.collapsed){
30171 this.el.dom.style.left = "-2000px";
30174 this.collapsedEl.dom.style.left = "-2000px";
30175 this.collapsedEl.hide();
30177 this.visible = false;
30178 this.fireEvent("visibilitychange", this, false);
30182 * Shows this region if it was previously hidden.
30185 if(!this.collapsed){
30188 this.collapsedEl.show();
30190 this.visible = true;
30191 this.fireEvent("visibilitychange", this, true);
30194 closeClicked : function(){
30195 if(this.activePanel){
30196 this.remove(this.activePanel);
30200 collapseClick : function(e){
30202 e.stopPropagation();
30205 e.stopPropagation();
30211 * Collapses this region.
30212 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
30214 collapse : function(skipAnim){
30215 if(this.collapsed) return;
30216 this.collapsed = true;
30218 this.split.el.hide();
30220 if(this.config.animate && skipAnim !== true){
30221 this.fireEvent("invalidated", this);
30222 this.animateCollapse();
30224 this.el.setLocation(-20000,-20000);
30226 this.collapsedEl.show();
30227 this.fireEvent("collapsed", this);
30228 this.fireEvent("invalidated", this);
30232 animateCollapse : function(){
30237 * Expands this region if it was previously collapsed.
30238 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
30239 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
30241 expand : function(e, skipAnim){
30242 if(e) e.stopPropagation();
30243 if(!this.collapsed || this.el.hasActiveFx()) return;
30245 this.afterSlideIn();
30248 this.collapsed = false;
30249 if(this.config.animate && skipAnim !== true){
30250 this.animateExpand();
30254 this.split.el.show();
30256 this.collapsedEl.setLocation(-2000,-2000);
30257 this.collapsedEl.hide();
30258 this.fireEvent("invalidated", this);
30259 this.fireEvent("expanded", this);
30263 animateExpand : function(){
30267 initTabs : function(){
30268 this.bodyEl.setStyle("overflow", "hidden");
30269 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30270 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30271 disableTooltips: this.config.disableTabTips
30273 if(this.config.hideTabs){
30274 ts.stripWrap.setDisplayed(false);
30277 ts.resizeTabs = this.config.resizeTabs === true;
30278 ts.minTabWidth = this.config.minTabWidth || 40;
30279 ts.maxTabWidth = this.config.maxTabWidth || 250;
30280 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30281 ts.monitorResize = false;
30282 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30283 ts.bodyEl.addClass('x-layout-tabs-body');
30284 this.panels.each(this.initPanelAsTab, this);
30287 initPanelAsTab : function(panel){
30288 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30289 this.config.closeOnTab && panel.isClosable());
30290 if(panel.tabTip !== undefined){
30291 ti.setTooltip(panel.tabTip);
30293 ti.on("activate", function(){
30294 this.setActivePanel(panel);
30296 if(this.config.closeOnTab){
30297 ti.on("beforeclose", function(t, e){
30299 this.remove(panel);
30305 updatePanelTitle : function(panel, title){
30306 if(this.activePanel == panel){
30307 this.updateTitle(title);
30310 var ti = this.tabs.getTab(panel.getEl().id);
30312 if(panel.tabTip !== undefined){
30313 ti.setTooltip(panel.tabTip);
30318 updateTitle : function(title){
30319 if(this.titleTextEl && !this.config.title){
30320 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30324 setActivePanel : function(panel){
30325 panel = this.getPanel(panel);
30326 if(this.activePanel && this.activePanel != panel){
30327 this.activePanel.setActiveState(false);
30329 this.activePanel = panel;
30330 panel.setActiveState(true);
30331 if(this.panelSize){
30332 panel.setSize(this.panelSize.width, this.panelSize.height);
30335 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30337 this.updateTitle(panel.getTitle());
30339 this.fireEvent("invalidated", this);
30341 this.fireEvent("panelactivated", this, panel);
30345 * Shows the specified panel.
30346 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30347 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30349 showPanel : function(panel){
30350 if(panel = this.getPanel(panel)){
30352 var tab = this.tabs.getTab(panel.getEl().id);
30353 if(tab.isHidden()){
30354 this.tabs.unhideTab(tab.id);
30358 this.setActivePanel(panel);
30365 * Get the active panel for this region.
30366 * @return {Roo.ContentPanel} The active panel or null
30368 getActivePanel : function(){
30369 return this.activePanel;
30372 validateVisibility : function(){
30373 if(this.panels.getCount() < 1){
30374 this.updateTitle(" ");
30375 this.closeBtn.hide();
30378 if(!this.isVisible()){
30385 * Adds the passed ContentPanel(s) to this region.
30386 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30387 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30389 add : function(panel){
30390 if(arguments.length > 1){
30391 for(var i = 0, len = arguments.length; i < len; i++) {
30392 this.add(arguments[i]);
30396 if(this.hasPanel(panel)){
30397 this.showPanel(panel);
30400 panel.setRegion(this);
30401 this.panels.add(panel);
30402 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30403 this.bodyEl.dom.appendChild(panel.getEl().dom);
30404 if(panel.background !== true){
30405 this.setActivePanel(panel);
30407 this.fireEvent("paneladded", this, panel);
30413 this.initPanelAsTab(panel);
30415 if(panel.background !== true){
30416 this.tabs.activate(panel.getEl().id);
30418 this.fireEvent("paneladded", this, panel);
30423 * Hides the tab for the specified panel.
30424 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30426 hidePanel : function(panel){
30427 if(this.tabs && (panel = this.getPanel(panel))){
30428 this.tabs.hideTab(panel.getEl().id);
30433 * Unhides the tab for a previously hidden panel.
30434 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30436 unhidePanel : function(panel){
30437 if(this.tabs && (panel = this.getPanel(panel))){
30438 this.tabs.unhideTab(panel.getEl().id);
30442 clearPanels : function(){
30443 while(this.panels.getCount() > 0){
30444 this.remove(this.panels.first());
30449 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30450 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30451 * @param {Boolean} preservePanel Overrides the config preservePanel option
30452 * @return {Roo.ContentPanel} The panel that was removed
30454 remove : function(panel, preservePanel){
30455 panel = this.getPanel(panel);
30460 this.fireEvent("beforeremove", this, panel, e);
30461 if(e.cancel === true){
30464 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30465 var panelId = panel.getId();
30466 this.panels.removeKey(panelId);
30468 document.body.appendChild(panel.getEl().dom);
30471 this.tabs.removeTab(panel.getEl().id);
30472 }else if (!preservePanel){
30473 this.bodyEl.dom.removeChild(panel.getEl().dom);
30475 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30476 var p = this.panels.first();
30477 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30478 tempEl.appendChild(p.getEl().dom);
30479 this.bodyEl.update("");
30480 this.bodyEl.dom.appendChild(p.getEl().dom);
30482 this.updateTitle(p.getTitle());
30484 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30485 this.setActivePanel(p);
30487 panel.setRegion(null);
30488 if(this.activePanel == panel){
30489 this.activePanel = null;
30491 if(this.config.autoDestroy !== false && preservePanel !== true){
30492 try{panel.destroy();}catch(e){}
30494 this.fireEvent("panelremoved", this, panel);
30499 * Returns the TabPanel component used by this region
30500 * @return {Roo.TabPanel}
30502 getTabs : function(){
30506 createTool : function(parentEl, className){
30507 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30508 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30509 btn.addClassOnOver("x-layout-tools-button-over");
30514 * Ext JS Library 1.1.1
30515 * Copyright(c) 2006-2007, Ext JS, LLC.
30517 * Originally Released Under LGPL - original licence link has changed is not relivant.
30520 * <script type="text/javascript">
30526 * @class Roo.SplitLayoutRegion
30527 * @extends Roo.LayoutRegion
30528 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30530 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30531 this.cursor = cursor;
30532 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30535 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30536 splitTip : "Drag to resize.",
30537 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30538 useSplitTips : false,
30540 applyConfig : function(config){
30541 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30544 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30545 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30546 /** The SplitBar for this region
30547 * @type Roo.SplitBar */
30548 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30549 this.split.on("moved", this.onSplitMove, this);
30550 this.split.useShim = config.useShim === true;
30551 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30552 if(this.useSplitTips){
30553 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30555 if(config.collapsible){
30556 this.split.el.on("dblclick", this.collapse, this);
30559 if(typeof config.minSize != "undefined"){
30560 this.split.minSize = config.minSize;
30562 if(typeof config.maxSize != "undefined"){
30563 this.split.maxSize = config.maxSize;
30565 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30566 this.hideSplitter();
30571 getHMaxSize : function(){
30572 var cmax = this.config.maxSize || 10000;
30573 var center = this.mgr.getRegion("center");
30574 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30577 getVMaxSize : function(){
30578 var cmax = this.config.maxSize || 10000;
30579 var center = this.mgr.getRegion("center");
30580 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30583 onSplitMove : function(split, newSize){
30584 this.fireEvent("resized", this, newSize);
30588 * Returns the {@link Roo.SplitBar} for this region.
30589 * @return {Roo.SplitBar}
30591 getSplitBar : function(){
30596 this.hideSplitter();
30597 Roo.SplitLayoutRegion.superclass.hide.call(this);
30600 hideSplitter : function(){
30602 this.split.el.setLocation(-2000,-2000);
30603 this.split.el.hide();
30609 this.split.el.show();
30611 Roo.SplitLayoutRegion.superclass.show.call(this);
30614 beforeSlide: function(){
30615 if(Roo.isGecko){// firefox overflow auto bug workaround
30616 this.bodyEl.clip();
30617 if(this.tabs) this.tabs.bodyEl.clip();
30618 if(this.activePanel){
30619 this.activePanel.getEl().clip();
30621 if(this.activePanel.beforeSlide){
30622 this.activePanel.beforeSlide();
30628 afterSlide : function(){
30629 if(Roo.isGecko){// firefox overflow auto bug workaround
30630 this.bodyEl.unclip();
30631 if(this.tabs) this.tabs.bodyEl.unclip();
30632 if(this.activePanel){
30633 this.activePanel.getEl().unclip();
30634 if(this.activePanel.afterSlide){
30635 this.activePanel.afterSlide();
30641 initAutoHide : function(){
30642 if(this.autoHide !== false){
30643 if(!this.autoHideHd){
30644 var st = new Roo.util.DelayedTask(this.slideIn, this);
30645 this.autoHideHd = {
30646 "mouseout": function(e){
30647 if(!e.within(this.el, true)){
30651 "mouseover" : function(e){
30657 this.el.on(this.autoHideHd);
30661 clearAutoHide : function(){
30662 if(this.autoHide !== false){
30663 this.el.un("mouseout", this.autoHideHd.mouseout);
30664 this.el.un("mouseover", this.autoHideHd.mouseover);
30668 clearMonitor : function(){
30669 Roo.get(document).un("click", this.slideInIf, this);
30672 // these names are backwards but not changed for compat
30673 slideOut : function(){
30674 if(this.isSlid || this.el.hasActiveFx()){
30677 this.isSlid = true;
30678 if(this.collapseBtn){
30679 this.collapseBtn.hide();
30681 this.closeBtnState = this.closeBtn.getStyle('display');
30682 this.closeBtn.hide();
30684 this.stickBtn.show();
30687 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30688 this.beforeSlide();
30689 this.el.setStyle("z-index", 10001);
30690 this.el.slideIn(this.getSlideAnchor(), {
30691 callback: function(){
30693 this.initAutoHide();
30694 Roo.get(document).on("click", this.slideInIf, this);
30695 this.fireEvent("slideshow", this);
30702 afterSlideIn : function(){
30703 this.clearAutoHide();
30704 this.isSlid = false;
30705 this.clearMonitor();
30706 this.el.setStyle("z-index", "");
30707 if(this.collapseBtn){
30708 this.collapseBtn.show();
30710 this.closeBtn.setStyle('display', this.closeBtnState);
30712 this.stickBtn.hide();
30714 this.fireEvent("slidehide", this);
30717 slideIn : function(cb){
30718 if(!this.isSlid || this.el.hasActiveFx()){
30722 this.isSlid = false;
30723 this.beforeSlide();
30724 this.el.slideOut(this.getSlideAnchor(), {
30725 callback: function(){
30726 this.el.setLeftTop(-10000, -10000);
30728 this.afterSlideIn();
30736 slideInIf : function(e){
30737 if(!e.within(this.el)){
30742 animateCollapse : function(){
30743 this.beforeSlide();
30744 this.el.setStyle("z-index", 20000);
30745 var anchor = this.getSlideAnchor();
30746 this.el.slideOut(anchor, {
30747 callback : function(){
30748 this.el.setStyle("z-index", "");
30749 this.collapsedEl.slideIn(anchor, {duration:.3});
30751 this.el.setLocation(-10000,-10000);
30753 this.fireEvent("collapsed", this);
30760 animateExpand : function(){
30761 this.beforeSlide();
30762 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30763 this.el.setStyle("z-index", 20000);
30764 this.collapsedEl.hide({
30767 this.el.slideIn(this.getSlideAnchor(), {
30768 callback : function(){
30769 this.el.setStyle("z-index", "");
30772 this.split.el.show();
30774 this.fireEvent("invalidated", this);
30775 this.fireEvent("expanded", this);
30803 getAnchor : function(){
30804 return this.anchors[this.position];
30807 getCollapseAnchor : function(){
30808 return this.canchors[this.position];
30811 getSlideAnchor : function(){
30812 return this.sanchors[this.position];
30815 getAlignAdj : function(){
30816 var cm = this.cmargins;
30817 switch(this.position){
30833 getExpandAdj : function(){
30834 var c = this.collapsedEl, cm = this.cmargins;
30835 switch(this.position){
30837 return [-(cm.right+c.getWidth()+cm.left), 0];
30840 return [cm.right+c.getWidth()+cm.left, 0];
30843 return [0, -(cm.top+cm.bottom+c.getHeight())];
30846 return [0, cm.top+cm.bottom+c.getHeight()];
30852 * Ext JS Library 1.1.1
30853 * Copyright(c) 2006-2007, Ext JS, LLC.
30855 * Originally Released Under LGPL - original licence link has changed is not relivant.
30858 * <script type="text/javascript">
30861 * These classes are private internal classes
30863 Roo.CenterLayoutRegion = function(mgr, config){
30864 Roo.LayoutRegion.call(this, mgr, config, "center");
30865 this.visible = true;
30866 this.minWidth = config.minWidth || 20;
30867 this.minHeight = config.minHeight || 20;
30870 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30872 // center panel can't be hidden
30876 // center panel can't be hidden
30879 getMinWidth: function(){
30880 return this.minWidth;
30883 getMinHeight: function(){
30884 return this.minHeight;
30889 Roo.NorthLayoutRegion = function(mgr, config){
30890 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30892 this.split.placement = Roo.SplitBar.TOP;
30893 this.split.orientation = Roo.SplitBar.VERTICAL;
30894 this.split.el.addClass("x-layout-split-v");
30896 var size = config.initialSize || config.height;
30897 if(typeof size != "undefined"){
30898 this.el.setHeight(size);
30901 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30902 orientation: Roo.SplitBar.VERTICAL,
30903 getBox : function(){
30904 if(this.collapsed){
30905 return this.collapsedEl.getBox();
30907 var box = this.el.getBox();
30909 box.height += this.split.el.getHeight();
30914 updateBox : function(box){
30915 if(this.split && !this.collapsed){
30916 box.height -= this.split.el.getHeight();
30917 this.split.el.setLeft(box.x);
30918 this.split.el.setTop(box.y+box.height);
30919 this.split.el.setWidth(box.width);
30921 if(this.collapsed){
30922 this.updateBody(box.width, null);
30924 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30928 Roo.SouthLayoutRegion = function(mgr, config){
30929 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30931 this.split.placement = Roo.SplitBar.BOTTOM;
30932 this.split.orientation = Roo.SplitBar.VERTICAL;
30933 this.split.el.addClass("x-layout-split-v");
30935 var size = config.initialSize || config.height;
30936 if(typeof size != "undefined"){
30937 this.el.setHeight(size);
30940 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30941 orientation: Roo.SplitBar.VERTICAL,
30942 getBox : function(){
30943 if(this.collapsed){
30944 return this.collapsedEl.getBox();
30946 var box = this.el.getBox();
30948 var sh = this.split.el.getHeight();
30955 updateBox : function(box){
30956 if(this.split && !this.collapsed){
30957 var sh = this.split.el.getHeight();
30960 this.split.el.setLeft(box.x);
30961 this.split.el.setTop(box.y-sh);
30962 this.split.el.setWidth(box.width);
30964 if(this.collapsed){
30965 this.updateBody(box.width, null);
30967 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30971 Roo.EastLayoutRegion = function(mgr, config){
30972 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
30974 this.split.placement = Roo.SplitBar.RIGHT;
30975 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30976 this.split.el.addClass("x-layout-split-h");
30978 var size = config.initialSize || config.width;
30979 if(typeof size != "undefined"){
30980 this.el.setWidth(size);
30983 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
30984 orientation: Roo.SplitBar.HORIZONTAL,
30985 getBox : function(){
30986 if(this.collapsed){
30987 return this.collapsedEl.getBox();
30989 var box = this.el.getBox();
30991 var sw = this.split.el.getWidth();
30998 updateBox : function(box){
30999 if(this.split && !this.collapsed){
31000 var sw = this.split.el.getWidth();
31002 this.split.el.setLeft(box.x);
31003 this.split.el.setTop(box.y);
31004 this.split.el.setHeight(box.height);
31007 if(this.collapsed){
31008 this.updateBody(null, box.height);
31010 Roo.LayoutRegion.prototype.updateBox.call(this, box);
31014 Roo.WestLayoutRegion = function(mgr, config){
31015 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
31017 this.split.placement = Roo.SplitBar.LEFT;
31018 this.split.orientation = Roo.SplitBar.HORIZONTAL;
31019 this.split.el.addClass("x-layout-split-h");
31021 var size = config.initialSize || config.width;
31022 if(typeof size != "undefined"){
31023 this.el.setWidth(size);
31026 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
31027 orientation: Roo.SplitBar.HORIZONTAL,
31028 getBox : function(){
31029 if(this.collapsed){
31030 return this.collapsedEl.getBox();
31032 var box = this.el.getBox();
31034 box.width += this.split.el.getWidth();
31039 updateBox : function(box){
31040 if(this.split && !this.collapsed){
31041 var sw = this.split.el.getWidth();
31043 this.split.el.setLeft(box.x+box.width);
31044 this.split.el.setTop(box.y);
31045 this.split.el.setHeight(box.height);
31047 if(this.collapsed){
31048 this.updateBody(null, box.height);
31050 Roo.LayoutRegion.prototype.updateBox.call(this, box);
31055 * Ext JS Library 1.1.1
31056 * Copyright(c) 2006-2007, Ext JS, LLC.
31058 * Originally Released Under LGPL - original licence link has changed is not relivant.
31061 * <script type="text/javascript">
31066 * Private internal class for reading and applying state
31068 Roo.LayoutStateManager = function(layout){
31069 // default empty state
31078 Roo.LayoutStateManager.prototype = {
31079 init : function(layout, provider){
31080 this.provider = provider;
31081 var state = provider.get(layout.id+"-layout-state");
31083 var wasUpdating = layout.isUpdating();
31085 layout.beginUpdate();
31087 for(var key in state){
31088 if(typeof state[key] != "function"){
31089 var rstate = state[key];
31090 var r = layout.getRegion(key);
31093 r.resizeTo(rstate.size);
31095 if(rstate.collapsed == true){
31098 r.expand(null, true);
31104 layout.endUpdate();
31106 this.state = state;
31108 this.layout = layout;
31109 layout.on("regionresized", this.onRegionResized, this);
31110 layout.on("regioncollapsed", this.onRegionCollapsed, this);
31111 layout.on("regionexpanded", this.onRegionExpanded, this);
31114 storeState : function(){
31115 this.provider.set(this.layout.id+"-layout-state", this.state);
31118 onRegionResized : function(region, newSize){
31119 this.state[region.getPosition()].size = newSize;
31123 onRegionCollapsed : function(region){
31124 this.state[region.getPosition()].collapsed = true;
31128 onRegionExpanded : function(region){
31129 this.state[region.getPosition()].collapsed = false;
31134 * Ext JS Library 1.1.1
31135 * Copyright(c) 2006-2007, Ext JS, LLC.
31137 * Originally Released Under LGPL - original licence link has changed is not relivant.
31140 * <script type="text/javascript">
31143 * @class Roo.ContentPanel
31144 * @extends Roo.util.Observable
31145 * A basic ContentPanel element.
31146 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
31147 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
31148 * @cfg {Boolean/Object} autoCreate True to auto generate the DOM element for this panel, or a {@link Roo.DomHelper} config of the element to create
31149 * @cfg {Boolean} closable True if the panel can be closed/removed
31150 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
31151 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
31152 * @cfg {Toolbar} toolbar A toolbar for this panel
31153 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
31154 * @cfg {String} title The title for this panel
31155 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
31156 * @cfg {String} url Calls {@link #setUrl} with this value
31157 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
31158 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
31159 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
31161 * Create a new ContentPanel.
31162 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
31163 * @param {String/Object} config A string to set only the title or a config object
31164 * @param {String} content (optional) Set the HTML content for this panel
31165 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
31167 Roo.ContentPanel = function(el, config, content){
31171 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
31175 if (config && config.parentLayout) {
31176 el = config.parentLayout.el.createChild();
31179 if(el.autoCreate){ // xtype is available if this is called from factory
31183 this.el = Roo.get(el);
31184 if(!this.el && config && config.autoCreate){
31185 if(typeof config.autoCreate == "object"){
31186 if(!config.autoCreate.id){
31187 config.autoCreate.id = config.id||el;
31189 this.el = Roo.DomHelper.append(document.body,
31190 config.autoCreate, true);
31192 this.el = Roo.DomHelper.append(document.body,
31193 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
31196 this.closable = false;
31197 this.loaded = false;
31198 this.active = false;
31199 if(typeof config == "string"){
31200 this.title = config;
31202 Roo.apply(this, config);
31205 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
31206 this.wrapEl = this.el.wrap();
31207 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
31214 this.resizeEl = Roo.get(this.resizeEl, true);
31216 this.resizeEl = this.el;
31221 * Fires when this panel is activated.
31222 * @param {Roo.ContentPanel} this
31226 * @event deactivate
31227 * Fires when this panel is activated.
31228 * @param {Roo.ContentPanel} this
31230 "deactivate" : true,
31234 * Fires when this panel is resized if fitToFrame is true.
31235 * @param {Roo.ContentPanel} this
31236 * @param {Number} width The width after any component adjustments
31237 * @param {Number} height The height after any component adjustments
31241 if(this.autoScroll){
31242 this.resizeEl.setStyle("overflow", "auto");
31244 // fix randome scrolling
31245 this.el.on('scroll', function() {
31246 Roo.log('fix random scolling');
31247 this.scrollTo('top',0);
31250 content = content || this.content;
31252 this.setContent(content);
31254 if(config && config.url){
31255 this.setUrl(this.url, this.params, this.loadOnce);
31260 Roo.ContentPanel.superclass.constructor.call(this);
31263 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31265 setRegion : function(region){
31266 this.region = region;
31268 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31270 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31275 * Returns the toolbar for this Panel if one was configured.
31276 * @return {Roo.Toolbar}
31278 getToolbar : function(){
31279 return this.toolbar;
31282 setActiveState : function(active){
31283 this.active = active;
31285 this.fireEvent("deactivate", this);
31287 this.fireEvent("activate", this);
31291 * Updates this panel's element
31292 * @param {String} content The new content
31293 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31295 setContent : function(content, loadScripts){
31296 this.el.update(content, loadScripts);
31299 ignoreResize : function(w, h){
31300 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31303 this.lastSize = {width: w, height: h};
31308 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31309 * @return {Roo.UpdateManager} The UpdateManager
31311 getUpdateManager : function(){
31312 return this.el.getUpdateManager();
31315 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31316 * @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:
31319 url: "your-url.php",
31320 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31321 callback: yourFunction,
31322 scope: yourObject, //(optional scope)
31325 text: "Loading...",
31330 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31331 * are shorthand for <i>disableCaching</i>, <i>indicatorText</i> and <i>loadScripts</i> and are used to set their associated property on this panel UpdateManager instance.
31332 * @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}
31333 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31334 * @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.
31335 * @return {Roo.ContentPanel} this
31338 var um = this.el.getUpdateManager();
31339 um.update.apply(um, arguments);
31345 * Set a URL to be used to load the content for this panel. When this panel is activated, the content will be loaded from that URL.
31346 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31347 * @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)
31348 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this panel is activated. (Defaults to false)
31349 * @return {Roo.UpdateManager} The UpdateManager
31351 setUrl : function(url, params, loadOnce){
31352 if(this.refreshDelegate){
31353 this.removeListener("activate", this.refreshDelegate);
31355 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31356 this.on("activate", this.refreshDelegate);
31357 return this.el.getUpdateManager();
31360 _handleRefresh : function(url, params, loadOnce){
31361 if(!loadOnce || !this.loaded){
31362 var updater = this.el.getUpdateManager();
31363 updater.update(url, params, this._setLoaded.createDelegate(this));
31367 _setLoaded : function(){
31368 this.loaded = true;
31372 * Returns this panel's id
31375 getId : function(){
31380 * Returns this panel's element - used by regiosn to add.
31381 * @return {Roo.Element}
31383 getEl : function(){
31384 return this.wrapEl || this.el;
31387 adjustForComponents : function(width, height){
31388 if(this.resizeEl != this.el){
31389 width -= this.el.getFrameWidth('lr');
31390 height -= this.el.getFrameWidth('tb');
31393 var te = this.toolbar.getEl();
31394 height -= te.getHeight();
31395 te.setWidth(width);
31397 if(this.adjustments){
31398 width += this.adjustments[0];
31399 height += this.adjustments[1];
31401 return {"width": width, "height": height};
31404 setSize : function(width, height){
31405 if(this.fitToFrame && !this.ignoreResize(width, height)){
31406 if(this.fitContainer && this.resizeEl != this.el){
31407 this.el.setSize(width, height);
31409 var size = this.adjustForComponents(width, height);
31410 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31411 this.fireEvent('resize', this, size.width, size.height);
31416 * Returns this panel's title
31419 getTitle : function(){
31424 * Set this panel's title
31425 * @param {String} title
31427 setTitle : function(title){
31428 this.title = title;
31430 this.region.updatePanelTitle(this, title);
31435 * Returns true is this panel was configured to be closable
31436 * @return {Boolean}
31438 isClosable : function(){
31439 return this.closable;
31442 beforeSlide : function(){
31444 this.resizeEl.clip();
31447 afterSlide : function(){
31449 this.resizeEl.unclip();
31453 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31454 * Will fail silently if the {@link #setUrl} method has not been called.
31455 * This does not activate the panel, just updates its content.
31457 refresh : function(){
31458 if(this.refreshDelegate){
31459 this.loaded = false;
31460 this.refreshDelegate();
31465 * Destroys this panel
31467 destroy : function(){
31468 this.el.removeAllListeners();
31469 var tempEl = document.createElement("span");
31470 tempEl.appendChild(this.el.dom);
31471 tempEl.innerHTML = "";
31477 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31487 * @param {Object} cfg Xtype definition of item to add.
31490 addxtype : function(cfg) {
31492 if (cfg.xtype.match(/^Form$/)) {
31493 var el = this.el.createChild();
31495 this.form = new Roo.form.Form(cfg);
31498 if ( this.form.allItems.length) this.form.render(el.dom);
31501 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
31503 cfg.el = this.el.appendChild(document.createElement("div"));
31505 var ret = new Roo[cfg.xtype](cfg);
31506 ret.render(false, ''); // render blank..
31516 * @class Roo.GridPanel
31517 * @extends Roo.ContentPanel
31519 * Create a new GridPanel.
31520 * @param {Roo.grid.Grid} grid The grid for this panel
31521 * @param {String/Object} config A string to set only the panel's title, or a config object
31523 Roo.GridPanel = function(grid, config){
31526 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31527 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31529 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31531 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31534 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31536 // xtype created footer. - not sure if will work as we normally have to render first..
31537 if (this.footer && !this.footer.el && this.footer.xtype) {
31539 this.footer.container = this.grid.getView().getFooterPanel(true);
31540 this.footer.dataSource = this.grid.dataSource;
31541 this.footer = Roo.factory(this.footer, Roo);
31545 grid.monitorWindowResize = false; // turn off autosizing
31546 grid.autoHeight = false;
31547 grid.autoWidth = false;
31549 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31552 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31553 getId : function(){
31554 return this.grid.id;
31558 * Returns the grid for this panel
31559 * @return {Roo.grid.Grid}
31561 getGrid : function(){
31565 setSize : function(width, height){
31566 if(!this.ignoreResize(width, height)){
31567 var grid = this.grid;
31568 var size = this.adjustForComponents(width, height);
31569 grid.getGridEl().setSize(size.width, size.height);
31574 beforeSlide : function(){
31575 this.grid.getView().scroller.clip();
31578 afterSlide : function(){
31579 this.grid.getView().scroller.unclip();
31582 destroy : function(){
31583 this.grid.destroy();
31585 Roo.GridPanel.superclass.destroy.call(this);
31591 * @class Roo.NestedLayoutPanel
31592 * @extends Roo.ContentPanel
31594 * Create a new NestedLayoutPanel.
31597 * @param {Roo.BorderLayout} layout The layout for this panel
31598 * @param {String/Object} config A string to set only the title or a config object
31600 Roo.NestedLayoutPanel = function(layout, config)
31602 // construct with only one argument..
31603 /* FIXME - implement nicer consturctors
31604 if (layout.layout) {
31606 layout = config.layout;
31607 delete config.layout;
31609 if (layout.xtype && !layout.getEl) {
31610 // then layout needs constructing..
31611 layout = Roo.factory(layout, Roo);
31616 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31618 layout.monitorWindowResize = false; // turn off autosizing
31619 this.layout = layout;
31620 this.layout.getEl().addClass("x-layout-nested-layout");
31627 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31629 setSize : function(width, height){
31630 if(!this.ignoreResize(width, height)){
31631 var size = this.adjustForComponents(width, height);
31632 var el = this.layout.getEl();
31633 el.setSize(size.width, size.height);
31634 var touch = el.dom.offsetWidth;
31635 this.layout.layout();
31636 // ie requires a double layout on the first pass
31637 if(Roo.isIE && !this.initialized){
31638 this.initialized = true;
31639 this.layout.layout();
31644 // activate all subpanels if not currently active..
31646 setActiveState : function(active){
31647 this.active = active;
31649 this.fireEvent("deactivate", this);
31653 this.fireEvent("activate", this);
31654 // not sure if this should happen before or after..
31655 if (!this.layout) {
31656 return; // should not happen..
31659 for (var r in this.layout.regions) {
31660 reg = this.layout.getRegion(r);
31661 if (reg.getActivePanel()) {
31662 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31663 reg.setActivePanel(reg.getActivePanel());
31666 if (!reg.panels.length) {
31669 reg.showPanel(reg.getPanel(0));
31678 * Returns the nested BorderLayout for this panel
31679 * @return {Roo.BorderLayout}
31681 getLayout : function(){
31682 return this.layout;
31686 * Adds a xtype elements to the layout of the nested panel
31690 xtype : 'ContentPanel',
31697 xtype : 'NestedLayoutPanel',
31703 items : [ ... list of content panels or nested layout panels.. ]
31707 * @param {Object} cfg Xtype definition of item to add.
31709 addxtype : function(cfg) {
31710 return this.layout.addxtype(cfg);
31715 Roo.ScrollPanel = function(el, config, content){
31716 config = config || {};
31717 config.fitToFrame = true;
31718 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31720 this.el.dom.style.overflow = "hidden";
31721 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31722 this.el.removeClass("x-layout-inactive-content");
31723 this.el.on("mousewheel", this.onWheel, this);
31725 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31726 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31727 up.unselectable(); down.unselectable();
31728 up.on("click", this.scrollUp, this);
31729 down.on("click", this.scrollDown, this);
31730 up.addClassOnOver("x-scroller-btn-over");
31731 down.addClassOnOver("x-scroller-btn-over");
31732 up.addClassOnClick("x-scroller-btn-click");
31733 down.addClassOnClick("x-scroller-btn-click");
31734 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31736 this.resizeEl = this.el;
31737 this.el = wrap; this.up = up; this.down = down;
31740 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31742 wheelIncrement : 5,
31743 scrollUp : function(){
31744 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31747 scrollDown : function(){
31748 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31751 afterScroll : function(){
31752 var el = this.resizeEl;
31753 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31754 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31755 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31758 setSize : function(){
31759 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31760 this.afterScroll();
31763 onWheel : function(e){
31764 var d = e.getWheelDelta();
31765 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31766 this.afterScroll();
31770 setContent : function(content, loadScripts){
31771 this.resizeEl.update(content, loadScripts);
31785 * @class Roo.TreePanel
31786 * @extends Roo.ContentPanel
31788 * Create a new TreePanel. - defaults to fit/scoll contents.
31789 * @param {String/Object} config A string to set only the panel's title, or a config object
31790 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31792 Roo.TreePanel = function(config){
31793 var el = config.el;
31794 var tree = config.tree;
31795 delete config.tree;
31796 delete config.el; // hopefull!
31798 // wrapper for IE7 strict & safari scroll issue
31800 var treeEl = el.createChild();
31801 config.resizeEl = treeEl;
31805 Roo.TreePanel.superclass.constructor.call(this, el, config);
31808 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31809 //console.log(tree);
31810 this.on('activate', function()
31812 if (this.tree.rendered) {
31815 //console.log('render tree');
31816 this.tree.render();
31819 this.on('resize', function (cp, w, h) {
31820 this.tree.innerCt.setWidth(w);
31821 this.tree.innerCt.setHeight(h);
31822 this.tree.innerCt.setStyle('overflow-y', 'auto');
31829 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31846 * Ext JS Library 1.1.1
31847 * Copyright(c) 2006-2007, Ext JS, LLC.
31849 * Originally Released Under LGPL - original licence link has changed is not relivant.
31852 * <script type="text/javascript">
31857 * @class Roo.ReaderLayout
31858 * @extends Roo.BorderLayout
31859 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31860 * center region containing two nested regions (a top one for a list view and one for item preview below),
31861 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31862 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31863 * expedites the setup of the overall layout and regions for this common application style.
31866 var reader = new Roo.ReaderLayout();
31867 var CP = Roo.ContentPanel; // shortcut for adding
31869 reader.beginUpdate();
31870 reader.add("north", new CP("north", "North"));
31871 reader.add("west", new CP("west", {title: "West"}));
31872 reader.add("east", new CP("east", {title: "East"}));
31874 reader.regions.listView.add(new CP("listView", "List"));
31875 reader.regions.preview.add(new CP("preview", "Preview"));
31876 reader.endUpdate();
31879 * Create a new ReaderLayout
31880 * @param {Object} config Configuration options
31881 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31882 * document.body if omitted)
31884 Roo.ReaderLayout = function(config, renderTo){
31885 var c = config || {size:{}};
31886 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31887 north: c.north !== false ? Roo.apply({
31891 }, c.north) : false,
31892 west: c.west !== false ? Roo.apply({
31900 margins:{left:5,right:0,bottom:5,top:5},
31901 cmargins:{left:5,right:5,bottom:5,top:5}
31902 }, c.west) : false,
31903 east: c.east !== false ? Roo.apply({
31911 margins:{left:0,right:5,bottom:5,top:5},
31912 cmargins:{left:5,right:5,bottom:5,top:5}
31913 }, c.east) : false,
31914 center: Roo.apply({
31915 tabPosition: 'top',
31919 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31923 this.el.addClass('x-reader');
31925 this.beginUpdate();
31927 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31928 south: c.preview !== false ? Roo.apply({
31935 cmargins:{top:5,left:0, right:0, bottom:0}
31936 }, c.preview) : false,
31937 center: Roo.apply({
31943 this.add('center', new Roo.NestedLayoutPanel(inner,
31944 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31948 this.regions.preview = inner.getRegion('south');
31949 this.regions.listView = inner.getRegion('center');
31952 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31954 * Ext JS Library 1.1.1
31955 * Copyright(c) 2006-2007, Ext JS, LLC.
31957 * Originally Released Under LGPL - original licence link has changed is not relivant.
31960 * <script type="text/javascript">
31964 * @class Roo.grid.Grid
31965 * @extends Roo.util.Observable
31966 * This class represents the primary interface of a component based grid control.
31967 * <br><br>Usage:<pre><code>
31968 var grid = new Roo.grid.Grid("my-container-id", {
31971 selModel: mySelectionModel,
31972 autoSizeColumns: true,
31973 monitorWindowResize: false,
31974 trackMouseOver: true
31979 * <b>Common Problems:</b><br/>
31980 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
31981 * element will correct this<br/>
31982 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
31983 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
31984 * are unpredictable.<br/>
31985 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
31986 * grid to calculate dimensions/offsets.<br/>
31988 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
31989 * The container MUST have some type of size defined for the grid to fill. The container will be
31990 * automatically set to position relative if it isn't already.
31991 * @param {Object} config A config object that sets properties on this grid.
31993 Roo.grid.Grid = function(container, config){
31994 // initialize the container
31995 this.container = Roo.get(container);
31996 this.container.update("");
31997 this.container.setStyle("overflow", "hidden");
31998 this.container.addClass('x-grid-container');
32000 this.id = this.container.id;
32002 Roo.apply(this, config);
32003 // check and correct shorthanded configs
32005 this.dataSource = this.ds;
32009 this.colModel = this.cm;
32013 this.selModel = this.sm;
32017 if (this.selModel) {
32018 this.selModel = Roo.factory(this.selModel, Roo.grid);
32019 this.sm = this.selModel;
32020 this.sm.xmodule = this.xmodule || false;
32022 if (typeof(this.colModel.config) == 'undefined') {
32023 this.colModel = new Roo.grid.ColumnModel(this.colModel);
32024 this.cm = this.colModel;
32025 this.cm.xmodule = this.xmodule || false;
32027 if (this.dataSource) {
32028 this.dataSource= Roo.factory(this.dataSource, Roo.data);
32029 this.ds = this.dataSource;
32030 this.ds.xmodule = this.xmodule || false;
32037 this.container.setWidth(this.width);
32041 this.container.setHeight(this.height);
32048 * The raw click event for the entire grid.
32049 * @param {Roo.EventObject} e
32054 * The raw dblclick event for the entire grid.
32055 * @param {Roo.EventObject} e
32059 * @event contextmenu
32060 * The raw contextmenu event for the entire grid.
32061 * @param {Roo.EventObject} e
32063 "contextmenu" : true,
32066 * The raw mousedown event for the entire grid.
32067 * @param {Roo.EventObject} e
32069 "mousedown" : true,
32072 * The raw mouseup event for the entire grid.
32073 * @param {Roo.EventObject} e
32078 * The raw mouseover event for the entire grid.
32079 * @param {Roo.EventObject} e
32081 "mouseover" : true,
32084 * The raw mouseout event for the entire grid.
32085 * @param {Roo.EventObject} e
32090 * The raw keypress event for the entire grid.
32091 * @param {Roo.EventObject} e
32096 * The raw keydown event for the entire grid.
32097 * @param {Roo.EventObject} e
32105 * Fires when a cell is clicked
32106 * @param {Grid} this
32107 * @param {Number} rowIndex
32108 * @param {Number} columnIndex
32109 * @param {Roo.EventObject} e
32111 "cellclick" : true,
32113 * @event celldblclick
32114 * Fires when a cell is double clicked
32115 * @param {Grid} this
32116 * @param {Number} rowIndex
32117 * @param {Number} columnIndex
32118 * @param {Roo.EventObject} e
32120 "celldblclick" : true,
32123 * Fires when a row is clicked
32124 * @param {Grid} this
32125 * @param {Number} rowIndex
32126 * @param {Roo.EventObject} e
32130 * @event rowdblclick
32131 * Fires when a row is double clicked
32132 * @param {Grid} this
32133 * @param {Number} rowIndex
32134 * @param {Roo.EventObject} e
32136 "rowdblclick" : true,
32138 * @event headerclick
32139 * Fires when a header is clicked
32140 * @param {Grid} this
32141 * @param {Number} columnIndex
32142 * @param {Roo.EventObject} e
32144 "headerclick" : true,
32146 * @event headerdblclick
32147 * Fires when a header cell is double clicked
32148 * @param {Grid} this
32149 * @param {Number} columnIndex
32150 * @param {Roo.EventObject} e
32152 "headerdblclick" : true,
32154 * @event rowcontextmenu
32155 * Fires when a row is right clicked
32156 * @param {Grid} this
32157 * @param {Number} rowIndex
32158 * @param {Roo.EventObject} e
32160 "rowcontextmenu" : true,
32162 * @event cellcontextmenu
32163 * Fires when a cell is right clicked
32164 * @param {Grid} this
32165 * @param {Number} rowIndex
32166 * @param {Number} cellIndex
32167 * @param {Roo.EventObject} e
32169 "cellcontextmenu" : true,
32171 * @event headercontextmenu
32172 * Fires when a header is right clicked
32173 * @param {Grid} this
32174 * @param {Number} columnIndex
32175 * @param {Roo.EventObject} e
32177 "headercontextmenu" : true,
32179 * @event bodyscroll
32180 * Fires when the body element is scrolled
32181 * @param {Number} scrollLeft
32182 * @param {Number} scrollTop
32184 "bodyscroll" : true,
32186 * @event columnresize
32187 * Fires when the user resizes a column
32188 * @param {Number} columnIndex
32189 * @param {Number} newSize
32191 "columnresize" : true,
32193 * @event columnmove
32194 * Fires when the user moves a column
32195 * @param {Number} oldIndex
32196 * @param {Number} newIndex
32198 "columnmove" : true,
32201 * Fires when row(s) start being dragged
32202 * @param {Grid} this
32203 * @param {Roo.GridDD} dd The drag drop object
32204 * @param {event} e The raw browser event
32206 "startdrag" : true,
32209 * Fires when a drag operation is complete
32210 * @param {Grid} this
32211 * @param {Roo.GridDD} dd The drag drop object
32212 * @param {event} e The raw browser event
32217 * Fires when dragged row(s) are dropped on a valid DD target
32218 * @param {Grid} this
32219 * @param {Roo.GridDD} dd The drag drop object
32220 * @param {String} targetId The target drag drop object
32221 * @param {event} e The raw browser event
32226 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
32227 * @param {Grid} this
32228 * @param {Roo.GridDD} dd The drag drop object
32229 * @param {String} targetId The target drag drop object
32230 * @param {event} e The raw browser event
32235 * Fires when the dragged row(s) first cross another DD target while being dragged
32236 * @param {Grid} this
32237 * @param {Roo.GridDD} dd The drag drop object
32238 * @param {String} targetId The target drag drop object
32239 * @param {event} e The raw browser event
32241 "dragenter" : true,
32244 * Fires when the dragged row(s) leave another DD target while being dragged
32245 * @param {Grid} this
32246 * @param {Roo.GridDD} dd The drag drop object
32247 * @param {String} targetId The target drag drop object
32248 * @param {event} e The raw browser event
32253 * Fires when a row is rendered, so you can change add a style to it.
32254 * @param {GridView} gridview The grid view
32255 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
32261 * Fires when the grid is rendered
32262 * @param {Grid} grid
32267 Roo.grid.Grid.superclass.constructor.call(this);
32269 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32272 * @cfg {String} ddGroup - drag drop group.
32276 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32278 minColumnWidth : 25,
32281 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32282 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32283 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32285 autoSizeColumns : false,
32288 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32290 autoSizeHeaders : true,
32293 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32295 monitorWindowResize : true,
32298 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32299 * rows measured to get a columns size. Default is 0 (all rows).
32301 maxRowsToMeasure : 0,
32304 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32306 trackMouseOver : true,
32309 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32313 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32315 enableDragDrop : false,
32318 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32320 enableColumnMove : true,
32323 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32325 enableColumnHide : true,
32328 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32330 enableRowHeightSync : false,
32333 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32338 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32340 autoHeight : false,
32343 * @cfg {String} autoExpandColumn The id (or dataIndex) of a column in this grid that should expand to fill unused space. This id can not be 0. Default is false.
32345 autoExpandColumn : false,
32348 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32351 autoExpandMin : 50,
32354 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32356 autoExpandMax : 1000,
32359 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32364 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32368 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
32378 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32379 * of a fixed width. Default is false.
32382 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32385 * Called once after all setup has been completed and the grid is ready to be rendered.
32386 * @return {Roo.grid.Grid} this
32388 render : function()
32390 var c = this.container;
32391 // try to detect autoHeight/width mode
32392 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32393 this.autoHeight = true;
32395 var view = this.getView();
32398 c.on("click", this.onClick, this);
32399 c.on("dblclick", this.onDblClick, this);
32400 c.on("contextmenu", this.onContextMenu, this);
32401 c.on("keydown", this.onKeyDown, this);
32403 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32405 this.getSelectionModel().init(this);
32410 this.loadMask = new Roo.LoadMask(this.container,
32411 Roo.apply({store:this.dataSource}, this.loadMask));
32415 if (this.toolbar && this.toolbar.xtype) {
32416 this.toolbar.container = this.getView().getHeaderPanel(true);
32417 this.toolbar = new Roo.Toolbar(this.toolbar);
32419 if (this.footer && this.footer.xtype) {
32420 this.footer.dataSource = this.getDataSource();
32421 this.footer.container = this.getView().getFooterPanel(true);
32422 this.footer = Roo.factory(this.footer, Roo);
32424 if (this.dropTarget && this.dropTarget.xtype) {
32425 delete this.dropTarget.xtype;
32426 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
32430 this.rendered = true;
32431 this.fireEvent('render', this);
32436 * Reconfigures the grid to use a different Store and Column Model.
32437 * The View will be bound to the new objects and refreshed.
32438 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32439 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32441 reconfigure : function(dataSource, colModel){
32443 this.loadMask.destroy();
32444 this.loadMask = new Roo.LoadMask(this.container,
32445 Roo.apply({store:dataSource}, this.loadMask));
32447 this.view.bind(dataSource, colModel);
32448 this.dataSource = dataSource;
32449 this.colModel = colModel;
32450 this.view.refresh(true);
32454 onKeyDown : function(e){
32455 this.fireEvent("keydown", e);
32459 * Destroy this grid.
32460 * @param {Boolean} removeEl True to remove the element
32462 destroy : function(removeEl, keepListeners){
32464 this.loadMask.destroy();
32466 var c = this.container;
32467 c.removeAllListeners();
32468 this.view.destroy();
32469 this.colModel.purgeListeners();
32470 if(!keepListeners){
32471 this.purgeListeners();
32474 if(removeEl === true){
32480 processEvent : function(name, e){
32481 this.fireEvent(name, e);
32482 var t = e.getTarget();
32484 var header = v.findHeaderIndex(t);
32485 if(header !== false){
32486 this.fireEvent("header" + name, this, header, e);
32488 var row = v.findRowIndex(t);
32489 var cell = v.findCellIndex(t);
32491 this.fireEvent("row" + name, this, row, e);
32492 if(cell !== false){
32493 this.fireEvent("cell" + name, this, row, cell, e);
32500 onClick : function(e){
32501 this.processEvent("click", e);
32505 onContextMenu : function(e, t){
32506 this.processEvent("contextmenu", e);
32510 onDblClick : function(e){
32511 this.processEvent("dblclick", e);
32515 walkCells : function(row, col, step, fn, scope){
32516 var cm = this.colModel, clen = cm.getColumnCount();
32517 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32529 if(fn.call(scope || this, row, col, cm) === true){
32547 if(fn.call(scope || this, row, col, cm) === true){
32559 getSelections : function(){
32560 return this.selModel.getSelections();
32564 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32565 * but if manual update is required this method will initiate it.
32567 autoSize : function(){
32569 this.view.layout();
32570 if(this.view.adjustForScroll){
32571 this.view.adjustForScroll();
32577 * Returns the grid's underlying element.
32578 * @return {Element} The element
32580 getGridEl : function(){
32581 return this.container;
32584 // private for compatibility, overridden by editor grid
32585 stopEditing : function(){},
32588 * Returns the grid's SelectionModel.
32589 * @return {SelectionModel}
32591 getSelectionModel : function(){
32592 if(!this.selModel){
32593 this.selModel = new Roo.grid.RowSelectionModel();
32595 return this.selModel;
32599 * Returns the grid's DataSource.
32600 * @return {DataSource}
32602 getDataSource : function(){
32603 return this.dataSource;
32607 * Returns the grid's ColumnModel.
32608 * @return {ColumnModel}
32610 getColumnModel : function(){
32611 return this.colModel;
32615 * Returns the grid's GridView object.
32616 * @return {GridView}
32618 getView : function(){
32620 this.view = new Roo.grid.GridView(this.viewConfig);
32625 * Called to get grid's drag proxy text, by default returns this.ddText.
32628 getDragDropText : function(){
32629 var count = this.selModel.getCount();
32630 return String.format(this.ddText, count, count == 1 ? '' : 's');
32634 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32635 * %0 is replaced with the number of selected rows.
32638 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32640 * Ext JS Library 1.1.1
32641 * Copyright(c) 2006-2007, Ext JS, LLC.
32643 * Originally Released Under LGPL - original licence link has changed is not relivant.
32646 * <script type="text/javascript">
32649 Roo.grid.AbstractGridView = function(){
32653 "beforerowremoved" : true,
32654 "beforerowsinserted" : true,
32655 "beforerefresh" : true,
32656 "rowremoved" : true,
32657 "rowsinserted" : true,
32658 "rowupdated" : true,
32661 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32664 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32665 rowClass : "x-grid-row",
32666 cellClass : "x-grid-cell",
32667 tdClass : "x-grid-td",
32668 hdClass : "x-grid-hd",
32669 splitClass : "x-grid-hd-split",
32671 init: function(grid){
32673 var cid = this.grid.getGridEl().id;
32674 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32675 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32676 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32677 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32680 getColumnRenderers : function(){
32681 var renderers = [];
32682 var cm = this.grid.colModel;
32683 var colCount = cm.getColumnCount();
32684 for(var i = 0; i < colCount; i++){
32685 renderers[i] = cm.getRenderer(i);
32690 getColumnIds : function(){
32692 var cm = this.grid.colModel;
32693 var colCount = cm.getColumnCount();
32694 for(var i = 0; i < colCount; i++){
32695 ids[i] = cm.getColumnId(i);
32700 getDataIndexes : function(){
32701 if(!this.indexMap){
32702 this.indexMap = this.buildIndexMap();
32704 return this.indexMap.colToData;
32707 getColumnIndexByDataIndex : function(dataIndex){
32708 if(!this.indexMap){
32709 this.indexMap = this.buildIndexMap();
32711 return this.indexMap.dataToCol[dataIndex];
32715 * Set a css style for a column dynamically.
32716 * @param {Number} colIndex The index of the column
32717 * @param {String} name The css property name
32718 * @param {String} value The css value
32720 setCSSStyle : function(colIndex, name, value){
32721 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32722 Roo.util.CSS.updateRule(selector, name, value);
32725 generateRules : function(cm){
32726 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32727 Roo.util.CSS.removeStyleSheet(rulesId);
32728 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32729 var cid = cm.getColumnId(i);
32730 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32731 this.tdSelector, cid, " {\n}\n",
32732 this.hdSelector, cid, " {\n}\n",
32733 this.splitSelector, cid, " {\n}\n");
32735 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32739 * Ext JS Library 1.1.1
32740 * Copyright(c) 2006-2007, Ext JS, LLC.
32742 * Originally Released Under LGPL - original licence link has changed is not relivant.
32745 * <script type="text/javascript">
32749 // This is a support class used internally by the Grid components
32750 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32752 this.view = grid.getView();
32753 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32754 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32756 this.setHandleElId(Roo.id(hd));
32757 this.setOuterHandleElId(Roo.id(hd2));
32759 this.scroll = false;
32761 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32763 getDragData : function(e){
32764 var t = Roo.lib.Event.getTarget(e);
32765 var h = this.view.findHeaderCell(t);
32767 return {ddel: h.firstChild, header:h};
32772 onInitDrag : function(e){
32773 this.view.headersDisabled = true;
32774 var clone = this.dragData.ddel.cloneNode(true);
32775 clone.id = Roo.id();
32776 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32777 this.proxy.update(clone);
32781 afterValidDrop : function(){
32783 setTimeout(function(){
32784 v.headersDisabled = false;
32788 afterInvalidDrop : function(){
32790 setTimeout(function(){
32791 v.headersDisabled = false;
32797 * Ext JS Library 1.1.1
32798 * Copyright(c) 2006-2007, Ext JS, LLC.
32800 * Originally Released Under LGPL - original licence link has changed is not relivant.
32803 * <script type="text/javascript">
32806 // This is a support class used internally by the Grid components
32807 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32809 this.view = grid.getView();
32810 // split the proxies so they don't interfere with mouse events
32811 this.proxyTop = Roo.DomHelper.append(document.body, {
32812 cls:"col-move-top", html:" "
32814 this.proxyBottom = Roo.DomHelper.append(document.body, {
32815 cls:"col-move-bottom", html:" "
32817 this.proxyTop.hide = this.proxyBottom.hide = function(){
32818 this.setLeftTop(-100,-100);
32819 this.setStyle("visibility", "hidden");
32821 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32822 // temporarily disabled
32823 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32824 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32826 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32827 proxyOffsets : [-4, -9],
32828 fly: Roo.Element.fly,
32830 getTargetFromEvent : function(e){
32831 var t = Roo.lib.Event.getTarget(e);
32832 var cindex = this.view.findCellIndex(t);
32833 if(cindex !== false){
32834 return this.view.getHeaderCell(cindex);
32839 nextVisible : function(h){
32840 var v = this.view, cm = this.grid.colModel;
32843 if(!cm.isHidden(v.getCellIndex(h))){
32851 prevVisible : function(h){
32852 var v = this.view, cm = this.grid.colModel;
32855 if(!cm.isHidden(v.getCellIndex(h))){
32863 positionIndicator : function(h, n, e){
32864 var x = Roo.lib.Event.getPageX(e);
32865 var r = Roo.lib.Dom.getRegion(n.firstChild);
32866 var px, pt, py = r.top + this.proxyOffsets[1];
32867 if((r.right - x) <= (r.right-r.left)/2){
32868 px = r.right+this.view.borderWidth;
32874 var oldIndex = this.view.getCellIndex(h);
32875 var newIndex = this.view.getCellIndex(n);
32877 if(this.grid.colModel.isFixed(newIndex)){
32881 var locked = this.grid.colModel.isLocked(newIndex);
32886 if(oldIndex < newIndex){
32889 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32892 px += this.proxyOffsets[0];
32893 this.proxyTop.setLeftTop(px, py);
32894 this.proxyTop.show();
32895 if(!this.bottomOffset){
32896 this.bottomOffset = this.view.mainHd.getHeight();
32898 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32899 this.proxyBottom.show();
32903 onNodeEnter : function(n, dd, e, data){
32904 if(data.header != n){
32905 this.positionIndicator(data.header, n, e);
32909 onNodeOver : function(n, dd, e, data){
32910 var result = false;
32911 if(data.header != n){
32912 result = this.positionIndicator(data.header, n, e);
32915 this.proxyTop.hide();
32916 this.proxyBottom.hide();
32918 return result ? this.dropAllowed : this.dropNotAllowed;
32921 onNodeOut : function(n, dd, e, data){
32922 this.proxyTop.hide();
32923 this.proxyBottom.hide();
32926 onNodeDrop : function(n, dd, e, data){
32927 var h = data.header;
32929 var cm = this.grid.colModel;
32930 var x = Roo.lib.Event.getPageX(e);
32931 var r = Roo.lib.Dom.getRegion(n.firstChild);
32932 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32933 var oldIndex = this.view.getCellIndex(h);
32934 var newIndex = this.view.getCellIndex(n);
32935 var locked = cm.isLocked(newIndex);
32939 if(oldIndex < newIndex){
32942 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32945 cm.setLocked(oldIndex, locked, true);
32946 cm.moveColumn(oldIndex, newIndex);
32947 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32955 * Ext JS Library 1.1.1
32956 * Copyright(c) 2006-2007, Ext JS, LLC.
32958 * Originally Released Under LGPL - original licence link has changed is not relivant.
32961 * <script type="text/javascript">
32965 * @class Roo.grid.GridView
32966 * @extends Roo.util.Observable
32969 * @param {Object} config
32971 Roo.grid.GridView = function(config){
32972 Roo.grid.GridView.superclass.constructor.call(this);
32975 Roo.apply(this, config);
32978 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
32981 * Override this function to apply custom css classes to rows during rendering
32982 * @param {Record} record The record
32983 * @param {Number} index
32984 * @method getRowClass
32986 rowClass : "x-grid-row",
32988 cellClass : "x-grid-col",
32990 tdClass : "x-grid-td",
32992 hdClass : "x-grid-hd",
32994 splitClass : "x-grid-split",
32996 sortClasses : ["sort-asc", "sort-desc"],
32998 enableMoveAnim : false,
33002 dh : Roo.DomHelper,
33004 fly : Roo.Element.fly,
33006 css : Roo.util.CSS,
33012 scrollIncrement : 22,
33014 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
33016 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
33018 bind : function(ds, cm){
33020 this.ds.un("load", this.onLoad, this);
33021 this.ds.un("datachanged", this.onDataChange, this);
33022 this.ds.un("add", this.onAdd, this);
33023 this.ds.un("remove", this.onRemove, this);
33024 this.ds.un("update", this.onUpdate, this);
33025 this.ds.un("clear", this.onClear, this);
33028 ds.on("load", this.onLoad, this);
33029 ds.on("datachanged", this.onDataChange, this);
33030 ds.on("add", this.onAdd, this);
33031 ds.on("remove", this.onRemove, this);
33032 ds.on("update", this.onUpdate, this);
33033 ds.on("clear", this.onClear, this);
33038 this.cm.un("widthchange", this.onColWidthChange, this);
33039 this.cm.un("headerchange", this.onHeaderChange, this);
33040 this.cm.un("hiddenchange", this.onHiddenChange, this);
33041 this.cm.un("columnmoved", this.onColumnMove, this);
33042 this.cm.un("columnlockchange", this.onColumnLock, this);
33045 this.generateRules(cm);
33046 cm.on("widthchange", this.onColWidthChange, this);
33047 cm.on("headerchange", this.onHeaderChange, this);
33048 cm.on("hiddenchange", this.onHiddenChange, this);
33049 cm.on("columnmoved", this.onColumnMove, this);
33050 cm.on("columnlockchange", this.onColumnLock, this);
33055 init: function(grid){
33056 Roo.grid.GridView.superclass.init.call(this, grid);
33058 this.bind(grid.dataSource, grid.colModel);
33060 grid.on("headerclick", this.handleHeaderClick, this);
33062 if(grid.trackMouseOver){
33063 grid.on("mouseover", this.onRowOver, this);
33064 grid.on("mouseout", this.onRowOut, this);
33066 grid.cancelTextSelection = function(){};
33067 this.gridId = grid.id;
33069 var tpls = this.templates || {};
33072 tpls.master = new Roo.Template(
33073 '<div class="x-grid" hidefocus="true">',
33074 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
33075 '<div class="x-grid-topbar"></div>',
33076 '<div class="x-grid-scroller"><div></div></div>',
33077 '<div class="x-grid-locked">',
33078 '<div class="x-grid-header">{lockedHeader}</div>',
33079 '<div class="x-grid-body">{lockedBody}</div>',
33081 '<div class="x-grid-viewport">',
33082 '<div class="x-grid-header">{header}</div>',
33083 '<div class="x-grid-body">{body}</div>',
33085 '<div class="x-grid-bottombar"></div>',
33087 '<div class="x-grid-resize-proxy"> </div>',
33090 tpls.master.disableformats = true;
33094 tpls.header = new Roo.Template(
33095 '<table border="0" cellspacing="0" cellpadding="0">',
33096 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
33099 tpls.header.disableformats = true;
33101 tpls.header.compile();
33104 tpls.hcell = new Roo.Template(
33105 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
33106 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
33109 tpls.hcell.disableFormats = true;
33111 tpls.hcell.compile();
33114 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
33115 tpls.hsplit.disableFormats = true;
33117 tpls.hsplit.compile();
33120 tpls.body = new Roo.Template(
33121 '<table border="0" cellspacing="0" cellpadding="0">',
33122 "<tbody>{rows}</tbody>",
33125 tpls.body.disableFormats = true;
33127 tpls.body.compile();
33130 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
33131 tpls.row.disableFormats = true;
33133 tpls.row.compile();
33136 tpls.cell = new Roo.Template(
33137 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
33138 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
33141 tpls.cell.disableFormats = true;
33143 tpls.cell.compile();
33145 this.templates = tpls;
33148 // remap these for backwards compat
33149 onColWidthChange : function(){
33150 this.updateColumns.apply(this, arguments);
33152 onHeaderChange : function(){
33153 this.updateHeaders.apply(this, arguments);
33155 onHiddenChange : function(){
33156 this.handleHiddenChange.apply(this, arguments);
33158 onColumnMove : function(){
33159 this.handleColumnMove.apply(this, arguments);
33161 onColumnLock : function(){
33162 this.handleLockChange.apply(this, arguments);
33165 onDataChange : function(){
33167 this.updateHeaderSortState();
33170 onClear : function(){
33174 onUpdate : function(ds, record){
33175 this.refreshRow(record);
33178 refreshRow : function(record){
33179 var ds = this.ds, index;
33180 if(typeof record == 'number'){
33182 record = ds.getAt(index);
33184 index = ds.indexOf(record);
33186 this.insertRows(ds, index, index, true);
33187 this.onRemove(ds, record, index+1, true);
33188 this.syncRowHeights(index, index);
33190 this.fireEvent("rowupdated", this, index, record);
33193 onAdd : function(ds, records, index){
33194 this.insertRows(ds, index, index + (records.length-1));
33197 onRemove : function(ds, record, index, isUpdate){
33198 if(isUpdate !== true){
33199 this.fireEvent("beforerowremoved", this, index, record);
33201 var bt = this.getBodyTable(), lt = this.getLockedTable();
33202 if(bt.rows[index]){
33203 bt.firstChild.removeChild(bt.rows[index]);
33205 if(lt.rows[index]){
33206 lt.firstChild.removeChild(lt.rows[index]);
33208 if(isUpdate !== true){
33209 this.stripeRows(index);
33210 this.syncRowHeights(index, index);
33212 this.fireEvent("rowremoved", this, index, record);
33216 onLoad : function(){
33217 this.scrollToTop();
33221 * Scrolls the grid to the top
33223 scrollToTop : function(){
33225 this.scroller.dom.scrollTop = 0;
33231 * Gets a panel in the header of the grid that can be used for toolbars etc.
33232 * After modifying the contents of this panel a call to grid.autoSize() may be
33233 * required to register any changes in size.
33234 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
33235 * @return Roo.Element
33237 getHeaderPanel : function(doShow){
33239 this.headerPanel.show();
33241 return this.headerPanel;
33245 * Gets a panel in the footer of the grid that can be used for toolbars etc.
33246 * After modifying the contents of this panel a call to grid.autoSize() may be
33247 * required to register any changes in size.
33248 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
33249 * @return Roo.Element
33251 getFooterPanel : function(doShow){
33253 this.footerPanel.show();
33255 return this.footerPanel;
33258 initElements : function(){
33259 var E = Roo.Element;
33260 var el = this.grid.getGridEl().dom.firstChild;
33261 var cs = el.childNodes;
33263 this.el = new E(el);
33265 this.focusEl = new E(el.firstChild);
33266 this.focusEl.swallowEvent("click", true);
33268 this.headerPanel = new E(cs[1]);
33269 this.headerPanel.enableDisplayMode("block");
33271 this.scroller = new E(cs[2]);
33272 this.scrollSizer = new E(this.scroller.dom.firstChild);
33274 this.lockedWrap = new E(cs[3]);
33275 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33276 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33278 this.mainWrap = new E(cs[4]);
33279 this.mainHd = new E(this.mainWrap.dom.firstChild);
33280 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33282 this.footerPanel = new E(cs[5]);
33283 this.footerPanel.enableDisplayMode("block");
33285 this.resizeProxy = new E(cs[6]);
33287 this.headerSelector = String.format(
33288 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33289 this.lockedHd.id, this.mainHd.id
33292 this.splitterSelector = String.format(
33293 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33294 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33297 idToCssName : function(s)
33299 return s.replace(/[^a-z0-9]+/ig, '-');
33302 getHeaderCell : function(index){
33303 return Roo.DomQuery.select(this.headerSelector)[index];
33306 getHeaderCellMeasure : function(index){
33307 return this.getHeaderCell(index).firstChild;
33310 getHeaderCellText : function(index){
33311 return this.getHeaderCell(index).firstChild.firstChild;
33314 getLockedTable : function(){
33315 return this.lockedBody.dom.firstChild;
33318 getBodyTable : function(){
33319 return this.mainBody.dom.firstChild;
33322 getLockedRow : function(index){
33323 return this.getLockedTable().rows[index];
33326 getRow : function(index){
33327 return this.getBodyTable().rows[index];
33330 getRowComposite : function(index){
33332 this.rowEl = new Roo.CompositeElementLite();
33334 var els = [], lrow, mrow;
33335 if(lrow = this.getLockedRow(index)){
33338 if(mrow = this.getRow(index)){
33341 this.rowEl.elements = els;
33345 getCell : function(rowIndex, colIndex){
33346 var locked = this.cm.getLockedCount();
33348 if(colIndex < locked){
33349 source = this.lockedBody.dom.firstChild;
33351 source = this.mainBody.dom.firstChild;
33352 colIndex -= locked;
33354 return source.rows[rowIndex].childNodes[colIndex];
33357 getCellText : function(rowIndex, colIndex){
33358 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33361 getCellBox : function(cell){
33362 var b = this.fly(cell).getBox();
33363 if(Roo.isOpera){ // opera fails to report the Y
33364 b.y = cell.offsetTop + this.mainBody.getY();
33369 getCellIndex : function(cell){
33370 var id = String(cell.className).match(this.cellRE);
33372 return parseInt(id[1], 10);
33377 findHeaderIndex : function(n){
33378 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33379 return r ? this.getCellIndex(r) : false;
33382 findHeaderCell : function(n){
33383 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33384 return r ? r : false;
33387 findRowIndex : function(n){
33391 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33392 return r ? r.rowIndex : false;
33395 findCellIndex : function(node){
33396 var stop = this.el.dom;
33397 while(node && node != stop){
33398 if(this.findRE.test(node.className)){
33399 return this.getCellIndex(node);
33401 node = node.parentNode;
33406 getColumnId : function(index){
33407 return this.cm.getColumnId(index);
33410 getSplitters : function()
33412 if(this.splitterSelector){
33413 return Roo.DomQuery.select(this.splitterSelector);
33419 getSplitter : function(index){
33420 return this.getSplitters()[index];
33423 onRowOver : function(e, t){
33425 if((row = this.findRowIndex(t)) !== false){
33426 this.getRowComposite(row).addClass("x-grid-row-over");
33430 onRowOut : function(e, t){
33432 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33433 this.getRowComposite(row).removeClass("x-grid-row-over");
33437 renderHeaders : function(){
33439 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33440 var cb = [], lb = [], sb = [], lsb = [], p = {};
33441 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33442 p.cellId = "x-grid-hd-0-" + i;
33443 p.splitId = "x-grid-csplit-0-" + i;
33444 p.id = cm.getColumnId(i);
33445 p.title = cm.getColumnTooltip(i) || "";
33446 p.value = cm.getColumnHeader(i) || "";
33447 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33448 if(!cm.isLocked(i)){
33449 cb[cb.length] = ct.apply(p);
33450 sb[sb.length] = st.apply(p);
33452 lb[lb.length] = ct.apply(p);
33453 lsb[lsb.length] = st.apply(p);
33456 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33457 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33460 updateHeaders : function(){
33461 var html = this.renderHeaders();
33462 this.lockedHd.update(html[0]);
33463 this.mainHd.update(html[1]);
33467 * Focuses the specified row.
33468 * @param {Number} row The row index
33470 focusRow : function(row)
33472 //Roo.log('GridView.focusRow');
33473 var x = this.scroller.dom.scrollLeft;
33474 this.focusCell(row, 0, false);
33475 this.scroller.dom.scrollLeft = x;
33479 * Focuses the specified cell.
33480 * @param {Number} row The row index
33481 * @param {Number} col The column index
33482 * @param {Boolean} hscroll false to disable horizontal scrolling
33484 focusCell : function(row, col, hscroll)
33486 //Roo.log('GridView.focusCell');
33487 var el = this.ensureVisible(row, col, hscroll);
33488 this.focusEl.alignTo(el, "tl-tl");
33490 this.focusEl.focus();
33492 this.focusEl.focus.defer(1, this.focusEl);
33497 * Scrolls the specified cell into view
33498 * @param {Number} row The row index
33499 * @param {Number} col The column index
33500 * @param {Boolean} hscroll false to disable horizontal scrolling
33502 ensureVisible : function(row, col, hscroll)
33504 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
33505 //return null; //disable for testing.
33506 if(typeof row != "number"){
33507 row = row.rowIndex;
33509 if(row < 0 && row >= this.ds.getCount()){
33512 col = (col !== undefined ? col : 0);
33513 var cm = this.grid.colModel;
33514 while(cm.isHidden(col)){
33518 var el = this.getCell(row, col);
33522 var c = this.scroller.dom;
33524 var ctop = parseInt(el.offsetTop, 10);
33525 var cleft = parseInt(el.offsetLeft, 10);
33526 var cbot = ctop + el.offsetHeight;
33527 var cright = cleft + el.offsetWidth;
33529 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33530 var stop = parseInt(c.scrollTop, 10);
33531 var sleft = parseInt(c.scrollLeft, 10);
33532 var sbot = stop + ch;
33533 var sright = sleft + c.clientWidth;
33535 Roo.log('GridView.ensureVisible:' +
33537 ' c.clientHeight:' + c.clientHeight +
33538 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
33546 c.scrollTop = ctop;
33547 //Roo.log("set scrolltop to ctop DISABLE?");
33548 }else if(cbot > sbot){
33549 //Roo.log("set scrolltop to cbot-ch");
33550 c.scrollTop = cbot-ch;
33553 if(hscroll !== false){
33555 c.scrollLeft = cleft;
33556 }else if(cright > sright){
33557 c.scrollLeft = cright-c.clientWidth;
33564 updateColumns : function(){
33565 this.grid.stopEditing();
33566 var cm = this.grid.colModel, colIds = this.getColumnIds();
33567 //var totalWidth = cm.getTotalWidth();
33569 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33570 //if(cm.isHidden(i)) continue;
33571 var w = cm.getColumnWidth(i);
33572 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33573 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33575 this.updateSplitters();
33578 generateRules : function(cm){
33579 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33580 Roo.util.CSS.removeStyleSheet(rulesId);
33581 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33582 var cid = cm.getColumnId(i);
33584 if(cm.config[i].align){
33585 align = 'text-align:'+cm.config[i].align+';';
33588 if(cm.isHidden(i)){
33589 hidden = 'display:none;';
33591 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33593 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33594 this.hdSelector, cid, " {\n", align, width, "}\n",
33595 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33596 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33598 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33601 updateSplitters : function(){
33602 var cm = this.cm, s = this.getSplitters();
33603 if(s){ // splitters not created yet
33604 var pos = 0, locked = true;
33605 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33606 if(cm.isHidden(i)) continue;
33607 var w = cm.getColumnWidth(i); // make sure it's a number
33608 if(!cm.isLocked(i) && locked){
33613 s[i].style.left = (pos-this.splitOffset) + "px";
33618 handleHiddenChange : function(colModel, colIndex, hidden){
33620 this.hideColumn(colIndex);
33622 this.unhideColumn(colIndex);
33626 hideColumn : function(colIndex){
33627 var cid = this.getColumnId(colIndex);
33628 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33629 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33631 this.updateHeaders();
33633 this.updateSplitters();
33637 unhideColumn : function(colIndex){
33638 var cid = this.getColumnId(colIndex);
33639 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33640 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33643 this.updateHeaders();
33645 this.updateSplitters();
33649 insertRows : function(dm, firstRow, lastRow, isUpdate){
33650 if(firstRow == 0 && lastRow == dm.getCount()-1){
33654 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33656 var s = this.getScrollState();
33657 var markup = this.renderRows(firstRow, lastRow);
33658 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33659 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33660 this.restoreScroll(s);
33662 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33663 this.syncRowHeights(firstRow, lastRow);
33664 this.stripeRows(firstRow);
33670 bufferRows : function(markup, target, index){
33671 var before = null, trows = target.rows, tbody = target.tBodies[0];
33672 if(index < trows.length){
33673 before = trows[index];
33675 var b = document.createElement("div");
33676 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33677 var rows = b.firstChild.rows;
33678 for(var i = 0, len = rows.length; i < len; i++){
33680 tbody.insertBefore(rows[0], before);
33682 tbody.appendChild(rows[0]);
33689 deleteRows : function(dm, firstRow, lastRow){
33690 if(dm.getRowCount()<1){
33691 this.fireEvent("beforerefresh", this);
33692 this.mainBody.update("");
33693 this.lockedBody.update("");
33694 this.fireEvent("refresh", this);
33696 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33697 var bt = this.getBodyTable();
33698 var tbody = bt.firstChild;
33699 var rows = bt.rows;
33700 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33701 tbody.removeChild(rows[firstRow]);
33703 this.stripeRows(firstRow);
33704 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33708 updateRows : function(dataSource, firstRow, lastRow){
33709 var s = this.getScrollState();
33711 this.restoreScroll(s);
33714 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33718 this.updateHeaderSortState();
33721 getScrollState : function(){
33723 var sb = this.scroller.dom;
33724 return {left: sb.scrollLeft, top: sb.scrollTop};
33727 stripeRows : function(startRow){
33728 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33731 startRow = startRow || 0;
33732 var rows = this.getBodyTable().rows;
33733 var lrows = this.getLockedTable().rows;
33734 var cls = ' x-grid-row-alt ';
33735 for(var i = startRow, len = rows.length; i < len; i++){
33736 var row = rows[i], lrow = lrows[i];
33737 var isAlt = ((i+1) % 2 == 0);
33738 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33739 if(isAlt == hasAlt){
33743 row.className += " x-grid-row-alt";
33745 row.className = row.className.replace("x-grid-row-alt", "");
33748 lrow.className = row.className;
33753 restoreScroll : function(state){
33754 //Roo.log('GridView.restoreScroll');
33755 var sb = this.scroller.dom;
33756 sb.scrollLeft = state.left;
33757 sb.scrollTop = state.top;
33761 syncScroll : function(){
33762 //Roo.log('GridView.syncScroll');
33763 var sb = this.scroller.dom;
33764 var sh = this.mainHd.dom;
33765 var bs = this.mainBody.dom;
33766 var lv = this.lockedBody.dom;
33767 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33768 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33771 handleScroll : function(e){
33773 var sb = this.scroller.dom;
33774 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33778 handleWheel : function(e){
33779 var d = e.getWheelDelta();
33780 this.scroller.dom.scrollTop -= d*22;
33781 // set this here to prevent jumpy scrolling on large tables
33782 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33786 renderRows : function(startRow, endRow){
33787 // pull in all the crap needed to render rows
33788 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33789 var colCount = cm.getColumnCount();
33791 if(ds.getCount() < 1){
33795 // build a map for all the columns
33797 for(var i = 0; i < colCount; i++){
33798 var name = cm.getDataIndex(i);
33800 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33801 renderer : cm.getRenderer(i),
33802 id : cm.getColumnId(i),
33803 locked : cm.isLocked(i)
33807 startRow = startRow || 0;
33808 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33810 // records to render
33811 var rs = ds.getRange(startRow, endRow);
33813 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33816 // As much as I hate to duplicate code, this was branched because FireFox really hates
33817 // [].join("") on strings. The performance difference was substantial enough to
33818 // branch this function
33819 doRender : Roo.isGecko ?
33820 function(cs, rs, ds, startRow, colCount, stripe){
33821 var ts = this.templates, ct = ts.cell, rt = ts.row;
33823 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33825 var hasListener = this.grid.hasListener('rowclass');
33827 for(var j = 0, len = rs.length; j < len; j++){
33828 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33829 for(var i = 0; i < colCount; i++){
33831 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33833 p.css = p.attr = "";
33834 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33835 if(p.value == undefined || p.value === "") p.value = " ";
33836 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33837 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33839 var markup = ct.apply(p);
33847 if(stripe && ((rowIndex+1) % 2 == 0)){
33848 alt.push("x-grid-row-alt")
33851 alt.push( " x-grid-dirty-row");
33854 if(this.getRowClass){
33855 alt.push(this.getRowClass(r, rowIndex));
33861 rowIndex : rowIndex,
33864 this.grid.fireEvent('rowclass', this, rowcfg);
33865 alt.push(rowcfg.rowClass);
33867 rp.alt = alt.join(" ");
33868 lbuf+= rt.apply(rp);
33870 buf+= rt.apply(rp);
33872 return [lbuf, buf];
33874 function(cs, rs, ds, startRow, colCount, stripe){
33875 var ts = this.templates, ct = ts.cell, rt = ts.row;
33877 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33878 var hasListener = this.grid.hasListener('rowclass');
33880 for(var j = 0, len = rs.length; j < len; j++){
33881 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33882 for(var i = 0; i < colCount; i++){
33884 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33886 p.css = p.attr = "";
33887 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33888 if(p.value == undefined || p.value === "") p.value = " ";
33889 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33890 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33892 var markup = ct.apply(p);
33894 cb[cb.length] = markup;
33896 lcb[lcb.length] = markup;
33900 if(stripe && ((rowIndex+1) % 2 == 0)){
33901 alt.push( "x-grid-row-alt");
33904 alt.push(" x-grid-dirty-row");
33907 if(this.getRowClass){
33908 alt.push( this.getRowClass(r, rowIndex));
33914 rowIndex : rowIndex,
33917 this.grid.fireEvent('rowclass', this, rowcfg);
33918 alt.push(rowcfg.rowClass);
33920 rp.alt = alt.join(" ");
33921 rp.cells = lcb.join("");
33922 lbuf[lbuf.length] = rt.apply(rp);
33923 rp.cells = cb.join("");
33924 buf[buf.length] = rt.apply(rp);
33926 return [lbuf.join(""), buf.join("")];
33929 renderBody : function(){
33930 var markup = this.renderRows();
33931 var bt = this.templates.body;
33932 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33936 * Refreshes the grid
33937 * @param {Boolean} headersToo
33939 refresh : function(headersToo){
33940 this.fireEvent("beforerefresh", this);
33941 this.grid.stopEditing();
33942 var result = this.renderBody();
33943 this.lockedBody.update(result[0]);
33944 this.mainBody.update(result[1]);
33945 if(headersToo === true){
33946 this.updateHeaders();
33947 this.updateColumns();
33948 this.updateSplitters();
33949 this.updateHeaderSortState();
33951 this.syncRowHeights();
33953 this.fireEvent("refresh", this);
33956 handleColumnMove : function(cm, oldIndex, newIndex){
33957 this.indexMap = null;
33958 var s = this.getScrollState();
33959 this.refresh(true);
33960 this.restoreScroll(s);
33961 this.afterMove(newIndex);
33964 afterMove : function(colIndex){
33965 if(this.enableMoveAnim && Roo.enableFx){
33966 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
33968 // if multisort - fix sortOrder, and reload..
33969 if (this.grid.dataSource.multiSort) {
33970 // the we can call sort again..
33971 var dm = this.grid.dataSource;
33972 var cm = this.grid.colModel;
33974 for(var i = 0; i < cm.config.length; i++ ) {
33976 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
33977 continue; // dont' bother, it's not in sort list or being set.
33980 so.push(cm.config[i].dataIndex);
33983 dm.load(dm.lastOptions);
33990 updateCell : function(dm, rowIndex, dataIndex){
33991 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
33992 if(typeof colIndex == "undefined"){ // not present in grid
33995 var cm = this.grid.colModel;
33996 var cell = this.getCell(rowIndex, colIndex);
33997 var cellText = this.getCellText(rowIndex, colIndex);
34000 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
34001 id : cm.getColumnId(colIndex),
34002 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
34004 var renderer = cm.getRenderer(colIndex);
34005 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
34006 if(typeof val == "undefined" || val === "") val = " ";
34007 cellText.innerHTML = val;
34008 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
34009 this.syncRowHeights(rowIndex, rowIndex);
34012 calcColumnWidth : function(colIndex, maxRowsToMeasure){
34014 if(this.grid.autoSizeHeaders){
34015 var h = this.getHeaderCellMeasure(colIndex);
34016 maxWidth = Math.max(maxWidth, h.scrollWidth);
34019 if(this.cm.isLocked(colIndex)){
34020 tb = this.getLockedTable();
34023 tb = this.getBodyTable();
34024 index = colIndex - this.cm.getLockedCount();
34027 var rows = tb.rows;
34028 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
34029 for(var i = 0; i < stopIndex; i++){
34030 var cell = rows[i].childNodes[index].firstChild;
34031 maxWidth = Math.max(maxWidth, cell.scrollWidth);
34034 return maxWidth + /*margin for error in IE*/ 5;
34037 * Autofit a column to its content.
34038 * @param {Number} colIndex
34039 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
34041 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
34042 if(this.cm.isHidden(colIndex)){
34043 return; // can't calc a hidden column
34046 var cid = this.cm.getColumnId(colIndex);
34047 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
34048 if(this.grid.autoSizeHeaders){
34049 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
34052 var newWidth = this.calcColumnWidth(colIndex);
34053 this.cm.setColumnWidth(colIndex,
34054 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
34055 if(!suppressEvent){
34056 this.grid.fireEvent("columnresize", colIndex, newWidth);
34061 * Autofits all columns to their content and then expands to fit any extra space in the grid
34063 autoSizeColumns : function(){
34064 var cm = this.grid.colModel;
34065 var colCount = cm.getColumnCount();
34066 for(var i = 0; i < colCount; i++){
34067 this.autoSizeColumn(i, true, true);
34069 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
34072 this.updateColumns();
34078 * Autofits all columns to the grid's width proportionate with their current size
34079 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
34081 fitColumns : function(reserveScrollSpace){
34082 var cm = this.grid.colModel;
34083 var colCount = cm.getColumnCount();
34087 for (i = 0; i < colCount; i++){
34088 if(!cm.isHidden(i) && !cm.isFixed(i)){
34089 w = cm.getColumnWidth(i);
34095 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
34096 if(reserveScrollSpace){
34099 var frac = (avail - cm.getTotalWidth())/width;
34100 while (cols.length){
34103 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
34105 this.updateColumns();
34109 onRowSelect : function(rowIndex){
34110 var row = this.getRowComposite(rowIndex);
34111 row.addClass("x-grid-row-selected");
34114 onRowDeselect : function(rowIndex){
34115 var row = this.getRowComposite(rowIndex);
34116 row.removeClass("x-grid-row-selected");
34119 onCellSelect : function(row, col){
34120 var cell = this.getCell(row, col);
34122 Roo.fly(cell).addClass("x-grid-cell-selected");
34126 onCellDeselect : function(row, col){
34127 var cell = this.getCell(row, col);
34129 Roo.fly(cell).removeClass("x-grid-cell-selected");
34133 updateHeaderSortState : function(){
34135 // sort state can be single { field: xxx, direction : yyy}
34136 // or { xxx=>ASC , yyy : DESC ..... }
34139 if (!this.ds.multiSort) {
34140 var state = this.ds.getSortState();
34144 mstate[state.field] = state.direction;
34145 // FIXME... - this is not used here.. but might be elsewhere..
34146 this.sortState = state;
34149 mstate = this.ds.sortToggle;
34151 //remove existing sort classes..
34153 var sc = this.sortClasses;
34154 var hds = this.el.select(this.headerSelector).removeClass(sc);
34156 for(var f in mstate) {
34158 var sortColumn = this.cm.findColumnIndex(f);
34160 if(sortColumn != -1){
34161 var sortDir = mstate[f];
34162 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
34171 handleHeaderClick : function(g, index){
34172 if(this.headersDisabled){
34175 var dm = g.dataSource, cm = g.colModel;
34176 if(!cm.isSortable(index)){
34181 if (dm.multiSort) {
34182 // update the sortOrder
34184 for(var i = 0; i < cm.config.length; i++ ) {
34186 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
34187 continue; // dont' bother, it's not in sort list or being set.
34190 so.push(cm.config[i].dataIndex);
34196 dm.sort(cm.getDataIndex(index));
34200 destroy : function(){
34202 this.colMenu.removeAll();
34203 Roo.menu.MenuMgr.unregister(this.colMenu);
34204 this.colMenu.getEl().remove();
34205 delete this.colMenu;
34208 this.hmenu.removeAll();
34209 Roo.menu.MenuMgr.unregister(this.hmenu);
34210 this.hmenu.getEl().remove();
34213 if(this.grid.enableColumnMove){
34214 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
34216 for(var dd in dds){
34217 if(!dds[dd].config.isTarget && dds[dd].dragElId){
34218 var elid = dds[dd].dragElId;
34220 Roo.get(elid).remove();
34221 } else if(dds[dd].config.isTarget){
34222 dds[dd].proxyTop.remove();
34223 dds[dd].proxyBottom.remove();
34226 if(Roo.dd.DDM.locationCache[dd]){
34227 delete Roo.dd.DDM.locationCache[dd];
34230 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
34233 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
34234 this.bind(null, null);
34235 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
34238 handleLockChange : function(){
34239 this.refresh(true);
34242 onDenyColumnLock : function(){
34246 onDenyColumnHide : function(){
34250 handleHdMenuClick : function(item){
34251 var index = this.hdCtxIndex;
34252 var cm = this.cm, ds = this.ds;
34255 ds.sort(cm.getDataIndex(index), "ASC");
34258 ds.sort(cm.getDataIndex(index), "DESC");
34261 var lc = cm.getLockedCount();
34262 if(cm.getColumnCount(true) <= lc+1){
34263 this.onDenyColumnLock();
34267 cm.setLocked(index, true, true);
34268 cm.moveColumn(index, lc);
34269 this.grid.fireEvent("columnmove", index, lc);
34271 cm.setLocked(index, true);
34275 var lc = cm.getLockedCount();
34276 if((lc-1) != index){
34277 cm.setLocked(index, false, true);
34278 cm.moveColumn(index, lc-1);
34279 this.grid.fireEvent("columnmove", index, lc-1);
34281 cm.setLocked(index, false);
34285 index = cm.getIndexById(item.id.substr(4));
34287 if(item.checked && cm.getColumnCount(true) <= 1){
34288 this.onDenyColumnHide();
34291 cm.setHidden(index, item.checked);
34297 beforeColMenuShow : function(){
34298 var cm = this.cm, colCount = cm.getColumnCount();
34299 this.colMenu.removeAll();
34300 for(var i = 0; i < colCount; i++){
34301 this.colMenu.add(new Roo.menu.CheckItem({
34302 id: "col-"+cm.getColumnId(i),
34303 text: cm.getColumnHeader(i),
34304 checked: !cm.isHidden(i),
34310 handleHdCtx : function(g, index, e){
34312 var hd = this.getHeaderCell(index);
34313 this.hdCtxIndex = index;
34314 var ms = this.hmenu.items, cm = this.cm;
34315 ms.get("asc").setDisabled(!cm.isSortable(index));
34316 ms.get("desc").setDisabled(!cm.isSortable(index));
34317 if(this.grid.enableColLock !== false){
34318 ms.get("lock").setDisabled(cm.isLocked(index));
34319 ms.get("unlock").setDisabled(!cm.isLocked(index));
34321 this.hmenu.show(hd, "tl-bl");
34324 handleHdOver : function(e){
34325 var hd = this.findHeaderCell(e.getTarget());
34326 if(hd && !this.headersDisabled){
34327 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
34328 this.fly(hd).addClass("x-grid-hd-over");
34333 handleHdOut : function(e){
34334 var hd = this.findHeaderCell(e.getTarget());
34336 this.fly(hd).removeClass("x-grid-hd-over");
34340 handleSplitDblClick : function(e, t){
34341 var i = this.getCellIndex(t);
34342 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
34343 this.autoSizeColumn(i, true);
34348 render : function(){
34351 var colCount = cm.getColumnCount();
34353 if(this.grid.monitorWindowResize === true){
34354 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34356 var header = this.renderHeaders();
34357 var body = this.templates.body.apply({rows:""});
34358 var html = this.templates.master.apply({
34361 lockedHeader: header[0],
34365 //this.updateColumns();
34367 this.grid.getGridEl().dom.innerHTML = html;
34369 this.initElements();
34371 // a kludge to fix the random scolling effect in webkit
34372 this.el.on("scroll", function() {
34373 this.el.dom.scrollTop=0; // hopefully not recursive..
34376 this.scroller.on("scroll", this.handleScroll, this);
34377 this.lockedBody.on("mousewheel", this.handleWheel, this);
34378 this.mainBody.on("mousewheel", this.handleWheel, this);
34380 this.mainHd.on("mouseover", this.handleHdOver, this);
34381 this.mainHd.on("mouseout", this.handleHdOut, this);
34382 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34383 {delegate: "."+this.splitClass});
34385 this.lockedHd.on("mouseover", this.handleHdOver, this);
34386 this.lockedHd.on("mouseout", this.handleHdOut, this);
34387 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34388 {delegate: "."+this.splitClass});
34390 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34391 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34394 this.updateSplitters();
34396 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34397 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34398 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34401 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34402 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34404 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34405 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34407 if(this.grid.enableColLock !== false){
34408 this.hmenu.add('-',
34409 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34410 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34413 if(this.grid.enableColumnHide !== false){
34415 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34416 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34417 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34419 this.hmenu.add('-',
34420 {id:"columns", text: this.columnsText, menu: this.colMenu}
34423 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34425 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34428 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34429 this.dd = new Roo.grid.GridDragZone(this.grid, {
34430 ddGroup : this.grid.ddGroup || 'GridDD'
34435 for(var i = 0; i < colCount; i++){
34436 if(cm.isHidden(i)){
34437 this.hideColumn(i);
34439 if(cm.config[i].align){
34440 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34441 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34445 this.updateHeaderSortState();
34447 this.beforeInitialResize();
34450 // two part rendering gives faster view to the user
34451 this.renderPhase2.defer(1, this);
34454 renderPhase2 : function(){
34455 // render the rows now
34457 if(this.grid.autoSizeColumns){
34458 this.autoSizeColumns();
34462 beforeInitialResize : function(){
34466 onColumnSplitterMoved : function(i, w){
34467 this.userResized = true;
34468 var cm = this.grid.colModel;
34469 cm.setColumnWidth(i, w, true);
34470 var cid = cm.getColumnId(i);
34471 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34472 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34473 this.updateSplitters();
34475 this.grid.fireEvent("columnresize", i, w);
34478 syncRowHeights : function(startIndex, endIndex){
34479 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34480 startIndex = startIndex || 0;
34481 var mrows = this.getBodyTable().rows;
34482 var lrows = this.getLockedTable().rows;
34483 var len = mrows.length-1;
34484 endIndex = Math.min(endIndex || len, len);
34485 for(var i = startIndex; i <= endIndex; i++){
34486 var m = mrows[i], l = lrows[i];
34487 var h = Math.max(m.offsetHeight, l.offsetHeight);
34488 m.style.height = l.style.height = h + "px";
34493 layout : function(initialRender, is2ndPass){
34495 var auto = g.autoHeight;
34496 var scrollOffset = 16;
34497 var c = g.getGridEl(), cm = this.cm,
34498 expandCol = g.autoExpandColumn,
34500 //c.beginMeasure();
34502 if(!c.dom.offsetWidth){ // display:none?
34504 this.lockedWrap.show();
34505 this.mainWrap.show();
34510 var hasLock = this.cm.isLocked(0);
34512 var tbh = this.headerPanel.getHeight();
34513 var bbh = this.footerPanel.getHeight();
34516 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34517 var newHeight = ch + c.getBorderWidth("tb");
34519 newHeight = Math.min(g.maxHeight, newHeight);
34521 c.setHeight(newHeight);
34525 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34528 var s = this.scroller;
34530 var csize = c.getSize(true);
34532 this.el.setSize(csize.width, csize.height);
34534 this.headerPanel.setWidth(csize.width);
34535 this.footerPanel.setWidth(csize.width);
34537 var hdHeight = this.mainHd.getHeight();
34538 var vw = csize.width;
34539 var vh = csize.height - (tbh + bbh);
34543 var bt = this.getBodyTable();
34544 var ltWidth = hasLock ?
34545 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34547 var scrollHeight = bt.offsetHeight;
34548 var scrollWidth = ltWidth + bt.offsetWidth;
34549 var vscroll = false, hscroll = false;
34551 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34553 var lw = this.lockedWrap, mw = this.mainWrap;
34554 var lb = this.lockedBody, mb = this.mainBody;
34556 setTimeout(function(){
34557 var t = s.dom.offsetTop;
34558 var w = s.dom.clientWidth,
34559 h = s.dom.clientHeight;
34562 lw.setSize(ltWidth, h);
34564 mw.setLeftTop(ltWidth, t);
34565 mw.setSize(w-ltWidth, h);
34567 lb.setHeight(h-hdHeight);
34568 mb.setHeight(h-hdHeight);
34570 if(is2ndPass !== true && !gv.userResized && expandCol){
34571 // high speed resize without full column calculation
34573 var ci = cm.getIndexById(expandCol);
34575 ci = cm.findColumnIndex(expandCol);
34577 ci = Math.max(0, ci); // make sure it's got at least the first col.
34578 var expandId = cm.getColumnId(ci);
34579 var tw = cm.getTotalWidth(false);
34580 var currentWidth = cm.getColumnWidth(ci);
34581 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34582 if(currentWidth != cw){
34583 cm.setColumnWidth(ci, cw, true);
34584 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34585 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34586 gv.updateSplitters();
34587 gv.layout(false, true);
34599 onWindowResize : function(){
34600 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34606 appendFooter : function(parentEl){
34610 sortAscText : "Sort Ascending",
34611 sortDescText : "Sort Descending",
34612 lockText : "Lock Column",
34613 unlockText : "Unlock Column",
34614 columnsText : "Columns"
34618 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34619 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34620 this.proxy.el.addClass('x-grid3-col-dd');
34623 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34624 handleMouseDown : function(e){
34628 callHandleMouseDown : function(e){
34629 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34634 * Ext JS Library 1.1.1
34635 * Copyright(c) 2006-2007, Ext JS, LLC.
34637 * Originally Released Under LGPL - original licence link has changed is not relivant.
34640 * <script type="text/javascript">
34644 // This is a support class used internally by the Grid components
34645 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34647 this.view = grid.getView();
34648 this.proxy = this.view.resizeProxy;
34649 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34650 "gridSplitters" + this.grid.getGridEl().id, {
34651 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34653 this.setHandleElId(Roo.id(hd));
34654 this.setOuterHandleElId(Roo.id(hd2));
34655 this.scroll = false;
34657 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34658 fly: Roo.Element.fly,
34660 b4StartDrag : function(x, y){
34661 this.view.headersDisabled = true;
34662 this.proxy.setHeight(this.view.mainWrap.getHeight());
34663 var w = this.cm.getColumnWidth(this.cellIndex);
34664 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34665 this.resetConstraints();
34666 this.setXConstraint(minw, 1000);
34667 this.setYConstraint(0, 0);
34668 this.minX = x - minw;
34669 this.maxX = x + 1000;
34671 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34675 handleMouseDown : function(e){
34676 ev = Roo.EventObject.setEvent(e);
34677 var t = this.fly(ev.getTarget());
34678 if(t.hasClass("x-grid-split")){
34679 this.cellIndex = this.view.getCellIndex(t.dom);
34680 this.split = t.dom;
34681 this.cm = this.grid.colModel;
34682 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34683 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34688 endDrag : function(e){
34689 this.view.headersDisabled = false;
34690 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34691 var diff = endX - this.startPos;
34692 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34695 autoOffset : function(){
34696 this.setDelta(0,0);
34700 * Ext JS Library 1.1.1
34701 * Copyright(c) 2006-2007, Ext JS, LLC.
34703 * Originally Released Under LGPL - original licence link has changed is not relivant.
34706 * <script type="text/javascript">
34710 // This is a support class used internally by the Grid components
34711 Roo.grid.GridDragZone = function(grid, config){
34712 this.view = grid.getView();
34713 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34714 if(this.view.lockedBody){
34715 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34716 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34718 this.scroll = false;
34720 this.ddel = document.createElement('div');
34721 this.ddel.className = 'x-grid-dd-wrap';
34724 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34725 ddGroup : "GridDD",
34727 getDragData : function(e){
34728 var t = Roo.lib.Event.getTarget(e);
34729 var rowIndex = this.view.findRowIndex(t);
34730 if(rowIndex !== false){
34731 var sm = this.grid.selModel;
34732 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34733 // sm.mouseDown(e, t);
34735 if (e.hasModifier()){
34736 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34738 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34743 onInitDrag : function(e){
34744 var data = this.dragData;
34745 this.ddel.innerHTML = this.grid.getDragDropText();
34746 this.proxy.update(this.ddel);
34747 // fire start drag?
34750 afterRepair : function(){
34751 this.dragging = false;
34754 getRepairXY : function(e, data){
34758 onEndDrag : function(data, e){
34762 onValidDrop : function(dd, e, id){
34767 beforeInvalidDrop : function(e, id){
34772 * Ext JS Library 1.1.1
34773 * Copyright(c) 2006-2007, Ext JS, LLC.
34775 * Originally Released Under LGPL - original licence link has changed is not relivant.
34778 * <script type="text/javascript">
34783 * @class Roo.grid.ColumnModel
34784 * @extends Roo.util.Observable
34785 * This is the default implementation of a ColumnModel used by the Grid. It defines
34786 * the columns in the grid.
34789 var colModel = new Roo.grid.ColumnModel([
34790 {header: "Ticker", width: 60, sortable: true, locked: true},
34791 {header: "Company Name", width: 150, sortable: true},
34792 {header: "Market Cap.", width: 100, sortable: true},
34793 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34794 {header: "Employees", width: 100, sortable: true, resizable: false}
34799 * The config options listed for this class are options which may appear in each
34800 * individual column definition.
34801 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34803 * @param {Object} config An Array of column config objects. See this class's
34804 * config objects for details.
34806 Roo.grid.ColumnModel = function(config){
34808 * The config passed into the constructor
34810 this.config = config;
34813 // if no id, create one
34814 // if the column does not have a dataIndex mapping,
34815 // map it to the order it is in the config
34816 for(var i = 0, len = config.length; i < len; i++){
34818 if(typeof c.dataIndex == "undefined"){
34821 if(typeof c.renderer == "string"){
34822 c.renderer = Roo.util.Format[c.renderer];
34824 if(typeof c.id == "undefined"){
34827 if(c.editor && c.editor.xtype){
34828 c.editor = Roo.factory(c.editor, Roo.grid);
34830 if(c.editor && c.editor.isFormField){
34831 c.editor = new Roo.grid.GridEditor(c.editor);
34833 this.lookup[c.id] = c;
34837 * The width of columns which have no width specified (defaults to 100)
34840 this.defaultWidth = 100;
34843 * Default sortable of columns which have no sortable specified (defaults to false)
34846 this.defaultSortable = false;
34850 * @event widthchange
34851 * Fires when the width of a column changes.
34852 * @param {ColumnModel} this
34853 * @param {Number} columnIndex The column index
34854 * @param {Number} newWidth The new width
34856 "widthchange": true,
34858 * @event headerchange
34859 * Fires when the text of a header changes.
34860 * @param {ColumnModel} this
34861 * @param {Number} columnIndex The column index
34862 * @param {Number} newText The new header text
34864 "headerchange": true,
34866 * @event hiddenchange
34867 * Fires when a column is hidden or "unhidden".
34868 * @param {ColumnModel} this
34869 * @param {Number} columnIndex The column index
34870 * @param {Boolean} hidden true if hidden, false otherwise
34872 "hiddenchange": true,
34874 * @event columnmoved
34875 * Fires when a column is moved.
34876 * @param {ColumnModel} this
34877 * @param {Number} oldIndex
34878 * @param {Number} newIndex
34880 "columnmoved" : true,
34882 * @event columlockchange
34883 * Fires when a column's locked state is changed
34884 * @param {ColumnModel} this
34885 * @param {Number} colIndex
34886 * @param {Boolean} locked true if locked
34888 "columnlockchange" : true
34890 Roo.grid.ColumnModel.superclass.constructor.call(this);
34892 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34894 * @cfg {String} header The header text to display in the Grid view.
34897 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34898 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34899 * specified, the column's index is used as an index into the Record's data Array.
34902 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34903 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34906 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34907 * Defaults to the value of the {@link #defaultSortable} property.
34908 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34911 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34914 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34917 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34920 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34923 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34924 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34925 * default renderer uses the raw data value.
34928 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34931 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34935 * Returns the id of the column at the specified index.
34936 * @param {Number} index The column index
34937 * @return {String} the id
34939 getColumnId : function(index){
34940 return this.config[index].id;
34944 * Returns the column for a specified id.
34945 * @param {String} id The column id
34946 * @return {Object} the column
34948 getColumnById : function(id){
34949 return this.lookup[id];
34954 * Returns the column for a specified dataIndex.
34955 * @param {String} dataIndex The column dataIndex
34956 * @return {Object|Boolean} the column or false if not found
34958 getColumnByDataIndex: function(dataIndex){
34959 var index = this.findColumnIndex(dataIndex);
34960 return index > -1 ? this.config[index] : false;
34964 * Returns the index for a specified column id.
34965 * @param {String} id The column id
34966 * @return {Number} the index, or -1 if not found
34968 getIndexById : function(id){
34969 for(var i = 0, len = this.config.length; i < len; i++){
34970 if(this.config[i].id == id){
34978 * Returns the index for a specified column dataIndex.
34979 * @param {String} dataIndex The column dataIndex
34980 * @return {Number} the index, or -1 if not found
34983 findColumnIndex : function(dataIndex){
34984 for(var i = 0, len = this.config.length; i < len; i++){
34985 if(this.config[i].dataIndex == dataIndex){
34993 moveColumn : function(oldIndex, newIndex){
34994 var c = this.config[oldIndex];
34995 this.config.splice(oldIndex, 1);
34996 this.config.splice(newIndex, 0, c);
34997 this.dataMap = null;
34998 this.fireEvent("columnmoved", this, oldIndex, newIndex);
35001 isLocked : function(colIndex){
35002 return this.config[colIndex].locked === true;
35005 setLocked : function(colIndex, value, suppressEvent){
35006 if(this.isLocked(colIndex) == value){
35009 this.config[colIndex].locked = value;
35010 if(!suppressEvent){
35011 this.fireEvent("columnlockchange", this, colIndex, value);
35015 getTotalLockedWidth : function(){
35016 var totalWidth = 0;
35017 for(var i = 0; i < this.config.length; i++){
35018 if(this.isLocked(i) && !this.isHidden(i)){
35019 this.totalWidth += this.getColumnWidth(i);
35025 getLockedCount : function(){
35026 for(var i = 0, len = this.config.length; i < len; i++){
35027 if(!this.isLocked(i)){
35034 * Returns the number of columns.
35037 getColumnCount : function(visibleOnly){
35038 if(visibleOnly === true){
35040 for(var i = 0, len = this.config.length; i < len; i++){
35041 if(!this.isHidden(i)){
35047 return this.config.length;
35051 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
35052 * @param {Function} fn
35053 * @param {Object} scope (optional)
35054 * @return {Array} result
35056 getColumnsBy : function(fn, scope){
35058 for(var i = 0, len = this.config.length; i < len; i++){
35059 var c = this.config[i];
35060 if(fn.call(scope||this, c, i) === true){
35068 * Returns true if the specified column is sortable.
35069 * @param {Number} col The column index
35070 * @return {Boolean}
35072 isSortable : function(col){
35073 if(typeof this.config[col].sortable == "undefined"){
35074 return this.defaultSortable;
35076 return this.config[col].sortable;
35080 * Returns the rendering (formatting) function defined for the column.
35081 * @param {Number} col The column index.
35082 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
35084 getRenderer : function(col){
35085 if(!this.config[col].renderer){
35086 return Roo.grid.ColumnModel.defaultRenderer;
35088 return this.config[col].renderer;
35092 * Sets the rendering (formatting) function for a column.
35093 * @param {Number} col The column index
35094 * @param {Function} fn The function to use to process the cell's raw data
35095 * to return HTML markup for the grid view. The render function is called with
35096 * the following parameters:<ul>
35097 * <li>Data value.</li>
35098 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
35099 * <li>css A CSS style string to apply to the table cell.</li>
35100 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
35101 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
35102 * <li>Row index</li>
35103 * <li>Column index</li>
35104 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
35106 setRenderer : function(col, fn){
35107 this.config[col].renderer = fn;
35111 * Returns the width for the specified column.
35112 * @param {Number} col The column index
35115 getColumnWidth : function(col){
35116 return this.config[col].width * 1 || this.defaultWidth;
35120 * Sets the width for a column.
35121 * @param {Number} col The column index
35122 * @param {Number} width The new width
35124 setColumnWidth : function(col, width, suppressEvent){
35125 this.config[col].width = width;
35126 this.totalWidth = null;
35127 if(!suppressEvent){
35128 this.fireEvent("widthchange", this, col, width);
35133 * Returns the total width of all columns.
35134 * @param {Boolean} includeHidden True to include hidden column widths
35137 getTotalWidth : function(includeHidden){
35138 if(!this.totalWidth){
35139 this.totalWidth = 0;
35140 for(var i = 0, len = this.config.length; i < len; i++){
35141 if(includeHidden || !this.isHidden(i)){
35142 this.totalWidth += this.getColumnWidth(i);
35146 return this.totalWidth;
35150 * Returns the header for the specified column.
35151 * @param {Number} col The column index
35154 getColumnHeader : function(col){
35155 return this.config[col].header;
35159 * Sets the header for a column.
35160 * @param {Number} col The column index
35161 * @param {String} header The new header
35163 setColumnHeader : function(col, header){
35164 this.config[col].header = header;
35165 this.fireEvent("headerchange", this, col, header);
35169 * Returns the tooltip for the specified column.
35170 * @param {Number} col The column index
35173 getColumnTooltip : function(col){
35174 return this.config[col].tooltip;
35177 * Sets the tooltip for a column.
35178 * @param {Number} col The column index
35179 * @param {String} tooltip The new tooltip
35181 setColumnTooltip : function(col, tooltip){
35182 this.config[col].tooltip = tooltip;
35186 * Returns the dataIndex for the specified column.
35187 * @param {Number} col The column index
35190 getDataIndex : function(col){
35191 return this.config[col].dataIndex;
35195 * Sets the dataIndex for a column.
35196 * @param {Number} col The column index
35197 * @param {Number} dataIndex The new dataIndex
35199 setDataIndex : function(col, dataIndex){
35200 this.config[col].dataIndex = dataIndex;
35206 * Returns true if the cell is editable.
35207 * @param {Number} colIndex The column index
35208 * @param {Number} rowIndex The row index
35209 * @return {Boolean}
35211 isCellEditable : function(colIndex, rowIndex){
35212 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
35216 * Returns the editor defined for the cell/column.
35217 * return false or null to disable editing.
35218 * @param {Number} colIndex The column index
35219 * @param {Number} rowIndex The row index
35222 getCellEditor : function(colIndex, rowIndex){
35223 return this.config[colIndex].editor;
35227 * Sets if a column is editable.
35228 * @param {Number} col The column index
35229 * @param {Boolean} editable True if the column is editable
35231 setEditable : function(col, editable){
35232 this.config[col].editable = editable;
35237 * Returns true if the column is hidden.
35238 * @param {Number} colIndex The column index
35239 * @return {Boolean}
35241 isHidden : function(colIndex){
35242 return this.config[colIndex].hidden;
35247 * Returns true if the column width cannot be changed
35249 isFixed : function(colIndex){
35250 return this.config[colIndex].fixed;
35254 * Returns true if the column can be resized
35255 * @return {Boolean}
35257 isResizable : function(colIndex){
35258 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
35261 * Sets if a column is hidden.
35262 * @param {Number} colIndex The column index
35263 * @param {Boolean} hidden True if the column is hidden
35265 setHidden : function(colIndex, hidden){
35266 this.config[colIndex].hidden = hidden;
35267 this.totalWidth = null;
35268 this.fireEvent("hiddenchange", this, colIndex, hidden);
35272 * Sets the editor for a column.
35273 * @param {Number} col The column index
35274 * @param {Object} editor The editor object
35276 setEditor : function(col, editor){
35277 this.config[col].editor = editor;
35281 Roo.grid.ColumnModel.defaultRenderer = function(value){
35282 if(typeof value == "string" && value.length < 1){
35288 // Alias for backwards compatibility
35289 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
35292 * Ext JS Library 1.1.1
35293 * Copyright(c) 2006-2007, Ext JS, LLC.
35295 * Originally Released Under LGPL - original licence link has changed is not relivant.
35298 * <script type="text/javascript">
35302 * @class Roo.grid.AbstractSelectionModel
35303 * @extends Roo.util.Observable
35304 * Abstract base class for grid SelectionModels. It provides the interface that should be
35305 * implemented by descendant classes. This class should not be directly instantiated.
35308 Roo.grid.AbstractSelectionModel = function(){
35309 this.locked = false;
35310 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
35313 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
35314 /** @ignore Called by the grid automatically. Do not call directly. */
35315 init : function(grid){
35321 * Locks the selections.
35324 this.locked = true;
35328 * Unlocks the selections.
35330 unlock : function(){
35331 this.locked = false;
35335 * Returns true if the selections are locked.
35336 * @return {Boolean}
35338 isLocked : function(){
35339 return this.locked;
35343 * Ext JS Library 1.1.1
35344 * Copyright(c) 2006-2007, Ext JS, LLC.
35346 * Originally Released Under LGPL - original licence link has changed is not relivant.
35349 * <script type="text/javascript">
35352 * @extends Roo.grid.AbstractSelectionModel
35353 * @class Roo.grid.RowSelectionModel
35354 * The default SelectionModel used by {@link Roo.grid.Grid}.
35355 * It supports multiple selections and keyboard selection/navigation.
35357 * @param {Object} config
35359 Roo.grid.RowSelectionModel = function(config){
35360 Roo.apply(this, config);
35361 this.selections = new Roo.util.MixedCollection(false, function(o){
35366 this.lastActive = false;
35370 * @event selectionchange
35371 * Fires when the selection changes
35372 * @param {SelectionModel} this
35374 "selectionchange" : true,
35376 * @event afterselectionchange
35377 * Fires after the selection changes (eg. by key press or clicking)
35378 * @param {SelectionModel} this
35380 "afterselectionchange" : true,
35382 * @event beforerowselect
35383 * Fires when a row is selected being selected, return false to cancel.
35384 * @param {SelectionModel} this
35385 * @param {Number} rowIndex The selected index
35386 * @param {Boolean} keepExisting False if other selections will be cleared
35388 "beforerowselect" : true,
35391 * Fires when a row is selected.
35392 * @param {SelectionModel} this
35393 * @param {Number} rowIndex The selected index
35394 * @param {Roo.data.Record} r The record
35396 "rowselect" : true,
35398 * @event rowdeselect
35399 * Fires when a row is deselected.
35400 * @param {SelectionModel} this
35401 * @param {Number} rowIndex The selected index
35403 "rowdeselect" : true
35405 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35406 this.locked = false;
35409 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35411 * @cfg {Boolean} singleSelect
35412 * True to allow selection of only one row at a time (defaults to false)
35414 singleSelect : false,
35417 initEvents : function(){
35419 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35420 this.grid.on("mousedown", this.handleMouseDown, this);
35421 }else{ // allow click to work like normal
35422 this.grid.on("rowclick", this.handleDragableRowClick, this);
35425 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35426 "up" : function(e){
35428 this.selectPrevious(e.shiftKey);
35429 }else if(this.last !== false && this.lastActive !== false){
35430 var last = this.last;
35431 this.selectRange(this.last, this.lastActive-1);
35432 this.grid.getView().focusRow(this.lastActive);
35433 if(last !== false){
35437 this.selectFirstRow();
35439 this.fireEvent("afterselectionchange", this);
35441 "down" : function(e){
35443 this.selectNext(e.shiftKey);
35444 }else if(this.last !== false && this.lastActive !== false){
35445 var last = this.last;
35446 this.selectRange(this.last, this.lastActive+1);
35447 this.grid.getView().focusRow(this.lastActive);
35448 if(last !== false){
35452 this.selectFirstRow();
35454 this.fireEvent("afterselectionchange", this);
35459 var view = this.grid.view;
35460 view.on("refresh", this.onRefresh, this);
35461 view.on("rowupdated", this.onRowUpdated, this);
35462 view.on("rowremoved", this.onRemove, this);
35466 onRefresh : function(){
35467 var ds = this.grid.dataSource, i, v = this.grid.view;
35468 var s = this.selections;
35469 s.each(function(r){
35470 if((i = ds.indexOfId(r.id)) != -1){
35479 onRemove : function(v, index, r){
35480 this.selections.remove(r);
35484 onRowUpdated : function(v, index, r){
35485 if(this.isSelected(r)){
35486 v.onRowSelect(index);
35492 * @param {Array} records The records to select
35493 * @param {Boolean} keepExisting (optional) True to keep existing selections
35495 selectRecords : function(records, keepExisting){
35497 this.clearSelections();
35499 var ds = this.grid.dataSource;
35500 for(var i = 0, len = records.length; i < len; i++){
35501 this.selectRow(ds.indexOf(records[i]), true);
35506 * Gets the number of selected rows.
35509 getCount : function(){
35510 return this.selections.length;
35514 * Selects the first row in the grid.
35516 selectFirstRow : function(){
35521 * Select the last row.
35522 * @param {Boolean} keepExisting (optional) True to keep existing selections
35524 selectLastRow : function(keepExisting){
35525 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35529 * Selects the row immediately following the last selected row.
35530 * @param {Boolean} keepExisting (optional) True to keep existing selections
35532 selectNext : function(keepExisting){
35533 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35534 this.selectRow(this.last+1, keepExisting);
35535 this.grid.getView().focusRow(this.last);
35540 * Selects the row that precedes the last selected row.
35541 * @param {Boolean} keepExisting (optional) True to keep existing selections
35543 selectPrevious : function(keepExisting){
35545 this.selectRow(this.last-1, keepExisting);
35546 this.grid.getView().focusRow(this.last);
35551 * Returns the selected records
35552 * @return {Array} Array of selected records
35554 getSelections : function(){
35555 return [].concat(this.selections.items);
35559 * Returns the first selected record.
35562 getSelected : function(){
35563 return this.selections.itemAt(0);
35568 * Clears all selections.
35570 clearSelections : function(fast){
35571 if(this.locked) return;
35573 var ds = this.grid.dataSource;
35574 var s = this.selections;
35575 s.each(function(r){
35576 this.deselectRow(ds.indexOfId(r.id));
35580 this.selections.clear();
35587 * Selects all rows.
35589 selectAll : function(){
35590 if(this.locked) return;
35591 this.selections.clear();
35592 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35593 this.selectRow(i, true);
35598 * Returns True if there is a selection.
35599 * @return {Boolean}
35601 hasSelection : function(){
35602 return this.selections.length > 0;
35606 * Returns True if the specified row is selected.
35607 * @param {Number/Record} record The record or index of the record to check
35608 * @return {Boolean}
35610 isSelected : function(index){
35611 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35612 return (r && this.selections.key(r.id) ? true : false);
35616 * Returns True if the specified record id is selected.
35617 * @param {String} id The id of record to check
35618 * @return {Boolean}
35620 isIdSelected : function(id){
35621 return (this.selections.key(id) ? true : false);
35625 handleMouseDown : function(e, t){
35626 var view = this.grid.getView(), rowIndex;
35627 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35630 if(e.shiftKey && this.last !== false){
35631 var last = this.last;
35632 this.selectRange(last, rowIndex, e.ctrlKey);
35633 this.last = last; // reset the last
35634 view.focusRow(rowIndex);
35636 var isSelected = this.isSelected(rowIndex);
35637 if(e.button !== 0 && isSelected){
35638 view.focusRow(rowIndex);
35639 }else if(e.ctrlKey && isSelected){
35640 this.deselectRow(rowIndex);
35641 }else if(!isSelected){
35642 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35643 view.focusRow(rowIndex);
35646 this.fireEvent("afterselectionchange", this);
35649 handleDragableRowClick : function(grid, rowIndex, e)
35651 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35652 this.selectRow(rowIndex, false);
35653 grid.view.focusRow(rowIndex);
35654 this.fireEvent("afterselectionchange", this);
35659 * Selects multiple rows.
35660 * @param {Array} rows Array of the indexes of the row to select
35661 * @param {Boolean} keepExisting (optional) True to keep existing selections
35663 selectRows : function(rows, keepExisting){
35665 this.clearSelections();
35667 for(var i = 0, len = rows.length; i < len; i++){
35668 this.selectRow(rows[i], true);
35673 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35674 * @param {Number} startRow The index of the first row in the range
35675 * @param {Number} endRow The index of the last row in the range
35676 * @param {Boolean} keepExisting (optional) True to retain existing selections
35678 selectRange : function(startRow, endRow, keepExisting){
35679 if(this.locked) return;
35681 this.clearSelections();
35683 if(startRow <= endRow){
35684 for(var i = startRow; i <= endRow; i++){
35685 this.selectRow(i, true);
35688 for(var i = startRow; i >= endRow; i--){
35689 this.selectRow(i, true);
35695 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35696 * @param {Number} startRow The index of the first row in the range
35697 * @param {Number} endRow The index of the last row in the range
35699 deselectRange : function(startRow, endRow, preventViewNotify){
35700 if(this.locked) return;
35701 for(var i = startRow; i <= endRow; i++){
35702 this.deselectRow(i, preventViewNotify);
35708 * @param {Number} row The index of the row to select
35709 * @param {Boolean} keepExisting (optional) True to keep existing selections
35711 selectRow : function(index, keepExisting, preventViewNotify){
35712 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35713 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35714 if(!keepExisting || this.singleSelect){
35715 this.clearSelections();
35717 var r = this.grid.dataSource.getAt(index);
35718 this.selections.add(r);
35719 this.last = this.lastActive = index;
35720 if(!preventViewNotify){
35721 this.grid.getView().onRowSelect(index);
35723 this.fireEvent("rowselect", this, index, r);
35724 this.fireEvent("selectionchange", this);
35730 * @param {Number} row The index of the row to deselect
35732 deselectRow : function(index, preventViewNotify){
35733 if(this.locked) return;
35734 if(this.last == index){
35737 if(this.lastActive == index){
35738 this.lastActive = false;
35740 var r = this.grid.dataSource.getAt(index);
35741 this.selections.remove(r);
35742 if(!preventViewNotify){
35743 this.grid.getView().onRowDeselect(index);
35745 this.fireEvent("rowdeselect", this, index);
35746 this.fireEvent("selectionchange", this);
35750 restoreLast : function(){
35752 this.last = this._last;
35757 acceptsNav : function(row, col, cm){
35758 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35762 onEditorKey : function(field, e){
35763 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35768 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35770 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35772 }else if(k == e.ENTER && !e.ctrlKey){
35776 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35778 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35780 }else if(k == e.ESC){
35784 g.startEditing(newCell[0], newCell[1]);
35789 * Ext JS Library 1.1.1
35790 * Copyright(c) 2006-2007, Ext JS, LLC.
35792 * Originally Released Under LGPL - original licence link has changed is not relivant.
35795 * <script type="text/javascript">
35798 * @class Roo.grid.CellSelectionModel
35799 * @extends Roo.grid.AbstractSelectionModel
35800 * This class provides the basic implementation for cell selection in a grid.
35802 * @param {Object} config The object containing the configuration of this model.
35804 Roo.grid.CellSelectionModel = function(config){
35805 Roo.apply(this, config);
35807 this.selection = null;
35811 * @event beforerowselect
35812 * Fires before a cell is selected.
35813 * @param {SelectionModel} this
35814 * @param {Number} rowIndex The selected row index
35815 * @param {Number} colIndex The selected cell index
35817 "beforecellselect" : true,
35819 * @event cellselect
35820 * Fires when a cell is selected.
35821 * @param {SelectionModel} this
35822 * @param {Number} rowIndex The selected row index
35823 * @param {Number} colIndex The selected cell index
35825 "cellselect" : true,
35827 * @event selectionchange
35828 * Fires when the active selection changes.
35829 * @param {SelectionModel} this
35830 * @param {Object} selection null for no selection or an object (o) with two properties
35832 <li>o.record: the record object for the row the selection is in</li>
35833 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35836 "selectionchange" : true
35838 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35841 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35844 initEvents : function(){
35845 this.grid.on("mousedown", this.handleMouseDown, this);
35846 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35847 var view = this.grid.view;
35848 view.on("refresh", this.onViewChange, this);
35849 view.on("rowupdated", this.onRowUpdated, this);
35850 view.on("beforerowremoved", this.clearSelections, this);
35851 view.on("beforerowsinserted", this.clearSelections, this);
35852 if(this.grid.isEditor){
35853 this.grid.on("beforeedit", this.beforeEdit, this);
35858 beforeEdit : function(e){
35859 this.select(e.row, e.column, false, true, e.record);
35863 onRowUpdated : function(v, index, r){
35864 if(this.selection && this.selection.record == r){
35865 v.onCellSelect(index, this.selection.cell[1]);
35870 onViewChange : function(){
35871 this.clearSelections(true);
35875 * Returns the currently selected cell,.
35876 * @return {Array} The selected cell (row, column) or null if none selected.
35878 getSelectedCell : function(){
35879 return this.selection ? this.selection.cell : null;
35883 * Clears all selections.
35884 * @param {Boolean} true to prevent the gridview from being notified about the change.
35886 clearSelections : function(preventNotify){
35887 var s = this.selection;
35889 if(preventNotify !== true){
35890 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35892 this.selection = null;
35893 this.fireEvent("selectionchange", this, null);
35898 * Returns true if there is a selection.
35899 * @return {Boolean}
35901 hasSelection : function(){
35902 return this.selection ? true : false;
35906 handleMouseDown : function(e, t){
35907 var v = this.grid.getView();
35908 if(this.isLocked()){
35911 var row = v.findRowIndex(t);
35912 var cell = v.findCellIndex(t);
35913 if(row !== false && cell !== false){
35914 this.select(row, cell);
35920 * @param {Number} rowIndex
35921 * @param {Number} collIndex
35923 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35924 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35925 this.clearSelections();
35926 r = r || this.grid.dataSource.getAt(rowIndex);
35929 cell : [rowIndex, colIndex]
35931 if(!preventViewNotify){
35932 var v = this.grid.getView();
35933 v.onCellSelect(rowIndex, colIndex);
35934 if(preventFocus !== true){
35935 v.focusCell(rowIndex, colIndex);
35938 this.fireEvent("cellselect", this, rowIndex, colIndex);
35939 this.fireEvent("selectionchange", this, this.selection);
35944 isSelectable : function(rowIndex, colIndex, cm){
35945 return !cm.isHidden(colIndex);
35949 handleKeyDown : function(e){
35950 Roo.log('Cell Sel Model handleKeyDown');
35951 if(!e.isNavKeyPress()){
35954 var g = this.grid, s = this.selection;
35957 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35959 this.select(cell[0], cell[1]);
35964 var walk = function(row, col, step){
35965 return g.walkCells(row, col, step, sm.isSelectable, sm);
35967 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
35972 // handled by onEditorKey
35973 if (g.isEditor && g.editing) {
35977 newCell = walk(r, c-1, -1);
35979 newCell = walk(r, c+1, 1);
35983 newCell = walk(r+1, c, 1);
35986 newCell = walk(r-1, c, -1);
35989 newCell = walk(r, c+1, 1);
35992 newCell = walk(r, c-1, -1);
35995 if(g.isEditor && !g.editing){
35996 g.startEditing(r, c);
36003 this.select(newCell[0], newCell[1]);
36008 acceptsNav : function(row, col, cm){
36009 return !cm.isHidden(col) && cm.isCellEditable(col, row);
36012 onEditorKey : function(field, e){
36014 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
36015 ///Roo.log('onEditorKey' + k);
36019 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
36021 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
36024 }else if(k == e.ENTER && !e.ctrlKey){
36027 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
36028 }else if(k == e.ESC){
36034 //Roo.log('next cell after edit');
36035 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
36040 * Ext JS Library 1.1.1
36041 * Copyright(c) 2006-2007, Ext JS, LLC.
36043 * Originally Released Under LGPL - original licence link has changed is not relivant.
36046 * <script type="text/javascript">
36050 * @class Roo.grid.EditorGrid
36051 * @extends Roo.grid.Grid
36052 * Class for creating and editable grid.
36053 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36054 * The container MUST have some type of size defined for the grid to fill. The container will be
36055 * automatically set to position relative if it isn't already.
36056 * @param {Object} dataSource The data model to bind to
36057 * @param {Object} colModel The column model with info about this grid's columns
36059 Roo.grid.EditorGrid = function(container, config){
36060 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
36061 this.getGridEl().addClass("xedit-grid");
36063 if(!this.selModel){
36064 this.selModel = new Roo.grid.CellSelectionModel();
36067 this.activeEditor = null;
36071 * @event beforeedit
36072 * Fires before cell editing is triggered. The edit event object has the following properties <br />
36073 * <ul style="padding:5px;padding-left:16px;">
36074 * <li>grid - This grid</li>
36075 * <li>record - The record being edited</li>
36076 * <li>field - The field name being edited</li>
36077 * <li>value - The value for the field being edited.</li>
36078 * <li>row - The grid row index</li>
36079 * <li>column - The grid column index</li>
36080 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
36082 * @param {Object} e An edit event (see above for description)
36084 "beforeedit" : true,
36087 * Fires after a cell is edited. <br />
36088 * <ul style="padding:5px;padding-left:16px;">
36089 * <li>grid - This grid</li>
36090 * <li>record - The record being edited</li>
36091 * <li>field - The field name being edited</li>
36092 * <li>value - The value being set</li>
36093 * <li>originalValue - The original value for the field, before the edit.</li>
36094 * <li>row - The grid row index</li>
36095 * <li>column - The grid column index</li>
36097 * @param {Object} e An edit event (see above for description)
36099 "afteredit" : true,
36101 * @event validateedit
36102 * Fires after a cell is edited, but before the value is set in the record.
36103 * You can use this to modify the value being set in the field, Return false
36104 * to cancel the change. The edit event object has the following properties <br />
36105 * <ul style="padding:5px;padding-left:16px;">
36106 * <li>editor - This editor</li>
36107 * <li>grid - This grid</li>
36108 * <li>record - The record being edited</li>
36109 * <li>field - The field name being edited</li>
36110 * <li>value - The value being set</li>
36111 * <li>originalValue - The original value for the field, before the edit.</li>
36112 * <li>row - The grid row index</li>
36113 * <li>column - The grid column index</li>
36114 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
36116 * @param {Object} e An edit event (see above for description)
36118 "validateedit" : true
36120 this.on("bodyscroll", this.stopEditing, this);
36121 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
36124 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
36126 * @cfg {Number} clicksToEdit
36127 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
36134 trackMouseOver: false, // causes very odd FF errors
36136 onCellDblClick : function(g, row, col){
36137 this.startEditing(row, col);
36140 onEditComplete : function(ed, value, startValue){
36141 this.editing = false;
36142 this.activeEditor = null;
36143 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
36145 var field = this.colModel.getDataIndex(ed.col);
36150 originalValue: startValue,
36157 if(String(value) !== String(startValue)){
36159 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
36160 r.set(field, e.value);
36161 // if we are dealing with a combo box..
36162 // then we also set the 'name' colum to be the displayField
36163 if (ed.field.displayField && ed.field.name) {
36164 r.set(ed.field.name, ed.field.el.dom.value);
36167 delete e.cancel; //?? why!!!
36168 this.fireEvent("afteredit", e);
36171 this.fireEvent("afteredit", e); // always fire it!
36173 this.view.focusCell(ed.row, ed.col);
36177 * Starts editing the specified for the specified row/column
36178 * @param {Number} rowIndex
36179 * @param {Number} colIndex
36181 startEditing : function(row, col){
36182 this.stopEditing();
36183 if(this.colModel.isCellEditable(col, row)){
36184 this.view.ensureVisible(row, col, true);
36185 var r = this.dataSource.getAt(row);
36186 var field = this.colModel.getDataIndex(col);
36191 value: r.data[field],
36196 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
36197 this.editing = true;
36198 var ed = this.colModel.getCellEditor(col, row);
36204 ed.render(ed.parentEl || document.body);
36207 (function(){ // complex but required for focus issues in safari, ie and opera
36211 ed.on("complete", this.onEditComplete, this, {single: true});
36212 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
36213 this.activeEditor = ed;
36214 var v = r.data[field];
36215 ed.startEdit(this.view.getCell(row, col), v);
36216 // combo's with 'displayField and name set
36217 if (ed.field.displayField && ed.field.name) {
36218 ed.field.el.dom.value = r.data[ed.field.name];
36222 }).defer(50, this);
36228 * Stops any active editing
36230 stopEditing : function(){
36231 if(this.activeEditor){
36232 this.activeEditor.completeEdit();
36234 this.activeEditor = null;
36238 * Ext JS Library 1.1.1
36239 * Copyright(c) 2006-2007, Ext JS, LLC.
36241 * Originally Released Under LGPL - original licence link has changed is not relivant.
36244 * <script type="text/javascript">
36247 // private - not really -- you end up using it !
36248 // This is a support class used internally by the Grid components
36251 * @class Roo.grid.GridEditor
36252 * @extends Roo.Editor
36253 * Class for creating and editable grid elements.
36254 * @param {Object} config any settings (must include field)
36256 Roo.grid.GridEditor = function(field, config){
36257 if (!config && field.field) {
36259 field = Roo.factory(config.field, Roo.form);
36261 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
36262 field.monitorTab = false;
36265 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
36268 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
36271 alignment: "tl-tl",
36274 cls: "x-small-editor x-grid-editor",
36279 * Ext JS Library 1.1.1
36280 * Copyright(c) 2006-2007, Ext JS, LLC.
36282 * Originally Released Under LGPL - original licence link has changed is not relivant.
36285 * <script type="text/javascript">
36290 Roo.grid.PropertyRecord = Roo.data.Record.create([
36291 {name:'name',type:'string'}, 'value'
36295 Roo.grid.PropertyStore = function(grid, source){
36297 this.store = new Roo.data.Store({
36298 recordType : Roo.grid.PropertyRecord
36300 this.store.on('update', this.onUpdate, this);
36302 this.setSource(source);
36304 Roo.grid.PropertyStore.superclass.constructor.call(this);
36309 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
36310 setSource : function(o){
36312 this.store.removeAll();
36315 if(this.isEditableValue(o[k])){
36316 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
36319 this.store.loadRecords({records: data}, {}, true);
36322 onUpdate : function(ds, record, type){
36323 if(type == Roo.data.Record.EDIT){
36324 var v = record.data['value'];
36325 var oldValue = record.modified['value'];
36326 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
36327 this.source[record.id] = v;
36329 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
36336 getProperty : function(row){
36337 return this.store.getAt(row);
36340 isEditableValue: function(val){
36341 if(val && val instanceof Date){
36343 }else if(typeof val == 'object' || typeof val == 'function'){
36349 setValue : function(prop, value){
36350 this.source[prop] = value;
36351 this.store.getById(prop).set('value', value);
36354 getSource : function(){
36355 return this.source;
36359 Roo.grid.PropertyColumnModel = function(grid, store){
36362 g.PropertyColumnModel.superclass.constructor.call(this, [
36363 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
36364 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
36366 this.store = store;
36367 this.bselect = Roo.DomHelper.append(document.body, {
36368 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
36369 {tag: 'option', value: 'true', html: 'true'},
36370 {tag: 'option', value: 'false', html: 'false'}
36373 Roo.id(this.bselect);
36376 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
36377 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
36378 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
36379 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
36380 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36382 this.renderCellDelegate = this.renderCell.createDelegate(this);
36383 this.renderPropDelegate = this.renderProp.createDelegate(this);
36386 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36390 valueText : 'Value',
36392 dateFormat : 'm/j/Y',
36395 renderDate : function(dateVal){
36396 return dateVal.dateFormat(this.dateFormat);
36399 renderBool : function(bVal){
36400 return bVal ? 'true' : 'false';
36403 isCellEditable : function(colIndex, rowIndex){
36404 return colIndex == 1;
36407 getRenderer : function(col){
36409 this.renderCellDelegate : this.renderPropDelegate;
36412 renderProp : function(v){
36413 return this.getPropertyName(v);
36416 renderCell : function(val){
36418 if(val instanceof Date){
36419 rv = this.renderDate(val);
36420 }else if(typeof val == 'boolean'){
36421 rv = this.renderBool(val);
36423 return Roo.util.Format.htmlEncode(rv);
36426 getPropertyName : function(name){
36427 var pn = this.grid.propertyNames;
36428 return pn && pn[name] ? pn[name] : name;
36431 getCellEditor : function(colIndex, rowIndex){
36432 var p = this.store.getProperty(rowIndex);
36433 var n = p.data['name'], val = p.data['value'];
36435 if(typeof(this.grid.customEditors[n]) == 'string'){
36436 return this.editors[this.grid.customEditors[n]];
36438 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36439 return this.grid.customEditors[n];
36441 if(val instanceof Date){
36442 return this.editors['date'];
36443 }else if(typeof val == 'number'){
36444 return this.editors['number'];
36445 }else if(typeof val == 'boolean'){
36446 return this.editors['boolean'];
36448 return this.editors['string'];
36454 * @class Roo.grid.PropertyGrid
36455 * @extends Roo.grid.EditorGrid
36456 * This class represents the interface of a component based property grid control.
36457 * <br><br>Usage:<pre><code>
36458 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36466 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36467 * The container MUST have some type of size defined for the grid to fill. The container will be
36468 * automatically set to position relative if it isn't already.
36469 * @param {Object} config A config object that sets properties on this grid.
36471 Roo.grid.PropertyGrid = function(container, config){
36472 config = config || {};
36473 var store = new Roo.grid.PropertyStore(this);
36474 this.store = store;
36475 var cm = new Roo.grid.PropertyColumnModel(this, store);
36476 store.store.sort('name', 'ASC');
36477 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36480 enableColLock:false,
36481 enableColumnMove:false,
36483 trackMouseOver: false,
36486 this.getGridEl().addClass('x-props-grid');
36487 this.lastEditRow = null;
36488 this.on('columnresize', this.onColumnResize, this);
36491 * @event beforepropertychange
36492 * Fires before a property changes (return false to stop?)
36493 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36494 * @param {String} id Record Id
36495 * @param {String} newval New Value
36496 * @param {String} oldval Old Value
36498 "beforepropertychange": true,
36500 * @event propertychange
36501 * Fires after a property changes
36502 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36503 * @param {String} id Record Id
36504 * @param {String} newval New Value
36505 * @param {String} oldval Old Value
36507 "propertychange": true
36509 this.customEditors = this.customEditors || {};
36511 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36514 * @cfg {Object} customEditors map of colnames=> custom editors.
36515 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36516 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36517 * false disables editing of the field.
36521 * @cfg {Object} propertyNames map of property Names to their displayed value
36524 render : function(){
36525 Roo.grid.PropertyGrid.superclass.render.call(this);
36526 this.autoSize.defer(100, this);
36529 autoSize : function(){
36530 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36532 this.view.fitColumns();
36536 onColumnResize : function(){
36537 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36541 * Sets the data for the Grid
36542 * accepts a Key => Value object of all the elements avaiable.
36543 * @param {Object} data to appear in grid.
36545 setSource : function(source){
36546 this.store.setSource(source);
36550 * Gets all the data from the grid.
36551 * @return {Object} data data stored in grid
36553 getSource : function(){
36554 return this.store.getSource();
36558 * Ext JS Library 1.1.1
36559 * Copyright(c) 2006-2007, Ext JS, LLC.
36561 * Originally Released Under LGPL - original licence link has changed is not relivant.
36564 * <script type="text/javascript">
36568 * @class Roo.LoadMask
36569 * A simple utility class for generically masking elements while loading data. If the element being masked has
36570 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36571 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36572 * element's UpdateManager load indicator and will be destroyed after the initial load.
36574 * Create a new LoadMask
36575 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36576 * @param {Object} config The config object
36578 Roo.LoadMask = function(el, config){
36579 this.el = Roo.get(el);
36580 Roo.apply(this, config);
36582 this.store.on('beforeload', this.onBeforeLoad, this);
36583 this.store.on('load', this.onLoad, this);
36584 this.store.on('loadexception', this.onLoad, this);
36585 this.removeMask = false;
36587 var um = this.el.getUpdateManager();
36588 um.showLoadIndicator = false; // disable the default indicator
36589 um.on('beforeupdate', this.onBeforeLoad, this);
36590 um.on('update', this.onLoad, this);
36591 um.on('failure', this.onLoad, this);
36592 this.removeMask = true;
36596 Roo.LoadMask.prototype = {
36598 * @cfg {Boolean} removeMask
36599 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36600 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36603 * @cfg {String} msg
36604 * The text to display in a centered loading message box (defaults to 'Loading...')
36606 msg : 'Loading...',
36608 * @cfg {String} msgCls
36609 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36611 msgCls : 'x-mask-loading',
36614 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36620 * Disables the mask to prevent it from being displayed
36622 disable : function(){
36623 this.disabled = true;
36627 * Enables the mask so that it can be displayed
36629 enable : function(){
36630 this.disabled = false;
36634 onLoad : function(){
36635 this.el.unmask(this.removeMask);
36639 onBeforeLoad : function(){
36640 if(!this.disabled){
36641 this.el.mask(this.msg, this.msgCls);
36646 destroy : function(){
36648 this.store.un('beforeload', this.onBeforeLoad, this);
36649 this.store.un('load', this.onLoad, this);
36650 this.store.un('loadexception', this.onLoad, this);
36652 var um = this.el.getUpdateManager();
36653 um.un('beforeupdate', this.onBeforeLoad, this);
36654 um.un('update', this.onLoad, this);
36655 um.un('failure', this.onLoad, this);
36660 * Ext JS Library 1.1.1
36661 * Copyright(c) 2006-2007, Ext JS, LLC.
36663 * Originally Released Under LGPL - original licence link has changed is not relivant.
36666 * <script type="text/javascript">
36668 Roo.XTemplate = function(){
36669 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36672 s = ['<tpl>', s, '</tpl>'].join('');
36674 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36676 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36677 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36678 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36682 while(m = s.match(re)){
36683 var m2 = m[0].match(nameRe);
36684 var m3 = m[0].match(ifRe);
36685 var m4 = m[0].match(execRe);
36686 var exp = null, fn = null, exec = null;
36687 var name = m2 && m2[1] ? m2[1] : '';
36689 exp = m3 && m3[1] ? m3[1] : null;
36691 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36695 exp = m4 && m4[1] ? m4[1] : null;
36697 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36702 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36703 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36704 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36714 s = s.replace(m[0], '{xtpl'+ id + '}');
36717 for(var i = tpls.length-1; i >= 0; --i){
36718 this.compileTpl(tpls[i]);
36720 this.master = tpls[tpls.length-1];
36723 Roo.extend(Roo.XTemplate, Roo.Template, {
36725 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36727 applySubTemplate : function(id, values, parent){
36728 var t = this.tpls[id];
36729 if(t.test && !t.test.call(this, values, parent)){
36732 if(t.exec && t.exec.call(this, values, parent)){
36735 var vs = t.target ? t.target.call(this, values, parent) : values;
36736 parent = t.target ? values : parent;
36737 if(t.target && vs instanceof Array){
36739 for(var i = 0, len = vs.length; i < len; i++){
36740 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36742 return buf.join('');
36744 return t.compiled.call(this, vs, parent);
36747 compileTpl : function(tpl){
36748 var fm = Roo.util.Format;
36749 var useF = this.disableFormats !== true;
36750 var sep = Roo.isGecko ? "+" : ",";
36751 var fn = function(m, name, format, args){
36752 if(name.substr(0, 4) == 'xtpl'){
36753 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36756 if(name.indexOf('.') != -1){
36759 v = "values['" + name + "']";
36761 if(format && useF){
36762 args = args ? ',' + args : "";
36763 if(format.substr(0, 5) != "this."){
36764 format = "fm." + format + '(';
36766 format = 'this.call("'+ format.substr(5) + '", ';
36770 args= ''; format = "("+v+" === undefined ? '' : ";
36772 return "'"+ sep + format + v + args + ")"+sep+"'";
36775 // branched to use + in gecko and [].join() in others
36777 body = "tpl.compiled = function(values, parent){ return '" +
36778 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36781 body = ["tpl.compiled = function(values, parent){ return ['"];
36782 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36783 body.push("'].join('');};");
36784 body = body.join('');
36786 /** eval:var:zzzzzzz */
36791 applyTemplate : function(values){
36792 return this.master.compiled.call(this, values, {});
36796 apply : function(){
36797 return this.applyTemplate.apply(this, arguments);
36800 compile : function(){return this;}
36803 Roo.XTemplate.from = function(el){
36804 el = Roo.getDom(el);
36805 return new Roo.XTemplate(el.value || el.innerHTML);
36807 * Original code for Roojs - LGPL
36808 * <script type="text/javascript">
36812 * @class Roo.XComponent
36813 * A delayed Element creator...
36814 * Or a way to group chunks of interface together.
36816 * Mypart.xyx = new Roo.XComponent({
36818 parent : 'Mypart.xyz', // empty == document.element.!!
36822 disabled : function() {}
36824 tree : function() { // return an tree of xtype declared components
36828 xtype : 'NestedLayoutPanel',
36835 * It can be used to build a big heiracy, with parent etc.
36836 * or you can just use this to render a single compoent to a dom element
36837 * MYPART.render(Roo.Element | String(id) | dom_element )
36839 * @extends Roo.util.Observable
36841 * @param cfg {Object} configuration of component
36844 Roo.XComponent = function(cfg) {
36845 Roo.apply(this, cfg);
36849 * Fires when this the componnt is built
36850 * @param {Roo.XComponent} c the component
36854 * @event buildcomplete
36855 * Fires on the top level element when all elements have been built
36856 * @param {Roo.XComponent} c the top level component.
36858 'buildcomplete' : true
36861 this.region = this.region || 'center'; // default..
36862 Roo.XComponent.register(this);
36863 this.modules = false;
36864 this.el = false; // where the layout goes..
36868 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36871 * The created element (with Roo.factory())
36872 * @type {Roo.Layout}
36878 * for BC - use el in new code
36879 * @type {Roo.Layout}
36885 * for BC - use el in new code
36886 * @type {Roo.Layout}
36891 * @cfg {Function|boolean} disabled
36892 * If this module is disabled by some rule, return true from the funtion
36897 * @cfg {String} parent
36898 * Name of parent element which it get xtype added to..
36903 * @cfg {String} order
36904 * Used to set the order in which elements are created (usefull for multiple tabs)
36909 * @cfg {String} name
36910 * String to display while loading.
36914 * @cfg {String} region
36915 * Region to render component to (defaults to center)
36920 * @cfg {Array} items
36921 * A single item array - the first element is the root of the tree..
36922 * It's done this way to stay compatible with the Xtype system...
36929 * render element to dom or tree
36930 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
36933 render : function(el)
36938 if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
36939 // if parent is a '#.....' string, then let's use that..
36940 var ename = this.parent.substr(1)
36941 this.parent = false;
36942 el = Roo.get(ename);
36944 Roo.log("Warning - element can not be found :#" + ename );
36948 if (!this.parent) {
36950 el = el ? Roo.get(el) : false;
36952 // it's a top level one..
36954 el : new Roo.BorderLayout(el || document.body, {
36960 tabPosition: 'top',
36961 //resizeTabs: true,
36962 alwaysShowTabs: el ? false : true,
36963 hideTabs: el ? true : false,
36972 var tree = this.tree();
36973 tree.region = tree.region || this.region;
36974 this.el = this.parent.el.addxtype(tree);
36975 this.fireEvent('built', this);
36977 this.panel = this.el;
36978 this.layout = this.panel.layout;
36984 Roo.apply(Roo.XComponent, {
36987 * @property buildCompleted
36988 * True when the builder has completed building the interface.
36991 buildCompleted : false,
36994 * @property topModule
36995 * the upper most module - uses document.element as it's constructor.
37002 * @property modules
37003 * array of modules to be created by registration system.
37004 * @type {Array} of Roo.XComponent
37009 * @property elmodules
37010 * array of modules to be created by which use #ID
37011 * @type {Array} of Roo.XComponent
37018 * Register components to be built later.
37020 * This solves the following issues
37021 * - Building is not done on page load, but after an authentication process has occured.
37022 * - Interface elements are registered on page load
37023 * - Parent Interface elements may not be loaded before child, so this handles that..
37030 module : 'Pman.Tab.projectMgr',
37032 parent : 'Pman.layout',
37033 disabled : false, // or use a function..
37036 * * @param {Object} details about module
37038 register : function(obj) {
37039 this.modules.push(obj);
37043 * convert a string to an object..
37044 * eg. 'AAA.BBB' -> finds AAA.BBB
37048 toObject : function(str)
37050 if (!str || typeof(str) == 'object') {
37057 var ar = str.split('.');
37061 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
37063 throw "Module not found : " + str;
37065 Roo.each(ar, function(e) {
37066 if (typeof(o[e]) == 'undefined') {
37067 throw "Module not found : " + str;
37077 * move modules into their correct place in the tree..
37080 preBuild : function ()
37083 Roo.each(this.modules , function (obj)
37085 obj.parent = this.toObject(obj.parent);
37088 this.topModule = obj;
37091 if (typeof(obj.parent) == 'string') {
37092 this.elmodules.push(obj);
37096 if (!obj.parent.modules) {
37097 obj.parent.modules = new Roo.util.MixedCollection(false,
37098 function(o) { return o.order + '' }
37102 obj.parent.modules.add(obj);
37107 * make a list of modules to build.
37108 * @return {Array} list of modules.
37111 buildOrder : function()
37114 var cmp = function(a,b) {
37115 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
37117 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
37118 throw "No top level modules to build";
37121 // make a flat list in order of modules to build.
37122 var mods = this.topModule ? [ this.topModule ] : [];
37123 Roo.each(this.elmodules,function(e) { mods.push(e) });
37126 // add modules to their parents..
37127 var addMod = function(m) {
37128 // Roo.debug && Roo.log(m.modKey);
37132 m.modules.keySort('ASC', cmp );
37133 m.modules.each(addMod);
37135 // not sure if this is used any more..
37137 m.finalize.name = m.name + " (clean up) ";
37138 mods.push(m.finalize);
37142 if (this.topModule) {
37143 this.topModule.modules.keySort('ASC', cmp );
37144 this.topModule.modules.each(addMod);
37150 * Build the registered modules.
37151 * @param {Object} parent element.
37152 * @param {Function} optional method to call after module has been added.
37160 var mods = this.buildOrder();
37162 //this.allmods = mods;
37163 //Roo.debug && Roo.log(mods);
37165 if (!mods.length) { // should not happen
37166 throw "NO modules!!!";
37171 // flash it up as modal - so we store the mask!?
37172 Roo.MessageBox.show({ title: 'loading' });
37173 Roo.MessageBox.show({
37174 title: "Please wait...",
37175 msg: "Building Interface...",
37182 var total = mods.length;
37185 var progressRun = function() {
37186 if (!mods.length) {
37187 Roo.debug && Roo.log('hide?');
37188 Roo.MessageBox.hide();
37189 if (_this.topModule) {
37190 _this.topModule.fireEvent('buildcomplete', _this.topModule);
37196 var m = mods.shift();
37199 Roo.debug && Roo.log(m);
37200 // not sure if this is supported any more.. - modules that are are just function
37201 if (typeof(m) == 'function') {
37203 return progressRun.defer(10, _this);
37208 Roo.MessageBox.updateProgress(
37209 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
37211 (m.name ? (' - ' + m.name) : '')
37215 // is the module disabled?
37216 var disabled = (typeof(m.disabled) == 'function') ?
37217 m.disabled.call(m.module.disabled) : m.disabled;
37221 return progressRun(); // we do not update the display!
37227 // it's 10 on top level, and 1 on others??? why...
37228 return progressRun.defer(10, _this);
37231 progressRun.defer(1, _this);
37242 //<script type="text/javascript">
37247 * @extends Roo.LayoutDialog
37248 * A generic Login Dialog..... - only one needed in theory!?!?
37250 * Fires XComponent builder on success...
37253 * username,password, lang = for login actions.
37254 * check = 1 for periodic checking that sesion is valid.
37255 * passwordRequest = email request password
37256 * logout = 1 = to logout
37258 * Affects: (this id="????" elements)
37259 * loading (removed) (used to indicate application is loading)
37260 * loading-mask (hides) (used to hide application when it's building loading)
37266 * Myapp.login = Roo.Login({
37282 Roo.Login = function(cfg)
37288 Roo.apply(this,cfg);
37290 Roo.onReady(function() {
37296 Roo.Login.superclass.constructor.call(this, this);
37297 //this.addxtype(this.items[0]);
37303 Roo.extend(Roo.Login, Roo.LayoutDialog, {
37306 * @cfg {String} method
37307 * Method used to query for login details.
37312 * @cfg {String} url
37313 * URL to query login data. - eg. baseURL + '/Login.php'
37319 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
37324 * @property checkFails
37325 * Number of times we have attempted to get authentication check, and failed.
37330 * @property intervalID
37331 * The window interval that does the constant login checking.
37337 onLoad : function() // called on page load...
37341 if (Roo.get('loading')) { // clear any loading indicator..
37342 Roo.get('loading').remove();
37345 //this.switchLang('en'); // set the language to english..
37348 success: function(response, opts) { // check successfull...
37350 var res = this.processResponse(response);
37351 this.checkFails =0;
37352 if (!res.success) { // error!
37353 this.checkFails = 5;
37354 //console.log('call failure');
37355 return this.failure(response,opts);
37358 if (!res.data.id) { // id=0 == login failure.
37359 return this.show();
37363 //console.log(success);
37364 this.fillAuth(res.data);
37365 this.checkFails =0;
37366 Roo.XComponent.build();
37368 failure : this.show
37374 check: function(cfg) // called every so often to refresh cookie etc..
37376 if (cfg.again) { // could be undefined..
37379 this.checkFails = 0;
37382 if (this.sending) {
37383 if ( this.checkFails > 4) {
37384 Roo.MessageBox.alert("Error",
37385 "Error getting authentication status. - try reloading, or wait a while", function() {
37386 _this.sending = false;
37391 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
37394 this.sending = true;
37401 method: this.method,
37402 success: cfg.success || this.success,
37403 failure : cfg.failure || this.failure,
37413 window.onbeforeunload = function() { }; // false does not work for IE..
37423 failure : function() {
37424 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
37425 document.location = document.location.toString() + '?ts=' + Math.random();
37429 success : function() {
37430 _this.user = false;
37431 this.checkFails =0;
37433 document.location = document.location.toString() + '?ts=' + Math.random();
37440 processResponse : function (response)
37444 res = Roo.decode(response.responseText);
37446 if (typeof(res) != 'object') {
37447 res = { success : false, errorMsg : res, errors : true };
37449 if (typeof(res.success) == 'undefined') {
37450 res.success = false;
37454 res = { success : false, errorMsg : response.responseText, errors : true };
37459 success : function(response, opts) // check successfull...
37461 this.sending = false;
37462 var res = this.processResponse(response);
37463 if (!res.success) {
37464 return this.failure(response, opts);
37466 if (!res.data || !res.data.id) {
37467 return this.failure(response,opts);
37469 //console.log(res);
37470 this.fillAuth(res.data);
37472 this.checkFails =0;
37477 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37479 this.authUser = -1;
37480 this.sending = false;
37481 var res = this.processResponse(response);
37482 //console.log(res);
37483 if ( this.checkFails > 2) {
37485 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37486 "Error getting authentication status. - try reloading");
37489 opts.callCfg.again = true;
37490 this.check.defer(1000, this, [ opts.callCfg ]);
37496 fillAuth: function(au) {
37497 this.startAuthCheck();
37498 this.authUserId = au.id;
37499 this.authUser = au;
37500 this.lastChecked = new Date();
37501 this.fireEvent('refreshed', au);
37502 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37503 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37504 au.lang = au.lang || 'en';
37505 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37506 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37507 this.switchLang(au.lang );
37510 // open system... - -on setyp..
37511 if (this.authUserId < 0) {
37512 Roo.MessageBox.alert("Warning",
37513 "This is an open system - please set up a admin user with a password.");
37516 //Pman.onload(); // which should do nothing if it's a re-auth result...
37521 startAuthCheck : function() // starter for timeout checking..
37523 if (this.intervalID) { // timer already in place...
37527 this.intervalID = window.setInterval(function() {
37528 _this.check(false);
37529 }, 120000); // every 120 secs = 2mins..
37535 switchLang : function (lang)
37537 _T = typeof(_T) == 'undefined' ? false : _T;
37538 if (!_T || !lang.length) {
37542 if (!_T && lang != 'en') {
37543 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37547 if (typeof(_T.en) == 'undefined') {
37549 Roo.apply(_T.en, _T);
37552 if (typeof(_T[lang]) == 'undefined') {
37553 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37558 Roo.apply(_T, _T[lang]);
37559 // just need to set the text values for everything...
37561 /* this will not work ...
37565 function formLabel(name, val) {
37566 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37569 formLabel('password', "Password"+':');
37570 formLabel('username', "Email Address"+':');
37571 formLabel('lang', "Language"+':');
37572 this.dialog.setTitle("Login");
37573 this.dialog.buttons[0].setText("Forgot Password");
37574 this.dialog.buttons[1].setText("Login");
37593 collapsible: false,
37595 center: { // needed??
37598 // tabPosition: 'top',
37601 alwaysShowTabs: false
37605 show : function(dlg)
37607 //console.log(this);
37608 this.form = this.layout.getRegion('center').activePanel.form;
37609 this.form.dialog = dlg;
37610 this.buttons[0].form = this.form;
37611 this.buttons[0].dialog = dlg;
37612 this.buttons[1].form = this.form;
37613 this.buttons[1].dialog = dlg;
37615 //this.resizeToLogo.defer(1000,this);
37616 // this is all related to resizing for logos..
37617 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37619 // this.resizeToLogo.defer(1000,this);
37622 //var w = Ext.lib.Dom.getViewWidth() - 100;
37623 //var h = Ext.lib.Dom.getViewHeight() - 100;
37624 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37626 if (this.disabled) {
37631 if (this.user.id < 0) { // used for inital setup situations.
37635 if (this.intervalID) {
37636 // remove the timer
37637 window.clearInterval(this.intervalID);
37638 this.intervalID = false;
37642 if (Roo.get('loading')) {
37643 Roo.get('loading').remove();
37645 if (Roo.get('loading-mask')) {
37646 Roo.get('loading-mask').hide();
37649 //incomming._node = tnode;
37651 //this.dialog.modal = !modal;
37652 //this.dialog.show();
37656 this.form.setValues({
37657 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37658 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37661 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37662 if (this.form.findField('username').getValue().length > 0 ){
37663 this.form.findField('password').focus();
37665 this.form.findField('username').focus();
37673 xtype : 'ContentPanel',
37685 style : 'margin: 10px;',
37688 actionfailed : function(f, act) {
37689 // form can return { errors: .... }
37691 //act.result.errors // invalid form element list...
37692 //act.result.errorMsg// invalid form element list...
37694 this.dialog.el.unmask();
37695 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37696 "Login failed - communication error - try again.");
37699 actioncomplete: function(re, act) {
37701 Roo.state.Manager.set(
37702 this.dialog.realm + '.username',
37703 this.findField('username').getValue()
37705 Roo.state.Manager.set(
37706 this.dialog.realm + '.lang',
37707 this.findField('lang').getValue()
37710 this.dialog.fillAuth(act.result.data);
37712 this.dialog.hide();
37714 if (Roo.get('loading-mask')) {
37715 Roo.get('loading-mask').show();
37717 Roo.XComponent.build();
37725 xtype : 'TextField',
37727 fieldLabel: "Email Address",
37730 autoCreate : {tag: "input", type: "text", size: "20"}
37733 xtype : 'TextField',
37735 fieldLabel: "Password",
37736 inputType: 'password',
37739 autoCreate : {tag: "input", type: "text", size: "20"},
37741 specialkey : function(e,ev) {
37742 if (ev.keyCode == 13) {
37743 this.form.dialog.el.mask("Logging in");
37744 this.form.doAction('submit', {
37745 url: this.form.dialog.url,
37746 method: this.form.dialog.method
37753 xtype : 'ComboBox',
37755 fieldLabel: "Language",
37758 xtype : 'SimpleStore',
37759 fields: ['lang', 'ldisp'],
37761 [ 'en', 'English' ],
37762 [ 'zh_HK' , '\u7E41\u4E2D' ],
37763 [ 'zh_CN', '\u7C21\u4E2D' ]
37767 valueField : 'lang',
37768 hiddenName: 'lang',
37770 displayField:'ldisp',
37774 triggerAction: 'all',
37775 emptyText:'Select a Language...',
37776 selectOnFocus:true,
37778 select : function(cb, rec, ix) {
37779 this.form.switchLang(rec.data.lang);
37795 text : "Forgot Password",
37797 click : function() {
37798 //console.log(this);
37799 var n = this.form.findField('username').getValue();
37801 Roo.MessageBox.alert("Error", "Fill in your email address");
37805 url: this.dialog.url,
37809 method: this.dialog.method,
37810 success: function(response, opts) { // check successfull...
37812 var res = this.dialog.processResponse(response);
37813 if (!res.success) { // error!
37814 Roo.MessageBox.alert("Error" ,
37815 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37818 Roo.MessageBox.alert("Notice" ,
37819 "Please check you email for the Password Reset message");
37821 failure : function() {
37822 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37835 click : function () {
37837 this.dialog.el.mask("Logging in");
37838 this.form.doAction('submit', {
37839 url: this.dialog.url,
37840 method: this.dialog.method