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;
10795 // toolbar on the tabbar support...
10796 if (this.toolbar) {
10797 var tcfg = this.toolbar;
10798 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
10799 this.toolbar = new Roo.Toolbar(tcfg);
10800 if (Roo.isSafari) {
10801 var tbl = tcfg.container.child('table', true);
10802 tbl.setAttribute('width', '100%');
10809 Roo.TabPanel.superclass.constructor.call(this);
10812 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10814 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10816 tabPosition : "top",
10818 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10820 currentTabWidth : 0,
10822 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10826 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10830 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10832 preferredTabWidth : 175,
10834 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10836 resizeTabs : false,
10838 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10840 monitorResize : true,
10842 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
10847 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10848 * @param {String} id The id of the div to use <b>or create</b>
10849 * @param {String} text The text for the tab
10850 * @param {String} content (optional) Content to put in the TabPanelItem body
10851 * @param {Boolean} closable (optional) True to create a close icon on the tab
10852 * @return {Roo.TabPanelItem} The created TabPanelItem
10854 addTab : function(id, text, content, closable){
10855 var item = new Roo.TabPanelItem(this, id, text, closable);
10856 this.addTabItem(item);
10858 item.setContent(content);
10864 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10865 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10866 * @return {Roo.TabPanelItem}
10868 getTab : function(id){
10869 return this.items[id];
10873 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10874 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10876 hideTab : function(id){
10877 var t = this.items[id];
10880 this.hiddenCount++;
10881 this.autoSizeTabs();
10886 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10887 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10889 unhideTab : function(id){
10890 var t = this.items[id];
10892 t.setHidden(false);
10893 this.hiddenCount--;
10894 this.autoSizeTabs();
10899 * Adds an existing {@link Roo.TabPanelItem}.
10900 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10902 addTabItem : function(item){
10903 this.items[item.id] = item;
10904 this.items.push(item);
10905 if(this.resizeTabs){
10906 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10907 this.autoSizeTabs();
10914 * Removes a {@link Roo.TabPanelItem}.
10915 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10917 removeTab : function(id){
10918 var items = this.items;
10919 var tab = items[id];
10920 if(!tab) { return; }
10921 var index = items.indexOf(tab);
10922 if(this.active == tab && items.length > 1){
10923 var newTab = this.getNextAvailable(index);
10928 this.stripEl.dom.removeChild(tab.pnode.dom);
10929 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10930 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10932 items.splice(index, 1);
10933 delete this.items[tab.id];
10934 tab.fireEvent("close", tab);
10935 tab.purgeListeners();
10936 this.autoSizeTabs();
10939 getNextAvailable : function(start){
10940 var items = this.items;
10942 // look for a next tab that will slide over to
10943 // replace the one being removed
10944 while(index < items.length){
10945 var item = items[++index];
10946 if(item && !item.isHidden()){
10950 // if one isn't found select the previous tab (on the left)
10953 var item = items[--index];
10954 if(item && !item.isHidden()){
10962 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10963 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10965 disableTab : function(id){
10966 var tab = this.items[id];
10967 if(tab && this.active != tab){
10973 * Enables a {@link Roo.TabPanelItem} that is disabled.
10974 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10976 enableTab : function(id){
10977 var tab = this.items[id];
10982 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10983 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10984 * @return {Roo.TabPanelItem} The TabPanelItem.
10986 activate : function(id){
10987 var tab = this.items[id];
10991 if(tab == this.active || tab.disabled){
10995 this.fireEvent("beforetabchange", this, e, tab);
10996 if(e.cancel !== true && !tab.disabled){
10998 this.active.hide();
11000 this.active = this.items[id];
11001 this.active.show();
11002 this.fireEvent("tabchange", this, this.active);
11008 * Gets the active {@link Roo.TabPanelItem}.
11009 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
11011 getActiveTab : function(){
11012 return this.active;
11016 * Updates the tab body element to fit the height of the container element
11017 * for overflow scrolling
11018 * @param {Number} targetHeight (optional) Override the starting height from the elements height
11020 syncHeight : function(targetHeight){
11021 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
11022 var bm = this.bodyEl.getMargins();
11023 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
11024 this.bodyEl.setHeight(newHeight);
11028 onResize : function(){
11029 if(this.monitorResize){
11030 this.autoSizeTabs();
11035 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11037 beginUpdate : function(){
11038 this.updating = true;
11042 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11044 endUpdate : function(){
11045 this.updating = false;
11046 this.autoSizeTabs();
11050 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11052 autoSizeTabs : function(){
11053 var count = this.items.length;
11054 var vcount = count - this.hiddenCount;
11055 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11056 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11057 var availWidth = Math.floor(w / vcount);
11058 var b = this.stripBody;
11059 if(b.getWidth() > w){
11060 var tabs = this.items;
11061 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11062 if(availWidth < this.minTabWidth){
11063 /*if(!this.sleft){ // incomplete scrolling code
11064 this.createScrollButtons();
11067 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11070 if(this.currentTabWidth < this.preferredTabWidth){
11071 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11077 * Returns the number of tabs in this TabPanel.
11080 getCount : function(){
11081 return this.items.length;
11085 * Resizes all the tabs to the passed width
11086 * @param {Number} The new width
11088 setTabWidth : function(width){
11089 this.currentTabWidth = width;
11090 for(var i = 0, len = this.items.length; i < len; i++) {
11091 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11096 * Destroys this TabPanel
11097 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11099 destroy : function(removeEl){
11100 Roo.EventManager.removeResizeListener(this.onResize, this);
11101 for(var i = 0, len = this.items.length; i < len; i++){
11102 this.items[i].purgeListeners();
11104 if(removeEl === true){
11105 this.el.update("");
11112 * @class Roo.TabPanelItem
11113 * @extends Roo.util.Observable
11114 * Represents an individual item (tab plus body) in a TabPanel.
11115 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11116 * @param {String} id The id of this TabPanelItem
11117 * @param {String} text The text for the tab of this TabPanelItem
11118 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11120 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11122 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11123 * @type Roo.TabPanel
11125 this.tabPanel = tabPanel;
11127 * The id for this TabPanelItem
11132 this.disabled = false;
11136 this.loaded = false;
11137 this.closable = closable;
11140 * The body element for this TabPanelItem.
11141 * @type Roo.Element
11143 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11144 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11145 this.bodyEl.setStyle("display", "block");
11146 this.bodyEl.setStyle("zoom", "1");
11149 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11151 this.el = Roo.get(els.el, true);
11152 this.inner = Roo.get(els.inner, true);
11153 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11154 this.pnode = Roo.get(els.el.parentNode, true);
11155 this.el.on("mousedown", this.onTabMouseDown, this);
11156 this.el.on("click", this.onTabClick, this);
11159 var c = Roo.get(els.close, true);
11160 c.dom.title = this.closeText;
11161 c.addClassOnOver("close-over");
11162 c.on("click", this.closeClick, this);
11168 * Fires when this tab becomes the active tab.
11169 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11170 * @param {Roo.TabPanelItem} this
11174 * @event beforeclose
11175 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11176 * @param {Roo.TabPanelItem} this
11177 * @param {Object} e Set cancel to true on this object to cancel the close.
11179 "beforeclose": true,
11182 * Fires when this tab is closed.
11183 * @param {Roo.TabPanelItem} this
11187 * @event deactivate
11188 * Fires when this tab is no longer the active tab.
11189 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11190 * @param {Roo.TabPanelItem} this
11192 "deactivate" : true
11194 this.hidden = false;
11196 Roo.TabPanelItem.superclass.constructor.call(this);
11199 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11200 purgeListeners : function(){
11201 Roo.util.Observable.prototype.purgeListeners.call(this);
11202 this.el.removeAllListeners();
11205 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11208 this.pnode.addClass("on");
11211 this.tabPanel.stripWrap.repaint();
11213 this.fireEvent("activate", this.tabPanel, this);
11217 * Returns true if this tab is the active tab.
11218 * @return {Boolean}
11220 isActive : function(){
11221 return this.tabPanel.getActiveTab() == this;
11225 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11228 this.pnode.removeClass("on");
11230 this.fireEvent("deactivate", this.tabPanel, this);
11233 hideAction : function(){
11234 this.bodyEl.hide();
11235 this.bodyEl.setStyle("position", "absolute");
11236 this.bodyEl.setLeft("-20000px");
11237 this.bodyEl.setTop("-20000px");
11240 showAction : function(){
11241 this.bodyEl.setStyle("position", "relative");
11242 this.bodyEl.setTop("");
11243 this.bodyEl.setLeft("");
11244 this.bodyEl.show();
11248 * Set the tooltip for the tab.
11249 * @param {String} tooltip The tab's tooltip
11251 setTooltip : function(text){
11252 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11253 this.textEl.dom.qtip = text;
11254 this.textEl.dom.removeAttribute('title');
11256 this.textEl.dom.title = text;
11260 onTabClick : function(e){
11261 e.preventDefault();
11262 this.tabPanel.activate(this.id);
11265 onTabMouseDown : function(e){
11266 e.preventDefault();
11267 this.tabPanel.activate(this.id);
11270 getWidth : function(){
11271 return this.inner.getWidth();
11274 setWidth : function(width){
11275 var iwidth = width - this.pnode.getPadding("lr");
11276 this.inner.setWidth(iwidth);
11277 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11278 this.pnode.setWidth(width);
11282 * Show or hide the tab
11283 * @param {Boolean} hidden True to hide or false to show.
11285 setHidden : function(hidden){
11286 this.hidden = hidden;
11287 this.pnode.setStyle("display", hidden ? "none" : "");
11291 * Returns true if this tab is "hidden"
11292 * @return {Boolean}
11294 isHidden : function(){
11295 return this.hidden;
11299 * Returns the text for this tab
11302 getText : function(){
11306 autoSize : function(){
11307 //this.el.beginMeasure();
11308 this.textEl.setWidth(1);
11309 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11310 //this.el.endMeasure();
11314 * Sets the text for the tab (Note: this also sets the tooltip text)
11315 * @param {String} text The tab's text and tooltip
11317 setText : function(text){
11319 this.textEl.update(text);
11320 this.setTooltip(text);
11321 if(!this.tabPanel.resizeTabs){
11326 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11328 activate : function(){
11329 this.tabPanel.activate(this.id);
11333 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11335 disable : function(){
11336 if(this.tabPanel.active != this){
11337 this.disabled = true;
11338 this.pnode.addClass("disabled");
11343 * Enables this TabPanelItem if it was previously disabled.
11345 enable : function(){
11346 this.disabled = false;
11347 this.pnode.removeClass("disabled");
11351 * Sets the content for this TabPanelItem.
11352 * @param {String} content The content
11353 * @param {Boolean} loadScripts true to look for and load scripts
11355 setContent : function(content, loadScripts){
11356 this.bodyEl.update(content, loadScripts);
11360 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11361 * @return {Roo.UpdateManager} The UpdateManager
11363 getUpdateManager : function(){
11364 return this.bodyEl.getUpdateManager();
11368 * Set a URL to be used to load the content for this TabPanelItem.
11369 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11370 * @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)
11371 * @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)
11372 * @return {Roo.UpdateManager} The UpdateManager
11374 setUrl : function(url, params, loadOnce){
11375 if(this.refreshDelegate){
11376 this.un('activate', this.refreshDelegate);
11378 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11379 this.on("activate", this.refreshDelegate);
11380 return this.bodyEl.getUpdateManager();
11384 _handleRefresh : function(url, params, loadOnce){
11385 if(!loadOnce || !this.loaded){
11386 var updater = this.bodyEl.getUpdateManager();
11387 updater.update(url, params, this._setLoaded.createDelegate(this));
11392 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11393 * Will fail silently if the setUrl method has not been called.
11394 * This does not activate the panel, just updates its content.
11396 refresh : function(){
11397 if(this.refreshDelegate){
11398 this.loaded = false;
11399 this.refreshDelegate();
11404 _setLoaded : function(){
11405 this.loaded = true;
11409 closeClick : function(e){
11412 this.fireEvent("beforeclose", this, o);
11413 if(o.cancel !== true){
11414 this.tabPanel.removeTab(this.id);
11418 * The text displayed in the tooltip for the close icon.
11421 closeText : "Close this tab"
11425 Roo.TabPanel.prototype.createStrip = function(container){
11426 var strip = document.createElement("div");
11427 strip.className = "x-tabs-wrap";
11428 container.appendChild(strip);
11432 Roo.TabPanel.prototype.createStripList = function(strip){
11433 // div wrapper for retard IE
11434 // returns the "tr" element.
11435 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
11436 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
11437 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
11438 return strip.firstChild.firstChild.firstChild.firstChild;
11441 Roo.TabPanel.prototype.createBody = function(container){
11442 var body = document.createElement("div");
11443 Roo.id(body, "tab-body");
11444 Roo.fly(body).addClass("x-tabs-body");
11445 container.appendChild(body);
11449 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11450 var body = Roo.getDom(id);
11452 body = document.createElement("div");
11455 Roo.fly(body).addClass("x-tabs-item-body");
11456 bodyEl.insertBefore(body, bodyEl.firstChild);
11460 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11461 var td = document.createElement("td");
11462 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
11463 //stripEl.appendChild(td);
11465 td.className = "x-tabs-closable";
11466 if(!this.closeTpl){
11467 this.closeTpl = new Roo.Template(
11468 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11469 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11470 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11473 var el = this.closeTpl.overwrite(td, {"text": text});
11474 var close = el.getElementsByTagName("div")[0];
11475 var inner = el.getElementsByTagName("em")[0];
11476 return {"el": el, "close": close, "inner": inner};
11479 this.tabTpl = new Roo.Template(
11480 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11481 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11484 var el = this.tabTpl.overwrite(td, {"text": text});
11485 var inner = el.getElementsByTagName("em")[0];
11486 return {"el": el, "inner": inner};
11490 * Ext JS Library 1.1.1
11491 * Copyright(c) 2006-2007, Ext JS, LLC.
11493 * Originally Released Under LGPL - original licence link has changed is not relivant.
11496 * <script type="text/javascript">
11500 * @class Roo.Button
11501 * @extends Roo.util.Observable
11502 * Simple Button class
11503 * @cfg {String} text The button text
11504 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11505 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11506 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11507 * @cfg {Object} scope The scope of the handler
11508 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11509 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11510 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11511 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11512 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11513 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11514 applies if enableToggle = true)
11515 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11516 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11517 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11519 * Create a new button
11520 * @param {Object} config The config object
11522 Roo.Button = function(renderTo, config)
11526 renderTo = config.renderTo || false;
11529 Roo.apply(this, config);
11533 * Fires when this button is clicked
11534 * @param {Button} this
11535 * @param {EventObject} e The click event
11540 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11541 * @param {Button} this
11542 * @param {Boolean} pressed
11547 * Fires when the mouse hovers over the button
11548 * @param {Button} this
11549 * @param {Event} e The event object
11551 'mouseover' : true,
11554 * Fires when the mouse exits the button
11555 * @param {Button} this
11556 * @param {Event} e The event object
11561 * Fires when the button is rendered
11562 * @param {Button} this
11567 this.menu = Roo.menu.MenuMgr.get(this.menu);
11569 // register listeners first!! - so render can be captured..
11570 Roo.util.Observable.call(this);
11572 this.render(renderTo);
11578 Roo.extend(Roo.Button, Roo.util.Observable, {
11584 * Read-only. True if this button is hidden
11589 * Read-only. True if this button is disabled
11594 * Read-only. True if this button is pressed (only if enableToggle = true)
11600 * @cfg {Number} tabIndex
11601 * The DOM tabIndex for this button (defaults to undefined)
11603 tabIndex : undefined,
11606 * @cfg {Boolean} enableToggle
11607 * True to enable pressed/not pressed toggling (defaults to false)
11609 enableToggle: false,
11611 * @cfg {Mixed} menu
11612 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11616 * @cfg {String} menuAlign
11617 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11619 menuAlign : "tl-bl?",
11622 * @cfg {String} iconCls
11623 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11625 iconCls : undefined,
11627 * @cfg {String} type
11628 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11633 menuClassTarget: 'tr',
11636 * @cfg {String} clickEvent
11637 * The type of event to map to the button's event handler (defaults to 'click')
11639 clickEvent : 'click',
11642 * @cfg {Boolean} handleMouseEvents
11643 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11645 handleMouseEvents : true,
11648 * @cfg {String} tooltipType
11649 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11651 tooltipType : 'qtip',
11654 * @cfg {String} cls
11655 * A CSS class to apply to the button's main element.
11659 * @cfg {Roo.Template} template (Optional)
11660 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11661 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11662 * require code modifications if required elements (e.g. a button) aren't present.
11666 render : function(renderTo){
11668 if(this.hideParent){
11669 this.parentEl = Roo.get(renderTo);
11671 if(!this.dhconfig){
11672 if(!this.template){
11673 if(!Roo.Button.buttonTemplate){
11674 // hideous table template
11675 Roo.Button.buttonTemplate = new Roo.Template(
11676 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11677 '<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>',
11678 "</tr></tbody></table>");
11680 this.template = Roo.Button.buttonTemplate;
11682 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11683 var btnEl = btn.child("button:first");
11684 btnEl.on('focus', this.onFocus, this);
11685 btnEl.on('blur', this.onBlur, this);
11687 btn.addClass(this.cls);
11690 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11693 btnEl.addClass(this.iconCls);
11695 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11698 if(this.tabIndex !== undefined){
11699 btnEl.dom.tabIndex = this.tabIndex;
11702 if(typeof this.tooltip == 'object'){
11703 Roo.QuickTips.tips(Roo.apply({
11707 btnEl.dom[this.tooltipType] = this.tooltip;
11711 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11715 this.el.dom.id = this.el.id = this.id;
11718 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11719 this.menu.on("show", this.onMenuShow, this);
11720 this.menu.on("hide", this.onMenuHide, this);
11722 btn.addClass("x-btn");
11723 if(Roo.isIE && !Roo.isIE7){
11724 this.autoWidth.defer(1, this);
11728 if(this.handleMouseEvents){
11729 btn.on("mouseover", this.onMouseOver, this);
11730 btn.on("mouseout", this.onMouseOut, this);
11731 btn.on("mousedown", this.onMouseDown, this);
11733 btn.on(this.clickEvent, this.onClick, this);
11734 //btn.on("mouseup", this.onMouseUp, this);
11741 Roo.ButtonToggleMgr.register(this);
11743 this.el.addClass("x-btn-pressed");
11746 var repeater = new Roo.util.ClickRepeater(btn,
11747 typeof this.repeat == "object" ? this.repeat : {}
11749 repeater.on("click", this.onClick, this);
11752 this.fireEvent('render', this);
11756 * Returns the button's underlying element
11757 * @return {Roo.Element} The element
11759 getEl : function(){
11764 * Destroys this Button and removes any listeners.
11766 destroy : function(){
11767 Roo.ButtonToggleMgr.unregister(this);
11768 this.el.removeAllListeners();
11769 this.purgeListeners();
11774 autoWidth : function(){
11776 this.el.setWidth("auto");
11777 if(Roo.isIE7 && Roo.isStrict){
11778 var ib = this.el.child('button');
11779 if(ib && ib.getWidth() > 20){
11781 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11786 this.el.beginMeasure();
11788 if(this.el.getWidth() < this.minWidth){
11789 this.el.setWidth(this.minWidth);
11792 this.el.endMeasure();
11799 * Assigns this button's click handler
11800 * @param {Function} handler The function to call when the button is clicked
11801 * @param {Object} scope (optional) Scope for the function passed in
11803 setHandler : function(handler, scope){
11804 this.handler = handler;
11805 this.scope = scope;
11809 * Sets this button's text
11810 * @param {String} text The button text
11812 setText : function(text){
11815 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11821 * Gets the text for this button
11822 * @return {String} The button text
11824 getText : function(){
11832 this.hidden = false;
11834 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11842 this.hidden = true;
11844 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11849 * Convenience function for boolean show/hide
11850 * @param {Boolean} visible True to show, false to hide
11852 setVisible: function(visible){
11861 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11862 * @param {Boolean} state (optional) Force a particular state
11864 toggle : function(state){
11865 state = state === undefined ? !this.pressed : state;
11866 if(state != this.pressed){
11868 this.el.addClass("x-btn-pressed");
11869 this.pressed = true;
11870 this.fireEvent("toggle", this, true);
11872 this.el.removeClass("x-btn-pressed");
11873 this.pressed = false;
11874 this.fireEvent("toggle", this, false);
11876 if(this.toggleHandler){
11877 this.toggleHandler.call(this.scope || this, this, state);
11885 focus : function(){
11886 this.el.child('button:first').focus();
11890 * Disable this button
11892 disable : function(){
11894 this.el.addClass("x-btn-disabled");
11896 this.disabled = true;
11900 * Enable this button
11902 enable : function(){
11904 this.el.removeClass("x-btn-disabled");
11906 this.disabled = false;
11910 * Convenience function for boolean enable/disable
11911 * @param {Boolean} enabled True to enable, false to disable
11913 setDisabled : function(v){
11914 this[v !== true ? "enable" : "disable"]();
11918 onClick : function(e){
11920 e.preventDefault();
11925 if(!this.disabled){
11926 if(this.enableToggle){
11929 if(this.menu && !this.menu.isVisible()){
11930 this.menu.show(this.el, this.menuAlign);
11932 this.fireEvent("click", this, e);
11934 this.el.removeClass("x-btn-over");
11935 this.handler.call(this.scope || this, this, e);
11940 onMouseOver : function(e){
11941 if(!this.disabled){
11942 this.el.addClass("x-btn-over");
11943 this.fireEvent('mouseover', this, e);
11947 onMouseOut : function(e){
11948 if(!e.within(this.el, true)){
11949 this.el.removeClass("x-btn-over");
11950 this.fireEvent('mouseout', this, e);
11954 onFocus : function(e){
11955 if(!this.disabled){
11956 this.el.addClass("x-btn-focus");
11960 onBlur : function(e){
11961 this.el.removeClass("x-btn-focus");
11964 onMouseDown : function(e){
11965 if(!this.disabled && e.button == 0){
11966 this.el.addClass("x-btn-click");
11967 Roo.get(document).on('mouseup', this.onMouseUp, this);
11971 onMouseUp : function(e){
11973 this.el.removeClass("x-btn-click");
11974 Roo.get(document).un('mouseup', this.onMouseUp, this);
11978 onMenuShow : function(e){
11979 this.el.addClass("x-btn-menu-active");
11982 onMenuHide : function(e){
11983 this.el.removeClass("x-btn-menu-active");
11987 // Private utility class used by Button
11988 Roo.ButtonToggleMgr = function(){
11991 function toggleGroup(btn, state){
11993 var g = groups[btn.toggleGroup];
11994 for(var i = 0, l = g.length; i < l; i++){
11996 g[i].toggle(false);
12003 register : function(btn){
12004 if(!btn.toggleGroup){
12007 var g = groups[btn.toggleGroup];
12009 g = groups[btn.toggleGroup] = [];
12012 btn.on("toggle", toggleGroup);
12015 unregister : function(btn){
12016 if(!btn.toggleGroup){
12019 var g = groups[btn.toggleGroup];
12022 btn.un("toggle", toggleGroup);
12028 * Ext JS Library 1.1.1
12029 * Copyright(c) 2006-2007, Ext JS, LLC.
12031 * Originally Released Under LGPL - original licence link has changed is not relivant.
12034 * <script type="text/javascript">
12038 * @class Roo.SplitButton
12039 * @extends Roo.Button
12040 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12041 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
12042 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12043 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12044 * @cfg {String} arrowTooltip The title attribute of the arrow
12046 * Create a new menu button
12047 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12048 * @param {Object} config The config object
12050 Roo.SplitButton = function(renderTo, config){
12051 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12053 * @event arrowclick
12054 * Fires when this button's arrow is clicked
12055 * @param {SplitButton} this
12056 * @param {EventObject} e The click event
12058 this.addEvents({"arrowclick":true});
12061 Roo.extend(Roo.SplitButton, Roo.Button, {
12062 render : function(renderTo){
12063 // this is one sweet looking template!
12064 var tpl = new Roo.Template(
12065 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12066 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12067 '<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>',
12068 "</tbody></table></td><td>",
12069 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12070 '<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>',
12071 "</tbody></table></td></tr></table>"
12073 var btn = tpl.append(renderTo, [this.text, this.type], true);
12074 var btnEl = btn.child("button");
12076 btn.addClass(this.cls);
12079 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12082 btnEl.addClass(this.iconCls);
12084 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12088 if(this.handleMouseEvents){
12089 btn.on("mouseover", this.onMouseOver, this);
12090 btn.on("mouseout", this.onMouseOut, this);
12091 btn.on("mousedown", this.onMouseDown, this);
12092 btn.on("mouseup", this.onMouseUp, this);
12094 btn.on(this.clickEvent, this.onClick, this);
12096 if(typeof this.tooltip == 'object'){
12097 Roo.QuickTips.tips(Roo.apply({
12101 btnEl.dom[this.tooltipType] = this.tooltip;
12104 if(this.arrowTooltip){
12105 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12114 this.el.addClass("x-btn-pressed");
12116 if(Roo.isIE && !Roo.isIE7){
12117 this.autoWidth.defer(1, this);
12122 this.menu.on("show", this.onMenuShow, this);
12123 this.menu.on("hide", this.onMenuHide, this);
12125 this.fireEvent('render', this);
12129 autoWidth : function(){
12131 var tbl = this.el.child("table:first");
12132 var tbl2 = this.el.child("table:last");
12133 this.el.setWidth("auto");
12134 tbl.setWidth("auto");
12135 if(Roo.isIE7 && Roo.isStrict){
12136 var ib = this.el.child('button:first');
12137 if(ib && ib.getWidth() > 20){
12139 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12144 this.el.beginMeasure();
12146 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12147 tbl.setWidth(this.minWidth-tbl2.getWidth());
12150 this.el.endMeasure();
12153 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12157 * Sets this button's click handler
12158 * @param {Function} handler The function to call when the button is clicked
12159 * @param {Object} scope (optional) Scope for the function passed above
12161 setHandler : function(handler, scope){
12162 this.handler = handler;
12163 this.scope = scope;
12167 * Sets this button's arrow click handler
12168 * @param {Function} handler The function to call when the arrow is clicked
12169 * @param {Object} scope (optional) Scope for the function passed above
12171 setArrowHandler : function(handler, scope){
12172 this.arrowHandler = handler;
12173 this.scope = scope;
12179 focus : function(){
12181 this.el.child("button:first").focus();
12186 onClick : function(e){
12187 e.preventDefault();
12188 if(!this.disabled){
12189 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12190 if(this.menu && !this.menu.isVisible()){
12191 this.menu.show(this.el, this.menuAlign);
12193 this.fireEvent("arrowclick", this, e);
12194 if(this.arrowHandler){
12195 this.arrowHandler.call(this.scope || this, this, e);
12198 this.fireEvent("click", this, e);
12200 this.handler.call(this.scope || this, this, e);
12206 onMouseDown : function(e){
12207 if(!this.disabled){
12208 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12212 onMouseUp : function(e){
12213 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12218 // backwards compat
12219 Roo.MenuButton = Roo.SplitButton;/*
12221 * Ext JS Library 1.1.1
12222 * Copyright(c) 2006-2007, Ext JS, LLC.
12224 * Originally Released Under LGPL - original licence link has changed is not relivant.
12227 * <script type="text/javascript">
12231 * @class Roo.Toolbar
12232 * Basic Toolbar class.
12234 * Creates a new Toolbar
12235 * @param {Object} config The config object
12237 Roo.Toolbar = function(container, buttons, config)
12239 /// old consturctor format still supported..
12240 if(container instanceof Array){ // omit the container for later rendering
12241 buttons = container;
12245 if (typeof(container) == 'object' && container.xtype) {
12246 config = container;
12247 container = config.container;
12248 buttons = config.buttons; // not really - use items!!
12251 if (config && config.items) {
12252 xitems = config.items;
12253 delete config.items;
12255 Roo.apply(this, config);
12256 this.buttons = buttons;
12259 this.render(container);
12261 Roo.each(xitems, function(b) {
12267 Roo.Toolbar.prototype = {
12269 * @cfg {Roo.data.Store} items
12270 * array of button configs or elements to add
12274 * @cfg {String/HTMLElement/Element} container
12275 * The id or element that will contain the toolbar
12278 render : function(ct){
12279 this.el = Roo.get(ct);
12281 this.el.addClass(this.cls);
12283 // using a table allows for vertical alignment
12284 // 100% width is needed by Safari...
12285 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12286 this.tr = this.el.child("tr", true);
12288 this.items = new Roo.util.MixedCollection(false, function(o){
12289 return o.id || ("item" + (++autoId));
12292 this.add.apply(this, this.buttons);
12293 delete this.buttons;
12298 * Adds element(s) to the toolbar -- this function takes a variable number of
12299 * arguments of mixed type and adds them to the toolbar.
12300 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12302 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12303 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12304 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12305 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12306 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12307 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12308 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12309 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12310 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12312 * @param {Mixed} arg2
12313 * @param {Mixed} etc.
12316 var a = arguments, l = a.length;
12317 for(var i = 0; i < l; i++){
12322 _add : function(el) {
12325 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12328 if (el.applyTo){ // some kind of form field
12329 return this.addField(el);
12331 if (el.render){ // some kind of Toolbar.Item
12332 return this.addItem(el);
12334 if (typeof el == "string"){ // string
12335 if(el == "separator" || el == "-"){
12336 return this.addSeparator();
12339 return this.addSpacer();
12342 return this.addFill();
12344 return this.addText(el);
12347 if(el.tagName){ // element
12348 return this.addElement(el);
12350 if(typeof el == "object"){ // must be button config?
12351 return this.addButton(el);
12353 // and now what?!?!
12359 * Add an Xtype element
12360 * @param {Object} xtype Xtype Object
12361 * @return {Object} created Object
12363 addxtype : function(e){
12364 return this.add(e);
12368 * Returns the Element for this toolbar.
12369 * @return {Roo.Element}
12371 getEl : function(){
12377 * @return {Roo.Toolbar.Item} The separator item
12379 addSeparator : function(){
12380 return this.addItem(new Roo.Toolbar.Separator());
12384 * Adds a spacer element
12385 * @return {Roo.Toolbar.Spacer} The spacer item
12387 addSpacer : function(){
12388 return this.addItem(new Roo.Toolbar.Spacer());
12392 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12393 * @return {Roo.Toolbar.Fill} The fill item
12395 addFill : function(){
12396 return this.addItem(new Roo.Toolbar.Fill());
12400 * Adds any standard HTML element to the toolbar
12401 * @param {String/HTMLElement/Element} el The element or id of the element to add
12402 * @return {Roo.Toolbar.Item} The element's item
12404 addElement : function(el){
12405 return this.addItem(new Roo.Toolbar.Item(el));
12408 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12409 * @type Roo.util.MixedCollection
12414 * Adds any Toolbar.Item or subclass
12415 * @param {Roo.Toolbar.Item} item
12416 * @return {Roo.Toolbar.Item} The item
12418 addItem : function(item){
12419 var td = this.nextBlock();
12421 this.items.add(item);
12426 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12427 * @param {Object/Array} config A button config or array of configs
12428 * @return {Roo.Toolbar.Button/Array}
12430 addButton : function(config){
12431 if(config instanceof Array){
12433 for(var i = 0, len = config.length; i < len; i++) {
12434 buttons.push(this.addButton(config[i]));
12439 if(!(config instanceof Roo.Toolbar.Button)){
12441 new Roo.Toolbar.SplitButton(config) :
12442 new Roo.Toolbar.Button(config);
12444 var td = this.nextBlock();
12451 * Adds text to the toolbar
12452 * @param {String} text The text to add
12453 * @return {Roo.Toolbar.Item} The element's item
12455 addText : function(text){
12456 return this.addItem(new Roo.Toolbar.TextItem(text));
12460 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12461 * @param {Number} index The index where the item is to be inserted
12462 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12463 * @return {Roo.Toolbar.Button/Item}
12465 insertButton : function(index, item){
12466 if(item instanceof Array){
12468 for(var i = 0, len = item.length; i < len; i++) {
12469 buttons.push(this.insertButton(index + i, item[i]));
12473 if (!(item instanceof Roo.Toolbar.Button)){
12474 item = new Roo.Toolbar.Button(item);
12476 var td = document.createElement("td");
12477 this.tr.insertBefore(td, this.tr.childNodes[index]);
12479 this.items.insert(index, item);
12484 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12485 * @param {Object} config
12486 * @return {Roo.Toolbar.Item} The element's item
12488 addDom : function(config, returnEl){
12489 var td = this.nextBlock();
12490 Roo.DomHelper.overwrite(td, config);
12491 var ti = new Roo.Toolbar.Item(td.firstChild);
12493 this.items.add(ti);
12498 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12499 * @type Roo.util.MixedCollection
12504 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12505 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12506 * @param {Roo.form.Field} field
12507 * @return {Roo.ToolbarItem}
12511 addField : function(field) {
12512 if (!this.fields) {
12514 this.fields = new Roo.util.MixedCollection(false, function(o){
12515 return o.id || ("item" + (++autoId));
12520 var td = this.nextBlock();
12522 var ti = new Roo.Toolbar.Item(td.firstChild);
12524 this.items.add(ti);
12525 this.fields.add(field);
12536 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12537 this.el.child('div').hide();
12545 this.el.child('div').show();
12549 nextBlock : function(){
12550 var td = document.createElement("td");
12551 this.tr.appendChild(td);
12556 destroy : function(){
12557 if(this.items){ // rendered?
12558 Roo.destroy.apply(Roo, this.items.items);
12560 if(this.fields){ // rendered?
12561 Roo.destroy.apply(Roo, this.fields.items);
12563 Roo.Element.uncache(this.el, this.tr);
12568 * @class Roo.Toolbar.Item
12569 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12571 * Creates a new Item
12572 * @param {HTMLElement} el
12574 Roo.Toolbar.Item = function(el){
12575 this.el = Roo.getDom(el);
12576 this.id = Roo.id(this.el);
12577 this.hidden = false;
12580 Roo.Toolbar.Item.prototype = {
12583 * Get this item's HTML Element
12584 * @return {HTMLElement}
12586 getEl : function(){
12591 render : function(td){
12593 td.appendChild(this.el);
12597 * Removes and destroys this item.
12599 destroy : function(){
12600 this.td.parentNode.removeChild(this.td);
12607 this.hidden = false;
12608 this.td.style.display = "";
12615 this.hidden = true;
12616 this.td.style.display = "none";
12620 * Convenience function for boolean show/hide.
12621 * @param {Boolean} visible true to show/false to hide
12623 setVisible: function(visible){
12632 * Try to focus this item.
12634 focus : function(){
12635 Roo.fly(this.el).focus();
12639 * Disables this item.
12641 disable : function(){
12642 Roo.fly(this.td).addClass("x-item-disabled");
12643 this.disabled = true;
12644 this.el.disabled = true;
12648 * Enables this item.
12650 enable : function(){
12651 Roo.fly(this.td).removeClass("x-item-disabled");
12652 this.disabled = false;
12653 this.el.disabled = false;
12659 * @class Roo.Toolbar.Separator
12660 * @extends Roo.Toolbar.Item
12661 * A simple toolbar separator class
12663 * Creates a new Separator
12665 Roo.Toolbar.Separator = function(){
12666 var s = document.createElement("span");
12667 s.className = "ytb-sep";
12668 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12670 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12671 enable:Roo.emptyFn,
12672 disable:Roo.emptyFn,
12677 * @class Roo.Toolbar.Spacer
12678 * @extends Roo.Toolbar.Item
12679 * A simple element that adds extra horizontal space to a toolbar.
12681 * Creates a new Spacer
12683 Roo.Toolbar.Spacer = function(){
12684 var s = document.createElement("div");
12685 s.className = "ytb-spacer";
12686 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12688 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12689 enable:Roo.emptyFn,
12690 disable:Roo.emptyFn,
12695 * @class Roo.Toolbar.Fill
12696 * @extends Roo.Toolbar.Spacer
12697 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12699 * Creates a new Spacer
12701 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12703 render : function(td){
12704 td.style.width = '100%';
12705 Roo.Toolbar.Fill.superclass.render.call(this, td);
12710 * @class Roo.Toolbar.TextItem
12711 * @extends Roo.Toolbar.Item
12712 * A simple class that renders text directly into a toolbar.
12714 * Creates a new TextItem
12715 * @param {String} text
12717 Roo.Toolbar.TextItem = function(text){
12718 if (typeof(text) == 'object') {
12721 var s = document.createElement("span");
12722 s.className = "ytb-text";
12723 s.innerHTML = text;
12724 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12726 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12727 enable:Roo.emptyFn,
12728 disable:Roo.emptyFn,
12733 * @class Roo.Toolbar.Button
12734 * @extends Roo.Button
12735 * A button that renders into a toolbar.
12737 * Creates a new Button
12738 * @param {Object} config A standard {@link Roo.Button} config object
12740 Roo.Toolbar.Button = function(config){
12741 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12743 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12744 render : function(td){
12746 Roo.Toolbar.Button.superclass.render.call(this, td);
12750 * Removes and destroys this button
12752 destroy : function(){
12753 Roo.Toolbar.Button.superclass.destroy.call(this);
12754 this.td.parentNode.removeChild(this.td);
12758 * Shows this button
12761 this.hidden = false;
12762 this.td.style.display = "";
12766 * Hides this button
12769 this.hidden = true;
12770 this.td.style.display = "none";
12774 * Disables this item
12776 disable : function(){
12777 Roo.fly(this.td).addClass("x-item-disabled");
12778 this.disabled = true;
12782 * Enables this item
12784 enable : function(){
12785 Roo.fly(this.td).removeClass("x-item-disabled");
12786 this.disabled = false;
12789 // backwards compat
12790 Roo.ToolbarButton = Roo.Toolbar.Button;
12793 * @class Roo.Toolbar.SplitButton
12794 * @extends Roo.SplitButton
12795 * A menu button that renders into a toolbar.
12797 * Creates a new SplitButton
12798 * @param {Object} config A standard {@link Roo.SplitButton} config object
12800 Roo.Toolbar.SplitButton = function(config){
12801 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12803 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12804 render : function(td){
12806 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12810 * Removes and destroys this button
12812 destroy : function(){
12813 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12814 this.td.parentNode.removeChild(this.td);
12818 * Shows this button
12821 this.hidden = false;
12822 this.td.style.display = "";
12826 * Hides this button
12829 this.hidden = true;
12830 this.td.style.display = "none";
12834 // backwards compat
12835 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12837 * Ext JS Library 1.1.1
12838 * Copyright(c) 2006-2007, Ext JS, LLC.
12840 * Originally Released Under LGPL - original licence link has changed is not relivant.
12843 * <script type="text/javascript">
12847 * @class Roo.PagingToolbar
12848 * @extends Roo.Toolbar
12849 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12851 * Create a new PagingToolbar
12852 * @param {Object} config The config object
12854 Roo.PagingToolbar = function(el, ds, config)
12856 // old args format still supported... - xtype is prefered..
12857 if (typeof(el) == 'object' && el.xtype) {
12858 // created from xtype...
12860 ds = el.dataSource;
12861 el = config.container;
12864 if (config.items) {
12865 items = config.items;
12869 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12872 this.renderButtons(this.el);
12875 // supprot items array.
12877 Roo.each(items, function(e) {
12878 this.add(Roo.factory(e));
12883 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12885 * @cfg {Roo.data.Store} dataSource
12886 * The underlying data store providing the paged data
12889 * @cfg {String/HTMLElement/Element} container
12890 * container The id or element that will contain the toolbar
12893 * @cfg {Boolean} displayInfo
12894 * True to display the displayMsg (defaults to false)
12897 * @cfg {Number} pageSize
12898 * The number of records to display per page (defaults to 20)
12902 * @cfg {String} displayMsg
12903 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12905 displayMsg : 'Displaying {0} - {1} of {2}',
12907 * @cfg {String} emptyMsg
12908 * The message to display when no records are found (defaults to "No data to display")
12910 emptyMsg : 'No data to display',
12912 * Customizable piece of the default paging text (defaults to "Page")
12915 beforePageText : "Page",
12917 * Customizable piece of the default paging text (defaults to "of %0")
12920 afterPageText : "of {0}",
12922 * Customizable piece of the default paging text (defaults to "First Page")
12925 firstText : "First Page",
12927 * Customizable piece of the default paging text (defaults to "Previous Page")
12930 prevText : "Previous Page",
12932 * Customizable piece of the default paging text (defaults to "Next Page")
12935 nextText : "Next Page",
12937 * Customizable piece of the default paging text (defaults to "Last Page")
12940 lastText : "Last Page",
12942 * Customizable piece of the default paging text (defaults to "Refresh")
12945 refreshText : "Refresh",
12948 renderButtons : function(el){
12949 Roo.PagingToolbar.superclass.render.call(this, el);
12950 this.first = this.addButton({
12951 tooltip: this.firstText,
12952 cls: "x-btn-icon x-grid-page-first",
12954 handler: this.onClick.createDelegate(this, ["first"])
12956 this.prev = this.addButton({
12957 tooltip: this.prevText,
12958 cls: "x-btn-icon x-grid-page-prev",
12960 handler: this.onClick.createDelegate(this, ["prev"])
12962 //this.addSeparator();
12963 this.add(this.beforePageText);
12964 this.field = Roo.get(this.addDom({
12969 cls: "x-grid-page-number"
12971 this.field.on("keydown", this.onPagingKeydown, this);
12972 this.field.on("focus", function(){this.dom.select();});
12973 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12974 this.field.setHeight(18);
12975 //this.addSeparator();
12976 this.next = this.addButton({
12977 tooltip: this.nextText,
12978 cls: "x-btn-icon x-grid-page-next",
12980 handler: this.onClick.createDelegate(this, ["next"])
12982 this.last = this.addButton({
12983 tooltip: this.lastText,
12984 cls: "x-btn-icon x-grid-page-last",
12986 handler: this.onClick.createDelegate(this, ["last"])
12988 //this.addSeparator();
12989 this.loading = this.addButton({
12990 tooltip: this.refreshText,
12991 cls: "x-btn-icon x-grid-loading",
12992 handler: this.onClick.createDelegate(this, ["refresh"])
12995 if(this.displayInfo){
12996 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
13001 updateInfo : function(){
13002 if(this.displayEl){
13003 var count = this.ds.getCount();
13004 var msg = count == 0 ?
13008 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
13010 this.displayEl.update(msg);
13015 onLoad : function(ds, r, o){
13016 this.cursor = o.params ? o.params.start : 0;
13017 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
13019 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
13020 this.field.dom.value = ap;
13021 this.first.setDisabled(ap == 1);
13022 this.prev.setDisabled(ap == 1);
13023 this.next.setDisabled(ap == ps);
13024 this.last.setDisabled(ap == ps);
13025 this.loading.enable();
13030 getPageData : function(){
13031 var total = this.ds.getTotalCount();
13034 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
13035 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13040 onLoadError : function(){
13041 this.loading.enable();
13045 onPagingKeydown : function(e){
13046 var k = e.getKey();
13047 var d = this.getPageData();
13049 var v = this.field.dom.value, pageNum;
13050 if(!v || isNaN(pageNum = parseInt(v, 10))){
13051 this.field.dom.value = d.activePage;
13054 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13055 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13058 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))
13060 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13061 this.field.dom.value = pageNum;
13062 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13065 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13067 var v = this.field.dom.value, pageNum;
13068 var increment = (e.shiftKey) ? 10 : 1;
13069 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13071 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13072 this.field.dom.value = d.activePage;
13075 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13077 this.field.dom.value = parseInt(v, 10) + increment;
13078 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13079 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13086 beforeLoad : function(){
13088 this.loading.disable();
13093 onClick : function(which){
13097 ds.load({params:{start: 0, limit: this.pageSize}});
13100 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13103 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13106 var total = ds.getTotalCount();
13107 var extra = total % this.pageSize;
13108 var lastStart = extra ? (total - extra) : total-this.pageSize;
13109 ds.load({params:{start: lastStart, limit: this.pageSize}});
13112 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13118 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13119 * @param {Roo.data.Store} store The data store to unbind
13121 unbind : function(ds){
13122 ds.un("beforeload", this.beforeLoad, this);
13123 ds.un("load", this.onLoad, this);
13124 ds.un("loadexception", this.onLoadError, this);
13125 ds.un("remove", this.updateInfo, this);
13126 ds.un("add", this.updateInfo, this);
13127 this.ds = undefined;
13131 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13132 * @param {Roo.data.Store} store The data store to bind
13134 bind : function(ds){
13135 ds.on("beforeload", this.beforeLoad, this);
13136 ds.on("load", this.onLoad, this);
13137 ds.on("loadexception", this.onLoadError, this);
13138 ds.on("remove", this.updateInfo, this);
13139 ds.on("add", this.updateInfo, this);
13144 * Ext JS Library 1.1.1
13145 * Copyright(c) 2006-2007, Ext JS, LLC.
13147 * Originally Released Under LGPL - original licence link has changed is not relivant.
13150 * <script type="text/javascript">
13154 * @class Roo.Resizable
13155 * @extends Roo.util.Observable
13156 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13157 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13158 * 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
13159 * the element will be wrapped for you automatically.</p>
13160 * <p>Here is the list of valid resize handles:</p>
13163 ------ -------------------
13172 'hd' horizontal drag
13175 * <p>Here's an example showing the creation of a typical Resizable:</p>
13177 var resizer = new Roo.Resizable("element-id", {
13185 resizer.on("resize", myHandler);
13187 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13188 * resizer.east.setDisplayed(false);</p>
13189 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13190 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13191 * resize operation's new size (defaults to [0, 0])
13192 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13193 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13194 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13195 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13196 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13197 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13198 * @cfg {Number} width The width of the element in pixels (defaults to null)
13199 * @cfg {Number} height The height of the element in pixels (defaults to null)
13200 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13201 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13202 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13203 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13204 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13205 * in favor of the handles config option (defaults to false)
13206 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13207 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13208 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13209 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13210 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13211 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13212 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13213 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13214 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13215 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13216 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13218 * Create a new resizable component
13219 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13220 * @param {Object} config configuration options
13222 Roo.Resizable = function(el, config)
13224 this.el = Roo.get(el);
13226 if(config && config.wrap){
13227 config.resizeChild = this.el;
13228 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13229 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13230 this.el.setStyle("overflow", "hidden");
13231 this.el.setPositioning(config.resizeChild.getPositioning());
13232 config.resizeChild.clearPositioning();
13233 if(!config.width || !config.height){
13234 var csize = config.resizeChild.getSize();
13235 this.el.setSize(csize.width, csize.height);
13237 if(config.pinned && !config.adjustments){
13238 config.adjustments = "auto";
13242 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13243 this.proxy.unselectable();
13244 this.proxy.enableDisplayMode('block');
13246 Roo.apply(this, config);
13249 this.disableTrackOver = true;
13250 this.el.addClass("x-resizable-pinned");
13252 // if the element isn't positioned, make it relative
13253 var position = this.el.getStyle("position");
13254 if(position != "absolute" && position != "fixed"){
13255 this.el.setStyle("position", "relative");
13257 if(!this.handles){ // no handles passed, must be legacy style
13258 this.handles = 's,e,se';
13259 if(this.multiDirectional){
13260 this.handles += ',n,w';
13263 if(this.handles == "all"){
13264 this.handles = "n s e w ne nw se sw";
13266 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13267 var ps = Roo.Resizable.positions;
13268 for(var i = 0, len = hs.length; i < len; i++){
13269 if(hs[i] && ps[hs[i]]){
13270 var pos = ps[hs[i]];
13271 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13275 this.corner = this.southeast;
13277 // updateBox = the box can move..
13278 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13279 this.updateBox = true;
13282 this.activeHandle = null;
13284 if(this.resizeChild){
13285 if(typeof this.resizeChild == "boolean"){
13286 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13288 this.resizeChild = Roo.get(this.resizeChild, true);
13292 if(this.adjustments == "auto"){
13293 var rc = this.resizeChild;
13294 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13295 if(rc && (hw || hn)){
13296 rc.position("relative");
13297 rc.setLeft(hw ? hw.el.getWidth() : 0);
13298 rc.setTop(hn ? hn.el.getHeight() : 0);
13300 this.adjustments = [
13301 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13302 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13306 if(this.draggable){
13307 this.dd = this.dynamic ?
13308 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13309 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13315 * @event beforeresize
13316 * Fired before resize is allowed. Set enabled to false to cancel resize.
13317 * @param {Roo.Resizable} this
13318 * @param {Roo.EventObject} e The mousedown event
13320 "beforeresize" : true,
13323 * Fired after a resize.
13324 * @param {Roo.Resizable} this
13325 * @param {Number} width The new width
13326 * @param {Number} height The new height
13327 * @param {Roo.EventObject} e The mouseup event
13332 if(this.width !== null && this.height !== null){
13333 this.resizeTo(this.width, this.height);
13335 this.updateChildSize();
13338 this.el.dom.style.zoom = 1;
13340 Roo.Resizable.superclass.constructor.call(this);
13343 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13344 resizeChild : false,
13345 adjustments : [0, 0],
13355 multiDirectional : false,
13356 disableTrackOver : false,
13357 easing : 'easeOutStrong',
13358 widthIncrement : 0,
13359 heightIncrement : 0,
13363 preserveRatio : false,
13364 transparent: false,
13370 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13372 constrainTo: undefined,
13374 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13376 resizeRegion: undefined,
13380 * Perform a manual resize
13381 * @param {Number} width
13382 * @param {Number} height
13384 resizeTo : function(width, height){
13385 this.el.setSize(width, height);
13386 this.updateChildSize();
13387 this.fireEvent("resize", this, width, height, null);
13391 startSizing : function(e, handle){
13392 this.fireEvent("beforeresize", this, e);
13393 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13396 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13397 this.overlay.unselectable();
13398 this.overlay.enableDisplayMode("block");
13399 this.overlay.on("mousemove", this.onMouseMove, this);
13400 this.overlay.on("mouseup", this.onMouseUp, this);
13402 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13404 this.resizing = true;
13405 this.startBox = this.el.getBox();
13406 this.startPoint = e.getXY();
13407 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13408 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13410 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13411 this.overlay.show();
13413 if(this.constrainTo) {
13414 var ct = Roo.get(this.constrainTo);
13415 this.resizeRegion = ct.getRegion().adjust(
13416 ct.getFrameWidth('t'),
13417 ct.getFrameWidth('l'),
13418 -ct.getFrameWidth('b'),
13419 -ct.getFrameWidth('r')
13423 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13425 this.proxy.setBox(this.startBox);
13427 this.proxy.setStyle('visibility', 'visible');
13433 onMouseDown : function(handle, e){
13436 this.activeHandle = handle;
13437 this.startSizing(e, handle);
13442 onMouseUp : function(e){
13443 var size = this.resizeElement();
13444 this.resizing = false;
13446 this.overlay.hide();
13448 this.fireEvent("resize", this, size.width, size.height, e);
13452 updateChildSize : function(){
13453 if(this.resizeChild){
13455 var child = this.resizeChild;
13456 var adj = this.adjustments;
13457 if(el.dom.offsetWidth){
13458 var b = el.getSize(true);
13459 child.setSize(b.width+adj[0], b.height+adj[1]);
13461 // Second call here for IE
13462 // The first call enables instant resizing and
13463 // the second call corrects scroll bars if they
13466 setTimeout(function(){
13467 if(el.dom.offsetWidth){
13468 var b = el.getSize(true);
13469 child.setSize(b.width+adj[0], b.height+adj[1]);
13477 snap : function(value, inc, min){
13478 if(!inc || !value) return value;
13479 var newValue = value;
13480 var m = value % inc;
13483 newValue = value + (inc-m);
13485 newValue = value - m;
13488 return Math.max(min, newValue);
13492 resizeElement : function(){
13493 var box = this.proxy.getBox();
13494 if(this.updateBox){
13495 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13497 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13499 this.updateChildSize();
13507 constrain : function(v, diff, m, mx){
13510 }else if(v - diff > mx){
13517 onMouseMove : function(e){
13519 try{// try catch so if something goes wrong the user doesn't get hung
13521 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13525 //var curXY = this.startPoint;
13526 var curSize = this.curSize || this.startBox;
13527 var x = this.startBox.x, y = this.startBox.y;
13528 var ox = x, oy = y;
13529 var w = curSize.width, h = curSize.height;
13530 var ow = w, oh = h;
13531 var mw = this.minWidth, mh = this.minHeight;
13532 var mxw = this.maxWidth, mxh = this.maxHeight;
13533 var wi = this.widthIncrement;
13534 var hi = this.heightIncrement;
13536 var eventXY = e.getXY();
13537 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13538 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13540 var pos = this.activeHandle.position;
13545 w = Math.min(Math.max(mw, w), mxw);
13550 h = Math.min(Math.max(mh, h), mxh);
13555 w = Math.min(Math.max(mw, w), mxw);
13556 h = Math.min(Math.max(mh, h), mxh);
13559 diffY = this.constrain(h, diffY, mh, mxh);
13566 var adiffX = Math.abs(diffX);
13567 var sub = (adiffX % wi); // how much
13568 if (sub > (wi/2)) { // far enough to snap
13569 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13571 // remove difference..
13572 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13576 x = Math.max(this.minX, x);
13579 diffX = this.constrain(w, diffX, mw, mxw);
13585 w = Math.min(Math.max(mw, w), mxw);
13586 diffY = this.constrain(h, diffY, mh, mxh);
13591 diffX = this.constrain(w, diffX, mw, mxw);
13592 diffY = this.constrain(h, diffY, mh, mxh);
13599 diffX = this.constrain(w, diffX, mw, mxw);
13601 h = Math.min(Math.max(mh, h), mxh);
13607 var sw = this.snap(w, wi, mw);
13608 var sh = this.snap(h, hi, mh);
13609 if(sw != w || sh != h){
13632 if(this.preserveRatio){
13637 h = Math.min(Math.max(mh, h), mxh);
13642 w = Math.min(Math.max(mw, w), mxw);
13647 w = Math.min(Math.max(mw, w), mxw);
13653 w = Math.min(Math.max(mw, w), mxw);
13659 h = Math.min(Math.max(mh, h), mxh);
13667 h = Math.min(Math.max(mh, h), mxh);
13677 h = Math.min(Math.max(mh, h), mxh);
13685 if (pos == 'hdrag') {
13688 this.proxy.setBounds(x, y, w, h);
13690 this.resizeElement();
13697 handleOver : function(){
13699 this.el.addClass("x-resizable-over");
13704 handleOut : function(){
13705 if(!this.resizing){
13706 this.el.removeClass("x-resizable-over");
13711 * Returns the element this component is bound to.
13712 * @return {Roo.Element}
13714 getEl : function(){
13719 * Returns the resizeChild element (or null).
13720 * @return {Roo.Element}
13722 getResizeChild : function(){
13723 return this.resizeChild;
13727 * Destroys this resizable. If the element was wrapped and
13728 * removeEl is not true then the element remains.
13729 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13731 destroy : function(removeEl){
13732 this.proxy.remove();
13734 this.overlay.removeAllListeners();
13735 this.overlay.remove();
13737 var ps = Roo.Resizable.positions;
13739 if(typeof ps[k] != "function" && this[ps[k]]){
13740 var h = this[ps[k]];
13741 h.el.removeAllListeners();
13746 this.el.update("");
13753 // hash to map config positions to true positions
13754 Roo.Resizable.positions = {
13755 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13760 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13762 // only initialize the template if resizable is used
13763 var tpl = Roo.DomHelper.createTemplate(
13764 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13767 Roo.Resizable.Handle.prototype.tpl = tpl;
13769 this.position = pos;
13771 // show north drag fro topdra
13772 var handlepos = pos == 'hdrag' ? 'north' : pos;
13774 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13775 if (pos == 'hdrag') {
13776 this.el.setStyle('cursor', 'pointer');
13778 this.el.unselectable();
13780 this.el.setOpacity(0);
13782 this.el.on("mousedown", this.onMouseDown, this);
13783 if(!disableTrackOver){
13784 this.el.on("mouseover", this.onMouseOver, this);
13785 this.el.on("mouseout", this.onMouseOut, this);
13790 Roo.Resizable.Handle.prototype = {
13791 afterResize : function(rz){
13795 onMouseDown : function(e){
13796 this.rz.onMouseDown(this, e);
13799 onMouseOver : function(e){
13800 this.rz.handleOver(this, e);
13803 onMouseOut : function(e){
13804 this.rz.handleOut(this, e);
13808 * Ext JS Library 1.1.1
13809 * Copyright(c) 2006-2007, Ext JS, LLC.
13811 * Originally Released Under LGPL - original licence link has changed is not relivant.
13814 * <script type="text/javascript">
13818 * @class Roo.Editor
13819 * @extends Roo.Component
13820 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13822 * Create a new Editor
13823 * @param {Roo.form.Field} field The Field object (or descendant)
13824 * @param {Object} config The config object
13826 Roo.Editor = function(field, config){
13827 Roo.Editor.superclass.constructor.call(this, config);
13828 this.field = field;
13831 * @event beforestartedit
13832 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13833 * false from the handler of this event.
13834 * @param {Editor} this
13835 * @param {Roo.Element} boundEl The underlying element bound to this editor
13836 * @param {Mixed} value The field value being set
13838 "beforestartedit" : true,
13841 * Fires when this editor is displayed
13842 * @param {Roo.Element} boundEl The underlying element bound to this editor
13843 * @param {Mixed} value The starting field value
13845 "startedit" : true,
13847 * @event beforecomplete
13848 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13849 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13850 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13851 * event will not fire since no edit actually occurred.
13852 * @param {Editor} this
13853 * @param {Mixed} value The current field value
13854 * @param {Mixed} startValue The original field value
13856 "beforecomplete" : true,
13859 * Fires after editing is complete and any changed value has been written to the underlying field.
13860 * @param {Editor} this
13861 * @param {Mixed} value The current field value
13862 * @param {Mixed} startValue The original field value
13866 * @event specialkey
13867 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13868 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13869 * @param {Roo.form.Field} this
13870 * @param {Roo.EventObject} e The event object
13872 "specialkey" : true
13876 Roo.extend(Roo.Editor, Roo.Component, {
13878 * @cfg {Boolean/String} autosize
13879 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13880 * or "height" to adopt the height only (defaults to false)
13883 * @cfg {Boolean} revertInvalid
13884 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13885 * validation fails (defaults to true)
13888 * @cfg {Boolean} ignoreNoChange
13889 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13890 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13891 * will never be ignored.
13894 * @cfg {Boolean} hideEl
13895 * False to keep the bound element visible while the editor is displayed (defaults to true)
13898 * @cfg {Mixed} value
13899 * The data value of the underlying field (defaults to "")
13903 * @cfg {String} alignment
13904 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13908 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13909 * for bottom-right shadow (defaults to "frame")
13913 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13917 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13919 completeOnEnter : false,
13921 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13923 cancelOnEsc : false,
13925 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13930 onRender : function(ct, position){
13931 this.el = new Roo.Layer({
13932 shadow: this.shadow,
13938 constrain: this.constrain
13940 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13941 if(this.field.msgTarget != 'title'){
13942 this.field.msgTarget = 'qtip';
13944 this.field.render(this.el);
13946 this.field.el.dom.setAttribute('autocomplete', 'off');
13948 this.field.on("specialkey", this.onSpecialKey, this);
13949 if(this.swallowKeys){
13950 this.field.el.swallowEvent(['keydown','keypress']);
13953 this.field.on("blur", this.onBlur, this);
13954 if(this.field.grow){
13955 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13959 onSpecialKey : function(field, e)
13961 //Roo.log('editor onSpecialKey');
13962 if(this.completeOnEnter && e.getKey() == e.ENTER){
13964 this.completeEdit();
13967 // do not fire special key otherwise it might hide close the editor...
13968 if(e.getKey() == e.ENTER){
13971 if(this.cancelOnEsc && e.getKey() == e.ESC){
13975 this.fireEvent('specialkey', field, e);
13980 * Starts the editing process and shows the editor.
13981 * @param {String/HTMLElement/Element} el The element to edit
13982 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13983 * to the innerHTML of el.
13985 startEdit : function(el, value){
13987 this.completeEdit();
13989 this.boundEl = Roo.get(el);
13990 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13991 if(!this.rendered){
13992 this.render(this.parentEl || document.body);
13994 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13997 this.startValue = v;
13998 this.field.setValue(v);
14000 var sz = this.boundEl.getSize();
14001 switch(this.autoSize){
14003 this.setSize(sz.width, "");
14006 this.setSize("", sz.height);
14009 this.setSize(sz.width, sz.height);
14012 this.el.alignTo(this.boundEl, this.alignment);
14013 this.editing = true;
14015 Roo.QuickTips.disable();
14021 * Sets the height and width of this editor.
14022 * @param {Number} width The new width
14023 * @param {Number} height The new height
14025 setSize : function(w, h){
14026 this.field.setSize(w, h);
14033 * Realigns the editor to the bound field based on the current alignment config value.
14035 realign : function(){
14036 this.el.alignTo(this.boundEl, this.alignment);
14040 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
14041 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
14043 completeEdit : function(remainVisible){
14047 var v = this.getValue();
14048 if(this.revertInvalid !== false && !this.field.isValid()){
14049 v = this.startValue;
14050 this.cancelEdit(true);
14052 if(String(v) === String(this.startValue) && this.ignoreNoChange){
14053 this.editing = false;
14057 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
14058 this.editing = false;
14059 if(this.updateEl && this.boundEl){
14060 this.boundEl.update(v);
14062 if(remainVisible !== true){
14065 this.fireEvent("complete", this, v, this.startValue);
14070 onShow : function(){
14072 if(this.hideEl !== false){
14073 this.boundEl.hide();
14076 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14077 this.fixIEFocus = true;
14078 this.deferredFocus.defer(50, this);
14080 this.field.focus();
14082 this.fireEvent("startedit", this.boundEl, this.startValue);
14085 deferredFocus : function(){
14087 this.field.focus();
14092 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14093 * reverted to the original starting value.
14094 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14095 * cancel (defaults to false)
14097 cancelEdit : function(remainVisible){
14099 this.setValue(this.startValue);
14100 if(remainVisible !== true){
14107 onBlur : function(){
14108 if(this.allowBlur !== true && this.editing){
14109 this.completeEdit();
14114 onHide : function(){
14116 this.completeEdit();
14120 if(this.field.collapse){
14121 this.field.collapse();
14124 if(this.hideEl !== false){
14125 this.boundEl.show();
14128 Roo.QuickTips.enable();
14133 * Sets the data value of the editor
14134 * @param {Mixed} value Any valid value supported by the underlying field
14136 setValue : function(v){
14137 this.field.setValue(v);
14141 * Gets the data value of the editor
14142 * @return {Mixed} The data value
14144 getValue : function(){
14145 return this.field.getValue();
14149 * Ext JS Library 1.1.1
14150 * Copyright(c) 2006-2007, Ext JS, LLC.
14152 * Originally Released Under LGPL - original licence link has changed is not relivant.
14155 * <script type="text/javascript">
14159 * @class Roo.BasicDialog
14160 * @extends Roo.util.Observable
14161 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14163 var dlg = new Roo.BasicDialog("my-dlg", {
14172 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14173 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14174 dlg.addButton('Cancel', dlg.hide, dlg);
14177 <b>A Dialog should always be a direct child of the body element.</b>
14178 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14179 * @cfg {String} title Default text to display in the title bar (defaults to null)
14180 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14181 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14182 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14183 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14184 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14185 * (defaults to null with no animation)
14186 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14187 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14188 * property for valid values (defaults to 'all')
14189 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14190 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14191 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14192 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14193 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14194 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14195 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14196 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14197 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14198 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14199 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14200 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14201 * draggable = true (defaults to false)
14202 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14203 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14204 * shadow (defaults to false)
14205 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14206 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14207 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14208 * @cfg {Array} buttons Array of buttons
14209 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14211 * Create a new BasicDialog.
14212 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14213 * @param {Object} config Configuration options
14215 Roo.BasicDialog = function(el, config){
14216 this.el = Roo.get(el);
14217 var dh = Roo.DomHelper;
14218 if(!this.el && config && config.autoCreate){
14219 if(typeof config.autoCreate == "object"){
14220 if(!config.autoCreate.id){
14221 config.autoCreate.id = el;
14223 this.el = dh.append(document.body,
14224 config.autoCreate, true);
14226 this.el = dh.append(document.body,
14227 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14231 el.setDisplayed(true);
14232 el.hide = this.hideAction;
14234 el.addClass("x-dlg");
14236 Roo.apply(this, config);
14238 this.proxy = el.createProxy("x-dlg-proxy");
14239 this.proxy.hide = this.hideAction;
14240 this.proxy.setOpacity(.5);
14244 el.setWidth(config.width);
14247 el.setHeight(config.height);
14249 this.size = el.getSize();
14250 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14251 this.xy = [config.x,config.y];
14253 this.xy = el.getCenterXY(true);
14255 /** The header element @type Roo.Element */
14256 this.header = el.child("> .x-dlg-hd");
14257 /** The body element @type Roo.Element */
14258 this.body = el.child("> .x-dlg-bd");
14259 /** The footer element @type Roo.Element */
14260 this.footer = el.child("> .x-dlg-ft");
14263 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14266 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14269 this.header.unselectable();
14271 this.header.update(this.title);
14273 // this element allows the dialog to be focused for keyboard event
14274 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14275 this.focusEl.swallowEvent("click", true);
14277 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14279 // wrap the body and footer for special rendering
14280 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14282 this.bwrap.dom.appendChild(this.footer.dom);
14285 this.bg = this.el.createChild({
14286 tag: "div", cls:"x-dlg-bg",
14287 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14289 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14292 if(this.autoScroll !== false && !this.autoTabs){
14293 this.body.setStyle("overflow", "auto");
14296 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14298 if(this.closable !== false){
14299 this.el.addClass("x-dlg-closable");
14300 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14301 this.close.on("click", this.closeClick, this);
14302 this.close.addClassOnOver("x-dlg-close-over");
14304 if(this.collapsible !== false){
14305 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14306 this.collapseBtn.on("click", this.collapseClick, this);
14307 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14308 this.header.on("dblclick", this.collapseClick, this);
14310 if(this.resizable !== false){
14311 this.el.addClass("x-dlg-resizable");
14312 this.resizer = new Roo.Resizable(el, {
14313 minWidth: this.minWidth || 80,
14314 minHeight:this.minHeight || 80,
14315 handles: this.resizeHandles || "all",
14318 this.resizer.on("beforeresize", this.beforeResize, this);
14319 this.resizer.on("resize", this.onResize, this);
14321 if(this.draggable !== false){
14322 el.addClass("x-dlg-draggable");
14323 if (!this.proxyDrag) {
14324 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14327 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14329 dd.setHandleElId(this.header.id);
14330 dd.endDrag = this.endMove.createDelegate(this);
14331 dd.startDrag = this.startMove.createDelegate(this);
14332 dd.onDrag = this.onDrag.createDelegate(this);
14337 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14338 this.mask.enableDisplayMode("block");
14340 this.el.addClass("x-dlg-modal");
14343 this.shadow = new Roo.Shadow({
14344 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14345 offset : this.shadowOffset
14348 this.shadowOffset = 0;
14350 if(Roo.useShims && this.shim !== false){
14351 this.shim = this.el.createShim();
14352 this.shim.hide = this.hideAction;
14360 if (this.buttons) {
14361 var bts= this.buttons;
14363 Roo.each(bts, function(b) {
14372 * Fires when a key is pressed
14373 * @param {Roo.BasicDialog} this
14374 * @param {Roo.EventObject} e
14379 * Fires when this dialog is moved by the user.
14380 * @param {Roo.BasicDialog} this
14381 * @param {Number} x The new page X
14382 * @param {Number} y The new page Y
14387 * Fires when this dialog is resized by the user.
14388 * @param {Roo.BasicDialog} this
14389 * @param {Number} width The new width
14390 * @param {Number} height The new height
14394 * @event beforehide
14395 * Fires before this dialog is hidden.
14396 * @param {Roo.BasicDialog} this
14398 "beforehide" : true,
14401 * Fires when this dialog is hidden.
14402 * @param {Roo.BasicDialog} this
14406 * @event beforeshow
14407 * Fires before this dialog is shown.
14408 * @param {Roo.BasicDialog} this
14410 "beforeshow" : true,
14413 * Fires when this dialog is shown.
14414 * @param {Roo.BasicDialog} this
14418 el.on("keydown", this.onKeyDown, this);
14419 el.on("mousedown", this.toFront, this);
14420 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14422 Roo.DialogManager.register(this);
14423 Roo.BasicDialog.superclass.constructor.call(this);
14426 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14427 shadowOffset: Roo.isIE ? 6 : 5,
14430 minButtonWidth: 75,
14431 defaultButton: null,
14432 buttonAlign: "right",
14437 * Sets the dialog title text
14438 * @param {String} text The title text to display
14439 * @return {Roo.BasicDialog} this
14441 setTitle : function(text){
14442 this.header.update(text);
14447 closeClick : function(){
14452 collapseClick : function(){
14453 this[this.collapsed ? "expand" : "collapse"]();
14457 * Collapses the dialog to its minimized state (only the title bar is visible).
14458 * Equivalent to the user clicking the collapse dialog button.
14460 collapse : function(){
14461 if(!this.collapsed){
14462 this.collapsed = true;
14463 this.el.addClass("x-dlg-collapsed");
14464 this.restoreHeight = this.el.getHeight();
14465 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14470 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14471 * clicking the expand dialog button.
14473 expand : function(){
14474 if(this.collapsed){
14475 this.collapsed = false;
14476 this.el.removeClass("x-dlg-collapsed");
14477 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14482 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14483 * @return {Roo.TabPanel} The tabs component
14485 initTabs : function(){
14486 var tabs = this.getTabs();
14487 while(tabs.getTab(0)){
14490 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14492 tabs.addTab(Roo.id(dom), dom.title);
14500 beforeResize : function(){
14501 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14505 onResize : function(){
14506 this.refreshSize();
14507 this.syncBodyHeight();
14508 this.adjustAssets();
14510 this.fireEvent("resize", this, this.size.width, this.size.height);
14514 onKeyDown : function(e){
14515 if(this.isVisible()){
14516 this.fireEvent("keydown", this, e);
14521 * Resizes the dialog.
14522 * @param {Number} width
14523 * @param {Number} height
14524 * @return {Roo.BasicDialog} this
14526 resizeTo : function(width, height){
14527 this.el.setSize(width, height);
14528 this.size = {width: width, height: height};
14529 this.syncBodyHeight();
14530 if(this.fixedcenter){
14533 if(this.isVisible()){
14534 this.constrainXY();
14535 this.adjustAssets();
14537 this.fireEvent("resize", this, width, height);
14543 * Resizes the dialog to fit the specified content size.
14544 * @param {Number} width
14545 * @param {Number} height
14546 * @return {Roo.BasicDialog} this
14548 setContentSize : function(w, h){
14549 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14550 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14551 //if(!this.el.isBorderBox()){
14552 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14553 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14556 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14557 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14559 this.resizeTo(w, h);
14564 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14565 * executed in response to a particular key being pressed while the dialog is active.
14566 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14567 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14568 * @param {Function} fn The function to call
14569 * @param {Object} scope (optional) The scope of the function
14570 * @return {Roo.BasicDialog} this
14572 addKeyListener : function(key, fn, scope){
14573 var keyCode, shift, ctrl, alt;
14574 if(typeof key == "object" && !(key instanceof Array)){
14575 keyCode = key["key"];
14576 shift = key["shift"];
14577 ctrl = key["ctrl"];
14582 var handler = function(dlg, e){
14583 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14584 var k = e.getKey();
14585 if(keyCode instanceof Array){
14586 for(var i = 0, len = keyCode.length; i < len; i++){
14587 if(keyCode[i] == k){
14588 fn.call(scope || window, dlg, k, e);
14594 fn.call(scope || window, dlg, k, e);
14599 this.on("keydown", handler);
14604 * Returns the TabPanel component (creates it if it doesn't exist).
14605 * Note: If you wish to simply check for the existence of tabs without creating them,
14606 * check for a null 'tabs' property.
14607 * @return {Roo.TabPanel} The tabs component
14609 getTabs : function(){
14611 this.el.addClass("x-dlg-auto-tabs");
14612 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14613 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14619 * Adds a button to the footer section of the dialog.
14620 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14621 * object or a valid Roo.DomHelper element config
14622 * @param {Function} handler The function called when the button is clicked
14623 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14624 * @return {Roo.Button} The new button
14626 addButton : function(config, handler, scope){
14627 var dh = Roo.DomHelper;
14629 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14631 if(!this.btnContainer){
14632 var tb = this.footer.createChild({
14634 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14635 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14637 this.btnContainer = tb.firstChild.firstChild.firstChild;
14642 minWidth: this.minButtonWidth,
14645 if(typeof config == "string"){
14646 bconfig.text = config;
14649 bconfig.dhconfig = config;
14651 Roo.apply(bconfig, config);
14655 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14656 bconfig.position = Math.max(0, bconfig.position);
14657 fc = this.btnContainer.childNodes[bconfig.position];
14660 var btn = new Roo.Button(
14662 this.btnContainer.insertBefore(document.createElement("td"),fc)
14663 : this.btnContainer.appendChild(document.createElement("td")),
14664 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14667 this.syncBodyHeight();
14670 * Array of all the buttons that have been added to this dialog via addButton
14675 this.buttons.push(btn);
14680 * Sets the default button to be focused when the dialog is displayed.
14681 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14682 * @return {Roo.BasicDialog} this
14684 setDefaultButton : function(btn){
14685 this.defaultButton = btn;
14690 getHeaderFooterHeight : function(safe){
14693 height += this.header.getHeight();
14696 var fm = this.footer.getMargins();
14697 height += (this.footer.getHeight()+fm.top+fm.bottom);
14699 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14700 height += this.centerBg.getPadding("tb");
14705 syncBodyHeight : function(){
14706 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14707 var height = this.size.height - this.getHeaderFooterHeight(false);
14708 bd.setHeight(height-bd.getMargins("tb"));
14709 var hh = this.header.getHeight();
14710 var h = this.size.height-hh;
14712 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14713 bw.setHeight(h-cb.getPadding("tb"));
14714 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14715 bd.setWidth(bw.getWidth(true));
14717 this.tabs.syncHeight();
14719 this.tabs.el.repaint();
14725 * Restores the previous state of the dialog if Roo.state is configured.
14726 * @return {Roo.BasicDialog} this
14728 restoreState : function(){
14729 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14730 if(box && box.width){
14731 this.xy = [box.x, box.y];
14732 this.resizeTo(box.width, box.height);
14738 beforeShow : function(){
14740 if(this.fixedcenter){
14741 this.xy = this.el.getCenterXY(true);
14744 Roo.get(document.body).addClass("x-body-masked");
14745 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14748 this.constrainXY();
14752 animShow : function(){
14753 var b = Roo.get(this.animateTarget).getBox();
14754 this.proxy.setSize(b.width, b.height);
14755 this.proxy.setLocation(b.x, b.y);
14757 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14758 true, .35, this.showEl.createDelegate(this));
14762 * Shows the dialog.
14763 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14764 * @return {Roo.BasicDialog} this
14766 show : function(animateTarget){
14767 if (this.fireEvent("beforeshow", this) === false){
14770 if(this.syncHeightBeforeShow){
14771 this.syncBodyHeight();
14772 }else if(this.firstShow){
14773 this.firstShow = false;
14774 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14776 this.animateTarget = animateTarget || this.animateTarget;
14777 if(!this.el.isVisible()){
14779 if(this.animateTarget && Roo.get(this.animateTarget)){
14789 showEl : function(){
14791 this.el.setXY(this.xy);
14793 this.adjustAssets(true);
14796 // IE peekaboo bug - fix found by Dave Fenwick
14800 this.fireEvent("show", this);
14804 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14805 * dialog itself will receive focus.
14807 focus : function(){
14808 if(this.defaultButton){
14809 this.defaultButton.focus();
14811 this.focusEl.focus();
14816 constrainXY : function(){
14817 if(this.constraintoviewport !== false){
14818 if(!this.viewSize){
14819 if(this.container){
14820 var s = this.container.getSize();
14821 this.viewSize = [s.width, s.height];
14823 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14826 var s = Roo.get(this.container||document).getScroll();
14828 var x = this.xy[0], y = this.xy[1];
14829 var w = this.size.width, h = this.size.height;
14830 var vw = this.viewSize[0], vh = this.viewSize[1];
14831 // only move it if it needs it
14833 // first validate right/bottom
14834 if(x + w > vw+s.left){
14838 if(y + h > vh+s.top){
14842 // then make sure top/left isn't negative
14854 if(this.isVisible()){
14855 this.el.setLocation(x, y);
14856 this.adjustAssets();
14863 onDrag : function(){
14864 if(!this.proxyDrag){
14865 this.xy = this.el.getXY();
14866 this.adjustAssets();
14871 adjustAssets : function(doShow){
14872 var x = this.xy[0], y = this.xy[1];
14873 var w = this.size.width, h = this.size.height;
14874 if(doShow === true){
14876 this.shadow.show(this.el);
14882 if(this.shadow && this.shadow.isVisible()){
14883 this.shadow.show(this.el);
14885 if(this.shim && this.shim.isVisible()){
14886 this.shim.setBounds(x, y, w, h);
14891 adjustViewport : function(w, h){
14893 w = Roo.lib.Dom.getViewWidth();
14894 h = Roo.lib.Dom.getViewHeight();
14897 this.viewSize = [w, h];
14898 if(this.modal && this.mask.isVisible()){
14899 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14900 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14902 if(this.isVisible()){
14903 this.constrainXY();
14908 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14909 * shadow, proxy, mask, etc.) Also removes all event listeners.
14910 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14912 destroy : function(removeEl){
14913 if(this.isVisible()){
14914 this.animateTarget = null;
14917 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14919 this.tabs.destroy(removeEl);
14932 for(var i = 0, len = this.buttons.length; i < len; i++){
14933 this.buttons[i].destroy();
14936 this.el.removeAllListeners();
14937 if(removeEl === true){
14938 this.el.update("");
14941 Roo.DialogManager.unregister(this);
14945 startMove : function(){
14946 if(this.proxyDrag){
14949 if(this.constraintoviewport !== false){
14950 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14955 endMove : function(){
14956 if(!this.proxyDrag){
14957 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14959 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14962 this.refreshSize();
14963 this.adjustAssets();
14965 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14969 * Brings this dialog to the front of any other visible dialogs
14970 * @return {Roo.BasicDialog} this
14972 toFront : function(){
14973 Roo.DialogManager.bringToFront(this);
14978 * Sends this dialog to the back (under) of any other visible dialogs
14979 * @return {Roo.BasicDialog} this
14981 toBack : function(){
14982 Roo.DialogManager.sendToBack(this);
14987 * Centers this dialog in the viewport
14988 * @return {Roo.BasicDialog} this
14990 center : function(){
14991 var xy = this.el.getCenterXY(true);
14992 this.moveTo(xy[0], xy[1]);
14997 * Moves the dialog's top-left corner to the specified point
14998 * @param {Number} x
14999 * @param {Number} y
15000 * @return {Roo.BasicDialog} this
15002 moveTo : function(x, y){
15004 if(this.isVisible()){
15005 this.el.setXY(this.xy);
15006 this.adjustAssets();
15012 * Aligns the dialog to the specified element
15013 * @param {String/HTMLElement/Roo.Element} element The element to align to.
15014 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
15015 * @param {Array} offsets (optional) Offset the positioning by [x, y]
15016 * @return {Roo.BasicDialog} this
15018 alignTo : function(element, position, offsets){
15019 this.xy = this.el.getAlignToXY(element, position, offsets);
15020 if(this.isVisible()){
15021 this.el.setXY(this.xy);
15022 this.adjustAssets();
15028 * Anchors an element to another element and realigns it when the window is resized.
15029 * @param {String/HTMLElement/Roo.Element} element The element to align to.
15030 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
15031 * @param {Array} offsets (optional) Offset the positioning by [x, y]
15032 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
15033 * is a number, it is used as the buffer delay (defaults to 50ms).
15034 * @return {Roo.BasicDialog} this
15036 anchorTo : function(el, alignment, offsets, monitorScroll){
15037 var action = function(){
15038 this.alignTo(el, alignment, offsets);
15040 Roo.EventManager.onWindowResize(action, this);
15041 var tm = typeof monitorScroll;
15042 if(tm != 'undefined'){
15043 Roo.EventManager.on(window, 'scroll', action, this,
15044 {buffer: tm == 'number' ? monitorScroll : 50});
15051 * Returns true if the dialog is visible
15052 * @return {Boolean}
15054 isVisible : function(){
15055 return this.el.isVisible();
15059 animHide : function(callback){
15060 var b = Roo.get(this.animateTarget).getBox();
15062 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15064 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15065 this.hideEl.createDelegate(this, [callback]));
15069 * Hides the dialog.
15070 * @param {Function} callback (optional) Function to call when the dialog is hidden
15071 * @return {Roo.BasicDialog} this
15073 hide : function(callback){
15074 if (this.fireEvent("beforehide", this) === false){
15078 this.shadow.hide();
15083 // sometimes animateTarget seems to get set.. causing problems...
15084 // this just double checks..
15085 if(this.animateTarget && Roo.get(this.animateTarget)) {
15086 this.animHide(callback);
15089 this.hideEl(callback);
15095 hideEl : function(callback){
15099 Roo.get(document.body).removeClass("x-body-masked");
15101 this.fireEvent("hide", this);
15102 if(typeof callback == "function"){
15108 hideAction : function(){
15109 this.setLeft("-10000px");
15110 this.setTop("-10000px");
15111 this.setStyle("visibility", "hidden");
15115 refreshSize : function(){
15116 this.size = this.el.getSize();
15117 this.xy = this.el.getXY();
15118 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15122 // z-index is managed by the DialogManager and may be overwritten at any time
15123 setZIndex : function(index){
15125 this.mask.setStyle("z-index", index);
15128 this.shim.setStyle("z-index", ++index);
15131 this.shadow.setZIndex(++index);
15133 this.el.setStyle("z-index", ++index);
15135 this.proxy.setStyle("z-index", ++index);
15138 this.resizer.proxy.setStyle("z-index", ++index);
15141 this.lastZIndex = index;
15145 * Returns the element for this dialog
15146 * @return {Roo.Element} The underlying dialog Element
15148 getEl : function(){
15154 * @class Roo.DialogManager
15155 * Provides global access to BasicDialogs that have been created and
15156 * support for z-indexing (layering) multiple open dialogs.
15158 Roo.DialogManager = function(){
15160 var accessList = [];
15164 var sortDialogs = function(d1, d2){
15165 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15169 var orderDialogs = function(){
15170 accessList.sort(sortDialogs);
15171 var seed = Roo.DialogManager.zseed;
15172 for(var i = 0, len = accessList.length; i < len; i++){
15173 var dlg = accessList[i];
15175 dlg.setZIndex(seed + (i*10));
15182 * The starting z-index for BasicDialogs (defaults to 9000)
15183 * @type Number The z-index value
15188 register : function(dlg){
15189 list[dlg.id] = dlg;
15190 accessList.push(dlg);
15194 unregister : function(dlg){
15195 delete list[dlg.id];
15198 if(!accessList.indexOf){
15199 for( i = 0, len = accessList.length; i < len; i++){
15200 if(accessList[i] == dlg){
15201 accessList.splice(i, 1);
15206 i = accessList.indexOf(dlg);
15208 accessList.splice(i, 1);
15214 * Gets a registered dialog by id
15215 * @param {String/Object} id The id of the dialog or a dialog
15216 * @return {Roo.BasicDialog} this
15218 get : function(id){
15219 return typeof id == "object" ? id : list[id];
15223 * Brings the specified dialog to the front
15224 * @param {String/Object} dlg The id of the dialog or a dialog
15225 * @return {Roo.BasicDialog} this
15227 bringToFront : function(dlg){
15228 dlg = this.get(dlg);
15231 dlg._lastAccess = new Date().getTime();
15238 * Sends the specified dialog to the back
15239 * @param {String/Object} dlg The id of the dialog or a dialog
15240 * @return {Roo.BasicDialog} this
15242 sendToBack : function(dlg){
15243 dlg = this.get(dlg);
15244 dlg._lastAccess = -(new Date().getTime());
15250 * Hides all dialogs
15252 hideAll : function(){
15253 for(var id in list){
15254 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15263 * @class Roo.LayoutDialog
15264 * @extends Roo.BasicDialog
15265 * Dialog which provides adjustments for working with a layout in a Dialog.
15266 * Add your necessary layout config options to the dialog's config.<br>
15267 * Example usage (including a nested layout):
15270 dialog = new Roo.LayoutDialog("download-dlg", {
15279 // layout config merges with the dialog config
15281 tabPosition: "top",
15282 alwaysShowTabs: true
15285 dialog.addKeyListener(27, dialog.hide, dialog);
15286 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15287 dialog.addButton("Build It!", this.getDownload, this);
15289 // we can even add nested layouts
15290 var innerLayout = new Roo.BorderLayout("dl-inner", {
15300 innerLayout.beginUpdate();
15301 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15302 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15303 innerLayout.endUpdate(true);
15305 var layout = dialog.getLayout();
15306 layout.beginUpdate();
15307 layout.add("center", new Roo.ContentPanel("standard-panel",
15308 {title: "Download the Source", fitToFrame:true}));
15309 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15310 {title: "Build your own roo.js"}));
15311 layout.getRegion("center").showPanel(sp);
15312 layout.endUpdate();
15316 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15317 * @param {Object} config configuration options
15319 Roo.LayoutDialog = function(el, cfg){
15322 if (typeof(cfg) == 'undefined') {
15323 config = Roo.apply({}, el);
15324 // not sure why we use documentElement here.. - it should always be body.
15325 // IE7 borks horribly if we use documentElement.
15326 // webkit also does not like documentElement - it creates a body element...
15327 el = Roo.get( document.body || document.documentElement ).createChild();
15328 //config.autoCreate = true;
15332 config.autoTabs = false;
15333 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15334 this.body.setStyle({overflow:"hidden", position:"relative"});
15335 this.layout = new Roo.BorderLayout(this.body.dom, config);
15336 this.layout.monitorWindowResize = false;
15337 this.el.addClass("x-dlg-auto-layout");
15338 // fix case when center region overwrites center function
15339 this.center = Roo.BasicDialog.prototype.center;
15340 this.on("show", this.layout.layout, this.layout, true);
15341 if (config.items) {
15342 var xitems = config.items;
15343 delete config.items;
15344 Roo.each(xitems, this.addxtype, this);
15349 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15351 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15354 endUpdate : function(){
15355 this.layout.endUpdate();
15359 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15362 beginUpdate : function(){
15363 this.layout.beginUpdate();
15367 * Get the BorderLayout for this dialog
15368 * @return {Roo.BorderLayout}
15370 getLayout : function(){
15371 return this.layout;
15374 showEl : function(){
15375 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15377 this.layout.layout();
15382 // Use the syncHeightBeforeShow config option to control this automatically
15383 syncBodyHeight : function(){
15384 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15385 if(this.layout){this.layout.layout();}
15389 * Add an xtype element (actually adds to the layout.)
15390 * @return {Object} xdata xtype object data.
15393 addxtype : function(c) {
15394 return this.layout.addxtype(c);
15398 * Ext JS Library 1.1.1
15399 * Copyright(c) 2006-2007, Ext JS, LLC.
15401 * Originally Released Under LGPL - original licence link has changed is not relivant.
15404 * <script type="text/javascript">
15408 * @class Roo.MessageBox
15409 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15413 Roo.Msg.alert('Status', 'Changes saved successfully.');
15415 // Prompt for user data:
15416 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15418 // process text value...
15422 // Show a dialog using config options:
15424 title:'Save Changes?',
15425 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15426 buttons: Roo.Msg.YESNOCANCEL,
15433 Roo.MessageBox = function(){
15434 var dlg, opt, mask, waitTimer;
15435 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15436 var buttons, activeTextEl, bwidth;
15439 var handleButton = function(button){
15441 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15445 var handleHide = function(){
15446 if(opt && opt.cls){
15447 dlg.el.removeClass(opt.cls);
15450 Roo.TaskMgr.stop(waitTimer);
15456 var updateButtons = function(b){
15459 buttons["ok"].hide();
15460 buttons["cancel"].hide();
15461 buttons["yes"].hide();
15462 buttons["no"].hide();
15463 dlg.footer.dom.style.display = 'none';
15466 dlg.footer.dom.style.display = '';
15467 for(var k in buttons){
15468 if(typeof buttons[k] != "function"){
15471 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15472 width += buttons[k].el.getWidth()+15;
15482 var handleEsc = function(d, k, e){
15483 if(opt && opt.closable !== false){
15493 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15494 * @return {Roo.BasicDialog} The BasicDialog element
15496 getDialog : function(){
15498 dlg = new Roo.BasicDialog("x-msg-box", {
15503 constraintoviewport:false,
15505 collapsible : false,
15508 width:400, height:100,
15509 buttonAlign:"center",
15510 closeClick : function(){
15511 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15512 handleButton("no");
15514 handleButton("cancel");
15518 dlg.on("hide", handleHide);
15520 dlg.addKeyListener(27, handleEsc);
15522 var bt = this.buttonText;
15523 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15524 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15525 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15526 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15527 bodyEl = dlg.body.createChild({
15529 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>'
15531 msgEl = bodyEl.dom.firstChild;
15532 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15533 textboxEl.enableDisplayMode();
15534 textboxEl.addKeyListener([10,13], function(){
15535 if(dlg.isVisible() && opt && opt.buttons){
15536 if(opt.buttons.ok){
15537 handleButton("ok");
15538 }else if(opt.buttons.yes){
15539 handleButton("yes");
15543 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15544 textareaEl.enableDisplayMode();
15545 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15546 progressEl.enableDisplayMode();
15547 var pf = progressEl.dom.firstChild;
15549 pp = Roo.get(pf.firstChild);
15550 pp.setHeight(pf.offsetHeight);
15558 * Updates the message box body text
15559 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15560 * the XHTML-compliant non-breaking space character '&#160;')
15561 * @return {Roo.MessageBox} This message box
15563 updateText : function(text){
15564 if(!dlg.isVisible() && !opt.width){
15565 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15567 msgEl.innerHTML = text || ' ';
15568 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15569 Math.max(opt.minWidth || this.minWidth, bwidth));
15571 activeTextEl.setWidth(w);
15573 if(dlg.isVisible()){
15574 dlg.fixedcenter = false;
15576 dlg.setContentSize(w, bodyEl.getHeight());
15577 if(dlg.isVisible()){
15578 dlg.fixedcenter = true;
15584 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15585 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15586 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15587 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15588 * @return {Roo.MessageBox} This message box
15590 updateProgress : function(value, text){
15592 this.updateText(text);
15594 if (pp) { // weird bug on my firefox - for some reason this is not defined
15595 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15601 * Returns true if the message box is currently displayed
15602 * @return {Boolean} True if the message box is visible, else false
15604 isVisible : function(){
15605 return dlg && dlg.isVisible();
15609 * Hides the message box if it is displayed
15612 if(this.isVisible()){
15618 * Displays a new message box, or reinitializes an existing message box, based on the config options
15619 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15620 * The following config object properties are supported:
15622 Property Type Description
15623 ---------- --------------- ------------------------------------------------------------------------------------
15624 animEl String/Element An id or Element from which the message box should animate as it opens and
15625 closes (defaults to undefined)
15626 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15627 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15628 closable Boolean False to hide the top-right close button (defaults to true). Note that
15629 progress and wait dialogs will ignore this property and always hide the
15630 close button as they can only be closed programmatically.
15631 cls String A custom CSS class to apply to the message box element
15632 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15633 displayed (defaults to 75)
15634 fn Function A callback function to execute after closing the dialog. The arguments to the
15635 function will be btn (the name of the button that was clicked, if applicable,
15636 e.g. "ok"), and text (the value of the active text field, if applicable).
15637 Progress and wait dialogs will ignore this option since they do not respond to
15638 user actions and can only be closed programmatically, so any required function
15639 should be called by the same code after it closes the dialog.
15640 icon String A CSS class that provides a background image to be used as an icon for
15641 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15642 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15643 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15644 modal Boolean False to allow user interaction with the page while the message box is
15645 displayed (defaults to true)
15646 msg String A string that will replace the existing message box body text (defaults
15647 to the XHTML-compliant non-breaking space character ' ')
15648 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15649 progress Boolean True to display a progress bar (defaults to false)
15650 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15651 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15652 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15653 title String The title text
15654 value String The string value to set into the active textbox element if displayed
15655 wait Boolean True to display a progress bar (defaults to false)
15656 width Number The width of the dialog in pixels
15663 msg: 'Please enter your address:',
15665 buttons: Roo.MessageBox.OKCANCEL,
15668 animEl: 'addAddressBtn'
15671 * @param {Object} config Configuration options
15672 * @return {Roo.MessageBox} This message box
15674 show : function(options){
15675 if(this.isVisible()){
15678 var d = this.getDialog();
15680 d.setTitle(opt.title || " ");
15681 d.close.setDisplayed(opt.closable !== false);
15682 activeTextEl = textboxEl;
15683 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15688 textareaEl.setHeight(typeof opt.multiline == "number" ?
15689 opt.multiline : this.defaultTextHeight);
15690 activeTextEl = textareaEl;
15699 progressEl.setDisplayed(opt.progress === true);
15700 this.updateProgress(0);
15701 activeTextEl.dom.value = opt.value || "";
15703 dlg.setDefaultButton(activeTextEl);
15705 var bs = opt.buttons;
15708 db = buttons["ok"];
15709 }else if(bs && bs.yes){
15710 db = buttons["yes"];
15712 dlg.setDefaultButton(db);
15714 bwidth = updateButtons(opt.buttons);
15715 this.updateText(opt.msg);
15717 d.el.addClass(opt.cls);
15719 d.proxyDrag = opt.proxyDrag === true;
15720 d.modal = opt.modal !== false;
15721 d.mask = opt.modal !== false ? mask : false;
15722 if(!d.isVisible()){
15723 // force it to the end of the z-index stack so it gets a cursor in FF
15724 document.body.appendChild(dlg.el.dom);
15725 d.animateTarget = null;
15726 d.show(options.animEl);
15732 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15733 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15734 * and closing the message box when the process is complete.
15735 * @param {String} title The title bar text
15736 * @param {String} msg The message box body text
15737 * @return {Roo.MessageBox} This message box
15739 progress : function(title, msg){
15746 minWidth: this.minProgressWidth,
15753 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15754 * If a callback function is passed it will be called after the user clicks the button, and the
15755 * id of the button that was clicked will be passed as the only parameter to the callback
15756 * (could also be the top-right close button).
15757 * @param {String} title The title bar text
15758 * @param {String} msg The message box body text
15759 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15760 * @param {Object} scope (optional) The scope of the callback function
15761 * @return {Roo.MessageBox} This message box
15763 alert : function(title, msg, fn, scope){
15776 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15777 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15778 * You are responsible for closing the message box when the process is complete.
15779 * @param {String} msg The message box body text
15780 * @param {String} title (optional) The title bar text
15781 * @return {Roo.MessageBox} This message box
15783 wait : function(msg, title){
15794 waitTimer = Roo.TaskMgr.start({
15796 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15804 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15805 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15806 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15807 * @param {String} title The title bar text
15808 * @param {String} msg The message box body text
15809 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15810 * @param {Object} scope (optional) The scope of the callback function
15811 * @return {Roo.MessageBox} This message box
15813 confirm : function(title, msg, fn, scope){
15817 buttons: this.YESNO,
15826 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15827 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15828 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15829 * (could also be the top-right close button) and the text that was entered will be passed as the two
15830 * parameters to the callback.
15831 * @param {String} title The title bar text
15832 * @param {String} msg The message box body text
15833 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15834 * @param {Object} scope (optional) The scope of the callback function
15835 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15836 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15837 * @return {Roo.MessageBox} This message box
15839 prompt : function(title, msg, fn, scope, multiline){
15843 buttons: this.OKCANCEL,
15848 multiline: multiline,
15855 * Button config that displays a single OK button
15860 * Button config that displays Yes and No buttons
15863 YESNO : {yes:true, no:true},
15865 * Button config that displays OK and Cancel buttons
15868 OKCANCEL : {ok:true, cancel:true},
15870 * Button config that displays Yes, No and Cancel buttons
15873 YESNOCANCEL : {yes:true, no:true, cancel:true},
15876 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15879 defaultTextHeight : 75,
15881 * The maximum width in pixels of the message box (defaults to 600)
15886 * The minimum width in pixels of the message box (defaults to 100)
15891 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15892 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15895 minProgressWidth : 250,
15897 * An object containing the default button text strings that can be overriden for localized language support.
15898 * Supported properties are: ok, cancel, yes and no.
15899 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15912 * Shorthand for {@link Roo.MessageBox}
15914 Roo.Msg = Roo.MessageBox;/*
15916 * Ext JS Library 1.1.1
15917 * Copyright(c) 2006-2007, Ext JS, LLC.
15919 * Originally Released Under LGPL - original licence link has changed is not relivant.
15922 * <script type="text/javascript">
15925 * @class Roo.QuickTips
15926 * Provides attractive and customizable tooltips for any element.
15929 Roo.QuickTips = function(){
15930 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15931 var ce, bd, xy, dd;
15932 var visible = false, disabled = true, inited = false;
15933 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15935 var onOver = function(e){
15939 var t = e.getTarget();
15940 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15943 if(ce && t == ce.el){
15944 clearTimeout(hideProc);
15947 if(t && tagEls[t.id]){
15948 tagEls[t.id].el = t;
15949 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15952 var ttp, et = Roo.fly(t);
15953 var ns = cfg.namespace;
15954 if(tm.interceptTitles && t.title){
15957 t.removeAttribute("title");
15958 e.preventDefault();
15960 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15963 showProc = show.defer(tm.showDelay, tm, [{
15966 width: et.getAttributeNS(ns, cfg.width),
15967 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15968 title: et.getAttributeNS(ns, cfg.title),
15969 cls: et.getAttributeNS(ns, cfg.cls)
15974 var onOut = function(e){
15975 clearTimeout(showProc);
15976 var t = e.getTarget();
15977 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15978 hideProc = setTimeout(hide, tm.hideDelay);
15982 var onMove = function(e){
15988 if(tm.trackMouse && ce){
15993 var onDown = function(e){
15994 clearTimeout(showProc);
15995 clearTimeout(hideProc);
15997 if(tm.hideOnClick){
16000 tm.enable.defer(100, tm);
16005 var getPad = function(){
16006 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
16009 var show = function(o){
16013 clearTimeout(dismissProc);
16015 if(removeCls){ // in case manually hidden
16016 el.removeClass(removeCls);
16020 el.addClass(ce.cls);
16021 removeCls = ce.cls;
16024 tipTitle.update(ce.title);
16027 tipTitle.update('');
16030 el.dom.style.width = tm.maxWidth+'px';
16031 //tipBody.dom.style.width = '';
16032 tipBodyText.update(o.text);
16033 var p = getPad(), w = ce.width;
16035 var td = tipBodyText.dom;
16036 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
16037 if(aw > tm.maxWidth){
16039 }else if(aw < tm.minWidth){
16045 //tipBody.setWidth(w);
16046 el.setWidth(parseInt(w, 10) + p);
16047 if(ce.autoHide === false){
16048 close.setDisplayed(true);
16053 close.setDisplayed(false);
16059 el.avoidY = xy[1]-18;
16064 el.setStyle("visibility", "visible");
16065 el.fadeIn({callback: afterShow});
16071 var afterShow = function(){
16075 if(tm.autoDismiss && ce.autoHide !== false){
16076 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16081 var hide = function(noanim){
16082 clearTimeout(dismissProc);
16083 clearTimeout(hideProc);
16085 if(el.isVisible()){
16087 if(noanim !== true && tm.animate){
16088 el.fadeOut({callback: afterHide});
16095 var afterHide = function(){
16098 el.removeClass(removeCls);
16105 * @cfg {Number} minWidth
16106 * The minimum width of the quick tip (defaults to 40)
16110 * @cfg {Number} maxWidth
16111 * The maximum width of the quick tip (defaults to 300)
16115 * @cfg {Boolean} interceptTitles
16116 * True to automatically use the element's DOM title value if available (defaults to false)
16118 interceptTitles : false,
16120 * @cfg {Boolean} trackMouse
16121 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16123 trackMouse : false,
16125 * @cfg {Boolean} hideOnClick
16126 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16128 hideOnClick : true,
16130 * @cfg {Number} showDelay
16131 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16135 * @cfg {Number} hideDelay
16136 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16140 * @cfg {Boolean} autoHide
16141 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16142 * Used in conjunction with hideDelay.
16147 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16148 * (defaults to true). Used in conjunction with autoDismissDelay.
16150 autoDismiss : true,
16153 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16155 autoDismissDelay : 5000,
16157 * @cfg {Boolean} animate
16158 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16163 * @cfg {String} title
16164 * Title text to display (defaults to ''). This can be any valid HTML markup.
16168 * @cfg {String} text
16169 * Body text to display (defaults to ''). This can be any valid HTML markup.
16173 * @cfg {String} cls
16174 * A CSS class to apply to the base quick tip element (defaults to '').
16178 * @cfg {Number} width
16179 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16180 * minWidth or maxWidth.
16185 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16186 * or display QuickTips in a page.
16189 tm = Roo.QuickTips;
16190 cfg = tm.tagConfig;
16192 if(!Roo.isReady){ // allow calling of init() before onReady
16193 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16196 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16197 el.fxDefaults = {stopFx: true};
16198 // maximum custom styling
16199 //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>');
16200 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>');
16201 tipTitle = el.child('h3');
16202 tipTitle.enableDisplayMode("block");
16203 tipBody = el.child('div.x-tip-bd');
16204 tipBodyText = el.child('div.x-tip-bd-inner');
16205 //bdLeft = el.child('div.x-tip-bd-left');
16206 //bdRight = el.child('div.x-tip-bd-right');
16207 close = el.child('div.x-tip-close');
16208 close.enableDisplayMode("block");
16209 close.on("click", hide);
16210 var d = Roo.get(document);
16211 d.on("mousedown", onDown);
16212 d.on("mouseover", onOver);
16213 d.on("mouseout", onOut);
16214 d.on("mousemove", onMove);
16215 esc = d.addKeyListener(27, hide);
16218 dd = el.initDD("default", null, {
16219 onDrag : function(){
16223 dd.setHandleElId(tipTitle.id);
16232 * Configures a new quick tip instance and assigns it to a target element. The following config options
16235 Property Type Description
16236 ---------- --------------------- ------------------------------------------------------------------------
16237 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16239 * @param {Object} config The config object
16241 register : function(config){
16242 var cs = config instanceof Array ? config : arguments;
16243 for(var i = 0, len = cs.length; i < len; i++) {
16245 var target = c.target;
16247 if(target instanceof Array){
16248 for(var j = 0, jlen = target.length; j < jlen; j++){
16249 tagEls[target[j]] = c;
16252 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16259 * Removes this quick tip from its element and destroys it.
16260 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16262 unregister : function(el){
16263 delete tagEls[Roo.id(el)];
16267 * Enable this quick tip.
16269 enable : function(){
16270 if(inited && disabled){
16272 if(locks.length < 1){
16279 * Disable this quick tip.
16281 disable : function(){
16283 clearTimeout(showProc);
16284 clearTimeout(hideProc);
16285 clearTimeout(dismissProc);
16293 * Returns true if the quick tip is enabled, else false.
16295 isEnabled : function(){
16302 attribute : "qtip",
16312 // backwards compat
16313 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16315 * Ext JS Library 1.1.1
16316 * Copyright(c) 2006-2007, Ext JS, LLC.
16318 * Originally Released Under LGPL - original licence link has changed is not relivant.
16321 * <script type="text/javascript">
16326 * @class Roo.tree.TreePanel
16327 * @extends Roo.data.Tree
16329 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16330 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16331 * @cfg {Boolean} enableDD true to enable drag and drop
16332 * @cfg {Boolean} enableDrag true to enable just drag
16333 * @cfg {Boolean} enableDrop true to enable just drop
16334 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16335 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16336 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16337 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16338 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16339 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16340 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16341 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16342 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16343 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16344 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16345 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16346 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16347 * @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>
16348 * @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>
16351 * @param {String/HTMLElement/Element} el The container element
16352 * @param {Object} config
16354 Roo.tree.TreePanel = function(el, config){
16356 var loader = false;
16358 root = config.root;
16359 delete config.root;
16361 if (config.loader) {
16362 loader = config.loader;
16363 delete config.loader;
16366 Roo.apply(this, config);
16367 Roo.tree.TreePanel.superclass.constructor.call(this);
16368 this.el = Roo.get(el);
16369 this.el.addClass('x-tree');
16370 //console.log(root);
16372 this.setRootNode( Roo.factory(root, Roo.tree));
16375 this.loader = Roo.factory(loader, Roo.tree);
16378 * Read-only. The id of the container element becomes this TreePanel's id.
16380 this.id = this.el.id;
16383 * @event beforeload
16384 * Fires before a node is loaded, return false to cancel
16385 * @param {Node} node The node being loaded
16387 "beforeload" : true,
16390 * Fires when a node is loaded
16391 * @param {Node} node The node that was loaded
16395 * @event textchange
16396 * Fires when the text for a node is changed
16397 * @param {Node} node The node
16398 * @param {String} text The new text
16399 * @param {String} oldText The old text
16401 "textchange" : true,
16403 * @event beforeexpand
16404 * Fires before a node is expanded, return false to cancel.
16405 * @param {Node} node The node
16406 * @param {Boolean} deep
16407 * @param {Boolean} anim
16409 "beforeexpand" : true,
16411 * @event beforecollapse
16412 * Fires before a node is collapsed, return false to cancel.
16413 * @param {Node} node The node
16414 * @param {Boolean} deep
16415 * @param {Boolean} anim
16417 "beforecollapse" : true,
16420 * Fires when a node is expanded
16421 * @param {Node} node The node
16425 * @event disabledchange
16426 * Fires when the disabled status of a node changes
16427 * @param {Node} node The node
16428 * @param {Boolean} disabled
16430 "disabledchange" : true,
16433 * Fires when a node is collapsed
16434 * @param {Node} node The node
16438 * @event beforeclick
16439 * Fires before click processing on a node. Return false to cancel the default action.
16440 * @param {Node} node The node
16441 * @param {Roo.EventObject} e The event object
16443 "beforeclick":true,
16445 * @event checkchange
16446 * Fires when a node with a checkbox's checked property changes
16447 * @param {Node} this This node
16448 * @param {Boolean} checked
16450 "checkchange":true,
16453 * Fires when a node is clicked
16454 * @param {Node} node The node
16455 * @param {Roo.EventObject} e The event object
16460 * Fires when a node is double clicked
16461 * @param {Node} node The node
16462 * @param {Roo.EventObject} e The event object
16466 * @event contextmenu
16467 * Fires when a node is right clicked
16468 * @param {Node} node The node
16469 * @param {Roo.EventObject} e The event object
16471 "contextmenu":true,
16473 * @event beforechildrenrendered
16474 * Fires right before the child nodes for a node are rendered
16475 * @param {Node} node The node
16477 "beforechildrenrendered":true,
16480 * Fires when a node starts being dragged
16481 * @param {Roo.tree.TreePanel} this
16482 * @param {Roo.tree.TreeNode} node
16483 * @param {event} e The raw browser event
16485 "startdrag" : true,
16488 * Fires when a drag operation is complete
16489 * @param {Roo.tree.TreePanel} this
16490 * @param {Roo.tree.TreeNode} node
16491 * @param {event} e The raw browser event
16496 * Fires when a dragged node is dropped on a valid DD target
16497 * @param {Roo.tree.TreePanel} this
16498 * @param {Roo.tree.TreeNode} node
16499 * @param {DD} dd The dd it was dropped on
16500 * @param {event} e The raw browser event
16504 * @event beforenodedrop
16505 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16506 * passed to handlers has the following properties:<br />
16507 * <ul style="padding:5px;padding-left:16px;">
16508 * <li>tree - The TreePanel</li>
16509 * <li>target - The node being targeted for the drop</li>
16510 * <li>data - The drag data from the drag source</li>
16511 * <li>point - The point of the drop - append, above or below</li>
16512 * <li>source - The drag source</li>
16513 * <li>rawEvent - Raw mouse event</li>
16514 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16515 * to be inserted by setting them on this object.</li>
16516 * <li>cancel - Set this to true to cancel the drop.</li>
16518 * @param {Object} dropEvent
16520 "beforenodedrop" : true,
16523 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16524 * passed to handlers has the following properties:<br />
16525 * <ul style="padding:5px;padding-left:16px;">
16526 * <li>tree - The TreePanel</li>
16527 * <li>target - The node being targeted for the drop</li>
16528 * <li>data - The drag data from the drag source</li>
16529 * <li>point - The point of the drop - append, above or below</li>
16530 * <li>source - The drag source</li>
16531 * <li>rawEvent - Raw mouse event</li>
16532 * <li>dropNode - Dropped node(s).</li>
16534 * @param {Object} dropEvent
16538 * @event nodedragover
16539 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16540 * passed to handlers has the following properties:<br />
16541 * <ul style="padding:5px;padding-left:16px;">
16542 * <li>tree - The TreePanel</li>
16543 * <li>target - The node being targeted for the drop</li>
16544 * <li>data - The drag data from the drag source</li>
16545 * <li>point - The point of the drop - append, above or below</li>
16546 * <li>source - The drag source</li>
16547 * <li>rawEvent - Raw mouse event</li>
16548 * <li>dropNode - Drop node(s) provided by the source.</li>
16549 * <li>cancel - Set this to true to signal drop not allowed.</li>
16551 * @param {Object} dragOverEvent
16553 "nodedragover" : true
16556 if(this.singleExpand){
16557 this.on("beforeexpand", this.restrictExpand, this);
16560 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16561 rootVisible : true,
16562 animate: Roo.enableFx,
16565 hlDrop : Roo.enableFx,
16569 rendererTip: false,
16571 restrictExpand : function(node){
16572 var p = node.parentNode;
16574 if(p.expandedChild && p.expandedChild.parentNode == p){
16575 p.expandedChild.collapse();
16577 p.expandedChild = node;
16581 // private override
16582 setRootNode : function(node){
16583 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16584 if(!this.rootVisible){
16585 node.ui = new Roo.tree.RootTreeNodeUI(node);
16591 * Returns the container element for this TreePanel
16593 getEl : function(){
16598 * Returns the default TreeLoader for this TreePanel
16600 getLoader : function(){
16601 return this.loader;
16607 expandAll : function(){
16608 this.root.expand(true);
16612 * Collapse all nodes
16614 collapseAll : function(){
16615 this.root.collapse(true);
16619 * Returns the selection model used by this TreePanel
16621 getSelectionModel : function(){
16622 if(!this.selModel){
16623 this.selModel = new Roo.tree.DefaultSelectionModel();
16625 return this.selModel;
16629 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16630 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16631 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16634 getChecked : function(a, startNode){
16635 startNode = startNode || this.root;
16637 var f = function(){
16638 if(this.attributes.checked){
16639 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16642 startNode.cascade(f);
16647 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16648 * @param {String} path
16649 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16650 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16651 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16653 expandPath : function(path, attr, callback){
16654 attr = attr || "id";
16655 var keys = path.split(this.pathSeparator);
16656 var curNode = this.root;
16657 if(curNode.attributes[attr] != keys[1]){ // invalid root
16659 callback(false, null);
16664 var f = function(){
16665 if(++index == keys.length){
16667 callback(true, curNode);
16671 var c = curNode.findChild(attr, keys[index]);
16674 callback(false, curNode);
16679 c.expand(false, false, f);
16681 curNode.expand(false, false, f);
16685 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16686 * @param {String} path
16687 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16688 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16689 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16691 selectPath : function(path, attr, callback){
16692 attr = attr || "id";
16693 var keys = path.split(this.pathSeparator);
16694 var v = keys.pop();
16695 if(keys.length > 0){
16696 var f = function(success, node){
16697 if(success && node){
16698 var n = node.findChild(attr, v);
16704 }else if(callback){
16705 callback(false, n);
16709 callback(false, n);
16713 this.expandPath(keys.join(this.pathSeparator), attr, f);
16715 this.root.select();
16717 callback(true, this.root);
16722 getTreeEl : function(){
16727 * Trigger rendering of this TreePanel
16729 render : function(){
16730 if (this.innerCt) {
16731 return this; // stop it rendering more than once!!
16734 this.innerCt = this.el.createChild({tag:"ul",
16735 cls:"x-tree-root-ct " +
16736 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16738 if(this.containerScroll){
16739 Roo.dd.ScrollManager.register(this.el);
16741 if((this.enableDD || this.enableDrop) && !this.dropZone){
16743 * The dropZone used by this tree if drop is enabled
16744 * @type Roo.tree.TreeDropZone
16746 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16747 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16750 if((this.enableDD || this.enableDrag) && !this.dragZone){
16752 * The dragZone used by this tree if drag is enabled
16753 * @type Roo.tree.TreeDragZone
16755 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16756 ddGroup: this.ddGroup || "TreeDD",
16757 scroll: this.ddScroll
16760 this.getSelectionModel().init(this);
16762 console.log("ROOT not set in tree");
16765 this.root.render();
16766 if(!this.rootVisible){
16767 this.root.renderChildren();
16773 * Ext JS Library 1.1.1
16774 * Copyright(c) 2006-2007, Ext JS, LLC.
16776 * Originally Released Under LGPL - original licence link has changed is not relivant.
16779 * <script type="text/javascript">
16784 * @class Roo.tree.DefaultSelectionModel
16785 * @extends Roo.util.Observable
16786 * The default single selection for a TreePanel.
16788 Roo.tree.DefaultSelectionModel = function(){
16789 this.selNode = null;
16793 * @event selectionchange
16794 * Fires when the selected node changes
16795 * @param {DefaultSelectionModel} this
16796 * @param {TreeNode} node the new selection
16798 "selectionchange" : true,
16801 * @event beforeselect
16802 * Fires before the selected node changes, return false to cancel the change
16803 * @param {DefaultSelectionModel} this
16804 * @param {TreeNode} node the new selection
16805 * @param {TreeNode} node the old selection
16807 "beforeselect" : true
16811 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16812 init : function(tree){
16814 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16815 tree.on("click", this.onNodeClick, this);
16818 onNodeClick : function(node, e){
16819 if (e.ctrlKey && this.selNode == node) {
16820 this.unselect(node);
16828 * @param {TreeNode} node The node to select
16829 * @return {TreeNode} The selected node
16831 select : function(node){
16832 var last = this.selNode;
16833 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16835 last.ui.onSelectedChange(false);
16837 this.selNode = node;
16838 node.ui.onSelectedChange(true);
16839 this.fireEvent("selectionchange", this, node, last);
16846 * @param {TreeNode} node The node to unselect
16848 unselect : function(node){
16849 if(this.selNode == node){
16850 this.clearSelections();
16855 * Clear all selections
16857 clearSelections : function(){
16858 var n = this.selNode;
16860 n.ui.onSelectedChange(false);
16861 this.selNode = null;
16862 this.fireEvent("selectionchange", this, null);
16868 * Get the selected node
16869 * @return {TreeNode} The selected node
16871 getSelectedNode : function(){
16872 return this.selNode;
16876 * Returns true if the node is selected
16877 * @param {TreeNode} node The node to check
16878 * @return {Boolean}
16880 isSelected : function(node){
16881 return this.selNode == node;
16885 * Selects the node above the selected node in the tree, intelligently walking the nodes
16886 * @return TreeNode The new selection
16888 selectPrevious : function(){
16889 var s = this.selNode || this.lastSelNode;
16893 var ps = s.previousSibling;
16895 if(!ps.isExpanded() || ps.childNodes.length < 1){
16896 return this.select(ps);
16898 var lc = ps.lastChild;
16899 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16902 return this.select(lc);
16904 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16905 return this.select(s.parentNode);
16911 * Selects the node above the selected node in the tree, intelligently walking the nodes
16912 * @return TreeNode The new selection
16914 selectNext : function(){
16915 var s = this.selNode || this.lastSelNode;
16919 if(s.firstChild && s.isExpanded()){
16920 return this.select(s.firstChild);
16921 }else if(s.nextSibling){
16922 return this.select(s.nextSibling);
16923 }else if(s.parentNode){
16925 s.parentNode.bubble(function(){
16926 if(this.nextSibling){
16927 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16936 onKeyDown : function(e){
16937 var s = this.selNode || this.lastSelNode;
16938 // undesirable, but required
16943 var k = e.getKey();
16951 this.selectPrevious();
16954 e.preventDefault();
16955 if(s.hasChildNodes()){
16956 if(!s.isExpanded()){
16958 }else if(s.firstChild){
16959 this.select(s.firstChild, e);
16964 e.preventDefault();
16965 if(s.hasChildNodes() && s.isExpanded()){
16967 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16968 this.select(s.parentNode, e);
16976 * @class Roo.tree.MultiSelectionModel
16977 * @extends Roo.util.Observable
16978 * Multi selection for a TreePanel.
16980 Roo.tree.MultiSelectionModel = function(){
16981 this.selNodes = [];
16985 * @event selectionchange
16986 * Fires when the selected nodes change
16987 * @param {MultiSelectionModel} this
16988 * @param {Array} nodes Array of the selected nodes
16990 "selectionchange" : true
16994 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16995 init : function(tree){
16997 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16998 tree.on("click", this.onNodeClick, this);
17001 onNodeClick : function(node, e){
17002 this.select(node, e, e.ctrlKey);
17007 * @param {TreeNode} node The node to select
17008 * @param {EventObject} e (optional) An event associated with the selection
17009 * @param {Boolean} keepExisting True to retain existing selections
17010 * @return {TreeNode} The selected node
17012 select : function(node, e, keepExisting){
17013 if(keepExisting !== true){
17014 this.clearSelections(true);
17016 if(this.isSelected(node)){
17017 this.lastSelNode = node;
17020 this.selNodes.push(node);
17021 this.selMap[node.id] = node;
17022 this.lastSelNode = node;
17023 node.ui.onSelectedChange(true);
17024 this.fireEvent("selectionchange", this, this.selNodes);
17030 * @param {TreeNode} node The node to unselect
17032 unselect : function(node){
17033 if(this.selMap[node.id]){
17034 node.ui.onSelectedChange(false);
17035 var sn = this.selNodes;
17038 index = sn.indexOf(node);
17040 for(var i = 0, len = sn.length; i < len; i++){
17048 this.selNodes.splice(index, 1);
17050 delete this.selMap[node.id];
17051 this.fireEvent("selectionchange", this, this.selNodes);
17056 * Clear all selections
17058 clearSelections : function(suppressEvent){
17059 var sn = this.selNodes;
17061 for(var i = 0, len = sn.length; i < len; i++){
17062 sn[i].ui.onSelectedChange(false);
17064 this.selNodes = [];
17066 if(suppressEvent !== true){
17067 this.fireEvent("selectionchange", this, this.selNodes);
17073 * Returns true if the node is selected
17074 * @param {TreeNode} node The node to check
17075 * @return {Boolean}
17077 isSelected : function(node){
17078 return this.selMap[node.id] ? true : false;
17082 * Returns an array of the selected nodes
17085 getSelectedNodes : function(){
17086 return this.selNodes;
17089 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17091 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17093 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17096 * Ext JS Library 1.1.1
17097 * Copyright(c) 2006-2007, Ext JS, LLC.
17099 * Originally Released Under LGPL - original licence link has changed is not relivant.
17102 * <script type="text/javascript">
17106 * @class Roo.tree.TreeNode
17107 * @extends Roo.data.Node
17108 * @cfg {String} text The text for this node
17109 * @cfg {Boolean} expanded true to start the node expanded
17110 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17111 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17112 * @cfg {Boolean} disabled true to start the node disabled
17113 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17114 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17115 * @cfg {String} cls A css class to be added to the node
17116 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17117 * @cfg {String} href URL of the link used for the node (defaults to #)
17118 * @cfg {String} hrefTarget target frame for the link
17119 * @cfg {String} qtip An Ext QuickTip for the node
17120 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17121 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17122 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17123 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17124 * (defaults to undefined with no checkbox rendered)
17126 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17128 Roo.tree.TreeNode = function(attributes){
17129 attributes = attributes || {};
17130 if(typeof attributes == "string"){
17131 attributes = {text: attributes};
17133 this.childrenRendered = false;
17134 this.rendered = false;
17135 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17136 this.expanded = attributes.expanded === true;
17137 this.isTarget = attributes.isTarget !== false;
17138 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17139 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17142 * Read-only. The text for this node. To change it use setText().
17145 this.text = attributes.text;
17147 * True if this node is disabled.
17150 this.disabled = attributes.disabled === true;
17154 * @event textchange
17155 * Fires when the text for this node is changed
17156 * @param {Node} this This node
17157 * @param {String} text The new text
17158 * @param {String} oldText The old text
17160 "textchange" : true,
17162 * @event beforeexpand
17163 * Fires before this node is expanded, return false to cancel.
17164 * @param {Node} this This node
17165 * @param {Boolean} deep
17166 * @param {Boolean} anim
17168 "beforeexpand" : true,
17170 * @event beforecollapse
17171 * Fires before this node is collapsed, return false to cancel.
17172 * @param {Node} this This node
17173 * @param {Boolean} deep
17174 * @param {Boolean} anim
17176 "beforecollapse" : true,
17179 * Fires when this node is expanded
17180 * @param {Node} this This node
17184 * @event disabledchange
17185 * Fires when the disabled status of this node changes
17186 * @param {Node} this This node
17187 * @param {Boolean} disabled
17189 "disabledchange" : true,
17192 * Fires when this node is collapsed
17193 * @param {Node} this This node
17197 * @event beforeclick
17198 * Fires before click processing. Return false to cancel the default action.
17199 * @param {Node} this This node
17200 * @param {Roo.EventObject} e The event object
17202 "beforeclick":true,
17204 * @event checkchange
17205 * Fires when a node with a checkbox's checked property changes
17206 * @param {Node} this This node
17207 * @param {Boolean} checked
17209 "checkchange":true,
17212 * Fires when this node is clicked
17213 * @param {Node} this This node
17214 * @param {Roo.EventObject} e The event object
17219 * Fires when this node is double clicked
17220 * @param {Node} this This node
17221 * @param {Roo.EventObject} e The event object
17225 * @event contextmenu
17226 * Fires when this node is right clicked
17227 * @param {Node} this This node
17228 * @param {Roo.EventObject} e The event object
17230 "contextmenu":true,
17232 * @event beforechildrenrendered
17233 * Fires right before the child nodes for this node are rendered
17234 * @param {Node} this This node
17236 "beforechildrenrendered":true
17239 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17242 * Read-only. The UI for this node
17245 this.ui = new uiClass(this);
17247 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17248 preventHScroll: true,
17250 * Returns true if this node is expanded
17251 * @return {Boolean}
17253 isExpanded : function(){
17254 return this.expanded;
17258 * Returns the UI object for this node
17259 * @return {TreeNodeUI}
17261 getUI : function(){
17265 // private override
17266 setFirstChild : function(node){
17267 var of = this.firstChild;
17268 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17269 if(this.childrenRendered && of && node != of){
17270 of.renderIndent(true, true);
17273 this.renderIndent(true, true);
17277 // private override
17278 setLastChild : function(node){
17279 var ol = this.lastChild;
17280 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17281 if(this.childrenRendered && ol && node != ol){
17282 ol.renderIndent(true, true);
17285 this.renderIndent(true, true);
17289 // these methods are overridden to provide lazy rendering support
17290 // private override
17291 appendChild : function(){
17292 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17293 if(node && this.childrenRendered){
17296 this.ui.updateExpandIcon();
17300 // private override
17301 removeChild : function(node){
17302 this.ownerTree.getSelectionModel().unselect(node);
17303 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17304 // if it's been rendered remove dom node
17305 if(this.childrenRendered){
17308 if(this.childNodes.length < 1){
17309 this.collapse(false, false);
17311 this.ui.updateExpandIcon();
17313 if(!this.firstChild) {
17314 this.childrenRendered = false;
17319 // private override
17320 insertBefore : function(node, refNode){
17321 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17322 if(newNode && refNode && this.childrenRendered){
17325 this.ui.updateExpandIcon();
17330 * Sets the text for this node
17331 * @param {String} text
17333 setText : function(text){
17334 var oldText = this.text;
17336 this.attributes.text = text;
17337 if(this.rendered){ // event without subscribing
17338 this.ui.onTextChange(this, text, oldText);
17340 this.fireEvent("textchange", this, text, oldText);
17344 * Triggers selection of this node
17346 select : function(){
17347 this.getOwnerTree().getSelectionModel().select(this);
17351 * Triggers deselection of this node
17353 unselect : function(){
17354 this.getOwnerTree().getSelectionModel().unselect(this);
17358 * Returns true if this node is selected
17359 * @return {Boolean}
17361 isSelected : function(){
17362 return this.getOwnerTree().getSelectionModel().isSelected(this);
17366 * Expand this node.
17367 * @param {Boolean} deep (optional) True to expand all children as well
17368 * @param {Boolean} anim (optional) false to cancel the default animation
17369 * @param {Function} callback (optional) A callback to be called when
17370 * expanding this node completes (does not wait for deep expand to complete).
17371 * Called with 1 parameter, this node.
17373 expand : function(deep, anim, callback){
17374 if(!this.expanded){
17375 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17378 if(!this.childrenRendered){
17379 this.renderChildren();
17381 this.expanded = true;
17382 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17383 this.ui.animExpand(function(){
17384 this.fireEvent("expand", this);
17385 if(typeof callback == "function"){
17389 this.expandChildNodes(true);
17391 }.createDelegate(this));
17395 this.fireEvent("expand", this);
17396 if(typeof callback == "function"){
17401 if(typeof callback == "function"){
17406 this.expandChildNodes(true);
17410 isHiddenRoot : function(){
17411 return this.isRoot && !this.getOwnerTree().rootVisible;
17415 * Collapse this node.
17416 * @param {Boolean} deep (optional) True to collapse all children as well
17417 * @param {Boolean} anim (optional) false to cancel the default animation
17419 collapse : function(deep, anim){
17420 if(this.expanded && !this.isHiddenRoot()){
17421 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17424 this.expanded = false;
17425 if((this.getOwnerTree().animate && anim !== false) || anim){
17426 this.ui.animCollapse(function(){
17427 this.fireEvent("collapse", this);
17429 this.collapseChildNodes(true);
17431 }.createDelegate(this));
17434 this.ui.collapse();
17435 this.fireEvent("collapse", this);
17439 var cs = this.childNodes;
17440 for(var i = 0, len = cs.length; i < len; i++) {
17441 cs[i].collapse(true, false);
17447 delayedExpand : function(delay){
17448 if(!this.expandProcId){
17449 this.expandProcId = this.expand.defer(delay, this);
17454 cancelExpand : function(){
17455 if(this.expandProcId){
17456 clearTimeout(this.expandProcId);
17458 this.expandProcId = false;
17462 * Toggles expanded/collapsed state of the node
17464 toggle : function(){
17473 * Ensures all parent nodes are expanded
17475 ensureVisible : function(callback){
17476 var tree = this.getOwnerTree();
17477 tree.expandPath(this.parentNode.getPath(), false, function(){
17478 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17479 Roo.callback(callback);
17480 }.createDelegate(this));
17484 * Expand all child nodes
17485 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17487 expandChildNodes : function(deep){
17488 var cs = this.childNodes;
17489 for(var i = 0, len = cs.length; i < len; i++) {
17490 cs[i].expand(deep);
17495 * Collapse all child nodes
17496 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17498 collapseChildNodes : function(deep){
17499 var cs = this.childNodes;
17500 for(var i = 0, len = cs.length; i < len; i++) {
17501 cs[i].collapse(deep);
17506 * Disables this node
17508 disable : function(){
17509 this.disabled = true;
17511 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17512 this.ui.onDisableChange(this, true);
17514 this.fireEvent("disabledchange", this, true);
17518 * Enables this node
17520 enable : function(){
17521 this.disabled = false;
17522 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17523 this.ui.onDisableChange(this, false);
17525 this.fireEvent("disabledchange", this, false);
17529 renderChildren : function(suppressEvent){
17530 if(suppressEvent !== false){
17531 this.fireEvent("beforechildrenrendered", this);
17533 var cs = this.childNodes;
17534 for(var i = 0, len = cs.length; i < len; i++){
17535 cs[i].render(true);
17537 this.childrenRendered = true;
17541 sort : function(fn, scope){
17542 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17543 if(this.childrenRendered){
17544 var cs = this.childNodes;
17545 for(var i = 0, len = cs.length; i < len; i++){
17546 cs[i].render(true);
17552 render : function(bulkRender){
17553 this.ui.render(bulkRender);
17554 if(!this.rendered){
17555 this.rendered = true;
17557 this.expanded = false;
17558 this.expand(false, false);
17564 renderIndent : function(deep, refresh){
17566 this.ui.childIndent = null;
17568 this.ui.renderIndent();
17569 if(deep === true && this.childrenRendered){
17570 var cs = this.childNodes;
17571 for(var i = 0, len = cs.length; i < len; i++){
17572 cs[i].renderIndent(true, refresh);
17578 * Ext JS Library 1.1.1
17579 * Copyright(c) 2006-2007, Ext JS, LLC.
17581 * Originally Released Under LGPL - original licence link has changed is not relivant.
17584 * <script type="text/javascript">
17588 * @class Roo.tree.AsyncTreeNode
17589 * @extends Roo.tree.TreeNode
17590 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17592 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17594 Roo.tree.AsyncTreeNode = function(config){
17595 this.loaded = false;
17596 this.loading = false;
17597 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17599 * @event beforeload
17600 * Fires before this node is loaded, return false to cancel
17601 * @param {Node} this This node
17603 this.addEvents({'beforeload':true, 'load': true});
17606 * Fires when this node is loaded
17607 * @param {Node} this This node
17610 * The loader used by this node (defaults to using the tree's defined loader)
17615 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17616 expand : function(deep, anim, callback){
17617 if(this.loading){ // if an async load is already running, waiting til it's done
17619 var f = function(){
17620 if(!this.loading){ // done loading
17621 clearInterval(timer);
17622 this.expand(deep, anim, callback);
17624 }.createDelegate(this);
17625 timer = setInterval(f, 200);
17629 if(this.fireEvent("beforeload", this) === false){
17632 this.loading = true;
17633 this.ui.beforeLoad(this);
17634 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17636 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17640 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17644 * Returns true if this node is currently loading
17645 * @return {Boolean}
17647 isLoading : function(){
17648 return this.loading;
17651 loadComplete : function(deep, anim, callback){
17652 this.loading = false;
17653 this.loaded = true;
17654 this.ui.afterLoad(this);
17655 this.fireEvent("load", this);
17656 this.expand(deep, anim, callback);
17660 * Returns true if this node has been loaded
17661 * @return {Boolean}
17663 isLoaded : function(){
17664 return this.loaded;
17667 hasChildNodes : function(){
17668 if(!this.isLeaf() && !this.loaded){
17671 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17676 * Trigger a reload for this node
17677 * @param {Function} callback
17679 reload : function(callback){
17680 this.collapse(false, false);
17681 while(this.firstChild){
17682 this.removeChild(this.firstChild);
17684 this.childrenRendered = false;
17685 this.loaded = false;
17686 if(this.isHiddenRoot()){
17687 this.expanded = false;
17689 this.expand(false, false, callback);
17693 * Ext JS Library 1.1.1
17694 * Copyright(c) 2006-2007, Ext JS, LLC.
17696 * Originally Released Under LGPL - original licence link has changed is not relivant.
17699 * <script type="text/javascript">
17703 * @class Roo.tree.TreeNodeUI
17705 * @param {Object} node The node to render
17706 * The TreeNode UI implementation is separate from the
17707 * tree implementation. Unless you are customizing the tree UI,
17708 * you should never have to use this directly.
17710 Roo.tree.TreeNodeUI = function(node){
17712 this.rendered = false;
17713 this.animating = false;
17714 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17717 Roo.tree.TreeNodeUI.prototype = {
17718 removeChild : function(node){
17720 this.ctNode.removeChild(node.ui.getEl());
17724 beforeLoad : function(){
17725 this.addClass("x-tree-node-loading");
17728 afterLoad : function(){
17729 this.removeClass("x-tree-node-loading");
17732 onTextChange : function(node, text, oldText){
17734 this.textNode.innerHTML = text;
17738 onDisableChange : function(node, state){
17739 this.disabled = state;
17741 this.addClass("x-tree-node-disabled");
17743 this.removeClass("x-tree-node-disabled");
17747 onSelectedChange : function(state){
17750 this.addClass("x-tree-selected");
17753 this.removeClass("x-tree-selected");
17757 onMove : function(tree, node, oldParent, newParent, index, refNode){
17758 this.childIndent = null;
17760 var targetNode = newParent.ui.getContainer();
17761 if(!targetNode){//target not rendered
17762 this.holder = document.createElement("div");
17763 this.holder.appendChild(this.wrap);
17766 var insertBefore = refNode ? refNode.ui.getEl() : null;
17768 targetNode.insertBefore(this.wrap, insertBefore);
17770 targetNode.appendChild(this.wrap);
17772 this.node.renderIndent(true);
17776 addClass : function(cls){
17778 Roo.fly(this.elNode).addClass(cls);
17782 removeClass : function(cls){
17784 Roo.fly(this.elNode).removeClass(cls);
17788 remove : function(){
17790 this.holder = document.createElement("div");
17791 this.holder.appendChild(this.wrap);
17795 fireEvent : function(){
17796 return this.node.fireEvent.apply(this.node, arguments);
17799 initEvents : function(){
17800 this.node.on("move", this.onMove, this);
17801 var E = Roo.EventManager;
17802 var a = this.anchor;
17804 var el = Roo.fly(a, '_treeui');
17806 if(Roo.isOpera){ // opera render bug ignores the CSS
17807 el.setStyle("text-decoration", "none");
17810 el.on("click", this.onClick, this);
17811 el.on("dblclick", this.onDblClick, this);
17814 Roo.EventManager.on(this.checkbox,
17815 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17818 el.on("contextmenu", this.onContextMenu, this);
17820 var icon = Roo.fly(this.iconNode);
17821 icon.on("click", this.onClick, this);
17822 icon.on("dblclick", this.onDblClick, this);
17823 icon.on("contextmenu", this.onContextMenu, this);
17824 E.on(this.ecNode, "click", this.ecClick, this, true);
17826 if(this.node.disabled){
17827 this.addClass("x-tree-node-disabled");
17829 if(this.node.hidden){
17830 this.addClass("x-tree-node-disabled");
17832 var ot = this.node.getOwnerTree();
17833 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17834 if(dd && (!this.node.isRoot || ot.rootVisible)){
17835 Roo.dd.Registry.register(this.elNode, {
17837 handles: this.getDDHandles(),
17843 getDDHandles : function(){
17844 return [this.iconNode, this.textNode];
17849 this.wrap.style.display = "none";
17855 this.wrap.style.display = "";
17859 onContextMenu : function(e){
17860 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17861 e.preventDefault();
17863 this.fireEvent("contextmenu", this.node, e);
17867 onClick : function(e){
17872 if(this.fireEvent("beforeclick", this.node, e) !== false){
17873 if(!this.disabled && this.node.attributes.href){
17874 this.fireEvent("click", this.node, e);
17877 e.preventDefault();
17882 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17883 this.node.toggle();
17886 this.fireEvent("click", this.node, e);
17892 onDblClick : function(e){
17893 e.preventDefault();
17898 this.toggleCheck();
17900 if(!this.animating && this.node.hasChildNodes()){
17901 this.node.toggle();
17903 this.fireEvent("dblclick", this.node, e);
17906 onCheckChange : function(){
17907 var checked = this.checkbox.checked;
17908 this.node.attributes.checked = checked;
17909 this.fireEvent('checkchange', this.node, checked);
17912 ecClick : function(e){
17913 if(!this.animating && this.node.hasChildNodes()){
17914 this.node.toggle();
17918 startDrop : function(){
17919 this.dropping = true;
17922 // delayed drop so the click event doesn't get fired on a drop
17923 endDrop : function(){
17924 setTimeout(function(){
17925 this.dropping = false;
17926 }.createDelegate(this), 50);
17929 expand : function(){
17930 this.updateExpandIcon();
17931 this.ctNode.style.display = "";
17934 focus : function(){
17935 if(!this.node.preventHScroll){
17936 try{this.anchor.focus();
17938 }else if(!Roo.isIE){
17940 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17941 var l = noscroll.scrollLeft;
17942 this.anchor.focus();
17943 noscroll.scrollLeft = l;
17948 toggleCheck : function(value){
17949 var cb = this.checkbox;
17951 cb.checked = (value === undefined ? !cb.checked : value);
17957 this.anchor.blur();
17961 animExpand : function(callback){
17962 var ct = Roo.get(this.ctNode);
17964 if(!this.node.hasChildNodes()){
17965 this.updateExpandIcon();
17966 this.ctNode.style.display = "";
17967 Roo.callback(callback);
17970 this.animating = true;
17971 this.updateExpandIcon();
17974 callback : function(){
17975 this.animating = false;
17976 Roo.callback(callback);
17979 duration: this.node.ownerTree.duration || .25
17983 highlight : function(){
17984 var tree = this.node.getOwnerTree();
17985 Roo.fly(this.wrap).highlight(
17986 tree.hlColor || "C3DAF9",
17987 {endColor: tree.hlBaseColor}
17991 collapse : function(){
17992 this.updateExpandIcon();
17993 this.ctNode.style.display = "none";
17996 animCollapse : function(callback){
17997 var ct = Roo.get(this.ctNode);
17998 ct.enableDisplayMode('block');
18001 this.animating = true;
18002 this.updateExpandIcon();
18005 callback : function(){
18006 this.animating = false;
18007 Roo.callback(callback);
18010 duration: this.node.ownerTree.duration || .25
18014 getContainer : function(){
18015 return this.ctNode;
18018 getEl : function(){
18022 appendDDGhost : function(ghostNode){
18023 ghostNode.appendChild(this.elNode.cloneNode(true));
18026 getDDRepairXY : function(){
18027 return Roo.lib.Dom.getXY(this.iconNode);
18030 onRender : function(){
18034 render : function(bulkRender){
18035 var n = this.node, a = n.attributes;
18036 var targetNode = n.parentNode ?
18037 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
18039 if(!this.rendered){
18040 this.rendered = true;
18042 this.renderElements(n, a, targetNode, bulkRender);
18045 if(this.textNode.setAttributeNS){
18046 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
18048 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
18051 this.textNode.setAttribute("ext:qtip", a.qtip);
18053 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
18056 }else if(a.qtipCfg){
18057 a.qtipCfg.target = Roo.id(this.textNode);
18058 Roo.QuickTips.register(a.qtipCfg);
18061 if(!this.node.expanded){
18062 this.updateExpandIcon();
18065 if(bulkRender === true) {
18066 targetNode.appendChild(this.wrap);
18071 renderElements : function(n, a, targetNode, bulkRender){
18072 // add some indent caching, this helps performance when rendering a large tree
18073 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18074 var t = n.getOwnerTree();
18075 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18076 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18077 var cb = typeof a.checked == 'boolean';
18078 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18079 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18080 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18081 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18082 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18083 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18084 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18085 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18086 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18087 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18090 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18091 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18092 n.nextSibling.ui.getEl(), buf.join(""));
18094 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18097 this.elNode = this.wrap.childNodes[0];
18098 this.ctNode = this.wrap.childNodes[1];
18099 var cs = this.elNode.childNodes;
18100 this.indentNode = cs[0];
18101 this.ecNode = cs[1];
18102 this.iconNode = cs[2];
18105 this.checkbox = cs[3];
18108 this.anchor = cs[index];
18109 this.textNode = cs[index].firstChild;
18112 getAnchor : function(){
18113 return this.anchor;
18116 getTextEl : function(){
18117 return this.textNode;
18120 getIconEl : function(){
18121 return this.iconNode;
18124 isChecked : function(){
18125 return this.checkbox ? this.checkbox.checked : false;
18128 updateExpandIcon : function(){
18130 var n = this.node, c1, c2;
18131 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18132 var hasChild = n.hasChildNodes();
18136 c1 = "x-tree-node-collapsed";
18137 c2 = "x-tree-node-expanded";
18140 c1 = "x-tree-node-expanded";
18141 c2 = "x-tree-node-collapsed";
18144 this.removeClass("x-tree-node-leaf");
18145 this.wasLeaf = false;
18147 if(this.c1 != c1 || this.c2 != c2){
18148 Roo.fly(this.elNode).replaceClass(c1, c2);
18149 this.c1 = c1; this.c2 = c2;
18153 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18156 this.wasLeaf = true;
18159 var ecc = "x-tree-ec-icon "+cls;
18160 if(this.ecc != ecc){
18161 this.ecNode.className = ecc;
18167 getChildIndent : function(){
18168 if(!this.childIndent){
18172 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18174 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18176 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18181 this.childIndent = buf.join("");
18183 return this.childIndent;
18186 renderIndent : function(){
18189 var p = this.node.parentNode;
18191 indent = p.ui.getChildIndent();
18193 if(this.indentMarkup != indent){ // don't rerender if not required
18194 this.indentNode.innerHTML = indent;
18195 this.indentMarkup = indent;
18197 this.updateExpandIcon();
18202 Roo.tree.RootTreeNodeUI = function(){
18203 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18205 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18206 render : function(){
18207 if(!this.rendered){
18208 var targetNode = this.node.ownerTree.innerCt.dom;
18209 this.node.expanded = true;
18210 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18211 this.wrap = this.ctNode = targetNode.firstChild;
18214 collapse : function(){
18216 expand : function(){
18220 * Ext JS Library 1.1.1
18221 * Copyright(c) 2006-2007, Ext JS, LLC.
18223 * Originally Released Under LGPL - original licence link has changed is not relivant.
18226 * <script type="text/javascript">
18229 * @class Roo.tree.TreeLoader
18230 * @extends Roo.util.Observable
18231 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18232 * nodes from a specified URL. The response must be a javascript Array definition
18233 * who's elements are node definition objects. eg:
18235 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18236 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18239 * A server request is sent, and child nodes are loaded only when a node is expanded.
18240 * The loading node's id is passed to the server under the parameter name "node" to
18241 * enable the server to produce the correct child nodes.
18243 * To pass extra parameters, an event handler may be attached to the "beforeload"
18244 * event, and the parameters specified in the TreeLoader's baseParams property:
18246 myTreeLoader.on("beforeload", function(treeLoader, node) {
18247 this.baseParams.category = node.attributes.category;
18250 * This would pass an HTTP parameter called "category" to the server containing
18251 * the value of the Node's "category" attribute.
18253 * Creates a new Treeloader.
18254 * @param {Object} config A config object containing config properties.
18256 Roo.tree.TreeLoader = function(config){
18257 this.baseParams = {};
18258 this.requestMethod = "POST";
18259 Roo.apply(this, config);
18264 * @event beforeload
18265 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18266 * @param {Object} This TreeLoader object.
18267 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18268 * @param {Object} callback The callback function specified in the {@link #load} call.
18273 * Fires when the node has been successfuly loaded.
18274 * @param {Object} This TreeLoader object.
18275 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18276 * @param {Object} response The response object containing the data from the server.
18280 * @event loadexception
18281 * Fires if the network request failed.
18282 * @param {Object} This TreeLoader object.
18283 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18284 * @param {Object} response The response object containing the data from the server.
18286 loadexception : true,
18289 * Fires before a node is created, enabling you to return custom Node types
18290 * @param {Object} This TreeLoader object.
18291 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18296 Roo.tree.TreeLoader.superclass.constructor.call(this);
18299 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18301 * @cfg {String} dataUrl The URL from which to request a Json string which
18302 * specifies an array of node definition object representing the child nodes
18306 * @cfg {Object} baseParams (optional) An object containing properties which
18307 * specify HTTP parameters to be passed to each request for child nodes.
18310 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18311 * created by this loader. If the attributes sent by the server have an attribute in this object,
18312 * they take priority.
18315 * @cfg {Object} uiProviders (optional) An object containing properties which
18317 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18318 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18319 * <i>uiProvider</i> attribute of a returned child node is a string rather
18320 * than a reference to a TreeNodeUI implementation, this that string value
18321 * is used as a property name in the uiProviders object. You can define the provider named
18322 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18327 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18328 * child nodes before loading.
18330 clearOnLoad : true,
18333 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18334 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18335 * Grid query { data : [ .....] }
18340 * @cfg {String} queryParam (optional)
18341 * Name of the query as it will be passed on the querystring (defaults to 'node')
18342 * eg. the request will be ?node=[id]
18349 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18350 * This is called automatically when a node is expanded, but may be used to reload
18351 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18352 * @param {Roo.tree.TreeNode} node
18353 * @param {Function} callback
18355 load : function(node, callback){
18356 if(this.clearOnLoad){
18357 while(node.firstChild){
18358 node.removeChild(node.firstChild);
18361 if(node.attributes.children){ // preloaded json children
18362 var cs = node.attributes.children;
18363 for(var i = 0, len = cs.length; i < len; i++){
18364 node.appendChild(this.createNode(cs[i]));
18366 if(typeof callback == "function"){
18369 }else if(this.dataUrl){
18370 this.requestData(node, callback);
18374 getParams: function(node){
18375 var buf = [], bp = this.baseParams;
18376 for(var key in bp){
18377 if(typeof bp[key] != "function"){
18378 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18381 var n = this.queryParam === false ? 'node' : this.queryParam;
18382 buf.push(n + "=", encodeURIComponent(node.id));
18383 return buf.join("");
18386 requestData : function(node, callback){
18387 if(this.fireEvent("beforeload", this, node, callback) !== false){
18388 this.transId = Roo.Ajax.request({
18389 method:this.requestMethod,
18390 url: this.dataUrl||this.url,
18391 success: this.handleResponse,
18392 failure: this.handleFailure,
18394 argument: {callback: callback, node: node},
18395 params: this.getParams(node)
18398 // if the load is cancelled, make sure we notify
18399 // the node that we are done
18400 if(typeof callback == "function"){
18406 isLoading : function(){
18407 return this.transId ? true : false;
18410 abort : function(){
18411 if(this.isLoading()){
18412 Roo.Ajax.abort(this.transId);
18417 createNode : function(attr){
18418 // apply baseAttrs, nice idea Corey!
18419 if(this.baseAttrs){
18420 Roo.applyIf(attr, this.baseAttrs);
18422 if(this.applyLoader !== false){
18423 attr.loader = this;
18425 // uiProvider = depreciated..
18427 if(typeof(attr.uiProvider) == 'string'){
18428 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18429 /** eval:var:attr */ eval(attr.uiProvider);
18431 if(typeof(this.uiProviders['default']) != 'undefined') {
18432 attr.uiProvider = this.uiProviders['default'];
18435 this.fireEvent('create', this, attr);
18437 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18439 new Roo.tree.TreeNode(attr) :
18440 new Roo.tree.AsyncTreeNode(attr));
18443 processResponse : function(response, node, callback){
18444 var json = response.responseText;
18447 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18448 if (this.root !== false) {
18452 for(var i = 0, len = o.length; i < len; i++){
18453 var n = this.createNode(o[i]);
18455 node.appendChild(n);
18458 if(typeof callback == "function"){
18459 callback(this, node);
18462 this.handleFailure(response);
18466 handleResponse : function(response){
18467 this.transId = false;
18468 var a = response.argument;
18469 this.processResponse(response, a.node, a.callback);
18470 this.fireEvent("load", this, a.node, response);
18473 handleFailure : function(response){
18474 this.transId = false;
18475 var a = response.argument;
18476 this.fireEvent("loadexception", this, a.node, response);
18477 if(typeof a.callback == "function"){
18478 a.callback(this, a.node);
18483 * Ext JS Library 1.1.1
18484 * Copyright(c) 2006-2007, Ext JS, LLC.
18486 * Originally Released Under LGPL - original licence link has changed is not relivant.
18489 * <script type="text/javascript">
18493 * @class Roo.tree.TreeFilter
18494 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18495 * @param {TreePanel} tree
18496 * @param {Object} config (optional)
18498 Roo.tree.TreeFilter = function(tree, config){
18500 this.filtered = {};
18501 Roo.apply(this, config);
18504 Roo.tree.TreeFilter.prototype = {
18511 * Filter the data by a specific attribute.
18512 * @param {String/RegExp} value Either string that the attribute value
18513 * should start with or a RegExp to test against the attribute
18514 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18515 * @param {TreeNode} startNode (optional) The node to start the filter at.
18517 filter : function(value, attr, startNode){
18518 attr = attr || "text";
18520 if(typeof value == "string"){
18521 var vlen = value.length;
18522 // auto clear empty filter
18523 if(vlen == 0 && this.clearBlank){
18527 value = value.toLowerCase();
18529 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18531 }else if(value.exec){ // regex?
18533 return value.test(n.attributes[attr]);
18536 throw 'Illegal filter type, must be string or regex';
18538 this.filterBy(f, null, startNode);
18542 * Filter by a function. The passed function will be called with each
18543 * node in the tree (or from the startNode). If the function returns true, the node is kept
18544 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18545 * @param {Function} fn The filter function
18546 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18548 filterBy : function(fn, scope, startNode){
18549 startNode = startNode || this.tree.root;
18550 if(this.autoClear){
18553 var af = this.filtered, rv = this.reverse;
18554 var f = function(n){
18555 if(n == startNode){
18561 var m = fn.call(scope || n, n);
18569 startNode.cascade(f);
18572 if(typeof id != "function"){
18574 if(n && n.parentNode){
18575 n.parentNode.removeChild(n);
18583 * Clears the current filter. Note: with the "remove" option
18584 * set a filter cannot be cleared.
18586 clear : function(){
18588 var af = this.filtered;
18590 if(typeof id != "function"){
18597 this.filtered = {};
18602 * Ext JS Library 1.1.1
18603 * Copyright(c) 2006-2007, Ext JS, LLC.
18605 * Originally Released Under LGPL - original licence link has changed is not relivant.
18608 * <script type="text/javascript">
18613 * @class Roo.tree.TreeSorter
18614 * Provides sorting of nodes in a TreePanel
18616 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18617 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18618 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18619 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18620 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18621 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18623 * @param {TreePanel} tree
18624 * @param {Object} config
18626 Roo.tree.TreeSorter = function(tree, config){
18627 Roo.apply(this, config);
18628 tree.on("beforechildrenrendered", this.doSort, this);
18629 tree.on("append", this.updateSort, this);
18630 tree.on("insert", this.updateSort, this);
18632 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18633 var p = this.property || "text";
18634 var sortType = this.sortType;
18635 var fs = this.folderSort;
18636 var cs = this.caseSensitive === true;
18637 var leafAttr = this.leafAttr || 'leaf';
18639 this.sortFn = function(n1, n2){
18641 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18644 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18648 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18649 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18651 return dsc ? +1 : -1;
18653 return dsc ? -1 : +1;
18660 Roo.tree.TreeSorter.prototype = {
18661 doSort : function(node){
18662 node.sort(this.sortFn);
18665 compareNodes : function(n1, n2){
18666 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18669 updateSort : function(tree, node){
18670 if(node.childrenRendered){
18671 this.doSort.defer(1, this, [node]);
18676 * Ext JS Library 1.1.1
18677 * Copyright(c) 2006-2007, Ext JS, LLC.
18679 * Originally Released Under LGPL - original licence link has changed is not relivant.
18682 * <script type="text/javascript">
18685 if(Roo.dd.DropZone){
18687 Roo.tree.TreeDropZone = function(tree, config){
18688 this.allowParentInsert = false;
18689 this.allowContainerDrop = false;
18690 this.appendOnly = false;
18691 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18693 this.lastInsertClass = "x-tree-no-status";
18694 this.dragOverData = {};
18697 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18698 ddGroup : "TreeDD",
18700 expandDelay : 1000,
18702 expandNode : function(node){
18703 if(node.hasChildNodes() && !node.isExpanded()){
18704 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18708 queueExpand : function(node){
18709 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18712 cancelExpand : function(){
18713 if(this.expandProcId){
18714 clearTimeout(this.expandProcId);
18715 this.expandProcId = false;
18719 isValidDropPoint : function(n, pt, dd, e, data){
18720 if(!n || !data){ return false; }
18721 var targetNode = n.node;
18722 var dropNode = data.node;
18723 // default drop rules
18724 if(!(targetNode && targetNode.isTarget && pt)){
18727 if(pt == "append" && targetNode.allowChildren === false){
18730 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18733 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18736 // reuse the object
18737 var overEvent = this.dragOverData;
18738 overEvent.tree = this.tree;
18739 overEvent.target = targetNode;
18740 overEvent.data = data;
18741 overEvent.point = pt;
18742 overEvent.source = dd;
18743 overEvent.rawEvent = e;
18744 overEvent.dropNode = dropNode;
18745 overEvent.cancel = false;
18746 var result = this.tree.fireEvent("nodedragover", overEvent);
18747 return overEvent.cancel === false && result !== false;
18750 getDropPoint : function(e, n, dd){
18753 return tn.allowChildren !== false ? "append" : false; // always append for root
18755 var dragEl = n.ddel;
18756 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18757 var y = Roo.lib.Event.getPageY(e);
18758 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18760 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18761 var noAppend = tn.allowChildren === false;
18762 if(this.appendOnly || tn.parentNode.allowChildren === false){
18763 return noAppend ? false : "append";
18765 var noBelow = false;
18766 if(!this.allowParentInsert){
18767 noBelow = tn.hasChildNodes() && tn.isExpanded();
18769 var q = (b - t) / (noAppend ? 2 : 3);
18770 if(y >= t && y < (t + q)){
18772 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18779 onNodeEnter : function(n, dd, e, data){
18780 this.cancelExpand();
18783 onNodeOver : function(n, dd, e, data){
18784 var pt = this.getDropPoint(e, n, dd);
18787 // auto node expand check
18788 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18789 this.queueExpand(node);
18790 }else if(pt != "append"){
18791 this.cancelExpand();
18794 // set the insert point style on the target node
18795 var returnCls = this.dropNotAllowed;
18796 if(this.isValidDropPoint(n, pt, dd, e, data)){
18801 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18802 cls = "x-tree-drag-insert-above";
18803 }else if(pt == "below"){
18804 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18805 cls = "x-tree-drag-insert-below";
18807 returnCls = "x-tree-drop-ok-append";
18808 cls = "x-tree-drag-append";
18810 if(this.lastInsertClass != cls){
18811 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18812 this.lastInsertClass = cls;
18819 onNodeOut : function(n, dd, e, data){
18820 this.cancelExpand();
18821 this.removeDropIndicators(n);
18824 onNodeDrop : function(n, dd, e, data){
18825 var point = this.getDropPoint(e, n, dd);
18826 var targetNode = n.node;
18827 targetNode.ui.startDrop();
18828 if(!this.isValidDropPoint(n, point, dd, e, data)){
18829 targetNode.ui.endDrop();
18832 // first try to find the drop node
18833 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18836 target: targetNode,
18841 dropNode: dropNode,
18844 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18845 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18846 targetNode.ui.endDrop();
18849 // allow target changing
18850 targetNode = dropEvent.target;
18851 if(point == "append" && !targetNode.isExpanded()){
18852 targetNode.expand(false, null, function(){
18853 this.completeDrop(dropEvent);
18854 }.createDelegate(this));
18856 this.completeDrop(dropEvent);
18861 completeDrop : function(de){
18862 var ns = de.dropNode, p = de.point, t = de.target;
18863 if(!(ns instanceof Array)){
18867 for(var i = 0, len = ns.length; i < len; i++){
18870 t.parentNode.insertBefore(n, t);
18871 }else if(p == "below"){
18872 t.parentNode.insertBefore(n, t.nextSibling);
18878 if(this.tree.hlDrop){
18882 this.tree.fireEvent("nodedrop", de);
18885 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18886 if(this.tree.hlDrop){
18887 dropNode.ui.focus();
18888 dropNode.ui.highlight();
18890 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18893 getTree : function(){
18897 removeDropIndicators : function(n){
18900 Roo.fly(el).removeClass([
18901 "x-tree-drag-insert-above",
18902 "x-tree-drag-insert-below",
18903 "x-tree-drag-append"]);
18904 this.lastInsertClass = "_noclass";
18908 beforeDragDrop : function(target, e, id){
18909 this.cancelExpand();
18913 afterRepair : function(data){
18914 if(data && Roo.enableFx){
18915 data.node.ui.highlight();
18924 * Ext JS Library 1.1.1
18925 * Copyright(c) 2006-2007, Ext JS, LLC.
18927 * Originally Released Under LGPL - original licence link has changed is not relivant.
18930 * <script type="text/javascript">
18934 if(Roo.dd.DragZone){
18935 Roo.tree.TreeDragZone = function(tree, config){
18936 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18940 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18941 ddGroup : "TreeDD",
18943 onBeforeDrag : function(data, e){
18945 return n && n.draggable && !n.disabled;
18948 onInitDrag : function(e){
18949 var data = this.dragData;
18950 this.tree.getSelectionModel().select(data.node);
18951 this.proxy.update("");
18952 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18953 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18956 getRepairXY : function(e, data){
18957 return data.node.ui.getDDRepairXY();
18960 onEndDrag : function(data, e){
18961 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18964 onValidDrop : function(dd, e, id){
18965 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18969 beforeInvalidDrop : function(e, id){
18970 // this scrolls the original position back into view
18971 var sm = this.tree.getSelectionModel();
18972 sm.clearSelections();
18973 sm.select(this.dragData.node);
18978 * Ext JS Library 1.1.1
18979 * Copyright(c) 2006-2007, Ext JS, LLC.
18981 * Originally Released Under LGPL - original licence link has changed is not relivant.
18984 * <script type="text/javascript">
18987 * @class Roo.tree.TreeEditor
18988 * @extends Roo.Editor
18989 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18990 * as the editor field.
18992 * @param {TreePanel} tree
18993 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18995 Roo.tree.TreeEditor = function(tree, config){
18996 config = config || {};
18997 var field = config.events ? config : new Roo.form.TextField(config);
18998 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
19002 tree.on('beforeclick', this.beforeNodeClick, this);
19003 tree.getTreeEl().on('mousedown', this.hide, this);
19004 this.on('complete', this.updateNode, this);
19005 this.on('beforestartedit', this.fitToTree, this);
19006 this.on('startedit', this.bindScroll, this, {delay:10});
19007 this.on('specialkey', this.onSpecialKey, this);
19010 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
19012 * @cfg {String} alignment
19013 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
19019 * @cfg {Boolean} hideEl
19020 * True to hide the bound element while the editor is displayed (defaults to false)
19024 * @cfg {String} cls
19025 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
19027 cls: "x-small-editor x-tree-editor",
19029 * @cfg {Boolean} shim
19030 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
19036 * @cfg {Number} maxWidth
19037 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
19038 * the containing tree element's size, it will be automatically limited for you to the container width, taking
19039 * scroll and client offsets into account prior to each edit.
19046 fitToTree : function(ed, el){
19047 var td = this.tree.getTreeEl().dom, nd = el.dom;
19048 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
19049 td.scrollLeft = nd.offsetLeft;
19053 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
19054 this.setSize(w, '');
19058 triggerEdit : function(node){
19059 this.completeEdit();
19060 this.editNode = node;
19061 this.startEdit(node.ui.textNode, node.text);
19065 bindScroll : function(){
19066 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19070 beforeNodeClick : function(node, e){
19071 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19072 this.lastClick = new Date();
19073 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19075 this.triggerEdit(node);
19081 updateNode : function(ed, value){
19082 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19083 this.editNode.setText(value);
19087 onHide : function(){
19088 Roo.tree.TreeEditor.superclass.onHide.call(this);
19090 this.editNode.ui.focus();
19095 onSpecialKey : function(field, e){
19096 var k = e.getKey();
19100 }else if(k == e.ENTER && !e.hasModifier()){
19102 this.completeEdit();
19105 });//<Script type="text/javascript">
19108 * Ext JS Library 1.1.1
19109 * Copyright(c) 2006-2007, Ext JS, LLC.
19111 * Originally Released Under LGPL - original licence link has changed is not relivant.
19114 * <script type="text/javascript">
19118 * Not documented??? - probably should be...
19121 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19122 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19124 renderElements : function(n, a, targetNode, bulkRender){
19125 //consel.log("renderElements?");
19126 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19128 var t = n.getOwnerTree();
19129 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19131 var cols = t.columns;
19132 var bw = t.borderWidth;
19134 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19135 var cb = typeof a.checked == "boolean";
19136 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19137 var colcls = 'x-t-' + tid + '-c0';
19139 '<li class="x-tree-node">',
19142 '<div class="x-tree-node-el ', a.cls,'">',
19144 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19147 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19148 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19149 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19150 (a.icon ? ' x-tree-node-inline-icon' : ''),
19151 (a.iconCls ? ' '+a.iconCls : ''),
19152 '" unselectable="on" />',
19153 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19154 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19156 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19157 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19158 '<span unselectable="on" qtip="' + tx + '">',
19162 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19163 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19165 for(var i = 1, len = cols.length; i < len; i++){
19167 colcls = 'x-t-' + tid + '-c' +i;
19168 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19169 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19170 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19176 '<div class="x-clear"></div></div>',
19177 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19180 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19181 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19182 n.nextSibling.ui.getEl(), buf.join(""));
19184 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19186 var el = this.wrap.firstChild;
19188 this.elNode = el.firstChild;
19189 this.ranchor = el.childNodes[1];
19190 this.ctNode = this.wrap.childNodes[1];
19191 var cs = el.firstChild.childNodes;
19192 this.indentNode = cs[0];
19193 this.ecNode = cs[1];
19194 this.iconNode = cs[2];
19197 this.checkbox = cs[3];
19200 this.anchor = cs[index];
19202 this.textNode = cs[index].firstChild;
19204 //el.on("click", this.onClick, this);
19205 //el.on("dblclick", this.onDblClick, this);
19208 // console.log(this);
19210 initEvents : function(){
19211 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19214 var a = this.ranchor;
19216 var el = Roo.get(a);
19218 if(Roo.isOpera){ // opera render bug ignores the CSS
19219 el.setStyle("text-decoration", "none");
19222 el.on("click", this.onClick, this);
19223 el.on("dblclick", this.onDblClick, this);
19224 el.on("contextmenu", this.onContextMenu, this);
19228 /*onSelectedChange : function(state){
19231 this.addClass("x-tree-selected");
19234 this.removeClass("x-tree-selected");
19237 addClass : function(cls){
19239 Roo.fly(this.elRow).addClass(cls);
19245 removeClass : function(cls){
19247 Roo.fly(this.elRow).removeClass(cls);
19253 });//<Script type="text/javascript">
19257 * Ext JS Library 1.1.1
19258 * Copyright(c) 2006-2007, Ext JS, LLC.
19260 * Originally Released Under LGPL - original licence link has changed is not relivant.
19263 * <script type="text/javascript">
19268 * @class Roo.tree.ColumnTree
19269 * @extends Roo.data.TreePanel
19270 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19271 * @cfg {int} borderWidth compined right/left border allowance
19273 * @param {String/HTMLElement/Element} el The container element
19274 * @param {Object} config
19276 Roo.tree.ColumnTree = function(el, config)
19278 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19282 * Fire this event on a container when it resizes
19283 * @param {int} w Width
19284 * @param {int} h Height
19288 this.on('resize', this.onResize, this);
19291 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19295 borderWidth: Roo.isBorderBox ? 0 : 2,
19298 render : function(){
19299 // add the header.....
19301 Roo.tree.ColumnTree.superclass.render.apply(this);
19303 this.el.addClass('x-column-tree');
19305 this.headers = this.el.createChild(
19306 {cls:'x-tree-headers'},this.innerCt.dom);
19308 var cols = this.columns, c;
19309 var totalWidth = 0;
19311 var len = cols.length;
19312 for(var i = 0; i < len; i++){
19314 totalWidth += c.width;
19315 this.headEls.push(this.headers.createChild({
19316 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19318 cls:'x-tree-hd-text',
19321 style:'width:'+(c.width-this.borderWidth)+'px;'
19324 this.headers.createChild({cls:'x-clear'});
19325 // prevent floats from wrapping when clipped
19326 this.headers.setWidth(totalWidth);
19327 //this.innerCt.setWidth(totalWidth);
19328 this.innerCt.setStyle({ overflow: 'auto' });
19329 this.onResize(this.width, this.height);
19333 onResize : function(w,h)
19338 this.innerCt.setWidth(this.width);
19339 this.innerCt.setHeight(this.height-20);
19342 var cols = this.columns, c;
19343 var totalWidth = 0;
19345 var len = cols.length;
19346 for(var i = 0; i < len; i++){
19348 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19349 // it's the expander..
19350 expEl = this.headEls[i];
19353 totalWidth += c.width;
19357 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19359 this.headers.setWidth(w-20);
19368 * Ext JS Library 1.1.1
19369 * Copyright(c) 2006-2007, Ext JS, LLC.
19371 * Originally Released Under LGPL - original licence link has changed is not relivant.
19374 * <script type="text/javascript">
19378 * @class Roo.menu.Menu
19379 * @extends Roo.util.Observable
19380 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19381 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19383 * Creates a new Menu
19384 * @param {Object} config Configuration options
19386 Roo.menu.Menu = function(config){
19387 Roo.apply(this, config);
19388 this.id = this.id || Roo.id();
19391 * @event beforeshow
19392 * Fires before this menu is displayed
19393 * @param {Roo.menu.Menu} this
19397 * @event beforehide
19398 * Fires before this menu is hidden
19399 * @param {Roo.menu.Menu} this
19404 * Fires after this menu is displayed
19405 * @param {Roo.menu.Menu} this
19410 * Fires after this menu is hidden
19411 * @param {Roo.menu.Menu} this
19416 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19417 * @param {Roo.menu.Menu} this
19418 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19419 * @param {Roo.EventObject} e
19424 * Fires when the mouse is hovering over this menu
19425 * @param {Roo.menu.Menu} this
19426 * @param {Roo.EventObject} e
19427 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19432 * Fires when the mouse exits this menu
19433 * @param {Roo.menu.Menu} this
19434 * @param {Roo.EventObject} e
19435 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19440 * Fires when a menu item contained in this menu is clicked
19441 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19442 * @param {Roo.EventObject} e
19446 if (this.registerMenu) {
19447 Roo.menu.MenuMgr.register(this);
19450 var mis = this.items;
19451 this.items = new Roo.util.MixedCollection();
19453 this.add.apply(this, mis);
19457 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19459 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19463 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19464 * for bottom-right shadow (defaults to "sides")
19468 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19469 * this menu (defaults to "tl-tr?")
19471 subMenuAlign : "tl-tr?",
19473 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19474 * relative to its element of origin (defaults to "tl-bl?")
19476 defaultAlign : "tl-bl?",
19478 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19480 allowOtherMenus : false,
19482 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19484 registerMenu : true,
19489 render : function(){
19493 var el = this.el = new Roo.Layer({
19495 shadow:this.shadow,
19497 parentEl: this.parentEl || document.body,
19501 this.keyNav = new Roo.menu.MenuNav(this);
19504 el.addClass("x-menu-plain");
19507 el.addClass(this.cls);
19509 // generic focus element
19510 this.focusEl = el.createChild({
19511 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19513 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19514 ul.on("click", this.onClick, this);
19515 ul.on("mouseover", this.onMouseOver, this);
19516 ul.on("mouseout", this.onMouseOut, this);
19517 this.items.each(function(item){
19518 var li = document.createElement("li");
19519 li.className = "x-menu-list-item";
19520 ul.dom.appendChild(li);
19521 item.render(li, this);
19528 autoWidth : function(){
19529 var el = this.el, ul = this.ul;
19533 var w = this.width;
19536 }else if(Roo.isIE){
19537 el.setWidth(this.minWidth);
19538 var t = el.dom.offsetWidth; // force recalc
19539 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19544 delayAutoWidth : function(){
19547 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19549 this.awTask.delay(20);
19554 findTargetItem : function(e){
19555 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19556 if(t && t.menuItemId){
19557 return this.items.get(t.menuItemId);
19562 onClick : function(e){
19564 if(t = this.findTargetItem(e)){
19566 this.fireEvent("click", this, t, e);
19571 setActiveItem : function(item, autoExpand){
19572 if(item != this.activeItem){
19573 if(this.activeItem){
19574 this.activeItem.deactivate();
19576 this.activeItem = item;
19577 item.activate(autoExpand);
19578 }else if(autoExpand){
19584 tryActivate : function(start, step){
19585 var items = this.items;
19586 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19587 var item = items.get(i);
19588 if(!item.disabled && item.canActivate){
19589 this.setActiveItem(item, false);
19597 onMouseOver : function(e){
19599 if(t = this.findTargetItem(e)){
19600 if(t.canActivate && !t.disabled){
19601 this.setActiveItem(t, true);
19604 this.fireEvent("mouseover", this, e, t);
19608 onMouseOut : function(e){
19610 if(t = this.findTargetItem(e)){
19611 if(t == this.activeItem && t.shouldDeactivate(e)){
19612 this.activeItem.deactivate();
19613 delete this.activeItem;
19616 this.fireEvent("mouseout", this, e, t);
19620 * Read-only. Returns true if the menu is currently displayed, else false.
19623 isVisible : function(){
19624 return this.el && !this.hidden;
19628 * Displays this menu relative to another element
19629 * @param {String/HTMLElement/Roo.Element} element The element to align to
19630 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19631 * the element (defaults to this.defaultAlign)
19632 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19634 show : function(el, pos, parentMenu){
19635 this.parentMenu = parentMenu;
19639 this.fireEvent("beforeshow", this);
19640 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19644 * Displays this menu at a specific xy position
19645 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19646 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19648 showAt : function(xy, parentMenu, /* private: */_e){
19649 this.parentMenu = parentMenu;
19654 this.fireEvent("beforeshow", this);
19655 xy = this.el.adjustForConstraints(xy);
19659 this.hidden = false;
19661 this.fireEvent("show", this);
19664 focus : function(){
19666 this.doFocus.defer(50, this);
19670 doFocus : function(){
19672 this.focusEl.focus();
19677 * Hides this menu and optionally all parent menus
19678 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19680 hide : function(deep){
19681 if(this.el && this.isVisible()){
19682 this.fireEvent("beforehide", this);
19683 if(this.activeItem){
19684 this.activeItem.deactivate();
19685 this.activeItem = null;
19688 this.hidden = true;
19689 this.fireEvent("hide", this);
19691 if(deep === true && this.parentMenu){
19692 this.parentMenu.hide(true);
19697 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19698 * Any of the following are valid:
19700 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19701 * <li>An HTMLElement object which will be converted to a menu item</li>
19702 * <li>A menu item config object that will be created as a new menu item</li>
19703 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19704 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19709 var menu = new Roo.menu.Menu();
19711 // Create a menu item to add by reference
19712 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19714 // Add a bunch of items at once using different methods.
19715 // Only the last item added will be returned.
19716 var item = menu.add(
19717 menuItem, // add existing item by ref
19718 'Dynamic Item', // new TextItem
19719 '-', // new separator
19720 { text: 'Config Item' } // new item by config
19723 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19724 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19727 var a = arguments, l = a.length, item;
19728 for(var i = 0; i < l; i++){
19730 if ((typeof(el) == "object") && el.xtype && el.xns) {
19731 el = Roo.factory(el, Roo.menu);
19734 if(el.render){ // some kind of Item
19735 item = this.addItem(el);
19736 }else if(typeof el == "string"){ // string
19737 if(el == "separator" || el == "-"){
19738 item = this.addSeparator();
19740 item = this.addText(el);
19742 }else if(el.tagName || el.el){ // element
19743 item = this.addElement(el);
19744 }else if(typeof el == "object"){ // must be menu item config?
19745 item = this.addMenuItem(el);
19752 * Returns this menu's underlying {@link Roo.Element} object
19753 * @return {Roo.Element} The element
19755 getEl : function(){
19763 * Adds a separator bar to the menu
19764 * @return {Roo.menu.Item} The menu item that was added
19766 addSeparator : function(){
19767 return this.addItem(new Roo.menu.Separator());
19771 * Adds an {@link Roo.Element} object to the menu
19772 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19773 * @return {Roo.menu.Item} The menu item that was added
19775 addElement : function(el){
19776 return this.addItem(new Roo.menu.BaseItem(el));
19780 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19781 * @param {Roo.menu.Item} item The menu item to add
19782 * @return {Roo.menu.Item} The menu item that was added
19784 addItem : function(item){
19785 this.items.add(item);
19787 var li = document.createElement("li");
19788 li.className = "x-menu-list-item";
19789 this.ul.dom.appendChild(li);
19790 item.render(li, this);
19791 this.delayAutoWidth();
19797 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19798 * @param {Object} config A MenuItem config object
19799 * @return {Roo.menu.Item} The menu item that was added
19801 addMenuItem : function(config){
19802 if(!(config instanceof Roo.menu.Item)){
19803 if(typeof config.checked == "boolean"){ // must be check menu item config?
19804 config = new Roo.menu.CheckItem(config);
19806 config = new Roo.menu.Item(config);
19809 return this.addItem(config);
19813 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19814 * @param {String} text The text to display in the menu item
19815 * @return {Roo.menu.Item} The menu item that was added
19817 addText : function(text){
19818 return this.addItem(new Roo.menu.TextItem({ text : text }));
19822 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19823 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19824 * @param {Roo.menu.Item} item The menu item to add
19825 * @return {Roo.menu.Item} The menu item that was added
19827 insert : function(index, item){
19828 this.items.insert(index, item);
19830 var li = document.createElement("li");
19831 li.className = "x-menu-list-item";
19832 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19833 item.render(li, this);
19834 this.delayAutoWidth();
19840 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19841 * @param {Roo.menu.Item} item The menu item to remove
19843 remove : function(item){
19844 this.items.removeKey(item.id);
19849 * Removes and destroys all items in the menu
19851 removeAll : function(){
19853 while(f = this.items.first()){
19859 // MenuNav is a private utility class used internally by the Menu
19860 Roo.menu.MenuNav = function(menu){
19861 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19862 this.scope = this.menu = menu;
19865 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19866 doRelay : function(e, h){
19867 var k = e.getKey();
19868 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19869 this.menu.tryActivate(0, 1);
19872 return h.call(this.scope || this, e, this.menu);
19875 up : function(e, m){
19876 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19877 m.tryActivate(m.items.length-1, -1);
19881 down : function(e, m){
19882 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19883 m.tryActivate(0, 1);
19887 right : function(e, m){
19889 m.activeItem.expandMenu(true);
19893 left : function(e, m){
19895 if(m.parentMenu && m.parentMenu.activeItem){
19896 m.parentMenu.activeItem.activate();
19900 enter : function(e, m){
19902 e.stopPropagation();
19903 m.activeItem.onClick(e);
19904 m.fireEvent("click", this, m.activeItem);
19910 * Ext JS Library 1.1.1
19911 * Copyright(c) 2006-2007, Ext JS, LLC.
19913 * Originally Released Under LGPL - original licence link has changed is not relivant.
19916 * <script type="text/javascript">
19920 * @class Roo.menu.MenuMgr
19921 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19924 Roo.menu.MenuMgr = function(){
19925 var menus, active, groups = {}, attached = false, lastShow = new Date();
19927 // private - called when first menu is created
19930 active = new Roo.util.MixedCollection();
19931 Roo.get(document).addKeyListener(27, function(){
19932 if(active.length > 0){
19939 function hideAll(){
19940 if(active && active.length > 0){
19941 var c = active.clone();
19942 c.each(function(m){
19949 function onHide(m){
19951 if(active.length < 1){
19952 Roo.get(document).un("mousedown", onMouseDown);
19958 function onShow(m){
19959 var last = active.last();
19960 lastShow = new Date();
19963 Roo.get(document).on("mousedown", onMouseDown);
19967 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19968 m.parentMenu.activeChild = m;
19969 }else if(last && last.isVisible()){
19970 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19975 function onBeforeHide(m){
19977 m.activeChild.hide();
19979 if(m.autoHideTimer){
19980 clearTimeout(m.autoHideTimer);
19981 delete m.autoHideTimer;
19986 function onBeforeShow(m){
19987 var pm = m.parentMenu;
19988 if(!pm && !m.allowOtherMenus){
19990 }else if(pm && pm.activeChild && active != m){
19991 pm.activeChild.hide();
19996 function onMouseDown(e){
19997 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
20003 function onBeforeCheck(mi, state){
20005 var g = groups[mi.group];
20006 for(var i = 0, l = g.length; i < l; i++){
20008 g[i].setChecked(false);
20017 * Hides all menus that are currently visible
20019 hideAll : function(){
20024 register : function(menu){
20028 menus[menu.id] = menu;
20029 menu.on("beforehide", onBeforeHide);
20030 menu.on("hide", onHide);
20031 menu.on("beforeshow", onBeforeShow);
20032 menu.on("show", onShow);
20033 var g = menu.group;
20034 if(g && menu.events["checkchange"]){
20038 groups[g].push(menu);
20039 menu.on("checkchange", onCheck);
20044 * Returns a {@link Roo.menu.Menu} object
20045 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
20046 * be used to generate and return a new Menu instance.
20048 get : function(menu){
20049 if(typeof menu == "string"){ // menu id
20050 return menus[menu];
20051 }else if(menu.events){ // menu instance
20053 }else if(typeof menu.length == 'number'){ // array of menu items?
20054 return new Roo.menu.Menu({items:menu});
20055 }else{ // otherwise, must be a config
20056 return new Roo.menu.Menu(menu);
20061 unregister : function(menu){
20062 delete menus[menu.id];
20063 menu.un("beforehide", onBeforeHide);
20064 menu.un("hide", onHide);
20065 menu.un("beforeshow", onBeforeShow);
20066 menu.un("show", onShow);
20067 var g = menu.group;
20068 if(g && menu.events["checkchange"]){
20069 groups[g].remove(menu);
20070 menu.un("checkchange", onCheck);
20075 registerCheckable : function(menuItem){
20076 var g = menuItem.group;
20081 groups[g].push(menuItem);
20082 menuItem.on("beforecheckchange", onBeforeCheck);
20087 unregisterCheckable : function(menuItem){
20088 var g = menuItem.group;
20090 groups[g].remove(menuItem);
20091 menuItem.un("beforecheckchange", onBeforeCheck);
20097 * Ext JS Library 1.1.1
20098 * Copyright(c) 2006-2007, Ext JS, LLC.
20100 * Originally Released Under LGPL - original licence link has changed is not relivant.
20103 * <script type="text/javascript">
20108 * @class Roo.menu.BaseItem
20109 * @extends Roo.Component
20110 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20111 * management and base configuration options shared by all menu components.
20113 * Creates a new BaseItem
20114 * @param {Object} config Configuration options
20116 Roo.menu.BaseItem = function(config){
20117 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20122 * Fires when this item is clicked
20123 * @param {Roo.menu.BaseItem} this
20124 * @param {Roo.EventObject} e
20129 * Fires when this item is activated
20130 * @param {Roo.menu.BaseItem} this
20134 * @event deactivate
20135 * Fires when this item is deactivated
20136 * @param {Roo.menu.BaseItem} this
20142 this.on("click", this.handler, this.scope, true);
20146 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20148 * @cfg {Function} handler
20149 * A function that will handle the click event of this menu item (defaults to undefined)
20152 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20154 canActivate : false,
20156 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20158 activeClass : "x-menu-item-active",
20160 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20162 hideOnClick : true,
20164 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20169 ctype: "Roo.menu.BaseItem",
20172 actionMode : "container",
20175 render : function(container, parentMenu){
20176 this.parentMenu = parentMenu;
20177 Roo.menu.BaseItem.superclass.render.call(this, container);
20178 this.container.menuItemId = this.id;
20182 onRender : function(container, position){
20183 this.el = Roo.get(this.el);
20184 container.dom.appendChild(this.el.dom);
20188 onClick : function(e){
20189 if(!this.disabled && this.fireEvent("click", this, e) !== false
20190 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20191 this.handleClick(e);
20198 activate : function(){
20202 var li = this.container;
20203 li.addClass(this.activeClass);
20204 this.region = li.getRegion().adjust(2, 2, -2, -2);
20205 this.fireEvent("activate", this);
20210 deactivate : function(){
20211 this.container.removeClass(this.activeClass);
20212 this.fireEvent("deactivate", this);
20216 shouldDeactivate : function(e){
20217 return !this.region || !this.region.contains(e.getPoint());
20221 handleClick : function(e){
20222 if(this.hideOnClick){
20223 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20228 expandMenu : function(autoActivate){
20233 hideMenu : function(){
20238 * Ext JS Library 1.1.1
20239 * Copyright(c) 2006-2007, Ext JS, LLC.
20241 * Originally Released Under LGPL - original licence link has changed is not relivant.
20244 * <script type="text/javascript">
20248 * @class Roo.menu.Adapter
20249 * @extends Roo.menu.BaseItem
20250 * 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.
20251 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20253 * Creates a new Adapter
20254 * @param {Object} config Configuration options
20256 Roo.menu.Adapter = function(component, config){
20257 Roo.menu.Adapter.superclass.constructor.call(this, config);
20258 this.component = component;
20260 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20262 canActivate : true,
20265 onRender : function(container, position){
20266 this.component.render(container);
20267 this.el = this.component.getEl();
20271 activate : function(){
20275 this.component.focus();
20276 this.fireEvent("activate", this);
20281 deactivate : function(){
20282 this.fireEvent("deactivate", this);
20286 disable : function(){
20287 this.component.disable();
20288 Roo.menu.Adapter.superclass.disable.call(this);
20292 enable : function(){
20293 this.component.enable();
20294 Roo.menu.Adapter.superclass.enable.call(this);
20298 * Ext JS Library 1.1.1
20299 * Copyright(c) 2006-2007, Ext JS, LLC.
20301 * Originally Released Under LGPL - original licence link has changed is not relivant.
20304 * <script type="text/javascript">
20308 * @class Roo.menu.TextItem
20309 * @extends Roo.menu.BaseItem
20310 * Adds a static text string to a menu, usually used as either a heading or group separator.
20311 * Note: old style constructor with text is still supported.
20314 * Creates a new TextItem
20315 * @param {Object} cfg Configuration
20317 Roo.menu.TextItem = function(cfg){
20318 if (typeof(cfg) == 'string') {
20321 Roo.apply(this,cfg);
20324 Roo.menu.TextItem.superclass.constructor.call(this);
20327 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20329 * @cfg {Boolean} text Text to show on item.
20334 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20336 hideOnClick : false,
20338 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20340 itemCls : "x-menu-text",
20343 onRender : function(){
20344 var s = document.createElement("span");
20345 s.className = this.itemCls;
20346 s.innerHTML = this.text;
20348 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20352 * Ext JS Library 1.1.1
20353 * Copyright(c) 2006-2007, Ext JS, LLC.
20355 * Originally Released Under LGPL - original licence link has changed is not relivant.
20358 * <script type="text/javascript">
20362 * @class Roo.menu.Separator
20363 * @extends Roo.menu.BaseItem
20364 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20365 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20367 * @param {Object} config Configuration options
20369 Roo.menu.Separator = function(config){
20370 Roo.menu.Separator.superclass.constructor.call(this, config);
20373 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20375 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20377 itemCls : "x-menu-sep",
20379 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20381 hideOnClick : false,
20384 onRender : function(li){
20385 var s = document.createElement("span");
20386 s.className = this.itemCls;
20387 s.innerHTML = " ";
20389 li.addClass("x-menu-sep-li");
20390 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20394 * Ext JS Library 1.1.1
20395 * Copyright(c) 2006-2007, Ext JS, LLC.
20397 * Originally Released Under LGPL - original licence link has changed is not relivant.
20400 * <script type="text/javascript">
20403 * @class Roo.menu.Item
20404 * @extends Roo.menu.BaseItem
20405 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20406 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20407 * activation and click handling.
20409 * Creates a new Item
20410 * @param {Object} config Configuration options
20412 Roo.menu.Item = function(config){
20413 Roo.menu.Item.superclass.constructor.call(this, config);
20415 this.menu = Roo.menu.MenuMgr.get(this.menu);
20418 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20421 * @cfg {String} text
20422 * The text to show on the menu item.
20426 * @cfg {String} HTML to render in menu
20427 * The text to show on the menu item (HTML version).
20431 * @cfg {String} icon
20432 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20436 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20438 itemCls : "x-menu-item",
20440 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20442 canActivate : true,
20444 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20447 // doc'd in BaseItem
20451 ctype: "Roo.menu.Item",
20454 onRender : function(container, position){
20455 var el = document.createElement("a");
20456 el.hideFocus = true;
20457 el.unselectable = "on";
20458 el.href = this.href || "#";
20459 if(this.hrefTarget){
20460 el.target = this.hrefTarget;
20462 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20464 var html = this.html.length ? this.html : String.format('{0}',this.text);
20466 el.innerHTML = String.format(
20467 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20468 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20470 Roo.menu.Item.superclass.onRender.call(this, container, position);
20474 * Sets the text to display in this menu item
20475 * @param {String} text The text to display
20476 * @param {Boolean} isHTML true to indicate text is pure html.
20478 setText : function(text, isHTML){
20486 var html = this.html.length ? this.html : String.format('{0}',this.text);
20488 this.el.update(String.format(
20489 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20490 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20491 this.parentMenu.autoWidth();
20496 handleClick : function(e){
20497 if(!this.href){ // if no link defined, stop the event automatically
20500 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20504 activate : function(autoExpand){
20505 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20515 shouldDeactivate : function(e){
20516 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20517 if(this.menu && this.menu.isVisible()){
20518 return !this.menu.getEl().getRegion().contains(e.getPoint());
20526 deactivate : function(){
20527 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20532 expandMenu : function(autoActivate){
20533 if(!this.disabled && this.menu){
20534 clearTimeout(this.hideTimer);
20535 delete this.hideTimer;
20536 if(!this.menu.isVisible() && !this.showTimer){
20537 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20538 }else if (this.menu.isVisible() && autoActivate){
20539 this.menu.tryActivate(0, 1);
20545 deferExpand : function(autoActivate){
20546 delete this.showTimer;
20547 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20549 this.menu.tryActivate(0, 1);
20554 hideMenu : function(){
20555 clearTimeout(this.showTimer);
20556 delete this.showTimer;
20557 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20558 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20563 deferHide : function(){
20564 delete this.hideTimer;
20569 * Ext JS Library 1.1.1
20570 * Copyright(c) 2006-2007, Ext JS, LLC.
20572 * Originally Released Under LGPL - original licence link has changed is not relivant.
20575 * <script type="text/javascript">
20579 * @class Roo.menu.CheckItem
20580 * @extends Roo.menu.Item
20581 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20583 * Creates a new CheckItem
20584 * @param {Object} config Configuration options
20586 Roo.menu.CheckItem = function(config){
20587 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20590 * @event beforecheckchange
20591 * Fires before the checked value is set, providing an opportunity to cancel if needed
20592 * @param {Roo.menu.CheckItem} this
20593 * @param {Boolean} checked The new checked value that will be set
20595 "beforecheckchange" : true,
20597 * @event checkchange
20598 * Fires after the checked value has been set
20599 * @param {Roo.menu.CheckItem} this
20600 * @param {Boolean} checked The checked value that was set
20602 "checkchange" : true
20604 if(this.checkHandler){
20605 this.on('checkchange', this.checkHandler, this.scope);
20608 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20610 * @cfg {String} group
20611 * All check items with the same group name will automatically be grouped into a single-select
20612 * radio button group (defaults to '')
20615 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20617 itemCls : "x-menu-item x-menu-check-item",
20619 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20621 groupClass : "x-menu-group-item",
20624 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20625 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20626 * initialized with checked = true will be rendered as checked.
20631 ctype: "Roo.menu.CheckItem",
20634 onRender : function(c){
20635 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20637 this.el.addClass(this.groupClass);
20639 Roo.menu.MenuMgr.registerCheckable(this);
20641 this.checked = false;
20642 this.setChecked(true, true);
20647 destroy : function(){
20649 Roo.menu.MenuMgr.unregisterCheckable(this);
20651 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20655 * Set the checked state of this item
20656 * @param {Boolean} checked The new checked value
20657 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20659 setChecked : function(state, suppressEvent){
20660 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20661 if(this.container){
20662 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20664 this.checked = state;
20665 if(suppressEvent !== true){
20666 this.fireEvent("checkchange", this, state);
20672 handleClick : function(e){
20673 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20674 this.setChecked(!this.checked);
20676 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20680 * Ext JS Library 1.1.1
20681 * Copyright(c) 2006-2007, Ext JS, LLC.
20683 * Originally Released Under LGPL - original licence link has changed is not relivant.
20686 * <script type="text/javascript">
20690 * @class Roo.menu.DateItem
20691 * @extends Roo.menu.Adapter
20692 * A menu item that wraps the {@link Roo.DatPicker} component.
20694 * Creates a new DateItem
20695 * @param {Object} config Configuration options
20697 Roo.menu.DateItem = function(config){
20698 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20699 /** The Roo.DatePicker object @type Roo.DatePicker */
20700 this.picker = this.component;
20701 this.addEvents({select: true});
20703 this.picker.on("render", function(picker){
20704 picker.getEl().swallowEvent("click");
20705 picker.container.addClass("x-menu-date-item");
20708 this.picker.on("select", this.onSelect, this);
20711 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20713 onSelect : function(picker, date){
20714 this.fireEvent("select", this, date, picker);
20715 Roo.menu.DateItem.superclass.handleClick.call(this);
20719 * Ext JS Library 1.1.1
20720 * Copyright(c) 2006-2007, Ext JS, LLC.
20722 * Originally Released Under LGPL - original licence link has changed is not relivant.
20725 * <script type="text/javascript">
20729 * @class Roo.menu.ColorItem
20730 * @extends Roo.menu.Adapter
20731 * A menu item that wraps the {@link Roo.ColorPalette} component.
20733 * Creates a new ColorItem
20734 * @param {Object} config Configuration options
20736 Roo.menu.ColorItem = function(config){
20737 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20738 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20739 this.palette = this.component;
20740 this.relayEvents(this.palette, ["select"]);
20741 if(this.selectHandler){
20742 this.on('select', this.selectHandler, this.scope);
20745 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20747 * Ext JS Library 1.1.1
20748 * Copyright(c) 2006-2007, Ext JS, LLC.
20750 * Originally Released Under LGPL - original licence link has changed is not relivant.
20753 * <script type="text/javascript">
20758 * @class Roo.menu.DateMenu
20759 * @extends Roo.menu.Menu
20760 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20762 * Creates a new DateMenu
20763 * @param {Object} config Configuration options
20765 Roo.menu.DateMenu = function(config){
20766 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20768 var di = new Roo.menu.DateItem(config);
20771 * The {@link Roo.DatePicker} instance for this DateMenu
20774 this.picker = di.picker;
20777 * @param {DatePicker} picker
20778 * @param {Date} date
20780 this.relayEvents(di, ["select"]);
20782 this.on('beforeshow', function(){
20784 this.picker.hideMonthPicker(true);
20788 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20792 * Ext JS Library 1.1.1
20793 * Copyright(c) 2006-2007, Ext JS, LLC.
20795 * Originally Released Under LGPL - original licence link has changed is not relivant.
20798 * <script type="text/javascript">
20803 * @class Roo.menu.ColorMenu
20804 * @extends Roo.menu.Menu
20805 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20807 * Creates a new ColorMenu
20808 * @param {Object} config Configuration options
20810 Roo.menu.ColorMenu = function(config){
20811 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20813 var ci = new Roo.menu.ColorItem(config);
20816 * The {@link Roo.ColorPalette} instance for this ColorMenu
20817 * @type ColorPalette
20819 this.palette = ci.palette;
20822 * @param {ColorPalette} palette
20823 * @param {String} color
20825 this.relayEvents(ci, ["select"]);
20827 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20829 * Ext JS Library 1.1.1
20830 * Copyright(c) 2006-2007, Ext JS, LLC.
20832 * Originally Released Under LGPL - original licence link has changed is not relivant.
20835 * <script type="text/javascript">
20839 * @class Roo.form.Field
20840 * @extends Roo.BoxComponent
20841 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20843 * Creates a new Field
20844 * @param {Object} config Configuration options
20846 Roo.form.Field = function(config){
20847 Roo.form.Field.superclass.constructor.call(this, config);
20850 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20852 * @cfg {String} fieldLabel Label to use when rendering a form.
20855 * @cfg {String} qtip Mouse over tip
20859 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20861 invalidClass : "x-form-invalid",
20863 * @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")
20865 invalidText : "The value in this field is invalid",
20867 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20869 focusClass : "x-form-focus",
20871 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20872 automatic validation (defaults to "keyup").
20874 validationEvent : "keyup",
20876 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20878 validateOnBlur : true,
20880 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20882 validationDelay : 250,
20884 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20885 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20887 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20889 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20891 fieldClass : "x-form-field",
20893 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20896 ----------- ----------------------------------------------------------------------
20897 qtip Display a quick tip when the user hovers over the field
20898 title Display a default browser title attribute popup
20899 under Add a block div beneath the field containing the error text
20900 side Add an error icon to the right of the field with a popup on hover
20901 [element id] Add the error text directly to the innerHTML of the specified element
20904 msgTarget : 'qtip',
20906 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20911 * @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.
20916 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20921 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20923 inputType : undefined,
20926 * @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).
20928 tabIndex : undefined,
20931 isFormField : true,
20936 * @property {Roo.Element} fieldEl
20937 * Element Containing the rendered Field (with label etc.)
20940 * @cfg {Mixed} value A value to initialize this field with.
20945 * @cfg {String} name The field's HTML name attribute.
20948 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20952 initComponent : function(){
20953 Roo.form.Field.superclass.initComponent.call(this);
20957 * Fires when this field receives input focus.
20958 * @param {Roo.form.Field} this
20963 * Fires when this field loses input focus.
20964 * @param {Roo.form.Field} this
20968 * @event specialkey
20969 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20970 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20971 * @param {Roo.form.Field} this
20972 * @param {Roo.EventObject} e The event object
20977 * Fires just before the field blurs if the field value has changed.
20978 * @param {Roo.form.Field} this
20979 * @param {Mixed} newValue The new value
20980 * @param {Mixed} oldValue The original value
20985 * Fires after the field has been marked as invalid.
20986 * @param {Roo.form.Field} this
20987 * @param {String} msg The validation message
20992 * Fires after the field has been validated with no errors.
20993 * @param {Roo.form.Field} this
20998 * Fires after the key up
20999 * @param {Roo.form.Field} this
21000 * @param {Roo.EventObject} e The event Object
21007 * Returns the name attribute of the field if available
21008 * @return {String} name The field name
21010 getName: function(){
21011 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
21015 onRender : function(ct, position){
21016 Roo.form.Field.superclass.onRender.call(this, ct, position);
21018 var cfg = this.getAutoCreate();
21020 cfg.name = this.name || this.id;
21022 if(this.inputType){
21023 cfg.type = this.inputType;
21025 this.el = ct.createChild(cfg, position);
21027 var type = this.el.dom.type;
21029 if(type == 'password'){
21032 this.el.addClass('x-form-'+type);
21035 this.el.dom.readOnly = true;
21037 if(this.tabIndex !== undefined){
21038 this.el.dom.setAttribute('tabIndex', this.tabIndex);
21041 this.el.addClass([this.fieldClass, this.cls]);
21046 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
21047 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
21048 * @return {Roo.form.Field} this
21050 applyTo : function(target){
21051 this.allowDomMove = false;
21052 this.el = Roo.get(target);
21053 this.render(this.el.dom.parentNode);
21058 initValue : function(){
21059 if(this.value !== undefined){
21060 this.setValue(this.value);
21061 }else if(this.el.dom.value.length > 0){
21062 this.setValue(this.el.dom.value);
21067 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21069 isDirty : function() {
21070 if(this.disabled) {
21073 return String(this.getValue()) !== String(this.originalValue);
21077 afterRender : function(){
21078 Roo.form.Field.superclass.afterRender.call(this);
21083 fireKey : function(e){
21084 //Roo.log('field ' + e.getKey());
21085 if(e.isNavKeyPress()){
21086 this.fireEvent("specialkey", this, e);
21091 * Resets the current field value to the originally loaded value and clears any validation messages
21093 reset : function(){
21094 this.setValue(this.originalValue);
21095 this.clearInvalid();
21099 initEvents : function(){
21100 // safari killled keypress - so keydown is now used..
21101 this.el.on("keydown" , this.fireKey, this);
21102 this.el.on("focus", this.onFocus, this);
21103 this.el.on("blur", this.onBlur, this);
21104 this.el.relayEvent('keyup', this);
21106 // reference to original value for reset
21107 this.originalValue = this.getValue();
21111 onFocus : function(){
21112 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21113 this.el.addClass(this.focusClass);
21115 if(!this.hasFocus){
21116 this.hasFocus = true;
21117 this.startValue = this.getValue();
21118 this.fireEvent("focus", this);
21122 beforeBlur : Roo.emptyFn,
21125 onBlur : function(){
21127 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21128 this.el.removeClass(this.focusClass);
21130 this.hasFocus = false;
21131 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21134 var v = this.getValue();
21135 if(String(v) !== String(this.startValue)){
21136 this.fireEvent('change', this, v, this.startValue);
21138 this.fireEvent("blur", this);
21142 * Returns whether or not the field value is currently valid
21143 * @param {Boolean} preventMark True to disable marking the field invalid
21144 * @return {Boolean} True if the value is valid, else false
21146 isValid : function(preventMark){
21150 var restore = this.preventMark;
21151 this.preventMark = preventMark === true;
21152 var v = this.validateValue(this.processValue(this.getRawValue()));
21153 this.preventMark = restore;
21158 * Validates the field value
21159 * @return {Boolean} True if the value is valid, else false
21161 validate : function(){
21162 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21163 this.clearInvalid();
21169 processValue : function(value){
21174 // Subclasses should provide the validation implementation by overriding this
21175 validateValue : function(value){
21180 * Mark this field as invalid
21181 * @param {String} msg The validation message
21183 markInvalid : function(msg){
21184 if(!this.rendered || this.preventMark){ // not rendered
21187 this.el.addClass(this.invalidClass);
21188 msg = msg || this.invalidText;
21189 switch(this.msgTarget){
21191 this.el.dom.qtip = msg;
21192 this.el.dom.qclass = 'x-form-invalid-tip';
21193 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21194 Roo.QuickTips.enable();
21198 this.el.dom.title = msg;
21202 var elp = this.el.findParent('.x-form-element', 5, true);
21203 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21204 this.errorEl.setWidth(elp.getWidth(true)-20);
21206 this.errorEl.update(msg);
21207 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21210 if(!this.errorIcon){
21211 var elp = this.el.findParent('.x-form-element', 5, true);
21212 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21214 this.alignErrorIcon();
21215 this.errorIcon.dom.qtip = msg;
21216 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21217 this.errorIcon.show();
21218 this.on('resize', this.alignErrorIcon, this);
21221 var t = Roo.getDom(this.msgTarget);
21223 t.style.display = this.msgDisplay;
21226 this.fireEvent('invalid', this, msg);
21230 alignErrorIcon : function(){
21231 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21235 * Clear any invalid styles/messages for this field
21237 clearInvalid : function(){
21238 if(!this.rendered || this.preventMark){ // not rendered
21241 this.el.removeClass(this.invalidClass);
21242 switch(this.msgTarget){
21244 this.el.dom.qtip = '';
21247 this.el.dom.title = '';
21251 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21255 if(this.errorIcon){
21256 this.errorIcon.dom.qtip = '';
21257 this.errorIcon.hide();
21258 this.un('resize', this.alignErrorIcon, this);
21262 var t = Roo.getDom(this.msgTarget);
21264 t.style.display = 'none';
21267 this.fireEvent('valid', this);
21271 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21272 * @return {Mixed} value The field value
21274 getRawValue : function(){
21275 var v = this.el.getValue();
21276 if(v === this.emptyText){
21283 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21284 * @return {Mixed} value The field value
21286 getValue : function(){
21287 var v = this.el.getValue();
21288 if(v === this.emptyText || v === undefined){
21295 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21296 * @param {Mixed} value The value to set
21298 setRawValue : function(v){
21299 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21303 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21304 * @param {Mixed} value The value to set
21306 setValue : function(v){
21309 this.el.dom.value = (v === null || v === undefined ? '' : v);
21314 adjustSize : function(w, h){
21315 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21316 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21320 adjustWidth : function(tag, w){
21321 tag = tag.toLowerCase();
21322 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21323 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21324 if(tag == 'input'){
21327 if(tag = 'textarea'){
21330 }else if(Roo.isOpera){
21331 if(tag == 'input'){
21334 if(tag = 'textarea'){
21344 // anything other than normal should be considered experimental
21345 Roo.form.Field.msgFx = {
21347 show: function(msgEl, f){
21348 msgEl.setDisplayed('block');
21351 hide : function(msgEl, f){
21352 msgEl.setDisplayed(false).update('');
21357 show: function(msgEl, f){
21358 msgEl.slideIn('t', {stopFx:true});
21361 hide : function(msgEl, f){
21362 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21367 show: function(msgEl, f){
21368 msgEl.fixDisplay();
21369 msgEl.alignTo(f.el, 'tl-tr');
21370 msgEl.slideIn('l', {stopFx:true});
21373 hide : function(msgEl, f){
21374 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21379 * Ext JS Library 1.1.1
21380 * Copyright(c) 2006-2007, Ext JS, LLC.
21382 * Originally Released Under LGPL - original licence link has changed is not relivant.
21385 * <script type="text/javascript">
21390 * @class Roo.form.TextField
21391 * @extends Roo.form.Field
21392 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21393 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21395 * Creates a new TextField
21396 * @param {Object} config Configuration options
21398 Roo.form.TextField = function(config){
21399 Roo.form.TextField.superclass.constructor.call(this, config);
21403 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21404 * according to the default logic, but this event provides a hook for the developer to apply additional
21405 * logic at runtime to resize the field if needed.
21406 * @param {Roo.form.Field} this This text field
21407 * @param {Number} width The new field width
21413 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21415 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21419 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21423 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21427 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21431 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21435 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21437 disableKeyFilter : false,
21439 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21443 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21447 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21449 maxLength : Number.MAX_VALUE,
21451 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21453 minLengthText : "The minimum length for this field is {0}",
21455 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21457 maxLengthText : "The maximum length for this field is {0}",
21459 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21461 selectOnFocus : false,
21463 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21465 blankText : "This field is required",
21467 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21468 * If available, this function will be called only after the basic validators all return true, and will be passed the
21469 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21473 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21474 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21475 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21479 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21483 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21487 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21488 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21490 emptyClass : 'x-form-empty-field',
21493 initEvents : function(){
21494 Roo.form.TextField.superclass.initEvents.call(this);
21495 if(this.validationEvent == 'keyup'){
21496 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21497 this.el.on('keyup', this.filterValidation, this);
21499 else if(this.validationEvent !== false){
21500 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21502 if(this.selectOnFocus || this.emptyText){
21503 this.on("focus", this.preFocus, this);
21504 if(this.emptyText){
21505 this.on('blur', this.postBlur, this);
21506 this.applyEmptyText();
21509 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21510 this.el.on("keypress", this.filterKeys, this);
21513 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21514 this.el.on("click", this.autoSize, this);
21518 processValue : function(value){
21519 if(this.stripCharsRe){
21520 var newValue = value.replace(this.stripCharsRe, '');
21521 if(newValue !== value){
21522 this.setRawValue(newValue);
21529 filterValidation : function(e){
21530 if(!e.isNavKeyPress()){
21531 this.validationTask.delay(this.validationDelay);
21536 onKeyUp : function(e){
21537 if(!e.isNavKeyPress()){
21543 * Resets the current field value to the originally-loaded value and clears any validation messages.
21544 * Also adds emptyText and emptyClass if the original value was blank.
21546 reset : function(){
21547 Roo.form.TextField.superclass.reset.call(this);
21548 this.applyEmptyText();
21551 applyEmptyText : function(){
21552 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21553 this.setRawValue(this.emptyText);
21554 this.el.addClass(this.emptyClass);
21559 preFocus : function(){
21560 if(this.emptyText){
21561 if(this.el.dom.value == this.emptyText){
21562 this.setRawValue('');
21564 this.el.removeClass(this.emptyClass);
21566 if(this.selectOnFocus){
21567 this.el.dom.select();
21572 postBlur : function(){
21573 this.applyEmptyText();
21577 filterKeys : function(e){
21578 var k = e.getKey();
21579 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21582 var c = e.getCharCode(), cc = String.fromCharCode(c);
21583 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21586 if(!this.maskRe.test(cc)){
21591 setValue : function(v){
21592 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21593 this.el.removeClass(this.emptyClass);
21595 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21596 this.applyEmptyText();
21601 * Validates a value according to the field's validation rules and marks the field as invalid
21602 * if the validation fails
21603 * @param {Mixed} value The value to validate
21604 * @return {Boolean} True if the value is valid, else false
21606 validateValue : function(value){
21607 if(value.length < 1 || value === this.emptyText){ // if it's blank
21608 if(this.allowBlank){
21609 this.clearInvalid();
21612 this.markInvalid(this.blankText);
21616 if(value.length < this.minLength){
21617 this.markInvalid(String.format(this.minLengthText, this.minLength));
21620 if(value.length > this.maxLength){
21621 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21625 var vt = Roo.form.VTypes;
21626 if(!vt[this.vtype](value, this)){
21627 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21631 if(typeof this.validator == "function"){
21632 var msg = this.validator(value);
21634 this.markInvalid(msg);
21638 if(this.regex && !this.regex.test(value)){
21639 this.markInvalid(this.regexText);
21646 * Selects text in this field
21647 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21648 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21650 selectText : function(start, end){
21651 var v = this.getRawValue();
21653 start = start === undefined ? 0 : start;
21654 end = end === undefined ? v.length : end;
21655 var d = this.el.dom;
21656 if(d.setSelectionRange){
21657 d.setSelectionRange(start, end);
21658 }else if(d.createTextRange){
21659 var range = d.createTextRange();
21660 range.moveStart("character", start);
21661 range.moveEnd("character", v.length-end);
21668 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21669 * This only takes effect if grow = true, and fires the autosize event.
21671 autoSize : function(){
21672 if(!this.grow || !this.rendered){
21676 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21679 var v = el.dom.value;
21680 var d = document.createElement('div');
21681 d.appendChild(document.createTextNode(v));
21685 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21686 this.el.setWidth(w);
21687 this.fireEvent("autosize", this, w);
21691 * Ext JS Library 1.1.1
21692 * Copyright(c) 2006-2007, Ext JS, LLC.
21694 * Originally Released Under LGPL - original licence link has changed is not relivant.
21697 * <script type="text/javascript">
21701 * @class Roo.form.Hidden
21702 * @extends Roo.form.TextField
21703 * Simple Hidden element used on forms
21705 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21708 * Creates a new Hidden form element.
21709 * @param {Object} config Configuration options
21714 // easy hidden field...
21715 Roo.form.Hidden = function(config){
21716 Roo.form.Hidden.superclass.constructor.call(this, config);
21719 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21721 inputType: 'hidden',
21724 labelSeparator: '',
21726 itemCls : 'x-form-item-display-none'
21734 * Ext JS Library 1.1.1
21735 * Copyright(c) 2006-2007, Ext JS, LLC.
21737 * Originally Released Under LGPL - original licence link has changed is not relivant.
21740 * <script type="text/javascript">
21744 * @class Roo.form.TriggerField
21745 * @extends Roo.form.TextField
21746 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21747 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21748 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21749 * for which you can provide a custom implementation. For example:
21751 var trigger = new Roo.form.TriggerField();
21752 trigger.onTriggerClick = myTriggerFn;
21753 trigger.applyTo('my-field');
21756 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21757 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21758 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21759 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21761 * Create a new TriggerField.
21762 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21763 * to the base TextField)
21765 Roo.form.TriggerField = function(config){
21766 this.mimicing = false;
21767 Roo.form.TriggerField.superclass.constructor.call(this, config);
21770 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21772 * @cfg {String} triggerClass A CSS class to apply to the trigger
21775 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21776 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21778 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21780 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21784 /** @cfg {Boolean} grow @hide */
21785 /** @cfg {Number} growMin @hide */
21786 /** @cfg {Number} growMax @hide */
21792 autoSize: Roo.emptyFn,
21796 deferHeight : true,
21799 actionMode : 'wrap',
21801 onResize : function(w, h){
21802 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21803 if(typeof w == 'number'){
21804 var x = w - this.trigger.getWidth();
21805 this.el.setWidth(this.adjustWidth('input', x));
21806 this.trigger.setStyle('left', x+'px');
21811 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21814 getResizeEl : function(){
21819 getPositionEl : function(){
21824 alignErrorIcon : function(){
21825 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21829 onRender : function(ct, position){
21830 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21831 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21832 this.trigger = this.wrap.createChild(this.triggerConfig ||
21833 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21834 if(this.hideTrigger){
21835 this.trigger.setDisplayed(false);
21837 this.initTrigger();
21839 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21844 initTrigger : function(){
21845 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21846 this.trigger.addClassOnOver('x-form-trigger-over');
21847 this.trigger.addClassOnClick('x-form-trigger-click');
21851 onDestroy : function(){
21853 this.trigger.removeAllListeners();
21854 this.trigger.remove();
21857 this.wrap.remove();
21859 Roo.form.TriggerField.superclass.onDestroy.call(this);
21863 onFocus : function(){
21864 Roo.form.TriggerField.superclass.onFocus.call(this);
21865 if(!this.mimicing){
21866 this.wrap.addClass('x-trigger-wrap-focus');
21867 this.mimicing = true;
21868 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21869 if(this.monitorTab){
21870 this.el.on("keydown", this.checkTab, this);
21876 checkTab : function(e){
21877 if(e.getKey() == e.TAB){
21878 this.triggerBlur();
21883 onBlur : function(){
21888 mimicBlur : function(e, t){
21889 if(!this.wrap.contains(t) && this.validateBlur()){
21890 this.triggerBlur();
21895 triggerBlur : function(){
21896 this.mimicing = false;
21897 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21898 if(this.monitorTab){
21899 this.el.un("keydown", this.checkTab, this);
21901 this.wrap.removeClass('x-trigger-wrap-focus');
21902 Roo.form.TriggerField.superclass.onBlur.call(this);
21906 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21907 validateBlur : function(e, t){
21912 onDisable : function(){
21913 Roo.form.TriggerField.superclass.onDisable.call(this);
21915 this.wrap.addClass('x-item-disabled');
21920 onEnable : function(){
21921 Roo.form.TriggerField.superclass.onEnable.call(this);
21923 this.wrap.removeClass('x-item-disabled');
21928 onShow : function(){
21929 var ae = this.getActionEl();
21932 ae.dom.style.display = '';
21933 ae.dom.style.visibility = 'visible';
21939 onHide : function(){
21940 var ae = this.getActionEl();
21941 ae.dom.style.display = 'none';
21945 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21946 * by an implementing function.
21948 * @param {EventObject} e
21950 onTriggerClick : Roo.emptyFn
21953 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21954 // to be extended by an implementing class. For an example of implementing this class, see the custom
21955 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21956 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21957 initComponent : function(){
21958 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21960 this.triggerConfig = {
21961 tag:'span', cls:'x-form-twin-triggers', cn:[
21962 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21963 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21967 getTrigger : function(index){
21968 return this.triggers[index];
21971 initTrigger : function(){
21972 var ts = this.trigger.select('.x-form-trigger', true);
21973 this.wrap.setStyle('overflow', 'hidden');
21974 var triggerField = this;
21975 ts.each(function(t, all, index){
21976 t.hide = function(){
21977 var w = triggerField.wrap.getWidth();
21978 this.dom.style.display = 'none';
21979 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21981 t.show = function(){
21982 var w = triggerField.wrap.getWidth();
21983 this.dom.style.display = '';
21984 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21986 var triggerIndex = 'Trigger'+(index+1);
21988 if(this['hide'+triggerIndex]){
21989 t.dom.style.display = 'none';
21991 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21992 t.addClassOnOver('x-form-trigger-over');
21993 t.addClassOnClick('x-form-trigger-click');
21995 this.triggers = ts.elements;
21998 onTrigger1Click : Roo.emptyFn,
21999 onTrigger2Click : Roo.emptyFn
22002 * Ext JS Library 1.1.1
22003 * Copyright(c) 2006-2007, Ext JS, LLC.
22005 * Originally Released Under LGPL - original licence link has changed is not relivant.
22008 * <script type="text/javascript">
22012 * @class Roo.form.TextArea
22013 * @extends Roo.form.TextField
22014 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
22015 * support for auto-sizing.
22017 * Creates a new TextArea
22018 * @param {Object} config Configuration options
22020 Roo.form.TextArea = function(config){
22021 Roo.form.TextArea.superclass.constructor.call(this, config);
22022 // these are provided exchanges for backwards compat
22023 // minHeight/maxHeight were replaced by growMin/growMax to be
22024 // compatible with TextField growing config values
22025 if(this.minHeight !== undefined){
22026 this.growMin = this.minHeight;
22028 if(this.maxHeight !== undefined){
22029 this.growMax = this.maxHeight;
22033 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
22035 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
22039 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
22043 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
22044 * in the field (equivalent to setting overflow: hidden, defaults to false)
22046 preventScrollbars: false,
22048 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
22049 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
22053 onRender : function(ct, position){
22055 this.defaultAutoCreate = {
22057 style:"width:300px;height:60px;",
22058 autocomplete: "off"
22061 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22063 this.textSizeEl = Roo.DomHelper.append(document.body, {
22064 tag: "pre", cls: "x-form-grow-sizer"
22066 if(this.preventScrollbars){
22067 this.el.setStyle("overflow", "hidden");
22069 this.el.setHeight(this.growMin);
22073 onDestroy : function(){
22074 if(this.textSizeEl){
22075 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22077 Roo.form.TextArea.superclass.onDestroy.call(this);
22081 onKeyUp : function(e){
22082 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22088 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22089 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22091 autoSize : function(){
22092 if(!this.grow || !this.textSizeEl){
22096 var v = el.dom.value;
22097 var ts = this.textSizeEl;
22100 ts.appendChild(document.createTextNode(v));
22103 Roo.fly(ts).setWidth(this.el.getWidth());
22105 v = "  ";
22108 v = v.replace(/\n/g, '<p> </p>');
22110 v += " \n ";
22113 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22114 if(h != this.lastHeight){
22115 this.lastHeight = h;
22116 this.el.setHeight(h);
22117 this.fireEvent("autosize", this, h);
22122 * Ext JS Library 1.1.1
22123 * Copyright(c) 2006-2007, Ext JS, LLC.
22125 * Originally Released Under LGPL - original licence link has changed is not relivant.
22128 * <script type="text/javascript">
22133 * @class Roo.form.NumberField
22134 * @extends Roo.form.TextField
22135 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22137 * Creates a new NumberField
22138 * @param {Object} config Configuration options
22140 Roo.form.NumberField = function(config){
22141 Roo.form.NumberField.superclass.constructor.call(this, config);
22144 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22146 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22148 fieldClass: "x-form-field x-form-num-field",
22150 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22152 allowDecimals : true,
22154 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22156 decimalSeparator : ".",
22158 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22160 decimalPrecision : 2,
22162 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22164 allowNegative : true,
22166 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22168 minValue : Number.NEGATIVE_INFINITY,
22170 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22172 maxValue : Number.MAX_VALUE,
22174 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22176 minText : "The minimum value for this field is {0}",
22178 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22180 maxText : "The maximum value for this field is {0}",
22182 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22183 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22185 nanText : "{0} is not a valid number",
22188 initEvents : function(){
22189 Roo.form.NumberField.superclass.initEvents.call(this);
22190 var allowed = "0123456789";
22191 if(this.allowDecimals){
22192 allowed += this.decimalSeparator;
22194 if(this.allowNegative){
22197 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22198 var keyPress = function(e){
22199 var k = e.getKey();
22200 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22203 var c = e.getCharCode();
22204 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22208 this.el.on("keypress", keyPress, this);
22212 validateValue : function(value){
22213 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22216 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22219 var num = this.parseValue(value);
22221 this.markInvalid(String.format(this.nanText, value));
22224 if(num < this.minValue){
22225 this.markInvalid(String.format(this.minText, this.minValue));
22228 if(num > this.maxValue){
22229 this.markInvalid(String.format(this.maxText, this.maxValue));
22235 getValue : function(){
22236 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22240 parseValue : function(value){
22241 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22242 return isNaN(value) ? '' : value;
22246 fixPrecision : function(value){
22247 var nan = isNaN(value);
22248 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22249 return nan ? '' : value;
22251 return parseFloat(value).toFixed(this.decimalPrecision);
22254 setValue : function(v){
22255 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22259 decimalPrecisionFcn : function(v){
22260 return Math.floor(v);
22263 beforeBlur : function(){
22264 var v = this.parseValue(this.getRawValue());
22266 this.setValue(this.fixPrecision(v));
22271 * Ext JS Library 1.1.1
22272 * Copyright(c) 2006-2007, Ext JS, LLC.
22274 * Originally Released Under LGPL - original licence link has changed is not relivant.
22277 * <script type="text/javascript">
22281 * @class Roo.form.DateField
22282 * @extends Roo.form.TriggerField
22283 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22285 * Create a new DateField
22286 * @param {Object} config
22288 Roo.form.DateField = function(config){
22289 Roo.form.DateField.superclass.constructor.call(this, config);
22295 * Fires when a date is selected
22296 * @param {Roo.form.DateField} combo This combo box
22297 * @param {Date} date The date selected
22304 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22305 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22306 this.ddMatch = null;
22307 if(this.disabledDates){
22308 var dd = this.disabledDates;
22310 for(var i = 0; i < dd.length; i++){
22312 if(i != dd.length-1) re += "|";
22314 this.ddMatch = new RegExp(re + ")");
22318 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22320 * @cfg {String} format
22321 * The default date format string which can be overriden for localization support. The format must be
22322 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22326 * @cfg {String} altFormats
22327 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22328 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22330 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22332 * @cfg {Array} disabledDays
22333 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22335 disabledDays : null,
22337 * @cfg {String} disabledDaysText
22338 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22340 disabledDaysText : "Disabled",
22342 * @cfg {Array} disabledDates
22343 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22344 * expression so they are very powerful. Some examples:
22346 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22347 * <li>["03/08", "09/16"] would disable those days for every year</li>
22348 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22349 * <li>["03/../2006"] would disable every day in March 2006</li>
22350 * <li>["^03"] would disable every day in every March</li>
22352 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22353 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22355 disabledDates : null,
22357 * @cfg {String} disabledDatesText
22358 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22360 disabledDatesText : "Disabled",
22362 * @cfg {Date/String} minValue
22363 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22364 * valid format (defaults to null).
22368 * @cfg {Date/String} maxValue
22369 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22370 * valid format (defaults to null).
22374 * @cfg {String} minText
22375 * The error text to display when the date in the cell is before minValue (defaults to
22376 * 'The date in this field must be after {minValue}').
22378 minText : "The date in this field must be equal to or after {0}",
22380 * @cfg {String} maxText
22381 * The error text to display when the date in the cell is after maxValue (defaults to
22382 * 'The date in this field must be before {maxValue}').
22384 maxText : "The date in this field must be equal to or before {0}",
22386 * @cfg {String} invalidText
22387 * The error text to display when the date in the field is invalid (defaults to
22388 * '{value} is not a valid date - it must be in the format {format}').
22390 invalidText : "{0} is not a valid date - it must be in the format {1}",
22392 * @cfg {String} triggerClass
22393 * An additional CSS class used to style the trigger button. The trigger will always get the
22394 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22395 * which displays a calendar icon).
22397 triggerClass : 'x-form-date-trigger',
22401 * @cfg {bool} useIso
22402 * if enabled, then the date field will use a hidden field to store the
22403 * real value as iso formated date. default (false)
22407 * @cfg {String/Object} autoCreate
22408 * A DomHelper element spec, or true for a default element spec (defaults to
22409 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22412 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22415 hiddenField: false,
22417 onRender : function(ct, position)
22419 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22421 this.el.dom.removeAttribute('name');
22422 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22424 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22425 // prevent input submission
22426 this.hiddenName = this.name;
22433 validateValue : function(value)
22435 value = this.formatDate(value);
22436 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22439 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22442 var svalue = value;
22443 value = this.parseDate(value);
22445 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22448 var time = value.getTime();
22449 if(this.minValue && time < this.minValue.getTime()){
22450 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22453 if(this.maxValue && time > this.maxValue.getTime()){
22454 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22457 if(this.disabledDays){
22458 var day = value.getDay();
22459 for(var i = 0; i < this.disabledDays.length; i++) {
22460 if(day === this.disabledDays[i]){
22461 this.markInvalid(this.disabledDaysText);
22466 var fvalue = this.formatDate(value);
22467 if(this.ddMatch && this.ddMatch.test(fvalue)){
22468 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22475 // Provides logic to override the default TriggerField.validateBlur which just returns true
22476 validateBlur : function(){
22477 return !this.menu || !this.menu.isVisible();
22481 * Returns the current date value of the date field.
22482 * @return {Date} The date value
22484 getValue : function(){
22486 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22490 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22491 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22492 * (the default format used is "m/d/y").
22495 //All of these calls set the same date value (May 4, 2006)
22497 //Pass a date object:
22498 var dt = new Date('5/4/06');
22499 dateField.setValue(dt);
22501 //Pass a date string (default format):
22502 dateField.setValue('5/4/06');
22504 //Pass a date string (custom format):
22505 dateField.format = 'Y-m-d';
22506 dateField.setValue('2006-5-4');
22508 * @param {String/Date} date The date or valid date string
22510 setValue : function(date){
22511 if (this.hiddenField) {
22512 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22514 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22518 parseDate : function(value){
22519 if(!value || value instanceof Date){
22522 var v = Date.parseDate(value, this.format);
22523 if(!v && this.altFormats){
22524 if(!this.altFormatsArray){
22525 this.altFormatsArray = this.altFormats.split("|");
22527 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22528 v = Date.parseDate(value, this.altFormatsArray[i]);
22535 formatDate : function(date, fmt){
22536 return (!date || !(date instanceof Date)) ?
22537 date : date.dateFormat(fmt || this.format);
22542 select: function(m, d){
22544 this.fireEvent('select', this, d);
22546 show : function(){ // retain focus styling
22550 this.focus.defer(10, this);
22551 var ml = this.menuListeners;
22552 this.menu.un("select", ml.select, this);
22553 this.menu.un("show", ml.show, this);
22554 this.menu.un("hide", ml.hide, this);
22559 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22560 onTriggerClick : function(){
22564 if(this.menu == null){
22565 this.menu = new Roo.menu.DateMenu();
22567 Roo.apply(this.menu.picker, {
22568 showClear: this.allowBlank,
22569 minDate : this.minValue,
22570 maxDate : this.maxValue,
22571 disabledDatesRE : this.ddMatch,
22572 disabledDatesText : this.disabledDatesText,
22573 disabledDays : this.disabledDays,
22574 disabledDaysText : this.disabledDaysText,
22575 format : this.format,
22576 minText : String.format(this.minText, this.formatDate(this.minValue)),
22577 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22579 this.menu.on(Roo.apply({}, this.menuListeners, {
22582 this.menu.picker.setValue(this.getValue() || new Date());
22583 this.menu.show(this.el, "tl-bl?");
22586 beforeBlur : function(){
22587 var v = this.parseDate(this.getRawValue());
22593 /** @cfg {Boolean} grow @hide */
22594 /** @cfg {Number} growMin @hide */
22595 /** @cfg {Number} growMax @hide */
22602 * Ext JS Library 1.1.1
22603 * Copyright(c) 2006-2007, Ext JS, LLC.
22605 * Originally Released Under LGPL - original licence link has changed is not relivant.
22608 * <script type="text/javascript">
22613 * @class Roo.form.ComboBox
22614 * @extends Roo.form.TriggerField
22615 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22617 * Create a new ComboBox.
22618 * @param {Object} config Configuration options
22620 Roo.form.ComboBox = function(config){
22621 Roo.form.ComboBox.superclass.constructor.call(this, config);
22625 * Fires when the dropdown list is expanded
22626 * @param {Roo.form.ComboBox} combo This combo box
22631 * Fires when the dropdown list is collapsed
22632 * @param {Roo.form.ComboBox} combo This combo box
22636 * @event beforeselect
22637 * Fires before a list item is selected. Return false to cancel the selection.
22638 * @param {Roo.form.ComboBox} combo This combo box
22639 * @param {Roo.data.Record} record The data record returned from the underlying store
22640 * @param {Number} index The index of the selected item in the dropdown list
22642 'beforeselect' : true,
22645 * Fires when a list item is selected
22646 * @param {Roo.form.ComboBox} combo This combo box
22647 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22648 * @param {Number} index The index of the selected item in the dropdown list
22652 * @event beforequery
22653 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22654 * The event object passed has these properties:
22655 * @param {Roo.form.ComboBox} combo This combo box
22656 * @param {String} query The query
22657 * @param {Boolean} forceAll true to force "all" query
22658 * @param {Boolean} cancel true to cancel the query
22659 * @param {Object} e The query event object
22661 'beforequery': true,
22664 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22665 * @param {Roo.form.ComboBox} combo This combo box
22670 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22671 * @param {Roo.form.ComboBox} combo This combo box
22672 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22678 if(this.transform){
22679 this.allowDomMove = false;
22680 var s = Roo.getDom(this.transform);
22681 if(!this.hiddenName){
22682 this.hiddenName = s.name;
22685 this.mode = 'local';
22686 var d = [], opts = s.options;
22687 for(var i = 0, len = opts.length;i < len; i++){
22689 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22691 this.value = value;
22693 d.push([value, o.text]);
22695 this.store = new Roo.data.SimpleStore({
22697 fields: ['value', 'text'],
22700 this.valueField = 'value';
22701 this.displayField = 'text';
22703 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22704 if(!this.lazyRender){
22705 this.target = true;
22706 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22707 s.parentNode.removeChild(s); // remove it
22708 this.render(this.el.parentNode);
22710 s.parentNode.removeChild(s); // remove it
22715 this.store = Roo.factory(this.store, Roo.data);
22718 this.selectedIndex = -1;
22719 if(this.mode == 'local'){
22720 if(config.queryDelay === undefined){
22721 this.queryDelay = 10;
22723 if(config.minChars === undefined){
22729 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22731 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22734 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22735 * rendering into an Roo.Editor, defaults to false)
22738 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22739 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22742 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22745 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22746 * the dropdown list (defaults to undefined, with no header element)
22750 * @cfg {String/Roo.Template} tpl The template to use to render the output
22754 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22756 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22758 listWidth: undefined,
22760 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22761 * mode = 'remote' or 'text' if mode = 'local')
22763 displayField: undefined,
22765 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22766 * mode = 'remote' or 'value' if mode = 'local').
22767 * Note: use of a valueField requires the user make a selection
22768 * in order for a value to be mapped.
22770 valueField: undefined,
22772 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22773 * field's data value (defaults to the underlying DOM element's name)
22775 hiddenName: undefined,
22777 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22781 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22783 selectedClass: 'x-combo-selected',
22785 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22786 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22787 * which displays a downward arrow icon).
22789 triggerClass : 'x-form-arrow-trigger',
22791 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22795 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22796 * anchor positions (defaults to 'tl-bl')
22798 listAlign: 'tl-bl?',
22800 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22804 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22805 * query specified by the allQuery config option (defaults to 'query')
22807 triggerAction: 'query',
22809 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22810 * (defaults to 4, does not apply if editable = false)
22814 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22815 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22819 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22820 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22824 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22825 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22829 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22830 * when editable = true (defaults to false)
22832 selectOnFocus:false,
22834 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22836 queryParam: 'query',
22838 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22839 * when mode = 'remote' (defaults to 'Loading...')
22841 loadingText: 'Loading...',
22843 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22847 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22851 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22852 * traditional select (defaults to true)
22856 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22860 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22864 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22865 * listWidth has a higher value)
22869 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22870 * allow the user to set arbitrary text into the field (defaults to false)
22872 forceSelection:false,
22874 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22875 * if typeAhead = true (defaults to 250)
22877 typeAheadDelay : 250,
22879 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22880 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22882 valueNotFoundText : undefined,
22884 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22886 blockFocus : false,
22889 * @cfg {Boolean} disableClear Disable showing of clear button.
22891 disableClear : false,
22893 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22895 alwaysQuery : false,
22903 onRender : function(ct, position){
22904 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22905 if(this.hiddenName){
22906 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22908 this.hiddenField.value =
22909 this.hiddenValue !== undefined ? this.hiddenValue :
22910 this.value !== undefined ? this.value : '';
22912 // prevent input submission
22913 this.el.dom.removeAttribute('name');
22916 this.el.dom.setAttribute('autocomplete', 'off');
22919 var cls = 'x-combo-list';
22921 this.list = new Roo.Layer({
22922 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22925 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22926 this.list.setWidth(lw);
22927 this.list.swallowEvent('mousewheel');
22928 this.assetHeight = 0;
22931 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22932 this.assetHeight += this.header.getHeight();
22935 this.innerList = this.list.createChild({cls:cls+'-inner'});
22936 this.innerList.on('mouseover', this.onViewOver, this);
22937 this.innerList.on('mousemove', this.onViewMove, this);
22938 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22940 if(this.allowBlank && !this.pageSize && !this.disableClear){
22941 this.footer = this.list.createChild({cls:cls+'-ft'});
22942 this.pageTb = new Roo.Toolbar(this.footer);
22946 this.footer = this.list.createChild({cls:cls+'-ft'});
22947 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22948 {pageSize: this.pageSize});
22952 if (this.pageTb && this.allowBlank && !this.disableClear) {
22954 this.pageTb.add(new Roo.Toolbar.Fill(), {
22955 cls: 'x-btn-icon x-btn-clear',
22957 handler: function()
22960 _this.clearValue();
22961 _this.onSelect(false, -1);
22966 this.assetHeight += this.footer.getHeight();
22971 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22974 this.view = new Roo.View(this.innerList, this.tpl, {
22975 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22978 this.view.on('click', this.onViewClick, this);
22980 this.store.on('beforeload', this.onBeforeLoad, this);
22981 this.store.on('load', this.onLoad, this);
22982 this.store.on('loadexception', this.collapse, this);
22984 if(this.resizable){
22985 this.resizer = new Roo.Resizable(this.list, {
22986 pinned:true, handles:'se'
22988 this.resizer.on('resize', function(r, w, h){
22989 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22990 this.listWidth = w;
22991 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22992 this.restrictHeight();
22994 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22996 if(!this.editable){
22997 this.editable = true;
22998 this.setEditable(false);
23002 if (typeof(this.events.add.listeners) != 'undefined') {
23004 this.addicon = this.wrap.createChild(
23005 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
23007 this.addicon.on('click', function(e) {
23008 this.fireEvent('add', this);
23011 if (typeof(this.events.edit.listeners) != 'undefined') {
23013 this.editicon = this.wrap.createChild(
23014 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
23015 if (this.addicon) {
23016 this.editicon.setStyle('margin-left', '40px');
23018 this.editicon.on('click', function(e) {
23020 // we fire even if inothing is selected..
23021 this.fireEvent('edit', this, this.lastData );
23031 initEvents : function(){
23032 Roo.form.ComboBox.superclass.initEvents.call(this);
23034 this.keyNav = new Roo.KeyNav(this.el, {
23035 "up" : function(e){
23036 this.inKeyMode = true;
23040 "down" : function(e){
23041 if(!this.isExpanded()){
23042 this.onTriggerClick();
23044 this.inKeyMode = true;
23049 "enter" : function(e){
23050 this.onViewClick();
23054 "esc" : function(e){
23058 "tab" : function(e){
23059 this.onViewClick(false);
23065 doRelay : function(foo, bar, hname){
23066 if(hname == 'down' || this.scope.isExpanded()){
23067 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23074 this.queryDelay = Math.max(this.queryDelay || 10,
23075 this.mode == 'local' ? 10 : 250);
23076 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23077 if(this.typeAhead){
23078 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23080 if(this.editable !== false){
23081 this.el.on("keyup", this.onKeyUp, this);
23083 if(this.forceSelection){
23084 this.on('blur', this.doForce, this);
23088 onDestroy : function(){
23090 this.view.setStore(null);
23091 this.view.el.removeAllListeners();
23092 this.view.el.remove();
23093 this.view.purgeListeners();
23096 this.list.destroy();
23099 this.store.un('beforeload', this.onBeforeLoad, this);
23100 this.store.un('load', this.onLoad, this);
23101 this.store.un('loadexception', this.collapse, this);
23103 Roo.form.ComboBox.superclass.onDestroy.call(this);
23107 fireKey : function(e){
23108 if(e.isNavKeyPress() && !this.list.isVisible()){
23109 this.fireEvent("specialkey", this, e);
23114 onResize: function(w, h){
23115 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23117 if(typeof w != 'number'){
23118 // we do not handle it!?!?
23121 var tw = this.trigger.getWidth();
23122 tw += this.addicon ? this.addicon.getWidth() : 0;
23123 tw += this.editicon ? this.editicon.getWidth() : 0;
23125 this.el.setWidth( this.adjustWidth('input', x));
23127 this.trigger.setStyle('left', x+'px');
23129 if(this.list && this.listWidth === undefined){
23130 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23131 this.list.setWidth(lw);
23132 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23140 * Allow or prevent the user from directly editing the field text. If false is passed,
23141 * the user will only be able to select from the items defined in the dropdown list. This method
23142 * is the runtime equivalent of setting the 'editable' config option at config time.
23143 * @param {Boolean} value True to allow the user to directly edit the field text
23145 setEditable : function(value){
23146 if(value == this.editable){
23149 this.editable = value;
23151 this.el.dom.setAttribute('readOnly', true);
23152 this.el.on('mousedown', this.onTriggerClick, this);
23153 this.el.addClass('x-combo-noedit');
23155 this.el.dom.setAttribute('readOnly', false);
23156 this.el.un('mousedown', this.onTriggerClick, this);
23157 this.el.removeClass('x-combo-noedit');
23162 onBeforeLoad : function(){
23163 if(!this.hasFocus){
23166 this.innerList.update(this.loadingText ?
23167 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23168 this.restrictHeight();
23169 this.selectedIndex = -1;
23173 onLoad : function(){
23174 if(!this.hasFocus){
23177 if(this.store.getCount() > 0){
23179 this.restrictHeight();
23180 if(this.lastQuery == this.allQuery){
23182 this.el.dom.select();
23184 if(!this.selectByValue(this.value, true)){
23185 this.select(0, true);
23189 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23190 this.taTask.delay(this.typeAheadDelay);
23194 this.onEmptyResults();
23200 onTypeAhead : function(){
23201 if(this.store.getCount() > 0){
23202 var r = this.store.getAt(0);
23203 var newValue = r.data[this.displayField];
23204 var len = newValue.length;
23205 var selStart = this.getRawValue().length;
23206 if(selStart != len){
23207 this.setRawValue(newValue);
23208 this.selectText(selStart, newValue.length);
23214 onSelect : function(record, index){
23215 if(this.fireEvent('beforeselect', this, record, index) !== false){
23216 this.setFromData(index > -1 ? record.data : false);
23218 this.fireEvent('select', this, record, index);
23223 * Returns the currently selected field value or empty string if no value is set.
23224 * @return {String} value The selected value
23226 getValue : function(){
23227 if(this.valueField){
23228 return typeof this.value != 'undefined' ? this.value : '';
23230 return Roo.form.ComboBox.superclass.getValue.call(this);
23235 * Clears any text/value currently set in the field
23237 clearValue : function(){
23238 if(this.hiddenField){
23239 this.hiddenField.value = '';
23242 this.setRawValue('');
23243 this.lastSelectionText = '';
23244 this.applyEmptyText();
23248 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23249 * will be displayed in the field. If the value does not match the data value of an existing item,
23250 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23251 * Otherwise the field will be blank (although the value will still be set).
23252 * @param {String} value The value to match
23254 setValue : function(v){
23256 if(this.valueField){
23257 var r = this.findRecord(this.valueField, v);
23259 text = r.data[this.displayField];
23260 }else if(this.valueNotFoundText !== undefined){
23261 text = this.valueNotFoundText;
23264 this.lastSelectionText = text;
23265 if(this.hiddenField){
23266 this.hiddenField.value = v;
23268 Roo.form.ComboBox.superclass.setValue.call(this, text);
23272 * @property {Object} the last set data for the element
23277 * Sets the value of the field based on a object which is related to the record format for the store.
23278 * @param {Object} value the value to set as. or false on reset?
23280 setFromData : function(o){
23281 var dv = ''; // display value
23282 var vv = ''; // value value..
23284 if (this.displayField) {
23285 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23287 // this is an error condition!!!
23288 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23291 if(this.valueField){
23292 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23294 if(this.hiddenField){
23295 this.hiddenField.value = vv;
23297 this.lastSelectionText = dv;
23298 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23302 // no hidden field.. - we store the value in 'value', but still display
23303 // display field!!!!
23304 this.lastSelectionText = dv;
23305 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23311 reset : function(){
23312 // overridden so that last data is reset..
23313 this.setValue(this.originalValue);
23314 this.clearInvalid();
23315 this.lastData = false;
23318 findRecord : function(prop, value){
23320 if(this.store.getCount() > 0){
23321 this.store.each(function(r){
23322 if(r.data[prop] == value){
23332 onViewMove : function(e, t){
23333 this.inKeyMode = false;
23337 onViewOver : function(e, t){
23338 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23341 var item = this.view.findItemFromChild(t);
23343 var index = this.view.indexOf(item);
23344 this.select(index, false);
23349 onViewClick : function(doFocus){
23350 var index = this.view.getSelectedIndexes()[0];
23351 var r = this.store.getAt(index);
23353 this.onSelect(r, index);
23355 if(doFocus !== false && !this.blockFocus){
23361 restrictHeight : function(){
23362 this.innerList.dom.style.height = '';
23363 var inner = this.innerList.dom;
23364 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23365 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23366 this.list.beginUpdate();
23367 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23368 this.list.alignTo(this.el, this.listAlign);
23369 this.list.endUpdate();
23373 onEmptyResults : function(){
23378 * Returns true if the dropdown list is expanded, else false.
23380 isExpanded : function(){
23381 return this.list.isVisible();
23385 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23386 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23387 * @param {String} value The data value of the item to select
23388 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23389 * selected item if it is not currently in view (defaults to true)
23390 * @return {Boolean} True if the value matched an item in the list, else false
23392 selectByValue : function(v, scrollIntoView){
23393 if(v !== undefined && v !== null){
23394 var r = this.findRecord(this.valueField || this.displayField, v);
23396 this.select(this.store.indexOf(r), scrollIntoView);
23404 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23405 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23406 * @param {Number} index The zero-based index of the list item to select
23407 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23408 * selected item if it is not currently in view (defaults to true)
23410 select : function(index, scrollIntoView){
23411 this.selectedIndex = index;
23412 this.view.select(index);
23413 if(scrollIntoView !== false){
23414 var el = this.view.getNode(index);
23416 this.innerList.scrollChildIntoView(el, false);
23422 selectNext : function(){
23423 var ct = this.store.getCount();
23425 if(this.selectedIndex == -1){
23427 }else if(this.selectedIndex < ct-1){
23428 this.select(this.selectedIndex+1);
23434 selectPrev : function(){
23435 var ct = this.store.getCount();
23437 if(this.selectedIndex == -1){
23439 }else if(this.selectedIndex != 0){
23440 this.select(this.selectedIndex-1);
23446 onKeyUp : function(e){
23447 if(this.editable !== false && !e.isSpecialKey()){
23448 this.lastKey = e.getKey();
23449 this.dqTask.delay(this.queryDelay);
23454 validateBlur : function(){
23455 return !this.list || !this.list.isVisible();
23459 initQuery : function(){
23460 this.doQuery(this.getRawValue());
23464 doForce : function(){
23465 if(this.el.dom.value.length > 0){
23466 this.el.dom.value =
23467 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23468 this.applyEmptyText();
23473 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23474 * query allowing the query action to be canceled if needed.
23475 * @param {String} query The SQL query to execute
23476 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23477 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23478 * saved in the current store (defaults to false)
23480 doQuery : function(q, forceAll){
23481 if(q === undefined || q === null){
23486 forceAll: forceAll,
23490 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23494 forceAll = qe.forceAll;
23495 if(forceAll === true || (q.length >= this.minChars)){
23496 if(this.lastQuery != q || this.alwaysQuery){
23497 this.lastQuery = q;
23498 if(this.mode == 'local'){
23499 this.selectedIndex = -1;
23501 this.store.clearFilter();
23503 this.store.filter(this.displayField, q);
23507 this.store.baseParams[this.queryParam] = q;
23509 params: this.getParams(q)
23514 this.selectedIndex = -1;
23521 getParams : function(q){
23523 //p[this.queryParam] = q;
23526 p.limit = this.pageSize;
23532 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23534 collapse : function(){
23535 if(!this.isExpanded()){
23539 Roo.get(document).un('mousedown', this.collapseIf, this);
23540 Roo.get(document).un('mousewheel', this.collapseIf, this);
23541 if (!this.editable) {
23542 Roo.get(document).un('keydown', this.listKeyPress, this);
23544 this.fireEvent('collapse', this);
23548 collapseIf : function(e){
23549 if(!e.within(this.wrap) && !e.within(this.list)){
23555 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23557 expand : function(){
23558 if(this.isExpanded() || !this.hasFocus){
23561 this.list.alignTo(this.el, this.listAlign);
23563 Roo.get(document).on('mousedown', this.collapseIf, this);
23564 Roo.get(document).on('mousewheel', this.collapseIf, this);
23565 if (!this.editable) {
23566 Roo.get(document).on('keydown', this.listKeyPress, this);
23569 this.fireEvent('expand', this);
23573 // Implements the default empty TriggerField.onTriggerClick function
23574 onTriggerClick : function(){
23578 if(this.isExpanded()){
23580 if (!this.blockFocus) {
23585 this.hasFocus = true;
23586 if(this.triggerAction == 'all') {
23587 this.doQuery(this.allQuery, true);
23589 this.doQuery(this.getRawValue());
23591 if (!this.blockFocus) {
23596 listKeyPress : function(e)
23598 //Roo.log('listkeypress');
23599 // scroll to first matching element based on key pres..
23600 if (e.isSpecialKey()) {
23603 var k = String.fromCharCode(e.getKey()).toUpperCase();
23606 var csel = this.view.getSelectedNodes();
23607 var cselitem = false;
23609 var ix = this.view.indexOf(csel[0]);
23610 cselitem = this.store.getAt(ix);
23611 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23617 this.store.each(function(v) {
23619 // start at existing selection.
23620 if (cselitem.id == v.id) {
23626 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23627 match = this.store.indexOf(v);
23632 if (match === false) {
23633 return true; // no more action?
23636 this.view.select(match);
23637 var sn = Roo.get(this.view.getSelectedNodes()[0])
23638 sn.scrollIntoView(sn.dom.parentNode, false);
23642 * @cfg {Boolean} grow
23646 * @cfg {Number} growMin
23650 * @cfg {Number} growMax
23659 * Ext JS Library 1.1.1
23660 * Copyright(c) 2006-2007, Ext JS, LLC.
23662 * Originally Released Under LGPL - original licence link has changed is not relivant.
23665 * <script type="text/javascript">
23668 * @class Roo.form.Checkbox
23669 * @extends Roo.form.Field
23670 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23672 * Creates a new Checkbox
23673 * @param {Object} config Configuration options
23675 Roo.form.Checkbox = function(config){
23676 Roo.form.Checkbox.superclass.constructor.call(this, config);
23680 * Fires when the checkbox is checked or unchecked.
23681 * @param {Roo.form.Checkbox} this This checkbox
23682 * @param {Boolean} checked The new checked value
23688 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23690 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23692 focusClass : undefined,
23694 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23696 fieldClass: "x-form-field",
23698 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23702 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23703 * {tag: "input", type: "checkbox", autocomplete: "off"})
23705 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23707 * @cfg {String} boxLabel The text that appears beside the checkbox
23711 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23715 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23717 valueOff: '0', // value when not checked..
23719 actionMode : 'viewEl',
23722 itemCls : 'x-menu-check-item x-form-item',
23723 groupClass : 'x-menu-group-item',
23724 inputType : 'hidden',
23727 inSetChecked: false, // check that we are not calling self...
23729 inputElement: false, // real input element?
23730 basedOn: false, // ????
23732 isFormField: true, // not sure where this is needed!!!!
23734 onResize : function(){
23735 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23736 if(!this.boxLabel){
23737 this.el.alignTo(this.wrap, 'c-c');
23741 initEvents : function(){
23742 Roo.form.Checkbox.superclass.initEvents.call(this);
23743 this.el.on("click", this.onClick, this);
23744 this.el.on("change", this.onClick, this);
23748 getResizeEl : function(){
23752 getPositionEl : function(){
23757 onRender : function(ct, position){
23758 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23760 if(this.inputValue !== undefined){
23761 this.el.dom.value = this.inputValue;
23764 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23765 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23766 var viewEl = this.wrap.createChild({
23767 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23768 this.viewEl = viewEl;
23769 this.wrap.on('click', this.onClick, this);
23771 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23772 this.el.on('propertychange', this.setFromHidden, this); //ie
23777 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23778 // viewEl.on('click', this.onClick, this);
23780 //if(this.checked){
23781 this.setChecked(this.checked);
23783 //this.checked = this.el.dom;
23789 initValue : Roo.emptyFn,
23792 * Returns the checked state of the checkbox.
23793 * @return {Boolean} True if checked, else false
23795 getValue : function(){
23797 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23799 return this.valueOff;
23804 onClick : function(){
23805 this.setChecked(!this.checked);
23807 //if(this.el.dom.checked != this.checked){
23808 // this.setValue(this.el.dom.checked);
23813 * Sets the checked state of the checkbox.
23814 * On is always based on a string comparison between inputValue and the param.
23815 * @param {Boolean/String} value - the value to set
23816 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23818 setValue : function(v,suppressEvent){
23821 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23822 //if(this.el && this.el.dom){
23823 // this.el.dom.checked = this.checked;
23824 // this.el.dom.defaultChecked = this.checked;
23826 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23827 //this.fireEvent("check", this, this.checked);
23830 setChecked : function(state,suppressEvent)
23832 if (this.inSetChecked) {
23833 this.checked = state;
23839 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23841 this.checked = state;
23842 if(suppressEvent !== true){
23843 this.fireEvent('check', this, state);
23845 this.inSetChecked = true;
23846 this.el.dom.value = state ? this.inputValue : this.valueOff;
23847 this.inSetChecked = false;
23850 // handle setting of hidden value by some other method!!?!?
23851 setFromHidden: function()
23856 //console.log("SET FROM HIDDEN");
23857 //alert('setFrom hidden');
23858 this.setValue(this.el.dom.value);
23861 onDestroy : function()
23864 Roo.get(this.viewEl).remove();
23867 Roo.form.Checkbox.superclass.onDestroy.call(this);
23872 * Ext JS Library 1.1.1
23873 * Copyright(c) 2006-2007, Ext JS, LLC.
23875 * Originally Released Under LGPL - original licence link has changed is not relivant.
23878 * <script type="text/javascript">
23882 * @class Roo.form.Radio
23883 * @extends Roo.form.Checkbox
23884 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23885 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23887 * Creates a new Radio
23888 * @param {Object} config Configuration options
23890 Roo.form.Radio = function(){
23891 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23893 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23894 inputType: 'radio',
23897 * If this radio is part of a group, it will return the selected value
23900 getGroupValue : function(){
23901 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23903 });//<script type="text/javascript">
23906 * Ext JS Library 1.1.1
23907 * Copyright(c) 2006-2007, Ext JS, LLC.
23908 * licensing@extjs.com
23910 * http://www.extjs.com/license
23916 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23917 * - IE ? - no idea how much works there.
23925 * @class Ext.form.HtmlEditor
23926 * @extends Ext.form.Field
23927 * Provides a lightweight HTML Editor component.
23928 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23930 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23931 * supported by this editor.</b><br/><br/>
23932 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23933 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23935 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23937 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23941 * @cfg {String} createLinkText The default text for the create link prompt
23943 createLinkText : 'Please enter the URL for the link:',
23945 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23947 defaultLinkValue : 'http:/'+'/',
23953 // private properties
23954 validationEvent : false,
23956 initialized : false,
23958 sourceEditMode : false,
23959 onFocus : Roo.emptyFn,
23961 hideMode:'offsets',
23962 defaultAutoCreate : {
23964 style:"width:500px;height:300px;",
23965 autocomplete: "off"
23969 initComponent : function(){
23972 * @event initialize
23973 * Fires when the editor is fully initialized (including the iframe)
23974 * @param {HtmlEditor} this
23979 * Fires when the editor is first receives the focus. Any insertion must wait
23980 * until after this event.
23981 * @param {HtmlEditor} this
23985 * @event beforesync
23986 * Fires before the textarea is updated with content from the editor iframe. Return false
23987 * to cancel the sync.
23988 * @param {HtmlEditor} this
23989 * @param {String} html
23993 * @event beforepush
23994 * Fires before the iframe editor is updated with content from the textarea. Return false
23995 * to cancel the push.
23996 * @param {HtmlEditor} this
23997 * @param {String} html
24002 * Fires when the textarea is updated with content from the editor iframe.
24003 * @param {HtmlEditor} this
24004 * @param {String} html
24009 * Fires when the iframe editor is updated with content from the textarea.
24010 * @param {HtmlEditor} this
24011 * @param {String} html
24015 * @event editmodechange
24016 * Fires when the editor switches edit modes
24017 * @param {HtmlEditor} this
24018 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
24020 editmodechange: true,
24022 * @event editorevent
24023 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
24024 * @param {HtmlEditor} this
24031 * Protected method that will not generally be called directly. It
24032 * is called when the editor creates its toolbar. Override this method if you need to
24033 * add custom toolbar buttons.
24034 * @param {HtmlEditor} editor
24036 createToolbar : function(editor){
24037 if (!editor.toolbars || !editor.toolbars.length) {
24038 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
24041 for (var i =0 ; i < editor.toolbars.length;i++) {
24042 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
24043 editor.toolbars[i].init(editor);
24050 * Protected method that will not generally be called directly. It
24051 * is called when the editor initializes the iframe with HTML contents. Override this method if you
24052 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
24054 getDocMarkup : function(){
24055 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
24059 onRender : function(ct, position){
24060 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24061 this.el.dom.style.border = '0 none';
24062 this.el.dom.setAttribute('tabIndex', -1);
24063 this.el.addClass('x-hidden');
24064 if(Roo.isIE){ // fix IE 1px bogus margin
24065 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24067 this.wrap = this.el.wrap({
24068 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24071 this.frameId = Roo.id();
24072 this.createToolbar(this);
24079 var iframe = this.wrap.createChild({
24082 name: this.frameId,
24083 frameBorder : 'no',
24084 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24087 // console.log(iframe);
24088 //this.wrap.dom.appendChild(iframe);
24090 this.iframe = iframe.dom;
24092 this.assignDocWin();
24094 this.doc.designMode = 'on';
24097 this.doc.write(this.getDocMarkup());
24101 var task = { // must defer to wait for browser to be ready
24103 //console.log("run task?" + this.doc.readyState);
24104 this.assignDocWin();
24105 if(this.doc.body || this.doc.readyState == 'complete'){
24107 this.doc.designMode="on";
24111 Roo.TaskMgr.stop(task);
24112 this.initEditor.defer(10, this);
24119 Roo.TaskMgr.start(task);
24122 this.setSize(this.el.getSize());
24127 onResize : function(w, h){
24128 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24129 if(this.el && this.iframe){
24130 if(typeof w == 'number'){
24131 var aw = w - this.wrap.getFrameWidth('lr');
24132 this.el.setWidth(this.adjustWidth('textarea', aw));
24133 this.iframe.style.width = aw + 'px';
24135 if(typeof h == 'number'){
24137 for (var i =0; i < this.toolbars.length;i++) {
24138 // fixme - ask toolbars for heights?
24139 tbh += this.toolbars[i].tb.el.getHeight();
24145 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24146 this.el.setHeight(this.adjustWidth('textarea', ah));
24147 this.iframe.style.height = ah + 'px';
24149 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24156 * Toggles the editor between standard and source edit mode.
24157 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24159 toggleSourceEdit : function(sourceEditMode){
24161 this.sourceEditMode = sourceEditMode === true;
24163 if(this.sourceEditMode){
24166 this.iframe.className = 'x-hidden';
24167 this.el.removeClass('x-hidden');
24168 this.el.dom.removeAttribute('tabIndex');
24173 this.iframe.className = '';
24174 this.el.addClass('x-hidden');
24175 this.el.dom.setAttribute('tabIndex', -1);
24178 this.setSize(this.wrap.getSize());
24179 this.fireEvent('editmodechange', this, this.sourceEditMode);
24182 // private used internally
24183 createLink : function(){
24184 var url = prompt(this.createLinkText, this.defaultLinkValue);
24185 if(url && url != 'http:/'+'/'){
24186 this.relayCmd('createlink', url);
24190 // private (for BoxComponent)
24191 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24193 // private (for BoxComponent)
24194 getResizeEl : function(){
24198 // private (for BoxComponent)
24199 getPositionEl : function(){
24204 initEvents : function(){
24205 this.originalValue = this.getValue();
24209 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24212 markInvalid : Roo.emptyFn,
24214 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24217 clearInvalid : Roo.emptyFn,
24219 setValue : function(v){
24220 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24225 * Protected method that will not generally be called directly. If you need/want
24226 * custom HTML cleanup, this is the method you should override.
24227 * @param {String} html The HTML to be cleaned
24228 * return {String} The cleaned HTML
24230 cleanHtml : function(html){
24231 html = String(html);
24232 if(html.length > 5){
24233 if(Roo.isSafari){ // strip safari nonsense
24234 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24237 if(html == ' '){
24244 * Protected method that will not generally be called directly. Syncs the contents
24245 * of the editor iframe with the textarea.
24247 syncValue : function(){
24248 if(this.initialized){
24249 var bd = (this.doc.body || this.doc.documentElement);
24250 this.cleanUpPaste();
24251 var html = bd.innerHTML;
24253 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24254 var m = bs.match(/text-align:(.*?);/i);
24256 html = '<div style="'+m[0]+'">' + html + '</div>';
24259 html = this.cleanHtml(html);
24260 if(this.fireEvent('beforesync', this, html) !== false){
24261 this.el.dom.value = html;
24262 this.fireEvent('sync', this, html);
24268 * Protected method that will not generally be called directly. Pushes the value of the textarea
24269 * into the iframe editor.
24271 pushValue : function(){
24272 if(this.initialized){
24273 var v = this.el.dom.value;
24278 if(this.fireEvent('beforepush', this, v) !== false){
24279 var d = (this.doc.body || this.doc.documentElement);
24281 this.cleanUpPaste();
24282 this.el.dom.value = d.innerHTML;
24283 this.fireEvent('push', this, v);
24289 deferFocus : function(){
24290 this.focus.defer(10, this);
24294 focus : function(){
24295 if(this.win && !this.sourceEditMode){
24302 assignDocWin: function()
24304 var iframe = this.iframe;
24307 this.doc = iframe.contentWindow.document;
24308 this.win = iframe.contentWindow;
24310 if (!Roo.get(this.frameId)) {
24313 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24314 this.win = Roo.get(this.frameId).dom.contentWindow;
24319 initEditor : function(){
24320 //console.log("INIT EDITOR");
24321 this.assignDocWin();
24325 this.doc.designMode="on";
24327 this.doc.write(this.getDocMarkup());
24330 var dbody = (this.doc.body || this.doc.documentElement);
24331 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24332 // this copies styles from the containing element into thsi one..
24333 // not sure why we need all of this..
24334 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24335 ss['background-attachment'] = 'fixed'; // w3c
24336 dbody.bgProperties = 'fixed'; // ie
24337 Roo.DomHelper.applyStyles(dbody, ss);
24338 Roo.EventManager.on(this.doc, {
24339 'mousedown': this.onEditorEvent,
24340 'dblclick': this.onEditorEvent,
24341 'click': this.onEditorEvent,
24342 'keyup': this.onEditorEvent,
24347 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24349 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24350 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24352 this.initialized = true;
24354 this.fireEvent('initialize', this);
24359 onDestroy : function(){
24365 for (var i =0; i < this.toolbars.length;i++) {
24366 // fixme - ask toolbars for heights?
24367 this.toolbars[i].onDestroy();
24370 this.wrap.dom.innerHTML = '';
24371 this.wrap.remove();
24376 onFirstFocus : function(){
24378 this.assignDocWin();
24381 this.activated = true;
24382 for (var i =0; i < this.toolbars.length;i++) {
24383 this.toolbars[i].onFirstFocus();
24386 if(Roo.isGecko){ // prevent silly gecko errors
24388 var s = this.win.getSelection();
24389 if(!s.focusNode || s.focusNode.nodeType != 3){
24390 var r = s.getRangeAt(0);
24391 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24396 this.execCmd('useCSS', true);
24397 this.execCmd('styleWithCSS', false);
24400 this.fireEvent('activate', this);
24404 adjustFont: function(btn){
24405 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24406 //if(Roo.isSafari){ // safari
24409 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24410 if(Roo.isSafari){ // safari
24411 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24412 v = (v < 10) ? 10 : v;
24413 v = (v > 48) ? 48 : v;
24414 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24419 v = Math.max(1, v+adjust);
24421 this.execCmd('FontSize', v );
24424 onEditorEvent : function(e){
24425 this.fireEvent('editorevent', this, e);
24426 // this.updateToolbar();
24430 insertTag : function(tg)
24432 // could be a bit smarter... -> wrap the current selected tRoo..
24434 this.execCmd("formatblock", tg);
24438 insertText : function(txt)
24442 range = this.createRange();
24443 range.deleteContents();
24444 //alert(Sender.getAttribute('label'));
24446 range.insertNode(this.doc.createTextNode(txt));
24450 relayBtnCmd : function(btn){
24451 this.relayCmd(btn.cmd);
24455 * Executes a Midas editor command on the editor document and performs necessary focus and
24456 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24457 * @param {String} cmd The Midas command
24458 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24460 relayCmd : function(cmd, value){
24462 this.execCmd(cmd, value);
24463 this.fireEvent('editorevent', this);
24464 //this.updateToolbar();
24469 * Executes a Midas editor command directly on the editor document.
24470 * For visual commands, you should use {@link #relayCmd} instead.
24471 * <b>This should only be called after the editor is initialized.</b>
24472 * @param {String} cmd The Midas command
24473 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24475 execCmd : function(cmd, value){
24476 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24482 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24484 * @param {String} text
24486 insertAtCursor : function(text){
24487 if(!this.activated){
24492 var r = this.doc.selection.createRange();
24499 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24501 this.execCmd('InsertHTML', text);
24506 mozKeyPress : function(e){
24508 var c = e.getCharCode(), cmd;
24511 c = String.fromCharCode(c).toLowerCase();
24522 this.cleanUpPaste.defer(100, this);
24530 e.preventDefault();
24538 fixKeys : function(){ // load time branching for fastest keydown performance
24540 return function(e){
24541 var k = e.getKey(), r;
24544 r = this.doc.selection.createRange();
24547 r.pasteHTML('    ');
24554 r = this.doc.selection.createRange();
24556 var target = r.parentElement();
24557 if(!target || target.tagName.toLowerCase() != 'li'){
24559 r.pasteHTML('<br />');
24565 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24566 this.cleanUpPaste.defer(100, this);
24572 }else if(Roo.isOpera){
24573 return function(e){
24574 var k = e.getKey();
24578 this.execCmd('InsertHTML','    ');
24581 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24582 this.cleanUpPaste.defer(100, this);
24587 }else if(Roo.isSafari){
24588 return function(e){
24589 var k = e.getKey();
24593 this.execCmd('InsertText','\t');
24597 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24598 this.cleanUpPaste.defer(100, this);
24606 getAllAncestors: function()
24608 var p = this.getSelectedNode();
24611 a.push(p); // push blank onto stack..
24612 p = this.getParentElement();
24616 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24620 a.push(this.doc.body);
24624 lastSelNode : false,
24627 getSelection : function()
24629 this.assignDocWin();
24630 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24633 getSelectedNode: function()
24635 // this may only work on Gecko!!!
24637 // should we cache this!!!!
24642 var range = this.createRange(this.getSelection());
24645 var parent = range.parentElement();
24647 var testRange = range.duplicate();
24648 testRange.moveToElementText(parent);
24649 if (testRange.inRange(range)) {
24652 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24655 parent = parent.parentElement;
24661 var ar = range.endContainer.childNodes;
24663 ar = range.commonAncestorContainer.childNodes;
24664 //alert(ar.length);
24667 var other_nodes = [];
24668 var has_other_nodes = false;
24669 for (var i=0;i<ar.length;i++) {
24670 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24673 // fullly contained node.
24675 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24680 // probably selected..
24681 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24682 other_nodes.push(ar[i]);
24685 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24690 has_other_nodes = true;
24692 if (!nodes.length && other_nodes.length) {
24693 nodes= other_nodes;
24695 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24701 createRange: function(sel)
24703 // this has strange effects when using with
24704 // top toolbar - not sure if it's a great idea.
24705 //this.editor.contentWindow.focus();
24706 if (typeof sel != "undefined") {
24708 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24710 return this.doc.createRange();
24713 return this.doc.createRange();
24716 getParentElement: function()
24719 this.assignDocWin();
24720 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24722 var range = this.createRange(sel);
24725 var p = range.commonAncestorContainer;
24726 while (p.nodeType == 3) { // text node
24738 // BC Hacks - cause I cant work out what i was trying to do..
24739 rangeIntersectsNode : function(range, node)
24741 var nodeRange = node.ownerDocument.createRange();
24743 nodeRange.selectNode(node);
24746 nodeRange.selectNodeContents(node);
24749 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24750 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24752 rangeCompareNode : function(range, node) {
24753 var nodeRange = node.ownerDocument.createRange();
24755 nodeRange.selectNode(node);
24757 nodeRange.selectNodeContents(node);
24759 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24760 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24762 if (nodeIsBefore && !nodeIsAfter)
24764 if (!nodeIsBefore && nodeIsAfter)
24766 if (nodeIsBefore && nodeIsAfter)
24772 // private? - in a new class?
24773 cleanUpPaste : function()
24775 // cleans up the whole document..
24776 // console.log('cleanuppaste');
24777 this.cleanUpChildren(this.doc.body);
24781 cleanUpChildren : function (n)
24783 if (!n.childNodes.length) {
24786 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24787 this.cleanUpChild(n.childNodes[i]);
24794 cleanUpChild : function (node)
24796 //console.log(node);
24797 if (node.nodeName == "#text") {
24798 // clean up silly Windows -- stuff?
24801 if (node.nodeName == "#comment") {
24802 node.parentNode.removeChild(node);
24803 // clean up silly Windows -- stuff?
24807 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24809 node.parentNode.removeChild(node);
24813 if (!node.attributes || !node.attributes.length) {
24814 this.cleanUpChildren(node);
24818 function cleanAttr(n,v)
24821 if (v.match(/^\./) || v.match(/^\//)) {
24824 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24827 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24828 node.removeAttribute(n);
24832 function cleanStyle(n,v)
24834 if (v.match(/expression/)) { //XSS?? should we even bother..
24835 node.removeAttribute(n);
24840 var parts = v.split(/;/);
24841 Roo.each(parts, function(p) {
24842 p = p.replace(/\s+/g,'');
24846 var l = p.split(':').shift().replace(/\s+/g,'');
24848 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24849 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24850 node.removeAttribute(n);
24859 for (var i = node.attributes.length-1; i > -1 ; i--) {
24860 var a = node.attributes[i];
24862 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24863 node.removeAttribute(a.name);
24866 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24867 cleanAttr(a.name,a.value); // fixme..
24870 if (a.name == 'style') {
24871 cleanStyle(a.name,a.value);
24873 /// clean up MS crap..
24874 if (a.name == 'class') {
24875 if (a.value.match(/^Mso/)) {
24876 node.className = '';
24886 this.cleanUpChildren(node);
24892 // hide stuff that is not compatible
24906 * @event specialkey
24910 * @cfg {String} fieldClass @hide
24913 * @cfg {String} focusClass @hide
24916 * @cfg {String} autoCreate @hide
24919 * @cfg {String} inputType @hide
24922 * @cfg {String} invalidClass @hide
24925 * @cfg {String} invalidText @hide
24928 * @cfg {String} msgFx @hide
24931 * @cfg {String} validateOnBlur @hide
24935 Roo.form.HtmlEditor.white = [
24936 'area', 'br', 'img', 'input', 'hr', 'wbr',
24938 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24939 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24940 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24941 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24942 'table', 'ul', 'xmp',
24944 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24947 'dir', 'menu', 'ol', 'ul', 'dl',
24953 Roo.form.HtmlEditor.black = [
24954 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24956 'base', 'basefont', 'bgsound', 'blink', 'body',
24957 'frame', 'frameset', 'head', 'html', 'ilayer',
24958 'iframe', 'layer', 'link', 'meta', 'object',
24959 'script', 'style' ,'title', 'xml' // clean later..
24961 Roo.form.HtmlEditor.clean = [
24962 'script', 'style', 'title', 'xml'
24967 Roo.form.HtmlEditor.ablack = [
24971 Roo.form.HtmlEditor.aclean = [
24972 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24976 Roo.form.HtmlEditor.pwhite= [
24977 'http', 'https', 'mailto'
24980 Roo.form.HtmlEditor.cwhite= [
24985 // <script type="text/javascript">
24988 * Ext JS Library 1.1.1
24989 * Copyright(c) 2006-2007, Ext JS, LLC.
24995 * @class Roo.form.HtmlEditorToolbar1
25000 new Roo.form.HtmlEditor({
25003 new Roo.form.HtmlEditorToolbar1({
25004 disable : { fonts: 1 , format: 1, ..., ... , ...],
25010 * @cfg {Object} disable List of elements to disable..
25011 * @cfg {Array} btns List of additional buttons.
25015 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
25018 Roo.form.HtmlEditor.ToolbarStandard = function(config)
25021 Roo.apply(this, config);
25022 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25023 // dont call parent... till later.
25026 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
25034 * @cfg {Object} disable List of toolbar elements to disable
25039 * @cfg {Array} fontFamilies An array of available font families
25057 // "á" , ?? a acute?
25062 "°" // , // degrees
25064 // "é" , // e ecute
25065 // "ú" , // u ecute?
25068 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25069 "input:submit", "input:button", "select", "textarea", "label" ],
25072 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25074 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25077 * @cfg {String} defaultFont default font to use.
25079 defaultFont: 'tahoma',
25081 fontSelect : false,
25084 formatCombo : false,
25086 init : function(editor)
25088 this.editor = editor;
25091 var fid = editor.frameId;
25093 function btn(id, toggle, handler){
25094 var xid = fid + '-'+ id ;
25098 cls : 'x-btn-icon x-edit-'+id,
25099 enableToggle:toggle !== false,
25100 scope: editor, // was editor...
25101 handler:handler||editor.relayBtnCmd,
25102 clickEvent:'mousedown',
25103 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25110 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25112 // stop form submits
25113 tb.el.on('click', function(e){
25114 e.preventDefault(); // what does this do?
25117 if(!this.disable.font && !Roo.isSafari){
25118 /* why no safari for fonts
25119 editor.fontSelect = tb.el.createChild({
25122 cls:'x-font-select',
25123 html: editor.createFontOptions()
25125 editor.fontSelect.on('change', function(){
25126 var font = editor.fontSelect.dom.value;
25127 editor.relayCmd('fontname', font);
25128 editor.deferFocus();
25131 editor.fontSelect.dom,
25136 if(!this.disable.formats){
25137 this.formatCombo = new Roo.form.ComboBox({
25138 store: new Roo.data.SimpleStore({
25141 data : this.formats // from states.js
25144 //autoCreate : {tag: "div", size: "20"},
25145 displayField:'tag',
25149 triggerAction: 'all',
25150 emptyText:'Add tag',
25151 selectOnFocus:true,
25154 'select': function(c, r, i) {
25155 editor.insertTag(r.get('tag'));
25161 tb.addField(this.formatCombo);
25165 if(!this.disable.format){
25172 if(!this.disable.fontSize){
25177 btn('increasefontsize', false, editor.adjustFont),
25178 btn('decreasefontsize', false, editor.adjustFont)
25183 if(this.disable.colors){
25186 id:editor.frameId +'-forecolor',
25187 cls:'x-btn-icon x-edit-forecolor',
25188 clickEvent:'mousedown',
25189 tooltip: this.buttonTips['forecolor'] || undefined,
25191 menu : new Roo.menu.ColorMenu({
25192 allowReselect: true,
25193 focus: Roo.emptyFn,
25196 selectHandler: function(cp, color){
25197 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25198 editor.deferFocus();
25201 clickEvent:'mousedown'
25204 id:editor.frameId +'backcolor',
25205 cls:'x-btn-icon x-edit-backcolor',
25206 clickEvent:'mousedown',
25207 tooltip: this.buttonTips['backcolor'] || undefined,
25209 menu : new Roo.menu.ColorMenu({
25210 focus: Roo.emptyFn,
25213 allowReselect: true,
25214 selectHandler: function(cp, color){
25216 editor.execCmd('useCSS', false);
25217 editor.execCmd('hilitecolor', color);
25218 editor.execCmd('useCSS', true);
25219 editor.deferFocus();
25221 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25222 Roo.isSafari || Roo.isIE ? '#'+color : color);
25223 editor.deferFocus();
25227 clickEvent:'mousedown'
25232 // now add all the items...
25235 if(!this.disable.alignments){
25238 btn('justifyleft'),
25239 btn('justifycenter'),
25240 btn('justifyright')
25244 //if(!Roo.isSafari){
25245 if(!this.disable.links){
25248 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25252 if(!this.disable.lists){
25255 btn('insertorderedlist'),
25256 btn('insertunorderedlist')
25259 if(!this.disable.sourceEdit){
25262 btn('sourceedit', true, function(btn){
25263 this.toggleSourceEdit(btn.pressed);
25270 // special menu.. - needs to be tidied up..
25271 if (!this.disable.special) {
25274 cls: 'x-edit-none',
25279 for (var i =0; i < this.specialChars.length; i++) {
25280 smenu.menu.items.push({
25282 html: this.specialChars[i],
25283 handler: function(a,b) {
25284 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25297 for(var i =0; i< this.btns.length;i++) {
25298 var b = this.btns[i];
25299 b.cls = 'x-edit-none';
25308 // disable everything...
25310 this.tb.items.each(function(item){
25311 if(item.id != editor.frameId+ '-sourceedit'){
25315 this.rendered = true;
25317 // the all the btns;
25318 editor.on('editorevent', this.updateToolbar, this);
25319 // other toolbars need to implement this..
25320 //editor.on('editmodechange', this.updateToolbar, this);
25326 * Protected method that will not generally be called directly. It triggers
25327 * a toolbar update by reading the markup state of the current selection in the editor.
25329 updateToolbar: function(){
25331 if(!this.editor.activated){
25332 this.editor.onFirstFocus();
25336 var btns = this.tb.items.map,
25337 doc = this.editor.doc,
25338 frameId = this.editor.frameId;
25340 if(!this.disable.font && !Roo.isSafari){
25342 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25343 if(name != this.fontSelect.dom.value){
25344 this.fontSelect.dom.value = name;
25348 if(!this.disable.format){
25349 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25350 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25351 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25353 if(!this.disable.alignments){
25354 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25355 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25356 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25358 if(!Roo.isSafari && !this.disable.lists){
25359 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25360 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25363 var ans = this.editor.getAllAncestors();
25364 if (this.formatCombo) {
25367 var store = this.formatCombo.store;
25368 this.formatCombo.setValue("");
25369 for (var i =0; i < ans.length;i++) {
25370 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25372 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25380 // hides menus... - so this cant be on a menu...
25381 Roo.menu.MenuMgr.hideAll();
25383 //this.editorsyncValue();
25387 createFontOptions : function(){
25388 var buf = [], fs = this.fontFamilies, ff, lc;
25389 for(var i = 0, len = fs.length; i< len; i++){
25391 lc = ff.toLowerCase();
25393 '<option value="',lc,'" style="font-family:',ff,';"',
25394 (this.defaultFont == lc ? ' selected="true">' : '>'),
25399 return buf.join('');
25402 toggleSourceEdit : function(sourceEditMode){
25403 if(sourceEditMode === undefined){
25404 sourceEditMode = !this.sourceEditMode;
25406 this.sourceEditMode = sourceEditMode === true;
25407 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25408 // just toggle the button?
25409 if(btn.pressed !== this.editor.sourceEditMode){
25410 btn.toggle(this.editor.sourceEditMode);
25414 if(this.sourceEditMode){
25415 this.tb.items.each(function(item){
25416 if(item.cmd != 'sourceedit'){
25422 if(this.initialized){
25423 this.tb.items.each(function(item){
25429 // tell the editor that it's been pressed..
25430 this.editor.toggleSourceEdit(sourceEditMode);
25434 * Object collection of toolbar tooltips for the buttons in the editor. The key
25435 * is the command id associated with that button and the value is a valid QuickTips object.
25440 title: 'Bold (Ctrl+B)',
25441 text: 'Make the selected text bold.',
25442 cls: 'x-html-editor-tip'
25445 title: 'Italic (Ctrl+I)',
25446 text: 'Make the selected text italic.',
25447 cls: 'x-html-editor-tip'
25455 title: 'Bold (Ctrl+B)',
25456 text: 'Make the selected text bold.',
25457 cls: 'x-html-editor-tip'
25460 title: 'Italic (Ctrl+I)',
25461 text: 'Make the selected text italic.',
25462 cls: 'x-html-editor-tip'
25465 title: 'Underline (Ctrl+U)',
25466 text: 'Underline the selected text.',
25467 cls: 'x-html-editor-tip'
25469 increasefontsize : {
25470 title: 'Grow Text',
25471 text: 'Increase the font size.',
25472 cls: 'x-html-editor-tip'
25474 decreasefontsize : {
25475 title: 'Shrink Text',
25476 text: 'Decrease the font size.',
25477 cls: 'x-html-editor-tip'
25480 title: 'Text Highlight Color',
25481 text: 'Change the background color of the selected text.',
25482 cls: 'x-html-editor-tip'
25485 title: 'Font Color',
25486 text: 'Change the color of the selected text.',
25487 cls: 'x-html-editor-tip'
25490 title: 'Align Text Left',
25491 text: 'Align text to the left.',
25492 cls: 'x-html-editor-tip'
25495 title: 'Center Text',
25496 text: 'Center text in the editor.',
25497 cls: 'x-html-editor-tip'
25500 title: 'Align Text Right',
25501 text: 'Align text to the right.',
25502 cls: 'x-html-editor-tip'
25504 insertunorderedlist : {
25505 title: 'Bullet List',
25506 text: 'Start a bulleted list.',
25507 cls: 'x-html-editor-tip'
25509 insertorderedlist : {
25510 title: 'Numbered List',
25511 text: 'Start a numbered list.',
25512 cls: 'x-html-editor-tip'
25515 title: 'Hyperlink',
25516 text: 'Make the selected text a hyperlink.',
25517 cls: 'x-html-editor-tip'
25520 title: 'Source Edit',
25521 text: 'Switch to source editing mode.',
25522 cls: 'x-html-editor-tip'
25526 onDestroy : function(){
25529 this.tb.items.each(function(item){
25531 item.menu.removeAll();
25533 item.menu.el.destroy();
25541 onFirstFocus: function() {
25542 this.tb.items.each(function(item){
25551 // <script type="text/javascript">
25554 * Ext JS Library 1.1.1
25555 * Copyright(c) 2006-2007, Ext JS, LLC.
25562 * @class Roo.form.HtmlEditor.ToolbarContext
25567 new Roo.form.HtmlEditor({
25570 new Roo.form.HtmlEditor.ToolbarStandard(),
25571 new Roo.form.HtmlEditor.ToolbarContext()
25576 * @config : {Object} disable List of elements to disable.. (not done yet.)
25581 Roo.form.HtmlEditor.ToolbarContext = function(config)
25584 Roo.apply(this, config);
25585 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25586 // dont call parent... till later.
25588 Roo.form.HtmlEditor.ToolbarContext.types = {
25600 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25662 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25667 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25731 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25739 * @cfg {Object} disable List of toolbar elements to disable
25748 init : function(editor)
25750 this.editor = editor;
25753 var fid = editor.frameId;
25755 function btn(id, toggle, handler){
25756 var xid = fid + '-'+ id ;
25760 cls : 'x-btn-icon x-edit-'+id,
25761 enableToggle:toggle !== false,
25762 scope: editor, // was editor...
25763 handler:handler||editor.relayBtnCmd,
25764 clickEvent:'mousedown',
25765 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25769 // create a new element.
25770 var wdiv = editor.wrap.createChild({
25772 }, editor.wrap.dom.firstChild.nextSibling, true);
25774 // can we do this more than once??
25776 // stop form submits
25779 // disable everything...
25780 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25781 this.toolbars = {};
25783 for (var i in ty) {
25785 this.toolbars[i] = this.buildToolbar(ty[i],i);
25787 this.tb = this.toolbars.BODY;
25791 this.rendered = true;
25793 // the all the btns;
25794 editor.on('editorevent', this.updateToolbar, this);
25795 // other toolbars need to implement this..
25796 //editor.on('editmodechange', this.updateToolbar, this);
25802 * Protected method that will not generally be called directly. It triggers
25803 * a toolbar update by reading the markup state of the current selection in the editor.
25805 updateToolbar: function(){
25807 if(!this.editor.activated){
25808 this.editor.onFirstFocus();
25813 var ans = this.editor.getAllAncestors();
25816 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25817 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25818 sel = sel ? sel : this.editor.doc.body;
25819 sel = sel.tagName.length ? sel : this.editor.doc.body;
25820 var tn = sel.tagName.toUpperCase();
25821 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25822 tn = sel.tagName.toUpperCase();
25823 if (this.tb.name == tn) {
25824 return; // no change
25827 ///console.log("show: " + tn);
25828 this.tb = this.toolbars[tn];
25830 this.tb.fields.each(function(e) {
25831 e.setValue(sel.getAttribute(e.name));
25833 this.tb.selectedNode = sel;
25836 Roo.menu.MenuMgr.hideAll();
25838 //this.editorsyncValue();
25843 onDestroy : function(){
25846 this.tb.items.each(function(item){
25848 item.menu.removeAll();
25850 item.menu.el.destroy();
25858 onFirstFocus: function() {
25859 // need to do this for all the toolbars..
25860 this.tb.items.each(function(item){
25864 buildToolbar: function(tlist, nm)
25866 var editor = this.editor;
25867 // create a new element.
25868 var wdiv = editor.wrap.createChild({
25870 }, editor.wrap.dom.firstChild.nextSibling, true);
25873 var tb = new Roo.Toolbar(wdiv);
25874 tb.add(nm+ ": ");
25875 for (var i in tlist) {
25876 var item = tlist[i];
25877 tb.add(item.title + ": ");
25882 tb.addField( new Roo.form.ComboBox({
25883 store: new Roo.data.SimpleStore({
25886 data : item.opts // from states.js
25889 displayField:'val',
25893 triggerAction: 'all',
25894 emptyText:'Select',
25895 selectOnFocus:true,
25896 width: item.width ? item.width : 130,
25898 'select': function(c, r, i) {
25899 tb.selectedNode.setAttribute(c.name, r.get('val'));
25910 tb.addField( new Roo.form.TextField({
25913 //allowBlank:false,
25918 tb.addField( new Roo.form.TextField({
25924 'change' : function(f, nv, ov) {
25925 tb.selectedNode.setAttribute(f.name, nv);
25931 tb.el.on('click', function(e){
25932 e.preventDefault(); // what does this do?
25934 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25937 // dont need to disable them... as they will get hidden
25954 * Ext JS Library 1.1.1
25955 * Copyright(c) 2006-2007, Ext JS, LLC.
25957 * Originally Released Under LGPL - original licence link has changed is not relivant.
25960 * <script type="text/javascript">
25964 * @class Roo.form.BasicForm
25965 * @extends Roo.util.Observable
25966 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25968 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25969 * @param {Object} config Configuration options
25971 Roo.form.BasicForm = function(el, config){
25972 this.allItems = [];
25973 this.childForms = [];
25974 Roo.apply(this, config);
25976 * The Roo.form.Field items in this form.
25977 * @type MixedCollection
25981 this.items = new Roo.util.MixedCollection(false, function(o){
25982 return o.id || (o.id = Roo.id());
25986 * @event beforeaction
25987 * Fires before any action is performed. Return false to cancel the action.
25988 * @param {Form} this
25989 * @param {Action} action The action to be performed
25991 beforeaction: true,
25993 * @event actionfailed
25994 * Fires when an action fails.
25995 * @param {Form} this
25996 * @param {Action} action The action that failed
25998 actionfailed : true,
26000 * @event actioncomplete
26001 * Fires when an action is completed.
26002 * @param {Form} this
26003 * @param {Action} action The action that completed
26005 actioncomplete : true
26010 Roo.form.BasicForm.superclass.constructor.call(this);
26013 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
26015 * @cfg {String} method
26016 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
26019 * @cfg {DataReader} reader
26020 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
26021 * This is optional as there is built-in support for processing JSON.
26024 * @cfg {DataReader} errorReader
26025 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
26026 * This is completely optional as there is built-in support for processing JSON.
26029 * @cfg {String} url
26030 * The URL to use for form actions if one isn't supplied in the action options.
26033 * @cfg {Boolean} fileUpload
26034 * Set to true if this form is a file upload.
26038 * @cfg {Object} baseParams
26039 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
26044 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
26049 activeAction : null,
26052 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
26053 * or setValues() data instead of when the form was first created.
26055 trackResetOnLoad : false,
26059 * childForms - used for multi-tab forms
26062 childForms : false,
26065 * allItems - full list of fields.
26071 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26072 * element by passing it or its id or mask the form itself by passing in true.
26075 waitMsgTarget : false,
26078 initEl : function(el){
26079 this.el = Roo.get(el);
26080 this.id = this.el.id || Roo.id();
26081 this.el.on('submit', this.onSubmit, this);
26082 this.el.addClass('x-form');
26086 onSubmit : function(e){
26091 * Returns true if client-side validation on the form is successful.
26094 isValid : function(){
26096 this.items.each(function(f){
26105 * Returns true if any fields in this form have changed since their original load.
26108 isDirty : function(){
26110 this.items.each(function(f){
26120 * Performs a predefined action (submit or load) or custom actions you define on this form.
26121 * @param {String} actionName The name of the action type
26122 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26123 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26124 * accept other config options):
26126 Property Type Description
26127 ---------------- --------------- ----------------------------------------------------------------------------------
26128 url String The url for the action (defaults to the form's url)
26129 method String The form method to use (defaults to the form's method, or POST if not defined)
26130 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26131 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26132 validate the form on the client (defaults to false)
26134 * @return {BasicForm} this
26136 doAction : function(action, options){
26137 if(typeof action == 'string'){
26138 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26140 if(this.fireEvent('beforeaction', this, action) !== false){
26141 this.beforeAction(action);
26142 action.run.defer(100, action);
26148 * Shortcut to do a submit action.
26149 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26150 * @return {BasicForm} this
26152 submit : function(options){
26153 this.doAction('submit', options);
26158 * Shortcut to do a load action.
26159 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26160 * @return {BasicForm} this
26162 load : function(options){
26163 this.doAction('load', options);
26168 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26169 * @param {Record} record The record to edit
26170 * @return {BasicForm} this
26172 updateRecord : function(record){
26173 record.beginEdit();
26174 var fs = record.fields;
26175 fs.each(function(f){
26176 var field = this.findField(f.name);
26178 record.set(f.name, field.getValue());
26186 * Loads an Roo.data.Record into this form.
26187 * @param {Record} record The record to load
26188 * @return {BasicForm} this
26190 loadRecord : function(record){
26191 this.setValues(record.data);
26196 beforeAction : function(action){
26197 var o = action.options;
26200 if(this.waitMsgTarget === true){
26201 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
26202 }else if(this.waitMsgTarget){
26203 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26204 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
26206 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
26212 afterAction : function(action, success){
26213 this.activeAction = null;
26214 var o = action.options;
26216 if(this.waitMsgTarget === true){
26218 }else if(this.waitMsgTarget){
26219 this.waitMsgTarget.unmask();
26221 Roo.MessageBox.updateProgress(1);
26222 Roo.MessageBox.hide();
26229 Roo.callback(o.success, o.scope, [this, action]);
26230 this.fireEvent('actioncomplete', this, action);
26233 Roo.callback(o.failure, o.scope, [this, action]);
26234 // show an error message if no failed handler is set..
26235 if (!this.hasListener('actionfailed')) {
26236 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
26239 this.fireEvent('actionfailed', this, action);
26245 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26246 * @param {String} id The value to search for
26249 findField : function(id){
26250 var field = this.items.get(id);
26252 this.items.each(function(f){
26253 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26259 return field || null;
26263 * Add a secondary form to this one,
26264 * Used to provide tabbed forms. One form is primary, with hidden values
26265 * which mirror the elements from the other forms.
26267 * @param {Roo.form.Form} form to add.
26270 addForm : function(form)
26273 if (this.childForms.indexOf(form) > -1) {
26277 this.childForms.push(form);
26279 Roo.each(form.allItems, function (fe) {
26281 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26282 if (this.findField(n)) { // already added..
26285 var add = new Roo.form.Hidden({
26288 add.render(this.el);
26295 * Mark fields in this form invalid in bulk.
26296 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26297 * @return {BasicForm} this
26299 markInvalid : function(errors){
26300 if(errors instanceof Array){
26301 for(var i = 0, len = errors.length; i < len; i++){
26302 var fieldError = errors[i];
26303 var f = this.findField(fieldError.id);
26305 f.markInvalid(fieldError.msg);
26311 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26312 field.markInvalid(errors[id]);
26316 Roo.each(this.childForms || [], function (f) {
26317 f.markInvalid(errors);
26324 * Set values for fields in this form in bulk.
26325 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26326 * @return {BasicForm} this
26328 setValues : function(values){
26329 if(values instanceof Array){ // array of objects
26330 for(var i = 0, len = values.length; i < len; i++){
26332 var f = this.findField(v.id);
26334 f.setValue(v.value);
26335 if(this.trackResetOnLoad){
26336 f.originalValue = f.getValue();
26340 }else{ // object hash
26343 if(typeof values[id] != 'function' && (field = this.findField(id))){
26345 if (field.setFromData &&
26346 field.valueField &&
26347 field.displayField &&
26348 // combos' with local stores can
26349 // be queried via setValue()
26350 // to set their value..
26351 (field.store && !field.store.isLocal)
26355 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26356 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26357 field.setFromData(sd);
26360 field.setValue(values[id]);
26364 if(this.trackResetOnLoad){
26365 field.originalValue = field.getValue();
26371 Roo.each(this.childForms || [], function (f) {
26372 f.setValues(values);
26379 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26380 * they are returned as an array.
26381 * @param {Boolean} asString
26384 getValues : function(asString){
26385 if (this.childForms) {
26386 // copy values from the child forms
26387 Roo.each(this.childForms, function (f) {
26388 this.setValues(f.getValues());
26394 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26395 if(asString === true){
26398 return Roo.urlDecode(fs);
26402 * Returns the fields in this form as an object with key/value pairs.
26403 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26406 getFieldValues : function()
26408 if (this.childForms) {
26409 // copy values from the child forms
26410 Roo.each(this.childForms, function (f) {
26411 this.setValues(f.getValues());
26416 this.items.each(function(f){
26417 if (!f.getName()) {
26420 var v = f.getValue();
26421 if ((typeof(v) == 'object') && f.getRawValue) {
26422 v = f.getRawValue() ; // dates..
26424 ret[f.getName()] = v;
26431 * Clears all invalid messages in this form.
26432 * @return {BasicForm} this
26434 clearInvalid : function(){
26435 this.items.each(function(f){
26439 Roo.each(this.childForms || [], function (f) {
26448 * Resets this form.
26449 * @return {BasicForm} this
26451 reset : function(){
26452 this.items.each(function(f){
26456 Roo.each(this.childForms || [], function (f) {
26465 * Add Roo.form components to this form.
26466 * @param {Field} field1
26467 * @param {Field} field2 (optional)
26468 * @param {Field} etc (optional)
26469 * @return {BasicForm} this
26472 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26478 * Removes a field from the items collection (does NOT remove its markup).
26479 * @param {Field} field
26480 * @return {BasicForm} this
26482 remove : function(field){
26483 this.items.remove(field);
26488 * Looks at the fields in this form, checks them for an id attribute,
26489 * and calls applyTo on the existing dom element with that id.
26490 * @return {BasicForm} this
26492 render : function(){
26493 this.items.each(function(f){
26494 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26502 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26503 * @param {Object} values
26504 * @return {BasicForm} this
26506 applyToFields : function(o){
26507 this.items.each(function(f){
26514 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26515 * @param {Object} values
26516 * @return {BasicForm} this
26518 applyIfToFields : function(o){
26519 this.items.each(function(f){
26527 Roo.BasicForm = Roo.form.BasicForm;/*
26529 * Ext JS Library 1.1.1
26530 * Copyright(c) 2006-2007, Ext JS, LLC.
26532 * Originally Released Under LGPL - original licence link has changed is not relivant.
26535 * <script type="text/javascript">
26539 * @class Roo.form.Form
26540 * @extends Roo.form.BasicForm
26541 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26543 * @param {Object} config Configuration options
26545 Roo.form.Form = function(config){
26547 if (config.items) {
26548 xitems = config.items;
26549 delete config.items;
26553 Roo.form.Form.superclass.constructor.call(this, null, config);
26554 this.url = this.url || this.action;
26556 this.root = new Roo.form.Layout(Roo.applyIf({
26560 this.active = this.root;
26562 * Array of all the buttons that have been added to this form via {@link addButton}
26566 this.allItems = [];
26569 * @event clientvalidation
26570 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26571 * @param {Form} this
26572 * @param {Boolean} valid true if the form has passed client-side validation
26574 clientvalidation: true,
26577 * Fires when the form is rendered
26578 * @param {Roo.form.Form} form
26583 if (this.progressUrl) {
26584 // push a hidden field onto the list of fields..
26588 name : 'UPLOAD_IDENTIFIER'
26593 Roo.each(xitems, this.addxtype, this);
26599 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26601 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26604 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26607 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26609 buttonAlign:'center',
26612 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26617 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26618 * This property cascades to child containers if not set.
26623 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26624 * fires a looping event with that state. This is required to bind buttons to the valid
26625 * state using the config value formBind:true on the button.
26627 monitorValid : false,
26630 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26635 * @cfg {String} progressUrl - Url to return progress data
26638 progressUrl : false,
26641 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26642 * fields are added and the column is closed. If no fields are passed the column remains open
26643 * until end() is called.
26644 * @param {Object} config The config to pass to the column
26645 * @param {Field} field1 (optional)
26646 * @param {Field} field2 (optional)
26647 * @param {Field} etc (optional)
26648 * @return Column The column container object
26650 column : function(c){
26651 var col = new Roo.form.Column(c);
26653 if(arguments.length > 1){ // duplicate code required because of Opera
26654 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26661 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26662 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26663 * until end() is called.
26664 * @param {Object} config The config to pass to the fieldset
26665 * @param {Field} field1 (optional)
26666 * @param {Field} field2 (optional)
26667 * @param {Field} etc (optional)
26668 * @return FieldSet The fieldset container object
26670 fieldset : function(c){
26671 var fs = new Roo.form.FieldSet(c);
26673 if(arguments.length > 1){ // duplicate code required because of Opera
26674 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26681 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26682 * fields are added and the container is closed. If no fields are passed the container remains open
26683 * until end() is called.
26684 * @param {Object} config The config to pass to the Layout
26685 * @param {Field} field1 (optional)
26686 * @param {Field} field2 (optional)
26687 * @param {Field} etc (optional)
26688 * @return Layout The container object
26690 container : function(c){
26691 var l = new Roo.form.Layout(c);
26693 if(arguments.length > 1){ // duplicate code required because of Opera
26694 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26701 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26702 * @param {Object} container A Roo.form.Layout or subclass of Layout
26703 * @return {Form} this
26705 start : function(c){
26706 // cascade label info
26707 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26708 this.active.stack.push(c);
26709 c.ownerCt = this.active;
26715 * Closes the current open container
26716 * @return {Form} this
26719 if(this.active == this.root){
26722 this.active = this.active.ownerCt;
26727 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26728 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26729 * as the label of the field.
26730 * @param {Field} field1
26731 * @param {Field} field2 (optional)
26732 * @param {Field} etc. (optional)
26733 * @return {Form} this
26736 this.active.stack.push.apply(this.active.stack, arguments);
26737 this.allItems.push.apply(this.allItems,arguments);
26739 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26740 if(a[i].isFormField){
26745 Roo.form.Form.superclass.add.apply(this, r);
26755 * Find any element that has been added to a form, using it's ID or name
26756 * This can include framesets, columns etc. along with regular fields..
26757 * @param {String} id - id or name to find.
26759 * @return {Element} e - or false if nothing found.
26761 findbyId : function(id)
26767 Roo.each(this.allItems, function(f){
26768 if (f.id == id || f.name == id ){
26779 * Render this form into the passed container. This should only be called once!
26780 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26781 * @return {Form} this
26783 render : function(ct)
26789 var o = this.autoCreate || {
26791 method : this.method || 'POST',
26792 id : this.id || Roo.id()
26794 this.initEl(ct.createChild(o));
26796 this.root.render(this.el);
26800 this.items.each(function(f){
26801 f.render('x-form-el-'+f.id);
26804 if(this.buttons.length > 0){
26805 // tables are required to maintain order and for correct IE layout
26806 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26807 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26808 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26810 var tr = tb.getElementsByTagName('tr')[0];
26811 for(var i = 0, len = this.buttons.length; i < len; i++) {
26812 var b = this.buttons[i];
26813 var td = document.createElement('td');
26814 td.className = 'x-form-btn-td';
26815 b.render(tr.appendChild(td));
26818 if(this.monitorValid){ // initialize after render
26819 this.startMonitoring();
26821 this.fireEvent('rendered', this);
26826 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26827 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26828 * object or a valid Roo.DomHelper element config
26829 * @param {Function} handler The function called when the button is clicked
26830 * @param {Object} scope (optional) The scope of the handler function
26831 * @return {Roo.Button}
26833 addButton : function(config, handler, scope){
26837 minWidth: this.minButtonWidth,
26840 if(typeof config == "string"){
26843 Roo.apply(bc, config);
26845 var btn = new Roo.Button(null, bc);
26846 this.buttons.push(btn);
26851 * Adds a series of form elements (using the xtype property as the factory method.
26852 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26853 * @param {Object} config
26856 addxtype : function()
26858 var ar = Array.prototype.slice.call(arguments, 0);
26860 for(var i = 0; i < ar.length; i++) {
26862 continue; // skip -- if this happends something invalid got sent, we
26863 // should ignore it, as basically that interface element will not show up
26864 // and that should be pretty obvious!!
26867 if (Roo.form[ar[i].xtype]) {
26869 var fe = Roo.factory(ar[i], Roo.form);
26875 fe.store.form = this;
26880 this.allItems.push(fe);
26881 if (fe.items && fe.addxtype) {
26882 fe.addxtype.apply(fe, fe.items);
26892 // console.log('adding ' + ar[i].xtype);
26894 if (ar[i].xtype == 'Button') {
26895 //console.log('adding button');
26896 //console.log(ar[i]);
26897 this.addButton(ar[i]);
26898 this.allItems.push(fe);
26902 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26903 alert('end is not supported on xtype any more, use items');
26905 // //console.log('adding end');
26913 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26914 * option "monitorValid"
26916 startMonitoring : function(){
26919 Roo.TaskMgr.start({
26920 run : this.bindHandler,
26921 interval : this.monitorPoll || 200,
26928 * Stops monitoring of the valid state of this form
26930 stopMonitoring : function(){
26931 this.bound = false;
26935 bindHandler : function(){
26937 return false; // stops binding
26940 this.items.each(function(f){
26941 if(!f.isValid(true)){
26946 for(var i = 0, len = this.buttons.length; i < len; i++){
26947 var btn = this.buttons[i];
26948 if(btn.formBind === true && btn.disabled === valid){
26949 btn.setDisabled(!valid);
26952 this.fireEvent('clientvalidation', this, valid);
26966 Roo.Form = Roo.form.Form;
26969 * Ext JS Library 1.1.1
26970 * Copyright(c) 2006-2007, Ext JS, LLC.
26972 * Originally Released Under LGPL - original licence link has changed is not relivant.
26975 * <script type="text/javascript">
26979 * @class Roo.form.Action
26980 * Internal Class used to handle form actions
26982 * @param {Roo.form.BasicForm} el The form element or its id
26983 * @param {Object} config Configuration options
26987 // define the action interface
26988 Roo.form.Action = function(form, options){
26990 this.options = options || {};
26993 * Client Validation Failed
26996 Roo.form.Action.CLIENT_INVALID = 'client';
26998 * Server Validation Failed
27001 Roo.form.Action.SERVER_INVALID = 'server';
27003 * Connect to Server Failed
27006 Roo.form.Action.CONNECT_FAILURE = 'connect';
27008 * Reading Data from Server Failed
27011 Roo.form.Action.LOAD_FAILURE = 'load';
27013 Roo.form.Action.prototype = {
27015 failureType : undefined,
27016 response : undefined,
27017 result : undefined,
27019 // interface method
27020 run : function(options){
27024 // interface method
27025 success : function(response){
27029 // interface method
27030 handleResponse : function(response){
27034 // default connection failure
27035 failure : function(response){
27037 this.response = response;
27038 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27039 this.form.afterAction(this, false);
27042 processResponse : function(response){
27043 this.response = response;
27044 if(!response.responseText){
27047 this.result = this.handleResponse(response);
27048 return this.result;
27051 // utility functions used internally
27052 getUrl : function(appendParams){
27053 var url = this.options.url || this.form.url || this.form.el.dom.action;
27055 var p = this.getParams();
27057 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
27063 getMethod : function(){
27064 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
27067 getParams : function(){
27068 var bp = this.form.baseParams;
27069 var p = this.options.params;
27071 if(typeof p == "object"){
27072 p = Roo.urlEncode(Roo.applyIf(p, bp));
27073 }else if(typeof p == 'string' && bp){
27074 p += '&' + Roo.urlEncode(bp);
27077 p = Roo.urlEncode(bp);
27082 createCallback : function(){
27084 success: this.success,
27085 failure: this.failure,
27087 timeout: (this.form.timeout*1000),
27088 upload: this.form.fileUpload ? this.success : undefined
27093 Roo.form.Action.Submit = function(form, options){
27094 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27097 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27100 haveProgress : false,
27101 uploadComplete : false,
27103 // uploadProgress indicator.
27104 uploadProgress : function()
27106 if (!this.form.progressUrl) {
27110 if (!this.haveProgress) {
27111 Roo.MessageBox.progress("Uploading", "Uploading");
27113 if (this.uploadComplete) {
27114 Roo.MessageBox.hide();
27118 this.haveProgress = true;
27120 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27122 var c = new Roo.data.Connection();
27124 url : this.form.progressUrl,
27129 success : function(req){
27130 //console.log(data);
27134 rdata = Roo.decode(req.responseText)
27136 Roo.log("Invalid data from server..");
27140 if (!rdata || !rdata.success) {
27144 var data = rdata.data;
27146 if (this.uploadComplete) {
27147 Roo.MessageBox.hide();
27152 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27153 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27156 this.uploadProgress.defer(2000,this);
27159 failure: function(data) {
27160 Roo.log('progress url failed ');
27171 // run get Values on the form, so it syncs any secondary forms.
27172 this.form.getValues();
27174 var o = this.options;
27175 var method = this.getMethod();
27176 var isPost = method == 'POST';
27177 if(o.clientValidation === false || this.form.isValid()){
27179 if (this.form.progressUrl) {
27180 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27181 (new Date() * 1) + '' + Math.random());
27186 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27187 form:this.form.el.dom,
27188 url:this.getUrl(!isPost),
27190 params:isPost ? this.getParams() : null,
27191 isUpload: this.form.fileUpload
27194 this.uploadProgress();
27196 }else if (o.clientValidation !== false){ // client validation failed
27197 this.failureType = Roo.form.Action.CLIENT_INVALID;
27198 this.form.afterAction(this, false);
27202 success : function(response)
27204 this.uploadComplete= true;
27205 if (this.haveProgress) {
27206 Roo.MessageBox.hide();
27210 var result = this.processResponse(response);
27211 if(result === true || result.success){
27212 this.form.afterAction(this, true);
27216 this.form.markInvalid(result.errors);
27217 this.failureType = Roo.form.Action.SERVER_INVALID;
27219 this.form.afterAction(this, false);
27221 failure : function(response)
27223 this.uploadComplete= true;
27224 if (this.haveProgress) {
27225 Roo.MessageBox.hide();
27229 this.response = response;
27230 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27231 this.form.afterAction(this, false);
27234 handleResponse : function(response){
27235 if(this.form.errorReader){
27236 var rs = this.form.errorReader.read(response);
27239 for(var i = 0, len = rs.records.length; i < len; i++) {
27240 var r = rs.records[i];
27241 errors[i] = r.data;
27244 if(errors.length < 1){
27248 success : rs.success,
27254 ret = Roo.decode(response.responseText);
27258 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27268 Roo.form.Action.Load = function(form, options){
27269 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27270 this.reader = this.form.reader;
27273 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27278 Roo.Ajax.request(Roo.apply(
27279 this.createCallback(), {
27280 method:this.getMethod(),
27281 url:this.getUrl(false),
27282 params:this.getParams()
27286 success : function(response){
27288 var result = this.processResponse(response);
27289 if(result === true || !result.success || !result.data){
27290 this.failureType = Roo.form.Action.LOAD_FAILURE;
27291 this.form.afterAction(this, false);
27294 this.form.clearInvalid();
27295 this.form.setValues(result.data);
27296 this.form.afterAction(this, true);
27299 handleResponse : function(response){
27300 if(this.form.reader){
27301 var rs = this.form.reader.read(response);
27302 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27304 success : rs.success,
27308 return Roo.decode(response.responseText);
27312 Roo.form.Action.ACTION_TYPES = {
27313 'load' : Roo.form.Action.Load,
27314 'submit' : Roo.form.Action.Submit
27317 * Ext JS Library 1.1.1
27318 * Copyright(c) 2006-2007, Ext JS, LLC.
27320 * Originally Released Under LGPL - original licence link has changed is not relivant.
27323 * <script type="text/javascript">
27327 * @class Roo.form.Layout
27328 * @extends Roo.Component
27329 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27331 * @param {Object} config Configuration options
27333 Roo.form.Layout = function(config){
27335 if (config.items) {
27336 xitems = config.items;
27337 delete config.items;
27339 Roo.form.Layout.superclass.constructor.call(this, config);
27341 Roo.each(xitems, this.addxtype, this);
27345 Roo.extend(Roo.form.Layout, Roo.Component, {
27347 * @cfg {String/Object} autoCreate
27348 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27351 * @cfg {String/Object/Function} style
27352 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27353 * a function which returns such a specification.
27356 * @cfg {String} labelAlign
27357 * Valid values are "left," "top" and "right" (defaults to "left")
27360 * @cfg {Number} labelWidth
27361 * Fixed width in pixels of all field labels (defaults to undefined)
27364 * @cfg {Boolean} clear
27365 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27369 * @cfg {String} labelSeparator
27370 * The separator to use after field labels (defaults to ':')
27372 labelSeparator : ':',
27374 * @cfg {Boolean} hideLabels
27375 * True to suppress the display of field labels in this layout (defaults to false)
27377 hideLabels : false,
27380 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27385 onRender : function(ct, position){
27386 if(this.el){ // from markup
27387 this.el = Roo.get(this.el);
27388 }else { // generate
27389 var cfg = this.getAutoCreate();
27390 this.el = ct.createChild(cfg, position);
27393 this.el.applyStyles(this.style);
27395 if(this.labelAlign){
27396 this.el.addClass('x-form-label-'+this.labelAlign);
27398 if(this.hideLabels){
27399 this.labelStyle = "display:none";
27400 this.elementStyle = "padding-left:0;";
27402 if(typeof this.labelWidth == 'number'){
27403 this.labelStyle = "width:"+this.labelWidth+"px;";
27404 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27406 if(this.labelAlign == 'top'){
27407 this.labelStyle = "width:auto;";
27408 this.elementStyle = "padding-left:0;";
27411 var stack = this.stack;
27412 var slen = stack.length;
27414 if(!this.fieldTpl){
27415 var t = new Roo.Template(
27416 '<div class="x-form-item {5}">',
27417 '<label for="{0}" style="{2}">{1}{4}</label>',
27418 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27420 '</div><div class="x-form-clear-left"></div>'
27422 t.disableFormats = true;
27424 Roo.form.Layout.prototype.fieldTpl = t;
27426 for(var i = 0; i < slen; i++) {
27427 if(stack[i].isFormField){
27428 this.renderField(stack[i]);
27430 this.renderComponent(stack[i]);
27435 this.el.createChild({cls:'x-form-clear'});
27440 renderField : function(f){
27441 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27444 f.labelStyle||this.labelStyle||'', //2
27445 this.elementStyle||'', //3
27446 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27447 f.itemCls||this.itemCls||'' //5
27448 ], true).getPrevSibling());
27452 renderComponent : function(c){
27453 c.render(c.isLayout ? this.el : this.el.createChild());
27456 * Adds a object form elements (using the xtype property as the factory method.)
27457 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27458 * @param {Object} config
27460 addxtype : function(o)
27462 // create the lement.
27463 o.form = this.form;
27464 var fe = Roo.factory(o, Roo.form);
27465 this.form.allItems.push(fe);
27466 this.stack.push(fe);
27468 if (fe.isFormField) {
27469 this.form.items.add(fe);
27477 * @class Roo.form.Column
27478 * @extends Roo.form.Layout
27479 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27481 * @param {Object} config Configuration options
27483 Roo.form.Column = function(config){
27484 Roo.form.Column.superclass.constructor.call(this, config);
27487 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27489 * @cfg {Number/String} width
27490 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27493 * @cfg {String/Object} autoCreate
27494 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27498 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27501 onRender : function(ct, position){
27502 Roo.form.Column.superclass.onRender.call(this, ct, position);
27504 this.el.setWidth(this.width);
27511 * @class Roo.form.Row
27512 * @extends Roo.form.Layout
27513 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27515 * @param {Object} config Configuration options
27519 Roo.form.Row = function(config){
27520 Roo.form.Row.superclass.constructor.call(this, config);
27523 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27525 * @cfg {Number/String} width
27526 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27529 * @cfg {Number/String} height
27530 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27532 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27536 onRender : function(ct, position){
27537 //console.log('row render');
27539 var t = new Roo.Template(
27540 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27541 '<label for="{0}" style="{2}">{1}{4}</label>',
27542 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27546 t.disableFormats = true;
27548 Roo.form.Layout.prototype.rowTpl = t;
27550 this.fieldTpl = this.rowTpl;
27552 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27553 var labelWidth = 100;
27555 if ((this.labelAlign != 'top')) {
27556 if (typeof this.labelWidth == 'number') {
27557 labelWidth = this.labelWidth
27559 this.padWidth = 20 + labelWidth;
27563 Roo.form.Column.superclass.onRender.call(this, ct, position);
27565 this.el.setWidth(this.width);
27568 this.el.setHeight(this.height);
27573 renderField : function(f){
27574 f.fieldEl = this.fieldTpl.append(this.el, [
27575 f.id, f.fieldLabel,
27576 f.labelStyle||this.labelStyle||'',
27577 this.elementStyle||'',
27578 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27579 f.itemCls||this.itemCls||'',
27580 f.width ? f.width + this.padWidth : 160 + this.padWidth
27587 * @class Roo.form.FieldSet
27588 * @extends Roo.form.Layout
27589 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27591 * @param {Object} config Configuration options
27593 Roo.form.FieldSet = function(config){
27594 Roo.form.FieldSet.superclass.constructor.call(this, config);
27597 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27599 * @cfg {String} legend
27600 * The text to display as the legend for the FieldSet (defaults to '')
27603 * @cfg {String/Object} autoCreate
27604 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27608 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27611 onRender : function(ct, position){
27612 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27614 this.setLegend(this.legend);
27619 setLegend : function(text){
27621 this.el.child('legend').update(text);
27626 * Ext JS Library 1.1.1
27627 * Copyright(c) 2006-2007, Ext JS, LLC.
27629 * Originally Released Under LGPL - original licence link has changed is not relivant.
27632 * <script type="text/javascript">
27635 * @class Roo.form.VTypes
27636 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27639 Roo.form.VTypes = function(){
27640 // closure these in so they are only created once.
27641 var alpha = /^[a-zA-Z_]+$/;
27642 var alphanum = /^[a-zA-Z0-9_]+$/;
27643 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27644 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27646 // All these messages and functions are configurable
27649 * The function used to validate email addresses
27650 * @param {String} value The email address
27652 'email' : function(v){
27653 return email.test(v);
27656 * The error text to display when the email validation function returns false
27659 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27661 * The keystroke filter mask to be applied on email input
27664 'emailMask' : /[a-z0-9_\.\-@]/i,
27667 * The function used to validate URLs
27668 * @param {String} value The URL
27670 'url' : function(v){
27671 return url.test(v);
27674 * The error text to display when the url validation function returns false
27677 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27680 * The function used to validate alpha values
27681 * @param {String} value The value
27683 'alpha' : function(v){
27684 return alpha.test(v);
27687 * The error text to display when the alpha validation function returns false
27690 'alphaText' : 'This field should only contain letters and _',
27692 * The keystroke filter mask to be applied on alpha input
27695 'alphaMask' : /[a-z_]/i,
27698 * The function used to validate alphanumeric values
27699 * @param {String} value The value
27701 'alphanum' : function(v){
27702 return alphanum.test(v);
27705 * The error text to display when the alphanumeric validation function returns false
27708 'alphanumText' : 'This field should only contain letters, numbers and _',
27710 * The keystroke filter mask to be applied on alphanumeric input
27713 'alphanumMask' : /[a-z0-9_]/i
27715 }();//<script type="text/javascript">
27718 * @class Roo.form.FCKeditor
27719 * @extends Roo.form.TextArea
27720 * Wrapper around the FCKEditor http://www.fckeditor.net
27722 * Creates a new FCKeditor
27723 * @param {Object} config Configuration options
27725 Roo.form.FCKeditor = function(config){
27726 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27729 * @event editorinit
27730 * Fired when the editor is initialized - you can add extra handlers here..
27731 * @param {FCKeditor} this
27732 * @param {Object} the FCK object.
27739 Roo.form.FCKeditor.editors = { };
27740 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27742 //defaultAutoCreate : {
27743 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27747 * @cfg {Object} fck options - see fck manual for details.
27752 * @cfg {Object} fck toolbar set (Basic or Default)
27754 toolbarSet : 'Basic',
27756 * @cfg {Object} fck BasePath
27758 basePath : '/fckeditor/',
27766 onRender : function(ct, position)
27769 this.defaultAutoCreate = {
27771 style:"width:300px;height:60px;",
27772 autocomplete: "off"
27775 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27778 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27779 if(this.preventScrollbars){
27780 this.el.setStyle("overflow", "hidden");
27782 this.el.setHeight(this.growMin);
27785 //console.log('onrender' + this.getId() );
27786 Roo.form.FCKeditor.editors[this.getId()] = this;
27789 this.replaceTextarea() ;
27793 getEditor : function() {
27794 return this.fckEditor;
27797 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27798 * @param {Mixed} value The value to set
27802 setValue : function(value)
27804 //console.log('setValue: ' + value);
27806 if(typeof(value) == 'undefined') { // not sure why this is happending...
27809 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27811 //if(!this.el || !this.getEditor()) {
27812 // this.value = value;
27813 //this.setValue.defer(100,this,[value]);
27817 if(!this.getEditor()) {
27821 this.getEditor().SetData(value);
27828 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27829 * @return {Mixed} value The field value
27831 getValue : function()
27834 if (this.frame && this.frame.dom.style.display == 'none') {
27835 return Roo.form.FCKeditor.superclass.getValue.call(this);
27838 if(!this.el || !this.getEditor()) {
27840 // this.getValue.defer(100,this);
27845 var value=this.getEditor().GetData();
27846 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27847 return Roo.form.FCKeditor.superclass.getValue.call(this);
27853 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27854 * @return {Mixed} value The field value
27856 getRawValue : function()
27858 if (this.frame && this.frame.dom.style.display == 'none') {
27859 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27862 if(!this.el || !this.getEditor()) {
27863 //this.getRawValue.defer(100,this);
27870 var value=this.getEditor().GetData();
27871 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27872 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27876 setSize : function(w,h) {
27880 //if (this.frame && this.frame.dom.style.display == 'none') {
27881 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27884 //if(!this.el || !this.getEditor()) {
27885 // this.setSize.defer(100,this, [w,h]);
27891 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27893 this.frame.dom.setAttribute('width', w);
27894 this.frame.dom.setAttribute('height', h);
27895 this.frame.setSize(w,h);
27899 toggleSourceEdit : function(value) {
27903 this.el.dom.style.display = value ? '' : 'none';
27904 this.frame.dom.style.display = value ? 'none' : '';
27909 focus: function(tag)
27911 if (this.frame.dom.style.display == 'none') {
27912 return Roo.form.FCKeditor.superclass.focus.call(this);
27914 if(!this.el || !this.getEditor()) {
27915 this.focus.defer(100,this, [tag]);
27922 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27923 this.getEditor().Focus();
27925 if (!this.getEditor().Selection.GetSelection()) {
27926 this.focus.defer(100,this, [tag]);
27931 var r = this.getEditor().EditorDocument.createRange();
27932 r.setStart(tgs[0],0);
27933 r.setEnd(tgs[0],0);
27934 this.getEditor().Selection.GetSelection().removeAllRanges();
27935 this.getEditor().Selection.GetSelection().addRange(r);
27936 this.getEditor().Focus();
27943 replaceTextarea : function()
27945 if ( document.getElementById( this.getId() + '___Frame' ) )
27947 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27949 // We must check the elements firstly using the Id and then the name.
27950 var oTextarea = document.getElementById( this.getId() );
27952 var colElementsByName = document.getElementsByName( this.getId() ) ;
27954 oTextarea.style.display = 'none' ;
27956 if ( oTextarea.tabIndex ) {
27957 this.TabIndex = oTextarea.tabIndex ;
27960 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27961 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27962 this.frame = Roo.get(this.getId() + '___Frame')
27965 _getConfigHtml : function()
27969 for ( var o in this.fckconfig ) {
27970 sConfig += sConfig.length > 0 ? '&' : '';
27971 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27974 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27978 _getIFrameHtml : function()
27980 var sFile = 'fckeditor.html' ;
27981 /* no idea what this is about..
27984 if ( (/fcksource=true/i).test( window.top.location.search ) )
27985 sFile = 'fckeditor.original.html' ;
27990 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27991 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27994 var html = '<iframe id="' + this.getId() +
27995 '___Frame" src="' + sLink +
27996 '" width="' + this.width +
27997 '" height="' + this.height + '"' +
27998 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27999 ' frameborder="0" scrolling="no"></iframe>' ;
28004 _insertHtmlBefore : function( html, element )
28006 if ( element.insertAdjacentHTML ) {
28008 element.insertAdjacentHTML( 'beforeBegin', html ) ;
28010 var oRange = document.createRange() ;
28011 oRange.setStartBefore( element ) ;
28012 var oFragment = oRange.createContextualFragment( html );
28013 element.parentNode.insertBefore( oFragment, element ) ;
28026 //Roo.reg('fckeditor', Roo.form.FCKeditor);
28028 function FCKeditor_OnComplete(editorInstance){
28029 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
28030 f.fckEditor = editorInstance;
28031 //console.log("loaded");
28032 f.fireEvent('editorinit', f, editorInstance);
28052 //<script type="text/javascript">
28054 * @class Roo.form.GridField
28055 * @extends Roo.form.Field
28056 * Embed a grid (or editable grid into a form)
28059 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
28061 * xgrid.store = Roo.data.Store
28062 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
28063 * xgrid.store.reader = Roo.data.JsonReader
28067 * Creates a new GridField
28068 * @param {Object} config Configuration options
28070 Roo.form.GridField = function(config){
28071 Roo.form.GridField.superclass.constructor.call(this, config);
28075 Roo.extend(Roo.form.GridField, Roo.form.Field, {
28077 * @cfg {Number} width - used to restrict width of grid..
28081 * @cfg {Number} height - used to restrict height of grid..
28085 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28091 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28092 * {tag: "input", type: "checkbox", autocomplete: "off"})
28094 // defaultAutoCreate : { tag: 'div' },
28095 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28097 * @cfg {String} addTitle Text to include for adding a title.
28101 onResize : function(){
28102 Roo.form.Field.superclass.onResize.apply(this, arguments);
28105 initEvents : function(){
28106 // Roo.form.Checkbox.superclass.initEvents.call(this);
28107 // has no events...
28112 getResizeEl : function(){
28116 getPositionEl : function(){
28121 onRender : function(ct, position){
28123 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28124 var style = this.style;
28127 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28128 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28129 this.viewEl = this.wrap.createChild({ tag: 'div' });
28131 this.viewEl.applyStyles(style);
28134 this.viewEl.setWidth(this.width);
28137 this.viewEl.setHeight(this.height);
28139 //if(this.inputValue !== undefined){
28140 //this.setValue(this.value);
28143 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28146 this.grid.render();
28147 this.grid.getDataSource().on('remove', this.refreshValue, this);
28148 this.grid.getDataSource().on('update', this.refreshValue, this);
28149 this.grid.on('afteredit', this.refreshValue, this);
28155 * Sets the value of the item.
28156 * @param {String} either an object or a string..
28158 setValue : function(v){
28160 v = v || []; // empty set..
28161 // this does not seem smart - it really only affects memoryproxy grids..
28162 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28163 var ds = this.grid.getDataSource();
28164 // assumes a json reader..
28166 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28167 ds.loadData( data);
28169 Roo.form.GridField.superclass.setValue.call(this, v);
28170 this.refreshValue();
28171 // should load data in the grid really....
28175 refreshValue: function() {
28177 this.grid.getDataSource().each(function(r) {
28180 this.el.dom.value = Roo.encode(val);
28188 * Ext JS Library 1.1.1
28189 * Copyright(c) 2006-2007, Ext JS, LLC.
28191 * Originally Released Under LGPL - original licence link has changed is not relivant.
28194 * <script type="text/javascript">
28197 * @class Roo.form.DisplayField
28198 * @extends Roo.form.Field
28199 * A generic Field to display non-editable data.
28201 * Creates a new Display Field item.
28202 * @param {Object} config Configuration options
28204 Roo.form.DisplayField = function(config){
28205 Roo.form.DisplayField.superclass.constructor.call(this, config);
28209 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28210 inputType: 'hidden',
28216 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28218 focusClass : undefined,
28220 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28222 fieldClass: 'x-form-field',
28225 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28227 valueRenderer: undefined,
28231 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28232 * {tag: "input", type: "checkbox", autocomplete: "off"})
28235 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28237 onResize : function(){
28238 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28242 initEvents : function(){
28243 // Roo.form.Checkbox.superclass.initEvents.call(this);
28244 // has no events...
28249 getResizeEl : function(){
28253 getPositionEl : function(){
28258 onRender : function(ct, position){
28260 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28261 //if(this.inputValue !== undefined){
28262 this.wrap = this.el.wrap();
28264 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
28266 if (this.bodyStyle) {
28267 this.viewEl.applyStyles(this.bodyStyle);
28269 //this.viewEl.setStyle('padding', '2px');
28271 this.setValue(this.value);
28276 initValue : Roo.emptyFn,
28281 onClick : function(){
28286 * Sets the checked state of the checkbox.
28287 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28289 setValue : function(v){
28291 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28292 // this might be called before we have a dom element..
28293 if (!this.viewEl) {
28296 this.viewEl.dom.innerHTML = html;
28297 Roo.form.DisplayField.superclass.setValue.call(this, v);
28307 * @class Roo.form.DayPicker
28308 * @extends Roo.form.Field
28309 * A Day picker show [M] [T] [W] ....
28311 * Creates a new Day Picker
28312 * @param {Object} config Configuration options
28314 Roo.form.DayPicker= function(config){
28315 Roo.form.DayPicker.superclass.constructor.call(this, config);
28319 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
28321 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28323 focusClass : undefined,
28325 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28327 fieldClass: "x-form-field",
28330 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28331 * {tag: "input", type: "checkbox", autocomplete: "off"})
28333 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
28336 actionMode : 'viewEl',
28340 inputType : 'hidden',
28343 inputElement: false, // real input element?
28344 basedOn: false, // ????
28346 isFormField: true, // not sure where this is needed!!!!
28348 onResize : function(){
28349 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
28350 if(!this.boxLabel){
28351 this.el.alignTo(this.wrap, 'c-c');
28355 initEvents : function(){
28356 Roo.form.Checkbox.superclass.initEvents.call(this);
28357 this.el.on("click", this.onClick, this);
28358 this.el.on("change", this.onClick, this);
28362 getResizeEl : function(){
28366 getPositionEl : function(){
28372 onRender : function(ct, position){
28373 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
28375 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
28377 var r1 = '<table><tr>';
28378 var r2 = '<tr class="x-form-daypick-icons">';
28379 for (var i=0; i < 7; i++) {
28380 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
28381 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
28384 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
28385 viewEl.select('img').on('click', this.onClick, this);
28386 this.viewEl = viewEl;
28389 // this will not work on Chrome!!!
28390 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
28391 this.el.on('propertychange', this.setFromHidden, this); //ie
28399 initValue : Roo.emptyFn,
28402 * Returns the checked state of the checkbox.
28403 * @return {Boolean} True if checked, else false
28405 getValue : function(){
28406 return this.el.dom.value;
28411 onClick : function(e){
28412 //this.setChecked(!this.checked);
28413 Roo.get(e.target).toggleClass('x-menu-item-checked');
28414 this.refreshValue();
28415 //if(this.el.dom.checked != this.checked){
28416 // this.setValue(this.el.dom.checked);
28421 refreshValue : function()
28424 this.viewEl.select('img',true).each(function(e,i,n) {
28425 val += e.is(".x-menu-item-checked") ? String(n) : '';
28427 this.setValue(val, true);
28431 * Sets the checked state of the checkbox.
28432 * On is always based on a string comparison between inputValue and the param.
28433 * @param {Boolean/String} value - the value to set
28434 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
28436 setValue : function(v,suppressEvent){
28437 if (!this.el.dom) {
28440 var old = this.el.dom.value ;
28441 this.el.dom.value = v;
28442 if (suppressEvent) {
28446 // update display..
28447 this.viewEl.select('img',true).each(function(e,i,n) {
28449 var on = e.is(".x-menu-item-checked");
28450 var newv = v.indexOf(String(n)) > -1;
28452 e.toggleClass('x-menu-item-checked');
28458 this.fireEvent('change', this, v, old);
28463 // handle setting of hidden value by some other method!!?!?
28464 setFromHidden: function()
28469 //console.log("SET FROM HIDDEN");
28470 //alert('setFrom hidden');
28471 this.setValue(this.el.dom.value);
28474 onDestroy : function()
28477 Roo.get(this.viewEl).remove();
28480 Roo.form.DayPicker.superclass.onDestroy.call(this);
28483 });//<script type="text/javasscript">
28487 * @class Roo.DDView
28488 * A DnD enabled version of Roo.View.
28489 * @param {Element/String} container The Element in which to create the View.
28490 * @param {String} tpl The template string used to create the markup for each element of the View
28491 * @param {Object} config The configuration properties. These include all the config options of
28492 * {@link Roo.View} plus some specific to this class.<br>
28494 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28495 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28497 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28498 .x-view-drag-insert-above {
28499 border-top:1px dotted #3366cc;
28501 .x-view-drag-insert-below {
28502 border-bottom:1px dotted #3366cc;
28508 Roo.DDView = function(container, tpl, config) {
28509 Roo.DDView.superclass.constructor.apply(this, arguments);
28510 this.getEl().setStyle("outline", "0px none");
28511 this.getEl().unselectable();
28512 if (this.dragGroup) {
28513 this.setDraggable(this.dragGroup.split(","));
28515 if (this.dropGroup) {
28516 this.setDroppable(this.dropGroup.split(","));
28518 if (this.deletable) {
28519 this.setDeletable();
28521 this.isDirtyFlag = false;
28527 Roo.extend(Roo.DDView, Roo.View, {
28528 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28529 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28530 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28531 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28535 reset: Roo.emptyFn,
28537 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28539 validate: function() {
28543 destroy: function() {
28544 this.purgeListeners();
28545 this.getEl.removeAllListeners();
28546 this.getEl().remove();
28547 if (this.dragZone) {
28548 if (this.dragZone.destroy) {
28549 this.dragZone.destroy();
28552 if (this.dropZone) {
28553 if (this.dropZone.destroy) {
28554 this.dropZone.destroy();
28559 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28560 getName: function() {
28564 /** Loads the View from a JSON string representing the Records to put into the Store. */
28565 setValue: function(v) {
28567 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28570 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28571 this.store.proxy = new Roo.data.MemoryProxy(data);
28575 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28576 getValue: function() {
28578 this.store.each(function(rec) {
28579 result += rec.id + ',';
28581 return result.substr(0, result.length - 1) + ')';
28584 getIds: function() {
28585 var i = 0, result = new Array(this.store.getCount());
28586 this.store.each(function(rec) {
28587 result[i++] = rec.id;
28592 isDirty: function() {
28593 return this.isDirtyFlag;
28597 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28598 * whole Element becomes the target, and this causes the drop gesture to append.
28600 getTargetFromEvent : function(e) {
28601 var target = e.getTarget();
28602 while ((target !== null) && (target.parentNode != this.el.dom)) {
28603 target = target.parentNode;
28606 target = this.el.dom.lastChild || this.el.dom;
28612 * Create the drag data which consists of an object which has the property "ddel" as
28613 * the drag proxy element.
28615 getDragData : function(e) {
28616 var target = this.findItemFromChild(e.getTarget());
28618 this.handleSelection(e);
28619 var selNodes = this.getSelectedNodes();
28622 copy: this.copy || (this.allowCopy && e.ctrlKey),
28626 var selectedIndices = this.getSelectedIndexes();
28627 for (var i = 0; i < selectedIndices.length; i++) {
28628 dragData.records.push(this.store.getAt(selectedIndices[i]));
28630 if (selNodes.length == 1) {
28631 dragData.ddel = target.cloneNode(true); // the div element
28633 var div = document.createElement('div'); // create the multi element drag "ghost"
28634 div.className = 'multi-proxy';
28635 for (var i = 0, len = selNodes.length; i < len; i++) {
28636 div.appendChild(selNodes[i].cloneNode(true));
28638 dragData.ddel = div;
28640 //console.log(dragData)
28641 //console.log(dragData.ddel.innerHTML)
28644 //console.log('nodragData')
28648 /** Specify to which ddGroup items in this DDView may be dragged. */
28649 setDraggable: function(ddGroup) {
28650 if (ddGroup instanceof Array) {
28651 Roo.each(ddGroup, this.setDraggable, this);
28654 if (this.dragZone) {
28655 this.dragZone.addToGroup(ddGroup);
28657 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28658 containerScroll: true,
28662 // Draggability implies selection. DragZone's mousedown selects the element.
28663 if (!this.multiSelect) { this.singleSelect = true; }
28665 // Wire the DragZone's handlers up to methods in *this*
28666 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28670 /** Specify from which ddGroup this DDView accepts drops. */
28671 setDroppable: function(ddGroup) {
28672 if (ddGroup instanceof Array) {
28673 Roo.each(ddGroup, this.setDroppable, this);
28676 if (this.dropZone) {
28677 this.dropZone.addToGroup(ddGroup);
28679 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28680 containerScroll: true,
28684 // Wire the DropZone's handlers up to methods in *this*
28685 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28686 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28687 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28688 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28689 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28693 /** Decide whether to drop above or below a View node. */
28694 getDropPoint : function(e, n, dd){
28695 if (n == this.el.dom) { return "above"; }
28696 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28697 var c = t + (b - t) / 2;
28698 var y = Roo.lib.Event.getPageY(e);
28706 onNodeEnter : function(n, dd, e, data){
28710 onNodeOver : function(n, dd, e, data){
28711 var pt = this.getDropPoint(e, n, dd);
28712 // set the insert point style on the target node
28713 var dragElClass = this.dropNotAllowed;
28716 if (pt == "above"){
28717 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28718 targetElClass = "x-view-drag-insert-above";
28720 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28721 targetElClass = "x-view-drag-insert-below";
28723 if (this.lastInsertClass != targetElClass){
28724 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28725 this.lastInsertClass = targetElClass;
28728 return dragElClass;
28731 onNodeOut : function(n, dd, e, data){
28732 this.removeDropIndicators(n);
28735 onNodeDrop : function(n, dd, e, data){
28736 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28739 var pt = this.getDropPoint(e, n, dd);
28740 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28741 if (pt == "below") { insertAt++; }
28742 for (var i = 0; i < data.records.length; i++) {
28743 var r = data.records[i];
28744 var dup = this.store.getById(r.id);
28745 if (dup && (dd != this.dragZone)) {
28746 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28749 this.store.insert(insertAt++, r.copy());
28751 data.source.isDirtyFlag = true;
28753 this.store.insert(insertAt++, r);
28755 this.isDirtyFlag = true;
28758 this.dragZone.cachedTarget = null;
28762 removeDropIndicators : function(n){
28764 Roo.fly(n).removeClass([
28765 "x-view-drag-insert-above",
28766 "x-view-drag-insert-below"]);
28767 this.lastInsertClass = "_noclass";
28772 * Utility method. Add a delete option to the DDView's context menu.
28773 * @param {String} imageUrl The URL of the "delete" icon image.
28775 setDeletable: function(imageUrl) {
28776 if (!this.singleSelect && !this.multiSelect) {
28777 this.singleSelect = true;
28779 var c = this.getContextMenu();
28780 this.contextMenu.on("itemclick", function(item) {
28783 this.remove(this.getSelectedIndexes());
28787 this.contextMenu.add({
28794 /** Return the context menu for this DDView. */
28795 getContextMenu: function() {
28796 if (!this.contextMenu) {
28797 // Create the View's context menu
28798 this.contextMenu = new Roo.menu.Menu({
28799 id: this.id + "-contextmenu"
28801 this.el.on("contextmenu", this.showContextMenu, this);
28803 return this.contextMenu;
28806 disableContextMenu: function() {
28807 if (this.contextMenu) {
28808 this.el.un("contextmenu", this.showContextMenu, this);
28812 showContextMenu: function(e, item) {
28813 item = this.findItemFromChild(e.getTarget());
28816 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28817 this.contextMenu.showAt(e.getXY());
28822 * Remove {@link Roo.data.Record}s at the specified indices.
28823 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28825 remove: function(selectedIndices) {
28826 selectedIndices = [].concat(selectedIndices);
28827 for (var i = 0; i < selectedIndices.length; i++) {
28828 var rec = this.store.getAt(selectedIndices[i]);
28829 this.store.remove(rec);
28834 * Double click fires the event, but also, if this is draggable, and there is only one other
28835 * related DropZone, it transfers the selected node.
28837 onDblClick : function(e){
28838 var item = this.findItemFromChild(e.getTarget());
28840 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28843 if (this.dragGroup) {
28844 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28845 while (targets.indexOf(this.dropZone) > -1) {
28846 targets.remove(this.dropZone);
28848 if (targets.length == 1) {
28849 this.dragZone.cachedTarget = null;
28850 var el = Roo.get(targets[0].getEl());
28851 var box = el.getBox(true);
28852 targets[0].onNodeDrop(el.dom, {
28854 xy: [box.x, box.y + box.height - 1]
28855 }, null, this.getDragData(e));
28861 handleSelection: function(e) {
28862 this.dragZone.cachedTarget = null;
28863 var item = this.findItemFromChild(e.getTarget());
28865 this.clearSelections(true);
28868 if (item && (this.multiSelect || this.singleSelect)){
28869 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28870 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28871 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28872 this.unselect(item);
28874 this.select(item, this.multiSelect && e.ctrlKey);
28875 this.lastSelection = item;
28880 onItemClick : function(item, index, e){
28881 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28887 unselect : function(nodeInfo, suppressEvent){
28888 var node = this.getNode(nodeInfo);
28889 if(node && this.isSelected(node)){
28890 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28891 Roo.fly(node).removeClass(this.selectedClass);
28892 this.selections.remove(node);
28893 if(!suppressEvent){
28894 this.fireEvent("selectionchange", this, this.selections);
28902 * Ext JS Library 1.1.1
28903 * Copyright(c) 2006-2007, Ext JS, LLC.
28905 * Originally Released Under LGPL - original licence link has changed is not relivant.
28908 * <script type="text/javascript">
28912 * @class Roo.LayoutManager
28913 * @extends Roo.util.Observable
28914 * Base class for layout managers.
28916 Roo.LayoutManager = function(container, config){
28917 Roo.LayoutManager.superclass.constructor.call(this);
28918 this.el = Roo.get(container);
28919 // ie scrollbar fix
28920 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28921 document.body.scroll = "no";
28922 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28923 this.el.position('relative');
28925 this.id = this.el.id;
28926 this.el.addClass("x-layout-container");
28927 /** false to disable window resize monitoring @type Boolean */
28928 this.monitorWindowResize = true;
28933 * Fires when a layout is performed.
28934 * @param {Roo.LayoutManager} this
28938 * @event regionresized
28939 * Fires when the user resizes a region.
28940 * @param {Roo.LayoutRegion} region The resized region
28941 * @param {Number} newSize The new size (width for east/west, height for north/south)
28943 "regionresized" : true,
28945 * @event regioncollapsed
28946 * Fires when a region is collapsed.
28947 * @param {Roo.LayoutRegion} region The collapsed region
28949 "regioncollapsed" : true,
28951 * @event regionexpanded
28952 * Fires when a region is expanded.
28953 * @param {Roo.LayoutRegion} region The expanded region
28955 "regionexpanded" : true
28957 this.updating = false;
28958 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28961 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28963 * Returns true if this layout is currently being updated
28964 * @return {Boolean}
28966 isUpdating : function(){
28967 return this.updating;
28971 * Suspend the LayoutManager from doing auto-layouts while
28972 * making multiple add or remove calls
28974 beginUpdate : function(){
28975 this.updating = true;
28979 * Restore auto-layouts and optionally disable the manager from performing a layout
28980 * @param {Boolean} noLayout true to disable a layout update
28982 endUpdate : function(noLayout){
28983 this.updating = false;
28989 layout: function(){
28993 onRegionResized : function(region, newSize){
28994 this.fireEvent("regionresized", region, newSize);
28998 onRegionCollapsed : function(region){
28999 this.fireEvent("regioncollapsed", region);
29002 onRegionExpanded : function(region){
29003 this.fireEvent("regionexpanded", region);
29007 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
29008 * performs box-model adjustments.
29009 * @return {Object} The size as an object {width: (the width), height: (the height)}
29011 getViewSize : function(){
29013 if(this.el.dom != document.body){
29014 size = this.el.getSize();
29016 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
29018 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
29019 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
29024 * Returns the Element this layout is bound to.
29025 * @return {Roo.Element}
29027 getEl : function(){
29032 * Returns the specified region.
29033 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
29034 * @return {Roo.LayoutRegion}
29036 getRegion : function(target){
29037 return this.regions[target.toLowerCase()];
29040 onWindowResize : function(){
29041 if(this.monitorWindowResize){
29047 * Ext JS Library 1.1.1
29048 * Copyright(c) 2006-2007, Ext JS, LLC.
29050 * Originally Released Under LGPL - original licence link has changed is not relivant.
29053 * <script type="text/javascript">
29056 * @class Roo.BorderLayout
29057 * @extends Roo.LayoutManager
29058 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
29059 * please see: <br><br>
29060 * <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>
29061 * <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>
29064 var layout = new Roo.BorderLayout(document.body, {
29098 preferredTabWidth: 150
29103 var CP = Roo.ContentPanel;
29105 layout.beginUpdate();
29106 layout.add("north", new CP("north", "North"));
29107 layout.add("south", new CP("south", {title: "South", closable: true}));
29108 layout.add("west", new CP("west", {title: "West"}));
29109 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
29110 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
29111 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
29112 layout.getRegion("center").showPanel("center1");
29113 layout.endUpdate();
29116 <b>The container the layout is rendered into can be either the body element or any other element.
29117 If it is not the body element, the container needs to either be an absolute positioned element,
29118 or you will need to add "position:relative" to the css of the container. You will also need to specify
29119 the container size if it is not the body element.</b>
29122 * Create a new BorderLayout
29123 * @param {String/HTMLElement/Element} container The container this layout is bound to
29124 * @param {Object} config Configuration options
29126 Roo.BorderLayout = function(container, config){
29127 config = config || {};
29128 Roo.BorderLayout.superclass.constructor.call(this, container, config);
29129 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
29130 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
29131 var target = this.factory.validRegions[i];
29132 if(config[target]){
29133 this.addRegion(target, config[target]);
29138 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
29140 * Creates and adds a new region if it doesn't already exist.
29141 * @param {String} target The target region key (north, south, east, west or center).
29142 * @param {Object} config The regions config object
29143 * @return {BorderLayoutRegion} The new region
29145 addRegion : function(target, config){
29146 if(!this.regions[target]){
29147 var r = this.factory.create(target, this, config);
29148 this.bindRegion(target, r);
29150 return this.regions[target];
29154 bindRegion : function(name, r){
29155 this.regions[name] = r;
29156 r.on("visibilitychange", this.layout, this);
29157 r.on("paneladded", this.layout, this);
29158 r.on("panelremoved", this.layout, this);
29159 r.on("invalidated", this.layout, this);
29160 r.on("resized", this.onRegionResized, this);
29161 r.on("collapsed", this.onRegionCollapsed, this);
29162 r.on("expanded", this.onRegionExpanded, this);
29166 * Performs a layout update.
29168 layout : function(){
29169 if(this.updating) return;
29170 var size = this.getViewSize();
29171 var w = size.width;
29172 var h = size.height;
29177 //var x = 0, y = 0;
29179 var rs = this.regions;
29180 var north = rs["north"];
29181 var south = rs["south"];
29182 var west = rs["west"];
29183 var east = rs["east"];
29184 var center = rs["center"];
29185 //if(this.hideOnLayout){ // not supported anymore
29186 //c.el.setStyle("display", "none");
29188 if(north && north.isVisible()){
29189 var b = north.getBox();
29190 var m = north.getMargins();
29191 b.width = w - (m.left+m.right);
29194 centerY = b.height + b.y + m.bottom;
29195 centerH -= centerY;
29196 north.updateBox(this.safeBox(b));
29198 if(south && south.isVisible()){
29199 var b = south.getBox();
29200 var m = south.getMargins();
29201 b.width = w - (m.left+m.right);
29203 var totalHeight = (b.height + m.top + m.bottom);
29204 b.y = h - totalHeight + m.top;
29205 centerH -= totalHeight;
29206 south.updateBox(this.safeBox(b));
29208 if(west && west.isVisible()){
29209 var b = west.getBox();
29210 var m = west.getMargins();
29211 b.height = centerH - (m.top+m.bottom);
29213 b.y = centerY + m.top;
29214 var totalWidth = (b.width + m.left + m.right);
29215 centerX += totalWidth;
29216 centerW -= totalWidth;
29217 west.updateBox(this.safeBox(b));
29219 if(east && east.isVisible()){
29220 var b = east.getBox();
29221 var m = east.getMargins();
29222 b.height = centerH - (m.top+m.bottom);
29223 var totalWidth = (b.width + m.left + m.right);
29224 b.x = w - totalWidth + m.left;
29225 b.y = centerY + m.top;
29226 centerW -= totalWidth;
29227 east.updateBox(this.safeBox(b));
29230 var m = center.getMargins();
29232 x: centerX + m.left,
29233 y: centerY + m.top,
29234 width: centerW - (m.left+m.right),
29235 height: centerH - (m.top+m.bottom)
29237 //if(this.hideOnLayout){
29238 //center.el.setStyle("display", "block");
29240 center.updateBox(this.safeBox(centerBox));
29243 this.fireEvent("layout", this);
29247 safeBox : function(box){
29248 box.width = Math.max(0, box.width);
29249 box.height = Math.max(0, box.height);
29254 * Adds a ContentPanel (or subclass) to this layout.
29255 * @param {String} target The target region key (north, south, east, west or center).
29256 * @param {Roo.ContentPanel} panel The panel to add
29257 * @return {Roo.ContentPanel} The added panel
29259 add : function(target, panel){
29261 target = target.toLowerCase();
29262 return this.regions[target].add(panel);
29266 * Remove a ContentPanel (or subclass) to this layout.
29267 * @param {String} target The target region key (north, south, east, west or center).
29268 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29269 * @return {Roo.ContentPanel} The removed panel
29271 remove : function(target, panel){
29272 target = target.toLowerCase();
29273 return this.regions[target].remove(panel);
29277 * Searches all regions for a panel with the specified id
29278 * @param {String} panelId
29279 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29281 findPanel : function(panelId){
29282 var rs = this.regions;
29283 for(var target in rs){
29284 if(typeof rs[target] != "function"){
29285 var p = rs[target].getPanel(panelId);
29295 * Searches all regions for a panel with the specified id and activates (shows) it.
29296 * @param {String/ContentPanel} panelId The panels id or the panel itself
29297 * @return {Roo.ContentPanel} The shown panel or null
29299 showPanel : function(panelId) {
29300 var rs = this.regions;
29301 for(var target in rs){
29302 var r = rs[target];
29303 if(typeof r != "function"){
29304 if(r.hasPanel(panelId)){
29305 return r.showPanel(panelId);
29313 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29314 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29316 restoreState : function(provider){
29318 provider = Roo.state.Manager;
29320 var sm = new Roo.LayoutStateManager();
29321 sm.init(this, provider);
29325 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29326 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29327 * a valid ContentPanel config object. Example:
29329 // Create the main layout
29330 var layout = new Roo.BorderLayout('main-ct', {
29341 // Create and add multiple ContentPanels at once via configs
29344 id: 'source-files',
29346 title:'Ext Source Files',
29359 * @param {Object} regions An object containing ContentPanel configs by region name
29361 batchAdd : function(regions){
29362 this.beginUpdate();
29363 for(var rname in regions){
29364 var lr = this.regions[rname];
29366 this.addTypedPanels(lr, regions[rname]);
29373 addTypedPanels : function(lr, ps){
29374 if(typeof ps == 'string'){
29375 lr.add(new Roo.ContentPanel(ps));
29377 else if(ps instanceof Array){
29378 for(var i =0, len = ps.length; i < len; i++){
29379 this.addTypedPanels(lr, ps[i]);
29382 else if(!ps.events){ // raw config?
29384 delete ps.el; // prevent conflict
29385 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29387 else { // panel object assumed!
29392 * Adds a xtype elements to the layout.
29396 xtype : 'ContentPanel',
29403 xtype : 'NestedLayoutPanel',
29409 items : [ ... list of content panels or nested layout panels.. ]
29413 * @param {Object} cfg Xtype definition of item to add.
29415 addxtype : function(cfg)
29417 // basically accepts a pannel...
29418 // can accept a layout region..!?!?
29419 // console.log('BorderLayout add ' + cfg.xtype)
29421 if (!cfg.xtype.match(/Panel$/)) {
29425 var region = cfg.region;
29431 xitems = cfg.items;
29438 case 'ContentPanel': // ContentPanel (el, cfg)
29439 case 'ScrollPanel': // ContentPanel (el, cfg)
29440 if(cfg.autoCreate) {
29441 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29443 var el = this.el.createChild();
29444 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29447 this.add(region, ret);
29451 case 'TreePanel': // our new panel!
29452 cfg.el = this.el.createChild();
29453 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29454 this.add(region, ret);
29457 case 'NestedLayoutPanel':
29458 // create a new Layout (which is a Border Layout...
29459 var el = this.el.createChild();
29460 var clayout = cfg.layout;
29462 clayout.items = clayout.items || [];
29463 // replace this exitems with the clayout ones..
29464 xitems = clayout.items;
29467 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29468 cfg.background = false;
29470 var layout = new Roo.BorderLayout(el, clayout);
29472 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29473 //console.log('adding nested layout panel ' + cfg.toSource());
29474 this.add(region, ret);
29480 // needs grid and region
29482 //var el = this.getRegion(region).el.createChild();
29483 var el = this.el.createChild();
29484 // create the grid first...
29486 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29488 if (region == 'center' && this.active ) {
29489 cfg.background = false;
29491 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29493 this.add(region, ret);
29494 if (cfg.background) {
29495 ret.on('activate', function(gp) {
29496 if (!gp.grid.rendered) {
29509 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29511 // GridPanel (grid, cfg)
29514 this.beginUpdate();
29516 Roo.each(xitems, function(i) {
29526 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29527 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29528 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29529 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29532 var CP = Roo.ContentPanel;
29534 var layout = Roo.BorderLayout.create({
29538 panels: [new CP("north", "North")]
29547 panels: [new CP("west", {title: "West"})]
29556 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29565 panels: [new CP("south", {title: "South", closable: true})]
29572 preferredTabWidth: 150,
29574 new CP("center1", {title: "Close Me", closable: true}),
29575 new CP("center2", {title: "Center Panel", closable: false})
29580 layout.getRegion("center").showPanel("center1");
29585 Roo.BorderLayout.create = function(config, targetEl){
29586 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29587 layout.beginUpdate();
29588 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29589 for(var j = 0, jlen = regions.length; j < jlen; j++){
29590 var lr = regions[j];
29591 if(layout.regions[lr] && config[lr].panels){
29592 var r = layout.regions[lr];
29593 var ps = config[lr].panels;
29594 layout.addTypedPanels(r, ps);
29597 layout.endUpdate();
29602 Roo.BorderLayout.RegionFactory = {
29604 validRegions : ["north","south","east","west","center"],
29607 create : function(target, mgr, config){
29608 target = target.toLowerCase();
29609 if(config.lightweight || config.basic){
29610 return new Roo.BasicLayoutRegion(mgr, config, target);
29614 return new Roo.NorthLayoutRegion(mgr, config);
29616 return new Roo.SouthLayoutRegion(mgr, config);
29618 return new Roo.EastLayoutRegion(mgr, config);
29620 return new Roo.WestLayoutRegion(mgr, config);
29622 return new Roo.CenterLayoutRegion(mgr, config);
29624 throw 'Layout region "'+target+'" not supported.';
29628 * Ext JS Library 1.1.1
29629 * Copyright(c) 2006-2007, Ext JS, LLC.
29631 * Originally Released Under LGPL - original licence link has changed is not relivant.
29634 * <script type="text/javascript">
29638 * @class Roo.BasicLayoutRegion
29639 * @extends Roo.util.Observable
29640 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29641 * and does not have a titlebar, tabs or any other features. All it does is size and position
29642 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29644 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29646 this.position = pos;
29649 * @scope Roo.BasicLayoutRegion
29653 * @event beforeremove
29654 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29655 * @param {Roo.LayoutRegion} this
29656 * @param {Roo.ContentPanel} panel The panel
29657 * @param {Object} e The cancel event object
29659 "beforeremove" : true,
29661 * @event invalidated
29662 * Fires when the layout for this region is changed.
29663 * @param {Roo.LayoutRegion} this
29665 "invalidated" : true,
29667 * @event visibilitychange
29668 * Fires when this region is shown or hidden
29669 * @param {Roo.LayoutRegion} this
29670 * @param {Boolean} visibility true or false
29672 "visibilitychange" : true,
29674 * @event paneladded
29675 * Fires when a panel is added.
29676 * @param {Roo.LayoutRegion} this
29677 * @param {Roo.ContentPanel} panel The panel
29679 "paneladded" : true,
29681 * @event panelremoved
29682 * Fires when a panel is removed.
29683 * @param {Roo.LayoutRegion} this
29684 * @param {Roo.ContentPanel} panel The panel
29686 "panelremoved" : true,
29689 * Fires when this region is collapsed.
29690 * @param {Roo.LayoutRegion} this
29692 "collapsed" : true,
29695 * Fires when this region is expanded.
29696 * @param {Roo.LayoutRegion} this
29701 * Fires when this region is slid into view.
29702 * @param {Roo.LayoutRegion} this
29704 "slideshow" : true,
29707 * Fires when this region slides out of view.
29708 * @param {Roo.LayoutRegion} this
29710 "slidehide" : true,
29712 * @event panelactivated
29713 * Fires when a panel is activated.
29714 * @param {Roo.LayoutRegion} this
29715 * @param {Roo.ContentPanel} panel The activated panel
29717 "panelactivated" : true,
29720 * Fires when the user resizes this region.
29721 * @param {Roo.LayoutRegion} this
29722 * @param {Number} newSize The new size (width for east/west, height for north/south)
29726 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29727 this.panels = new Roo.util.MixedCollection();
29728 this.panels.getKey = this.getPanelId.createDelegate(this);
29730 this.activePanel = null;
29731 // ensure listeners are added...
29733 if (config.listeners || config.events) {
29734 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29735 listeners : config.listeners || {},
29736 events : config.events || {}
29740 if(skipConfig !== true){
29741 this.applyConfig(config);
29745 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29746 getPanelId : function(p){
29750 applyConfig : function(config){
29751 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29752 this.config = config;
29757 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29758 * the width, for horizontal (north, south) the height.
29759 * @param {Number} newSize The new width or height
29761 resizeTo : function(newSize){
29762 var el = this.el ? this.el :
29763 (this.activePanel ? this.activePanel.getEl() : null);
29765 switch(this.position){
29768 el.setWidth(newSize);
29769 this.fireEvent("resized", this, newSize);
29773 el.setHeight(newSize);
29774 this.fireEvent("resized", this, newSize);
29780 getBox : function(){
29781 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29784 getMargins : function(){
29785 return this.margins;
29788 updateBox : function(box){
29790 var el = this.activePanel.getEl();
29791 el.dom.style.left = box.x + "px";
29792 el.dom.style.top = box.y + "px";
29793 this.activePanel.setSize(box.width, box.height);
29797 * Returns the container element for this region.
29798 * @return {Roo.Element}
29800 getEl : function(){
29801 return this.activePanel;
29805 * Returns true if this region is currently visible.
29806 * @return {Boolean}
29808 isVisible : function(){
29809 return this.activePanel ? true : false;
29812 setActivePanel : function(panel){
29813 panel = this.getPanel(panel);
29814 if(this.activePanel && this.activePanel != panel){
29815 this.activePanel.setActiveState(false);
29816 this.activePanel.getEl().setLeftTop(-10000,-10000);
29818 this.activePanel = panel;
29819 panel.setActiveState(true);
29821 panel.setSize(this.box.width, this.box.height);
29823 this.fireEvent("panelactivated", this, panel);
29824 this.fireEvent("invalidated");
29828 * Show the specified panel.
29829 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29830 * @return {Roo.ContentPanel} The shown panel or null
29832 showPanel : function(panel){
29833 if(panel = this.getPanel(panel)){
29834 this.setActivePanel(panel);
29840 * Get the active panel for this region.
29841 * @return {Roo.ContentPanel} The active panel or null
29843 getActivePanel : function(){
29844 return this.activePanel;
29848 * Add the passed ContentPanel(s)
29849 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29850 * @return {Roo.ContentPanel} The panel added (if only one was added)
29852 add : function(panel){
29853 if(arguments.length > 1){
29854 for(var i = 0, len = arguments.length; i < len; i++) {
29855 this.add(arguments[i]);
29859 if(this.hasPanel(panel)){
29860 this.showPanel(panel);
29863 var el = panel.getEl();
29864 if(el.dom.parentNode != this.mgr.el.dom){
29865 this.mgr.el.dom.appendChild(el.dom);
29867 if(panel.setRegion){
29868 panel.setRegion(this);
29870 this.panels.add(panel);
29871 el.setStyle("position", "absolute");
29872 if(!panel.background){
29873 this.setActivePanel(panel);
29874 if(this.config.initialSize && this.panels.getCount()==1){
29875 this.resizeTo(this.config.initialSize);
29878 this.fireEvent("paneladded", this, panel);
29883 * Returns true if the panel is in this region.
29884 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29885 * @return {Boolean}
29887 hasPanel : function(panel){
29888 if(typeof panel == "object"){ // must be panel obj
29889 panel = panel.getId();
29891 return this.getPanel(panel) ? true : false;
29895 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29896 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29897 * @param {Boolean} preservePanel Overrides the config preservePanel option
29898 * @return {Roo.ContentPanel} The panel that was removed
29900 remove : function(panel, preservePanel){
29901 panel = this.getPanel(panel);
29906 this.fireEvent("beforeremove", this, panel, e);
29907 if(e.cancel === true){
29910 var panelId = panel.getId();
29911 this.panels.removeKey(panelId);
29916 * Returns the panel specified or null if it's not in this region.
29917 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29918 * @return {Roo.ContentPanel}
29920 getPanel : function(id){
29921 if(typeof id == "object"){ // must be panel obj
29924 return this.panels.get(id);
29928 * Returns this regions position (north/south/east/west/center).
29931 getPosition: function(){
29932 return this.position;
29936 * Ext JS Library 1.1.1
29937 * Copyright(c) 2006-2007, Ext JS, LLC.
29939 * Originally Released Under LGPL - original licence link has changed is not relivant.
29942 * <script type="text/javascript">
29946 * @class Roo.LayoutRegion
29947 * @extends Roo.BasicLayoutRegion
29948 * This class represents a region in a layout manager.
29949 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29950 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29951 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29952 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29953 * @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})
29954 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29955 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29956 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29957 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29958 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29959 * @cfg {String} title The title for the region (overrides panel titles)
29960 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29961 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29962 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29963 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29964 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29965 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29966 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29967 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29968 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29969 * @cfg {Boolean} showPin True to show a pin button
29970 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29971 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29972 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29973 * @cfg {Number} width For East/West panels
29974 * @cfg {Number} height For North/South panels
29975 * @cfg {Boolean} split To show the splitter
29976 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
29978 Roo.LayoutRegion = function(mgr, config, pos){
29979 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29980 var dh = Roo.DomHelper;
29981 /** This region's container element
29982 * @type Roo.Element */
29983 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29984 /** This region's title element
29985 * @type Roo.Element */
29987 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29988 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29989 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29991 this.titleEl.enableDisplayMode();
29992 /** This region's title text element
29993 * @type HTMLElement */
29994 this.titleTextEl = this.titleEl.dom.firstChild;
29995 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29996 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29997 this.closeBtn.enableDisplayMode();
29998 this.closeBtn.on("click", this.closeClicked, this);
29999 this.closeBtn.hide();
30001 this.createBody(config);
30002 this.visible = true;
30003 this.collapsed = false;
30005 if(config.hideWhenEmpty){
30007 this.on("paneladded", this.validateVisibility, this);
30008 this.on("panelremoved", this.validateVisibility, this);
30010 this.applyConfig(config);
30013 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
30015 createBody : function(){
30016 /** This region's body element
30017 * @type Roo.Element */
30018 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
30021 applyConfig : function(c){
30022 if(c.collapsible && this.position != "center" && !this.collapsedEl){
30023 var dh = Roo.DomHelper;
30024 if(c.titlebar !== false){
30025 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
30026 this.collapseBtn.on("click", this.collapse, this);
30027 this.collapseBtn.enableDisplayMode();
30029 if(c.showPin === true || this.showPin){
30030 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
30031 this.stickBtn.enableDisplayMode();
30032 this.stickBtn.on("click", this.expand, this);
30033 this.stickBtn.hide();
30036 /** This region's collapsed element
30037 * @type Roo.Element */
30038 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
30039 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
30041 if(c.floatable !== false){
30042 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
30043 this.collapsedEl.on("click", this.collapseClick, this);
30046 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
30047 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
30048 id: "message", unselectable: "on", style:{"float":"left"}});
30049 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
30051 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
30052 this.expandBtn.on("click", this.expand, this);
30054 if(this.collapseBtn){
30055 this.collapseBtn.setVisible(c.collapsible == true);
30057 this.cmargins = c.cmargins || this.cmargins ||
30058 (this.position == "west" || this.position == "east" ?
30059 {top: 0, left: 2, right:2, bottom: 0} :
30060 {top: 2, left: 0, right:0, bottom: 2});
30061 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
30062 this.bottomTabs = c.tabPosition != "top";
30063 this.autoScroll = c.autoScroll || false;
30064 if(this.autoScroll){
30065 this.bodyEl.setStyle("overflow", "auto");
30067 this.bodyEl.setStyle("overflow", "hidden");
30069 //if(c.titlebar !== false){
30070 if((!c.titlebar && !c.title) || c.titlebar === false){
30071 this.titleEl.hide();
30073 this.titleEl.show();
30075 this.titleTextEl.innerHTML = c.title;
30079 this.duration = c.duration || .30;
30080 this.slideDuration = c.slideDuration || .45;
30083 this.collapse(true);
30090 * Returns true if this region is currently visible.
30091 * @return {Boolean}
30093 isVisible : function(){
30094 return this.visible;
30098 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
30099 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
30101 setCollapsedTitle : function(title){
30102 title = title || " ";
30103 if(this.collapsedTitleTextEl){
30104 this.collapsedTitleTextEl.innerHTML = title;
30108 getBox : function(){
30110 if(!this.collapsed){
30111 b = this.el.getBox(false, true);
30113 b = this.collapsedEl.getBox(false, true);
30118 getMargins : function(){
30119 return this.collapsed ? this.cmargins : this.margins;
30122 highlight : function(){
30123 this.el.addClass("x-layout-panel-dragover");
30126 unhighlight : function(){
30127 this.el.removeClass("x-layout-panel-dragover");
30130 updateBox : function(box){
30132 if(!this.collapsed){
30133 this.el.dom.style.left = box.x + "px";
30134 this.el.dom.style.top = box.y + "px";
30135 this.updateBody(box.width, box.height);
30137 this.collapsedEl.dom.style.left = box.x + "px";
30138 this.collapsedEl.dom.style.top = box.y + "px";
30139 this.collapsedEl.setSize(box.width, box.height);
30142 this.tabs.autoSizeTabs();
30146 updateBody : function(w, h){
30148 this.el.setWidth(w);
30149 w -= this.el.getBorderWidth("rl");
30150 if(this.config.adjustments){
30151 w += this.config.adjustments[0];
30155 this.el.setHeight(h);
30156 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
30157 h -= this.el.getBorderWidth("tb");
30158 if(this.config.adjustments){
30159 h += this.config.adjustments[1];
30161 this.bodyEl.setHeight(h);
30163 h = this.tabs.syncHeight(h);
30166 if(this.panelSize){
30167 w = w !== null ? w : this.panelSize.width;
30168 h = h !== null ? h : this.panelSize.height;
30170 if(this.activePanel){
30171 var el = this.activePanel.getEl();
30172 w = w !== null ? w : el.getWidth();
30173 h = h !== null ? h : el.getHeight();
30174 this.panelSize = {width: w, height: h};
30175 this.activePanel.setSize(w, h);
30177 if(Roo.isIE && this.tabs){
30178 this.tabs.el.repaint();
30183 * Returns the container element for this region.
30184 * @return {Roo.Element}
30186 getEl : function(){
30191 * Hides this region.
30194 if(!this.collapsed){
30195 this.el.dom.style.left = "-2000px";
30198 this.collapsedEl.dom.style.left = "-2000px";
30199 this.collapsedEl.hide();
30201 this.visible = false;
30202 this.fireEvent("visibilitychange", this, false);
30206 * Shows this region if it was previously hidden.
30209 if(!this.collapsed){
30212 this.collapsedEl.show();
30214 this.visible = true;
30215 this.fireEvent("visibilitychange", this, true);
30218 closeClicked : function(){
30219 if(this.activePanel){
30220 this.remove(this.activePanel);
30224 collapseClick : function(e){
30226 e.stopPropagation();
30229 e.stopPropagation();
30235 * Collapses this region.
30236 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
30238 collapse : function(skipAnim){
30239 if(this.collapsed) return;
30240 this.collapsed = true;
30242 this.split.el.hide();
30244 if(this.config.animate && skipAnim !== true){
30245 this.fireEvent("invalidated", this);
30246 this.animateCollapse();
30248 this.el.setLocation(-20000,-20000);
30250 this.collapsedEl.show();
30251 this.fireEvent("collapsed", this);
30252 this.fireEvent("invalidated", this);
30256 animateCollapse : function(){
30261 * Expands this region if it was previously collapsed.
30262 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
30263 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
30265 expand : function(e, skipAnim){
30266 if(e) e.stopPropagation();
30267 if(!this.collapsed || this.el.hasActiveFx()) return;
30269 this.afterSlideIn();
30272 this.collapsed = false;
30273 if(this.config.animate && skipAnim !== true){
30274 this.animateExpand();
30278 this.split.el.show();
30280 this.collapsedEl.setLocation(-2000,-2000);
30281 this.collapsedEl.hide();
30282 this.fireEvent("invalidated", this);
30283 this.fireEvent("expanded", this);
30287 animateExpand : function(){
30291 initTabs : function()
30293 this.bodyEl.setStyle("overflow", "hidden");
30294 var ts = new Roo.TabPanel(
30297 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30298 disableTooltips: this.config.disableTabTips,
30299 toolbar : this.config.toolbar
30302 if(this.config.hideTabs){
30303 ts.stripWrap.setDisplayed(false);
30306 ts.resizeTabs = this.config.resizeTabs === true;
30307 ts.minTabWidth = this.config.minTabWidth || 40;
30308 ts.maxTabWidth = this.config.maxTabWidth || 250;
30309 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30310 ts.monitorResize = false;
30311 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30312 ts.bodyEl.addClass('x-layout-tabs-body');
30313 this.panels.each(this.initPanelAsTab, this);
30316 initPanelAsTab : function(panel){
30317 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30318 this.config.closeOnTab && panel.isClosable());
30319 if(panel.tabTip !== undefined){
30320 ti.setTooltip(panel.tabTip);
30322 ti.on("activate", function(){
30323 this.setActivePanel(panel);
30325 if(this.config.closeOnTab){
30326 ti.on("beforeclose", function(t, e){
30328 this.remove(panel);
30334 updatePanelTitle : function(panel, title){
30335 if(this.activePanel == panel){
30336 this.updateTitle(title);
30339 var ti = this.tabs.getTab(panel.getEl().id);
30341 if(panel.tabTip !== undefined){
30342 ti.setTooltip(panel.tabTip);
30347 updateTitle : function(title){
30348 if(this.titleTextEl && !this.config.title){
30349 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30353 setActivePanel : function(panel){
30354 panel = this.getPanel(panel);
30355 if(this.activePanel && this.activePanel != panel){
30356 this.activePanel.setActiveState(false);
30358 this.activePanel = panel;
30359 panel.setActiveState(true);
30360 if(this.panelSize){
30361 panel.setSize(this.panelSize.width, this.panelSize.height);
30364 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30366 this.updateTitle(panel.getTitle());
30368 this.fireEvent("invalidated", this);
30370 this.fireEvent("panelactivated", this, panel);
30374 * Shows the specified panel.
30375 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30376 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30378 showPanel : function(panel){
30379 if(panel = this.getPanel(panel)){
30381 var tab = this.tabs.getTab(panel.getEl().id);
30382 if(tab.isHidden()){
30383 this.tabs.unhideTab(tab.id);
30387 this.setActivePanel(panel);
30394 * Get the active panel for this region.
30395 * @return {Roo.ContentPanel} The active panel or null
30397 getActivePanel : function(){
30398 return this.activePanel;
30401 validateVisibility : function(){
30402 if(this.panels.getCount() < 1){
30403 this.updateTitle(" ");
30404 this.closeBtn.hide();
30407 if(!this.isVisible()){
30414 * Adds the passed ContentPanel(s) to this region.
30415 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30416 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30418 add : function(panel){
30419 if(arguments.length > 1){
30420 for(var i = 0, len = arguments.length; i < len; i++) {
30421 this.add(arguments[i]);
30425 if(this.hasPanel(panel)){
30426 this.showPanel(panel);
30429 panel.setRegion(this);
30430 this.panels.add(panel);
30431 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30432 this.bodyEl.dom.appendChild(panel.getEl().dom);
30433 if(panel.background !== true){
30434 this.setActivePanel(panel);
30436 this.fireEvent("paneladded", this, panel);
30442 this.initPanelAsTab(panel);
30444 if(panel.background !== true){
30445 this.tabs.activate(panel.getEl().id);
30447 this.fireEvent("paneladded", this, panel);
30452 * Hides the tab for the specified panel.
30453 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30455 hidePanel : function(panel){
30456 if(this.tabs && (panel = this.getPanel(panel))){
30457 this.tabs.hideTab(panel.getEl().id);
30462 * Unhides the tab for a previously hidden panel.
30463 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30465 unhidePanel : function(panel){
30466 if(this.tabs && (panel = this.getPanel(panel))){
30467 this.tabs.unhideTab(panel.getEl().id);
30471 clearPanels : function(){
30472 while(this.panels.getCount() > 0){
30473 this.remove(this.panels.first());
30478 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30479 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30480 * @param {Boolean} preservePanel Overrides the config preservePanel option
30481 * @return {Roo.ContentPanel} The panel that was removed
30483 remove : function(panel, preservePanel){
30484 panel = this.getPanel(panel);
30489 this.fireEvent("beforeremove", this, panel, e);
30490 if(e.cancel === true){
30493 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30494 var panelId = panel.getId();
30495 this.panels.removeKey(panelId);
30497 document.body.appendChild(panel.getEl().dom);
30500 this.tabs.removeTab(panel.getEl().id);
30501 }else if (!preservePanel){
30502 this.bodyEl.dom.removeChild(panel.getEl().dom);
30504 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30505 var p = this.panels.first();
30506 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30507 tempEl.appendChild(p.getEl().dom);
30508 this.bodyEl.update("");
30509 this.bodyEl.dom.appendChild(p.getEl().dom);
30511 this.updateTitle(p.getTitle());
30513 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30514 this.setActivePanel(p);
30516 panel.setRegion(null);
30517 if(this.activePanel == panel){
30518 this.activePanel = null;
30520 if(this.config.autoDestroy !== false && preservePanel !== true){
30521 try{panel.destroy();}catch(e){}
30523 this.fireEvent("panelremoved", this, panel);
30528 * Returns the TabPanel component used by this region
30529 * @return {Roo.TabPanel}
30531 getTabs : function(){
30535 createTool : function(parentEl, className){
30536 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30537 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30538 btn.addClassOnOver("x-layout-tools-button-over");
30543 * Ext JS Library 1.1.1
30544 * Copyright(c) 2006-2007, Ext JS, LLC.
30546 * Originally Released Under LGPL - original licence link has changed is not relivant.
30549 * <script type="text/javascript">
30555 * @class Roo.SplitLayoutRegion
30556 * @extends Roo.LayoutRegion
30557 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30559 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30560 this.cursor = cursor;
30561 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30564 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30565 splitTip : "Drag to resize.",
30566 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30567 useSplitTips : false,
30569 applyConfig : function(config){
30570 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30573 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30574 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30575 /** The SplitBar for this region
30576 * @type Roo.SplitBar */
30577 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30578 this.split.on("moved", this.onSplitMove, this);
30579 this.split.useShim = config.useShim === true;
30580 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30581 if(this.useSplitTips){
30582 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30584 if(config.collapsible){
30585 this.split.el.on("dblclick", this.collapse, this);
30588 if(typeof config.minSize != "undefined"){
30589 this.split.minSize = config.minSize;
30591 if(typeof config.maxSize != "undefined"){
30592 this.split.maxSize = config.maxSize;
30594 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30595 this.hideSplitter();
30600 getHMaxSize : function(){
30601 var cmax = this.config.maxSize || 10000;
30602 var center = this.mgr.getRegion("center");
30603 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30606 getVMaxSize : function(){
30607 var cmax = this.config.maxSize || 10000;
30608 var center = this.mgr.getRegion("center");
30609 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30612 onSplitMove : function(split, newSize){
30613 this.fireEvent("resized", this, newSize);
30617 * Returns the {@link Roo.SplitBar} for this region.
30618 * @return {Roo.SplitBar}
30620 getSplitBar : function(){
30625 this.hideSplitter();
30626 Roo.SplitLayoutRegion.superclass.hide.call(this);
30629 hideSplitter : function(){
30631 this.split.el.setLocation(-2000,-2000);
30632 this.split.el.hide();
30638 this.split.el.show();
30640 Roo.SplitLayoutRegion.superclass.show.call(this);
30643 beforeSlide: function(){
30644 if(Roo.isGecko){// firefox overflow auto bug workaround
30645 this.bodyEl.clip();
30646 if(this.tabs) this.tabs.bodyEl.clip();
30647 if(this.activePanel){
30648 this.activePanel.getEl().clip();
30650 if(this.activePanel.beforeSlide){
30651 this.activePanel.beforeSlide();
30657 afterSlide : function(){
30658 if(Roo.isGecko){// firefox overflow auto bug workaround
30659 this.bodyEl.unclip();
30660 if(this.tabs) this.tabs.bodyEl.unclip();
30661 if(this.activePanel){
30662 this.activePanel.getEl().unclip();
30663 if(this.activePanel.afterSlide){
30664 this.activePanel.afterSlide();
30670 initAutoHide : function(){
30671 if(this.autoHide !== false){
30672 if(!this.autoHideHd){
30673 var st = new Roo.util.DelayedTask(this.slideIn, this);
30674 this.autoHideHd = {
30675 "mouseout": function(e){
30676 if(!e.within(this.el, true)){
30680 "mouseover" : function(e){
30686 this.el.on(this.autoHideHd);
30690 clearAutoHide : function(){
30691 if(this.autoHide !== false){
30692 this.el.un("mouseout", this.autoHideHd.mouseout);
30693 this.el.un("mouseover", this.autoHideHd.mouseover);
30697 clearMonitor : function(){
30698 Roo.get(document).un("click", this.slideInIf, this);
30701 // these names are backwards but not changed for compat
30702 slideOut : function(){
30703 if(this.isSlid || this.el.hasActiveFx()){
30706 this.isSlid = true;
30707 if(this.collapseBtn){
30708 this.collapseBtn.hide();
30710 this.closeBtnState = this.closeBtn.getStyle('display');
30711 this.closeBtn.hide();
30713 this.stickBtn.show();
30716 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30717 this.beforeSlide();
30718 this.el.setStyle("z-index", 10001);
30719 this.el.slideIn(this.getSlideAnchor(), {
30720 callback: function(){
30722 this.initAutoHide();
30723 Roo.get(document).on("click", this.slideInIf, this);
30724 this.fireEvent("slideshow", this);
30731 afterSlideIn : function(){
30732 this.clearAutoHide();
30733 this.isSlid = false;
30734 this.clearMonitor();
30735 this.el.setStyle("z-index", "");
30736 if(this.collapseBtn){
30737 this.collapseBtn.show();
30739 this.closeBtn.setStyle('display', this.closeBtnState);
30741 this.stickBtn.hide();
30743 this.fireEvent("slidehide", this);
30746 slideIn : function(cb){
30747 if(!this.isSlid || this.el.hasActiveFx()){
30751 this.isSlid = false;
30752 this.beforeSlide();
30753 this.el.slideOut(this.getSlideAnchor(), {
30754 callback: function(){
30755 this.el.setLeftTop(-10000, -10000);
30757 this.afterSlideIn();
30765 slideInIf : function(e){
30766 if(!e.within(this.el)){
30771 animateCollapse : function(){
30772 this.beforeSlide();
30773 this.el.setStyle("z-index", 20000);
30774 var anchor = this.getSlideAnchor();
30775 this.el.slideOut(anchor, {
30776 callback : function(){
30777 this.el.setStyle("z-index", "");
30778 this.collapsedEl.slideIn(anchor, {duration:.3});
30780 this.el.setLocation(-10000,-10000);
30782 this.fireEvent("collapsed", this);
30789 animateExpand : function(){
30790 this.beforeSlide();
30791 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30792 this.el.setStyle("z-index", 20000);
30793 this.collapsedEl.hide({
30796 this.el.slideIn(this.getSlideAnchor(), {
30797 callback : function(){
30798 this.el.setStyle("z-index", "");
30801 this.split.el.show();
30803 this.fireEvent("invalidated", this);
30804 this.fireEvent("expanded", this);
30832 getAnchor : function(){
30833 return this.anchors[this.position];
30836 getCollapseAnchor : function(){
30837 return this.canchors[this.position];
30840 getSlideAnchor : function(){
30841 return this.sanchors[this.position];
30844 getAlignAdj : function(){
30845 var cm = this.cmargins;
30846 switch(this.position){
30862 getExpandAdj : function(){
30863 var c = this.collapsedEl, cm = this.cmargins;
30864 switch(this.position){
30866 return [-(cm.right+c.getWidth()+cm.left), 0];
30869 return [cm.right+c.getWidth()+cm.left, 0];
30872 return [0, -(cm.top+cm.bottom+c.getHeight())];
30875 return [0, cm.top+cm.bottom+c.getHeight()];
30881 * Ext JS Library 1.1.1
30882 * Copyright(c) 2006-2007, Ext JS, LLC.
30884 * Originally Released Under LGPL - original licence link has changed is not relivant.
30887 * <script type="text/javascript">
30890 * These classes are private internal classes
30892 Roo.CenterLayoutRegion = function(mgr, config){
30893 Roo.LayoutRegion.call(this, mgr, config, "center");
30894 this.visible = true;
30895 this.minWidth = config.minWidth || 20;
30896 this.minHeight = config.minHeight || 20;
30899 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30901 // center panel can't be hidden
30905 // center panel can't be hidden
30908 getMinWidth: function(){
30909 return this.minWidth;
30912 getMinHeight: function(){
30913 return this.minHeight;
30918 Roo.NorthLayoutRegion = function(mgr, config){
30919 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30921 this.split.placement = Roo.SplitBar.TOP;
30922 this.split.orientation = Roo.SplitBar.VERTICAL;
30923 this.split.el.addClass("x-layout-split-v");
30925 var size = config.initialSize || config.height;
30926 if(typeof size != "undefined"){
30927 this.el.setHeight(size);
30930 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30931 orientation: Roo.SplitBar.VERTICAL,
30932 getBox : function(){
30933 if(this.collapsed){
30934 return this.collapsedEl.getBox();
30936 var box = this.el.getBox();
30938 box.height += this.split.el.getHeight();
30943 updateBox : function(box){
30944 if(this.split && !this.collapsed){
30945 box.height -= this.split.el.getHeight();
30946 this.split.el.setLeft(box.x);
30947 this.split.el.setTop(box.y+box.height);
30948 this.split.el.setWidth(box.width);
30950 if(this.collapsed){
30951 this.updateBody(box.width, null);
30953 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30957 Roo.SouthLayoutRegion = function(mgr, config){
30958 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30960 this.split.placement = Roo.SplitBar.BOTTOM;
30961 this.split.orientation = Roo.SplitBar.VERTICAL;
30962 this.split.el.addClass("x-layout-split-v");
30964 var size = config.initialSize || config.height;
30965 if(typeof size != "undefined"){
30966 this.el.setHeight(size);
30969 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30970 orientation: Roo.SplitBar.VERTICAL,
30971 getBox : function(){
30972 if(this.collapsed){
30973 return this.collapsedEl.getBox();
30975 var box = this.el.getBox();
30977 var sh = this.split.el.getHeight();
30984 updateBox : function(box){
30985 if(this.split && !this.collapsed){
30986 var sh = this.split.el.getHeight();
30989 this.split.el.setLeft(box.x);
30990 this.split.el.setTop(box.y-sh);
30991 this.split.el.setWidth(box.width);
30993 if(this.collapsed){
30994 this.updateBody(box.width, null);
30996 Roo.LayoutRegion.prototype.updateBox.call(this, box);
31000 Roo.EastLayoutRegion = function(mgr, config){
31001 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
31003 this.split.placement = Roo.SplitBar.RIGHT;
31004 this.split.orientation = Roo.SplitBar.HORIZONTAL;
31005 this.split.el.addClass("x-layout-split-h");
31007 var size = config.initialSize || config.width;
31008 if(typeof size != "undefined"){
31009 this.el.setWidth(size);
31012 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
31013 orientation: Roo.SplitBar.HORIZONTAL,
31014 getBox : function(){
31015 if(this.collapsed){
31016 return this.collapsedEl.getBox();
31018 var box = this.el.getBox();
31020 var sw = this.split.el.getWidth();
31027 updateBox : function(box){
31028 if(this.split && !this.collapsed){
31029 var sw = this.split.el.getWidth();
31031 this.split.el.setLeft(box.x);
31032 this.split.el.setTop(box.y);
31033 this.split.el.setHeight(box.height);
31036 if(this.collapsed){
31037 this.updateBody(null, box.height);
31039 Roo.LayoutRegion.prototype.updateBox.call(this, box);
31043 Roo.WestLayoutRegion = function(mgr, config){
31044 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
31046 this.split.placement = Roo.SplitBar.LEFT;
31047 this.split.orientation = Roo.SplitBar.HORIZONTAL;
31048 this.split.el.addClass("x-layout-split-h");
31050 var size = config.initialSize || config.width;
31051 if(typeof size != "undefined"){
31052 this.el.setWidth(size);
31055 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
31056 orientation: Roo.SplitBar.HORIZONTAL,
31057 getBox : function(){
31058 if(this.collapsed){
31059 return this.collapsedEl.getBox();
31061 var box = this.el.getBox();
31063 box.width += this.split.el.getWidth();
31068 updateBox : function(box){
31069 if(this.split && !this.collapsed){
31070 var sw = this.split.el.getWidth();
31072 this.split.el.setLeft(box.x+box.width);
31073 this.split.el.setTop(box.y);
31074 this.split.el.setHeight(box.height);
31076 if(this.collapsed){
31077 this.updateBody(null, box.height);
31079 Roo.LayoutRegion.prototype.updateBox.call(this, box);
31084 * Ext JS Library 1.1.1
31085 * Copyright(c) 2006-2007, Ext JS, LLC.
31087 * Originally Released Under LGPL - original licence link has changed is not relivant.
31090 * <script type="text/javascript">
31095 * Private internal class for reading and applying state
31097 Roo.LayoutStateManager = function(layout){
31098 // default empty state
31107 Roo.LayoutStateManager.prototype = {
31108 init : function(layout, provider){
31109 this.provider = provider;
31110 var state = provider.get(layout.id+"-layout-state");
31112 var wasUpdating = layout.isUpdating();
31114 layout.beginUpdate();
31116 for(var key in state){
31117 if(typeof state[key] != "function"){
31118 var rstate = state[key];
31119 var r = layout.getRegion(key);
31122 r.resizeTo(rstate.size);
31124 if(rstate.collapsed == true){
31127 r.expand(null, true);
31133 layout.endUpdate();
31135 this.state = state;
31137 this.layout = layout;
31138 layout.on("regionresized", this.onRegionResized, this);
31139 layout.on("regioncollapsed", this.onRegionCollapsed, this);
31140 layout.on("regionexpanded", this.onRegionExpanded, this);
31143 storeState : function(){
31144 this.provider.set(this.layout.id+"-layout-state", this.state);
31147 onRegionResized : function(region, newSize){
31148 this.state[region.getPosition()].size = newSize;
31152 onRegionCollapsed : function(region){
31153 this.state[region.getPosition()].collapsed = true;
31157 onRegionExpanded : function(region){
31158 this.state[region.getPosition()].collapsed = false;
31163 * Ext JS Library 1.1.1
31164 * Copyright(c) 2006-2007, Ext JS, LLC.
31166 * Originally Released Under LGPL - original licence link has changed is not relivant.
31169 * <script type="text/javascript">
31172 * @class Roo.ContentPanel
31173 * @extends Roo.util.Observable
31174 * A basic ContentPanel element.
31175 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
31176 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
31177 * @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
31178 * @cfg {Boolean} closable True if the panel can be closed/removed
31179 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
31180 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
31181 * @cfg {Toolbar} toolbar A toolbar for this panel
31182 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
31183 * @cfg {String} title The title for this panel
31184 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
31185 * @cfg {String} url Calls {@link #setUrl} with this value
31186 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
31187 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
31188 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
31189 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
31192 * Create a new ContentPanel.
31193 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
31194 * @param {String/Object} config A string to set only the title or a config object
31195 * @param {String} content (optional) Set the HTML content for this panel
31196 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
31198 Roo.ContentPanel = function(el, config, content){
31202 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
31206 if (config && config.parentLayout) {
31207 el = config.parentLayout.el.createChild();
31210 if(el.autoCreate){ // xtype is available if this is called from factory
31214 this.el = Roo.get(el);
31215 if(!this.el && config && config.autoCreate){
31216 if(typeof config.autoCreate == "object"){
31217 if(!config.autoCreate.id){
31218 config.autoCreate.id = config.id||el;
31220 this.el = Roo.DomHelper.append(document.body,
31221 config.autoCreate, true);
31223 this.el = Roo.DomHelper.append(document.body,
31224 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
31227 this.closable = false;
31228 this.loaded = false;
31229 this.active = false;
31230 if(typeof config == "string"){
31231 this.title = config;
31233 Roo.apply(this, config);
31236 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
31237 this.wrapEl = this.el.wrap();
31238 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
31245 this.resizeEl = Roo.get(this.resizeEl, true);
31247 this.resizeEl = this.el;
31252 * Fires when this panel is activated.
31253 * @param {Roo.ContentPanel} this
31257 * @event deactivate
31258 * Fires when this panel is activated.
31259 * @param {Roo.ContentPanel} this
31261 "deactivate" : true,
31265 * Fires when this panel is resized if fitToFrame is true.
31266 * @param {Roo.ContentPanel} this
31267 * @param {Number} width The width after any component adjustments
31268 * @param {Number} height The height after any component adjustments
31272 if(this.autoScroll){
31273 this.resizeEl.setStyle("overflow", "auto");
31275 // fix randome scrolling
31276 this.el.on('scroll', function() {
31277 Roo.log('fix random scolling');
31278 this.scrollTo('top',0);
31281 content = content || this.content;
31283 this.setContent(content);
31285 if(config && config.url){
31286 this.setUrl(this.url, this.params, this.loadOnce);
31291 Roo.ContentPanel.superclass.constructor.call(this);
31294 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31296 setRegion : function(region){
31297 this.region = region;
31299 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31301 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31306 * Returns the toolbar for this Panel if one was configured.
31307 * @return {Roo.Toolbar}
31309 getToolbar : function(){
31310 return this.toolbar;
31313 setActiveState : function(active){
31314 this.active = active;
31316 this.fireEvent("deactivate", this);
31318 this.fireEvent("activate", this);
31322 * Updates this panel's element
31323 * @param {String} content The new content
31324 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31326 setContent : function(content, loadScripts){
31327 this.el.update(content, loadScripts);
31330 ignoreResize : function(w, h){
31331 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31334 this.lastSize = {width: w, height: h};
31339 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31340 * @return {Roo.UpdateManager} The UpdateManager
31342 getUpdateManager : function(){
31343 return this.el.getUpdateManager();
31346 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31347 * @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:
31350 url: "your-url.php",
31351 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31352 callback: yourFunction,
31353 scope: yourObject, //(optional scope)
31356 text: "Loading...",
31361 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31362 * 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.
31363 * @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}
31364 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31365 * @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.
31366 * @return {Roo.ContentPanel} this
31369 var um = this.el.getUpdateManager();
31370 um.update.apply(um, arguments);
31376 * 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.
31377 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31378 * @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)
31379 * @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)
31380 * @return {Roo.UpdateManager} The UpdateManager
31382 setUrl : function(url, params, loadOnce){
31383 if(this.refreshDelegate){
31384 this.removeListener("activate", this.refreshDelegate);
31386 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31387 this.on("activate", this.refreshDelegate);
31388 return this.el.getUpdateManager();
31391 _handleRefresh : function(url, params, loadOnce){
31392 if(!loadOnce || !this.loaded){
31393 var updater = this.el.getUpdateManager();
31394 updater.update(url, params, this._setLoaded.createDelegate(this));
31398 _setLoaded : function(){
31399 this.loaded = true;
31403 * Returns this panel's id
31406 getId : function(){
31411 * Returns this panel's element - used by regiosn to add.
31412 * @return {Roo.Element}
31414 getEl : function(){
31415 return this.wrapEl || this.el;
31418 adjustForComponents : function(width, height){
31419 if(this.resizeEl != this.el){
31420 width -= this.el.getFrameWidth('lr');
31421 height -= this.el.getFrameWidth('tb');
31424 var te = this.toolbar.getEl();
31425 height -= te.getHeight();
31426 te.setWidth(width);
31428 if(this.adjustments){
31429 width += this.adjustments[0];
31430 height += this.adjustments[1];
31432 return {"width": width, "height": height};
31435 setSize : function(width, height){
31436 if(this.fitToFrame && !this.ignoreResize(width, height)){
31437 if(this.fitContainer && this.resizeEl != this.el){
31438 this.el.setSize(width, height);
31440 var size = this.adjustForComponents(width, height);
31441 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31442 this.fireEvent('resize', this, size.width, size.height);
31447 * Returns this panel's title
31450 getTitle : function(){
31455 * Set this panel's title
31456 * @param {String} title
31458 setTitle : function(title){
31459 this.title = title;
31461 this.region.updatePanelTitle(this, title);
31466 * Returns true is this panel was configured to be closable
31467 * @return {Boolean}
31469 isClosable : function(){
31470 return this.closable;
31473 beforeSlide : function(){
31475 this.resizeEl.clip();
31478 afterSlide : function(){
31480 this.resizeEl.unclip();
31484 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31485 * Will fail silently if the {@link #setUrl} method has not been called.
31486 * This does not activate the panel, just updates its content.
31488 refresh : function(){
31489 if(this.refreshDelegate){
31490 this.loaded = false;
31491 this.refreshDelegate();
31496 * Destroys this panel
31498 destroy : function(){
31499 this.el.removeAllListeners();
31500 var tempEl = document.createElement("span");
31501 tempEl.appendChild(this.el.dom);
31502 tempEl.innerHTML = "";
31508 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31518 * @param {Object} cfg Xtype definition of item to add.
31521 addxtype : function(cfg) {
31523 if (cfg.xtype.match(/^Form$/)) {
31524 var el = this.el.createChild();
31526 this.form = new Roo.form.Form(cfg);
31529 if ( this.form.allItems.length) this.form.render(el.dom);
31533 if (['View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
31535 cfg.el = this.el.appendChild(document.createElement("div"));
31537 var ret = new Roo[cfg.xtype](cfg);
31538 ret.render(false, ''); // render blank..
31548 * @class Roo.GridPanel
31549 * @extends Roo.ContentPanel
31551 * Create a new GridPanel.
31552 * @param {Roo.grid.Grid} grid The grid for this panel
31553 * @param {String/Object} config A string to set only the panel's title, or a config object
31555 Roo.GridPanel = function(grid, config){
31558 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31559 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31561 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31563 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31566 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31568 // xtype created footer. - not sure if will work as we normally have to render first..
31569 if (this.footer && !this.footer.el && this.footer.xtype) {
31571 this.footer.container = this.grid.getView().getFooterPanel(true);
31572 this.footer.dataSource = this.grid.dataSource;
31573 this.footer = Roo.factory(this.footer, Roo);
31577 grid.monitorWindowResize = false; // turn off autosizing
31578 grid.autoHeight = false;
31579 grid.autoWidth = false;
31581 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31584 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31585 getId : function(){
31586 return this.grid.id;
31590 * Returns the grid for this panel
31591 * @return {Roo.grid.Grid}
31593 getGrid : function(){
31597 setSize : function(width, height){
31598 if(!this.ignoreResize(width, height)){
31599 var grid = this.grid;
31600 var size = this.adjustForComponents(width, height);
31601 grid.getGridEl().setSize(size.width, size.height);
31606 beforeSlide : function(){
31607 this.grid.getView().scroller.clip();
31610 afterSlide : function(){
31611 this.grid.getView().scroller.unclip();
31614 destroy : function(){
31615 this.grid.destroy();
31617 Roo.GridPanel.superclass.destroy.call(this);
31623 * @class Roo.NestedLayoutPanel
31624 * @extends Roo.ContentPanel
31626 * Create a new NestedLayoutPanel.
31629 * @param {Roo.BorderLayout} layout The layout for this panel
31630 * @param {String/Object} config A string to set only the title or a config object
31632 Roo.NestedLayoutPanel = function(layout, config)
31634 // construct with only one argument..
31635 /* FIXME - implement nicer consturctors
31636 if (layout.layout) {
31638 layout = config.layout;
31639 delete config.layout;
31641 if (layout.xtype && !layout.getEl) {
31642 // then layout needs constructing..
31643 layout = Roo.factory(layout, Roo);
31648 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31650 layout.monitorWindowResize = false; // turn off autosizing
31651 this.layout = layout;
31652 this.layout.getEl().addClass("x-layout-nested-layout");
31659 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31661 setSize : function(width, height){
31662 if(!this.ignoreResize(width, height)){
31663 var size = this.adjustForComponents(width, height);
31664 var el = this.layout.getEl();
31665 el.setSize(size.width, size.height);
31666 var touch = el.dom.offsetWidth;
31667 this.layout.layout();
31668 // ie requires a double layout on the first pass
31669 if(Roo.isIE && !this.initialized){
31670 this.initialized = true;
31671 this.layout.layout();
31676 // activate all subpanels if not currently active..
31678 setActiveState : function(active){
31679 this.active = active;
31681 this.fireEvent("deactivate", this);
31685 this.fireEvent("activate", this);
31686 // not sure if this should happen before or after..
31687 if (!this.layout) {
31688 return; // should not happen..
31691 for (var r in this.layout.regions) {
31692 reg = this.layout.getRegion(r);
31693 if (reg.getActivePanel()) {
31694 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31695 reg.setActivePanel(reg.getActivePanel());
31698 if (!reg.panels.length) {
31701 reg.showPanel(reg.getPanel(0));
31710 * Returns the nested BorderLayout for this panel
31711 * @return {Roo.BorderLayout}
31713 getLayout : function(){
31714 return this.layout;
31718 * Adds a xtype elements to the layout of the nested panel
31722 xtype : 'ContentPanel',
31729 xtype : 'NestedLayoutPanel',
31735 items : [ ... list of content panels or nested layout panels.. ]
31739 * @param {Object} cfg Xtype definition of item to add.
31741 addxtype : function(cfg) {
31742 return this.layout.addxtype(cfg);
31747 Roo.ScrollPanel = function(el, config, content){
31748 config = config || {};
31749 config.fitToFrame = true;
31750 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31752 this.el.dom.style.overflow = "hidden";
31753 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31754 this.el.removeClass("x-layout-inactive-content");
31755 this.el.on("mousewheel", this.onWheel, this);
31757 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31758 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31759 up.unselectable(); down.unselectable();
31760 up.on("click", this.scrollUp, this);
31761 down.on("click", this.scrollDown, this);
31762 up.addClassOnOver("x-scroller-btn-over");
31763 down.addClassOnOver("x-scroller-btn-over");
31764 up.addClassOnClick("x-scroller-btn-click");
31765 down.addClassOnClick("x-scroller-btn-click");
31766 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31768 this.resizeEl = this.el;
31769 this.el = wrap; this.up = up; this.down = down;
31772 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31774 wheelIncrement : 5,
31775 scrollUp : function(){
31776 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31779 scrollDown : function(){
31780 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31783 afterScroll : function(){
31784 var el = this.resizeEl;
31785 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31786 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31787 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31790 setSize : function(){
31791 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31792 this.afterScroll();
31795 onWheel : function(e){
31796 var d = e.getWheelDelta();
31797 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31798 this.afterScroll();
31802 setContent : function(content, loadScripts){
31803 this.resizeEl.update(content, loadScripts);
31817 * @class Roo.TreePanel
31818 * @extends Roo.ContentPanel
31820 * Create a new TreePanel. - defaults to fit/scoll contents.
31821 * @param {String/Object} config A string to set only the panel's title, or a config object
31822 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31824 Roo.TreePanel = function(config){
31825 var el = config.el;
31826 var tree = config.tree;
31827 delete config.tree;
31828 delete config.el; // hopefull!
31830 // wrapper for IE7 strict & safari scroll issue
31832 var treeEl = el.createChild();
31833 config.resizeEl = treeEl;
31837 Roo.TreePanel.superclass.constructor.call(this, el, config);
31840 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31841 //console.log(tree);
31842 this.on('activate', function()
31844 if (this.tree.rendered) {
31847 //console.log('render tree');
31848 this.tree.render();
31851 this.on('resize', function (cp, w, h) {
31852 this.tree.innerCt.setWidth(w);
31853 this.tree.innerCt.setHeight(h);
31854 this.tree.innerCt.setStyle('overflow-y', 'auto');
31861 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31878 * Ext JS Library 1.1.1
31879 * Copyright(c) 2006-2007, Ext JS, LLC.
31881 * Originally Released Under LGPL - original licence link has changed is not relivant.
31884 * <script type="text/javascript">
31889 * @class Roo.ReaderLayout
31890 * @extends Roo.BorderLayout
31891 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31892 * center region containing two nested regions (a top one for a list view and one for item preview below),
31893 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31894 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31895 * expedites the setup of the overall layout and regions for this common application style.
31898 var reader = new Roo.ReaderLayout();
31899 var CP = Roo.ContentPanel; // shortcut for adding
31901 reader.beginUpdate();
31902 reader.add("north", new CP("north", "North"));
31903 reader.add("west", new CP("west", {title: "West"}));
31904 reader.add("east", new CP("east", {title: "East"}));
31906 reader.regions.listView.add(new CP("listView", "List"));
31907 reader.regions.preview.add(new CP("preview", "Preview"));
31908 reader.endUpdate();
31911 * Create a new ReaderLayout
31912 * @param {Object} config Configuration options
31913 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31914 * document.body if omitted)
31916 Roo.ReaderLayout = function(config, renderTo){
31917 var c = config || {size:{}};
31918 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31919 north: c.north !== false ? Roo.apply({
31923 }, c.north) : false,
31924 west: c.west !== false ? Roo.apply({
31932 margins:{left:5,right:0,bottom:5,top:5},
31933 cmargins:{left:5,right:5,bottom:5,top:5}
31934 }, c.west) : false,
31935 east: c.east !== false ? Roo.apply({
31943 margins:{left:0,right:5,bottom:5,top:5},
31944 cmargins:{left:5,right:5,bottom:5,top:5}
31945 }, c.east) : false,
31946 center: Roo.apply({
31947 tabPosition: 'top',
31951 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31955 this.el.addClass('x-reader');
31957 this.beginUpdate();
31959 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31960 south: c.preview !== false ? Roo.apply({
31967 cmargins:{top:5,left:0, right:0, bottom:0}
31968 }, c.preview) : false,
31969 center: Roo.apply({
31975 this.add('center', new Roo.NestedLayoutPanel(inner,
31976 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31980 this.regions.preview = inner.getRegion('south');
31981 this.regions.listView = inner.getRegion('center');
31984 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31986 * Ext JS Library 1.1.1
31987 * Copyright(c) 2006-2007, Ext JS, LLC.
31989 * Originally Released Under LGPL - original licence link has changed is not relivant.
31992 * <script type="text/javascript">
31996 * @class Roo.grid.Grid
31997 * @extends Roo.util.Observable
31998 * This class represents the primary interface of a component based grid control.
31999 * <br><br>Usage:<pre><code>
32000 var grid = new Roo.grid.Grid("my-container-id", {
32003 selModel: mySelectionModel,
32004 autoSizeColumns: true,
32005 monitorWindowResize: false,
32006 trackMouseOver: true
32011 * <b>Common Problems:</b><br/>
32012 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
32013 * element will correct this<br/>
32014 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
32015 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
32016 * are unpredictable.<br/>
32017 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
32018 * grid to calculate dimensions/offsets.<br/>
32020 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
32021 * The container MUST have some type of size defined for the grid to fill. The container will be
32022 * automatically set to position relative if it isn't already.
32023 * @param {Object} config A config object that sets properties on this grid.
32025 Roo.grid.Grid = function(container, config){
32026 // initialize the container
32027 this.container = Roo.get(container);
32028 this.container.update("");
32029 this.container.setStyle("overflow", "hidden");
32030 this.container.addClass('x-grid-container');
32032 this.id = this.container.id;
32034 Roo.apply(this, config);
32035 // check and correct shorthanded configs
32037 this.dataSource = this.ds;
32041 this.colModel = this.cm;
32045 this.selModel = this.sm;
32049 if (this.selModel) {
32050 this.selModel = Roo.factory(this.selModel, Roo.grid);
32051 this.sm = this.selModel;
32052 this.sm.xmodule = this.xmodule || false;
32054 if (typeof(this.colModel.config) == 'undefined') {
32055 this.colModel = new Roo.grid.ColumnModel(this.colModel);
32056 this.cm = this.colModel;
32057 this.cm.xmodule = this.xmodule || false;
32059 if (this.dataSource) {
32060 this.dataSource= Roo.factory(this.dataSource, Roo.data);
32061 this.ds = this.dataSource;
32062 this.ds.xmodule = this.xmodule || false;
32069 this.container.setWidth(this.width);
32073 this.container.setHeight(this.height);
32080 * The raw click event for the entire grid.
32081 * @param {Roo.EventObject} e
32086 * The raw dblclick event for the entire grid.
32087 * @param {Roo.EventObject} e
32091 * @event contextmenu
32092 * The raw contextmenu event for the entire grid.
32093 * @param {Roo.EventObject} e
32095 "contextmenu" : true,
32098 * The raw mousedown event for the entire grid.
32099 * @param {Roo.EventObject} e
32101 "mousedown" : true,
32104 * The raw mouseup event for the entire grid.
32105 * @param {Roo.EventObject} e
32110 * The raw mouseover event for the entire grid.
32111 * @param {Roo.EventObject} e
32113 "mouseover" : true,
32116 * The raw mouseout event for the entire grid.
32117 * @param {Roo.EventObject} e
32122 * The raw keypress event for the entire grid.
32123 * @param {Roo.EventObject} e
32128 * The raw keydown event for the entire grid.
32129 * @param {Roo.EventObject} e
32137 * Fires when a cell is clicked
32138 * @param {Grid} this
32139 * @param {Number} rowIndex
32140 * @param {Number} columnIndex
32141 * @param {Roo.EventObject} e
32143 "cellclick" : true,
32145 * @event celldblclick
32146 * Fires when a cell is double clicked
32147 * @param {Grid} this
32148 * @param {Number} rowIndex
32149 * @param {Number} columnIndex
32150 * @param {Roo.EventObject} e
32152 "celldblclick" : true,
32155 * Fires when a row is clicked
32156 * @param {Grid} this
32157 * @param {Number} rowIndex
32158 * @param {Roo.EventObject} e
32162 * @event rowdblclick
32163 * Fires when a row is double clicked
32164 * @param {Grid} this
32165 * @param {Number} rowIndex
32166 * @param {Roo.EventObject} e
32168 "rowdblclick" : true,
32170 * @event headerclick
32171 * Fires when a header is clicked
32172 * @param {Grid} this
32173 * @param {Number} columnIndex
32174 * @param {Roo.EventObject} e
32176 "headerclick" : true,
32178 * @event headerdblclick
32179 * Fires when a header cell is double clicked
32180 * @param {Grid} this
32181 * @param {Number} columnIndex
32182 * @param {Roo.EventObject} e
32184 "headerdblclick" : true,
32186 * @event rowcontextmenu
32187 * Fires when a row is right clicked
32188 * @param {Grid} this
32189 * @param {Number} rowIndex
32190 * @param {Roo.EventObject} e
32192 "rowcontextmenu" : true,
32194 * @event cellcontextmenu
32195 * Fires when a cell is right clicked
32196 * @param {Grid} this
32197 * @param {Number} rowIndex
32198 * @param {Number} cellIndex
32199 * @param {Roo.EventObject} e
32201 "cellcontextmenu" : true,
32203 * @event headercontextmenu
32204 * Fires when a header is right clicked
32205 * @param {Grid} this
32206 * @param {Number} columnIndex
32207 * @param {Roo.EventObject} e
32209 "headercontextmenu" : true,
32211 * @event bodyscroll
32212 * Fires when the body element is scrolled
32213 * @param {Number} scrollLeft
32214 * @param {Number} scrollTop
32216 "bodyscroll" : true,
32218 * @event columnresize
32219 * Fires when the user resizes a column
32220 * @param {Number} columnIndex
32221 * @param {Number} newSize
32223 "columnresize" : true,
32225 * @event columnmove
32226 * Fires when the user moves a column
32227 * @param {Number} oldIndex
32228 * @param {Number} newIndex
32230 "columnmove" : true,
32233 * Fires when row(s) start being dragged
32234 * @param {Grid} this
32235 * @param {Roo.GridDD} dd The drag drop object
32236 * @param {event} e The raw browser event
32238 "startdrag" : true,
32241 * Fires when a drag operation is complete
32242 * @param {Grid} this
32243 * @param {Roo.GridDD} dd The drag drop object
32244 * @param {event} e The raw browser event
32249 * Fires when dragged row(s) are dropped on a valid DD target
32250 * @param {Grid} this
32251 * @param {Roo.GridDD} dd The drag drop object
32252 * @param {String} targetId The target drag drop object
32253 * @param {event} e The raw browser event
32258 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
32259 * @param {Grid} this
32260 * @param {Roo.GridDD} dd The drag drop object
32261 * @param {String} targetId The target drag drop object
32262 * @param {event} e The raw browser event
32267 * Fires when the dragged row(s) first cross another DD target while being dragged
32268 * @param {Grid} this
32269 * @param {Roo.GridDD} dd The drag drop object
32270 * @param {String} targetId The target drag drop object
32271 * @param {event} e The raw browser event
32273 "dragenter" : true,
32276 * Fires when the dragged row(s) leave another DD target while being dragged
32277 * @param {Grid} this
32278 * @param {Roo.GridDD} dd The drag drop object
32279 * @param {String} targetId The target drag drop object
32280 * @param {event} e The raw browser event
32285 * Fires when a row is rendered, so you can change add a style to it.
32286 * @param {GridView} gridview The grid view
32287 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
32293 * Fires when the grid is rendered
32294 * @param {Grid} grid
32299 Roo.grid.Grid.superclass.constructor.call(this);
32301 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32304 * @cfg {String} ddGroup - drag drop group.
32308 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32310 minColumnWidth : 25,
32313 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32314 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32315 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32317 autoSizeColumns : false,
32320 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32322 autoSizeHeaders : true,
32325 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32327 monitorWindowResize : true,
32330 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32331 * rows measured to get a columns size. Default is 0 (all rows).
32333 maxRowsToMeasure : 0,
32336 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32338 trackMouseOver : true,
32341 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32345 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32347 enableDragDrop : false,
32350 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32352 enableColumnMove : true,
32355 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32357 enableColumnHide : true,
32360 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32362 enableRowHeightSync : false,
32365 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32370 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32372 autoHeight : false,
32375 * @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.
32377 autoExpandColumn : false,
32380 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32383 autoExpandMin : 50,
32386 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32388 autoExpandMax : 1000,
32391 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32396 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32400 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
32410 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32411 * of a fixed width. Default is false.
32414 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32417 * Called once after all setup has been completed and the grid is ready to be rendered.
32418 * @return {Roo.grid.Grid} this
32420 render : function()
32422 var c = this.container;
32423 // try to detect autoHeight/width mode
32424 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32425 this.autoHeight = true;
32427 var view = this.getView();
32430 c.on("click", this.onClick, this);
32431 c.on("dblclick", this.onDblClick, this);
32432 c.on("contextmenu", this.onContextMenu, this);
32433 c.on("keydown", this.onKeyDown, this);
32435 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32437 this.getSelectionModel().init(this);
32442 this.loadMask = new Roo.LoadMask(this.container,
32443 Roo.apply({store:this.dataSource}, this.loadMask));
32447 if (this.toolbar && this.toolbar.xtype) {
32448 this.toolbar.container = this.getView().getHeaderPanel(true);
32449 this.toolbar = new Roo.Toolbar(this.toolbar);
32451 if (this.footer && this.footer.xtype) {
32452 this.footer.dataSource = this.getDataSource();
32453 this.footer.container = this.getView().getFooterPanel(true);
32454 this.footer = Roo.factory(this.footer, Roo);
32456 if (this.dropTarget && this.dropTarget.xtype) {
32457 delete this.dropTarget.xtype;
32458 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
32462 this.rendered = true;
32463 this.fireEvent('render', this);
32468 * Reconfigures the grid to use a different Store and Column Model.
32469 * The View will be bound to the new objects and refreshed.
32470 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32471 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32473 reconfigure : function(dataSource, colModel){
32475 this.loadMask.destroy();
32476 this.loadMask = new Roo.LoadMask(this.container,
32477 Roo.apply({store:dataSource}, this.loadMask));
32479 this.view.bind(dataSource, colModel);
32480 this.dataSource = dataSource;
32481 this.colModel = colModel;
32482 this.view.refresh(true);
32486 onKeyDown : function(e){
32487 this.fireEvent("keydown", e);
32491 * Destroy this grid.
32492 * @param {Boolean} removeEl True to remove the element
32494 destroy : function(removeEl, keepListeners){
32496 this.loadMask.destroy();
32498 var c = this.container;
32499 c.removeAllListeners();
32500 this.view.destroy();
32501 this.colModel.purgeListeners();
32502 if(!keepListeners){
32503 this.purgeListeners();
32506 if(removeEl === true){
32512 processEvent : function(name, e){
32513 this.fireEvent(name, e);
32514 var t = e.getTarget();
32516 var header = v.findHeaderIndex(t);
32517 if(header !== false){
32518 this.fireEvent("header" + name, this, header, e);
32520 var row = v.findRowIndex(t);
32521 var cell = v.findCellIndex(t);
32523 this.fireEvent("row" + name, this, row, e);
32524 if(cell !== false){
32525 this.fireEvent("cell" + name, this, row, cell, e);
32532 onClick : function(e){
32533 this.processEvent("click", e);
32537 onContextMenu : function(e, t){
32538 this.processEvent("contextmenu", e);
32542 onDblClick : function(e){
32543 this.processEvent("dblclick", e);
32547 walkCells : function(row, col, step, fn, scope){
32548 var cm = this.colModel, clen = cm.getColumnCount();
32549 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32561 if(fn.call(scope || this, row, col, cm) === true){
32579 if(fn.call(scope || this, row, col, cm) === true){
32591 getSelections : function(){
32592 return this.selModel.getSelections();
32596 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32597 * but if manual update is required this method will initiate it.
32599 autoSize : function(){
32601 this.view.layout();
32602 if(this.view.adjustForScroll){
32603 this.view.adjustForScroll();
32609 * Returns the grid's underlying element.
32610 * @return {Element} The element
32612 getGridEl : function(){
32613 return this.container;
32616 // private for compatibility, overridden by editor grid
32617 stopEditing : function(){},
32620 * Returns the grid's SelectionModel.
32621 * @return {SelectionModel}
32623 getSelectionModel : function(){
32624 if(!this.selModel){
32625 this.selModel = new Roo.grid.RowSelectionModel();
32627 return this.selModel;
32631 * Returns the grid's DataSource.
32632 * @return {DataSource}
32634 getDataSource : function(){
32635 return this.dataSource;
32639 * Returns the grid's ColumnModel.
32640 * @return {ColumnModel}
32642 getColumnModel : function(){
32643 return this.colModel;
32647 * Returns the grid's GridView object.
32648 * @return {GridView}
32650 getView : function(){
32652 this.view = new Roo.grid.GridView(this.viewConfig);
32657 * Called to get grid's drag proxy text, by default returns this.ddText.
32660 getDragDropText : function(){
32661 var count = this.selModel.getCount();
32662 return String.format(this.ddText, count, count == 1 ? '' : 's');
32666 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32667 * %0 is replaced with the number of selected rows.
32670 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32672 * Ext JS Library 1.1.1
32673 * Copyright(c) 2006-2007, Ext JS, LLC.
32675 * Originally Released Under LGPL - original licence link has changed is not relivant.
32678 * <script type="text/javascript">
32681 Roo.grid.AbstractGridView = function(){
32685 "beforerowremoved" : true,
32686 "beforerowsinserted" : true,
32687 "beforerefresh" : true,
32688 "rowremoved" : true,
32689 "rowsinserted" : true,
32690 "rowupdated" : true,
32693 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32696 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32697 rowClass : "x-grid-row",
32698 cellClass : "x-grid-cell",
32699 tdClass : "x-grid-td",
32700 hdClass : "x-grid-hd",
32701 splitClass : "x-grid-hd-split",
32703 init: function(grid){
32705 var cid = this.grid.getGridEl().id;
32706 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32707 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32708 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32709 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32712 getColumnRenderers : function(){
32713 var renderers = [];
32714 var cm = this.grid.colModel;
32715 var colCount = cm.getColumnCount();
32716 for(var i = 0; i < colCount; i++){
32717 renderers[i] = cm.getRenderer(i);
32722 getColumnIds : function(){
32724 var cm = this.grid.colModel;
32725 var colCount = cm.getColumnCount();
32726 for(var i = 0; i < colCount; i++){
32727 ids[i] = cm.getColumnId(i);
32732 getDataIndexes : function(){
32733 if(!this.indexMap){
32734 this.indexMap = this.buildIndexMap();
32736 return this.indexMap.colToData;
32739 getColumnIndexByDataIndex : function(dataIndex){
32740 if(!this.indexMap){
32741 this.indexMap = this.buildIndexMap();
32743 return this.indexMap.dataToCol[dataIndex];
32747 * Set a css style for a column dynamically.
32748 * @param {Number} colIndex The index of the column
32749 * @param {String} name The css property name
32750 * @param {String} value The css value
32752 setCSSStyle : function(colIndex, name, value){
32753 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32754 Roo.util.CSS.updateRule(selector, name, value);
32757 generateRules : function(cm){
32758 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32759 Roo.util.CSS.removeStyleSheet(rulesId);
32760 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32761 var cid = cm.getColumnId(i);
32762 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32763 this.tdSelector, cid, " {\n}\n",
32764 this.hdSelector, cid, " {\n}\n",
32765 this.splitSelector, cid, " {\n}\n");
32767 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32771 * Ext JS Library 1.1.1
32772 * Copyright(c) 2006-2007, Ext JS, LLC.
32774 * Originally Released Under LGPL - original licence link has changed is not relivant.
32777 * <script type="text/javascript">
32781 // This is a support class used internally by the Grid components
32782 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32784 this.view = grid.getView();
32785 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32786 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32788 this.setHandleElId(Roo.id(hd));
32789 this.setOuterHandleElId(Roo.id(hd2));
32791 this.scroll = false;
32793 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32795 getDragData : function(e){
32796 var t = Roo.lib.Event.getTarget(e);
32797 var h = this.view.findHeaderCell(t);
32799 return {ddel: h.firstChild, header:h};
32804 onInitDrag : function(e){
32805 this.view.headersDisabled = true;
32806 var clone = this.dragData.ddel.cloneNode(true);
32807 clone.id = Roo.id();
32808 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32809 this.proxy.update(clone);
32813 afterValidDrop : function(){
32815 setTimeout(function(){
32816 v.headersDisabled = false;
32820 afterInvalidDrop : function(){
32822 setTimeout(function(){
32823 v.headersDisabled = false;
32829 * Ext JS Library 1.1.1
32830 * Copyright(c) 2006-2007, Ext JS, LLC.
32832 * Originally Released Under LGPL - original licence link has changed is not relivant.
32835 * <script type="text/javascript">
32838 // This is a support class used internally by the Grid components
32839 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32841 this.view = grid.getView();
32842 // split the proxies so they don't interfere with mouse events
32843 this.proxyTop = Roo.DomHelper.append(document.body, {
32844 cls:"col-move-top", html:" "
32846 this.proxyBottom = Roo.DomHelper.append(document.body, {
32847 cls:"col-move-bottom", html:" "
32849 this.proxyTop.hide = this.proxyBottom.hide = function(){
32850 this.setLeftTop(-100,-100);
32851 this.setStyle("visibility", "hidden");
32853 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32854 // temporarily disabled
32855 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32856 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32858 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32859 proxyOffsets : [-4, -9],
32860 fly: Roo.Element.fly,
32862 getTargetFromEvent : function(e){
32863 var t = Roo.lib.Event.getTarget(e);
32864 var cindex = this.view.findCellIndex(t);
32865 if(cindex !== false){
32866 return this.view.getHeaderCell(cindex);
32871 nextVisible : function(h){
32872 var v = this.view, cm = this.grid.colModel;
32875 if(!cm.isHidden(v.getCellIndex(h))){
32883 prevVisible : function(h){
32884 var v = this.view, cm = this.grid.colModel;
32887 if(!cm.isHidden(v.getCellIndex(h))){
32895 positionIndicator : function(h, n, e){
32896 var x = Roo.lib.Event.getPageX(e);
32897 var r = Roo.lib.Dom.getRegion(n.firstChild);
32898 var px, pt, py = r.top + this.proxyOffsets[1];
32899 if((r.right - x) <= (r.right-r.left)/2){
32900 px = r.right+this.view.borderWidth;
32906 var oldIndex = this.view.getCellIndex(h);
32907 var newIndex = this.view.getCellIndex(n);
32909 if(this.grid.colModel.isFixed(newIndex)){
32913 var locked = this.grid.colModel.isLocked(newIndex);
32918 if(oldIndex < newIndex){
32921 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32924 px += this.proxyOffsets[0];
32925 this.proxyTop.setLeftTop(px, py);
32926 this.proxyTop.show();
32927 if(!this.bottomOffset){
32928 this.bottomOffset = this.view.mainHd.getHeight();
32930 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32931 this.proxyBottom.show();
32935 onNodeEnter : function(n, dd, e, data){
32936 if(data.header != n){
32937 this.positionIndicator(data.header, n, e);
32941 onNodeOver : function(n, dd, e, data){
32942 var result = false;
32943 if(data.header != n){
32944 result = this.positionIndicator(data.header, n, e);
32947 this.proxyTop.hide();
32948 this.proxyBottom.hide();
32950 return result ? this.dropAllowed : this.dropNotAllowed;
32953 onNodeOut : function(n, dd, e, data){
32954 this.proxyTop.hide();
32955 this.proxyBottom.hide();
32958 onNodeDrop : function(n, dd, e, data){
32959 var h = data.header;
32961 var cm = this.grid.colModel;
32962 var x = Roo.lib.Event.getPageX(e);
32963 var r = Roo.lib.Dom.getRegion(n.firstChild);
32964 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32965 var oldIndex = this.view.getCellIndex(h);
32966 var newIndex = this.view.getCellIndex(n);
32967 var locked = cm.isLocked(newIndex);
32971 if(oldIndex < newIndex){
32974 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32977 cm.setLocked(oldIndex, locked, true);
32978 cm.moveColumn(oldIndex, newIndex);
32979 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32987 * Ext JS Library 1.1.1
32988 * Copyright(c) 2006-2007, Ext JS, LLC.
32990 * Originally Released Under LGPL - original licence link has changed is not relivant.
32993 * <script type="text/javascript">
32997 * @class Roo.grid.GridView
32998 * @extends Roo.util.Observable
33001 * @param {Object} config
33003 Roo.grid.GridView = function(config){
33004 Roo.grid.GridView.superclass.constructor.call(this);
33007 Roo.apply(this, config);
33010 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
33013 * Override this function to apply custom css classes to rows during rendering
33014 * @param {Record} record The record
33015 * @param {Number} index
33016 * @method getRowClass
33018 rowClass : "x-grid-row",
33020 cellClass : "x-grid-col",
33022 tdClass : "x-grid-td",
33024 hdClass : "x-grid-hd",
33026 splitClass : "x-grid-split",
33028 sortClasses : ["sort-asc", "sort-desc"],
33030 enableMoveAnim : false,
33034 dh : Roo.DomHelper,
33036 fly : Roo.Element.fly,
33038 css : Roo.util.CSS,
33044 scrollIncrement : 22,
33046 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
33048 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
33050 bind : function(ds, cm){
33052 this.ds.un("load", this.onLoad, this);
33053 this.ds.un("datachanged", this.onDataChange, this);
33054 this.ds.un("add", this.onAdd, this);
33055 this.ds.un("remove", this.onRemove, this);
33056 this.ds.un("update", this.onUpdate, this);
33057 this.ds.un("clear", this.onClear, this);
33060 ds.on("load", this.onLoad, this);
33061 ds.on("datachanged", this.onDataChange, this);
33062 ds.on("add", this.onAdd, this);
33063 ds.on("remove", this.onRemove, this);
33064 ds.on("update", this.onUpdate, this);
33065 ds.on("clear", this.onClear, this);
33070 this.cm.un("widthchange", this.onColWidthChange, this);
33071 this.cm.un("headerchange", this.onHeaderChange, this);
33072 this.cm.un("hiddenchange", this.onHiddenChange, this);
33073 this.cm.un("columnmoved", this.onColumnMove, this);
33074 this.cm.un("columnlockchange", this.onColumnLock, this);
33077 this.generateRules(cm);
33078 cm.on("widthchange", this.onColWidthChange, this);
33079 cm.on("headerchange", this.onHeaderChange, this);
33080 cm.on("hiddenchange", this.onHiddenChange, this);
33081 cm.on("columnmoved", this.onColumnMove, this);
33082 cm.on("columnlockchange", this.onColumnLock, this);
33087 init: function(grid){
33088 Roo.grid.GridView.superclass.init.call(this, grid);
33090 this.bind(grid.dataSource, grid.colModel);
33092 grid.on("headerclick", this.handleHeaderClick, this);
33094 if(grid.trackMouseOver){
33095 grid.on("mouseover", this.onRowOver, this);
33096 grid.on("mouseout", this.onRowOut, this);
33098 grid.cancelTextSelection = function(){};
33099 this.gridId = grid.id;
33101 var tpls = this.templates || {};
33104 tpls.master = new Roo.Template(
33105 '<div class="x-grid" hidefocus="true">',
33106 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
33107 '<div class="x-grid-topbar"></div>',
33108 '<div class="x-grid-scroller"><div></div></div>',
33109 '<div class="x-grid-locked">',
33110 '<div class="x-grid-header">{lockedHeader}</div>',
33111 '<div class="x-grid-body">{lockedBody}</div>',
33113 '<div class="x-grid-viewport">',
33114 '<div class="x-grid-header">{header}</div>',
33115 '<div class="x-grid-body">{body}</div>',
33117 '<div class="x-grid-bottombar"></div>',
33119 '<div class="x-grid-resize-proxy"> </div>',
33122 tpls.master.disableformats = true;
33126 tpls.header = new Roo.Template(
33127 '<table border="0" cellspacing="0" cellpadding="0">',
33128 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
33131 tpls.header.disableformats = true;
33133 tpls.header.compile();
33136 tpls.hcell = new Roo.Template(
33137 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
33138 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
33141 tpls.hcell.disableFormats = true;
33143 tpls.hcell.compile();
33146 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
33147 tpls.hsplit.disableFormats = true;
33149 tpls.hsplit.compile();
33152 tpls.body = new Roo.Template(
33153 '<table border="0" cellspacing="0" cellpadding="0">',
33154 "<tbody>{rows}</tbody>",
33157 tpls.body.disableFormats = true;
33159 tpls.body.compile();
33162 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
33163 tpls.row.disableFormats = true;
33165 tpls.row.compile();
33168 tpls.cell = new Roo.Template(
33169 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
33170 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
33173 tpls.cell.disableFormats = true;
33175 tpls.cell.compile();
33177 this.templates = tpls;
33180 // remap these for backwards compat
33181 onColWidthChange : function(){
33182 this.updateColumns.apply(this, arguments);
33184 onHeaderChange : function(){
33185 this.updateHeaders.apply(this, arguments);
33187 onHiddenChange : function(){
33188 this.handleHiddenChange.apply(this, arguments);
33190 onColumnMove : function(){
33191 this.handleColumnMove.apply(this, arguments);
33193 onColumnLock : function(){
33194 this.handleLockChange.apply(this, arguments);
33197 onDataChange : function(){
33199 this.updateHeaderSortState();
33202 onClear : function(){
33206 onUpdate : function(ds, record){
33207 this.refreshRow(record);
33210 refreshRow : function(record){
33211 var ds = this.ds, index;
33212 if(typeof record == 'number'){
33214 record = ds.getAt(index);
33216 index = ds.indexOf(record);
33218 this.insertRows(ds, index, index, true);
33219 this.onRemove(ds, record, index+1, true);
33220 this.syncRowHeights(index, index);
33222 this.fireEvent("rowupdated", this, index, record);
33225 onAdd : function(ds, records, index){
33226 this.insertRows(ds, index, index + (records.length-1));
33229 onRemove : function(ds, record, index, isUpdate){
33230 if(isUpdate !== true){
33231 this.fireEvent("beforerowremoved", this, index, record);
33233 var bt = this.getBodyTable(), lt = this.getLockedTable();
33234 if(bt.rows[index]){
33235 bt.firstChild.removeChild(bt.rows[index]);
33237 if(lt.rows[index]){
33238 lt.firstChild.removeChild(lt.rows[index]);
33240 if(isUpdate !== true){
33241 this.stripeRows(index);
33242 this.syncRowHeights(index, index);
33244 this.fireEvent("rowremoved", this, index, record);
33248 onLoad : function(){
33249 this.scrollToTop();
33253 * Scrolls the grid to the top
33255 scrollToTop : function(){
33257 this.scroller.dom.scrollTop = 0;
33263 * Gets a panel in the header of the grid that can be used for toolbars etc.
33264 * After modifying the contents of this panel a call to grid.autoSize() may be
33265 * required to register any changes in size.
33266 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
33267 * @return Roo.Element
33269 getHeaderPanel : function(doShow){
33271 this.headerPanel.show();
33273 return this.headerPanel;
33277 * Gets a panel in the footer of the grid that can be used for toolbars etc.
33278 * After modifying the contents of this panel a call to grid.autoSize() may be
33279 * required to register any changes in size.
33280 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
33281 * @return Roo.Element
33283 getFooterPanel : function(doShow){
33285 this.footerPanel.show();
33287 return this.footerPanel;
33290 initElements : function(){
33291 var E = Roo.Element;
33292 var el = this.grid.getGridEl().dom.firstChild;
33293 var cs = el.childNodes;
33295 this.el = new E(el);
33297 this.focusEl = new E(el.firstChild);
33298 this.focusEl.swallowEvent("click", true);
33300 this.headerPanel = new E(cs[1]);
33301 this.headerPanel.enableDisplayMode("block");
33303 this.scroller = new E(cs[2]);
33304 this.scrollSizer = new E(this.scroller.dom.firstChild);
33306 this.lockedWrap = new E(cs[3]);
33307 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33308 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33310 this.mainWrap = new E(cs[4]);
33311 this.mainHd = new E(this.mainWrap.dom.firstChild);
33312 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33314 this.footerPanel = new E(cs[5]);
33315 this.footerPanel.enableDisplayMode("block");
33317 this.resizeProxy = new E(cs[6]);
33319 this.headerSelector = String.format(
33320 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33321 this.lockedHd.id, this.mainHd.id
33324 this.splitterSelector = String.format(
33325 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33326 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33329 idToCssName : function(s)
33331 return s.replace(/[^a-z0-9]+/ig, '-');
33334 getHeaderCell : function(index){
33335 return Roo.DomQuery.select(this.headerSelector)[index];
33338 getHeaderCellMeasure : function(index){
33339 return this.getHeaderCell(index).firstChild;
33342 getHeaderCellText : function(index){
33343 return this.getHeaderCell(index).firstChild.firstChild;
33346 getLockedTable : function(){
33347 return this.lockedBody.dom.firstChild;
33350 getBodyTable : function(){
33351 return this.mainBody.dom.firstChild;
33354 getLockedRow : function(index){
33355 return this.getLockedTable().rows[index];
33358 getRow : function(index){
33359 return this.getBodyTable().rows[index];
33362 getRowComposite : function(index){
33364 this.rowEl = new Roo.CompositeElementLite();
33366 var els = [], lrow, mrow;
33367 if(lrow = this.getLockedRow(index)){
33370 if(mrow = this.getRow(index)){
33373 this.rowEl.elements = els;
33377 getCell : function(rowIndex, colIndex){
33378 var locked = this.cm.getLockedCount();
33380 if(colIndex < locked){
33381 source = this.lockedBody.dom.firstChild;
33383 source = this.mainBody.dom.firstChild;
33384 colIndex -= locked;
33386 return source.rows[rowIndex].childNodes[colIndex];
33389 getCellText : function(rowIndex, colIndex){
33390 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33393 getCellBox : function(cell){
33394 var b = this.fly(cell).getBox();
33395 if(Roo.isOpera){ // opera fails to report the Y
33396 b.y = cell.offsetTop + this.mainBody.getY();
33401 getCellIndex : function(cell){
33402 var id = String(cell.className).match(this.cellRE);
33404 return parseInt(id[1], 10);
33409 findHeaderIndex : function(n){
33410 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33411 return r ? this.getCellIndex(r) : false;
33414 findHeaderCell : function(n){
33415 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33416 return r ? r : false;
33419 findRowIndex : function(n){
33423 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33424 return r ? r.rowIndex : false;
33427 findCellIndex : function(node){
33428 var stop = this.el.dom;
33429 while(node && node != stop){
33430 if(this.findRE.test(node.className)){
33431 return this.getCellIndex(node);
33433 node = node.parentNode;
33438 getColumnId : function(index){
33439 return this.cm.getColumnId(index);
33442 getSplitters : function()
33444 if(this.splitterSelector){
33445 return Roo.DomQuery.select(this.splitterSelector);
33451 getSplitter : function(index){
33452 return this.getSplitters()[index];
33455 onRowOver : function(e, t){
33457 if((row = this.findRowIndex(t)) !== false){
33458 this.getRowComposite(row).addClass("x-grid-row-over");
33462 onRowOut : function(e, t){
33464 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33465 this.getRowComposite(row).removeClass("x-grid-row-over");
33469 renderHeaders : function(){
33471 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33472 var cb = [], lb = [], sb = [], lsb = [], p = {};
33473 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33474 p.cellId = "x-grid-hd-0-" + i;
33475 p.splitId = "x-grid-csplit-0-" + i;
33476 p.id = cm.getColumnId(i);
33477 p.title = cm.getColumnTooltip(i) || "";
33478 p.value = cm.getColumnHeader(i) || "";
33479 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33480 if(!cm.isLocked(i)){
33481 cb[cb.length] = ct.apply(p);
33482 sb[sb.length] = st.apply(p);
33484 lb[lb.length] = ct.apply(p);
33485 lsb[lsb.length] = st.apply(p);
33488 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33489 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33492 updateHeaders : function(){
33493 var html = this.renderHeaders();
33494 this.lockedHd.update(html[0]);
33495 this.mainHd.update(html[1]);
33499 * Focuses the specified row.
33500 * @param {Number} row The row index
33502 focusRow : function(row)
33504 //Roo.log('GridView.focusRow');
33505 var x = this.scroller.dom.scrollLeft;
33506 this.focusCell(row, 0, false);
33507 this.scroller.dom.scrollLeft = x;
33511 * Focuses the specified cell.
33512 * @param {Number} row The row index
33513 * @param {Number} col The column index
33514 * @param {Boolean} hscroll false to disable horizontal scrolling
33516 focusCell : function(row, col, hscroll)
33518 //Roo.log('GridView.focusCell');
33519 var el = this.ensureVisible(row, col, hscroll);
33520 this.focusEl.alignTo(el, "tl-tl");
33522 this.focusEl.focus();
33524 this.focusEl.focus.defer(1, this.focusEl);
33529 * Scrolls the specified cell into view
33530 * @param {Number} row The row index
33531 * @param {Number} col The column index
33532 * @param {Boolean} hscroll false to disable horizontal scrolling
33534 ensureVisible : function(row, col, hscroll)
33536 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
33537 //return null; //disable for testing.
33538 if(typeof row != "number"){
33539 row = row.rowIndex;
33541 if(row < 0 && row >= this.ds.getCount()){
33544 col = (col !== undefined ? col : 0);
33545 var cm = this.grid.colModel;
33546 while(cm.isHidden(col)){
33550 var el = this.getCell(row, col);
33554 var c = this.scroller.dom;
33556 var ctop = parseInt(el.offsetTop, 10);
33557 var cleft = parseInt(el.offsetLeft, 10);
33558 var cbot = ctop + el.offsetHeight;
33559 var cright = cleft + el.offsetWidth;
33561 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33562 var stop = parseInt(c.scrollTop, 10);
33563 var sleft = parseInt(c.scrollLeft, 10);
33564 var sbot = stop + ch;
33565 var sright = sleft + c.clientWidth;
33567 Roo.log('GridView.ensureVisible:' +
33569 ' c.clientHeight:' + c.clientHeight +
33570 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
33578 c.scrollTop = ctop;
33579 //Roo.log("set scrolltop to ctop DISABLE?");
33580 }else if(cbot > sbot){
33581 //Roo.log("set scrolltop to cbot-ch");
33582 c.scrollTop = cbot-ch;
33585 if(hscroll !== false){
33587 c.scrollLeft = cleft;
33588 }else if(cright > sright){
33589 c.scrollLeft = cright-c.clientWidth;
33596 updateColumns : function(){
33597 this.grid.stopEditing();
33598 var cm = this.grid.colModel, colIds = this.getColumnIds();
33599 //var totalWidth = cm.getTotalWidth();
33601 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33602 //if(cm.isHidden(i)) continue;
33603 var w = cm.getColumnWidth(i);
33604 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33605 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33607 this.updateSplitters();
33610 generateRules : function(cm){
33611 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33612 Roo.util.CSS.removeStyleSheet(rulesId);
33613 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33614 var cid = cm.getColumnId(i);
33616 if(cm.config[i].align){
33617 align = 'text-align:'+cm.config[i].align+';';
33620 if(cm.isHidden(i)){
33621 hidden = 'display:none;';
33623 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33625 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33626 this.hdSelector, cid, " {\n", align, width, "}\n",
33627 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33628 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33630 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33633 updateSplitters : function(){
33634 var cm = this.cm, s = this.getSplitters();
33635 if(s){ // splitters not created yet
33636 var pos = 0, locked = true;
33637 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33638 if(cm.isHidden(i)) continue;
33639 var w = cm.getColumnWidth(i); // make sure it's a number
33640 if(!cm.isLocked(i) && locked){
33645 s[i].style.left = (pos-this.splitOffset) + "px";
33650 handleHiddenChange : function(colModel, colIndex, hidden){
33652 this.hideColumn(colIndex);
33654 this.unhideColumn(colIndex);
33658 hideColumn : function(colIndex){
33659 var cid = this.getColumnId(colIndex);
33660 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33661 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33663 this.updateHeaders();
33665 this.updateSplitters();
33669 unhideColumn : function(colIndex){
33670 var cid = this.getColumnId(colIndex);
33671 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33672 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33675 this.updateHeaders();
33677 this.updateSplitters();
33681 insertRows : function(dm, firstRow, lastRow, isUpdate){
33682 if(firstRow == 0 && lastRow == dm.getCount()-1){
33686 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33688 var s = this.getScrollState();
33689 var markup = this.renderRows(firstRow, lastRow);
33690 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33691 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33692 this.restoreScroll(s);
33694 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33695 this.syncRowHeights(firstRow, lastRow);
33696 this.stripeRows(firstRow);
33702 bufferRows : function(markup, target, index){
33703 var before = null, trows = target.rows, tbody = target.tBodies[0];
33704 if(index < trows.length){
33705 before = trows[index];
33707 var b = document.createElement("div");
33708 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33709 var rows = b.firstChild.rows;
33710 for(var i = 0, len = rows.length; i < len; i++){
33712 tbody.insertBefore(rows[0], before);
33714 tbody.appendChild(rows[0]);
33721 deleteRows : function(dm, firstRow, lastRow){
33722 if(dm.getRowCount()<1){
33723 this.fireEvent("beforerefresh", this);
33724 this.mainBody.update("");
33725 this.lockedBody.update("");
33726 this.fireEvent("refresh", this);
33728 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33729 var bt = this.getBodyTable();
33730 var tbody = bt.firstChild;
33731 var rows = bt.rows;
33732 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33733 tbody.removeChild(rows[firstRow]);
33735 this.stripeRows(firstRow);
33736 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33740 updateRows : function(dataSource, firstRow, lastRow){
33741 var s = this.getScrollState();
33743 this.restoreScroll(s);
33746 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33750 this.updateHeaderSortState();
33753 getScrollState : function(){
33755 var sb = this.scroller.dom;
33756 return {left: sb.scrollLeft, top: sb.scrollTop};
33759 stripeRows : function(startRow){
33760 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33763 startRow = startRow || 0;
33764 var rows = this.getBodyTable().rows;
33765 var lrows = this.getLockedTable().rows;
33766 var cls = ' x-grid-row-alt ';
33767 for(var i = startRow, len = rows.length; i < len; i++){
33768 var row = rows[i], lrow = lrows[i];
33769 var isAlt = ((i+1) % 2 == 0);
33770 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33771 if(isAlt == hasAlt){
33775 row.className += " x-grid-row-alt";
33777 row.className = row.className.replace("x-grid-row-alt", "");
33780 lrow.className = row.className;
33785 restoreScroll : function(state){
33786 //Roo.log('GridView.restoreScroll');
33787 var sb = this.scroller.dom;
33788 sb.scrollLeft = state.left;
33789 sb.scrollTop = state.top;
33793 syncScroll : function(){
33794 //Roo.log('GridView.syncScroll');
33795 var sb = this.scroller.dom;
33796 var sh = this.mainHd.dom;
33797 var bs = this.mainBody.dom;
33798 var lv = this.lockedBody.dom;
33799 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33800 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33803 handleScroll : function(e){
33805 var sb = this.scroller.dom;
33806 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33810 handleWheel : function(e){
33811 var d = e.getWheelDelta();
33812 this.scroller.dom.scrollTop -= d*22;
33813 // set this here to prevent jumpy scrolling on large tables
33814 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33818 renderRows : function(startRow, endRow){
33819 // pull in all the crap needed to render rows
33820 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33821 var colCount = cm.getColumnCount();
33823 if(ds.getCount() < 1){
33827 // build a map for all the columns
33829 for(var i = 0; i < colCount; i++){
33830 var name = cm.getDataIndex(i);
33832 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33833 renderer : cm.getRenderer(i),
33834 id : cm.getColumnId(i),
33835 locked : cm.isLocked(i)
33839 startRow = startRow || 0;
33840 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33842 // records to render
33843 var rs = ds.getRange(startRow, endRow);
33845 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33848 // As much as I hate to duplicate code, this was branched because FireFox really hates
33849 // [].join("") on strings. The performance difference was substantial enough to
33850 // branch this function
33851 doRender : Roo.isGecko ?
33852 function(cs, rs, ds, startRow, colCount, stripe){
33853 var ts = this.templates, ct = ts.cell, rt = ts.row;
33855 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33857 var hasListener = this.grid.hasListener('rowclass');
33859 for(var j = 0, len = rs.length; j < len; j++){
33860 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33861 for(var i = 0; i < colCount; i++){
33863 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33865 p.css = p.attr = "";
33866 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33867 if(p.value == undefined || p.value === "") p.value = " ";
33868 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33869 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33871 var markup = ct.apply(p);
33879 if(stripe && ((rowIndex+1) % 2 == 0)){
33880 alt.push("x-grid-row-alt")
33883 alt.push( " x-grid-dirty-row");
33886 if(this.getRowClass){
33887 alt.push(this.getRowClass(r, rowIndex));
33893 rowIndex : rowIndex,
33896 this.grid.fireEvent('rowclass', this, rowcfg);
33897 alt.push(rowcfg.rowClass);
33899 rp.alt = alt.join(" ");
33900 lbuf+= rt.apply(rp);
33902 buf+= rt.apply(rp);
33904 return [lbuf, buf];
33906 function(cs, rs, ds, startRow, colCount, stripe){
33907 var ts = this.templates, ct = ts.cell, rt = ts.row;
33909 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33910 var hasListener = this.grid.hasListener('rowclass');
33912 for(var j = 0, len = rs.length; j < len; j++){
33913 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33914 for(var i = 0; i < colCount; i++){
33916 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33918 p.css = p.attr = "";
33919 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33920 if(p.value == undefined || p.value === "") p.value = " ";
33921 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33922 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33924 var markup = ct.apply(p);
33926 cb[cb.length] = markup;
33928 lcb[lcb.length] = markup;
33932 if(stripe && ((rowIndex+1) % 2 == 0)){
33933 alt.push( "x-grid-row-alt");
33936 alt.push(" x-grid-dirty-row");
33939 if(this.getRowClass){
33940 alt.push( this.getRowClass(r, rowIndex));
33946 rowIndex : rowIndex,
33949 this.grid.fireEvent('rowclass', this, rowcfg);
33950 alt.push(rowcfg.rowClass);
33952 rp.alt = alt.join(" ");
33953 rp.cells = lcb.join("");
33954 lbuf[lbuf.length] = rt.apply(rp);
33955 rp.cells = cb.join("");
33956 buf[buf.length] = rt.apply(rp);
33958 return [lbuf.join(""), buf.join("")];
33961 renderBody : function(){
33962 var markup = this.renderRows();
33963 var bt = this.templates.body;
33964 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33968 * Refreshes the grid
33969 * @param {Boolean} headersToo
33971 refresh : function(headersToo){
33972 this.fireEvent("beforerefresh", this);
33973 this.grid.stopEditing();
33974 var result = this.renderBody();
33975 this.lockedBody.update(result[0]);
33976 this.mainBody.update(result[1]);
33977 if(headersToo === true){
33978 this.updateHeaders();
33979 this.updateColumns();
33980 this.updateSplitters();
33981 this.updateHeaderSortState();
33983 this.syncRowHeights();
33985 this.fireEvent("refresh", this);
33988 handleColumnMove : function(cm, oldIndex, newIndex){
33989 this.indexMap = null;
33990 var s = this.getScrollState();
33991 this.refresh(true);
33992 this.restoreScroll(s);
33993 this.afterMove(newIndex);
33996 afterMove : function(colIndex){
33997 if(this.enableMoveAnim && Roo.enableFx){
33998 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
34000 // if multisort - fix sortOrder, and reload..
34001 if (this.grid.dataSource.multiSort) {
34002 // the we can call sort again..
34003 var dm = this.grid.dataSource;
34004 var cm = this.grid.colModel;
34006 for(var i = 0; i < cm.config.length; i++ ) {
34008 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
34009 continue; // dont' bother, it's not in sort list or being set.
34012 so.push(cm.config[i].dataIndex);
34015 dm.load(dm.lastOptions);
34022 updateCell : function(dm, rowIndex, dataIndex){
34023 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
34024 if(typeof colIndex == "undefined"){ // not present in grid
34027 var cm = this.grid.colModel;
34028 var cell = this.getCell(rowIndex, colIndex);
34029 var cellText = this.getCellText(rowIndex, colIndex);
34032 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
34033 id : cm.getColumnId(colIndex),
34034 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
34036 var renderer = cm.getRenderer(colIndex);
34037 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
34038 if(typeof val == "undefined" || val === "") val = " ";
34039 cellText.innerHTML = val;
34040 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
34041 this.syncRowHeights(rowIndex, rowIndex);
34044 calcColumnWidth : function(colIndex, maxRowsToMeasure){
34046 if(this.grid.autoSizeHeaders){
34047 var h = this.getHeaderCellMeasure(colIndex);
34048 maxWidth = Math.max(maxWidth, h.scrollWidth);
34051 if(this.cm.isLocked(colIndex)){
34052 tb = this.getLockedTable();
34055 tb = this.getBodyTable();
34056 index = colIndex - this.cm.getLockedCount();
34059 var rows = tb.rows;
34060 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
34061 for(var i = 0; i < stopIndex; i++){
34062 var cell = rows[i].childNodes[index].firstChild;
34063 maxWidth = Math.max(maxWidth, cell.scrollWidth);
34066 return maxWidth + /*margin for error in IE*/ 5;
34069 * Autofit a column to its content.
34070 * @param {Number} colIndex
34071 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
34073 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
34074 if(this.cm.isHidden(colIndex)){
34075 return; // can't calc a hidden column
34078 var cid = this.cm.getColumnId(colIndex);
34079 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
34080 if(this.grid.autoSizeHeaders){
34081 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
34084 var newWidth = this.calcColumnWidth(colIndex);
34085 this.cm.setColumnWidth(colIndex,
34086 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
34087 if(!suppressEvent){
34088 this.grid.fireEvent("columnresize", colIndex, newWidth);
34093 * Autofits all columns to their content and then expands to fit any extra space in the grid
34095 autoSizeColumns : function(){
34096 var cm = this.grid.colModel;
34097 var colCount = cm.getColumnCount();
34098 for(var i = 0; i < colCount; i++){
34099 this.autoSizeColumn(i, true, true);
34101 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
34104 this.updateColumns();
34110 * Autofits all columns to the grid's width proportionate with their current size
34111 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
34113 fitColumns : function(reserveScrollSpace){
34114 var cm = this.grid.colModel;
34115 var colCount = cm.getColumnCount();
34119 for (i = 0; i < colCount; i++){
34120 if(!cm.isHidden(i) && !cm.isFixed(i)){
34121 w = cm.getColumnWidth(i);
34127 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
34128 if(reserveScrollSpace){
34131 var frac = (avail - cm.getTotalWidth())/width;
34132 while (cols.length){
34135 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
34137 this.updateColumns();
34141 onRowSelect : function(rowIndex){
34142 var row = this.getRowComposite(rowIndex);
34143 row.addClass("x-grid-row-selected");
34146 onRowDeselect : function(rowIndex){
34147 var row = this.getRowComposite(rowIndex);
34148 row.removeClass("x-grid-row-selected");
34151 onCellSelect : function(row, col){
34152 var cell = this.getCell(row, col);
34154 Roo.fly(cell).addClass("x-grid-cell-selected");
34158 onCellDeselect : function(row, col){
34159 var cell = this.getCell(row, col);
34161 Roo.fly(cell).removeClass("x-grid-cell-selected");
34165 updateHeaderSortState : function(){
34167 // sort state can be single { field: xxx, direction : yyy}
34168 // or { xxx=>ASC , yyy : DESC ..... }
34171 if (!this.ds.multiSort) {
34172 var state = this.ds.getSortState();
34176 mstate[state.field] = state.direction;
34177 // FIXME... - this is not used here.. but might be elsewhere..
34178 this.sortState = state;
34181 mstate = this.ds.sortToggle;
34183 //remove existing sort classes..
34185 var sc = this.sortClasses;
34186 var hds = this.el.select(this.headerSelector).removeClass(sc);
34188 for(var f in mstate) {
34190 var sortColumn = this.cm.findColumnIndex(f);
34192 if(sortColumn != -1){
34193 var sortDir = mstate[f];
34194 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
34203 handleHeaderClick : function(g, index){
34204 if(this.headersDisabled){
34207 var dm = g.dataSource, cm = g.colModel;
34208 if(!cm.isSortable(index)){
34213 if (dm.multiSort) {
34214 // update the sortOrder
34216 for(var i = 0; i < cm.config.length; i++ ) {
34218 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
34219 continue; // dont' bother, it's not in sort list or being set.
34222 so.push(cm.config[i].dataIndex);
34228 dm.sort(cm.getDataIndex(index));
34232 destroy : function(){
34234 this.colMenu.removeAll();
34235 Roo.menu.MenuMgr.unregister(this.colMenu);
34236 this.colMenu.getEl().remove();
34237 delete this.colMenu;
34240 this.hmenu.removeAll();
34241 Roo.menu.MenuMgr.unregister(this.hmenu);
34242 this.hmenu.getEl().remove();
34245 if(this.grid.enableColumnMove){
34246 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
34248 for(var dd in dds){
34249 if(!dds[dd].config.isTarget && dds[dd].dragElId){
34250 var elid = dds[dd].dragElId;
34252 Roo.get(elid).remove();
34253 } else if(dds[dd].config.isTarget){
34254 dds[dd].proxyTop.remove();
34255 dds[dd].proxyBottom.remove();
34258 if(Roo.dd.DDM.locationCache[dd]){
34259 delete Roo.dd.DDM.locationCache[dd];
34262 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
34265 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
34266 this.bind(null, null);
34267 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
34270 handleLockChange : function(){
34271 this.refresh(true);
34274 onDenyColumnLock : function(){
34278 onDenyColumnHide : function(){
34282 handleHdMenuClick : function(item){
34283 var index = this.hdCtxIndex;
34284 var cm = this.cm, ds = this.ds;
34287 ds.sort(cm.getDataIndex(index), "ASC");
34290 ds.sort(cm.getDataIndex(index), "DESC");
34293 var lc = cm.getLockedCount();
34294 if(cm.getColumnCount(true) <= lc+1){
34295 this.onDenyColumnLock();
34299 cm.setLocked(index, true, true);
34300 cm.moveColumn(index, lc);
34301 this.grid.fireEvent("columnmove", index, lc);
34303 cm.setLocked(index, true);
34307 var lc = cm.getLockedCount();
34308 if((lc-1) != index){
34309 cm.setLocked(index, false, true);
34310 cm.moveColumn(index, lc-1);
34311 this.grid.fireEvent("columnmove", index, lc-1);
34313 cm.setLocked(index, false);
34317 index = cm.getIndexById(item.id.substr(4));
34319 if(item.checked && cm.getColumnCount(true) <= 1){
34320 this.onDenyColumnHide();
34323 cm.setHidden(index, item.checked);
34329 beforeColMenuShow : function(){
34330 var cm = this.cm, colCount = cm.getColumnCount();
34331 this.colMenu.removeAll();
34332 for(var i = 0; i < colCount; i++){
34333 this.colMenu.add(new Roo.menu.CheckItem({
34334 id: "col-"+cm.getColumnId(i),
34335 text: cm.getColumnHeader(i),
34336 checked: !cm.isHidden(i),
34342 handleHdCtx : function(g, index, e){
34344 var hd = this.getHeaderCell(index);
34345 this.hdCtxIndex = index;
34346 var ms = this.hmenu.items, cm = this.cm;
34347 ms.get("asc").setDisabled(!cm.isSortable(index));
34348 ms.get("desc").setDisabled(!cm.isSortable(index));
34349 if(this.grid.enableColLock !== false){
34350 ms.get("lock").setDisabled(cm.isLocked(index));
34351 ms.get("unlock").setDisabled(!cm.isLocked(index));
34353 this.hmenu.show(hd, "tl-bl");
34356 handleHdOver : function(e){
34357 var hd = this.findHeaderCell(e.getTarget());
34358 if(hd && !this.headersDisabled){
34359 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
34360 this.fly(hd).addClass("x-grid-hd-over");
34365 handleHdOut : function(e){
34366 var hd = this.findHeaderCell(e.getTarget());
34368 this.fly(hd).removeClass("x-grid-hd-over");
34372 handleSplitDblClick : function(e, t){
34373 var i = this.getCellIndex(t);
34374 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
34375 this.autoSizeColumn(i, true);
34380 render : function(){
34383 var colCount = cm.getColumnCount();
34385 if(this.grid.monitorWindowResize === true){
34386 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34388 var header = this.renderHeaders();
34389 var body = this.templates.body.apply({rows:""});
34390 var html = this.templates.master.apply({
34393 lockedHeader: header[0],
34397 //this.updateColumns();
34399 this.grid.getGridEl().dom.innerHTML = html;
34401 this.initElements();
34403 // a kludge to fix the random scolling effect in webkit
34404 this.el.on("scroll", function() {
34405 this.el.dom.scrollTop=0; // hopefully not recursive..
34408 this.scroller.on("scroll", this.handleScroll, this);
34409 this.lockedBody.on("mousewheel", this.handleWheel, this);
34410 this.mainBody.on("mousewheel", this.handleWheel, this);
34412 this.mainHd.on("mouseover", this.handleHdOver, this);
34413 this.mainHd.on("mouseout", this.handleHdOut, this);
34414 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34415 {delegate: "."+this.splitClass});
34417 this.lockedHd.on("mouseover", this.handleHdOver, this);
34418 this.lockedHd.on("mouseout", this.handleHdOut, this);
34419 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34420 {delegate: "."+this.splitClass});
34422 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34423 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34426 this.updateSplitters();
34428 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34429 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34430 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34433 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34434 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34436 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34437 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34439 if(this.grid.enableColLock !== false){
34440 this.hmenu.add('-',
34441 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34442 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34445 if(this.grid.enableColumnHide !== false){
34447 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34448 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34449 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34451 this.hmenu.add('-',
34452 {id:"columns", text: this.columnsText, menu: this.colMenu}
34455 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34457 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34460 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34461 this.dd = new Roo.grid.GridDragZone(this.grid, {
34462 ddGroup : this.grid.ddGroup || 'GridDD'
34467 for(var i = 0; i < colCount; i++){
34468 if(cm.isHidden(i)){
34469 this.hideColumn(i);
34471 if(cm.config[i].align){
34472 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34473 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34477 this.updateHeaderSortState();
34479 this.beforeInitialResize();
34482 // two part rendering gives faster view to the user
34483 this.renderPhase2.defer(1, this);
34486 renderPhase2 : function(){
34487 // render the rows now
34489 if(this.grid.autoSizeColumns){
34490 this.autoSizeColumns();
34494 beforeInitialResize : function(){
34498 onColumnSplitterMoved : function(i, w){
34499 this.userResized = true;
34500 var cm = this.grid.colModel;
34501 cm.setColumnWidth(i, w, true);
34502 var cid = cm.getColumnId(i);
34503 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34504 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34505 this.updateSplitters();
34507 this.grid.fireEvent("columnresize", i, w);
34510 syncRowHeights : function(startIndex, endIndex){
34511 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34512 startIndex = startIndex || 0;
34513 var mrows = this.getBodyTable().rows;
34514 var lrows = this.getLockedTable().rows;
34515 var len = mrows.length-1;
34516 endIndex = Math.min(endIndex || len, len);
34517 for(var i = startIndex; i <= endIndex; i++){
34518 var m = mrows[i], l = lrows[i];
34519 var h = Math.max(m.offsetHeight, l.offsetHeight);
34520 m.style.height = l.style.height = h + "px";
34525 layout : function(initialRender, is2ndPass){
34527 var auto = g.autoHeight;
34528 var scrollOffset = 16;
34529 var c = g.getGridEl(), cm = this.cm,
34530 expandCol = g.autoExpandColumn,
34532 //c.beginMeasure();
34534 if(!c.dom.offsetWidth){ // display:none?
34536 this.lockedWrap.show();
34537 this.mainWrap.show();
34542 var hasLock = this.cm.isLocked(0);
34544 var tbh = this.headerPanel.getHeight();
34545 var bbh = this.footerPanel.getHeight();
34548 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34549 var newHeight = ch + c.getBorderWidth("tb");
34551 newHeight = Math.min(g.maxHeight, newHeight);
34553 c.setHeight(newHeight);
34557 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34560 var s = this.scroller;
34562 var csize = c.getSize(true);
34564 this.el.setSize(csize.width, csize.height);
34566 this.headerPanel.setWidth(csize.width);
34567 this.footerPanel.setWidth(csize.width);
34569 var hdHeight = this.mainHd.getHeight();
34570 var vw = csize.width;
34571 var vh = csize.height - (tbh + bbh);
34575 var bt = this.getBodyTable();
34576 var ltWidth = hasLock ?
34577 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34579 var scrollHeight = bt.offsetHeight;
34580 var scrollWidth = ltWidth + bt.offsetWidth;
34581 var vscroll = false, hscroll = false;
34583 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34585 var lw = this.lockedWrap, mw = this.mainWrap;
34586 var lb = this.lockedBody, mb = this.mainBody;
34588 setTimeout(function(){
34589 var t = s.dom.offsetTop;
34590 var w = s.dom.clientWidth,
34591 h = s.dom.clientHeight;
34594 lw.setSize(ltWidth, h);
34596 mw.setLeftTop(ltWidth, t);
34597 mw.setSize(w-ltWidth, h);
34599 lb.setHeight(h-hdHeight);
34600 mb.setHeight(h-hdHeight);
34602 if(is2ndPass !== true && !gv.userResized && expandCol){
34603 // high speed resize without full column calculation
34605 var ci = cm.getIndexById(expandCol);
34607 ci = cm.findColumnIndex(expandCol);
34609 ci = Math.max(0, ci); // make sure it's got at least the first col.
34610 var expandId = cm.getColumnId(ci);
34611 var tw = cm.getTotalWidth(false);
34612 var currentWidth = cm.getColumnWidth(ci);
34613 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34614 if(currentWidth != cw){
34615 cm.setColumnWidth(ci, cw, true);
34616 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34617 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34618 gv.updateSplitters();
34619 gv.layout(false, true);
34631 onWindowResize : function(){
34632 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34638 appendFooter : function(parentEl){
34642 sortAscText : "Sort Ascending",
34643 sortDescText : "Sort Descending",
34644 lockText : "Lock Column",
34645 unlockText : "Unlock Column",
34646 columnsText : "Columns"
34650 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34651 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34652 this.proxy.el.addClass('x-grid3-col-dd');
34655 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34656 handleMouseDown : function(e){
34660 callHandleMouseDown : function(e){
34661 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34666 * Ext JS Library 1.1.1
34667 * Copyright(c) 2006-2007, Ext JS, LLC.
34669 * Originally Released Under LGPL - original licence link has changed is not relivant.
34672 * <script type="text/javascript">
34676 // This is a support class used internally by the Grid components
34677 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34679 this.view = grid.getView();
34680 this.proxy = this.view.resizeProxy;
34681 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34682 "gridSplitters" + this.grid.getGridEl().id, {
34683 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34685 this.setHandleElId(Roo.id(hd));
34686 this.setOuterHandleElId(Roo.id(hd2));
34687 this.scroll = false;
34689 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34690 fly: Roo.Element.fly,
34692 b4StartDrag : function(x, y){
34693 this.view.headersDisabled = true;
34694 this.proxy.setHeight(this.view.mainWrap.getHeight());
34695 var w = this.cm.getColumnWidth(this.cellIndex);
34696 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34697 this.resetConstraints();
34698 this.setXConstraint(minw, 1000);
34699 this.setYConstraint(0, 0);
34700 this.minX = x - minw;
34701 this.maxX = x + 1000;
34703 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34707 handleMouseDown : function(e){
34708 ev = Roo.EventObject.setEvent(e);
34709 var t = this.fly(ev.getTarget());
34710 if(t.hasClass("x-grid-split")){
34711 this.cellIndex = this.view.getCellIndex(t.dom);
34712 this.split = t.dom;
34713 this.cm = this.grid.colModel;
34714 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34715 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34720 endDrag : function(e){
34721 this.view.headersDisabled = false;
34722 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34723 var diff = endX - this.startPos;
34724 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34727 autoOffset : function(){
34728 this.setDelta(0,0);
34732 * Ext JS Library 1.1.1
34733 * Copyright(c) 2006-2007, Ext JS, LLC.
34735 * Originally Released Under LGPL - original licence link has changed is not relivant.
34738 * <script type="text/javascript">
34742 // This is a support class used internally by the Grid components
34743 Roo.grid.GridDragZone = function(grid, config){
34744 this.view = grid.getView();
34745 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34746 if(this.view.lockedBody){
34747 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34748 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34750 this.scroll = false;
34752 this.ddel = document.createElement('div');
34753 this.ddel.className = 'x-grid-dd-wrap';
34756 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34757 ddGroup : "GridDD",
34759 getDragData : function(e){
34760 var t = Roo.lib.Event.getTarget(e);
34761 var rowIndex = this.view.findRowIndex(t);
34762 if(rowIndex !== false){
34763 var sm = this.grid.selModel;
34764 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34765 // sm.mouseDown(e, t);
34767 if (e.hasModifier()){
34768 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34770 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34775 onInitDrag : function(e){
34776 var data = this.dragData;
34777 this.ddel.innerHTML = this.grid.getDragDropText();
34778 this.proxy.update(this.ddel);
34779 // fire start drag?
34782 afterRepair : function(){
34783 this.dragging = false;
34786 getRepairXY : function(e, data){
34790 onEndDrag : function(data, e){
34794 onValidDrop : function(dd, e, id){
34799 beforeInvalidDrop : function(e, id){
34804 * Ext JS Library 1.1.1
34805 * Copyright(c) 2006-2007, Ext JS, LLC.
34807 * Originally Released Under LGPL - original licence link has changed is not relivant.
34810 * <script type="text/javascript">
34815 * @class Roo.grid.ColumnModel
34816 * @extends Roo.util.Observable
34817 * This is the default implementation of a ColumnModel used by the Grid. It defines
34818 * the columns in the grid.
34821 var colModel = new Roo.grid.ColumnModel([
34822 {header: "Ticker", width: 60, sortable: true, locked: true},
34823 {header: "Company Name", width: 150, sortable: true},
34824 {header: "Market Cap.", width: 100, sortable: true},
34825 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34826 {header: "Employees", width: 100, sortable: true, resizable: false}
34831 * The config options listed for this class are options which may appear in each
34832 * individual column definition.
34833 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34835 * @param {Object} config An Array of column config objects. See this class's
34836 * config objects for details.
34838 Roo.grid.ColumnModel = function(config){
34840 * The config passed into the constructor
34842 this.config = config;
34845 // if no id, create one
34846 // if the column does not have a dataIndex mapping,
34847 // map it to the order it is in the config
34848 for(var i = 0, len = config.length; i < len; i++){
34850 if(typeof c.dataIndex == "undefined"){
34853 if(typeof c.renderer == "string"){
34854 c.renderer = Roo.util.Format[c.renderer];
34856 if(typeof c.id == "undefined"){
34859 if(c.editor && c.editor.xtype){
34860 c.editor = Roo.factory(c.editor, Roo.grid);
34862 if(c.editor && c.editor.isFormField){
34863 c.editor = new Roo.grid.GridEditor(c.editor);
34865 this.lookup[c.id] = c;
34869 * The width of columns which have no width specified (defaults to 100)
34872 this.defaultWidth = 100;
34875 * Default sortable of columns which have no sortable specified (defaults to false)
34878 this.defaultSortable = false;
34882 * @event widthchange
34883 * Fires when the width of a column changes.
34884 * @param {ColumnModel} this
34885 * @param {Number} columnIndex The column index
34886 * @param {Number} newWidth The new width
34888 "widthchange": true,
34890 * @event headerchange
34891 * Fires when the text of a header changes.
34892 * @param {ColumnModel} this
34893 * @param {Number} columnIndex The column index
34894 * @param {Number} newText The new header text
34896 "headerchange": true,
34898 * @event hiddenchange
34899 * Fires when a column is hidden or "unhidden".
34900 * @param {ColumnModel} this
34901 * @param {Number} columnIndex The column index
34902 * @param {Boolean} hidden true if hidden, false otherwise
34904 "hiddenchange": true,
34906 * @event columnmoved
34907 * Fires when a column is moved.
34908 * @param {ColumnModel} this
34909 * @param {Number} oldIndex
34910 * @param {Number} newIndex
34912 "columnmoved" : true,
34914 * @event columlockchange
34915 * Fires when a column's locked state is changed
34916 * @param {ColumnModel} this
34917 * @param {Number} colIndex
34918 * @param {Boolean} locked true if locked
34920 "columnlockchange" : true
34922 Roo.grid.ColumnModel.superclass.constructor.call(this);
34924 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34926 * @cfg {String} header The header text to display in the Grid view.
34929 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34930 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34931 * specified, the column's index is used as an index into the Record's data Array.
34934 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34935 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34938 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34939 * Defaults to the value of the {@link #defaultSortable} property.
34940 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34943 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34946 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34949 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34952 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34955 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34956 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34957 * default renderer uses the raw data value.
34960 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34963 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34967 * Returns the id of the column at the specified index.
34968 * @param {Number} index The column index
34969 * @return {String} the id
34971 getColumnId : function(index){
34972 return this.config[index].id;
34976 * Returns the column for a specified id.
34977 * @param {String} id The column id
34978 * @return {Object} the column
34980 getColumnById : function(id){
34981 return this.lookup[id];
34986 * Returns the column for a specified dataIndex.
34987 * @param {String} dataIndex The column dataIndex
34988 * @return {Object|Boolean} the column or false if not found
34990 getColumnByDataIndex: function(dataIndex){
34991 var index = this.findColumnIndex(dataIndex);
34992 return index > -1 ? this.config[index] : false;
34996 * Returns the index for a specified column id.
34997 * @param {String} id The column id
34998 * @return {Number} the index, or -1 if not found
35000 getIndexById : function(id){
35001 for(var i = 0, len = this.config.length; i < len; i++){
35002 if(this.config[i].id == id){
35010 * Returns the index for a specified column dataIndex.
35011 * @param {String} dataIndex The column dataIndex
35012 * @return {Number} the index, or -1 if not found
35015 findColumnIndex : function(dataIndex){
35016 for(var i = 0, len = this.config.length; i < len; i++){
35017 if(this.config[i].dataIndex == dataIndex){
35025 moveColumn : function(oldIndex, newIndex){
35026 var c = this.config[oldIndex];
35027 this.config.splice(oldIndex, 1);
35028 this.config.splice(newIndex, 0, c);
35029 this.dataMap = null;
35030 this.fireEvent("columnmoved", this, oldIndex, newIndex);
35033 isLocked : function(colIndex){
35034 return this.config[colIndex].locked === true;
35037 setLocked : function(colIndex, value, suppressEvent){
35038 if(this.isLocked(colIndex) == value){
35041 this.config[colIndex].locked = value;
35042 if(!suppressEvent){
35043 this.fireEvent("columnlockchange", this, colIndex, value);
35047 getTotalLockedWidth : function(){
35048 var totalWidth = 0;
35049 for(var i = 0; i < this.config.length; i++){
35050 if(this.isLocked(i) && !this.isHidden(i)){
35051 this.totalWidth += this.getColumnWidth(i);
35057 getLockedCount : function(){
35058 for(var i = 0, len = this.config.length; i < len; i++){
35059 if(!this.isLocked(i)){
35066 * Returns the number of columns.
35069 getColumnCount : function(visibleOnly){
35070 if(visibleOnly === true){
35072 for(var i = 0, len = this.config.length; i < len; i++){
35073 if(!this.isHidden(i)){
35079 return this.config.length;
35083 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
35084 * @param {Function} fn
35085 * @param {Object} scope (optional)
35086 * @return {Array} result
35088 getColumnsBy : function(fn, scope){
35090 for(var i = 0, len = this.config.length; i < len; i++){
35091 var c = this.config[i];
35092 if(fn.call(scope||this, c, i) === true){
35100 * Returns true if the specified column is sortable.
35101 * @param {Number} col The column index
35102 * @return {Boolean}
35104 isSortable : function(col){
35105 if(typeof this.config[col].sortable == "undefined"){
35106 return this.defaultSortable;
35108 return this.config[col].sortable;
35112 * Returns the rendering (formatting) function defined for the column.
35113 * @param {Number} col The column index.
35114 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
35116 getRenderer : function(col){
35117 if(!this.config[col].renderer){
35118 return Roo.grid.ColumnModel.defaultRenderer;
35120 return this.config[col].renderer;
35124 * Sets the rendering (formatting) function for a column.
35125 * @param {Number} col The column index
35126 * @param {Function} fn The function to use to process the cell's raw data
35127 * to return HTML markup for the grid view. The render function is called with
35128 * the following parameters:<ul>
35129 * <li>Data value.</li>
35130 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
35131 * <li>css A CSS style string to apply to the table cell.</li>
35132 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
35133 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
35134 * <li>Row index</li>
35135 * <li>Column index</li>
35136 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
35138 setRenderer : function(col, fn){
35139 this.config[col].renderer = fn;
35143 * Returns the width for the specified column.
35144 * @param {Number} col The column index
35147 getColumnWidth : function(col){
35148 return this.config[col].width * 1 || this.defaultWidth;
35152 * Sets the width for a column.
35153 * @param {Number} col The column index
35154 * @param {Number} width The new width
35156 setColumnWidth : function(col, width, suppressEvent){
35157 this.config[col].width = width;
35158 this.totalWidth = null;
35159 if(!suppressEvent){
35160 this.fireEvent("widthchange", this, col, width);
35165 * Returns the total width of all columns.
35166 * @param {Boolean} includeHidden True to include hidden column widths
35169 getTotalWidth : function(includeHidden){
35170 if(!this.totalWidth){
35171 this.totalWidth = 0;
35172 for(var i = 0, len = this.config.length; i < len; i++){
35173 if(includeHidden || !this.isHidden(i)){
35174 this.totalWidth += this.getColumnWidth(i);
35178 return this.totalWidth;
35182 * Returns the header for the specified column.
35183 * @param {Number} col The column index
35186 getColumnHeader : function(col){
35187 return this.config[col].header;
35191 * Sets the header for a column.
35192 * @param {Number} col The column index
35193 * @param {String} header The new header
35195 setColumnHeader : function(col, header){
35196 this.config[col].header = header;
35197 this.fireEvent("headerchange", this, col, header);
35201 * Returns the tooltip for the specified column.
35202 * @param {Number} col The column index
35205 getColumnTooltip : function(col){
35206 return this.config[col].tooltip;
35209 * Sets the tooltip for a column.
35210 * @param {Number} col The column index
35211 * @param {String} tooltip The new tooltip
35213 setColumnTooltip : function(col, tooltip){
35214 this.config[col].tooltip = tooltip;
35218 * Returns the dataIndex for the specified column.
35219 * @param {Number} col The column index
35222 getDataIndex : function(col){
35223 return this.config[col].dataIndex;
35227 * Sets the dataIndex for a column.
35228 * @param {Number} col The column index
35229 * @param {Number} dataIndex The new dataIndex
35231 setDataIndex : function(col, dataIndex){
35232 this.config[col].dataIndex = dataIndex;
35238 * Returns true if the cell is editable.
35239 * @param {Number} colIndex The column index
35240 * @param {Number} rowIndex The row index
35241 * @return {Boolean}
35243 isCellEditable : function(colIndex, rowIndex){
35244 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
35248 * Returns the editor defined for the cell/column.
35249 * return false or null to disable editing.
35250 * @param {Number} colIndex The column index
35251 * @param {Number} rowIndex The row index
35254 getCellEditor : function(colIndex, rowIndex){
35255 return this.config[colIndex].editor;
35259 * Sets if a column is editable.
35260 * @param {Number} col The column index
35261 * @param {Boolean} editable True if the column is editable
35263 setEditable : function(col, editable){
35264 this.config[col].editable = editable;
35269 * Returns true if the column is hidden.
35270 * @param {Number} colIndex The column index
35271 * @return {Boolean}
35273 isHidden : function(colIndex){
35274 return this.config[colIndex].hidden;
35279 * Returns true if the column width cannot be changed
35281 isFixed : function(colIndex){
35282 return this.config[colIndex].fixed;
35286 * Returns true if the column can be resized
35287 * @return {Boolean}
35289 isResizable : function(colIndex){
35290 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
35293 * Sets if a column is hidden.
35294 * @param {Number} colIndex The column index
35295 * @param {Boolean} hidden True if the column is hidden
35297 setHidden : function(colIndex, hidden){
35298 this.config[colIndex].hidden = hidden;
35299 this.totalWidth = null;
35300 this.fireEvent("hiddenchange", this, colIndex, hidden);
35304 * Sets the editor for a column.
35305 * @param {Number} col The column index
35306 * @param {Object} editor The editor object
35308 setEditor : function(col, editor){
35309 this.config[col].editor = editor;
35313 Roo.grid.ColumnModel.defaultRenderer = function(value){
35314 if(typeof value == "string" && value.length < 1){
35320 // Alias for backwards compatibility
35321 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
35324 * Ext JS Library 1.1.1
35325 * Copyright(c) 2006-2007, Ext JS, LLC.
35327 * Originally Released Under LGPL - original licence link has changed is not relivant.
35330 * <script type="text/javascript">
35334 * @class Roo.grid.AbstractSelectionModel
35335 * @extends Roo.util.Observable
35336 * Abstract base class for grid SelectionModels. It provides the interface that should be
35337 * implemented by descendant classes. This class should not be directly instantiated.
35340 Roo.grid.AbstractSelectionModel = function(){
35341 this.locked = false;
35342 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
35345 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
35346 /** @ignore Called by the grid automatically. Do not call directly. */
35347 init : function(grid){
35353 * Locks the selections.
35356 this.locked = true;
35360 * Unlocks the selections.
35362 unlock : function(){
35363 this.locked = false;
35367 * Returns true if the selections are locked.
35368 * @return {Boolean}
35370 isLocked : function(){
35371 return this.locked;
35375 * Ext JS Library 1.1.1
35376 * Copyright(c) 2006-2007, Ext JS, LLC.
35378 * Originally Released Under LGPL - original licence link has changed is not relivant.
35381 * <script type="text/javascript">
35384 * @extends Roo.grid.AbstractSelectionModel
35385 * @class Roo.grid.RowSelectionModel
35386 * The default SelectionModel used by {@link Roo.grid.Grid}.
35387 * It supports multiple selections and keyboard selection/navigation.
35389 * @param {Object} config
35391 Roo.grid.RowSelectionModel = function(config){
35392 Roo.apply(this, config);
35393 this.selections = new Roo.util.MixedCollection(false, function(o){
35398 this.lastActive = false;
35402 * @event selectionchange
35403 * Fires when the selection changes
35404 * @param {SelectionModel} this
35406 "selectionchange" : true,
35408 * @event afterselectionchange
35409 * Fires after the selection changes (eg. by key press or clicking)
35410 * @param {SelectionModel} this
35412 "afterselectionchange" : true,
35414 * @event beforerowselect
35415 * Fires when a row is selected being selected, return false to cancel.
35416 * @param {SelectionModel} this
35417 * @param {Number} rowIndex The selected index
35418 * @param {Boolean} keepExisting False if other selections will be cleared
35420 "beforerowselect" : true,
35423 * Fires when a row is selected.
35424 * @param {SelectionModel} this
35425 * @param {Number} rowIndex The selected index
35426 * @param {Roo.data.Record} r The record
35428 "rowselect" : true,
35430 * @event rowdeselect
35431 * Fires when a row is deselected.
35432 * @param {SelectionModel} this
35433 * @param {Number} rowIndex The selected index
35435 "rowdeselect" : true
35437 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35438 this.locked = false;
35441 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35443 * @cfg {Boolean} singleSelect
35444 * True to allow selection of only one row at a time (defaults to false)
35446 singleSelect : false,
35449 initEvents : function(){
35451 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35452 this.grid.on("mousedown", this.handleMouseDown, this);
35453 }else{ // allow click to work like normal
35454 this.grid.on("rowclick", this.handleDragableRowClick, this);
35457 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35458 "up" : function(e){
35460 this.selectPrevious(e.shiftKey);
35461 }else if(this.last !== false && this.lastActive !== false){
35462 var last = this.last;
35463 this.selectRange(this.last, this.lastActive-1);
35464 this.grid.getView().focusRow(this.lastActive);
35465 if(last !== false){
35469 this.selectFirstRow();
35471 this.fireEvent("afterselectionchange", this);
35473 "down" : function(e){
35475 this.selectNext(e.shiftKey);
35476 }else if(this.last !== false && this.lastActive !== false){
35477 var last = this.last;
35478 this.selectRange(this.last, this.lastActive+1);
35479 this.grid.getView().focusRow(this.lastActive);
35480 if(last !== false){
35484 this.selectFirstRow();
35486 this.fireEvent("afterselectionchange", this);
35491 var view = this.grid.view;
35492 view.on("refresh", this.onRefresh, this);
35493 view.on("rowupdated", this.onRowUpdated, this);
35494 view.on("rowremoved", this.onRemove, this);
35498 onRefresh : function(){
35499 var ds = this.grid.dataSource, i, v = this.grid.view;
35500 var s = this.selections;
35501 s.each(function(r){
35502 if((i = ds.indexOfId(r.id)) != -1){
35511 onRemove : function(v, index, r){
35512 this.selections.remove(r);
35516 onRowUpdated : function(v, index, r){
35517 if(this.isSelected(r)){
35518 v.onRowSelect(index);
35524 * @param {Array} records The records to select
35525 * @param {Boolean} keepExisting (optional) True to keep existing selections
35527 selectRecords : function(records, keepExisting){
35529 this.clearSelections();
35531 var ds = this.grid.dataSource;
35532 for(var i = 0, len = records.length; i < len; i++){
35533 this.selectRow(ds.indexOf(records[i]), true);
35538 * Gets the number of selected rows.
35541 getCount : function(){
35542 return this.selections.length;
35546 * Selects the first row in the grid.
35548 selectFirstRow : function(){
35553 * Select the last row.
35554 * @param {Boolean} keepExisting (optional) True to keep existing selections
35556 selectLastRow : function(keepExisting){
35557 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35561 * Selects the row immediately following the last selected row.
35562 * @param {Boolean} keepExisting (optional) True to keep existing selections
35564 selectNext : function(keepExisting){
35565 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35566 this.selectRow(this.last+1, keepExisting);
35567 this.grid.getView().focusRow(this.last);
35572 * Selects the row that precedes the last selected row.
35573 * @param {Boolean} keepExisting (optional) True to keep existing selections
35575 selectPrevious : function(keepExisting){
35577 this.selectRow(this.last-1, keepExisting);
35578 this.grid.getView().focusRow(this.last);
35583 * Returns the selected records
35584 * @return {Array} Array of selected records
35586 getSelections : function(){
35587 return [].concat(this.selections.items);
35591 * Returns the first selected record.
35594 getSelected : function(){
35595 return this.selections.itemAt(0);
35600 * Clears all selections.
35602 clearSelections : function(fast){
35603 if(this.locked) return;
35605 var ds = this.grid.dataSource;
35606 var s = this.selections;
35607 s.each(function(r){
35608 this.deselectRow(ds.indexOfId(r.id));
35612 this.selections.clear();
35619 * Selects all rows.
35621 selectAll : function(){
35622 if(this.locked) return;
35623 this.selections.clear();
35624 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35625 this.selectRow(i, true);
35630 * Returns True if there is a selection.
35631 * @return {Boolean}
35633 hasSelection : function(){
35634 return this.selections.length > 0;
35638 * Returns True if the specified row is selected.
35639 * @param {Number/Record} record The record or index of the record to check
35640 * @return {Boolean}
35642 isSelected : function(index){
35643 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35644 return (r && this.selections.key(r.id) ? true : false);
35648 * Returns True if the specified record id is selected.
35649 * @param {String} id The id of record to check
35650 * @return {Boolean}
35652 isIdSelected : function(id){
35653 return (this.selections.key(id) ? true : false);
35657 handleMouseDown : function(e, t){
35658 var view = this.grid.getView(), rowIndex;
35659 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35662 if(e.shiftKey && this.last !== false){
35663 var last = this.last;
35664 this.selectRange(last, rowIndex, e.ctrlKey);
35665 this.last = last; // reset the last
35666 view.focusRow(rowIndex);
35668 var isSelected = this.isSelected(rowIndex);
35669 if(e.button !== 0 && isSelected){
35670 view.focusRow(rowIndex);
35671 }else if(e.ctrlKey && isSelected){
35672 this.deselectRow(rowIndex);
35673 }else if(!isSelected){
35674 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35675 view.focusRow(rowIndex);
35678 this.fireEvent("afterselectionchange", this);
35681 handleDragableRowClick : function(grid, rowIndex, e)
35683 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35684 this.selectRow(rowIndex, false);
35685 grid.view.focusRow(rowIndex);
35686 this.fireEvent("afterselectionchange", this);
35691 * Selects multiple rows.
35692 * @param {Array} rows Array of the indexes of the row to select
35693 * @param {Boolean} keepExisting (optional) True to keep existing selections
35695 selectRows : function(rows, keepExisting){
35697 this.clearSelections();
35699 for(var i = 0, len = rows.length; i < len; i++){
35700 this.selectRow(rows[i], true);
35705 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35706 * @param {Number} startRow The index of the first row in the range
35707 * @param {Number} endRow The index of the last row in the range
35708 * @param {Boolean} keepExisting (optional) True to retain existing selections
35710 selectRange : function(startRow, endRow, keepExisting){
35711 if(this.locked) return;
35713 this.clearSelections();
35715 if(startRow <= endRow){
35716 for(var i = startRow; i <= endRow; i++){
35717 this.selectRow(i, true);
35720 for(var i = startRow; i >= endRow; i--){
35721 this.selectRow(i, true);
35727 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35728 * @param {Number} startRow The index of the first row in the range
35729 * @param {Number} endRow The index of the last row in the range
35731 deselectRange : function(startRow, endRow, preventViewNotify){
35732 if(this.locked) return;
35733 for(var i = startRow; i <= endRow; i++){
35734 this.deselectRow(i, preventViewNotify);
35740 * @param {Number} row The index of the row to select
35741 * @param {Boolean} keepExisting (optional) True to keep existing selections
35743 selectRow : function(index, keepExisting, preventViewNotify){
35744 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35745 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35746 if(!keepExisting || this.singleSelect){
35747 this.clearSelections();
35749 var r = this.grid.dataSource.getAt(index);
35750 this.selections.add(r);
35751 this.last = this.lastActive = index;
35752 if(!preventViewNotify){
35753 this.grid.getView().onRowSelect(index);
35755 this.fireEvent("rowselect", this, index, r);
35756 this.fireEvent("selectionchange", this);
35762 * @param {Number} row The index of the row to deselect
35764 deselectRow : function(index, preventViewNotify){
35765 if(this.locked) return;
35766 if(this.last == index){
35769 if(this.lastActive == index){
35770 this.lastActive = false;
35772 var r = this.grid.dataSource.getAt(index);
35773 this.selections.remove(r);
35774 if(!preventViewNotify){
35775 this.grid.getView().onRowDeselect(index);
35777 this.fireEvent("rowdeselect", this, index);
35778 this.fireEvent("selectionchange", this);
35782 restoreLast : function(){
35784 this.last = this._last;
35789 acceptsNav : function(row, col, cm){
35790 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35794 onEditorKey : function(field, e){
35795 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35800 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35802 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35804 }else if(k == e.ENTER && !e.ctrlKey){
35808 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35810 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35812 }else if(k == e.ESC){
35816 g.startEditing(newCell[0], newCell[1]);
35821 * Ext JS Library 1.1.1
35822 * Copyright(c) 2006-2007, Ext JS, LLC.
35824 * Originally Released Under LGPL - original licence link has changed is not relivant.
35827 * <script type="text/javascript">
35830 * @class Roo.grid.CellSelectionModel
35831 * @extends Roo.grid.AbstractSelectionModel
35832 * This class provides the basic implementation for cell selection in a grid.
35834 * @param {Object} config The object containing the configuration of this model.
35836 Roo.grid.CellSelectionModel = function(config){
35837 Roo.apply(this, config);
35839 this.selection = null;
35843 * @event beforerowselect
35844 * Fires before a cell is selected.
35845 * @param {SelectionModel} this
35846 * @param {Number} rowIndex The selected row index
35847 * @param {Number} colIndex The selected cell index
35849 "beforecellselect" : true,
35851 * @event cellselect
35852 * Fires when a cell is selected.
35853 * @param {SelectionModel} this
35854 * @param {Number} rowIndex The selected row index
35855 * @param {Number} colIndex The selected cell index
35857 "cellselect" : true,
35859 * @event selectionchange
35860 * Fires when the active selection changes.
35861 * @param {SelectionModel} this
35862 * @param {Object} selection null for no selection or an object (o) with two properties
35864 <li>o.record: the record object for the row the selection is in</li>
35865 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35868 "selectionchange" : true
35870 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35873 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35876 initEvents : function(){
35877 this.grid.on("mousedown", this.handleMouseDown, this);
35878 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35879 var view = this.grid.view;
35880 view.on("refresh", this.onViewChange, this);
35881 view.on("rowupdated", this.onRowUpdated, this);
35882 view.on("beforerowremoved", this.clearSelections, this);
35883 view.on("beforerowsinserted", this.clearSelections, this);
35884 if(this.grid.isEditor){
35885 this.grid.on("beforeedit", this.beforeEdit, this);
35890 beforeEdit : function(e){
35891 this.select(e.row, e.column, false, true, e.record);
35895 onRowUpdated : function(v, index, r){
35896 if(this.selection && this.selection.record == r){
35897 v.onCellSelect(index, this.selection.cell[1]);
35902 onViewChange : function(){
35903 this.clearSelections(true);
35907 * Returns the currently selected cell,.
35908 * @return {Array} The selected cell (row, column) or null if none selected.
35910 getSelectedCell : function(){
35911 return this.selection ? this.selection.cell : null;
35915 * Clears all selections.
35916 * @param {Boolean} true to prevent the gridview from being notified about the change.
35918 clearSelections : function(preventNotify){
35919 var s = this.selection;
35921 if(preventNotify !== true){
35922 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35924 this.selection = null;
35925 this.fireEvent("selectionchange", this, null);
35930 * Returns true if there is a selection.
35931 * @return {Boolean}
35933 hasSelection : function(){
35934 return this.selection ? true : false;
35938 handleMouseDown : function(e, t){
35939 var v = this.grid.getView();
35940 if(this.isLocked()){
35943 var row = v.findRowIndex(t);
35944 var cell = v.findCellIndex(t);
35945 if(row !== false && cell !== false){
35946 this.select(row, cell);
35952 * @param {Number} rowIndex
35953 * @param {Number} collIndex
35955 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35956 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35957 this.clearSelections();
35958 r = r || this.grid.dataSource.getAt(rowIndex);
35961 cell : [rowIndex, colIndex]
35963 if(!preventViewNotify){
35964 var v = this.grid.getView();
35965 v.onCellSelect(rowIndex, colIndex);
35966 if(preventFocus !== true){
35967 v.focusCell(rowIndex, colIndex);
35970 this.fireEvent("cellselect", this, rowIndex, colIndex);
35971 this.fireEvent("selectionchange", this, this.selection);
35976 isSelectable : function(rowIndex, colIndex, cm){
35977 return !cm.isHidden(colIndex);
35981 handleKeyDown : function(e){
35982 Roo.log('Cell Sel Model handleKeyDown');
35983 if(!e.isNavKeyPress()){
35986 var g = this.grid, s = this.selection;
35989 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35991 this.select(cell[0], cell[1]);
35996 var walk = function(row, col, step){
35997 return g.walkCells(row, col, step, sm.isSelectable, sm);
35999 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
36004 // handled by onEditorKey
36005 if (g.isEditor && g.editing) {
36009 newCell = walk(r, c-1, -1);
36011 newCell = walk(r, c+1, 1);
36015 newCell = walk(r+1, c, 1);
36018 newCell = walk(r-1, c, -1);
36021 newCell = walk(r, c+1, 1);
36024 newCell = walk(r, c-1, -1);
36027 if(g.isEditor && !g.editing){
36028 g.startEditing(r, c);
36035 this.select(newCell[0], newCell[1]);
36040 acceptsNav : function(row, col, cm){
36041 return !cm.isHidden(col) && cm.isCellEditable(col, row);
36044 onEditorKey : function(field, e){
36046 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
36047 ///Roo.log('onEditorKey' + k);
36051 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
36053 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
36056 }else if(k == e.ENTER && !e.ctrlKey){
36059 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
36060 }else if(k == e.ESC){
36066 //Roo.log('next cell after edit');
36067 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
36072 * Ext JS Library 1.1.1
36073 * Copyright(c) 2006-2007, Ext JS, LLC.
36075 * Originally Released Under LGPL - original licence link has changed is not relivant.
36078 * <script type="text/javascript">
36082 * @class Roo.grid.EditorGrid
36083 * @extends Roo.grid.Grid
36084 * Class for creating and editable grid.
36085 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36086 * The container MUST have some type of size defined for the grid to fill. The container will be
36087 * automatically set to position relative if it isn't already.
36088 * @param {Object} dataSource The data model to bind to
36089 * @param {Object} colModel The column model with info about this grid's columns
36091 Roo.grid.EditorGrid = function(container, config){
36092 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
36093 this.getGridEl().addClass("xedit-grid");
36095 if(!this.selModel){
36096 this.selModel = new Roo.grid.CellSelectionModel();
36099 this.activeEditor = null;
36103 * @event beforeedit
36104 * Fires before cell editing is triggered. The edit event object has the following properties <br />
36105 * <ul style="padding:5px;padding-left:16px;">
36106 * <li>grid - This grid</li>
36107 * <li>record - The record being edited</li>
36108 * <li>field - The field name being edited</li>
36109 * <li>value - The value for the field being edited.</li>
36110 * <li>row - The grid row index</li>
36111 * <li>column - The grid column index</li>
36112 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
36114 * @param {Object} e An edit event (see above for description)
36116 "beforeedit" : true,
36119 * Fires after a cell is edited. <br />
36120 * <ul style="padding:5px;padding-left:16px;">
36121 * <li>grid - This grid</li>
36122 * <li>record - The record being edited</li>
36123 * <li>field - The field name being edited</li>
36124 * <li>value - The value being set</li>
36125 * <li>originalValue - The original value for the field, before the edit.</li>
36126 * <li>row - The grid row index</li>
36127 * <li>column - The grid column index</li>
36129 * @param {Object} e An edit event (see above for description)
36131 "afteredit" : true,
36133 * @event validateedit
36134 * Fires after a cell is edited, but before the value is set in the record.
36135 * You can use this to modify the value being set in the field, Return false
36136 * to cancel the change. The edit event object has the following properties <br />
36137 * <ul style="padding:5px;padding-left:16px;">
36138 * <li>editor - This editor</li>
36139 * <li>grid - This grid</li>
36140 * <li>record - The record being edited</li>
36141 * <li>field - The field name being edited</li>
36142 * <li>value - The value being set</li>
36143 * <li>originalValue - The original value for the field, before the edit.</li>
36144 * <li>row - The grid row index</li>
36145 * <li>column - The grid column index</li>
36146 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
36148 * @param {Object} e An edit event (see above for description)
36150 "validateedit" : true
36152 this.on("bodyscroll", this.stopEditing, this);
36153 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
36156 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
36158 * @cfg {Number} clicksToEdit
36159 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
36166 trackMouseOver: false, // causes very odd FF errors
36168 onCellDblClick : function(g, row, col){
36169 this.startEditing(row, col);
36172 onEditComplete : function(ed, value, startValue){
36173 this.editing = false;
36174 this.activeEditor = null;
36175 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
36177 var field = this.colModel.getDataIndex(ed.col);
36182 originalValue: startValue,
36189 if(String(value) !== String(startValue)){
36191 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
36192 r.set(field, e.value);
36193 // if we are dealing with a combo box..
36194 // then we also set the 'name' colum to be the displayField
36195 if (ed.field.displayField && ed.field.name) {
36196 r.set(ed.field.name, ed.field.el.dom.value);
36199 delete e.cancel; //?? why!!!
36200 this.fireEvent("afteredit", e);
36203 this.fireEvent("afteredit", e); // always fire it!
36205 this.view.focusCell(ed.row, ed.col);
36209 * Starts editing the specified for the specified row/column
36210 * @param {Number} rowIndex
36211 * @param {Number} colIndex
36213 startEditing : function(row, col){
36214 this.stopEditing();
36215 if(this.colModel.isCellEditable(col, row)){
36216 this.view.ensureVisible(row, col, true);
36217 var r = this.dataSource.getAt(row);
36218 var field = this.colModel.getDataIndex(col);
36223 value: r.data[field],
36228 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
36229 this.editing = true;
36230 var ed = this.colModel.getCellEditor(col, row);
36236 ed.render(ed.parentEl || document.body);
36239 (function(){ // complex but required for focus issues in safari, ie and opera
36243 ed.on("complete", this.onEditComplete, this, {single: true});
36244 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
36245 this.activeEditor = ed;
36246 var v = r.data[field];
36247 ed.startEdit(this.view.getCell(row, col), v);
36248 // combo's with 'displayField and name set
36249 if (ed.field.displayField && ed.field.name) {
36250 ed.field.el.dom.value = r.data[ed.field.name];
36254 }).defer(50, this);
36260 * Stops any active editing
36262 stopEditing : function(){
36263 if(this.activeEditor){
36264 this.activeEditor.completeEdit();
36266 this.activeEditor = null;
36270 * Ext JS Library 1.1.1
36271 * Copyright(c) 2006-2007, Ext JS, LLC.
36273 * Originally Released Under LGPL - original licence link has changed is not relivant.
36276 * <script type="text/javascript">
36279 // private - not really -- you end up using it !
36280 // This is a support class used internally by the Grid components
36283 * @class Roo.grid.GridEditor
36284 * @extends Roo.Editor
36285 * Class for creating and editable grid elements.
36286 * @param {Object} config any settings (must include field)
36288 Roo.grid.GridEditor = function(field, config){
36289 if (!config && field.field) {
36291 field = Roo.factory(config.field, Roo.form);
36293 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
36294 field.monitorTab = false;
36297 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
36300 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
36303 alignment: "tl-tl",
36306 cls: "x-small-editor x-grid-editor",
36311 * Ext JS Library 1.1.1
36312 * Copyright(c) 2006-2007, Ext JS, LLC.
36314 * Originally Released Under LGPL - original licence link has changed is not relivant.
36317 * <script type="text/javascript">
36322 Roo.grid.PropertyRecord = Roo.data.Record.create([
36323 {name:'name',type:'string'}, 'value'
36327 Roo.grid.PropertyStore = function(grid, source){
36329 this.store = new Roo.data.Store({
36330 recordType : Roo.grid.PropertyRecord
36332 this.store.on('update', this.onUpdate, this);
36334 this.setSource(source);
36336 Roo.grid.PropertyStore.superclass.constructor.call(this);
36341 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
36342 setSource : function(o){
36344 this.store.removeAll();
36347 if(this.isEditableValue(o[k])){
36348 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
36351 this.store.loadRecords({records: data}, {}, true);
36354 onUpdate : function(ds, record, type){
36355 if(type == Roo.data.Record.EDIT){
36356 var v = record.data['value'];
36357 var oldValue = record.modified['value'];
36358 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
36359 this.source[record.id] = v;
36361 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
36368 getProperty : function(row){
36369 return this.store.getAt(row);
36372 isEditableValue: function(val){
36373 if(val && val instanceof Date){
36375 }else if(typeof val == 'object' || typeof val == 'function'){
36381 setValue : function(prop, value){
36382 this.source[prop] = value;
36383 this.store.getById(prop).set('value', value);
36386 getSource : function(){
36387 return this.source;
36391 Roo.grid.PropertyColumnModel = function(grid, store){
36394 g.PropertyColumnModel.superclass.constructor.call(this, [
36395 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
36396 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
36398 this.store = store;
36399 this.bselect = Roo.DomHelper.append(document.body, {
36400 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
36401 {tag: 'option', value: 'true', html: 'true'},
36402 {tag: 'option', value: 'false', html: 'false'}
36405 Roo.id(this.bselect);
36408 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
36409 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
36410 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
36411 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
36412 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36414 this.renderCellDelegate = this.renderCell.createDelegate(this);
36415 this.renderPropDelegate = this.renderProp.createDelegate(this);
36418 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36422 valueText : 'Value',
36424 dateFormat : 'm/j/Y',
36427 renderDate : function(dateVal){
36428 return dateVal.dateFormat(this.dateFormat);
36431 renderBool : function(bVal){
36432 return bVal ? 'true' : 'false';
36435 isCellEditable : function(colIndex, rowIndex){
36436 return colIndex == 1;
36439 getRenderer : function(col){
36441 this.renderCellDelegate : this.renderPropDelegate;
36444 renderProp : function(v){
36445 return this.getPropertyName(v);
36448 renderCell : function(val){
36450 if(val instanceof Date){
36451 rv = this.renderDate(val);
36452 }else if(typeof val == 'boolean'){
36453 rv = this.renderBool(val);
36455 return Roo.util.Format.htmlEncode(rv);
36458 getPropertyName : function(name){
36459 var pn = this.grid.propertyNames;
36460 return pn && pn[name] ? pn[name] : name;
36463 getCellEditor : function(colIndex, rowIndex){
36464 var p = this.store.getProperty(rowIndex);
36465 var n = p.data['name'], val = p.data['value'];
36467 if(typeof(this.grid.customEditors[n]) == 'string'){
36468 return this.editors[this.grid.customEditors[n]];
36470 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36471 return this.grid.customEditors[n];
36473 if(val instanceof Date){
36474 return this.editors['date'];
36475 }else if(typeof val == 'number'){
36476 return this.editors['number'];
36477 }else if(typeof val == 'boolean'){
36478 return this.editors['boolean'];
36480 return this.editors['string'];
36486 * @class Roo.grid.PropertyGrid
36487 * @extends Roo.grid.EditorGrid
36488 * This class represents the interface of a component based property grid control.
36489 * <br><br>Usage:<pre><code>
36490 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36498 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36499 * The container MUST have some type of size defined for the grid to fill. The container will be
36500 * automatically set to position relative if it isn't already.
36501 * @param {Object} config A config object that sets properties on this grid.
36503 Roo.grid.PropertyGrid = function(container, config){
36504 config = config || {};
36505 var store = new Roo.grid.PropertyStore(this);
36506 this.store = store;
36507 var cm = new Roo.grid.PropertyColumnModel(this, store);
36508 store.store.sort('name', 'ASC');
36509 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36512 enableColLock:false,
36513 enableColumnMove:false,
36515 trackMouseOver: false,
36518 this.getGridEl().addClass('x-props-grid');
36519 this.lastEditRow = null;
36520 this.on('columnresize', this.onColumnResize, this);
36523 * @event beforepropertychange
36524 * Fires before a property changes (return false to stop?)
36525 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36526 * @param {String} id Record Id
36527 * @param {String} newval New Value
36528 * @param {String} oldval Old Value
36530 "beforepropertychange": true,
36532 * @event propertychange
36533 * Fires after a property changes
36534 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36535 * @param {String} id Record Id
36536 * @param {String} newval New Value
36537 * @param {String} oldval Old Value
36539 "propertychange": true
36541 this.customEditors = this.customEditors || {};
36543 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36546 * @cfg {Object} customEditors map of colnames=> custom editors.
36547 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36548 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36549 * false disables editing of the field.
36553 * @cfg {Object} propertyNames map of property Names to their displayed value
36556 render : function(){
36557 Roo.grid.PropertyGrid.superclass.render.call(this);
36558 this.autoSize.defer(100, this);
36561 autoSize : function(){
36562 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36564 this.view.fitColumns();
36568 onColumnResize : function(){
36569 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36573 * Sets the data for the Grid
36574 * accepts a Key => Value object of all the elements avaiable.
36575 * @param {Object} data to appear in grid.
36577 setSource : function(source){
36578 this.store.setSource(source);
36582 * Gets all the data from the grid.
36583 * @return {Object} data data stored in grid
36585 getSource : function(){
36586 return this.store.getSource();
36590 * Ext JS Library 1.1.1
36591 * Copyright(c) 2006-2007, Ext JS, LLC.
36593 * Originally Released Under LGPL - original licence link has changed is not relivant.
36596 * <script type="text/javascript">
36600 * @class Roo.LoadMask
36601 * A simple utility class for generically masking elements while loading data. If the element being masked has
36602 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36603 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36604 * element's UpdateManager load indicator and will be destroyed after the initial load.
36606 * Create a new LoadMask
36607 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36608 * @param {Object} config The config object
36610 Roo.LoadMask = function(el, config){
36611 this.el = Roo.get(el);
36612 Roo.apply(this, config);
36614 this.store.on('beforeload', this.onBeforeLoad, this);
36615 this.store.on('load', this.onLoad, this);
36616 this.store.on('loadexception', this.onLoad, this);
36617 this.removeMask = false;
36619 var um = this.el.getUpdateManager();
36620 um.showLoadIndicator = false; // disable the default indicator
36621 um.on('beforeupdate', this.onBeforeLoad, this);
36622 um.on('update', this.onLoad, this);
36623 um.on('failure', this.onLoad, this);
36624 this.removeMask = true;
36628 Roo.LoadMask.prototype = {
36630 * @cfg {Boolean} removeMask
36631 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36632 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36635 * @cfg {String} msg
36636 * The text to display in a centered loading message box (defaults to 'Loading...')
36638 msg : 'Loading...',
36640 * @cfg {String} msgCls
36641 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36643 msgCls : 'x-mask-loading',
36646 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36652 * Disables the mask to prevent it from being displayed
36654 disable : function(){
36655 this.disabled = true;
36659 * Enables the mask so that it can be displayed
36661 enable : function(){
36662 this.disabled = false;
36666 onLoad : function(){
36667 this.el.unmask(this.removeMask);
36671 onBeforeLoad : function(){
36672 if(!this.disabled){
36673 this.el.mask(this.msg, this.msgCls);
36678 destroy : function(){
36680 this.store.un('beforeload', this.onBeforeLoad, this);
36681 this.store.un('load', this.onLoad, this);
36682 this.store.un('loadexception', this.onLoad, this);
36684 var um = this.el.getUpdateManager();
36685 um.un('beforeupdate', this.onBeforeLoad, this);
36686 um.un('update', this.onLoad, this);
36687 um.un('failure', this.onLoad, this);
36692 * Ext JS Library 1.1.1
36693 * Copyright(c) 2006-2007, Ext JS, LLC.
36695 * Originally Released Under LGPL - original licence link has changed is not relivant.
36698 * <script type="text/javascript">
36700 Roo.XTemplate = function(){
36701 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36704 s = ['<tpl>', s, '</tpl>'].join('');
36706 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36708 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36709 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36710 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36714 while(m = s.match(re)){
36715 var m2 = m[0].match(nameRe);
36716 var m3 = m[0].match(ifRe);
36717 var m4 = m[0].match(execRe);
36718 var exp = null, fn = null, exec = null;
36719 var name = m2 && m2[1] ? m2[1] : '';
36721 exp = m3 && m3[1] ? m3[1] : null;
36723 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36727 exp = m4 && m4[1] ? m4[1] : null;
36729 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36734 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36735 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36736 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36746 s = s.replace(m[0], '{xtpl'+ id + '}');
36749 for(var i = tpls.length-1; i >= 0; --i){
36750 this.compileTpl(tpls[i]);
36752 this.master = tpls[tpls.length-1];
36755 Roo.extend(Roo.XTemplate, Roo.Template, {
36757 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36759 applySubTemplate : function(id, values, parent){
36760 var t = this.tpls[id];
36761 if(t.test && !t.test.call(this, values, parent)){
36764 if(t.exec && t.exec.call(this, values, parent)){
36767 var vs = t.target ? t.target.call(this, values, parent) : values;
36768 parent = t.target ? values : parent;
36769 if(t.target && vs instanceof Array){
36771 for(var i = 0, len = vs.length; i < len; i++){
36772 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36774 return buf.join('');
36776 return t.compiled.call(this, vs, parent);
36779 compileTpl : function(tpl){
36780 var fm = Roo.util.Format;
36781 var useF = this.disableFormats !== true;
36782 var sep = Roo.isGecko ? "+" : ",";
36783 var fn = function(m, name, format, args){
36784 if(name.substr(0, 4) == 'xtpl'){
36785 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36788 if(name.indexOf('.') != -1){
36791 v = "values['" + name + "']";
36793 if(format && useF){
36794 args = args ? ',' + args : "";
36795 if(format.substr(0, 5) != "this."){
36796 format = "fm." + format + '(';
36798 format = 'this.call("'+ format.substr(5) + '", ';
36802 args= ''; format = "("+v+" === undefined ? '' : ";
36804 return "'"+ sep + format + v + args + ")"+sep+"'";
36807 // branched to use + in gecko and [].join() in others
36809 body = "tpl.compiled = function(values, parent){ return '" +
36810 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36813 body = ["tpl.compiled = function(values, parent){ return ['"];
36814 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36815 body.push("'].join('');};");
36816 body = body.join('');
36818 /** eval:var:zzzzzzz */
36823 applyTemplate : function(values){
36824 return this.master.compiled.call(this, values, {});
36828 apply : function(){
36829 return this.applyTemplate.apply(this, arguments);
36832 compile : function(){return this;}
36835 Roo.XTemplate.from = function(el){
36836 el = Roo.getDom(el);
36837 return new Roo.XTemplate(el.value || el.innerHTML);
36839 * Original code for Roojs - LGPL
36840 * <script type="text/javascript">
36844 * @class Roo.XComponent
36845 * A delayed Element creator...
36846 * Or a way to group chunks of interface together.
36848 * Mypart.xyx = new Roo.XComponent({
36850 parent : 'Mypart.xyz', // empty == document.element.!!
36854 disabled : function() {}
36856 tree : function() { // return an tree of xtype declared components
36860 xtype : 'NestedLayoutPanel',
36867 * It can be used to build a big heiracy, with parent etc.
36868 * or you can just use this to render a single compoent to a dom element
36869 * MYPART.render(Roo.Element | String(id) | dom_element )
36871 * @extends Roo.util.Observable
36873 * @param cfg {Object} configuration of component
36876 Roo.XComponent = function(cfg) {
36877 Roo.apply(this, cfg);
36881 * Fires when this the componnt is built
36882 * @param {Roo.XComponent} c the component
36886 * @event buildcomplete
36887 * Fires on the top level element when all elements have been built
36888 * @param {Roo.XComponent} c the top level component.
36890 'buildcomplete' : true
36893 this.region = this.region || 'center'; // default..
36894 Roo.XComponent.register(this);
36895 this.modules = false;
36896 this.el = false; // where the layout goes..
36900 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36903 * The created element (with Roo.factory())
36904 * @type {Roo.Layout}
36910 * for BC - use el in new code
36911 * @type {Roo.Layout}
36917 * for BC - use el in new code
36918 * @type {Roo.Layout}
36923 * @cfg {Function|boolean} disabled
36924 * If this module is disabled by some rule, return true from the funtion
36929 * @cfg {String} parent
36930 * Name of parent element which it get xtype added to..
36935 * @cfg {String} order
36936 * Used to set the order in which elements are created (usefull for multiple tabs)
36941 * @cfg {String} name
36942 * String to display while loading.
36946 * @cfg {String} region
36947 * Region to render component to (defaults to center)
36952 * @cfg {Array} items
36953 * A single item array - the first element is the root of the tree..
36954 * It's done this way to stay compatible with the Xtype system...
36961 * render element to dom or tree
36962 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
36965 render : function(el)
36969 var hp = this.parent ? 1 : 0;
36971 if (!el && typeof(this.parent) == 'string' && this.parent[0] == '#') {
36972 // if parent is a '#.....' string, then let's use that..
36973 var ename = this.parent.substr(1)
36974 this.parent = false;
36975 el = Roo.get(ename);
36977 Roo.log("Warning - element can not be found :#" + ename );
36983 if (!this.parent) {
36985 el = el ? Roo.get(el) : false;
36987 // it's a top level one..
36989 el : new Roo.BorderLayout(el || document.body, {
36995 tabPosition: 'top',
36996 //resizeTabs: true,
36997 alwaysShowTabs: el && hp? false : true,
36998 hideTabs: el || !hp ? true : false,
37007 var tree = this.tree();
37008 tree.region = tree.region || this.region;
37009 this.el = this.parent.el.addxtype(tree);
37010 this.fireEvent('built', this);
37012 this.panel = this.el;
37013 this.layout = this.panel.layout;
37019 Roo.apply(Roo.XComponent, {
37022 * @property buildCompleted
37023 * True when the builder has completed building the interface.
37026 buildCompleted : false,
37029 * @property topModule
37030 * the upper most module - uses document.element as it's constructor.
37037 * @property modules
37038 * array of modules to be created by registration system.
37039 * @type {Array} of Roo.XComponent
37044 * @property elmodules
37045 * array of modules to be created by which use #ID
37046 * @type {Array} of Roo.XComponent
37053 * Register components to be built later.
37055 * This solves the following issues
37056 * - Building is not done on page load, but after an authentication process has occured.
37057 * - Interface elements are registered on page load
37058 * - Parent Interface elements may not be loaded before child, so this handles that..
37065 module : 'Pman.Tab.projectMgr',
37067 parent : 'Pman.layout',
37068 disabled : false, // or use a function..
37071 * * @param {Object} details about module
37073 register : function(obj) {
37074 this.modules.push(obj);
37078 * convert a string to an object..
37079 * eg. 'AAA.BBB' -> finds AAA.BBB
37083 toObject : function(str)
37085 if (!str || typeof(str) == 'object') {
37092 var ar = str.split('.');
37096 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
37098 throw "Module not found : " + str;
37100 Roo.each(ar, function(e) {
37101 if (typeof(o[e]) == 'undefined') {
37102 throw "Module not found : " + str;
37113 * move modules into their correct place in the tree..
37116 preBuild : function ()
37119 Roo.each(this.modules , function (obj)
37121 var opar = obj.parent;
37122 obj.parent = this.toObject(opar);
37125 this.topModule = obj;
37128 if (typeof(obj.parent) == 'string') {
37129 this.elmodules.push(obj);
37132 if (obj.parent.constructor != Roo.XComponent) {
37133 Roo.log("Object Parent is not instance of XComponent:" + obj.name)
37135 if (!obj.parent.modules) {
37136 obj.parent.modules = new Roo.util.MixedCollection(false,
37137 function(o) { return o.order + '' }
37141 obj.parent.modules.add(obj);
37146 * make a list of modules to build.
37147 * @return {Array} list of modules.
37150 buildOrder : function()
37153 var cmp = function(a,b) {
37154 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
37156 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
37157 throw "No top level modules to build";
37160 // make a flat list in order of modules to build.
37161 var mods = this.topModule ? [ this.topModule ] : [];
37162 Roo.each(this.elmodules,function(e) { mods.push(e) });
37165 // add modules to their parents..
37166 var addMod = function(m) {
37167 // Roo.debug && Roo.log(m.modKey);
37171 m.modules.keySort('ASC', cmp );
37172 m.modules.each(addMod);
37174 // not sure if this is used any more..
37176 m.finalize.name = m.name + " (clean up) ";
37177 mods.push(m.finalize);
37181 if (this.topModule) {
37182 this.topModule.modules.keySort('ASC', cmp );
37183 this.topModule.modules.each(addMod);
37189 * Build the registered modules.
37190 * @param {Object} parent element.
37191 * @param {Function} optional method to call after module has been added.
37199 var mods = this.buildOrder();
37201 //this.allmods = mods;
37202 //Roo.debug && Roo.log(mods);
37204 if (!mods.length) { // should not happen
37205 throw "NO modules!!!";
37210 // flash it up as modal - so we store the mask!?
37211 Roo.MessageBox.show({ title: 'loading' });
37212 Roo.MessageBox.show({
37213 title: "Please wait...",
37214 msg: "Building Interface...",
37221 var total = mods.length;
37224 var progressRun = function() {
37225 if (!mods.length) {
37226 Roo.debug && Roo.log('hide?');
37227 Roo.MessageBox.hide();
37228 if (_this.topModule) {
37229 _this.topModule.fireEvent('buildcomplete', _this.topModule);
37235 var m = mods.shift();
37238 Roo.debug && Roo.log(m);
37239 // not sure if this is supported any more.. - modules that are are just function
37240 if (typeof(m) == 'function') {
37242 return progressRun.defer(10, _this);
37247 Roo.MessageBox.updateProgress(
37248 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
37250 (m.name ? (' - ' + m.name) : '')
37254 // is the module disabled?
37255 var disabled = (typeof(m.disabled) == 'function') ?
37256 m.disabled.call(m.module.disabled) : m.disabled;
37260 return progressRun(); // we do not update the display!
37266 // it's 10 on top level, and 1 on others??? why...
37267 return progressRun.defer(10, _this);
37270 progressRun.defer(1, _this);
37281 //<script type="text/javascript">
37286 * @extends Roo.LayoutDialog
37287 * A generic Login Dialog..... - only one needed in theory!?!?
37289 * Fires XComponent builder on success...
37292 * username,password, lang = for login actions.
37293 * check = 1 for periodic checking that sesion is valid.
37294 * passwordRequest = email request password
37295 * logout = 1 = to logout
37297 * Affects: (this id="????" elements)
37298 * loading (removed) (used to indicate application is loading)
37299 * loading-mask (hides) (used to hide application when it's building loading)
37305 * Myapp.login = Roo.Login({
37321 Roo.Login = function(cfg)
37327 Roo.apply(this,cfg);
37329 Roo.onReady(function() {
37335 Roo.Login.superclass.constructor.call(this, this);
37336 //this.addxtype(this.items[0]);
37342 Roo.extend(Roo.Login, Roo.LayoutDialog, {
37345 * @cfg {String} method
37346 * Method used to query for login details.
37351 * @cfg {String} url
37352 * URL to query login data. - eg. baseURL + '/Login.php'
37358 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
37363 * @property checkFails
37364 * Number of times we have attempted to get authentication check, and failed.
37369 * @property intervalID
37370 * The window interval that does the constant login checking.
37376 onLoad : function() // called on page load...
37380 if (Roo.get('loading')) { // clear any loading indicator..
37381 Roo.get('loading').remove();
37384 //this.switchLang('en'); // set the language to english..
37387 success: function(response, opts) { // check successfull...
37389 var res = this.processResponse(response);
37390 this.checkFails =0;
37391 if (!res.success) { // error!
37392 this.checkFails = 5;
37393 //console.log('call failure');
37394 return this.failure(response,opts);
37397 if (!res.data.id) { // id=0 == login failure.
37398 return this.show();
37402 //console.log(success);
37403 this.fillAuth(res.data);
37404 this.checkFails =0;
37405 Roo.XComponent.build();
37407 failure : this.show
37413 check: function(cfg) // called every so often to refresh cookie etc..
37415 if (cfg.again) { // could be undefined..
37418 this.checkFails = 0;
37421 if (this.sending) {
37422 if ( this.checkFails > 4) {
37423 Roo.MessageBox.alert("Error",
37424 "Error getting authentication status. - try reloading, or wait a while", function() {
37425 _this.sending = false;
37430 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
37433 this.sending = true;
37440 method: this.method,
37441 success: cfg.success || this.success,
37442 failure : cfg.failure || this.failure,
37452 window.onbeforeunload = function() { }; // false does not work for IE..
37462 failure : function() {
37463 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
37464 document.location = document.location.toString() + '?ts=' + Math.random();
37468 success : function() {
37469 _this.user = false;
37470 this.checkFails =0;
37472 document.location = document.location.toString() + '?ts=' + Math.random();
37479 processResponse : function (response)
37483 res = Roo.decode(response.responseText);
37485 if (typeof(res) != 'object') {
37486 res = { success : false, errorMsg : res, errors : true };
37488 if (typeof(res.success) == 'undefined') {
37489 res.success = false;
37493 res = { success : false, errorMsg : response.responseText, errors : true };
37498 success : function(response, opts) // check successfull...
37500 this.sending = false;
37501 var res = this.processResponse(response);
37502 if (!res.success) {
37503 return this.failure(response, opts);
37505 if (!res.data || !res.data.id) {
37506 return this.failure(response,opts);
37508 //console.log(res);
37509 this.fillAuth(res.data);
37511 this.checkFails =0;
37516 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37518 this.authUser = -1;
37519 this.sending = false;
37520 var res = this.processResponse(response);
37521 //console.log(res);
37522 if ( this.checkFails > 2) {
37524 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37525 "Error getting authentication status. - try reloading");
37528 opts.callCfg.again = true;
37529 this.check.defer(1000, this, [ opts.callCfg ]);
37535 fillAuth: function(au) {
37536 this.startAuthCheck();
37537 this.authUserId = au.id;
37538 this.authUser = au;
37539 this.lastChecked = new Date();
37540 this.fireEvent('refreshed', au);
37541 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37542 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37543 au.lang = au.lang || 'en';
37544 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37545 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37546 this.switchLang(au.lang );
37549 // open system... - -on setyp..
37550 if (this.authUserId < 0) {
37551 Roo.MessageBox.alert("Warning",
37552 "This is an open system - please set up a admin user with a password.");
37555 //Pman.onload(); // which should do nothing if it's a re-auth result...
37560 startAuthCheck : function() // starter for timeout checking..
37562 if (this.intervalID) { // timer already in place...
37566 this.intervalID = window.setInterval(function() {
37567 _this.check(false);
37568 }, 120000); // every 120 secs = 2mins..
37574 switchLang : function (lang)
37576 _T = typeof(_T) == 'undefined' ? false : _T;
37577 if (!_T || !lang.length) {
37581 if (!_T && lang != 'en') {
37582 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37586 if (typeof(_T.en) == 'undefined') {
37588 Roo.apply(_T.en, _T);
37591 if (typeof(_T[lang]) == 'undefined') {
37592 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37597 Roo.apply(_T, _T[lang]);
37598 // just need to set the text values for everything...
37600 /* this will not work ...
37604 function formLabel(name, val) {
37605 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37608 formLabel('password', "Password"+':');
37609 formLabel('username', "Email Address"+':');
37610 formLabel('lang', "Language"+':');
37611 this.dialog.setTitle("Login");
37612 this.dialog.buttons[0].setText("Forgot Password");
37613 this.dialog.buttons[1].setText("Login");
37632 collapsible: false,
37634 center: { // needed??
37637 // tabPosition: 'top',
37640 alwaysShowTabs: false
37644 show : function(dlg)
37646 //console.log(this);
37647 this.form = this.layout.getRegion('center').activePanel.form;
37648 this.form.dialog = dlg;
37649 this.buttons[0].form = this.form;
37650 this.buttons[0].dialog = dlg;
37651 this.buttons[1].form = this.form;
37652 this.buttons[1].dialog = dlg;
37654 //this.resizeToLogo.defer(1000,this);
37655 // this is all related to resizing for logos..
37656 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37658 // this.resizeToLogo.defer(1000,this);
37661 //var w = Ext.lib.Dom.getViewWidth() - 100;
37662 //var h = Ext.lib.Dom.getViewHeight() - 100;
37663 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37665 if (this.disabled) {
37670 if (this.user.id < 0) { // used for inital setup situations.
37674 if (this.intervalID) {
37675 // remove the timer
37676 window.clearInterval(this.intervalID);
37677 this.intervalID = false;
37681 if (Roo.get('loading')) {
37682 Roo.get('loading').remove();
37684 if (Roo.get('loading-mask')) {
37685 Roo.get('loading-mask').hide();
37688 //incomming._node = tnode;
37690 //this.dialog.modal = !modal;
37691 //this.dialog.show();
37695 this.form.setValues({
37696 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37697 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37700 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37701 if (this.form.findField('username').getValue().length > 0 ){
37702 this.form.findField('password').focus();
37704 this.form.findField('username').focus();
37712 xtype : 'ContentPanel',
37724 style : 'margin: 10px;',
37727 actionfailed : function(f, act) {
37728 // form can return { errors: .... }
37730 //act.result.errors // invalid form element list...
37731 //act.result.errorMsg// invalid form element list...
37733 this.dialog.el.unmask();
37734 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37735 "Login failed - communication error - try again.");
37738 actioncomplete: function(re, act) {
37740 Roo.state.Manager.set(
37741 this.dialog.realm + '.username',
37742 this.findField('username').getValue()
37744 Roo.state.Manager.set(
37745 this.dialog.realm + '.lang',
37746 this.findField('lang').getValue()
37749 this.dialog.fillAuth(act.result.data);
37751 this.dialog.hide();
37753 if (Roo.get('loading-mask')) {
37754 Roo.get('loading-mask').show();
37756 Roo.XComponent.build();
37764 xtype : 'TextField',
37766 fieldLabel: "Email Address",
37769 autoCreate : {tag: "input", type: "text", size: "20"}
37772 xtype : 'TextField',
37774 fieldLabel: "Password",
37775 inputType: 'password',
37778 autoCreate : {tag: "input", type: "text", size: "20"},
37780 specialkey : function(e,ev) {
37781 if (ev.keyCode == 13) {
37782 this.form.dialog.el.mask("Logging in");
37783 this.form.doAction('submit', {
37784 url: this.form.dialog.url,
37785 method: this.form.dialog.method
37792 xtype : 'ComboBox',
37794 fieldLabel: "Language",
37797 xtype : 'SimpleStore',
37798 fields: ['lang', 'ldisp'],
37800 [ 'en', 'English' ],
37801 [ 'zh_HK' , '\u7E41\u4E2D' ],
37802 [ 'zh_CN', '\u7C21\u4E2D' ]
37806 valueField : 'lang',
37807 hiddenName: 'lang',
37809 displayField:'ldisp',
37813 triggerAction: 'all',
37814 emptyText:'Select a Language...',
37815 selectOnFocus:true,
37817 select : function(cb, rec, ix) {
37818 this.form.switchLang(rec.data.lang);
37834 text : "Forgot Password",
37836 click : function() {
37837 //console.log(this);
37838 var n = this.form.findField('username').getValue();
37840 Roo.MessageBox.alert("Error", "Fill in your email address");
37844 url: this.dialog.url,
37848 method: this.dialog.method,
37849 success: function(response, opts) { // check successfull...
37851 var res = this.dialog.processResponse(response);
37852 if (!res.success) { // error!
37853 Roo.MessageBox.alert("Error" ,
37854 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37857 Roo.MessageBox.alert("Notice" ,
37858 "Please check you email for the Password Reset message");
37860 failure : function() {
37861 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37874 click : function () {
37876 this.dialog.el.mask("Logging in");
37877 this.form.doAction('submit', {
37878 url: this.dialog.url,
37879 method: this.dialog.method