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 (add/sub/ok/nodrop)
4006 * if the drop point is valid for over/enter..
4013 isNotifyTarget : true,
4018 notifyEnter : function(dd, e, data){
4020 this.fireEvent('enter', dd, e, data);
4022 this.el.addClass(this.overClass);
4024 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4025 this.valid ? this.dropAllowed : this.dropNotAllowed
4032 notifyOver : function(dd, e, data){
4034 this.fireEvent('over', dd, e, data);
4035 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4036 this.valid ? this.dropAllowed : this.dropNotAllowed
4043 notifyOut : function(dd, e, data){
4044 this.fireEvent('out', dd, e, data);
4046 this.el.removeClass(this.overClass);
4053 notifyDrop : function(dd, e, data){
4054 this.success = false;
4055 this.fireEvent('drop', dd, e, data);
4056 return this.success;
4060 * Ext JS Library 1.1.1
4061 * Copyright(c) 2006-2007, Ext JS, LLC.
4063 * Originally Released Under LGPL - original licence link has changed is not relivant.
4066 * <script type="text/javascript">
4071 * @class Roo.dd.DragZone
4072 * @extends Roo.dd.DragSource
4073 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4074 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4076 * @param {String/HTMLElement/Element} el The container element
4077 * @param {Object} config
4079 Roo.dd.DragZone = function(el, config){
4080 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4081 if(this.containerScroll){
4082 Roo.dd.ScrollManager.register(this.el);
4086 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4088 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4089 * for auto scrolling during drag operations.
4092 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4093 * method after a failed drop (defaults to "c3daf9" - light blue)
4097 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4098 * for a valid target to drag based on the mouse down. Override this method
4099 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4100 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4101 * @param {EventObject} e The mouse down event
4102 * @return {Object} The dragData
4104 getDragData : function(e){
4105 return Roo.dd.Registry.getHandleFromEvent(e);
4109 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4110 * this.dragData.ddel
4111 * @param {Number} x The x position of the click on the dragged object
4112 * @param {Number} y The y position of the click on the dragged object
4113 * @return {Boolean} true to continue the drag, false to cancel
4115 onInitDrag : function(x, y){
4116 this.proxy.update(this.dragData.ddel.cloneNode(true));
4117 this.onStartDrag(x, y);
4122 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4124 afterRepair : function(){
4126 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4128 this.dragging = false;
4132 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4133 * the XY of this.dragData.ddel
4134 * @param {EventObject} e The mouse up event
4135 * @return {Array} The xy location (e.g. [100, 200])
4137 getRepairXY : function(e){
4138 return Roo.Element.fly(this.dragData.ddel).getXY();
4142 * Ext JS Library 1.1.1
4143 * Copyright(c) 2006-2007, Ext JS, LLC.
4145 * Originally Released Under LGPL - original licence link has changed is not relivant.
4148 * <script type="text/javascript">
4151 * @class Roo.dd.DropZone
4152 * @extends Roo.dd.DropTarget
4153 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4154 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4156 * @param {String/HTMLElement/Element} el The container element
4157 * @param {Object} config
4159 Roo.dd.DropZone = function(el, config){
4160 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4163 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4165 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4166 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4167 * provide your own custom lookup.
4168 * @param {Event} e The event
4169 * @return {Object} data The custom data
4171 getTargetFromEvent : function(e){
4172 return Roo.dd.Registry.getTargetFromEvent(e);
4176 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4177 * that it has registered. This method has no default implementation and should be overridden to provide
4178 * node-specific processing if necessary.
4179 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4180 * {@link #getTargetFromEvent} for this node)
4181 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4182 * @param {Event} e The event
4183 * @param {Object} data An object containing arbitrary data supplied by the drag source
4185 onNodeEnter : function(n, dd, e, data){
4190 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4191 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4192 * overridden to provide the proper feedback.
4193 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4194 * {@link #getTargetFromEvent} for this node)
4195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4196 * @param {Event} e The event
4197 * @param {Object} data An object containing arbitrary data supplied by the drag source
4198 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4199 * underlying {@link Roo.dd.StatusProxy} can be updated
4201 onNodeOver : function(n, dd, e, data){
4202 return this.dropAllowed;
4206 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4207 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4208 * node-specific processing if necessary.
4209 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4210 * {@link #getTargetFromEvent} for this node)
4211 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4212 * @param {Event} e The event
4213 * @param {Object} data An object containing arbitrary data supplied by the drag source
4215 onNodeOut : function(n, dd, e, data){
4220 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4221 * the drop node. The default implementation returns false, so it should be overridden to provide the
4222 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4223 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4224 * {@link #getTargetFromEvent} for this node)
4225 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4226 * @param {Event} e The event
4227 * @param {Object} data An object containing arbitrary data supplied by the drag source
4228 * @return {Boolean} True if the drop was valid, else false
4230 onNodeDrop : function(n, dd, e, data){
4235 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4236 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4237 * it should be overridden to provide the proper feedback if necessary.
4238 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4239 * @param {Event} e The event
4240 * @param {Object} data An object containing arbitrary data supplied by the drag source
4241 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4242 * underlying {@link Roo.dd.StatusProxy} can be updated
4244 onContainerOver : function(dd, e, data){
4245 return this.dropNotAllowed;
4249 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4250 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4251 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4252 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4253 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4254 * @param {Event} e The event
4255 * @param {Object} data An object containing arbitrary data supplied by the drag source
4256 * @return {Boolean} True if the drop was valid, else false
4258 onContainerDrop : function(dd, e, data){
4263 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4264 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4265 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4266 * you should override this method and provide a custom implementation.
4267 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4268 * @param {Event} e The event
4269 * @param {Object} data An object containing arbitrary data supplied by the drag source
4270 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4271 * underlying {@link Roo.dd.StatusProxy} can be updated
4273 notifyEnter : function(dd, e, data){
4274 return this.dropNotAllowed;
4278 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4279 * This method will be called on every mouse movement while the drag source is over the drop zone.
4280 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4281 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4282 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4283 * registered node, it will call {@link #onContainerOver}.
4284 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4285 * @param {Event} e The event
4286 * @param {Object} data An object containing arbitrary data supplied by the drag source
4287 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4288 * underlying {@link Roo.dd.StatusProxy} can be updated
4290 notifyOver : function(dd, e, data){
4291 var n = this.getTargetFromEvent(e);
4292 if(!n){ // not over valid drop target
4293 if(this.lastOverNode){
4294 this.onNodeOut(this.lastOverNode, dd, e, data);
4295 this.lastOverNode = null;
4297 return this.onContainerOver(dd, e, data);
4299 if(this.lastOverNode != n){
4300 if(this.lastOverNode){
4301 this.onNodeOut(this.lastOverNode, dd, e, data);
4303 this.onNodeEnter(n, dd, e, data);
4304 this.lastOverNode = n;
4306 return this.onNodeOver(n, dd, e, data);
4310 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4311 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4312 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4313 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4314 * @param {Event} e The event
4315 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4317 notifyOut : function(dd, e, data){
4318 if(this.lastOverNode){
4319 this.onNodeOut(this.lastOverNode, dd, e, data);
4320 this.lastOverNode = null;
4325 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4326 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4327 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4328 * otherwise it will call {@link #onContainerDrop}.
4329 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4330 * @param {Event} e The event
4331 * @param {Object} data An object containing arbitrary data supplied by the drag source
4332 * @return {Boolean} True if the drop was valid, else false
4334 notifyDrop : function(dd, e, data){
4335 if(this.lastOverNode){
4336 this.onNodeOut(this.lastOverNode, dd, e, data);
4337 this.lastOverNode = null;
4339 var n = this.getTargetFromEvent(e);
4341 this.onNodeDrop(n, dd, e, data) :
4342 this.onContainerDrop(dd, e, data);
4346 triggerCacheRefresh : function(){
4347 Roo.dd.DDM.refreshCache(this.groups);
4351 * Ext JS Library 1.1.1
4352 * Copyright(c) 2006-2007, Ext JS, LLC.
4354 * Originally Released Under LGPL - original licence link has changed is not relivant.
4357 * <script type="text/javascript">
4362 * @class Roo.data.SortTypes
4364 * Defines the default sorting (casting?) comparison functions used when sorting data.
4366 Roo.data.SortTypes = {
4368 * Default sort that does nothing
4369 * @param {Mixed} s The value being converted
4370 * @return {Mixed} The comparison value
4377 * The regular expression used to strip tags
4381 stripTagsRE : /<\/?[^>]+>/gi,
4384 * Strips all HTML tags to sort on text only
4385 * @param {Mixed} s The value being converted
4386 * @return {String} The comparison value
4388 asText : function(s){
4389 return String(s).replace(this.stripTagsRE, "");
4393 * Strips all HTML tags to sort on text only - Case insensitive
4394 * @param {Mixed} s The value being converted
4395 * @return {String} The comparison value
4397 asUCText : function(s){
4398 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4402 * Case insensitive string
4403 * @param {Mixed} s The value being converted
4404 * @return {String} The comparison value
4406 asUCString : function(s) {
4407 return String(s).toUpperCase();
4412 * @param {Mixed} s The value being converted
4413 * @return {Number} The comparison value
4415 asDate : function(s) {
4419 if(s instanceof Date){
4422 return Date.parse(String(s));
4427 * @param {Mixed} s The value being converted
4428 * @return {Float} The comparison value
4430 asFloat : function(s) {
4431 var val = parseFloat(String(s).replace(/,/g, ""));
4432 if(isNaN(val)) val = 0;
4438 * @param {Mixed} s The value being converted
4439 * @return {Number} The comparison value
4441 asInt : function(s) {
4442 var val = parseInt(String(s).replace(/,/g, ""));
4443 if(isNaN(val)) val = 0;
4448 * Ext JS Library 1.1.1
4449 * Copyright(c) 2006-2007, Ext JS, LLC.
4451 * Originally Released Under LGPL - original licence link has changed is not relivant.
4454 * <script type="text/javascript">
4458 * @class Roo.data.Record
4459 * Instances of this class encapsulate both record <em>definition</em> information, and record
4460 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4461 * to access Records cached in an {@link Roo.data.Store} object.<br>
4463 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4464 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4467 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4469 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4470 * {@link #create}. The parameters are the same.
4471 * @param {Array} data An associative Array of data values keyed by the field name.
4472 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4473 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4474 * not specified an integer id is generated.
4476 Roo.data.Record = function(data, id){
4477 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4482 * Generate a constructor for a specific record layout.
4483 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4484 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4485 * Each field definition object may contain the following properties: <ul>
4486 * <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,
4487 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4488 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4489 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4490 * is being used, then this is a string containing the javascript expression to reference the data relative to
4491 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4492 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4493 * this may be omitted.</p></li>
4494 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4495 * <ul><li>auto (Default, implies no conversion)</li>
4500 * <li>date</li></ul></p></li>
4501 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4502 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4503 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4504 * by the Reader into an object that will be stored in the Record. It is passed the
4505 * following parameters:<ul>
4506 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4508 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4510 * <br>usage:<br><pre><code>
4511 var TopicRecord = Roo.data.Record.create(
4512 {name: 'title', mapping: 'topic_title'},
4513 {name: 'author', mapping: 'username'},
4514 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4515 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4516 {name: 'lastPoster', mapping: 'user2'},
4517 {name: 'excerpt', mapping: 'post_text'}
4520 var myNewRecord = new TopicRecord({
4521 title: 'Do my job please',
4524 lastPost: new Date(),
4525 lastPoster: 'Animal',
4526 excerpt: 'No way dude!'
4528 myStore.add(myNewRecord);
4533 Roo.data.Record.create = function(o){
4535 f.superclass.constructor.apply(this, arguments);
4537 Roo.extend(f, Roo.data.Record);
4538 var p = f.prototype;
4539 p.fields = new Roo.util.MixedCollection(false, function(field){
4542 for(var i = 0, len = o.length; i < len; i++){
4543 p.fields.add(new Roo.data.Field(o[i]));
4545 f.getField = function(name){
4546 return p.fields.get(name);
4551 Roo.data.Record.AUTO_ID = 1000;
4552 Roo.data.Record.EDIT = 'edit';
4553 Roo.data.Record.REJECT = 'reject';
4554 Roo.data.Record.COMMIT = 'commit';
4556 Roo.data.Record.prototype = {
4558 * Readonly flag - true if this record has been modified.
4567 join : function(store){
4572 * Set the named field to the specified value.
4573 * @param {String} name The name of the field to set.
4574 * @param {Object} value The value to set the field to.
4576 set : function(name, value){
4577 if(this.data[name] == value){
4584 if(typeof this.modified[name] == 'undefined'){
4585 this.modified[name] = this.data[name];
4587 this.data[name] = value;
4589 this.store.afterEdit(this);
4594 * Get the value of the named field.
4595 * @param {String} name The name of the field to get the value of.
4596 * @return {Object} The value of the field.
4598 get : function(name){
4599 return this.data[name];
4603 beginEdit : function(){
4604 this.editing = true;
4609 cancelEdit : function(){
4610 this.editing = false;
4611 delete this.modified;
4615 endEdit : function(){
4616 this.editing = false;
4617 if(this.dirty && this.store){
4618 this.store.afterEdit(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Rejects all changes made to the Record since either creation, or the last commit operation.
4625 * Modified fields are reverted to their original values.
4627 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4628 * of reject operations.
4630 reject : function(){
4631 var m = this.modified;
4633 if(typeof m[n] != "function"){
4634 this.data[n] = m[n];
4638 delete this.modified;
4639 this.editing = false;
4641 this.store.afterReject(this);
4646 * Usually called by the {@link Roo.data.Store} which owns the Record.
4647 * Commits all changes made to the Record since either creation, or the last commit operation.
4649 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4650 * of commit operations.
4652 commit : function(){
4654 delete this.modified;
4655 this.editing = false;
4657 this.store.afterCommit(this);
4662 hasError : function(){
4663 return this.error != null;
4667 clearError : function(){
4672 * Creates a copy of this record.
4673 * @param {String} id (optional) A new record id if you don't want to use this record's id
4676 copy : function(newId) {
4677 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4681 * Ext JS Library 1.1.1
4682 * Copyright(c) 2006-2007, Ext JS, LLC.
4684 * Originally Released Under LGPL - original licence link has changed is not relivant.
4687 * <script type="text/javascript">
4693 * @class Roo.data.Store
4694 * @extends Roo.util.Observable
4695 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4696 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4698 * 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
4699 * has no knowledge of the format of the data returned by the Proxy.<br>
4701 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4702 * instances from the data object. These records are cached and made available through accessor functions.
4704 * Creates a new Store.
4705 * @param {Object} config A config object containing the objects needed for the Store to access data,
4706 * and read the data into Records.
4708 Roo.data.Store = function(config){
4709 this.data = new Roo.util.MixedCollection(false);
4710 this.data.getKey = function(o){
4713 this.baseParams = {};
4722 if(config && config.data){
4723 this.inlineData = config.data;
4727 Roo.apply(this, config);
4729 if(this.reader){ // reader passed
4730 this.reader = Roo.factory(this.reader, Roo.data);
4731 this.reader.xmodule = this.xmodule || false;
4732 if(!this.recordType){
4733 this.recordType = this.reader.recordType;
4735 if(this.reader.onMetaChange){
4736 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4740 if(this.recordType){
4741 this.fields = this.recordType.prototype.fields;
4747 * @event datachanged
4748 * Fires when the data cache has changed, and a widget which is using this Store
4749 * as a Record cache should refresh its view.
4750 * @param {Store} this
4755 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4756 * @param {Store} this
4757 * @param {Object} meta The JSON metadata
4762 * Fires when Records have been added to the Store
4763 * @param {Store} this
4764 * @param {Roo.data.Record[]} records The array of Records added
4765 * @param {Number} index The index at which the record(s) were added
4770 * Fires when a Record has been removed from the Store
4771 * @param {Store} this
4772 * @param {Roo.data.Record} record The Record that was removed
4773 * @param {Number} index The index at which the record was removed
4778 * Fires when a Record has been updated
4779 * @param {Store} this
4780 * @param {Roo.data.Record} record The Record that was updated
4781 * @param {String} operation The update operation being performed. Value may be one of:
4783 Roo.data.Record.EDIT
4784 Roo.data.Record.REJECT
4785 Roo.data.Record.COMMIT
4791 * Fires when the data cache has been cleared.
4792 * @param {Store} this
4797 * Fires before a request is made for a new data object. If the beforeload handler returns false
4798 * the load action will be canceled.
4799 * @param {Store} this
4800 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4805 * Fires after a new set of Records has been loaded.
4806 * @param {Store} this
4807 * @param {Roo.data.Record[]} records The Records that were loaded
4808 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4812 * @event loadexception
4813 * Fires if an exception occurs in the Proxy during loading.
4814 * Called with the signature of the Proxy's "loadexception" event.
4815 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4818 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4819 * @param {Object} load options
4820 * @param {Object} jsonData from your request (normally this contains the Exception)
4822 loadexception : true
4826 this.proxy = Roo.factory(this.proxy, Roo.data);
4827 this.proxy.xmodule = this.xmodule || false;
4828 this.relayEvents(this.proxy, ["loadexception"]);
4830 this.sortToggle = {};
4832 Roo.data.Store.superclass.constructor.call(this);
4834 if(this.inlineData){
4835 this.loadData(this.inlineData);
4836 delete this.inlineData;
4839 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4841 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4842 * without a remote query - used by combo/forms at present.
4846 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4849 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4852 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4853 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4856 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4857 * on any HTTP request
4860 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4863 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4864 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4869 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4870 * loaded or when a record is removed. (defaults to false).
4872 pruneModifiedRecords : false,
4878 * Add Records to the Store and fires the add event.
4879 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4881 add : function(records){
4882 records = [].concat(records);
4883 for(var i = 0, len = records.length; i < len; i++){
4884 records[i].join(this);
4886 var index = this.data.length;
4887 this.data.addAll(records);
4888 this.fireEvent("add", this, records, index);
4892 * Remove a Record from the Store and fires the remove event.
4893 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4895 remove : function(record){
4896 var index = this.data.indexOf(record);
4897 this.data.removeAt(index);
4898 if(this.pruneModifiedRecords){
4899 this.modified.remove(record);
4901 this.fireEvent("remove", this, record, index);
4905 * Remove all Records from the Store and fires the clear event.
4907 removeAll : function(){
4909 if(this.pruneModifiedRecords){
4912 this.fireEvent("clear", this);
4916 * Inserts Records to the Store at the given index and fires the add event.
4917 * @param {Number} index The start index at which to insert the passed Records.
4918 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4920 insert : function(index, records){
4921 records = [].concat(records);
4922 for(var i = 0, len = records.length; i < len; i++){
4923 this.data.insert(index, records[i]);
4924 records[i].join(this);
4926 this.fireEvent("add", this, records, index);
4930 * Get the index within the cache of the passed Record.
4931 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4932 * @return {Number} The index of the passed Record. Returns -1 if not found.
4934 indexOf : function(record){
4935 return this.data.indexOf(record);
4939 * Get the index within the cache of the Record with the passed id.
4940 * @param {String} id The id of the Record to find.
4941 * @return {Number} The index of the Record. Returns -1 if not found.
4943 indexOfId : function(id){
4944 return this.data.indexOfKey(id);
4948 * Get the Record with the specified id.
4949 * @param {String} id The id of the Record to find.
4950 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4952 getById : function(id){
4953 return this.data.key(id);
4957 * Get the Record at the specified index.
4958 * @param {Number} index The index of the Record to find.
4959 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4961 getAt : function(index){
4962 return this.data.itemAt(index);
4966 * Returns a range of Records between specified indices.
4967 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4968 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4969 * @return {Roo.data.Record[]} An array of Records
4971 getRange : function(start, end){
4972 return this.data.getRange(start, end);
4976 storeOptions : function(o){
4977 o = Roo.apply({}, o);
4980 this.lastOptions = o;
4984 * Loads the Record cache from the configured Proxy using the configured Reader.
4986 * If using remote paging, then the first load call must specify the <em>start</em>
4987 * and <em>limit</em> properties in the options.params property to establish the initial
4988 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4990 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4991 * and this call will return before the new data has been loaded. Perform any post-processing
4992 * in a callback function, or in a "load" event handler.</strong>
4994 * @param {Object} options An object containing properties which control loading options:<ul>
4995 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4996 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4997 * passed the following arguments:<ul>
4998 * <li>r : Roo.data.Record[]</li>
4999 * <li>options: Options object from the load call</li>
5000 * <li>success: Boolean success indicator</li></ul></li>
5001 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5002 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5005 load : function(options){
5006 options = options || {};
5007 if(this.fireEvent("beforeload", this, options) !== false){
5008 this.storeOptions(options);
5009 var p = Roo.apply(options.params || {}, this.baseParams);
5010 // if meta was not loaded from remote source.. try requesting it.
5011 if (!this.reader.metaFromRemote) {
5014 if(this.sortInfo && this.remoteSort){
5015 var pn = this.paramNames;
5016 p[pn["sort"]] = this.sortInfo.field;
5017 p[pn["dir"]] = this.sortInfo.direction;
5019 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5024 * Reloads the Record cache from the configured Proxy using the configured Reader and
5025 * the options from the last load operation performed.
5026 * @param {Object} options (optional) An object containing properties which may override the options
5027 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5028 * the most recently used options are reused).
5030 reload : function(options){
5031 this.load(Roo.applyIf(options||{}, this.lastOptions));
5035 // Called as a callback by the Reader during a load operation.
5036 loadRecords : function(o, options, success){
5037 if(!o || success === false){
5038 if(success !== false){
5039 this.fireEvent("load", this, [], options);
5041 if(options.callback){
5042 options.callback.call(options.scope || this, [], options, false);
5046 // if data returned failure - throw an exception.
5047 if (o.success === false) {
5048 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5051 var r = o.records, t = o.totalRecords || r.length;
5052 if(!options || options.add !== true){
5053 if(this.pruneModifiedRecords){
5056 for(var i = 0, len = r.length; i < len; i++){
5060 this.data = this.snapshot;
5061 delete this.snapshot;
5064 this.data.addAll(r);
5065 this.totalLength = t;
5067 this.fireEvent("datachanged", this);
5069 this.totalLength = Math.max(t, this.data.length+r.length);
5072 this.fireEvent("load", this, r, options);
5073 if(options.callback){
5074 options.callback.call(options.scope || this, r, options, true);
5079 * Loads data from a passed data block. A Reader which understands the format of the data
5080 * must have been configured in the constructor.
5081 * @param {Object} data The data block from which to read the Records. The format of the data expected
5082 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5083 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5085 loadData : function(o, append){
5086 var r = this.reader.readRecords(o);
5087 this.loadRecords(r, {add: append}, true);
5091 * Gets the number of cached records.
5093 * <em>If using paging, this may not be the total size of the dataset. If the data object
5094 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5095 * the data set size</em>
5097 getCount : function(){
5098 return this.data.length || 0;
5102 * Gets the total number of records in the dataset as returned by the server.
5104 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5105 * the dataset size</em>
5107 getTotalCount : function(){
5108 return this.totalLength || 0;
5112 * Returns the sort state of the Store as an object with two properties:
5114 field {String} The name of the field by which the Records are sorted
5115 direction {String} The sort order, "ASC" or "DESC"
5118 getSortState : function(){
5119 return this.sortInfo;
5123 applySort : function(){
5124 if(this.sortInfo && !this.remoteSort){
5125 var s = this.sortInfo, f = s.field;
5126 var st = this.fields.get(f).sortType;
5127 var fn = function(r1, r2){
5128 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5129 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5131 this.data.sort(s.direction, fn);
5132 if(this.snapshot && this.snapshot != this.data){
5133 this.snapshot.sort(s.direction, fn);
5139 * Sets the default sort column and order to be used by the next load operation.
5140 * @param {String} fieldName The name of the field to sort by.
5141 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5143 setDefaultSort : function(field, dir){
5144 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5149 * If remote sorting is used, the sort is performed on the server, and the cache is
5150 * reloaded. If local sorting is used, the cache is sorted internally.
5151 * @param {String} fieldName The name of the field to sort by.
5152 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5154 sort : function(fieldName, dir){
5155 var f = this.fields.get(fieldName);
5157 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5158 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5163 this.sortToggle[f.name] = dir;
5164 this.sortInfo = {field: f.name, direction: dir};
5165 if(!this.remoteSort){
5167 this.fireEvent("datachanged", this);
5169 this.load(this.lastOptions);
5174 * Calls the specified function for each of the Records in the cache.
5175 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5176 * Returning <em>false</em> aborts and exits the iteration.
5177 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5179 each : function(fn, scope){
5180 this.data.each(fn, scope);
5184 * Gets all records modified since the last commit. Modified records are persisted across load operations
5185 * (e.g., during paging).
5186 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5188 getModifiedRecords : function(){
5189 return this.modified;
5193 createFilterFn : function(property, value, anyMatch){
5194 if(!value.exec){ // not a regex
5195 value = String(value);
5196 if(value.length == 0){
5199 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5202 return value.test(r.data[property]);
5207 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5208 * @param {String} property A field on your records
5209 * @param {Number} start The record index to start at (defaults to 0)
5210 * @param {Number} end The last record index to include (defaults to length - 1)
5211 * @return {Number} The sum
5213 sum : function(property, start, end){
5214 var rs = this.data.items, v = 0;
5216 end = (end || end === 0) ? end : rs.length-1;
5218 for(var i = start; i <= end; i++){
5219 v += (rs[i].data[property] || 0);
5225 * Filter the records by a specified property.
5226 * @param {String} field A field on your records
5227 * @param {String/RegExp} value Either a string that the field
5228 * should start with or a RegExp to test against the field
5229 * @param {Boolean} anyMatch True to match any part not just the beginning
5231 filter : function(property, value, anyMatch){
5232 var fn = this.createFilterFn(property, value, anyMatch);
5233 return fn ? this.filterBy(fn) : this.clearFilter();
5237 * Filter by a function. The specified function will be called with each
5238 * record in this data source. If the function returns true the record is included,
5239 * otherwise it is filtered.
5240 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5241 * @param {Object} scope (optional) The scope of the function (defaults to this)
5243 filterBy : function(fn, scope){
5244 this.snapshot = this.snapshot || this.data;
5245 this.data = this.queryBy(fn, scope||this);
5246 this.fireEvent("datachanged", this);
5250 * Query the records by a specified property.
5251 * @param {String} field A field on your records
5252 * @param {String/RegExp} value Either a string that the field
5253 * should start with or a RegExp to test against the field
5254 * @param {Boolean} anyMatch True to match any part not just the beginning
5255 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5257 query : function(property, value, anyMatch){
5258 var fn = this.createFilterFn(property, value, anyMatch);
5259 return fn ? this.queryBy(fn) : this.data.clone();
5263 * Query by a function. The specified function will be called with each
5264 * record in this data source. If the function returns true the record is included
5266 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5267 * @param {Object} scope (optional) The scope of the function (defaults to this)
5268 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5270 queryBy : function(fn, scope){
5271 var data = this.snapshot || this.data;
5272 return data.filterBy(fn, scope||this);
5276 * Collects unique values for a particular dataIndex from this store.
5277 * @param {String} dataIndex The property to collect
5278 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5279 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5280 * @return {Array} An array of the unique values
5282 collect : function(dataIndex, allowNull, bypassFilter){
5283 var d = (bypassFilter === true && this.snapshot) ?
5284 this.snapshot.items : this.data.items;
5285 var v, sv, r = [], l = {};
5286 for(var i = 0, len = d.length; i < len; i++){
5287 v = d[i].data[dataIndex];
5289 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5298 * Revert to a view of the Record cache with no filtering applied.
5299 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5301 clearFilter : function(suppressEvent){
5302 if(this.snapshot && this.snapshot != this.data){
5303 this.data = this.snapshot;
5304 delete this.snapshot;
5305 if(suppressEvent !== true){
5306 this.fireEvent("datachanged", this);
5312 afterEdit : function(record){
5313 if(this.modified.indexOf(record) == -1){
5314 this.modified.push(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5320 afterReject : function(record){
5321 this.modified.remove(record);
5322 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5326 afterCommit : function(record){
5327 this.modified.remove(record);
5328 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5332 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5333 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5335 commitChanges : function(){
5336 var m = this.modified.slice(0);
5338 for(var i = 0, len = m.length; i < len; i++){
5344 * Cancel outstanding changes on all changed records.
5346 rejectChanges : function(){
5347 var m = this.modified.slice(0);
5349 for(var i = 0, len = m.length; i < len; i++){
5354 onMetaChange : function(meta, rtype, o){
5355 this.recordType = rtype;
5356 this.fields = rtype.prototype.fields;
5357 delete this.snapshot;
5358 this.sortInfo = meta.sortInfo || this.sortInfo;
5360 this.fireEvent('metachange', this, this.reader.meta);
5364 * Ext JS Library 1.1.1
5365 * Copyright(c) 2006-2007, Ext JS, LLC.
5367 * Originally Released Under LGPL - original licence link has changed is not relivant.
5370 * <script type="text/javascript">
5374 * @class Roo.data.SimpleStore
5375 * @extends Roo.data.Store
5376 * Small helper class to make creating Stores from Array data easier.
5377 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5378 * @cfg {Array} fields An array of field definition objects, or field name strings.
5379 * @cfg {Array} data The multi-dimensional array of data
5381 * @param {Object} config
5383 Roo.data.SimpleStore = function(config){
5384 Roo.data.SimpleStore.superclass.constructor.call(this, {
5386 reader: new Roo.data.ArrayReader({
5389 Roo.data.Record.create(config.fields)
5391 proxy : new Roo.data.MemoryProxy(config.data)
5395 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5397 * Ext JS Library 1.1.1
5398 * Copyright(c) 2006-2007, Ext JS, LLC.
5400 * Originally Released Under LGPL - original licence link has changed is not relivant.
5403 * <script type="text/javascript">
5408 * @extends Roo.data.Store
5409 * @class Roo.data.JsonStore
5410 * Small helper class to make creating Stores for JSON data easier. <br/>
5412 var store = new Roo.data.JsonStore({
5413 url: 'get-images.php',
5415 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5418 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5419 * JsonReader and HttpProxy (unless inline data is provided).</b>
5420 * @cfg {Array} fields An array of field definition objects, or field name strings.
5422 * @param {Object} config
5424 Roo.data.JsonStore = function(c){
5425 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5426 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5427 reader: new Roo.data.JsonReader(c, c.fields)
5430 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5432 * Ext JS Library 1.1.1
5433 * Copyright(c) 2006-2007, Ext JS, LLC.
5435 * Originally Released Under LGPL - original licence link has changed is not relivant.
5438 * <script type="text/javascript">
5442 Roo.data.Field = function(config){
5443 if(typeof config == "string"){
5444 config = {name: config};
5446 Roo.apply(this, config);
5452 var st = Roo.data.SortTypes;
5453 // named sortTypes are supported, here we look them up
5454 if(typeof this.sortType == "string"){
5455 this.sortType = st[this.sortType];
5458 // set default sortType for strings and dates
5462 this.sortType = st.asUCString;
5465 this.sortType = st.asDate;
5468 this.sortType = st.none;
5473 var stripRe = /[\$,%]/g;
5475 // prebuilt conversion function for this field, instead of
5476 // switching every time we're reading a value
5478 var cv, dateFormat = this.dateFormat;
5483 cv = function(v){ return v; };
5486 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5490 return v !== undefined && v !== null && v !== '' ?
5491 parseInt(String(v).replace(stripRe, ""), 10) : '';
5496 return v !== undefined && v !== null && v !== '' ?
5497 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5502 cv = function(v){ return v === true || v === "true" || v == 1; };
5509 if(v instanceof Date){
5513 if(dateFormat == "timestamp"){
5514 return new Date(v*1000);
5516 return Date.parseDate(v, dateFormat);
5518 var parsed = Date.parse(v);
5519 return parsed ? new Date(parsed) : null;
5528 Roo.data.Field.prototype = {
5536 * Ext JS Library 1.1.1
5537 * Copyright(c) 2006-2007, Ext JS, LLC.
5539 * Originally Released Under LGPL - original licence link has changed is not relivant.
5542 * <script type="text/javascript">
5545 // Base class for reading structured data from a data source. This class is intended to be
5546 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5549 * @class Roo.data.DataReader
5550 * Base class for reading structured data from a data source. This class is intended to be
5551 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5554 Roo.data.DataReader = function(meta, recordType){
5558 this.recordType = recordType instanceof Array ?
5559 Roo.data.Record.create(recordType) : recordType;
5562 Roo.data.DataReader.prototype = {
5564 * Create an empty record
5565 * @param {Object} data (optional) - overlay some values
5566 * @return {Roo.data.Record} record created.
5568 newRow : function(d) {
5570 this.recordType.prototype.fields.each(function(c) {
5572 case 'int' : da[c.name] = 0; break;
5573 case 'date' : da[c.name] = new Date(); break;
5574 case 'float' : da[c.name] = 0.0; break;
5575 case 'boolean' : da[c.name] = false; break;
5576 default : da[c.name] = ""; break;
5580 return new this.recordType(Roo.apply(da, d));
5585 * Ext JS Library 1.1.1
5586 * Copyright(c) 2006-2007, Ext JS, LLC.
5588 * Originally Released Under LGPL - original licence link has changed is not relivant.
5591 * <script type="text/javascript">
5595 * @class Roo.data.DataProxy
5596 * @extends Roo.data.Observable
5597 * This class is an abstract base class for implementations which provide retrieval of
5598 * unformatted data objects.<br>
5600 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5601 * (of the appropriate type which knows how to parse the data object) to provide a block of
5602 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5604 * Custom implementations must implement the load method as described in
5605 * {@link Roo.data.HttpProxy#load}.
5607 Roo.data.DataProxy = function(){
5611 * Fires before a network request is made to retrieve a data object.
5612 * @param {Object} This DataProxy object.
5613 * @param {Object} params The params parameter to the load function.
5618 * Fires before the load method's callback is called.
5619 * @param {Object} This DataProxy object.
5620 * @param {Object} o The data object.
5621 * @param {Object} arg The callback argument object passed to the load function.
5625 * @event loadexception
5626 * Fires if an Exception occurs during data retrieval.
5627 * @param {Object} This DataProxy object.
5628 * @param {Object} o The data object.
5629 * @param {Object} arg The callback argument object passed to the load function.
5630 * @param {Object} e The Exception.
5632 loadexception : true
5634 Roo.data.DataProxy.superclass.constructor.call(this);
5637 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5640 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5644 * Ext JS Library 1.1.1
5645 * Copyright(c) 2006-2007, Ext JS, LLC.
5647 * Originally Released Under LGPL - original licence link has changed is not relivant.
5650 * <script type="text/javascript">
5653 * @class Roo.data.MemoryProxy
5654 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5655 * to the Reader when its load method is called.
5657 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5659 Roo.data.MemoryProxy = function(data){
5663 Roo.data.MemoryProxy.superclass.constructor.call(this);
5667 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5669 * Load data from the requested source (in this case an in-memory
5670 * data object passed to the constructor), read the data object into
5671 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5672 * process that block using the passed callback.
5673 * @param {Object} params This parameter is not used by the MemoryProxy class.
5674 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5675 * object into a block of Roo.data.Records.
5676 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5677 * The function must be passed <ul>
5678 * <li>The Record block object</li>
5679 * <li>The "arg" argument from the load function</li>
5680 * <li>A boolean success indicator</li>
5682 * @param {Object} scope The scope in which to call the callback
5683 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5685 load : function(params, reader, callback, scope, arg){
5686 params = params || {};
5689 result = reader.readRecords(this.data);
5691 this.fireEvent("loadexception", this, arg, null, e);
5692 callback.call(scope, null, arg, false);
5695 callback.call(scope, result, arg, true);
5699 update : function(params, records){
5704 * Ext JS Library 1.1.1
5705 * Copyright(c) 2006-2007, Ext JS, LLC.
5707 * Originally Released Under LGPL - original licence link has changed is not relivant.
5710 * <script type="text/javascript">
5713 * @class Roo.data.HttpProxy
5714 * @extends Roo.data.DataProxy
5715 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5716 * configured to reference a certain URL.<br><br>
5718 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5719 * from which the running page was served.<br><br>
5721 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5723 * Be aware that to enable the browser to parse an XML document, the server must set
5724 * the Content-Type header in the HTTP response to "text/xml".
5726 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5727 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5728 * will be used to make the request.
5730 Roo.data.HttpProxy = function(conn){
5731 Roo.data.HttpProxy.superclass.constructor.call(this);
5732 // is conn a conn config or a real conn?
5734 this.useAjax = !conn || !conn.events;
5738 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5739 // thse are take from connection...
5742 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5745 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5746 * extra parameters to each request made by this object. (defaults to undefined)
5749 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5750 * to each request made by this object. (defaults to undefined)
5753 * @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)
5756 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5759 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5765 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5769 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5770 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5771 * a finer-grained basis than the DataProxy events.
5773 getConnection : function(){
5774 return this.useAjax ? Roo.Ajax : this.conn;
5778 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5779 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5780 * process that block using the passed callback.
5781 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5782 * for the request to the remote server.
5783 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5784 * object into a block of Roo.data.Records.
5785 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5786 * The function must be passed <ul>
5787 * <li>The Record block object</li>
5788 * <li>The "arg" argument from the load function</li>
5789 * <li>A boolean success indicator</li>
5791 * @param {Object} scope The scope in which to call the callback
5792 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5794 load : function(params, reader, callback, scope, arg){
5795 if(this.fireEvent("beforeload", this, params) !== false){
5797 params : params || {},
5799 callback : callback,
5804 callback : this.loadResponse,
5808 Roo.applyIf(o, this.conn);
5809 if(this.activeRequest){
5810 Roo.Ajax.abort(this.activeRequest);
5812 this.activeRequest = Roo.Ajax.request(o);
5814 this.conn.request(o);
5817 callback.call(scope||this, null, arg, false);
5822 loadResponse : function(o, success, response){
5823 delete this.activeRequest;
5825 this.fireEvent("loadexception", this, o, response);
5826 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5831 result = o.reader.read(response);
5833 this.fireEvent("loadexception", this, o, response, e);
5834 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5838 this.fireEvent("load", this, o, o.request.arg);
5839 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5843 update : function(dataSet){
5848 updateResponse : function(dataSet){
5853 * Ext JS Library 1.1.1
5854 * Copyright(c) 2006-2007, Ext JS, LLC.
5856 * Originally Released Under LGPL - original licence link has changed is not relivant.
5859 * <script type="text/javascript">
5863 * @class Roo.data.ScriptTagProxy
5864 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5865 * other than the originating domain of the running page.<br><br>
5867 * <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
5868 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5870 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5871 * source code that is used as the source inside a <script> tag.<br><br>
5873 * In order for the browser to process the returned data, the server must wrap the data object
5874 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5875 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5876 * depending on whether the callback name was passed:
5879 boolean scriptTag = false;
5880 String cb = request.getParameter("callback");
5883 response.setContentType("text/javascript");
5885 response.setContentType("application/x-json");
5887 Writer out = response.getWriter();
5889 out.write(cb + "(");
5891 out.print(dataBlock.toJsonString());
5898 * @param {Object} config A configuration object.
5900 Roo.data.ScriptTagProxy = function(config){
5901 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5902 Roo.apply(this, config);
5903 this.head = document.getElementsByTagName("head")[0];
5906 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5908 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5910 * @cfg {String} url The URL from which to request the data object.
5913 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5917 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5918 * the server the name of the callback function set up by the load call to process the returned data object.
5919 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5920 * javascript output which calls this named function passing the data object as its only parameter.
5922 callbackParam : "callback",
5924 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5925 * name to the request.
5930 * Load data from the configured URL, read the data object into
5931 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5932 * process that block using the passed callback.
5933 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5934 * for the request to the remote server.
5935 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5936 * object into a block of Roo.data.Records.
5937 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5938 * The function must be passed <ul>
5939 * <li>The Record block object</li>
5940 * <li>The "arg" argument from the load function</li>
5941 * <li>A boolean success indicator</li>
5943 * @param {Object} scope The scope in which to call the callback
5944 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5946 load : function(params, reader, callback, scope, arg){
5947 if(this.fireEvent("beforeload", this, params) !== false){
5949 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5952 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5954 url += "&_dc=" + (new Date().getTime());
5956 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5959 cb : "stcCallback"+transId,
5960 scriptId : "stcScript"+transId,
5964 callback : callback,
5970 window[trans.cb] = function(o){
5971 conn.handleResponse(o, trans);
5974 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5976 if(this.autoAbort !== false){
5980 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5982 var script = document.createElement("script");
5983 script.setAttribute("src", url);
5984 script.setAttribute("type", "text/javascript");
5985 script.setAttribute("id", trans.scriptId);
5986 this.head.appendChild(script);
5990 callback.call(scope||this, null, arg, false);
5995 isLoading : function(){
5996 return this.trans ? true : false;
6000 * Abort the current server request.
6003 if(this.isLoading()){
6004 this.destroyTrans(this.trans);
6009 destroyTrans : function(trans, isLoaded){
6010 this.head.removeChild(document.getElementById(trans.scriptId));
6011 clearTimeout(trans.timeoutId);
6013 window[trans.cb] = undefined;
6015 delete window[trans.cb];
6018 // if hasn't been loaded, wait for load to remove it to prevent script error
6019 window[trans.cb] = function(){
6020 window[trans.cb] = undefined;
6022 delete window[trans.cb];
6029 handleResponse : function(o, trans){
6031 this.destroyTrans(trans, true);
6034 result = trans.reader.readRecords(o);
6036 this.fireEvent("loadexception", this, o, trans.arg, e);
6037 trans.callback.call(trans.scope||window, null, trans.arg, false);
6040 this.fireEvent("load", this, o, trans.arg);
6041 trans.callback.call(trans.scope||window, result, trans.arg, true);
6045 handleFailure : function(trans){
6047 this.destroyTrans(trans, false);
6048 this.fireEvent("loadexception", this, null, trans.arg);
6049 trans.callback.call(trans.scope||window, null, trans.arg, false);
6053 * Ext JS Library 1.1.1
6054 * Copyright(c) 2006-2007, Ext JS, LLC.
6056 * Originally Released Under LGPL - original licence link has changed is not relivant.
6059 * <script type="text/javascript">
6063 * @class Roo.data.JsonReader
6064 * @extends Roo.data.DataReader
6065 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6066 * based on mappings in a provided Roo.data.Record constructor.
6068 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6069 * in the reply previously.
6074 var RecordDef = Roo.data.Record.create([
6075 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6076 {name: 'occupation'} // This field will use "occupation" as the mapping.
6078 var myReader = new Roo.data.JsonReader({
6079 totalProperty: "results", // The property which contains the total dataset size (optional)
6080 root: "rows", // The property which contains an Array of row objects
6081 id: "id" // The property within each row object that provides an ID for the record (optional)
6085 * This would consume a JSON file like this:
6087 { 'results': 2, 'rows': [
6088 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6089 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6092 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6093 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6094 * paged from the remote server.
6095 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6096 * @cfg {String} root name of the property which contains the Array of row objects.
6097 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6099 * Create a new JsonReader
6100 * @param {Object} meta Metadata configuration options
6101 * @param {Object} recordType Either an Array of field definition objects,
6102 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6104 Roo.data.JsonReader = function(meta, recordType){
6107 // set some defaults:
6109 totalProperty: 'total',
6110 successProperty : 'success',
6115 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6117 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6120 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6121 * Used by Store query builder to append _requestMeta to params.
6124 metaFromRemote : false,
6126 * This method is only used by a DataProxy which has retrieved data from a remote server.
6127 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6128 * @return {Object} data A data block which is used by an Roo.data.Store object as
6129 * a cache of Roo.data.Records.
6131 read : function(response){
6132 var json = response.responseText;
6134 var o = /* eval:var:o */ eval("("+json+")");
6136 throw {message: "JsonReader.read: Json object not found"};
6142 this.metaFromRemote = true;
6143 this.meta = o.metaData;
6144 this.recordType = Roo.data.Record.create(o.metaData.fields);
6145 this.onMetaChange(this.meta, this.recordType, o);
6147 return this.readRecords(o);
6150 // private function a store will implement
6151 onMetaChange : function(meta, recordType, o){
6158 simpleAccess: function(obj, subsc) {
6165 getJsonAccessor: function(){
6167 return function(expr) {
6169 return(re.test(expr))
6170 ? new Function("obj", "return obj." + expr)
6180 * Create a data block containing Roo.data.Records from an XML document.
6181 * @param {Object} o An object which contains an Array of row objects in the property specified
6182 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6183 * which contains the total size of the dataset.
6184 * @return {Object} data A data block which is used by an Roo.data.Store object as
6185 * a cache of Roo.data.Records.
6187 readRecords : function(o){
6189 * After any data loads, the raw JSON data is available for further custom processing.
6193 var s = this.meta, Record = this.recordType,
6194 f = Record.prototype.fields, fi = f.items, fl = f.length;
6196 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6198 if(s.totalProperty) {
6199 this.getTotal = this.getJsonAccessor(s.totalProperty);
6201 if(s.successProperty) {
6202 this.getSuccess = this.getJsonAccessor(s.successProperty);
6204 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6206 var g = this.getJsonAccessor(s.id);
6207 this.getId = function(rec) {
6209 return (r === undefined || r === "") ? null : r;
6212 this.getId = function(){return null;};
6215 for(var jj = 0; jj < fl; jj++){
6217 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6218 this.ef[jj] = this.getJsonAccessor(map);
6222 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6223 if(s.totalProperty){
6224 var vt = parseInt(this.getTotal(o), 10);
6229 if(s.successProperty){
6230 var vs = this.getSuccess(o);
6231 if(vs === false || vs === 'false'){
6236 for(var i = 0; i < c; i++){
6239 var id = this.getId(n);
6240 for(var j = 0; j < fl; j++){
6242 var v = this.ef[j](n);
6244 Roo.log('missing convert for ' + f.name);
6248 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6250 var record = new Record(values, id);
6252 records[i] = record;
6257 totalRecords : totalRecords
6262 * Ext JS Library 1.1.1
6263 * Copyright(c) 2006-2007, Ext JS, LLC.
6265 * Originally Released Under LGPL - original licence link has changed is not relivant.
6268 * <script type="text/javascript">
6272 * @class Roo.data.XmlReader
6273 * @extends Roo.data.DataReader
6274 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6275 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6277 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6278 * header in the HTTP response must be set to "text/xml".</em>
6282 var RecordDef = Roo.data.Record.create([
6283 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6284 {name: 'occupation'} // This field will use "occupation" as the mapping.
6286 var myReader = new Roo.data.XmlReader({
6287 totalRecords: "results", // The element which contains the total dataset size (optional)
6288 record: "row", // The repeated element which contains row information
6289 id: "id" // The element within the row that provides an ID for the record (optional)
6293 * This would consume an XML file like this:
6297 <results>2</results>
6300 <name>Bill</name>
6301 <occupation>Gardener</occupation>
6305 <name>Ben</name>
6306 <occupation>Horticulturalist</occupation>
6310 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6311 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6312 * paged from the remote server.
6313 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6314 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6315 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6316 * a record identifier value.
6318 * Create a new XmlReader
6319 * @param {Object} meta Metadata configuration options
6320 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6321 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6322 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6324 Roo.data.XmlReader = function(meta, recordType){
6326 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6328 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6330 * This method is only used by a DataProxy which has retrieved data from a remote server.
6331 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6332 * to contain a method called 'responseXML' that returns an XML document object.
6333 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6334 * a cache of Roo.data.Records.
6336 read : function(response){
6337 var doc = response.responseXML;
6339 throw {message: "XmlReader.read: XML Document not available"};
6341 return this.readRecords(doc);
6345 * Create a data block containing Roo.data.Records from an XML document.
6346 * @param {Object} doc A parsed XML document.
6347 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6348 * a cache of Roo.data.Records.
6350 readRecords : function(doc){
6352 * After any data loads/reads, the raw XML Document is available for further custom processing.
6356 var root = doc.documentElement || doc;
6357 var q = Roo.DomQuery;
6358 var recordType = this.recordType, fields = recordType.prototype.fields;
6359 var sid = this.meta.id;
6360 var totalRecords = 0, success = true;
6361 if(this.meta.totalRecords){
6362 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6365 if(this.meta.success){
6366 var sv = q.selectValue(this.meta.success, root, true);
6367 success = sv !== false && sv !== 'false';
6370 var ns = q.select(this.meta.record, root);
6371 for(var i = 0, len = ns.length; i < len; i++) {
6374 var id = sid ? q.selectValue(sid, n) : undefined;
6375 for(var j = 0, jlen = fields.length; j < jlen; j++){
6376 var f = fields.items[j];
6377 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6381 var record = new recordType(values, id);
6383 records[records.length] = record;
6389 totalRecords : totalRecords || records.length
6394 * Ext JS Library 1.1.1
6395 * Copyright(c) 2006-2007, Ext JS, LLC.
6397 * Originally Released Under LGPL - original licence link has changed is not relivant.
6400 * <script type="text/javascript">
6404 * @class Roo.data.ArrayReader
6405 * @extends Roo.data.DataReader
6406 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6407 * Each element of that Array represents a row of data fields. The
6408 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6409 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6413 var RecordDef = Roo.data.Record.create([
6414 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6415 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6417 var myReader = new Roo.data.ArrayReader({
6418 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6422 * This would consume an Array like this:
6424 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6426 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6428 * Create a new JsonReader
6429 * @param {Object} meta Metadata configuration options.
6430 * @param {Object} recordType Either an Array of field definition objects
6431 * as specified to {@link Roo.data.Record#create},
6432 * or an {@link Roo.data.Record} object
6433 * created using {@link Roo.data.Record#create}.
6435 Roo.data.ArrayReader = function(meta, recordType){
6436 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6439 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6441 * Create a data block containing Roo.data.Records from an XML document.
6442 * @param {Object} o An Array of row objects which represents the dataset.
6443 * @return {Object} data A data block which is used by an Roo.data.Store object as
6444 * a cache of Roo.data.Records.
6446 readRecords : function(o){
6447 var sid = this.meta ? this.meta.id : null;
6448 var recordType = this.recordType, fields = recordType.prototype.fields;
6451 for(var i = 0; i < root.length; i++){
6454 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6455 for(var j = 0, jlen = fields.length; j < jlen; j++){
6456 var f = fields.items[j];
6457 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6458 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6462 var record = new recordType(values, id);
6464 records[records.length] = record;
6468 totalRecords : records.length
6473 * Ext JS Library 1.1.1
6474 * Copyright(c) 2006-2007, Ext JS, LLC.
6476 * Originally Released Under LGPL - original licence link has changed is not relivant.
6479 * <script type="text/javascript">
6484 * @class Roo.data.Tree
6485 * @extends Roo.util.Observable
6486 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6487 * in the tree have most standard DOM functionality.
6489 * @param {Node} root (optional) The root node
6491 Roo.data.Tree = function(root){
6494 * The root node for this tree
6499 this.setRootNode(root);
6504 * Fires when a new child node is appended to a node in this tree.
6505 * @param {Tree} tree The owner tree
6506 * @param {Node} parent The parent node
6507 * @param {Node} node The newly appended node
6508 * @param {Number} index The index of the newly appended node
6513 * Fires when a child node is removed from a node in this tree.
6514 * @param {Tree} tree The owner tree
6515 * @param {Node} parent The parent node
6516 * @param {Node} node The child node removed
6521 * Fires when a node is moved to a new location in the tree
6522 * @param {Tree} tree The owner tree
6523 * @param {Node} node The node moved
6524 * @param {Node} oldParent The old parent of this node
6525 * @param {Node} newParent The new parent of this node
6526 * @param {Number} index The index it was moved to
6531 * Fires when a new child node is inserted in a node in this tree.
6532 * @param {Tree} tree The owner tree
6533 * @param {Node} parent The parent node
6534 * @param {Node} node The child node inserted
6535 * @param {Node} refNode The child node the node was inserted before
6539 * @event beforeappend
6540 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6541 * @param {Tree} tree The owner tree
6542 * @param {Node} parent The parent node
6543 * @param {Node} node The child node to be appended
6545 "beforeappend" : true,
6547 * @event beforeremove
6548 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6549 * @param {Tree} tree The owner tree
6550 * @param {Node} parent The parent node
6551 * @param {Node} node The child node to be removed
6553 "beforeremove" : true,
6556 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6557 * @param {Tree} tree The owner tree
6558 * @param {Node} node The node being moved
6559 * @param {Node} oldParent The parent of the node
6560 * @param {Node} newParent The new parent the node is moving to
6561 * @param {Number} index The index it is being moved to
6563 "beforemove" : true,
6565 * @event beforeinsert
6566 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6567 * @param {Tree} tree The owner tree
6568 * @param {Node} parent The parent node
6569 * @param {Node} node The child node to be inserted
6570 * @param {Node} refNode The child node the node is being inserted before
6572 "beforeinsert" : true
6575 Roo.data.Tree.superclass.constructor.call(this);
6578 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6581 proxyNodeEvent : function(){
6582 return this.fireEvent.apply(this, arguments);
6586 * Returns the root node for this tree.
6589 getRootNode : function(){
6594 * Sets the root node for this tree.
6595 * @param {Node} node
6598 setRootNode : function(node){
6600 node.ownerTree = this;
6602 this.registerNode(node);
6607 * Gets a node in this tree by its id.
6608 * @param {String} id
6611 getNodeById : function(id){
6612 return this.nodeHash[id];
6615 registerNode : function(node){
6616 this.nodeHash[node.id] = node;
6619 unregisterNode : function(node){
6620 delete this.nodeHash[node.id];
6623 toString : function(){
6624 return "[Tree"+(this.id?" "+this.id:"")+"]";
6629 * @class Roo.data.Node
6630 * @extends Roo.util.Observable
6631 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6632 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6634 * @param {Object} attributes The attributes/config for the node
6636 Roo.data.Node = function(attributes){
6638 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6641 this.attributes = attributes || {};
6642 this.leaf = this.attributes.leaf;
6644 * The node id. @type String
6646 this.id = this.attributes.id;
6648 this.id = Roo.id(null, "ynode-");
6649 this.attributes.id = this.id;
6652 * All child nodes of this node. @type Array
6654 this.childNodes = [];
6655 if(!this.childNodes.indexOf){ // indexOf is a must
6656 this.childNodes.indexOf = function(o){
6657 for(var i = 0, len = this.length; i < len; i++){
6666 * The parent node for this node. @type Node
6668 this.parentNode = null;
6670 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6672 this.firstChild = null;
6674 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6676 this.lastChild = null;
6678 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6680 this.previousSibling = null;
6682 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6684 this.nextSibling = null;
6689 * Fires when a new child node is appended
6690 * @param {Tree} tree The owner tree
6691 * @param {Node} this This node
6692 * @param {Node} node The newly appended node
6693 * @param {Number} index The index of the newly appended node
6698 * Fires when a child node is removed
6699 * @param {Tree} tree The owner tree
6700 * @param {Node} this This node
6701 * @param {Node} node The removed node
6706 * Fires when this node is moved to a new location in the tree
6707 * @param {Tree} tree The owner tree
6708 * @param {Node} this This node
6709 * @param {Node} oldParent The old parent of this node
6710 * @param {Node} newParent The new parent of this node
6711 * @param {Number} index The index it was moved to
6716 * Fires when a new child node is inserted.
6717 * @param {Tree} tree The owner tree
6718 * @param {Node} this This node
6719 * @param {Node} node The child node inserted
6720 * @param {Node} refNode The child node the node was inserted before
6724 * @event beforeappend
6725 * Fires before a new child is appended, return false to cancel the append.
6726 * @param {Tree} tree The owner tree
6727 * @param {Node} this This node
6728 * @param {Node} node The child node to be appended
6730 "beforeappend" : true,
6732 * @event beforeremove
6733 * Fires before a child is removed, return false to cancel the remove.
6734 * @param {Tree} tree The owner tree
6735 * @param {Node} this This node
6736 * @param {Node} node The child node to be removed
6738 "beforeremove" : true,
6741 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6742 * @param {Tree} tree The owner tree
6743 * @param {Node} this This node
6744 * @param {Node} oldParent The parent of this node
6745 * @param {Node} newParent The new parent this node is moving to
6746 * @param {Number} index The index it is being moved to
6748 "beforemove" : true,
6750 * @event beforeinsert
6751 * Fires before a new child is inserted, return false to cancel the insert.
6752 * @param {Tree} tree The owner tree
6753 * @param {Node} this This node
6754 * @param {Node} node The child node to be inserted
6755 * @param {Node} refNode The child node the node is being inserted before
6757 "beforeinsert" : true
6759 this.listeners = this.attributes.listeners;
6760 Roo.data.Node.superclass.constructor.call(this);
6763 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6764 fireEvent : function(evtName){
6765 // first do standard event for this node
6766 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6769 // then bubble it up to the tree if the event wasn't cancelled
6770 var ot = this.getOwnerTree();
6772 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6780 * Returns true if this node is a leaf
6783 isLeaf : function(){
6784 return this.leaf === true;
6788 setFirstChild : function(node){
6789 this.firstChild = node;
6793 setLastChild : function(node){
6794 this.lastChild = node;
6799 * Returns true if this node is the last child of its parent
6802 isLast : function(){
6803 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6807 * Returns true if this node is the first child of its parent
6810 isFirst : function(){
6811 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6814 hasChildNodes : function(){
6815 return !this.isLeaf() && this.childNodes.length > 0;
6819 * Insert node(s) as the last child node of this node.
6820 * @param {Node/Array} node The node or Array of nodes to append
6821 * @return {Node} The appended node if single append, or null if an array was passed
6823 appendChild : function(node){
6825 if(node instanceof Array){
6827 }else if(arguments.length > 1){
6830 // if passed an array or multiple args do them one by one
6832 for(var i = 0, len = multi.length; i < len; i++) {
6833 this.appendChild(multi[i]);
6836 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6839 var index = this.childNodes.length;
6840 var oldParent = node.parentNode;
6841 // it's a move, make sure we move it cleanly
6843 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6846 oldParent.removeChild(node);
6848 index = this.childNodes.length;
6850 this.setFirstChild(node);
6852 this.childNodes.push(node);
6853 node.parentNode = this;
6854 var ps = this.childNodes[index-1];
6856 node.previousSibling = ps;
6857 ps.nextSibling = node;
6859 node.previousSibling = null;
6861 node.nextSibling = null;
6862 this.setLastChild(node);
6863 node.setOwnerTree(this.getOwnerTree());
6864 this.fireEvent("append", this.ownerTree, this, node, index);
6866 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6873 * Removes a child node from this node.
6874 * @param {Node} node The node to remove
6875 * @return {Node} The removed node
6877 removeChild : function(node){
6878 var index = this.childNodes.indexOf(node);
6882 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6886 // remove it from childNodes collection
6887 this.childNodes.splice(index, 1);
6890 if(node.previousSibling){
6891 node.previousSibling.nextSibling = node.nextSibling;
6893 if(node.nextSibling){
6894 node.nextSibling.previousSibling = node.previousSibling;
6897 // update child refs
6898 if(this.firstChild == node){
6899 this.setFirstChild(node.nextSibling);
6901 if(this.lastChild == node){
6902 this.setLastChild(node.previousSibling);
6905 node.setOwnerTree(null);
6906 // clear any references from the node
6907 node.parentNode = null;
6908 node.previousSibling = null;
6909 node.nextSibling = null;
6910 this.fireEvent("remove", this.ownerTree, this, node);
6915 * Inserts the first node before the second node in this nodes childNodes collection.
6916 * @param {Node} node The node to insert
6917 * @param {Node} refNode The node to insert before (if null the node is appended)
6918 * @return {Node} The inserted node
6920 insertBefore : function(node, refNode){
6921 if(!refNode){ // like standard Dom, refNode can be null for append
6922 return this.appendChild(node);
6925 if(node == refNode){
6929 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6932 var index = this.childNodes.indexOf(refNode);
6933 var oldParent = node.parentNode;
6934 var refIndex = index;
6936 // when moving internally, indexes will change after remove
6937 if(oldParent == this && this.childNodes.indexOf(node) < index){
6941 // it's a move, make sure we move it cleanly
6943 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6946 oldParent.removeChild(node);
6949 this.setFirstChild(node);
6951 this.childNodes.splice(refIndex, 0, node);
6952 node.parentNode = this;
6953 var ps = this.childNodes[refIndex-1];
6955 node.previousSibling = ps;
6956 ps.nextSibling = node;
6958 node.previousSibling = null;
6960 node.nextSibling = refNode;
6961 refNode.previousSibling = node;
6962 node.setOwnerTree(this.getOwnerTree());
6963 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6965 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6971 * Returns the child node at the specified index.
6972 * @param {Number} index
6975 item : function(index){
6976 return this.childNodes[index];
6980 * Replaces one child node in this node with another.
6981 * @param {Node} newChild The replacement node
6982 * @param {Node} oldChild The node to replace
6983 * @return {Node} The replaced node
6985 replaceChild : function(newChild, oldChild){
6986 this.insertBefore(newChild, oldChild);
6987 this.removeChild(oldChild);
6992 * Returns the index of a child node
6993 * @param {Node} node
6994 * @return {Number} The index of the node or -1 if it was not found
6996 indexOf : function(child){
6997 return this.childNodes.indexOf(child);
7001 * Returns the tree this node is in.
7004 getOwnerTree : function(){
7005 // if it doesn't have one, look for one
7006 if(!this.ownerTree){
7010 this.ownerTree = p.ownerTree;
7016 return this.ownerTree;
7020 * Returns depth of this node (the root node has a depth of 0)
7023 getDepth : function(){
7026 while(p.parentNode){
7034 setOwnerTree : function(tree){
7035 // if it's move, we need to update everyone
7036 if(tree != this.ownerTree){
7038 this.ownerTree.unregisterNode(this);
7040 this.ownerTree = tree;
7041 var cs = this.childNodes;
7042 for(var i = 0, len = cs.length; i < len; i++) {
7043 cs[i].setOwnerTree(tree);
7046 tree.registerNode(this);
7052 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7053 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7054 * @return {String} The path
7056 getPath : function(attr){
7057 attr = attr || "id";
7058 var p = this.parentNode;
7059 var b = [this.attributes[attr]];
7061 b.unshift(p.attributes[attr]);
7064 var sep = this.getOwnerTree().pathSeparator;
7065 return sep + b.join(sep);
7069 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7070 * function call will be the scope provided or the current node. The arguments to the function
7071 * will be the args provided or the current node. If the function returns false at any point,
7072 * the bubble is stopped.
7073 * @param {Function} fn The function to call
7074 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7075 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7077 bubble : function(fn, scope, args){
7080 if(fn.call(scope || p, args || p) === false){
7088 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7089 * function call will be the scope provided or the current node. The arguments to the function
7090 * will be the args provided or the current node. If the function returns false at any point,
7091 * the cascade is stopped on that branch.
7092 * @param {Function} fn The function to call
7093 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7094 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7096 cascade : function(fn, scope, args){
7097 if(fn.call(scope || this, args || this) !== false){
7098 var cs = this.childNodes;
7099 for(var i = 0, len = cs.length; i < len; i++) {
7100 cs[i].cascade(fn, scope, args);
7106 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7107 * function call will be the scope provided or the current node. The arguments to the function
7108 * will be the args provided or the current node. If the function returns false at any point,
7109 * the iteration stops.
7110 * @param {Function} fn The function to call
7111 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7112 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7114 eachChild : function(fn, scope, args){
7115 var cs = this.childNodes;
7116 for(var i = 0, len = cs.length; i < len; i++) {
7117 if(fn.call(scope || this, args || cs[i]) === false){
7124 * Finds the first child that has the attribute with the specified value.
7125 * @param {String} attribute The attribute name
7126 * @param {Mixed} value The value to search for
7127 * @return {Node} The found child or null if none was found
7129 findChild : function(attribute, value){
7130 var cs = this.childNodes;
7131 for(var i = 0, len = cs.length; i < len; i++) {
7132 if(cs[i].attributes[attribute] == value){
7140 * Finds the first child by a custom function. The child matches if the function passed
7142 * @param {Function} fn
7143 * @param {Object} scope (optional)
7144 * @return {Node} The found child or null if none was found
7146 findChildBy : function(fn, scope){
7147 var cs = this.childNodes;
7148 for(var i = 0, len = cs.length; i < len; i++) {
7149 if(fn.call(scope||cs[i], cs[i]) === true){
7157 * Sorts this nodes children using the supplied sort function
7158 * @param {Function} fn
7159 * @param {Object} scope (optional)
7161 sort : function(fn, scope){
7162 var cs = this.childNodes;
7163 var len = cs.length;
7165 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7167 for(var i = 0; i < len; i++){
7169 n.previousSibling = cs[i-1];
7170 n.nextSibling = cs[i+1];
7172 this.setFirstChild(n);
7175 this.setLastChild(n);
7182 * Returns true if this node is an ancestor (at any point) of the passed node.
7183 * @param {Node} node
7186 contains : function(node){
7187 return node.isAncestor(this);
7191 * Returns true if the passed node is an ancestor (at any point) of this node.
7192 * @param {Node} node
7195 isAncestor : function(node){
7196 var p = this.parentNode;
7206 toString : function(){
7207 return "[Node"+(this.id?" "+this.id:"")+"]";
7211 * Ext JS Library 1.1.1
7212 * Copyright(c) 2006-2007, Ext JS, LLC.
7214 * Originally Released Under LGPL - original licence link has changed is not relivant.
7217 * <script type="text/javascript">
7222 * @class Roo.ComponentMgr
7223 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7226 Roo.ComponentMgr = function(){
7227 var all = new Roo.util.MixedCollection();
7231 * Registers a component.
7232 * @param {Roo.Component} c The component
7234 register : function(c){
7239 * Unregisters a component.
7240 * @param {Roo.Component} c The component
7242 unregister : function(c){
7247 * Returns a component by id
7248 * @param {String} id The component id
7255 * Registers a function that will be called when a specified component is added to ComponentMgr
7256 * @param {String} id The component id
7257 * @param {Funtction} fn The callback function
7258 * @param {Object} scope The scope of the callback
7260 onAvailable : function(id, fn, scope){
7261 all.on("add", function(index, o){
7263 fn.call(scope || o, o);
7264 all.un("add", fn, scope);
7271 * Ext JS Library 1.1.1
7272 * Copyright(c) 2006-2007, Ext JS, LLC.
7274 * Originally Released Under LGPL - original licence link has changed is not relivant.
7277 * <script type="text/javascript">
7281 * @class Roo.Component
7282 * @extends Roo.util.Observable
7283 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7284 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7285 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7286 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7287 * All visual components (widgets) that require rendering into a layout should subclass Component.
7289 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7290 * 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
7291 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7293 Roo.Component = function(config){
7294 config = config || {};
7295 if(config.tagName || config.dom || typeof config == "string"){ // element object
7296 config = {el: config, id: config.id || config};
7298 this.initialConfig = config;
7300 Roo.apply(this, config);
7304 * Fires after the component is disabled.
7305 * @param {Roo.Component} this
7310 * Fires after the component is enabled.
7311 * @param {Roo.Component} this
7316 * Fires before the component is shown. Return false to stop the show.
7317 * @param {Roo.Component} this
7322 * Fires after the component is shown.
7323 * @param {Roo.Component} this
7328 * Fires before the component is hidden. Return false to stop the hide.
7329 * @param {Roo.Component} this
7334 * Fires after the component is hidden.
7335 * @param {Roo.Component} this
7339 * @event beforerender
7340 * Fires before the component is rendered. Return false to stop the render.
7341 * @param {Roo.Component} this
7343 beforerender : true,
7346 * Fires after the component is rendered.
7347 * @param {Roo.Component} this
7351 * @event beforedestroy
7352 * Fires before the component is destroyed. Return false to stop the destroy.
7353 * @param {Roo.Component} this
7355 beforedestroy : true,
7358 * Fires after the component is destroyed.
7359 * @param {Roo.Component} this
7364 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7366 Roo.ComponentMgr.register(this);
7367 Roo.Component.superclass.constructor.call(this);
7368 this.initComponent();
7369 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7370 this.render(this.renderTo);
7371 delete this.renderTo;
7376 Roo.Component.AUTO_ID = 1000;
7378 Roo.extend(Roo.Component, Roo.util.Observable, {
7380 * @property {Boolean} hidden
7381 * true if this component is hidden. Read-only.
7385 * true if this component is disabled. Read-only.
7389 * true if this component has been rendered. Read-only.
7393 /** @cfg {String} disableClass
7394 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7396 disabledClass : "x-item-disabled",
7397 /** @cfg {Boolean} allowDomMove
7398 * Whether the component can move the Dom node when rendering (defaults to true).
7400 allowDomMove : true,
7401 /** @cfg {String} hideMode
7402 * How this component should hidden. Supported values are
7403 * "visibility" (css visibility), "offsets" (negative offset position) and
7404 * "display" (css display) - defaults to "display".
7406 hideMode: 'display',
7409 ctype : "Roo.Component",
7411 /** @cfg {String} actionMode
7412 * which property holds the element that used for hide() / show() / disable() / enable()
7418 getActionEl : function(){
7419 return this[this.actionMode];
7422 initComponent : Roo.emptyFn,
7424 * If this is a lazy rendering component, render it to its container element.
7425 * @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.
7427 render : function(container, position){
7428 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7429 if(!container && this.el){
7430 this.el = Roo.get(this.el);
7431 container = this.el.dom.parentNode;
7432 this.allowDomMove = false;
7434 this.container = Roo.get(container);
7435 this.rendered = true;
7436 if(position !== undefined){
7437 if(typeof position == 'number'){
7438 position = this.container.dom.childNodes[position];
7440 position = Roo.getDom(position);
7443 this.onRender(this.container, position || null);
7445 this.el.addClass(this.cls);
7449 this.el.applyStyles(this.style);
7452 this.fireEvent("render", this);
7453 this.afterRender(this.container);
7465 // default function is not really useful
7466 onRender : function(ct, position){
7468 this.el = Roo.get(this.el);
7469 if(this.allowDomMove !== false){
7470 ct.dom.insertBefore(this.el.dom, position);
7476 getAutoCreate : function(){
7477 var cfg = typeof this.autoCreate == "object" ?
7478 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7479 if(this.id && !cfg.id){
7486 afterRender : Roo.emptyFn,
7489 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7490 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7492 destroy : function(){
7493 if(this.fireEvent("beforedestroy", this) !== false){
7494 this.purgeListeners();
7495 this.beforeDestroy();
7497 this.el.removeAllListeners();
7499 if(this.actionMode == "container"){
7500 this.container.remove();
7504 Roo.ComponentMgr.unregister(this);
7505 this.fireEvent("destroy", this);
7510 beforeDestroy : function(){
7515 onDestroy : function(){
7520 * Returns the underlying {@link Roo.Element}.
7521 * @return {Roo.Element} The element
7528 * Returns the id of this component.
7536 * Try to focus this component.
7537 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7538 * @return {Roo.Component} this
7540 focus : function(selectText){
7543 if(selectText === true){
7544 this.el.dom.select();
7559 * Disable this component.
7560 * @return {Roo.Component} this
7562 disable : function(){
7566 this.disabled = true;
7567 this.fireEvent("disable", this);
7572 onDisable : function(){
7573 this.getActionEl().addClass(this.disabledClass);
7574 this.el.dom.disabled = true;
7578 * Enable this component.
7579 * @return {Roo.Component} this
7581 enable : function(){
7585 this.disabled = false;
7586 this.fireEvent("enable", this);
7591 onEnable : function(){
7592 this.getActionEl().removeClass(this.disabledClass);
7593 this.el.dom.disabled = false;
7597 * Convenience function for setting disabled/enabled by boolean.
7598 * @param {Boolean} disabled
7600 setDisabled : function(disabled){
7601 this[disabled ? "disable" : "enable"]();
7605 * Show this component.
7606 * @return {Roo.Component} this
7609 if(this.fireEvent("beforeshow", this) !== false){
7610 this.hidden = false;
7614 this.fireEvent("show", this);
7620 onShow : function(){
7621 var ae = this.getActionEl();
7622 if(this.hideMode == 'visibility'){
7623 ae.dom.style.visibility = "visible";
7624 }else if(this.hideMode == 'offsets'){
7625 ae.removeClass('x-hidden');
7627 ae.dom.style.display = "";
7632 * Hide this component.
7633 * @return {Roo.Component} this
7636 if(this.fireEvent("beforehide", this) !== false){
7641 this.fireEvent("hide", this);
7647 onHide : function(){
7648 var ae = this.getActionEl();
7649 if(this.hideMode == 'visibility'){
7650 ae.dom.style.visibility = "hidden";
7651 }else if(this.hideMode == 'offsets'){
7652 ae.addClass('x-hidden');
7654 ae.dom.style.display = "none";
7659 * Convenience function to hide or show this component by boolean.
7660 * @param {Boolean} visible True to show, false to hide
7661 * @return {Roo.Component} this
7663 setVisible: function(visible){
7673 * Returns true if this component is visible.
7675 isVisible : function(){
7676 return this.getActionEl().isVisible();
7679 cloneConfig : function(overrides){
7680 overrides = overrides || {};
7681 var id = overrides.id || Roo.id();
7682 var cfg = Roo.applyIf(overrides, this.initialConfig);
7683 cfg.id = id; // prevent dup id
7684 return new this.constructor(cfg);
7688 * Ext JS Library 1.1.1
7689 * Copyright(c) 2006-2007, Ext JS, LLC.
7691 * Originally Released Under LGPL - original licence link has changed is not relivant.
7694 * <script type="text/javascript">
7699 * @extends Roo.Element
7700 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7701 * automatic maintaining of shadow/shim positions.
7702 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7703 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7704 * you can pass a string with a CSS class name. False turns off the shadow.
7705 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7706 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7707 * @cfg {String} cls CSS class to add to the element
7708 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7709 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7711 * @param {Object} config An object with config options.
7712 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7715 Roo.Layer = function(config, existingEl){
7716 config = config || {};
7717 var dh = Roo.DomHelper;
7718 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7720 this.dom = Roo.getDom(existingEl);
7723 var o = config.dh || {tag: "div", cls: "x-layer"};
7724 this.dom = dh.append(pel, o);
7727 this.addClass(config.cls);
7729 this.constrain = config.constrain !== false;
7730 this.visibilityMode = Roo.Element.VISIBILITY;
7732 this.id = this.dom.id = config.id;
7734 this.id = Roo.id(this.dom);
7736 this.zindex = config.zindex || this.getZIndex();
7737 this.position("absolute", this.zindex);
7739 this.shadowOffset = config.shadowOffset || 4;
7740 this.shadow = new Roo.Shadow({
7741 offset : this.shadowOffset,
7742 mode : config.shadow
7745 this.shadowOffset = 0;
7747 this.useShim = config.shim !== false && Roo.useShims;
7748 this.useDisplay = config.useDisplay;
7752 var supr = Roo.Element.prototype;
7754 // shims are shared among layer to keep from having 100 iframes
7757 Roo.extend(Roo.Layer, Roo.Element, {
7759 getZIndex : function(){
7760 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7763 getShim : function(){
7770 var shim = shims.shift();
7772 shim = this.createShim();
7773 shim.enableDisplayMode('block');
7774 shim.dom.style.display = 'none';
7775 shim.dom.style.visibility = 'visible';
7777 var pn = this.dom.parentNode;
7778 if(shim.dom.parentNode != pn){
7779 pn.insertBefore(shim.dom, this.dom);
7781 shim.setStyle('z-index', this.getZIndex()-2);
7786 hideShim : function(){
7788 this.shim.setDisplayed(false);
7789 shims.push(this.shim);
7794 disableShadow : function(){
7796 this.shadowDisabled = true;
7798 this.lastShadowOffset = this.shadowOffset;
7799 this.shadowOffset = 0;
7803 enableShadow : function(show){
7805 this.shadowDisabled = false;
7806 this.shadowOffset = this.lastShadowOffset;
7807 delete this.lastShadowOffset;
7815 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7816 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7817 sync : function(doShow){
7818 var sw = this.shadow;
7819 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7820 var sh = this.getShim();
7822 var w = this.getWidth(),
7823 h = this.getHeight();
7825 var l = this.getLeft(true),
7826 t = this.getTop(true);
7828 if(sw && !this.shadowDisabled){
7829 if(doShow && !sw.isVisible()){
7832 sw.realign(l, t, w, h);
7838 // fit the shim behind the shadow, so it is shimmed too
7839 var a = sw.adjusts, s = sh.dom.style;
7840 s.left = (Math.min(l, l+a.l))+"px";
7841 s.top = (Math.min(t, t+a.t))+"px";
7842 s.width = (w+a.w)+"px";
7843 s.height = (h+a.h)+"px";
7850 sh.setLeftTop(l, t);
7857 destroy : function(){
7862 this.removeAllListeners();
7863 var pn = this.dom.parentNode;
7865 pn.removeChild(this.dom);
7867 Roo.Element.uncache(this.id);
7870 remove : function(){
7875 beginUpdate : function(){
7876 this.updating = true;
7880 endUpdate : function(){
7881 this.updating = false;
7886 hideUnders : function(negOffset){
7894 constrainXY : function(){
7896 var vw = Roo.lib.Dom.getViewWidth(),
7897 vh = Roo.lib.Dom.getViewHeight();
7898 var s = Roo.get(document).getScroll();
7900 var xy = this.getXY();
7901 var x = xy[0], y = xy[1];
7902 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7903 // only move it if it needs it
7905 // first validate right/bottom
7906 if((x + w) > vw+s.left){
7907 x = vw - w - this.shadowOffset;
7910 if((y + h) > vh+s.top){
7911 y = vh - h - this.shadowOffset;
7914 // then make sure top/left isn't negative
7925 var ay = this.avoidY;
7926 if(y <= ay && (y+h) >= ay){
7932 supr.setXY.call(this, xy);
7938 isVisible : function(){
7939 return this.visible;
7943 showAction : function(){
7944 this.visible = true; // track visibility to prevent getStyle calls
7945 if(this.useDisplay === true){
7946 this.setDisplayed("");
7947 }else if(this.lastXY){
7948 supr.setXY.call(this, this.lastXY);
7949 }else if(this.lastLT){
7950 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7955 hideAction : function(){
7956 this.visible = false;
7957 if(this.useDisplay === true){
7958 this.setDisplayed(false);
7960 this.setLeftTop(-10000,-10000);
7964 // overridden Element method
7965 setVisible : function(v, a, d, c, e){
7970 var cb = function(){
7975 }.createDelegate(this);
7976 supr.setVisible.call(this, true, true, d, cb, e);
7979 this.hideUnders(true);
7988 }.createDelegate(this);
7990 supr.setVisible.call(this, v, a, d, cb, e);
7999 storeXY : function(xy){
8004 storeLeftTop : function(left, top){
8006 this.lastLT = [left, top];
8010 beforeFx : function(){
8011 this.beforeAction();
8012 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8016 afterFx : function(){
8017 Roo.Layer.superclass.afterFx.apply(this, arguments);
8018 this.sync(this.isVisible());
8022 beforeAction : function(){
8023 if(!this.updating && this.shadow){
8028 // overridden Element method
8029 setLeft : function(left){
8030 this.storeLeftTop(left, this.getTop(true));
8031 supr.setLeft.apply(this, arguments);
8035 setTop : function(top){
8036 this.storeLeftTop(this.getLeft(true), top);
8037 supr.setTop.apply(this, arguments);
8041 setLeftTop : function(left, top){
8042 this.storeLeftTop(left, top);
8043 supr.setLeftTop.apply(this, arguments);
8047 setXY : function(xy, a, d, c, e){
8049 this.beforeAction();
8051 var cb = this.createCB(c);
8052 supr.setXY.call(this, xy, a, d, cb, e);
8059 createCB : function(c){
8070 // overridden Element method
8071 setX : function(x, a, d, c, e){
8072 this.setXY([x, this.getY()], a, d, c, e);
8075 // overridden Element method
8076 setY : function(y, a, d, c, e){
8077 this.setXY([this.getX(), y], a, d, c, e);
8080 // overridden Element method
8081 setSize : function(w, h, a, d, c, e){
8082 this.beforeAction();
8083 var cb = this.createCB(c);
8084 supr.setSize.call(this, w, h, a, d, cb, e);
8090 // overridden Element method
8091 setWidth : function(w, a, d, c, e){
8092 this.beforeAction();
8093 var cb = this.createCB(c);
8094 supr.setWidth.call(this, w, a, d, cb, e);
8100 // overridden Element method
8101 setHeight : function(h, a, d, c, e){
8102 this.beforeAction();
8103 var cb = this.createCB(c);
8104 supr.setHeight.call(this, h, a, d, cb, e);
8110 // overridden Element method
8111 setBounds : function(x, y, w, h, a, d, c, e){
8112 this.beforeAction();
8113 var cb = this.createCB(c);
8115 this.storeXY([x, y]);
8116 supr.setXY.call(this, [x, y]);
8117 supr.setSize.call(this, w, h, a, d, cb, e);
8120 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8126 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8127 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8128 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8129 * @param {Number} zindex The new z-index to set
8130 * @return {this} The Layer
8132 setZIndex : function(zindex){
8133 this.zindex = zindex;
8134 this.setStyle("z-index", zindex + 2);
8136 this.shadow.setZIndex(zindex + 1);
8139 this.shim.setStyle("z-index", zindex);
8145 * Ext JS Library 1.1.1
8146 * Copyright(c) 2006-2007, Ext JS, LLC.
8148 * Originally Released Under LGPL - original licence link has changed is not relivant.
8151 * <script type="text/javascript">
8157 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8158 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8159 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8161 * Create a new Shadow
8162 * @param {Object} config The config object
8164 Roo.Shadow = function(config){
8165 Roo.apply(this, config);
8166 if(typeof this.mode != "string"){
8167 this.mode = this.defaultMode;
8169 var o = this.offset, a = {h: 0};
8170 var rad = Math.floor(this.offset/2);
8171 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8177 a.l -= this.offset + rad;
8178 a.t -= this.offset + rad;
8189 a.l -= (this.offset - rad);
8190 a.t -= this.offset + rad;
8192 a.w -= (this.offset - rad)*2;
8203 a.l -= (this.offset - rad);
8204 a.t -= (this.offset - rad);
8206 a.w -= (this.offset + rad + 1);
8207 a.h -= (this.offset + rad);
8216 Roo.Shadow.prototype = {
8218 * @cfg {String} mode
8219 * The shadow display mode. Supports the following options:<br />
8220 * sides: Shadow displays on both sides and bottom only<br />
8221 * frame: Shadow displays equally on all four sides<br />
8222 * drop: Traditional bottom-right drop shadow (default)
8225 * @cfg {String} offset
8226 * The number of pixels to offset the shadow from the element (defaults to 4)
8231 defaultMode: "drop",
8234 * Displays the shadow under the target element
8235 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8237 show : function(target){
8238 target = Roo.get(target);
8240 this.el = Roo.Shadow.Pool.pull();
8241 if(this.el.dom.nextSibling != target.dom){
8242 this.el.insertBefore(target);
8245 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8247 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8250 target.getLeft(true),
8251 target.getTop(true),
8255 this.el.dom.style.display = "block";
8259 * Returns true if the shadow is visible, else false
8261 isVisible : function(){
8262 return this.el ? true : false;
8266 * Direct alignment when values are already available. Show must be called at least once before
8267 * calling this method to ensure it is initialized.
8268 * @param {Number} left The target element left position
8269 * @param {Number} top The target element top position
8270 * @param {Number} width The target element width
8271 * @param {Number} height The target element height
8273 realign : function(l, t, w, h){
8277 var a = this.adjusts, d = this.el.dom, s = d.style;
8279 s.left = (l+a.l)+"px";
8280 s.top = (t+a.t)+"px";
8281 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8283 if(s.width != sws || s.height != shs){
8287 var cn = d.childNodes;
8288 var sww = Math.max(0, (sw-12))+"px";
8289 cn[0].childNodes[1].style.width = sww;
8290 cn[1].childNodes[1].style.width = sww;
8291 cn[2].childNodes[1].style.width = sww;
8292 cn[1].style.height = Math.max(0, (sh-12))+"px";
8302 this.el.dom.style.display = "none";
8303 Roo.Shadow.Pool.push(this.el);
8309 * Adjust the z-index of this shadow
8310 * @param {Number} zindex The new z-index
8312 setZIndex : function(z){
8315 this.el.setStyle("z-index", z);
8320 // Private utility class that manages the internal Shadow cache
8321 Roo.Shadow.Pool = function(){
8323 var markup = Roo.isIE ?
8324 '<div class="x-ie-shadow"></div>' :
8325 '<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>';
8330 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8331 sh.autoBoxAdjust = false;
8336 push : function(sh){
8342 * Ext JS Library 1.1.1
8343 * Copyright(c) 2006-2007, Ext JS, LLC.
8345 * Originally Released Under LGPL - original licence link has changed is not relivant.
8348 * <script type="text/javascript">
8352 * @class Roo.BoxComponent
8353 * @extends Roo.Component
8354 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8355 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8356 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8357 * layout containers.
8359 * @param {Roo.Element/String/Object} config The configuration options.
8361 Roo.BoxComponent = function(config){
8362 Roo.Component.call(this, config);
8366 * Fires after the component is resized.
8367 * @param {Roo.Component} this
8368 * @param {Number} adjWidth The box-adjusted width that was set
8369 * @param {Number} adjHeight The box-adjusted height that was set
8370 * @param {Number} rawWidth The width that was originally specified
8371 * @param {Number} rawHeight The height that was originally specified
8376 * Fires after the component is moved.
8377 * @param {Roo.Component} this
8378 * @param {Number} x The new x position
8379 * @param {Number} y The new y position
8385 Roo.extend(Roo.BoxComponent, Roo.Component, {
8386 // private, set in afterRender to signify that the component has been rendered
8388 // private, used to defer height settings to subclasses
8390 /** @cfg {Number} width
8391 * width (optional) size of component
8393 /** @cfg {Number} height
8394 * height (optional) size of component
8398 * Sets the width and height of the component. This method fires the resize event. This method can accept
8399 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8400 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8401 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8402 * @return {Roo.BoxComponent} this
8404 setSize : function(w, h){
8405 // support for standard size objects
8406 if(typeof w == 'object'){
8417 // prevent recalcs when not needed
8418 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8421 this.lastSize = {width: w, height: h};
8423 var adj = this.adjustSize(w, h);
8424 var aw = adj.width, ah = adj.height;
8425 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8426 var rz = this.getResizeEl();
8427 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8429 }else if(!this.deferHeight && ah !== undefined){
8431 }else if(aw !== undefined){
8434 this.onResize(aw, ah, w, h);
8435 this.fireEvent('resize', this, aw, ah, w, h);
8441 * Gets the current size of the component's underlying element.
8442 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8444 getSize : function(){
8445 return this.el.getSize();
8449 * Gets the current XY position of the component's underlying element.
8450 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8451 * @return {Array} The XY position of the element (e.g., [100, 200])
8453 getPosition : function(local){
8455 return [this.el.getLeft(true), this.el.getTop(true)];
8457 return this.xy || this.el.getXY();
8461 * Gets the current box measurements of the component's underlying element.
8462 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8463 * @returns {Object} box An object in the format {x, y, width, height}
8465 getBox : function(local){
8466 var s = this.el.getSize();
8468 s.x = this.el.getLeft(true);
8469 s.y = this.el.getTop(true);
8471 var xy = this.xy || this.el.getXY();
8479 * Sets the current box measurements of the component's underlying element.
8480 * @param {Object} box An object in the format {x, y, width, height}
8481 * @returns {Roo.BoxComponent} this
8483 updateBox : function(box){
8484 this.setSize(box.width, box.height);
8485 this.setPagePosition(box.x, box.y);
8490 getResizeEl : function(){
8491 return this.resizeEl || this.el;
8495 getPositionEl : function(){
8496 return this.positionEl || this.el;
8500 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8501 * This method fires the move event.
8502 * @param {Number} left The new left
8503 * @param {Number} top The new top
8504 * @returns {Roo.BoxComponent} this
8506 setPosition : function(x, y){
8512 var adj = this.adjustPosition(x, y);
8513 var ax = adj.x, ay = adj.y;
8515 var el = this.getPositionEl();
8516 if(ax !== undefined || ay !== undefined){
8517 if(ax !== undefined && ay !== undefined){
8518 el.setLeftTop(ax, ay);
8519 }else if(ax !== undefined){
8521 }else if(ay !== undefined){
8524 this.onPosition(ax, ay);
8525 this.fireEvent('move', this, ax, ay);
8531 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8532 * This method fires the move event.
8533 * @param {Number} x The new x position
8534 * @param {Number} y The new y position
8535 * @returns {Roo.BoxComponent} this
8537 setPagePosition : function(x, y){
8543 if(x === undefined || y === undefined){ // cannot translate undefined points
8546 var p = this.el.translatePoints(x, y);
8547 this.setPosition(p.left, p.top);
8552 onRender : function(ct, position){
8553 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8555 this.resizeEl = Roo.get(this.resizeEl);
8557 if(this.positionEl){
8558 this.positionEl = Roo.get(this.positionEl);
8563 afterRender : function(){
8564 Roo.BoxComponent.superclass.afterRender.call(this);
8565 this.boxReady = true;
8566 this.setSize(this.width, this.height);
8567 if(this.x || this.y){
8568 this.setPosition(this.x, this.y);
8570 if(this.pageX || this.pageY){
8571 this.setPagePosition(this.pageX, this.pageY);
8576 * Force the component's size to recalculate based on the underlying element's current height and width.
8577 * @returns {Roo.BoxComponent} this
8579 syncSize : function(){
8580 delete this.lastSize;
8581 this.setSize(this.el.getWidth(), this.el.getHeight());
8586 * Called after the component is resized, this method is empty by default but can be implemented by any
8587 * subclass that needs to perform custom logic after a resize occurs.
8588 * @param {Number} adjWidth The box-adjusted width that was set
8589 * @param {Number} adjHeight The box-adjusted height that was set
8590 * @param {Number} rawWidth The width that was originally specified
8591 * @param {Number} rawHeight The height that was originally specified
8593 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8598 * Called after the component is moved, this method is empty by default but can be implemented by any
8599 * subclass that needs to perform custom logic after a move occurs.
8600 * @param {Number} x The new x position
8601 * @param {Number} y The new y position
8603 onPosition : function(x, y){
8608 adjustSize : function(w, h){
8612 if(this.autoHeight){
8615 return {width : w, height: h};
8619 adjustPosition : function(x, y){
8620 return {x : x, y: y};
8624 * Ext JS Library 1.1.1
8625 * Copyright(c) 2006-2007, Ext JS, LLC.
8627 * Originally Released Under LGPL - original licence link has changed is not relivant.
8630 * <script type="text/javascript">
8635 * @class Roo.SplitBar
8636 * @extends Roo.util.Observable
8637 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8641 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8642 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8643 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8644 split.minSize = 100;
8645 split.maxSize = 600;
8646 split.animate = true;
8647 split.on('moved', splitterMoved);
8650 * Create a new SplitBar
8651 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8652 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8653 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8654 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8655 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8656 position of the SplitBar).
8658 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8661 this.el = Roo.get(dragElement, true);
8662 this.el.dom.unselectable = "on";
8664 this.resizingEl = Roo.get(resizingElement, true);
8668 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8669 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8672 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8675 * The minimum size of the resizing element. (Defaults to 0)
8681 * The maximum size of the resizing element. (Defaults to 2000)
8684 this.maxSize = 2000;
8687 * Whether to animate the transition to the new size
8690 this.animate = false;
8693 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8696 this.useShim = false;
8703 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8705 this.proxy = Roo.get(existingProxy).dom;
8708 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8711 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8714 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8717 this.dragSpecs = {};
8720 * @private The adapter to use to positon and resize elements
8722 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8723 this.adapter.init(this);
8725 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8727 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8728 this.el.addClass("x-splitbar-h");
8731 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8732 this.el.addClass("x-splitbar-v");
8738 * Fires when the splitter is moved (alias for {@link #event-moved})
8739 * @param {Roo.SplitBar} this
8740 * @param {Number} newSize the new width or height
8745 * Fires when the splitter is moved
8746 * @param {Roo.SplitBar} this
8747 * @param {Number} newSize the new width or height
8751 * @event beforeresize
8752 * Fires before the splitter is dragged
8753 * @param {Roo.SplitBar} this
8755 "beforeresize" : true,
8757 "beforeapply" : true
8760 Roo.util.Observable.call(this);
8763 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8764 onStartProxyDrag : function(x, y){
8765 this.fireEvent("beforeresize", this);
8767 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8769 o.enableDisplayMode("block");
8770 // all splitbars share the same overlay
8771 Roo.SplitBar.prototype.overlay = o;
8773 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8774 this.overlay.show();
8775 Roo.get(this.proxy).setDisplayed("block");
8776 var size = this.adapter.getElementSize(this);
8777 this.activeMinSize = this.getMinimumSize();;
8778 this.activeMaxSize = this.getMaximumSize();;
8779 var c1 = size - this.activeMinSize;
8780 var c2 = Math.max(this.activeMaxSize - size, 0);
8781 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8782 this.dd.resetConstraints();
8783 this.dd.setXConstraint(
8784 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8785 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8787 this.dd.setYConstraint(0, 0);
8789 this.dd.resetConstraints();
8790 this.dd.setXConstraint(0, 0);
8791 this.dd.setYConstraint(
8792 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8793 this.placement == Roo.SplitBar.TOP ? c2 : c1
8796 this.dragSpecs.startSize = size;
8797 this.dragSpecs.startPoint = [x, y];
8798 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8802 * @private Called after the drag operation by the DDProxy
8804 onEndProxyDrag : function(e){
8805 Roo.get(this.proxy).setDisplayed(false);
8806 var endPoint = Roo.lib.Event.getXY(e);
8808 this.overlay.hide();
8811 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8812 newSize = this.dragSpecs.startSize +
8813 (this.placement == Roo.SplitBar.LEFT ?
8814 endPoint[0] - this.dragSpecs.startPoint[0] :
8815 this.dragSpecs.startPoint[0] - endPoint[0]
8818 newSize = this.dragSpecs.startSize +
8819 (this.placement == Roo.SplitBar.TOP ?
8820 endPoint[1] - this.dragSpecs.startPoint[1] :
8821 this.dragSpecs.startPoint[1] - endPoint[1]
8824 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8825 if(newSize != this.dragSpecs.startSize){
8826 if(this.fireEvent('beforeapply', this, newSize) !== false){
8827 this.adapter.setElementSize(this, newSize);
8828 this.fireEvent("moved", this, newSize);
8829 this.fireEvent("resize", this, newSize);
8835 * Get the adapter this SplitBar uses
8836 * @return The adapter object
8838 getAdapter : function(){
8839 return this.adapter;
8843 * Set the adapter this SplitBar uses
8844 * @param {Object} adapter A SplitBar adapter object
8846 setAdapter : function(adapter){
8847 this.adapter = adapter;
8848 this.adapter.init(this);
8852 * Gets the minimum size for the resizing element
8853 * @return {Number} The minimum size
8855 getMinimumSize : function(){
8856 return this.minSize;
8860 * Sets the minimum size for the resizing element
8861 * @param {Number} minSize The minimum size
8863 setMinimumSize : function(minSize){
8864 this.minSize = minSize;
8868 * Gets the maximum size for the resizing element
8869 * @return {Number} The maximum size
8871 getMaximumSize : function(){
8872 return this.maxSize;
8876 * Sets the maximum size for the resizing element
8877 * @param {Number} maxSize The maximum size
8879 setMaximumSize : function(maxSize){
8880 this.maxSize = maxSize;
8884 * Sets the initialize size for the resizing element
8885 * @param {Number} size The initial size
8887 setCurrentSize : function(size){
8888 var oldAnimate = this.animate;
8889 this.animate = false;
8890 this.adapter.setElementSize(this, size);
8891 this.animate = oldAnimate;
8895 * Destroy this splitbar.
8896 * @param {Boolean} removeEl True to remove the element
8898 destroy : function(removeEl){
8903 this.proxy.parentNode.removeChild(this.proxy);
8911 * @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.
8913 Roo.SplitBar.createProxy = function(dir){
8914 var proxy = new Roo.Element(document.createElement("div"));
8915 proxy.unselectable();
8916 var cls = 'x-splitbar-proxy';
8917 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8918 document.body.appendChild(proxy.dom);
8923 * @class Roo.SplitBar.BasicLayoutAdapter
8924 * Default Adapter. It assumes the splitter and resizing element are not positioned
8925 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8927 Roo.SplitBar.BasicLayoutAdapter = function(){
8930 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8931 // do nothing for now
8936 * Called before drag operations to get the current size of the resizing element.
8937 * @param {Roo.SplitBar} s The SplitBar using this adapter
8939 getElementSize : function(s){
8940 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8941 return s.resizingEl.getWidth();
8943 return s.resizingEl.getHeight();
8948 * Called after drag operations to set the size of the resizing element.
8949 * @param {Roo.SplitBar} s The SplitBar using this adapter
8950 * @param {Number} newSize The new size to set
8951 * @param {Function} onComplete A function to be invoked when resizing is complete
8953 setElementSize : function(s, newSize, onComplete){
8954 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8956 s.resizingEl.setWidth(newSize);
8958 onComplete(s, newSize);
8961 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8966 s.resizingEl.setHeight(newSize);
8968 onComplete(s, newSize);
8971 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8978 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8979 * @extends Roo.SplitBar.BasicLayoutAdapter
8980 * Adapter that moves the splitter element to align with the resized sizing element.
8981 * Used with an absolute positioned SplitBar.
8982 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8983 * document.body, make sure you assign an id to the body element.
8985 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8986 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8987 this.container = Roo.get(container);
8990 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8995 getElementSize : function(s){
8996 return this.basic.getElementSize(s);
8999 setElementSize : function(s, newSize, onComplete){
9000 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9003 moveSplitter : function(s){
9004 var yes = Roo.SplitBar;
9005 switch(s.placement){
9007 s.el.setX(s.resizingEl.getRight());
9010 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9013 s.el.setY(s.resizingEl.getBottom());
9016 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9023 * Orientation constant - Create a vertical SplitBar
9027 Roo.SplitBar.VERTICAL = 1;
9030 * Orientation constant - Create a horizontal SplitBar
9034 Roo.SplitBar.HORIZONTAL = 2;
9037 * Placement constant - The resizing element is to the left of the splitter element
9041 Roo.SplitBar.LEFT = 1;
9044 * Placement constant - The resizing element is to the right of the splitter element
9048 Roo.SplitBar.RIGHT = 2;
9051 * Placement constant - The resizing element is positioned above the splitter element
9055 Roo.SplitBar.TOP = 3;
9058 * Placement constant - The resizing element is positioned under splitter element
9062 Roo.SplitBar.BOTTOM = 4;
9065 * Ext JS Library 1.1.1
9066 * Copyright(c) 2006-2007, Ext JS, LLC.
9068 * Originally Released Under LGPL - original licence link has changed is not relivant.
9071 * <script type="text/javascript">
9076 * @extends Roo.util.Observable
9077 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9078 * This class also supports single and multi selection modes. <br>
9079 * Create a data model bound view:
9081 var store = new Roo.data.Store(...);
9083 var view = new Roo.View({
9085 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9088 selectedClass: "ydataview-selected",
9092 // listen for node click?
9093 view.on("click", function(vw, index, node, e){
9094 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9098 dataModel.load("foobar.xml");
9100 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9102 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9103 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9105 * Note: old style constructor is still suported (container, template, config)
9109 * @param {Object} config The config object
9112 Roo.View = function(config, depreciated_tpl, depreciated_config){
9114 if (typeof(depreciated_tpl) == 'undefined') {
9115 // new way.. - universal constructor.
9116 Roo.apply(this, config);
9117 this.el = Roo.get(this.el);
9120 this.el = Roo.get(config);
9121 this.tpl = depreciated_tpl;
9122 Roo.apply(this, depreciated_config);
9126 if(typeof(this.tpl) == "string"){
9127 this.tpl = new Roo.Template(this.tpl);
9129 // support xtype ctors..
9130 this.tpl = new Roo.factory(this.tpl, Roo);
9141 * @event beforeclick
9142 * Fires before a click is processed. Returns false to cancel the default action.
9143 * @param {Roo.View} this
9144 * @param {Number} index The index of the target node
9145 * @param {HTMLElement} node The target node
9146 * @param {Roo.EventObject} e The raw event object
9148 "beforeclick" : true,
9151 * Fires when a template node is clicked.
9152 * @param {Roo.View} this
9153 * @param {Number} index The index of the target node
9154 * @param {HTMLElement} node The target node
9155 * @param {Roo.EventObject} e The raw event object
9160 * Fires when a template node is double clicked.
9161 * @param {Roo.View} this
9162 * @param {Number} index The index of the target node
9163 * @param {HTMLElement} node The target node
9164 * @param {Roo.EventObject} e The raw event object
9168 * @event contextmenu
9169 * Fires when a template node is right clicked.
9170 * @param {Roo.View} this
9171 * @param {Number} index The index of the target node
9172 * @param {HTMLElement} node The target node
9173 * @param {Roo.EventObject} e The raw event object
9175 "contextmenu" : true,
9177 * @event selectionchange
9178 * Fires when the selected nodes change.
9179 * @param {Roo.View} this
9180 * @param {Array} selections Array of the selected nodes
9182 "selectionchange" : true,
9185 * @event beforeselect
9186 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9187 * @param {Roo.View} this
9188 * @param {HTMLElement} node The node to be selected
9189 * @param {Array} selections Array of currently selected nodes
9191 "beforeselect" : true
9195 "click": this.onClick,
9196 "dblclick": this.onDblClick,
9197 "contextmenu": this.onContextMenu,
9201 this.selections = [];
9203 this.cmp = new Roo.CompositeElementLite([]);
9205 this.store = Roo.factory(this.store, Roo.data);
9206 this.setStore(this.store, true);
9208 Roo.View.superclass.constructor.call(this);
9211 Roo.extend(Roo.View, Roo.util.Observable, {
9214 * @cfg {Roo.data.Store} store Data store to load data from.
9219 * @cfg {String|Roo.Element} el The container element.
9224 * @cfg {String|Roo.Template} tpl The template used by this View
9229 * @cfg {String} selectedClass The css class to add to selected nodes
9231 selectedClass : "x-view-selected",
9233 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9237 * @cfg {Boolean} multiSelect Allow multiple selection
9240 multiSelect : false,
9242 * @cfg {Boolean} singleSelect Allow single selection
9244 singleSelect: false,
9247 * Returns the element this view is bound to.
9248 * @return {Roo.Element}
9255 * Refreshes the view.
9257 refresh : function(){
9259 this.clearSelections();
9262 var records = this.store.getRange();
9263 if(records.length < 1){
9264 this.el.update(this.emptyText);
9267 for(var i = 0, len = records.length; i < len; i++){
9268 var data = this.prepareData(records[i].data, i, records[i]);
9269 html[html.length] = t.apply(data);
9271 this.el.update(html.join(""));
9272 this.nodes = this.el.dom.childNodes;
9273 this.updateIndexes(0);
9277 * Function to override to reformat the data that is sent to
9278 * the template for each node.
9279 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9280 * a JSON object for an UpdateManager bound view).
9282 prepareData : function(data){
9286 onUpdate : function(ds, record){
9287 this.clearSelections();
9288 var index = this.store.indexOf(record);
9289 var n = this.nodes[index];
9290 this.tpl.insertBefore(n, this.prepareData(record.data));
9291 n.parentNode.removeChild(n);
9292 this.updateIndexes(index, index);
9295 onAdd : function(ds, records, index){
9296 this.clearSelections();
9297 if(this.nodes.length == 0){
9301 var n = this.nodes[index];
9302 for(var i = 0, len = records.length; i < len; i++){
9303 var d = this.prepareData(records[i].data);
9305 this.tpl.insertBefore(n, d);
9307 this.tpl.append(this.el, d);
9310 this.updateIndexes(index);
9313 onRemove : function(ds, record, index){
9314 this.clearSelections();
9315 this.el.dom.removeChild(this.nodes[index]);
9316 this.updateIndexes(index);
9320 * Refresh an individual node.
9321 * @param {Number} index
9323 refreshNode : function(index){
9324 this.onUpdate(this.store, this.store.getAt(index));
9327 updateIndexes : function(startIndex, endIndex){
9328 var ns = this.nodes;
9329 startIndex = startIndex || 0;
9330 endIndex = endIndex || ns.length - 1;
9331 for(var i = startIndex; i <= endIndex; i++){
9332 ns[i].nodeIndex = i;
9337 * Changes the data store this view uses and refresh the view.
9338 * @param {Store} store
9340 setStore : function(store, initial){
9341 if(!initial && this.store){
9342 this.store.un("datachanged", this.refresh);
9343 this.store.un("add", this.onAdd);
9344 this.store.un("remove", this.onRemove);
9345 this.store.un("update", this.onUpdate);
9346 this.store.un("clear", this.refresh);
9350 store.on("datachanged", this.refresh, this);
9351 store.on("add", this.onAdd, this);
9352 store.on("remove", this.onRemove, this);
9353 store.on("update", this.onUpdate, this);
9354 store.on("clear", this.refresh, this);
9363 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9364 * @param {HTMLElement} node
9365 * @return {HTMLElement} The template node
9367 findItemFromChild : function(node){
9368 var el = this.el.dom;
9369 if(!node || node.parentNode == el){
9372 var p = node.parentNode;
9373 while(p && p != el){
9374 if(p.parentNode == el){
9383 onClick : function(e){
9384 var item = this.findItemFromChild(e.getTarget());
9386 var index = this.indexOf(item);
9387 if(this.onItemClick(item, index, e) !== false){
9388 this.fireEvent("click", this, index, item, e);
9391 this.clearSelections();
9396 onContextMenu : function(e){
9397 var item = this.findItemFromChild(e.getTarget());
9399 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9404 onDblClick : function(e){
9405 var item = this.findItemFromChild(e.getTarget());
9407 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9411 onItemClick : function(item, index, e){
9412 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9415 if(this.multiSelect || this.singleSelect){
9416 if(this.multiSelect && e.shiftKey && this.lastSelection){
9417 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9419 this.select(item, this.multiSelect && e.ctrlKey);
9420 this.lastSelection = item;
9428 * Get the number of selected nodes.
9431 getSelectionCount : function(){
9432 return this.selections.length;
9436 * Get the currently selected nodes.
9437 * @return {Array} An array of HTMLElements
9439 getSelectedNodes : function(){
9440 return this.selections;
9444 * Get the indexes of the selected nodes.
9447 getSelectedIndexes : function(){
9448 var indexes = [], s = this.selections;
9449 for(var i = 0, len = s.length; i < len; i++){
9450 indexes.push(s[i].nodeIndex);
9456 * Clear all selections
9457 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9459 clearSelections : function(suppressEvent){
9460 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9461 this.cmp.elements = this.selections;
9462 this.cmp.removeClass(this.selectedClass);
9463 this.selections = [];
9465 this.fireEvent("selectionchange", this, this.selections);
9471 * Returns true if the passed node is selected
9472 * @param {HTMLElement/Number} node The node or node index
9475 isSelected : function(node){
9476 var s = this.selections;
9480 node = this.getNode(node);
9481 return s.indexOf(node) !== -1;
9486 * @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
9487 * @param {Boolean} keepExisting (optional) true to keep existing selections
9488 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9490 select : function(nodeInfo, keepExisting, suppressEvent){
9491 if(nodeInfo instanceof Array){
9493 this.clearSelections(true);
9495 for(var i = 0, len = nodeInfo.length; i < len; i++){
9496 this.select(nodeInfo[i], true, true);
9499 var node = this.getNode(nodeInfo);
9500 if(node && !this.isSelected(node)){
9502 this.clearSelections(true);
9504 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9505 Roo.fly(node).addClass(this.selectedClass);
9506 this.selections.push(node);
9508 this.fireEvent("selectionchange", this, this.selections);
9516 * Gets a template node.
9517 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9518 * @return {HTMLElement} The node or null if it wasn't found
9520 getNode : function(nodeInfo){
9521 if(typeof nodeInfo == "string"){
9522 return document.getElementById(nodeInfo);
9523 }else if(typeof nodeInfo == "number"){
9524 return this.nodes[nodeInfo];
9530 * Gets a range template nodes.
9531 * @param {Number} startIndex
9532 * @param {Number} endIndex
9533 * @return {Array} An array of nodes
9535 getNodes : function(start, end){
9536 var ns = this.nodes;
9538 end = typeof end == "undefined" ? ns.length - 1 : end;
9541 for(var i = start; i <= end; i++){
9545 for(var i = start; i >= end; i--){
9553 * Finds the index of the passed node
9554 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9555 * @return {Number} The index of the node or -1
9557 indexOf : function(node){
9558 node = this.getNode(node);
9559 if(typeof node.nodeIndex == "number"){
9560 return node.nodeIndex;
9562 var ns = this.nodes;
9563 for(var i = 0, len = ns.length; i < len; i++){
9573 * Ext JS Library 1.1.1
9574 * Copyright(c) 2006-2007, Ext JS, LLC.
9576 * Originally Released Under LGPL - original licence link has changed is not relivant.
9579 * <script type="text/javascript">
9583 * @class Roo.JsonView
9585 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9587 var view = new Roo.JsonView({
9588 container: "my-element",
9589 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9594 // listen for node click?
9595 view.on("click", function(vw, index, node, e){
9596 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9599 // direct load of JSON data
9600 view.load("foobar.php");
9602 // Example from my blog list
9603 var tpl = new Roo.Template(
9604 '<div class="entry">' +
9605 '<a class="entry-title" href="{link}">{title}</a>' +
9606 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9607 "</div><hr />"
9610 var moreView = new Roo.JsonView({
9611 container : "entry-list",
9615 moreView.on("beforerender", this.sortEntries, this);
9617 url: "/blog/get-posts.php",
9618 params: "allposts=true",
9619 text: "Loading Blog Entries..."
9623 * Note: old code is supported with arguments : (container, template, config)
9627 * Create a new JsonView
9629 * @param {Object} config The config object
9632 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9635 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9637 var um = this.el.getUpdateManager();
9638 um.setRenderer(this);
9639 um.on("update", this.onLoad, this);
9640 um.on("failure", this.onLoadException, this);
9643 * @event beforerender
9644 * Fires before rendering of the downloaded JSON data.
9645 * @param {Roo.JsonView} this
9646 * @param {Object} data The JSON data loaded
9650 * Fires when data is loaded.
9651 * @param {Roo.JsonView} this
9652 * @param {Object} data The JSON data loaded
9653 * @param {Object} response The raw Connect response object
9656 * @event loadexception
9657 * Fires when loading fails.
9658 * @param {Roo.JsonView} this
9659 * @param {Object} response The raw Connect response object
9662 'beforerender' : true,
9664 'loadexception' : true
9667 Roo.extend(Roo.JsonView, Roo.View, {
9669 * @type {String} The root property in the loaded JSON object that contains the data
9674 * Refreshes the view.
9676 refresh : function(){
9677 this.clearSelections();
9680 var o = this.jsonData;
9681 if(o && o.length > 0){
9682 for(var i = 0, len = o.length; i < len; i++){
9683 var data = this.prepareData(o[i], i, o);
9684 html[html.length] = this.tpl.apply(data);
9687 html.push(this.emptyText);
9689 this.el.update(html.join(""));
9690 this.nodes = this.el.dom.childNodes;
9691 this.updateIndexes(0);
9695 * 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.
9696 * @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:
9699 url: "your-url.php",
9700 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9701 callback: yourFunction,
9702 scope: yourObject, //(optional scope)
9710 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9711 * 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.
9712 * @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}
9713 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9714 * @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.
9717 var um = this.el.getUpdateManager();
9718 um.update.apply(um, arguments);
9721 render : function(el, response){
9722 this.clearSelections();
9726 o = Roo.util.JSON.decode(response.responseText);
9729 o = o[this.jsonRoot];
9734 * The current JSON data or null
9737 this.beforeRender();
9742 * Get the number of records in the current JSON dataset
9745 getCount : function(){
9746 return this.jsonData ? this.jsonData.length : 0;
9750 * Returns the JSON object for the specified node(s)
9751 * @param {HTMLElement/Array} node The node or an array of nodes
9752 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9753 * you get the JSON object for the node
9755 getNodeData : function(node){
9756 if(node instanceof Array){
9758 for(var i = 0, len = node.length; i < len; i++){
9759 data.push(this.getNodeData(node[i]));
9763 return this.jsonData[this.indexOf(node)] || null;
9766 beforeRender : function(){
9767 this.snapshot = this.jsonData;
9769 this.sort.apply(this, this.sortInfo);
9771 this.fireEvent("beforerender", this, this.jsonData);
9774 onLoad : function(el, o){
9775 this.fireEvent("load", this, this.jsonData, o);
9778 onLoadException : function(el, o){
9779 this.fireEvent("loadexception", this, o);
9783 * Filter the data by a specific property.
9784 * @param {String} property A property on your JSON objects
9785 * @param {String/RegExp} value Either string that the property values
9786 * should start with, or a RegExp to test against the property
9788 filter : function(property, value){
9791 var ss = this.snapshot;
9792 if(typeof value == "string"){
9793 var vlen = value.length;
9798 value = value.toLowerCase();
9799 for(var i = 0, len = ss.length; i < len; i++){
9801 if(o[property].substr(0, vlen).toLowerCase() == value){
9805 } else if(value.exec){ // regex?
9806 for(var i = 0, len = ss.length; i < len; i++){
9808 if(value.test(o[property])){
9815 this.jsonData = data;
9821 * Filter by a function. The passed function will be called with each
9822 * object in the current dataset. If the function returns true the value is kept,
9823 * otherwise it is filtered.
9824 * @param {Function} fn
9825 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9827 filterBy : function(fn, scope){
9830 var ss = this.snapshot;
9831 for(var i = 0, len = ss.length; i < len; i++){
9833 if(fn.call(scope || this, o)){
9837 this.jsonData = data;
9843 * Clears the current filter.
9845 clearFilter : function(){
9846 if(this.snapshot && this.jsonData != this.snapshot){
9847 this.jsonData = this.snapshot;
9854 * Sorts the data for this view and refreshes it.
9855 * @param {String} property A property on your JSON objects to sort on
9856 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9857 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9859 sort : function(property, dir, sortType){
9860 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9863 var dsc = dir && dir.toLowerCase() == "desc";
9864 var f = function(o1, o2){
9865 var v1 = sortType ? sortType(o1[p]) : o1[p];
9866 var v2 = sortType ? sortType(o2[p]) : o2[p];
9869 return dsc ? +1 : -1;
9871 return dsc ? -1 : +1;
9876 this.jsonData.sort(f);
9878 if(this.jsonData != this.snapshot){
9879 this.snapshot.sort(f);
9885 * Ext JS Library 1.1.1
9886 * Copyright(c) 2006-2007, Ext JS, LLC.
9888 * Originally Released Under LGPL - original licence link has changed is not relivant.
9891 * <script type="text/javascript">
9896 * @class Roo.ColorPalette
9897 * @extends Roo.Component
9898 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9899 * Here's an example of typical usage:
9901 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9902 cp.render('my-div');
9904 cp.on('select', function(palette, selColor){
9905 // do something with selColor
9909 * Create a new ColorPalette
9910 * @param {Object} config The config object
9912 Roo.ColorPalette = function(config){
9913 Roo.ColorPalette.superclass.constructor.call(this, config);
9917 * Fires when a color is selected
9918 * @param {ColorPalette} this
9919 * @param {String} color The 6-digit color hex code (without the # symbol)
9925 this.on("select", this.handler, this.scope, true);
9928 Roo.extend(Roo.ColorPalette, Roo.Component, {
9930 * @cfg {String} itemCls
9931 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9933 itemCls : "x-color-palette",
9935 * @cfg {String} value
9936 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9937 * the hex codes are case-sensitive.
9942 ctype: "Roo.ColorPalette",
9945 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9947 allowReselect : false,
9950 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9951 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9952 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9953 * of colors with the width setting until the box is symmetrical.</p>
9954 * <p>You can override individual colors if needed:</p>
9956 var cp = new Roo.ColorPalette();
9957 cp.colors[0] = "FF0000"; // change the first box to red
9960 Or you can provide a custom array of your own for complete control:
9962 var cp = new Roo.ColorPalette();
9963 cp.colors = ["000000", "993300", "333300"];
9968 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9969 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9970 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9971 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9972 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9976 onRender : function(container, position){
9977 var t = new Roo.MasterTemplate(
9978 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9980 var c = this.colors;
9981 for(var i = 0, len = c.length; i < len; i++){
9984 var el = document.createElement("div");
9985 el.className = this.itemCls;
9987 container.dom.insertBefore(el, position);
9988 this.el = Roo.get(el);
9989 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9990 if(this.clickEvent != 'click'){
9991 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9996 afterRender : function(){
9997 Roo.ColorPalette.superclass.afterRender.call(this);
10006 handleClick : function(e, t){
10007 e.preventDefault();
10008 if(!this.disabled){
10009 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10010 this.select(c.toUpperCase());
10015 * Selects the specified color in the palette (fires the select event)
10016 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10018 select : function(color){
10019 color = color.replace("#", "");
10020 if(color != this.value || this.allowReselect){
10023 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10025 el.child("a.color-"+color).addClass("x-color-palette-sel");
10026 this.value = color;
10027 this.fireEvent("select", this, color);
10032 * Ext JS Library 1.1.1
10033 * Copyright(c) 2006-2007, Ext JS, LLC.
10035 * Originally Released Under LGPL - original licence link has changed is not relivant.
10038 * <script type="text/javascript">
10042 * @class Roo.DatePicker
10043 * @extends Roo.Component
10044 * Simple date picker class.
10046 * Create a new DatePicker
10047 * @param {Object} config The config object
10049 Roo.DatePicker = function(config){
10050 Roo.DatePicker.superclass.constructor.call(this, config);
10052 this.value = config && config.value ?
10053 config.value.clearTime() : new Date().clearTime();
10058 * Fires when a date is selected
10059 * @param {DatePicker} this
10060 * @param {Date} date The selected date
10066 this.on("select", this.handler, this.scope || this);
10068 // build the disabledDatesRE
10069 if(!this.disabledDatesRE && this.disabledDates){
10070 var dd = this.disabledDates;
10072 for(var i = 0; i < dd.length; i++){
10074 if(i != dd.length-1) re += "|";
10076 this.disabledDatesRE = new RegExp(re + ")");
10080 Roo.extend(Roo.DatePicker, Roo.Component, {
10082 * @cfg {String} todayText
10083 * The text to display on the button that selects the current date (defaults to "Today")
10085 todayText : "Today",
10087 * @cfg {String} okText
10088 * The text to display on the ok button
10090 okText : " OK ", //   to give the user extra clicking room
10092 * @cfg {String} cancelText
10093 * The text to display on the cancel button
10095 cancelText : "Cancel",
10097 * @cfg {String} todayTip
10098 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10100 todayTip : "{0} (Spacebar)",
10102 * @cfg {Date} minDate
10103 * Minimum allowable date (JavaScript date object, defaults to null)
10107 * @cfg {Date} maxDate
10108 * Maximum allowable date (JavaScript date object, defaults to null)
10112 * @cfg {String} minText
10113 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10115 minText : "This date is before the minimum date",
10117 * @cfg {String} maxText
10118 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10120 maxText : "This date is after the maximum date",
10122 * @cfg {String} format
10123 * The default date format string which can be overriden for localization support. The format must be
10124 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10128 * @cfg {Array} disabledDays
10129 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10131 disabledDays : null,
10133 * @cfg {String} disabledDaysText
10134 * The tooltip to display when the date falls on a disabled day (defaults to "")
10136 disabledDaysText : "",
10138 * @cfg {RegExp} disabledDatesRE
10139 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10141 disabledDatesRE : null,
10143 * @cfg {String} disabledDatesText
10144 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10146 disabledDatesText : "",
10148 * @cfg {Boolean} constrainToViewport
10149 * True to constrain the date picker to the viewport (defaults to true)
10151 constrainToViewport : true,
10153 * @cfg {Array} monthNames
10154 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10156 monthNames : Date.monthNames,
10158 * @cfg {Array} dayNames
10159 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10161 dayNames : Date.dayNames,
10163 * @cfg {String} nextText
10164 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10166 nextText: 'Next Month (Control+Right)',
10168 * @cfg {String} prevText
10169 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10171 prevText: 'Previous Month (Control+Left)',
10173 * @cfg {String} monthYearText
10174 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10176 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10178 * @cfg {Number} startDay
10179 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10183 * @cfg {Bool} showClear
10184 * Show a clear button (usefull for date form elements that can be blank.)
10190 * Sets the value of the date field
10191 * @param {Date} value The date to set
10193 setValue : function(value){
10194 var old = this.value;
10195 this.value = value.clearTime(true);
10197 this.update(this.value);
10202 * Gets the current selected value of the date field
10203 * @return {Date} The selected date
10205 getValue : function(){
10210 focus : function(){
10212 this.update(this.activeDate);
10217 onRender : function(container, position){
10219 '<table cellspacing="0">',
10220 '<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>',
10221 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10222 var dn = this.dayNames;
10223 for(var i = 0; i < 7; i++){
10224 var d = this.startDay+i;
10228 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10230 m[m.length] = "</tr></thead><tbody><tr>";
10231 for(var i = 0; i < 42; i++) {
10232 if(i % 7 == 0 && i != 0){
10233 m[m.length] = "</tr><tr>";
10235 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10237 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10238 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10240 var el = document.createElement("div");
10241 el.className = "x-date-picker";
10242 el.innerHTML = m.join("");
10244 container.dom.insertBefore(el, position);
10246 this.el = Roo.get(el);
10247 this.eventEl = Roo.get(el.firstChild);
10249 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10250 handler: this.showPrevMonth,
10252 preventDefault:true,
10256 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10257 handler: this.showNextMonth,
10259 preventDefault:true,
10263 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10265 this.monthPicker = this.el.down('div.x-date-mp');
10266 this.monthPicker.enableDisplayMode('block');
10268 var kn = new Roo.KeyNav(this.eventEl, {
10269 "left" : function(e){
10271 this.showPrevMonth() :
10272 this.update(this.activeDate.add("d", -1));
10275 "right" : function(e){
10277 this.showNextMonth() :
10278 this.update(this.activeDate.add("d", 1));
10281 "up" : function(e){
10283 this.showNextYear() :
10284 this.update(this.activeDate.add("d", -7));
10287 "down" : function(e){
10289 this.showPrevYear() :
10290 this.update(this.activeDate.add("d", 7));
10293 "pageUp" : function(e){
10294 this.showNextMonth();
10297 "pageDown" : function(e){
10298 this.showPrevMonth();
10301 "enter" : function(e){
10302 e.stopPropagation();
10309 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10311 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10313 this.el.unselectable();
10315 this.cells = this.el.select("table.x-date-inner tbody td");
10316 this.textNodes = this.el.query("table.x-date-inner tbody span");
10318 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10320 tooltip: this.monthYearText
10323 this.mbtn.on('click', this.showMonthPicker, this);
10324 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10327 var today = (new Date()).dateFormat(this.format);
10329 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10330 if (this.showClear) {
10331 baseTb.add( new Roo.Toolbar.Fill());
10334 text: String.format(this.todayText, today),
10335 tooltip: String.format(this.todayTip, today),
10336 handler: this.selectToday,
10340 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10343 if (this.showClear) {
10345 baseTb.add( new Roo.Toolbar.Fill());
10348 cls: 'x-btn-icon x-btn-clear',
10349 handler: function() {
10351 this.fireEvent("select", this, '');
10361 this.update(this.value);
10364 createMonthPicker : function(){
10365 if(!this.monthPicker.dom.firstChild){
10366 var buf = ['<table border="0" cellspacing="0">'];
10367 for(var i = 0; i < 6; i++){
10369 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10370 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10372 '<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>' :
10373 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10377 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10379 '</button><button type="button" class="x-date-mp-cancel">',
10381 '</button></td></tr>',
10384 this.monthPicker.update(buf.join(''));
10385 this.monthPicker.on('click', this.onMonthClick, this);
10386 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10388 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10389 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10391 this.mpMonths.each(function(m, a, i){
10394 m.dom.xmonth = 5 + Math.round(i * .5);
10396 m.dom.xmonth = Math.round((i-1) * .5);
10402 showMonthPicker : function(){
10403 this.createMonthPicker();
10404 var size = this.el.getSize();
10405 this.monthPicker.setSize(size);
10406 this.monthPicker.child('table').setSize(size);
10408 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10409 this.updateMPMonth(this.mpSelMonth);
10410 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10411 this.updateMPYear(this.mpSelYear);
10413 this.monthPicker.slideIn('t', {duration:.2});
10416 updateMPYear : function(y){
10418 var ys = this.mpYears.elements;
10419 for(var i = 1; i <= 10; i++){
10420 var td = ys[i-1], y2;
10422 y2 = y + Math.round(i * .5);
10423 td.firstChild.innerHTML = y2;
10426 y2 = y - (5-Math.round(i * .5));
10427 td.firstChild.innerHTML = y2;
10430 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10434 updateMPMonth : function(sm){
10435 this.mpMonths.each(function(m, a, i){
10436 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10440 selectMPMonth: function(m){
10444 onMonthClick : function(e, t){
10446 var el = new Roo.Element(t), pn;
10447 if(el.is('button.x-date-mp-cancel')){
10448 this.hideMonthPicker();
10450 else if(el.is('button.x-date-mp-ok')){
10451 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10452 this.hideMonthPicker();
10454 else if(pn = el.up('td.x-date-mp-month', 2)){
10455 this.mpMonths.removeClass('x-date-mp-sel');
10456 pn.addClass('x-date-mp-sel');
10457 this.mpSelMonth = pn.dom.xmonth;
10459 else if(pn = el.up('td.x-date-mp-year', 2)){
10460 this.mpYears.removeClass('x-date-mp-sel');
10461 pn.addClass('x-date-mp-sel');
10462 this.mpSelYear = pn.dom.xyear;
10464 else if(el.is('a.x-date-mp-prev')){
10465 this.updateMPYear(this.mpyear-10);
10467 else if(el.is('a.x-date-mp-next')){
10468 this.updateMPYear(this.mpyear+10);
10472 onMonthDblClick : function(e, t){
10474 var el = new Roo.Element(t), pn;
10475 if(pn = el.up('td.x-date-mp-month', 2)){
10476 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10477 this.hideMonthPicker();
10479 else if(pn = el.up('td.x-date-mp-year', 2)){
10480 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10481 this.hideMonthPicker();
10485 hideMonthPicker : function(disableAnim){
10486 if(this.monthPicker){
10487 if(disableAnim === true){
10488 this.monthPicker.hide();
10490 this.monthPicker.slideOut('t', {duration:.2});
10496 showPrevMonth : function(e){
10497 this.update(this.activeDate.add("mo", -1));
10501 showNextMonth : function(e){
10502 this.update(this.activeDate.add("mo", 1));
10506 showPrevYear : function(){
10507 this.update(this.activeDate.add("y", -1));
10511 showNextYear : function(){
10512 this.update(this.activeDate.add("y", 1));
10516 handleMouseWheel : function(e){
10517 var delta = e.getWheelDelta();
10519 this.showPrevMonth();
10521 } else if(delta < 0){
10522 this.showNextMonth();
10528 handleDateClick : function(e, t){
10530 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10531 this.setValue(new Date(t.dateValue));
10532 this.fireEvent("select", this, this.value);
10537 selectToday : function(){
10538 this.setValue(new Date().clearTime());
10539 this.fireEvent("select", this, this.value);
10543 update : function(date){
10544 var vd = this.activeDate;
10545 this.activeDate = date;
10547 var t = date.getTime();
10548 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10549 this.cells.removeClass("x-date-selected");
10550 this.cells.each(function(c){
10551 if(c.dom.firstChild.dateValue == t){
10552 c.addClass("x-date-selected");
10553 setTimeout(function(){
10554 try{c.dom.firstChild.focus();}catch(e){}
10562 var days = date.getDaysInMonth();
10563 var firstOfMonth = date.getFirstDateOfMonth();
10564 var startingPos = firstOfMonth.getDay()-this.startDay;
10566 if(startingPos <= this.startDay){
10570 var pm = date.add("mo", -1);
10571 var prevStart = pm.getDaysInMonth()-startingPos;
10573 var cells = this.cells.elements;
10574 var textEls = this.textNodes;
10575 days += startingPos;
10577 // convert everything to numbers so it's fast
10578 var day = 86400000;
10579 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10580 var today = new Date().clearTime().getTime();
10581 var sel = date.clearTime().getTime();
10582 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10583 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10584 var ddMatch = this.disabledDatesRE;
10585 var ddText = this.disabledDatesText;
10586 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10587 var ddaysText = this.disabledDaysText;
10588 var format = this.format;
10590 var setCellClass = function(cal, cell){
10592 var t = d.getTime();
10593 cell.firstChild.dateValue = t;
10595 cell.className += " x-date-today";
10596 cell.title = cal.todayText;
10599 cell.className += " x-date-selected";
10600 setTimeout(function(){
10601 try{cell.firstChild.focus();}catch(e){}
10606 cell.className = " x-date-disabled";
10607 cell.title = cal.minText;
10611 cell.className = " x-date-disabled";
10612 cell.title = cal.maxText;
10616 if(ddays.indexOf(d.getDay()) != -1){
10617 cell.title = ddaysText;
10618 cell.className = " x-date-disabled";
10621 if(ddMatch && format){
10622 var fvalue = d.dateFormat(format);
10623 if(ddMatch.test(fvalue)){
10624 cell.title = ddText.replace("%0", fvalue);
10625 cell.className = " x-date-disabled";
10631 for(; i < startingPos; i++) {
10632 textEls[i].innerHTML = (++prevStart);
10633 d.setDate(d.getDate()+1);
10634 cells[i].className = "x-date-prevday";
10635 setCellClass(this, cells[i]);
10637 for(; i < days; i++){
10638 intDay = i - startingPos + 1;
10639 textEls[i].innerHTML = (intDay);
10640 d.setDate(d.getDate()+1);
10641 cells[i].className = "x-date-active";
10642 setCellClass(this, cells[i]);
10645 for(; i < 42; i++) {
10646 textEls[i].innerHTML = (++extraDays);
10647 d.setDate(d.getDate()+1);
10648 cells[i].className = "x-date-nextday";
10649 setCellClass(this, cells[i]);
10652 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10654 if(!this.internalRender){
10655 var main = this.el.dom.firstChild;
10656 var w = main.offsetWidth;
10657 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10658 Roo.fly(main).setWidth(w);
10659 this.internalRender = true;
10660 // opera does not respect the auto grow header center column
10661 // then, after it gets a width opera refuses to recalculate
10662 // without a second pass
10663 if(Roo.isOpera && !this.secondPass){
10664 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10665 this.secondPass = true;
10666 this.update.defer(10, this, [date]);
10672 * Ext JS Library 1.1.1
10673 * Copyright(c) 2006-2007, Ext JS, LLC.
10675 * Originally Released Under LGPL - original licence link has changed is not relivant.
10678 * <script type="text/javascript">
10681 * @class Roo.TabPanel
10682 * @extends Roo.util.Observable
10683 * A lightweight tab container.
10687 // basic tabs 1, built from existing content
10688 var tabs = new Roo.TabPanel("tabs1");
10689 tabs.addTab("script", "View Script");
10690 tabs.addTab("markup", "View Markup");
10691 tabs.activate("script");
10693 // more advanced tabs, built from javascript
10694 var jtabs = new Roo.TabPanel("jtabs");
10695 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10697 // set up the UpdateManager
10698 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10699 var updater = tab2.getUpdateManager();
10700 updater.setDefaultUrl("ajax1.htm");
10701 tab2.on('activate', updater.refresh, updater, true);
10703 // Use setUrl for Ajax loading
10704 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10705 tab3.setUrl("ajax2.htm", null, true);
10708 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10711 jtabs.activate("jtabs-1");
10714 * Create a new TabPanel.
10715 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10716 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10718 Roo.TabPanel = function(container, config){
10720 * The container element for this TabPanel.
10721 * @type Roo.Element
10723 this.el = Roo.get(container, true);
10725 if(typeof config == "boolean"){
10726 this.tabPosition = config ? "bottom" : "top";
10728 Roo.apply(this, config);
10731 if(this.tabPosition == "bottom"){
10732 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10733 this.el.addClass("x-tabs-bottom");
10735 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10736 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10737 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10739 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10741 if(this.tabPosition != "bottom"){
10742 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10743 * @type Roo.Element
10745 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10746 this.el.addClass("x-tabs-top");
10750 this.bodyEl.setStyle("position", "relative");
10752 this.active = null;
10753 this.activateDelegate = this.activate.createDelegate(this);
10758 * Fires when the active tab changes
10759 * @param {Roo.TabPanel} this
10760 * @param {Roo.TabPanelItem} activePanel The new active tab
10764 * @event beforetabchange
10765 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10766 * @param {Roo.TabPanel} this
10767 * @param {Object} e Set cancel to true on this object to cancel the tab change
10768 * @param {Roo.TabPanelItem} tab The tab being changed to
10770 "beforetabchange" : true
10773 Roo.EventManager.onWindowResize(this.onResize, this);
10774 this.cpad = this.el.getPadding("lr");
10775 this.hiddenCount = 0;
10777 Roo.TabPanel.superclass.constructor.call(this);
10780 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10782 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10784 tabPosition : "top",
10786 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10788 currentTabWidth : 0,
10790 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10794 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10798 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10800 preferredTabWidth : 175,
10802 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10804 resizeTabs : false,
10806 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10808 monitorResize : true,
10811 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10812 * @param {String} id The id of the div to use <b>or create</b>
10813 * @param {String} text The text for the tab
10814 * @param {String} content (optional) Content to put in the TabPanelItem body
10815 * @param {Boolean} closable (optional) True to create a close icon on the tab
10816 * @return {Roo.TabPanelItem} The created TabPanelItem
10818 addTab : function(id, text, content, closable){
10819 var item = new Roo.TabPanelItem(this, id, text, closable);
10820 this.addTabItem(item);
10822 item.setContent(content);
10828 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10829 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10830 * @return {Roo.TabPanelItem}
10832 getTab : function(id){
10833 return this.items[id];
10837 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10838 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10840 hideTab : function(id){
10841 var t = this.items[id];
10844 this.hiddenCount++;
10845 this.autoSizeTabs();
10850 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10851 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10853 unhideTab : function(id){
10854 var t = this.items[id];
10856 t.setHidden(false);
10857 this.hiddenCount--;
10858 this.autoSizeTabs();
10863 * Adds an existing {@link Roo.TabPanelItem}.
10864 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10866 addTabItem : function(item){
10867 this.items[item.id] = item;
10868 this.items.push(item);
10869 if(this.resizeTabs){
10870 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10871 this.autoSizeTabs();
10878 * Removes a {@link Roo.TabPanelItem}.
10879 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10881 removeTab : function(id){
10882 var items = this.items;
10883 var tab = items[id];
10884 if(!tab) { return; }
10885 var index = items.indexOf(tab);
10886 if(this.active == tab && items.length > 1){
10887 var newTab = this.getNextAvailable(index);
10892 this.stripEl.dom.removeChild(tab.pnode.dom);
10893 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10894 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10896 items.splice(index, 1);
10897 delete this.items[tab.id];
10898 tab.fireEvent("close", tab);
10899 tab.purgeListeners();
10900 this.autoSizeTabs();
10903 getNextAvailable : function(start){
10904 var items = this.items;
10906 // look for a next tab that will slide over to
10907 // replace the one being removed
10908 while(index < items.length){
10909 var item = items[++index];
10910 if(item && !item.isHidden()){
10914 // if one isn't found select the previous tab (on the left)
10917 var item = items[--index];
10918 if(item && !item.isHidden()){
10926 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10927 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10929 disableTab : function(id){
10930 var tab = this.items[id];
10931 if(tab && this.active != tab){
10937 * Enables a {@link Roo.TabPanelItem} that is disabled.
10938 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10940 enableTab : function(id){
10941 var tab = this.items[id];
10946 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10947 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10948 * @return {Roo.TabPanelItem} The TabPanelItem.
10950 activate : function(id){
10951 var tab = this.items[id];
10955 if(tab == this.active || tab.disabled){
10959 this.fireEvent("beforetabchange", this, e, tab);
10960 if(e.cancel !== true && !tab.disabled){
10962 this.active.hide();
10964 this.active = this.items[id];
10965 this.active.show();
10966 this.fireEvent("tabchange", this, this.active);
10972 * Gets the active {@link Roo.TabPanelItem}.
10973 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10975 getActiveTab : function(){
10976 return this.active;
10980 * Updates the tab body element to fit the height of the container element
10981 * for overflow scrolling
10982 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10984 syncHeight : function(targetHeight){
10985 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10986 var bm = this.bodyEl.getMargins();
10987 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10988 this.bodyEl.setHeight(newHeight);
10992 onResize : function(){
10993 if(this.monitorResize){
10994 this.autoSizeTabs();
10999 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11001 beginUpdate : function(){
11002 this.updating = true;
11006 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11008 endUpdate : function(){
11009 this.updating = false;
11010 this.autoSizeTabs();
11014 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11016 autoSizeTabs : function(){
11017 var count = this.items.length;
11018 var vcount = count - this.hiddenCount;
11019 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11020 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11021 var availWidth = Math.floor(w / vcount);
11022 var b = this.stripBody;
11023 if(b.getWidth() > w){
11024 var tabs = this.items;
11025 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11026 if(availWidth < this.minTabWidth){
11027 /*if(!this.sleft){ // incomplete scrolling code
11028 this.createScrollButtons();
11031 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11034 if(this.currentTabWidth < this.preferredTabWidth){
11035 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11041 * Returns the number of tabs in this TabPanel.
11044 getCount : function(){
11045 return this.items.length;
11049 * Resizes all the tabs to the passed width
11050 * @param {Number} The new width
11052 setTabWidth : function(width){
11053 this.currentTabWidth = width;
11054 for(var i = 0, len = this.items.length; i < len; i++) {
11055 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11060 * Destroys this TabPanel
11061 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11063 destroy : function(removeEl){
11064 Roo.EventManager.removeResizeListener(this.onResize, this);
11065 for(var i = 0, len = this.items.length; i < len; i++){
11066 this.items[i].purgeListeners();
11068 if(removeEl === true){
11069 this.el.update("");
11076 * @class Roo.TabPanelItem
11077 * @extends Roo.util.Observable
11078 * Represents an individual item (tab plus body) in a TabPanel.
11079 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11080 * @param {String} id The id of this TabPanelItem
11081 * @param {String} text The text for the tab of this TabPanelItem
11082 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11084 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11086 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11087 * @type Roo.TabPanel
11089 this.tabPanel = tabPanel;
11091 * The id for this TabPanelItem
11096 this.disabled = false;
11100 this.loaded = false;
11101 this.closable = closable;
11104 * The body element for this TabPanelItem.
11105 * @type Roo.Element
11107 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11108 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11109 this.bodyEl.setStyle("display", "block");
11110 this.bodyEl.setStyle("zoom", "1");
11113 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11115 this.el = Roo.get(els.el, true);
11116 this.inner = Roo.get(els.inner, true);
11117 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11118 this.pnode = Roo.get(els.el.parentNode, true);
11119 this.el.on("mousedown", this.onTabMouseDown, this);
11120 this.el.on("click", this.onTabClick, this);
11123 var c = Roo.get(els.close, true);
11124 c.dom.title = this.closeText;
11125 c.addClassOnOver("close-over");
11126 c.on("click", this.closeClick, this);
11132 * Fires when this tab becomes the active tab.
11133 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11134 * @param {Roo.TabPanelItem} this
11138 * @event beforeclose
11139 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11140 * @param {Roo.TabPanelItem} this
11141 * @param {Object} e Set cancel to true on this object to cancel the close.
11143 "beforeclose": true,
11146 * Fires when this tab is closed.
11147 * @param {Roo.TabPanelItem} this
11151 * @event deactivate
11152 * Fires when this tab is no longer the active tab.
11153 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11154 * @param {Roo.TabPanelItem} this
11156 "deactivate" : true
11158 this.hidden = false;
11160 Roo.TabPanelItem.superclass.constructor.call(this);
11163 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11164 purgeListeners : function(){
11165 Roo.util.Observable.prototype.purgeListeners.call(this);
11166 this.el.removeAllListeners();
11169 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11172 this.pnode.addClass("on");
11175 this.tabPanel.stripWrap.repaint();
11177 this.fireEvent("activate", this.tabPanel, this);
11181 * Returns true if this tab is the active tab.
11182 * @return {Boolean}
11184 isActive : function(){
11185 return this.tabPanel.getActiveTab() == this;
11189 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11192 this.pnode.removeClass("on");
11194 this.fireEvent("deactivate", this.tabPanel, this);
11197 hideAction : function(){
11198 this.bodyEl.hide();
11199 this.bodyEl.setStyle("position", "absolute");
11200 this.bodyEl.setLeft("-20000px");
11201 this.bodyEl.setTop("-20000px");
11204 showAction : function(){
11205 this.bodyEl.setStyle("position", "relative");
11206 this.bodyEl.setTop("");
11207 this.bodyEl.setLeft("");
11208 this.bodyEl.show();
11212 * Set the tooltip for the tab.
11213 * @param {String} tooltip The tab's tooltip
11215 setTooltip : function(text){
11216 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11217 this.textEl.dom.qtip = text;
11218 this.textEl.dom.removeAttribute('title');
11220 this.textEl.dom.title = text;
11224 onTabClick : function(e){
11225 e.preventDefault();
11226 this.tabPanel.activate(this.id);
11229 onTabMouseDown : function(e){
11230 e.preventDefault();
11231 this.tabPanel.activate(this.id);
11234 getWidth : function(){
11235 return this.inner.getWidth();
11238 setWidth : function(width){
11239 var iwidth = width - this.pnode.getPadding("lr");
11240 this.inner.setWidth(iwidth);
11241 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11242 this.pnode.setWidth(width);
11246 * Show or hide the tab
11247 * @param {Boolean} hidden True to hide or false to show.
11249 setHidden : function(hidden){
11250 this.hidden = hidden;
11251 this.pnode.setStyle("display", hidden ? "none" : "");
11255 * Returns true if this tab is "hidden"
11256 * @return {Boolean}
11258 isHidden : function(){
11259 return this.hidden;
11263 * Returns the text for this tab
11266 getText : function(){
11270 autoSize : function(){
11271 //this.el.beginMeasure();
11272 this.textEl.setWidth(1);
11273 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11274 //this.el.endMeasure();
11278 * Sets the text for the tab (Note: this also sets the tooltip text)
11279 * @param {String} text The tab's text and tooltip
11281 setText : function(text){
11283 this.textEl.update(text);
11284 this.setTooltip(text);
11285 if(!this.tabPanel.resizeTabs){
11290 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11292 activate : function(){
11293 this.tabPanel.activate(this.id);
11297 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11299 disable : function(){
11300 if(this.tabPanel.active != this){
11301 this.disabled = true;
11302 this.pnode.addClass("disabled");
11307 * Enables this TabPanelItem if it was previously disabled.
11309 enable : function(){
11310 this.disabled = false;
11311 this.pnode.removeClass("disabled");
11315 * Sets the content for this TabPanelItem.
11316 * @param {String} content The content
11317 * @param {Boolean} loadScripts true to look for and load scripts
11319 setContent : function(content, loadScripts){
11320 this.bodyEl.update(content, loadScripts);
11324 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11325 * @return {Roo.UpdateManager} The UpdateManager
11327 getUpdateManager : function(){
11328 return this.bodyEl.getUpdateManager();
11332 * Set a URL to be used to load the content for this TabPanelItem.
11333 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11334 * @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)
11335 * @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)
11336 * @return {Roo.UpdateManager} The UpdateManager
11338 setUrl : function(url, params, loadOnce){
11339 if(this.refreshDelegate){
11340 this.un('activate', this.refreshDelegate);
11342 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11343 this.on("activate", this.refreshDelegate);
11344 return this.bodyEl.getUpdateManager();
11348 _handleRefresh : function(url, params, loadOnce){
11349 if(!loadOnce || !this.loaded){
11350 var updater = this.bodyEl.getUpdateManager();
11351 updater.update(url, params, this._setLoaded.createDelegate(this));
11356 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11357 * Will fail silently if the setUrl method has not been called.
11358 * This does not activate the panel, just updates its content.
11360 refresh : function(){
11361 if(this.refreshDelegate){
11362 this.loaded = false;
11363 this.refreshDelegate();
11368 _setLoaded : function(){
11369 this.loaded = true;
11373 closeClick : function(e){
11376 this.fireEvent("beforeclose", this, o);
11377 if(o.cancel !== true){
11378 this.tabPanel.removeTab(this.id);
11382 * The text displayed in the tooltip for the close icon.
11385 closeText : "Close this tab"
11389 Roo.TabPanel.prototype.createStrip = function(container){
11390 var strip = document.createElement("div");
11391 strip.className = "x-tabs-wrap";
11392 container.appendChild(strip);
11396 Roo.TabPanel.prototype.createStripList = function(strip){
11397 // div wrapper for retard IE
11398 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11399 return strip.firstChild.firstChild.firstChild.firstChild;
11402 Roo.TabPanel.prototype.createBody = function(container){
11403 var body = document.createElement("div");
11404 Roo.id(body, "tab-body");
11405 Roo.fly(body).addClass("x-tabs-body");
11406 container.appendChild(body);
11410 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11411 var body = Roo.getDom(id);
11413 body = document.createElement("div");
11416 Roo.fly(body).addClass("x-tabs-item-body");
11417 bodyEl.insertBefore(body, bodyEl.firstChild);
11421 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11422 var td = document.createElement("td");
11423 stripEl.appendChild(td);
11425 td.className = "x-tabs-closable";
11426 if(!this.closeTpl){
11427 this.closeTpl = new Roo.Template(
11428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11430 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11433 var el = this.closeTpl.overwrite(td, {"text": text});
11434 var close = el.getElementsByTagName("div")[0];
11435 var inner = el.getElementsByTagName("em")[0];
11436 return {"el": el, "close": close, "inner": inner};
11439 this.tabTpl = new Roo.Template(
11440 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11441 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11444 var el = this.tabTpl.overwrite(td, {"text": text});
11445 var inner = el.getElementsByTagName("em")[0];
11446 return {"el": el, "inner": inner};
11450 * Ext JS Library 1.1.1
11451 * Copyright(c) 2006-2007, Ext JS, LLC.
11453 * Originally Released Under LGPL - original licence link has changed is not relivant.
11456 * <script type="text/javascript">
11460 * @class Roo.Button
11461 * @extends Roo.util.Observable
11462 * Simple Button class
11463 * @cfg {String} text The button text
11464 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11465 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11466 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11467 * @cfg {Object} scope The scope of the handler
11468 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11469 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11470 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11471 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11472 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11473 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11474 applies if enableToggle = true)
11475 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11476 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11477 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11479 * Create a new button
11480 * @param {Object} config The config object
11482 Roo.Button = function(renderTo, config)
11486 renderTo = config.renderTo || false;
11489 Roo.apply(this, config);
11493 * Fires when this button is clicked
11494 * @param {Button} this
11495 * @param {EventObject} e The click event
11500 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11501 * @param {Button} this
11502 * @param {Boolean} pressed
11507 * Fires when the mouse hovers over the button
11508 * @param {Button} this
11509 * @param {Event} e The event object
11511 'mouseover' : true,
11514 * Fires when the mouse exits the button
11515 * @param {Button} this
11516 * @param {Event} e The event object
11521 * Fires when the button is rendered
11522 * @param {Button} this
11527 this.menu = Roo.menu.MenuMgr.get(this.menu);
11529 // register listeners first!! - so render can be captured..
11530 Roo.util.Observable.call(this);
11532 this.render(renderTo);
11538 Roo.extend(Roo.Button, Roo.util.Observable, {
11544 * Read-only. True if this button is hidden
11549 * Read-only. True if this button is disabled
11554 * Read-only. True if this button is pressed (only if enableToggle = true)
11560 * @cfg {Number} tabIndex
11561 * The DOM tabIndex for this button (defaults to undefined)
11563 tabIndex : undefined,
11566 * @cfg {Boolean} enableToggle
11567 * True to enable pressed/not pressed toggling (defaults to false)
11569 enableToggle: false,
11571 * @cfg {Mixed} menu
11572 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11576 * @cfg {String} menuAlign
11577 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11579 menuAlign : "tl-bl?",
11582 * @cfg {String} iconCls
11583 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11585 iconCls : undefined,
11587 * @cfg {String} type
11588 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11593 menuClassTarget: 'tr',
11596 * @cfg {String} clickEvent
11597 * The type of event to map to the button's event handler (defaults to 'click')
11599 clickEvent : 'click',
11602 * @cfg {Boolean} handleMouseEvents
11603 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11605 handleMouseEvents : true,
11608 * @cfg {String} tooltipType
11609 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11611 tooltipType : 'qtip',
11614 * @cfg {String} cls
11615 * A CSS class to apply to the button's main element.
11619 * @cfg {Roo.Template} template (Optional)
11620 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11621 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11622 * require code modifications if required elements (e.g. a button) aren't present.
11626 render : function(renderTo){
11628 if(this.hideParent){
11629 this.parentEl = Roo.get(renderTo);
11631 if(!this.dhconfig){
11632 if(!this.template){
11633 if(!Roo.Button.buttonTemplate){
11634 // hideous table template
11635 Roo.Button.buttonTemplate = new Roo.Template(
11636 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11637 '<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>',
11638 "</tr></tbody></table>");
11640 this.template = Roo.Button.buttonTemplate;
11642 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11643 var btnEl = btn.child("button:first");
11644 btnEl.on('focus', this.onFocus, this);
11645 btnEl.on('blur', this.onBlur, this);
11647 btn.addClass(this.cls);
11650 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11653 btnEl.addClass(this.iconCls);
11655 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11658 if(this.tabIndex !== undefined){
11659 btnEl.dom.tabIndex = this.tabIndex;
11662 if(typeof this.tooltip == 'object'){
11663 Roo.QuickTips.tips(Roo.apply({
11667 btnEl.dom[this.tooltipType] = this.tooltip;
11671 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11675 this.el.dom.id = this.el.id = this.id;
11678 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11679 this.menu.on("show", this.onMenuShow, this);
11680 this.menu.on("hide", this.onMenuHide, this);
11682 btn.addClass("x-btn");
11683 if(Roo.isIE && !Roo.isIE7){
11684 this.autoWidth.defer(1, this);
11688 if(this.handleMouseEvents){
11689 btn.on("mouseover", this.onMouseOver, this);
11690 btn.on("mouseout", this.onMouseOut, this);
11691 btn.on("mousedown", this.onMouseDown, this);
11693 btn.on(this.clickEvent, this.onClick, this);
11694 //btn.on("mouseup", this.onMouseUp, this);
11701 Roo.ButtonToggleMgr.register(this);
11703 this.el.addClass("x-btn-pressed");
11706 var repeater = new Roo.util.ClickRepeater(btn,
11707 typeof this.repeat == "object" ? this.repeat : {}
11709 repeater.on("click", this.onClick, this);
11712 this.fireEvent('render', this);
11716 * Returns the button's underlying element
11717 * @return {Roo.Element} The element
11719 getEl : function(){
11724 * Destroys this Button and removes any listeners.
11726 destroy : function(){
11727 Roo.ButtonToggleMgr.unregister(this);
11728 this.el.removeAllListeners();
11729 this.purgeListeners();
11734 autoWidth : function(){
11736 this.el.setWidth("auto");
11737 if(Roo.isIE7 && Roo.isStrict){
11738 var ib = this.el.child('button');
11739 if(ib && ib.getWidth() > 20){
11741 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11746 this.el.beginMeasure();
11748 if(this.el.getWidth() < this.minWidth){
11749 this.el.setWidth(this.minWidth);
11752 this.el.endMeasure();
11759 * Assigns this button's click handler
11760 * @param {Function} handler The function to call when the button is clicked
11761 * @param {Object} scope (optional) Scope for the function passed in
11763 setHandler : function(handler, scope){
11764 this.handler = handler;
11765 this.scope = scope;
11769 * Sets this button's text
11770 * @param {String} text The button text
11772 setText : function(text){
11775 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11781 * Gets the text for this button
11782 * @return {String} The button text
11784 getText : function(){
11792 this.hidden = false;
11794 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11802 this.hidden = true;
11804 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11809 * Convenience function for boolean show/hide
11810 * @param {Boolean} visible True to show, false to hide
11812 setVisible: function(visible){
11821 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11822 * @param {Boolean} state (optional) Force a particular state
11824 toggle : function(state){
11825 state = state === undefined ? !this.pressed : state;
11826 if(state != this.pressed){
11828 this.el.addClass("x-btn-pressed");
11829 this.pressed = true;
11830 this.fireEvent("toggle", this, true);
11832 this.el.removeClass("x-btn-pressed");
11833 this.pressed = false;
11834 this.fireEvent("toggle", this, false);
11836 if(this.toggleHandler){
11837 this.toggleHandler.call(this.scope || this, this, state);
11845 focus : function(){
11846 this.el.child('button:first').focus();
11850 * Disable this button
11852 disable : function(){
11854 this.el.addClass("x-btn-disabled");
11856 this.disabled = true;
11860 * Enable this button
11862 enable : function(){
11864 this.el.removeClass("x-btn-disabled");
11866 this.disabled = false;
11870 * Convenience function for boolean enable/disable
11871 * @param {Boolean} enabled True to enable, false to disable
11873 setDisabled : function(v){
11874 this[v !== true ? "enable" : "disable"]();
11878 onClick : function(e){
11880 e.preventDefault();
11885 if(!this.disabled){
11886 if(this.enableToggle){
11889 if(this.menu && !this.menu.isVisible()){
11890 this.menu.show(this.el, this.menuAlign);
11892 this.fireEvent("click", this, e);
11894 this.el.removeClass("x-btn-over");
11895 this.handler.call(this.scope || this, this, e);
11900 onMouseOver : function(e){
11901 if(!this.disabled){
11902 this.el.addClass("x-btn-over");
11903 this.fireEvent('mouseover', this, e);
11907 onMouseOut : function(e){
11908 if(!e.within(this.el, true)){
11909 this.el.removeClass("x-btn-over");
11910 this.fireEvent('mouseout', this, e);
11914 onFocus : function(e){
11915 if(!this.disabled){
11916 this.el.addClass("x-btn-focus");
11920 onBlur : function(e){
11921 this.el.removeClass("x-btn-focus");
11924 onMouseDown : function(e){
11925 if(!this.disabled && e.button == 0){
11926 this.el.addClass("x-btn-click");
11927 Roo.get(document).on('mouseup', this.onMouseUp, this);
11931 onMouseUp : function(e){
11933 this.el.removeClass("x-btn-click");
11934 Roo.get(document).un('mouseup', this.onMouseUp, this);
11938 onMenuShow : function(e){
11939 this.el.addClass("x-btn-menu-active");
11942 onMenuHide : function(e){
11943 this.el.removeClass("x-btn-menu-active");
11947 // Private utility class used by Button
11948 Roo.ButtonToggleMgr = function(){
11951 function toggleGroup(btn, state){
11953 var g = groups[btn.toggleGroup];
11954 for(var i = 0, l = g.length; i < l; i++){
11956 g[i].toggle(false);
11963 register : function(btn){
11964 if(!btn.toggleGroup){
11967 var g = groups[btn.toggleGroup];
11969 g = groups[btn.toggleGroup] = [];
11972 btn.on("toggle", toggleGroup);
11975 unregister : function(btn){
11976 if(!btn.toggleGroup){
11979 var g = groups[btn.toggleGroup];
11982 btn.un("toggle", toggleGroup);
11988 * Ext JS Library 1.1.1
11989 * Copyright(c) 2006-2007, Ext JS, LLC.
11991 * Originally Released Under LGPL - original licence link has changed is not relivant.
11994 * <script type="text/javascript">
11998 * @class Roo.SplitButton
11999 * @extends Roo.Button
12000 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12001 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
12002 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12003 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12004 * @cfg {String} arrowTooltip The title attribute of the arrow
12006 * Create a new menu button
12007 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12008 * @param {Object} config The config object
12010 Roo.SplitButton = function(renderTo, config){
12011 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12013 * @event arrowclick
12014 * Fires when this button's arrow is clicked
12015 * @param {SplitButton} this
12016 * @param {EventObject} e The click event
12018 this.addEvents({"arrowclick":true});
12021 Roo.extend(Roo.SplitButton, Roo.Button, {
12022 render : function(renderTo){
12023 // this is one sweet looking template!
12024 var tpl = new Roo.Template(
12025 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12026 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12027 '<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>',
12028 "</tbody></table></td><td>",
12029 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12030 '<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>',
12031 "</tbody></table></td></tr></table>"
12033 var btn = tpl.append(renderTo, [this.text, this.type], true);
12034 var btnEl = btn.child("button");
12036 btn.addClass(this.cls);
12039 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12042 btnEl.addClass(this.iconCls);
12044 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12048 if(this.handleMouseEvents){
12049 btn.on("mouseover", this.onMouseOver, this);
12050 btn.on("mouseout", this.onMouseOut, this);
12051 btn.on("mousedown", this.onMouseDown, this);
12052 btn.on("mouseup", this.onMouseUp, this);
12054 btn.on(this.clickEvent, this.onClick, this);
12056 if(typeof this.tooltip == 'object'){
12057 Roo.QuickTips.tips(Roo.apply({
12061 btnEl.dom[this.tooltipType] = this.tooltip;
12064 if(this.arrowTooltip){
12065 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12074 this.el.addClass("x-btn-pressed");
12076 if(Roo.isIE && !Roo.isIE7){
12077 this.autoWidth.defer(1, this);
12082 this.menu.on("show", this.onMenuShow, this);
12083 this.menu.on("hide", this.onMenuHide, this);
12085 this.fireEvent('render', this);
12089 autoWidth : function(){
12091 var tbl = this.el.child("table:first");
12092 var tbl2 = this.el.child("table:last");
12093 this.el.setWidth("auto");
12094 tbl.setWidth("auto");
12095 if(Roo.isIE7 && Roo.isStrict){
12096 var ib = this.el.child('button:first');
12097 if(ib && ib.getWidth() > 20){
12099 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12104 this.el.beginMeasure();
12106 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12107 tbl.setWidth(this.minWidth-tbl2.getWidth());
12110 this.el.endMeasure();
12113 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12117 * Sets this button's click handler
12118 * @param {Function} handler The function to call when the button is clicked
12119 * @param {Object} scope (optional) Scope for the function passed above
12121 setHandler : function(handler, scope){
12122 this.handler = handler;
12123 this.scope = scope;
12127 * Sets this button's arrow click handler
12128 * @param {Function} handler The function to call when the arrow is clicked
12129 * @param {Object} scope (optional) Scope for the function passed above
12131 setArrowHandler : function(handler, scope){
12132 this.arrowHandler = handler;
12133 this.scope = scope;
12139 focus : function(){
12141 this.el.child("button:first").focus();
12146 onClick : function(e){
12147 e.preventDefault();
12148 if(!this.disabled){
12149 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12150 if(this.menu && !this.menu.isVisible()){
12151 this.menu.show(this.el, this.menuAlign);
12153 this.fireEvent("arrowclick", this, e);
12154 if(this.arrowHandler){
12155 this.arrowHandler.call(this.scope || this, this, e);
12158 this.fireEvent("click", this, e);
12160 this.handler.call(this.scope || this, this, e);
12166 onMouseDown : function(e){
12167 if(!this.disabled){
12168 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12172 onMouseUp : function(e){
12173 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12178 // backwards compat
12179 Roo.MenuButton = Roo.SplitButton;/*
12181 * Ext JS Library 1.1.1
12182 * Copyright(c) 2006-2007, Ext JS, LLC.
12184 * Originally Released Under LGPL - original licence link has changed is not relivant.
12187 * <script type="text/javascript">
12191 * @class Roo.Toolbar
12192 * Basic Toolbar class.
12194 * Creates a new Toolbar
12195 * @param {Object} config The config object
12197 Roo.Toolbar = function(container, buttons, config)
12199 /// old consturctor format still supported..
12200 if(container instanceof Array){ // omit the container for later rendering
12201 buttons = container;
12205 if (typeof(container) == 'object' && container.xtype) {
12206 config = container;
12207 container = config.container;
12208 buttons = config.buttons; // not really - use items!!
12211 if (config && config.items) {
12212 xitems = config.items;
12213 delete config.items;
12215 Roo.apply(this, config);
12216 this.buttons = buttons;
12219 this.render(container);
12221 Roo.each(xitems, function(b) {
12227 Roo.Toolbar.prototype = {
12229 * @cfg {Roo.data.Store} items
12230 * array of button configs or elements to add
12234 * @cfg {String/HTMLElement/Element} container
12235 * The id or element that will contain the toolbar
12238 render : function(ct){
12239 this.el = Roo.get(ct);
12241 this.el.addClass(this.cls);
12243 // using a table allows for vertical alignment
12244 // 100% width is needed by Safari...
12245 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12246 this.tr = this.el.child("tr", true);
12248 this.items = new Roo.util.MixedCollection(false, function(o){
12249 return o.id || ("item" + (++autoId));
12252 this.add.apply(this, this.buttons);
12253 delete this.buttons;
12258 * Adds element(s) to the toolbar -- this function takes a variable number of
12259 * arguments of mixed type and adds them to the toolbar.
12260 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12262 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12263 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12264 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12265 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12266 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12267 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12268 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12269 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12270 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12272 * @param {Mixed} arg2
12273 * @param {Mixed} etc.
12276 var a = arguments, l = a.length;
12277 for(var i = 0; i < l; i++){
12282 _add : function(el) {
12285 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12288 if (el.applyTo){ // some kind of form field
12289 return this.addField(el);
12291 if (el.render){ // some kind of Toolbar.Item
12292 return this.addItem(el);
12294 if (typeof el == "string"){ // string
12295 if(el == "separator" || el == "-"){
12296 return this.addSeparator();
12299 return this.addSpacer();
12302 return this.addFill();
12304 return this.addText(el);
12307 if(el.tagName){ // element
12308 return this.addElement(el);
12310 if(typeof el == "object"){ // must be button config?
12311 return this.addButton(el);
12313 // and now what?!?!
12319 * Add an Xtype element
12320 * @param {Object} xtype Xtype Object
12321 * @return {Object} created Object
12323 addxtype : function(e){
12324 return this.add(e);
12328 * Returns the Element for this toolbar.
12329 * @return {Roo.Element}
12331 getEl : function(){
12337 * @return {Roo.Toolbar.Item} The separator item
12339 addSeparator : function(){
12340 return this.addItem(new Roo.Toolbar.Separator());
12344 * Adds a spacer element
12345 * @return {Roo.Toolbar.Spacer} The spacer item
12347 addSpacer : function(){
12348 return this.addItem(new Roo.Toolbar.Spacer());
12352 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12353 * @return {Roo.Toolbar.Fill} The fill item
12355 addFill : function(){
12356 return this.addItem(new Roo.Toolbar.Fill());
12360 * Adds any standard HTML element to the toolbar
12361 * @param {String/HTMLElement/Element} el The element or id of the element to add
12362 * @return {Roo.Toolbar.Item} The element's item
12364 addElement : function(el){
12365 return this.addItem(new Roo.Toolbar.Item(el));
12368 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12369 * @type Roo.util.MixedCollection
12374 * Adds any Toolbar.Item or subclass
12375 * @param {Roo.Toolbar.Item} item
12376 * @return {Roo.Toolbar.Item} The item
12378 addItem : function(item){
12379 var td = this.nextBlock();
12381 this.items.add(item);
12386 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12387 * @param {Object/Array} config A button config or array of configs
12388 * @return {Roo.Toolbar.Button/Array}
12390 addButton : function(config){
12391 if(config instanceof Array){
12393 for(var i = 0, len = config.length; i < len; i++) {
12394 buttons.push(this.addButton(config[i]));
12399 if(!(config instanceof Roo.Toolbar.Button)){
12401 new Roo.Toolbar.SplitButton(config) :
12402 new Roo.Toolbar.Button(config);
12404 var td = this.nextBlock();
12411 * Adds text to the toolbar
12412 * @param {String} text The text to add
12413 * @return {Roo.Toolbar.Item} The element's item
12415 addText : function(text){
12416 return this.addItem(new Roo.Toolbar.TextItem(text));
12420 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12421 * @param {Number} index The index where the item is to be inserted
12422 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12423 * @return {Roo.Toolbar.Button/Item}
12425 insertButton : function(index, item){
12426 if(item instanceof Array){
12428 for(var i = 0, len = item.length; i < len; i++) {
12429 buttons.push(this.insertButton(index + i, item[i]));
12433 if (!(item instanceof Roo.Toolbar.Button)){
12434 item = new Roo.Toolbar.Button(item);
12436 var td = document.createElement("td");
12437 this.tr.insertBefore(td, this.tr.childNodes[index]);
12439 this.items.insert(index, item);
12444 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12445 * @param {Object} config
12446 * @return {Roo.Toolbar.Item} The element's item
12448 addDom : function(config, returnEl){
12449 var td = this.nextBlock();
12450 Roo.DomHelper.overwrite(td, config);
12451 var ti = new Roo.Toolbar.Item(td.firstChild);
12453 this.items.add(ti);
12458 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12459 * @type Roo.util.MixedCollection
12464 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12465 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12466 * @param {Roo.form.Field} field
12467 * @return {Roo.ToolbarItem}
12471 addField : function(field) {
12472 if (!this.fields) {
12474 this.fields = new Roo.util.MixedCollection(false, function(o){
12475 return o.id || ("item" + (++autoId));
12480 var td = this.nextBlock();
12482 var ti = new Roo.Toolbar.Item(td.firstChild);
12484 this.items.add(ti);
12485 this.fields.add(field);
12496 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12497 this.el.child('div').hide();
12505 this.el.child('div').show();
12509 nextBlock : function(){
12510 var td = document.createElement("td");
12511 this.tr.appendChild(td);
12516 destroy : function(){
12517 if(this.items){ // rendered?
12518 Roo.destroy.apply(Roo, this.items.items);
12520 if(this.fields){ // rendered?
12521 Roo.destroy.apply(Roo, this.fields.items);
12523 Roo.Element.uncache(this.el, this.tr);
12528 * @class Roo.Toolbar.Item
12529 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12531 * Creates a new Item
12532 * @param {HTMLElement} el
12534 Roo.Toolbar.Item = function(el){
12535 this.el = Roo.getDom(el);
12536 this.id = Roo.id(this.el);
12537 this.hidden = false;
12540 Roo.Toolbar.Item.prototype = {
12543 * Get this item's HTML Element
12544 * @return {HTMLElement}
12546 getEl : function(){
12551 render : function(td){
12553 td.appendChild(this.el);
12557 * Removes and destroys this item.
12559 destroy : function(){
12560 this.td.parentNode.removeChild(this.td);
12567 this.hidden = false;
12568 this.td.style.display = "";
12575 this.hidden = true;
12576 this.td.style.display = "none";
12580 * Convenience function for boolean show/hide.
12581 * @param {Boolean} visible true to show/false to hide
12583 setVisible: function(visible){
12592 * Try to focus this item.
12594 focus : function(){
12595 Roo.fly(this.el).focus();
12599 * Disables this item.
12601 disable : function(){
12602 Roo.fly(this.td).addClass("x-item-disabled");
12603 this.disabled = true;
12604 this.el.disabled = true;
12608 * Enables this item.
12610 enable : function(){
12611 Roo.fly(this.td).removeClass("x-item-disabled");
12612 this.disabled = false;
12613 this.el.disabled = false;
12619 * @class Roo.Toolbar.Separator
12620 * @extends Roo.Toolbar.Item
12621 * A simple toolbar separator class
12623 * Creates a new Separator
12625 Roo.Toolbar.Separator = function(){
12626 var s = document.createElement("span");
12627 s.className = "ytb-sep";
12628 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12630 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12631 enable:Roo.emptyFn,
12632 disable:Roo.emptyFn,
12637 * @class Roo.Toolbar.Spacer
12638 * @extends Roo.Toolbar.Item
12639 * A simple element that adds extra horizontal space to a toolbar.
12641 * Creates a new Spacer
12643 Roo.Toolbar.Spacer = function(){
12644 var s = document.createElement("div");
12645 s.className = "ytb-spacer";
12646 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12648 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12649 enable:Roo.emptyFn,
12650 disable:Roo.emptyFn,
12655 * @class Roo.Toolbar.Fill
12656 * @extends Roo.Toolbar.Spacer
12657 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12659 * Creates a new Spacer
12661 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12663 render : function(td){
12664 td.style.width = '100%';
12665 Roo.Toolbar.Fill.superclass.render.call(this, td);
12670 * @class Roo.Toolbar.TextItem
12671 * @extends Roo.Toolbar.Item
12672 * A simple class that renders text directly into a toolbar.
12674 * Creates a new TextItem
12675 * @param {String} text
12677 Roo.Toolbar.TextItem = function(text){
12678 if (typeof(text) == 'object') {
12681 var s = document.createElement("span");
12682 s.className = "ytb-text";
12683 s.innerHTML = text;
12684 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12686 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12687 enable:Roo.emptyFn,
12688 disable:Roo.emptyFn,
12693 * @class Roo.Toolbar.Button
12694 * @extends Roo.Button
12695 * A button that renders into a toolbar.
12697 * Creates a new Button
12698 * @param {Object} config A standard {@link Roo.Button} config object
12700 Roo.Toolbar.Button = function(config){
12701 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12703 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12704 render : function(td){
12706 Roo.Toolbar.Button.superclass.render.call(this, td);
12710 * Removes and destroys this button
12712 destroy : function(){
12713 Roo.Toolbar.Button.superclass.destroy.call(this);
12714 this.td.parentNode.removeChild(this.td);
12718 * Shows this button
12721 this.hidden = false;
12722 this.td.style.display = "";
12726 * Hides this button
12729 this.hidden = true;
12730 this.td.style.display = "none";
12734 * Disables this item
12736 disable : function(){
12737 Roo.fly(this.td).addClass("x-item-disabled");
12738 this.disabled = true;
12742 * Enables this item
12744 enable : function(){
12745 Roo.fly(this.td).removeClass("x-item-disabled");
12746 this.disabled = false;
12749 // backwards compat
12750 Roo.ToolbarButton = Roo.Toolbar.Button;
12753 * @class Roo.Toolbar.SplitButton
12754 * @extends Roo.SplitButton
12755 * A menu button that renders into a toolbar.
12757 * Creates a new SplitButton
12758 * @param {Object} config A standard {@link Roo.SplitButton} config object
12760 Roo.Toolbar.SplitButton = function(config){
12761 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12763 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12764 render : function(td){
12766 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12770 * Removes and destroys this button
12772 destroy : function(){
12773 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12774 this.td.parentNode.removeChild(this.td);
12778 * Shows this button
12781 this.hidden = false;
12782 this.td.style.display = "";
12786 * Hides this button
12789 this.hidden = true;
12790 this.td.style.display = "none";
12794 // backwards compat
12795 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12797 * Ext JS Library 1.1.1
12798 * Copyright(c) 2006-2007, Ext JS, LLC.
12800 * Originally Released Under LGPL - original licence link has changed is not relivant.
12803 * <script type="text/javascript">
12807 * @class Roo.PagingToolbar
12808 * @extends Roo.Toolbar
12809 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12811 * Create a new PagingToolbar
12812 * @param {Object} config The config object
12814 Roo.PagingToolbar = function(el, ds, config)
12816 // old args format still supported... - xtype is prefered..
12817 if (typeof(el) == 'object' && el.xtype) {
12818 // created from xtype...
12820 ds = el.dataSource;
12821 el = config.container;
12824 if (config.items) {
12825 items = config.items;
12829 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12832 this.renderButtons(this.el);
12835 // supprot items array.
12837 Roo.each(items, function(e) {
12838 this.add(Roo.factory(e));
12843 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12845 * @cfg {Roo.data.Store} dataSource
12846 * The underlying data store providing the paged data
12849 * @cfg {String/HTMLElement/Element} container
12850 * container The id or element that will contain the toolbar
12853 * @cfg {Boolean} displayInfo
12854 * True to display the displayMsg (defaults to false)
12857 * @cfg {Number} pageSize
12858 * The number of records to display per page (defaults to 20)
12862 * @cfg {String} displayMsg
12863 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12865 displayMsg : 'Displaying {0} - {1} of {2}',
12867 * @cfg {String} emptyMsg
12868 * The message to display when no records are found (defaults to "No data to display")
12870 emptyMsg : 'No data to display',
12872 * Customizable piece of the default paging text (defaults to "Page")
12875 beforePageText : "Page",
12877 * Customizable piece of the default paging text (defaults to "of %0")
12880 afterPageText : "of {0}",
12882 * Customizable piece of the default paging text (defaults to "First Page")
12885 firstText : "First Page",
12887 * Customizable piece of the default paging text (defaults to "Previous Page")
12890 prevText : "Previous Page",
12892 * Customizable piece of the default paging text (defaults to "Next Page")
12895 nextText : "Next Page",
12897 * Customizable piece of the default paging text (defaults to "Last Page")
12900 lastText : "Last Page",
12902 * Customizable piece of the default paging text (defaults to "Refresh")
12905 refreshText : "Refresh",
12908 renderButtons : function(el){
12909 Roo.PagingToolbar.superclass.render.call(this, el);
12910 this.first = this.addButton({
12911 tooltip: this.firstText,
12912 cls: "x-btn-icon x-grid-page-first",
12914 handler: this.onClick.createDelegate(this, ["first"])
12916 this.prev = this.addButton({
12917 tooltip: this.prevText,
12918 cls: "x-btn-icon x-grid-page-prev",
12920 handler: this.onClick.createDelegate(this, ["prev"])
12922 //this.addSeparator();
12923 this.add(this.beforePageText);
12924 this.field = Roo.get(this.addDom({
12929 cls: "x-grid-page-number"
12931 this.field.on("keydown", this.onPagingKeydown, this);
12932 this.field.on("focus", function(){this.dom.select();});
12933 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12934 this.field.setHeight(18);
12935 //this.addSeparator();
12936 this.next = this.addButton({
12937 tooltip: this.nextText,
12938 cls: "x-btn-icon x-grid-page-next",
12940 handler: this.onClick.createDelegate(this, ["next"])
12942 this.last = this.addButton({
12943 tooltip: this.lastText,
12944 cls: "x-btn-icon x-grid-page-last",
12946 handler: this.onClick.createDelegate(this, ["last"])
12948 //this.addSeparator();
12949 this.loading = this.addButton({
12950 tooltip: this.refreshText,
12951 cls: "x-btn-icon x-grid-loading",
12952 handler: this.onClick.createDelegate(this, ["refresh"])
12955 if(this.displayInfo){
12956 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12961 updateInfo : function(){
12962 if(this.displayEl){
12963 var count = this.ds.getCount();
12964 var msg = count == 0 ?
12968 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12970 this.displayEl.update(msg);
12975 onLoad : function(ds, r, o){
12976 this.cursor = o.params ? o.params.start : 0;
12977 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12979 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12980 this.field.dom.value = ap;
12981 this.first.setDisabled(ap == 1);
12982 this.prev.setDisabled(ap == 1);
12983 this.next.setDisabled(ap == ps);
12984 this.last.setDisabled(ap == ps);
12985 this.loading.enable();
12990 getPageData : function(){
12991 var total = this.ds.getTotalCount();
12994 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12995 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13000 onLoadError : function(){
13001 this.loading.enable();
13005 onPagingKeydown : function(e){
13006 var k = e.getKey();
13007 var d = this.getPageData();
13009 var v = this.field.dom.value, pageNum;
13010 if(!v || isNaN(pageNum = parseInt(v, 10))){
13011 this.field.dom.value = d.activePage;
13014 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13015 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13018 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))
13020 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13021 this.field.dom.value = pageNum;
13022 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13025 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13027 var v = this.field.dom.value, pageNum;
13028 var increment = (e.shiftKey) ? 10 : 1;
13029 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13031 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13032 this.field.dom.value = d.activePage;
13035 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13037 this.field.dom.value = parseInt(v, 10) + increment;
13038 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13039 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13046 beforeLoad : function(){
13048 this.loading.disable();
13053 onClick : function(which){
13057 ds.load({params:{start: 0, limit: this.pageSize}});
13060 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13063 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13066 var total = ds.getTotalCount();
13067 var extra = total % this.pageSize;
13068 var lastStart = extra ? (total - extra) : total-this.pageSize;
13069 ds.load({params:{start: lastStart, limit: this.pageSize}});
13072 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13078 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13079 * @param {Roo.data.Store} store The data store to unbind
13081 unbind : function(ds){
13082 ds.un("beforeload", this.beforeLoad, this);
13083 ds.un("load", this.onLoad, this);
13084 ds.un("loadexception", this.onLoadError, this);
13085 ds.un("remove", this.updateInfo, this);
13086 ds.un("add", this.updateInfo, this);
13087 this.ds = undefined;
13091 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13092 * @param {Roo.data.Store} store The data store to bind
13094 bind : function(ds){
13095 ds.on("beforeload", this.beforeLoad, this);
13096 ds.on("load", this.onLoad, this);
13097 ds.on("loadexception", this.onLoadError, this);
13098 ds.on("remove", this.updateInfo, this);
13099 ds.on("add", this.updateInfo, this);
13104 * Ext JS Library 1.1.1
13105 * Copyright(c) 2006-2007, Ext JS, LLC.
13107 * Originally Released Under LGPL - original licence link has changed is not relivant.
13110 * <script type="text/javascript">
13114 * @class Roo.Resizable
13115 * @extends Roo.util.Observable
13116 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13117 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13118 * 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
13119 * the element will be wrapped for you automatically.</p>
13120 * <p>Here is the list of valid resize handles:</p>
13123 ------ -------------------
13132 'hd' horizontal drag
13135 * <p>Here's an example showing the creation of a typical Resizable:</p>
13137 var resizer = new Roo.Resizable("element-id", {
13145 resizer.on("resize", myHandler);
13147 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13148 * resizer.east.setDisplayed(false);</p>
13149 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13150 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13151 * resize operation's new size (defaults to [0, 0])
13152 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13153 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13154 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13155 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13156 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13157 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13158 * @cfg {Number} width The width of the element in pixels (defaults to null)
13159 * @cfg {Number} height The height of the element in pixels (defaults to null)
13160 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13161 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13162 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13163 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13164 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13165 * in favor of the handles config option (defaults to false)
13166 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13167 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13168 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13169 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13170 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13171 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13172 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13173 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13174 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13175 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13176 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13178 * Create a new resizable component
13179 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13180 * @param {Object} config configuration options
13182 Roo.Resizable = function(el, config)
13184 this.el = Roo.get(el);
13186 if(config && config.wrap){
13187 config.resizeChild = this.el;
13188 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13189 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13190 this.el.setStyle("overflow", "hidden");
13191 this.el.setPositioning(config.resizeChild.getPositioning());
13192 config.resizeChild.clearPositioning();
13193 if(!config.width || !config.height){
13194 var csize = config.resizeChild.getSize();
13195 this.el.setSize(csize.width, csize.height);
13197 if(config.pinned && !config.adjustments){
13198 config.adjustments = "auto";
13202 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13203 this.proxy.unselectable();
13204 this.proxy.enableDisplayMode('block');
13206 Roo.apply(this, config);
13209 this.disableTrackOver = true;
13210 this.el.addClass("x-resizable-pinned");
13212 // if the element isn't positioned, make it relative
13213 var position = this.el.getStyle("position");
13214 if(position != "absolute" && position != "fixed"){
13215 this.el.setStyle("position", "relative");
13217 if(!this.handles){ // no handles passed, must be legacy style
13218 this.handles = 's,e,se';
13219 if(this.multiDirectional){
13220 this.handles += ',n,w';
13223 if(this.handles == "all"){
13224 this.handles = "n s e w ne nw se sw";
13226 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13227 var ps = Roo.Resizable.positions;
13228 for(var i = 0, len = hs.length; i < len; i++){
13229 if(hs[i] && ps[hs[i]]){
13230 var pos = ps[hs[i]];
13231 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13235 this.corner = this.southeast;
13237 // updateBox = the box can move..
13238 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13239 this.updateBox = true;
13242 this.activeHandle = null;
13244 if(this.resizeChild){
13245 if(typeof this.resizeChild == "boolean"){
13246 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13248 this.resizeChild = Roo.get(this.resizeChild, true);
13252 if(this.adjustments == "auto"){
13253 var rc = this.resizeChild;
13254 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13255 if(rc && (hw || hn)){
13256 rc.position("relative");
13257 rc.setLeft(hw ? hw.el.getWidth() : 0);
13258 rc.setTop(hn ? hn.el.getHeight() : 0);
13260 this.adjustments = [
13261 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13262 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13266 if(this.draggable){
13267 this.dd = this.dynamic ?
13268 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13269 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13275 * @event beforeresize
13276 * Fired before resize is allowed. Set enabled to false to cancel resize.
13277 * @param {Roo.Resizable} this
13278 * @param {Roo.EventObject} e The mousedown event
13280 "beforeresize" : true,
13283 * Fired after a resize.
13284 * @param {Roo.Resizable} this
13285 * @param {Number} width The new width
13286 * @param {Number} height The new height
13287 * @param {Roo.EventObject} e The mouseup event
13292 if(this.width !== null && this.height !== null){
13293 this.resizeTo(this.width, this.height);
13295 this.updateChildSize();
13298 this.el.dom.style.zoom = 1;
13300 Roo.Resizable.superclass.constructor.call(this);
13303 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13304 resizeChild : false,
13305 adjustments : [0, 0],
13315 multiDirectional : false,
13316 disableTrackOver : false,
13317 easing : 'easeOutStrong',
13318 widthIncrement : 0,
13319 heightIncrement : 0,
13323 preserveRatio : false,
13324 transparent: false,
13330 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13332 constrainTo: undefined,
13334 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13336 resizeRegion: undefined,
13340 * Perform a manual resize
13341 * @param {Number} width
13342 * @param {Number} height
13344 resizeTo : function(width, height){
13345 this.el.setSize(width, height);
13346 this.updateChildSize();
13347 this.fireEvent("resize", this, width, height, null);
13351 startSizing : function(e, handle){
13352 this.fireEvent("beforeresize", this, e);
13353 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13356 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13357 this.overlay.unselectable();
13358 this.overlay.enableDisplayMode("block");
13359 this.overlay.on("mousemove", this.onMouseMove, this);
13360 this.overlay.on("mouseup", this.onMouseUp, this);
13362 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13364 this.resizing = true;
13365 this.startBox = this.el.getBox();
13366 this.startPoint = e.getXY();
13367 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13368 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13370 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13371 this.overlay.show();
13373 if(this.constrainTo) {
13374 var ct = Roo.get(this.constrainTo);
13375 this.resizeRegion = ct.getRegion().adjust(
13376 ct.getFrameWidth('t'),
13377 ct.getFrameWidth('l'),
13378 -ct.getFrameWidth('b'),
13379 -ct.getFrameWidth('r')
13383 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13385 this.proxy.setBox(this.startBox);
13387 this.proxy.setStyle('visibility', 'visible');
13393 onMouseDown : function(handle, e){
13396 this.activeHandle = handle;
13397 this.startSizing(e, handle);
13402 onMouseUp : function(e){
13403 var size = this.resizeElement();
13404 this.resizing = false;
13406 this.overlay.hide();
13408 this.fireEvent("resize", this, size.width, size.height, e);
13412 updateChildSize : function(){
13413 if(this.resizeChild){
13415 var child = this.resizeChild;
13416 var adj = this.adjustments;
13417 if(el.dom.offsetWidth){
13418 var b = el.getSize(true);
13419 child.setSize(b.width+adj[0], b.height+adj[1]);
13421 // Second call here for IE
13422 // The first call enables instant resizing and
13423 // the second call corrects scroll bars if they
13426 setTimeout(function(){
13427 if(el.dom.offsetWidth){
13428 var b = el.getSize(true);
13429 child.setSize(b.width+adj[0], b.height+adj[1]);
13437 snap : function(value, inc, min){
13438 if(!inc || !value) return value;
13439 var newValue = value;
13440 var m = value % inc;
13443 newValue = value + (inc-m);
13445 newValue = value - m;
13448 return Math.max(min, newValue);
13452 resizeElement : function(){
13453 var box = this.proxy.getBox();
13454 if(this.updateBox){
13455 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13457 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13459 this.updateChildSize();
13467 constrain : function(v, diff, m, mx){
13470 }else if(v - diff > mx){
13477 onMouseMove : function(e){
13479 try{// try catch so if something goes wrong the user doesn't get hung
13481 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13485 //var curXY = this.startPoint;
13486 var curSize = this.curSize || this.startBox;
13487 var x = this.startBox.x, y = this.startBox.y;
13488 var ox = x, oy = y;
13489 var w = curSize.width, h = curSize.height;
13490 var ow = w, oh = h;
13491 var mw = this.minWidth, mh = this.minHeight;
13492 var mxw = this.maxWidth, mxh = this.maxHeight;
13493 var wi = this.widthIncrement;
13494 var hi = this.heightIncrement;
13496 var eventXY = e.getXY();
13497 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13498 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13500 var pos = this.activeHandle.position;
13505 w = Math.min(Math.max(mw, w), mxw);
13510 h = Math.min(Math.max(mh, h), mxh);
13515 w = Math.min(Math.max(mw, w), mxw);
13516 h = Math.min(Math.max(mh, h), mxh);
13519 diffY = this.constrain(h, diffY, mh, mxh);
13526 var adiffX = Math.abs(diffX);
13527 var sub = (adiffX % wi); // how much
13528 if (sub > (wi/2)) { // far enough to snap
13529 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13531 // remove difference..
13532 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13536 x = Math.max(this.minX, x);
13539 diffX = this.constrain(w, diffX, mw, mxw);
13545 w = Math.min(Math.max(mw, w), mxw);
13546 diffY = this.constrain(h, diffY, mh, mxh);
13551 diffX = this.constrain(w, diffX, mw, mxw);
13552 diffY = this.constrain(h, diffY, mh, mxh);
13559 diffX = this.constrain(w, diffX, mw, mxw);
13561 h = Math.min(Math.max(mh, h), mxh);
13567 var sw = this.snap(w, wi, mw);
13568 var sh = this.snap(h, hi, mh);
13569 if(sw != w || sh != h){
13592 if(this.preserveRatio){
13597 h = Math.min(Math.max(mh, h), mxh);
13602 w = Math.min(Math.max(mw, w), mxw);
13607 w = Math.min(Math.max(mw, w), mxw);
13613 w = Math.min(Math.max(mw, w), mxw);
13619 h = Math.min(Math.max(mh, h), mxh);
13627 h = Math.min(Math.max(mh, h), mxh);
13637 h = Math.min(Math.max(mh, h), mxh);
13645 if (pos == 'hdrag') {
13648 this.proxy.setBounds(x, y, w, h);
13650 this.resizeElement();
13657 handleOver : function(){
13659 this.el.addClass("x-resizable-over");
13664 handleOut : function(){
13665 if(!this.resizing){
13666 this.el.removeClass("x-resizable-over");
13671 * Returns the element this component is bound to.
13672 * @return {Roo.Element}
13674 getEl : function(){
13679 * Returns the resizeChild element (or null).
13680 * @return {Roo.Element}
13682 getResizeChild : function(){
13683 return this.resizeChild;
13687 * Destroys this resizable. If the element was wrapped and
13688 * removeEl is not true then the element remains.
13689 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13691 destroy : function(removeEl){
13692 this.proxy.remove();
13694 this.overlay.removeAllListeners();
13695 this.overlay.remove();
13697 var ps = Roo.Resizable.positions;
13699 if(typeof ps[k] != "function" && this[ps[k]]){
13700 var h = this[ps[k]];
13701 h.el.removeAllListeners();
13706 this.el.update("");
13713 // hash to map config positions to true positions
13714 Roo.Resizable.positions = {
13715 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13720 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13722 // only initialize the template if resizable is used
13723 var tpl = Roo.DomHelper.createTemplate(
13724 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13727 Roo.Resizable.Handle.prototype.tpl = tpl;
13729 this.position = pos;
13731 // show north drag fro topdra
13732 var handlepos = pos == 'hdrag' ? 'north' : pos;
13734 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13735 if (pos == 'hdrag') {
13736 this.el.setStyle('cursor', 'pointer');
13738 this.el.unselectable();
13740 this.el.setOpacity(0);
13742 this.el.on("mousedown", this.onMouseDown, this);
13743 if(!disableTrackOver){
13744 this.el.on("mouseover", this.onMouseOver, this);
13745 this.el.on("mouseout", this.onMouseOut, this);
13750 Roo.Resizable.Handle.prototype = {
13751 afterResize : function(rz){
13755 onMouseDown : function(e){
13756 this.rz.onMouseDown(this, e);
13759 onMouseOver : function(e){
13760 this.rz.handleOver(this, e);
13763 onMouseOut : function(e){
13764 this.rz.handleOut(this, e);
13768 * Ext JS Library 1.1.1
13769 * Copyright(c) 2006-2007, Ext JS, LLC.
13771 * Originally Released Under LGPL - original licence link has changed is not relivant.
13774 * <script type="text/javascript">
13778 * @class Roo.Editor
13779 * @extends Roo.Component
13780 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13782 * Create a new Editor
13783 * @param {Roo.form.Field} field The Field object (or descendant)
13784 * @param {Object} config The config object
13786 Roo.Editor = function(field, config){
13787 Roo.Editor.superclass.constructor.call(this, config);
13788 this.field = field;
13791 * @event beforestartedit
13792 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13793 * false from the handler of this event.
13794 * @param {Editor} this
13795 * @param {Roo.Element} boundEl The underlying element bound to this editor
13796 * @param {Mixed} value The field value being set
13798 "beforestartedit" : true,
13801 * Fires when this editor is displayed
13802 * @param {Roo.Element} boundEl The underlying element bound to this editor
13803 * @param {Mixed} value The starting field value
13805 "startedit" : true,
13807 * @event beforecomplete
13808 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13809 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13810 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13811 * event will not fire since no edit actually occurred.
13812 * @param {Editor} this
13813 * @param {Mixed} value The current field value
13814 * @param {Mixed} startValue The original field value
13816 "beforecomplete" : true,
13819 * Fires after editing is complete and any changed value has been written to the underlying field.
13820 * @param {Editor} this
13821 * @param {Mixed} value The current field value
13822 * @param {Mixed} startValue The original field value
13826 * @event specialkey
13827 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13828 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13829 * @param {Roo.form.Field} this
13830 * @param {Roo.EventObject} e The event object
13832 "specialkey" : true
13836 Roo.extend(Roo.Editor, Roo.Component, {
13838 * @cfg {Boolean/String} autosize
13839 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13840 * or "height" to adopt the height only (defaults to false)
13843 * @cfg {Boolean} revertInvalid
13844 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13845 * validation fails (defaults to true)
13848 * @cfg {Boolean} ignoreNoChange
13849 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13850 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13851 * will never be ignored.
13854 * @cfg {Boolean} hideEl
13855 * False to keep the bound element visible while the editor is displayed (defaults to true)
13858 * @cfg {Mixed} value
13859 * The data value of the underlying field (defaults to "")
13863 * @cfg {String} alignment
13864 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13868 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13869 * for bottom-right shadow (defaults to "frame")
13873 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13877 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13879 completeOnEnter : false,
13881 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13883 cancelOnEsc : false,
13885 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13890 onRender : function(ct, position){
13891 this.el = new Roo.Layer({
13892 shadow: this.shadow,
13898 constrain: this.constrain
13900 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13901 if(this.field.msgTarget != 'title'){
13902 this.field.msgTarget = 'qtip';
13904 this.field.render(this.el);
13906 this.field.el.dom.setAttribute('autocomplete', 'off');
13908 this.field.on("specialkey", this.onSpecialKey, this);
13909 if(this.swallowKeys){
13910 this.field.el.swallowEvent(['keydown','keypress']);
13913 this.field.on("blur", this.onBlur, this);
13914 if(this.field.grow){
13915 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13919 onSpecialKey : function(field, e){
13920 //Roo.log('editor onSpecialKey');
13921 if(this.completeOnEnter && e.getKey() == e.ENTER){
13923 this.completeEdit();
13924 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13927 this.fireEvent('specialkey', field, e);
13932 * Starts the editing process and shows the editor.
13933 * @param {String/HTMLElement/Element} el The element to edit
13934 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13935 * to the innerHTML of el.
13937 startEdit : function(el, value){
13939 this.completeEdit();
13941 this.boundEl = Roo.get(el);
13942 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13943 if(!this.rendered){
13944 this.render(this.parentEl || document.body);
13946 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13949 this.startValue = v;
13950 this.field.setValue(v);
13952 var sz = this.boundEl.getSize();
13953 switch(this.autoSize){
13955 this.setSize(sz.width, "");
13958 this.setSize("", sz.height);
13961 this.setSize(sz.width, sz.height);
13964 this.el.alignTo(this.boundEl, this.alignment);
13965 this.editing = true;
13967 Roo.QuickTips.disable();
13973 * Sets the height and width of this editor.
13974 * @param {Number} width The new width
13975 * @param {Number} height The new height
13977 setSize : function(w, h){
13978 this.field.setSize(w, h);
13985 * Realigns the editor to the bound field based on the current alignment config value.
13987 realign : function(){
13988 this.el.alignTo(this.boundEl, this.alignment);
13992 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13993 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13995 completeEdit : function(remainVisible){
13999 var v = this.getValue();
14000 if(this.revertInvalid !== false && !this.field.isValid()){
14001 v = this.startValue;
14002 this.cancelEdit(true);
14004 if(String(v) === String(this.startValue) && this.ignoreNoChange){
14005 this.editing = false;
14009 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
14010 this.editing = false;
14011 if(this.updateEl && this.boundEl){
14012 this.boundEl.update(v);
14014 if(remainVisible !== true){
14017 this.fireEvent("complete", this, v, this.startValue);
14022 onShow : function(){
14024 if(this.hideEl !== false){
14025 this.boundEl.hide();
14028 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14029 this.fixIEFocus = true;
14030 this.deferredFocus.defer(50, this);
14032 this.field.focus();
14034 this.fireEvent("startedit", this.boundEl, this.startValue);
14037 deferredFocus : function(){
14039 this.field.focus();
14044 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14045 * reverted to the original starting value.
14046 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14047 * cancel (defaults to false)
14049 cancelEdit : function(remainVisible){
14051 this.setValue(this.startValue);
14052 if(remainVisible !== true){
14059 onBlur : function(){
14060 if(this.allowBlur !== true && this.editing){
14061 this.completeEdit();
14066 onHide : function(){
14068 this.completeEdit();
14072 if(this.field.collapse){
14073 this.field.collapse();
14076 if(this.hideEl !== false){
14077 this.boundEl.show();
14080 Roo.QuickTips.enable();
14085 * Sets the data value of the editor
14086 * @param {Mixed} value Any valid value supported by the underlying field
14088 setValue : function(v){
14089 this.field.setValue(v);
14093 * Gets the data value of the editor
14094 * @return {Mixed} The data value
14096 getValue : function(){
14097 return this.field.getValue();
14101 * Ext JS Library 1.1.1
14102 * Copyright(c) 2006-2007, Ext JS, LLC.
14104 * Originally Released Under LGPL - original licence link has changed is not relivant.
14107 * <script type="text/javascript">
14111 * @class Roo.BasicDialog
14112 * @extends Roo.util.Observable
14113 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14115 var dlg = new Roo.BasicDialog("my-dlg", {
14124 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14125 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14126 dlg.addButton('Cancel', dlg.hide, dlg);
14129 <b>A Dialog should always be a direct child of the body element.</b>
14130 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14131 * @cfg {String} title Default text to display in the title bar (defaults to null)
14132 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14133 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14134 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14135 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14136 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14137 * (defaults to null with no animation)
14138 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14139 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14140 * property for valid values (defaults to 'all')
14141 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14142 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14143 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14144 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14145 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14146 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14147 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14148 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14149 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14150 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14151 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14152 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14153 * draggable = true (defaults to false)
14154 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14155 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14156 * shadow (defaults to false)
14157 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14158 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14159 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14160 * @cfg {Array} buttons Array of buttons
14161 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14163 * Create a new BasicDialog.
14164 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14165 * @param {Object} config Configuration options
14167 Roo.BasicDialog = function(el, config){
14168 this.el = Roo.get(el);
14169 var dh = Roo.DomHelper;
14170 if(!this.el && config && config.autoCreate){
14171 if(typeof config.autoCreate == "object"){
14172 if(!config.autoCreate.id){
14173 config.autoCreate.id = el;
14175 this.el = dh.append(document.body,
14176 config.autoCreate, true);
14178 this.el = dh.append(document.body,
14179 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14183 el.setDisplayed(true);
14184 el.hide = this.hideAction;
14186 el.addClass("x-dlg");
14188 Roo.apply(this, config);
14190 this.proxy = el.createProxy("x-dlg-proxy");
14191 this.proxy.hide = this.hideAction;
14192 this.proxy.setOpacity(.5);
14196 el.setWidth(config.width);
14199 el.setHeight(config.height);
14201 this.size = el.getSize();
14202 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14203 this.xy = [config.x,config.y];
14205 this.xy = el.getCenterXY(true);
14207 /** The header element @type Roo.Element */
14208 this.header = el.child("> .x-dlg-hd");
14209 /** The body element @type Roo.Element */
14210 this.body = el.child("> .x-dlg-bd");
14211 /** The footer element @type Roo.Element */
14212 this.footer = el.child("> .x-dlg-ft");
14215 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14218 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14221 this.header.unselectable();
14223 this.header.update(this.title);
14225 // this element allows the dialog to be focused for keyboard event
14226 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14227 this.focusEl.swallowEvent("click", true);
14229 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14231 // wrap the body and footer for special rendering
14232 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14234 this.bwrap.dom.appendChild(this.footer.dom);
14237 this.bg = this.el.createChild({
14238 tag: "div", cls:"x-dlg-bg",
14239 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14241 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14244 if(this.autoScroll !== false && !this.autoTabs){
14245 this.body.setStyle("overflow", "auto");
14248 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14250 if(this.closable !== false){
14251 this.el.addClass("x-dlg-closable");
14252 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14253 this.close.on("click", this.closeClick, this);
14254 this.close.addClassOnOver("x-dlg-close-over");
14256 if(this.collapsible !== false){
14257 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14258 this.collapseBtn.on("click", this.collapseClick, this);
14259 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14260 this.header.on("dblclick", this.collapseClick, this);
14262 if(this.resizable !== false){
14263 this.el.addClass("x-dlg-resizable");
14264 this.resizer = new Roo.Resizable(el, {
14265 minWidth: this.minWidth || 80,
14266 minHeight:this.minHeight || 80,
14267 handles: this.resizeHandles || "all",
14270 this.resizer.on("beforeresize", this.beforeResize, this);
14271 this.resizer.on("resize", this.onResize, this);
14273 if(this.draggable !== false){
14274 el.addClass("x-dlg-draggable");
14275 if (!this.proxyDrag) {
14276 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14279 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14281 dd.setHandleElId(this.header.id);
14282 dd.endDrag = this.endMove.createDelegate(this);
14283 dd.startDrag = this.startMove.createDelegate(this);
14284 dd.onDrag = this.onDrag.createDelegate(this);
14289 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14290 this.mask.enableDisplayMode("block");
14292 this.el.addClass("x-dlg-modal");
14295 this.shadow = new Roo.Shadow({
14296 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14297 offset : this.shadowOffset
14300 this.shadowOffset = 0;
14302 if(Roo.useShims && this.shim !== false){
14303 this.shim = this.el.createShim();
14304 this.shim.hide = this.hideAction;
14312 if (this.buttons) {
14313 var bts= this.buttons;
14315 Roo.each(bts, function(b) {
14324 * Fires when a key is pressed
14325 * @param {Roo.BasicDialog} this
14326 * @param {Roo.EventObject} e
14331 * Fires when this dialog is moved by the user.
14332 * @param {Roo.BasicDialog} this
14333 * @param {Number} x The new page X
14334 * @param {Number} y The new page Y
14339 * Fires when this dialog is resized by the user.
14340 * @param {Roo.BasicDialog} this
14341 * @param {Number} width The new width
14342 * @param {Number} height The new height
14346 * @event beforehide
14347 * Fires before this dialog is hidden.
14348 * @param {Roo.BasicDialog} this
14350 "beforehide" : true,
14353 * Fires when this dialog is hidden.
14354 * @param {Roo.BasicDialog} this
14358 * @event beforeshow
14359 * Fires before this dialog is shown.
14360 * @param {Roo.BasicDialog} this
14362 "beforeshow" : true,
14365 * Fires when this dialog is shown.
14366 * @param {Roo.BasicDialog} this
14370 el.on("keydown", this.onKeyDown, this);
14371 el.on("mousedown", this.toFront, this);
14372 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14374 Roo.DialogManager.register(this);
14375 Roo.BasicDialog.superclass.constructor.call(this);
14378 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14379 shadowOffset: Roo.isIE ? 6 : 5,
14382 minButtonWidth: 75,
14383 defaultButton: null,
14384 buttonAlign: "right",
14389 * Sets the dialog title text
14390 * @param {String} text The title text to display
14391 * @return {Roo.BasicDialog} this
14393 setTitle : function(text){
14394 this.header.update(text);
14399 closeClick : function(){
14404 collapseClick : function(){
14405 this[this.collapsed ? "expand" : "collapse"]();
14409 * Collapses the dialog to its minimized state (only the title bar is visible).
14410 * Equivalent to the user clicking the collapse dialog button.
14412 collapse : function(){
14413 if(!this.collapsed){
14414 this.collapsed = true;
14415 this.el.addClass("x-dlg-collapsed");
14416 this.restoreHeight = this.el.getHeight();
14417 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14422 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14423 * clicking the expand dialog button.
14425 expand : function(){
14426 if(this.collapsed){
14427 this.collapsed = false;
14428 this.el.removeClass("x-dlg-collapsed");
14429 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14434 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14435 * @return {Roo.TabPanel} The tabs component
14437 initTabs : function(){
14438 var tabs = this.getTabs();
14439 while(tabs.getTab(0)){
14442 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14444 tabs.addTab(Roo.id(dom), dom.title);
14452 beforeResize : function(){
14453 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14457 onResize : function(){
14458 this.refreshSize();
14459 this.syncBodyHeight();
14460 this.adjustAssets();
14462 this.fireEvent("resize", this, this.size.width, this.size.height);
14466 onKeyDown : function(e){
14467 if(this.isVisible()){
14468 this.fireEvent("keydown", this, e);
14473 * Resizes the dialog.
14474 * @param {Number} width
14475 * @param {Number} height
14476 * @return {Roo.BasicDialog} this
14478 resizeTo : function(width, height){
14479 this.el.setSize(width, height);
14480 this.size = {width: width, height: height};
14481 this.syncBodyHeight();
14482 if(this.fixedcenter){
14485 if(this.isVisible()){
14486 this.constrainXY();
14487 this.adjustAssets();
14489 this.fireEvent("resize", this, width, height);
14495 * Resizes the dialog to fit the specified content size.
14496 * @param {Number} width
14497 * @param {Number} height
14498 * @return {Roo.BasicDialog} this
14500 setContentSize : function(w, h){
14501 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14502 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14503 //if(!this.el.isBorderBox()){
14504 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14505 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14508 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14509 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14511 this.resizeTo(w, h);
14516 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14517 * executed in response to a particular key being pressed while the dialog is active.
14518 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14519 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14520 * @param {Function} fn The function to call
14521 * @param {Object} scope (optional) The scope of the function
14522 * @return {Roo.BasicDialog} this
14524 addKeyListener : function(key, fn, scope){
14525 var keyCode, shift, ctrl, alt;
14526 if(typeof key == "object" && !(key instanceof Array)){
14527 keyCode = key["key"];
14528 shift = key["shift"];
14529 ctrl = key["ctrl"];
14534 var handler = function(dlg, e){
14535 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14536 var k = e.getKey();
14537 if(keyCode instanceof Array){
14538 for(var i = 0, len = keyCode.length; i < len; i++){
14539 if(keyCode[i] == k){
14540 fn.call(scope || window, dlg, k, e);
14546 fn.call(scope || window, dlg, k, e);
14551 this.on("keydown", handler);
14556 * Returns the TabPanel component (creates it if it doesn't exist).
14557 * Note: If you wish to simply check for the existence of tabs without creating them,
14558 * check for a null 'tabs' property.
14559 * @return {Roo.TabPanel} The tabs component
14561 getTabs : function(){
14563 this.el.addClass("x-dlg-auto-tabs");
14564 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14565 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14571 * Adds a button to the footer section of the dialog.
14572 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14573 * object or a valid Roo.DomHelper element config
14574 * @param {Function} handler The function called when the button is clicked
14575 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14576 * @return {Roo.Button} The new button
14578 addButton : function(config, handler, scope){
14579 var dh = Roo.DomHelper;
14581 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14583 if(!this.btnContainer){
14584 var tb = this.footer.createChild({
14586 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14587 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14589 this.btnContainer = tb.firstChild.firstChild.firstChild;
14594 minWidth: this.minButtonWidth,
14597 if(typeof config == "string"){
14598 bconfig.text = config;
14601 bconfig.dhconfig = config;
14603 Roo.apply(bconfig, config);
14607 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14608 bconfig.position = Math.max(0, bconfig.position);
14609 fc = this.btnContainer.childNodes[bconfig.position];
14612 var btn = new Roo.Button(
14614 this.btnContainer.insertBefore(document.createElement("td"),fc)
14615 : this.btnContainer.appendChild(document.createElement("td")),
14616 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14619 this.syncBodyHeight();
14622 * Array of all the buttons that have been added to this dialog via addButton
14627 this.buttons.push(btn);
14632 * Sets the default button to be focused when the dialog is displayed.
14633 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14634 * @return {Roo.BasicDialog} this
14636 setDefaultButton : function(btn){
14637 this.defaultButton = btn;
14642 getHeaderFooterHeight : function(safe){
14645 height += this.header.getHeight();
14648 var fm = this.footer.getMargins();
14649 height += (this.footer.getHeight()+fm.top+fm.bottom);
14651 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14652 height += this.centerBg.getPadding("tb");
14657 syncBodyHeight : function(){
14658 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14659 var height = this.size.height - this.getHeaderFooterHeight(false);
14660 bd.setHeight(height-bd.getMargins("tb"));
14661 var hh = this.header.getHeight();
14662 var h = this.size.height-hh;
14664 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14665 bw.setHeight(h-cb.getPadding("tb"));
14666 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14667 bd.setWidth(bw.getWidth(true));
14669 this.tabs.syncHeight();
14671 this.tabs.el.repaint();
14677 * Restores the previous state of the dialog if Roo.state is configured.
14678 * @return {Roo.BasicDialog} this
14680 restoreState : function(){
14681 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14682 if(box && box.width){
14683 this.xy = [box.x, box.y];
14684 this.resizeTo(box.width, box.height);
14690 beforeShow : function(){
14692 if(this.fixedcenter){
14693 this.xy = this.el.getCenterXY(true);
14696 Roo.get(document.body).addClass("x-body-masked");
14697 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14700 this.constrainXY();
14704 animShow : function(){
14705 var b = Roo.get(this.animateTarget).getBox();
14706 this.proxy.setSize(b.width, b.height);
14707 this.proxy.setLocation(b.x, b.y);
14709 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14710 true, .35, this.showEl.createDelegate(this));
14714 * Shows the dialog.
14715 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14716 * @return {Roo.BasicDialog} this
14718 show : function(animateTarget){
14719 if (this.fireEvent("beforeshow", this) === false){
14722 if(this.syncHeightBeforeShow){
14723 this.syncBodyHeight();
14724 }else if(this.firstShow){
14725 this.firstShow = false;
14726 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14728 this.animateTarget = animateTarget || this.animateTarget;
14729 if(!this.el.isVisible()){
14731 if(this.animateTarget && Roo.get(this.animateTarget)){
14741 showEl : function(){
14743 this.el.setXY(this.xy);
14745 this.adjustAssets(true);
14748 // IE peekaboo bug - fix found by Dave Fenwick
14752 this.fireEvent("show", this);
14756 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14757 * dialog itself will receive focus.
14759 focus : function(){
14760 if(this.defaultButton){
14761 this.defaultButton.focus();
14763 this.focusEl.focus();
14768 constrainXY : function(){
14769 if(this.constraintoviewport !== false){
14770 if(!this.viewSize){
14771 if(this.container){
14772 var s = this.container.getSize();
14773 this.viewSize = [s.width, s.height];
14775 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14778 var s = Roo.get(this.container||document).getScroll();
14780 var x = this.xy[0], y = this.xy[1];
14781 var w = this.size.width, h = this.size.height;
14782 var vw = this.viewSize[0], vh = this.viewSize[1];
14783 // only move it if it needs it
14785 // first validate right/bottom
14786 if(x + w > vw+s.left){
14790 if(y + h > vh+s.top){
14794 // then make sure top/left isn't negative
14806 if(this.isVisible()){
14807 this.el.setLocation(x, y);
14808 this.adjustAssets();
14815 onDrag : function(){
14816 if(!this.proxyDrag){
14817 this.xy = this.el.getXY();
14818 this.adjustAssets();
14823 adjustAssets : function(doShow){
14824 var x = this.xy[0], y = this.xy[1];
14825 var w = this.size.width, h = this.size.height;
14826 if(doShow === true){
14828 this.shadow.show(this.el);
14834 if(this.shadow && this.shadow.isVisible()){
14835 this.shadow.show(this.el);
14837 if(this.shim && this.shim.isVisible()){
14838 this.shim.setBounds(x, y, w, h);
14843 adjustViewport : function(w, h){
14845 w = Roo.lib.Dom.getViewWidth();
14846 h = Roo.lib.Dom.getViewHeight();
14849 this.viewSize = [w, h];
14850 if(this.modal && this.mask.isVisible()){
14851 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14852 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14854 if(this.isVisible()){
14855 this.constrainXY();
14860 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14861 * shadow, proxy, mask, etc.) Also removes all event listeners.
14862 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14864 destroy : function(removeEl){
14865 if(this.isVisible()){
14866 this.animateTarget = null;
14869 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14871 this.tabs.destroy(removeEl);
14884 for(var i = 0, len = this.buttons.length; i < len; i++){
14885 this.buttons[i].destroy();
14888 this.el.removeAllListeners();
14889 if(removeEl === true){
14890 this.el.update("");
14893 Roo.DialogManager.unregister(this);
14897 startMove : function(){
14898 if(this.proxyDrag){
14901 if(this.constraintoviewport !== false){
14902 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14907 endMove : function(){
14908 if(!this.proxyDrag){
14909 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14911 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14914 this.refreshSize();
14915 this.adjustAssets();
14917 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14921 * Brings this dialog to the front of any other visible dialogs
14922 * @return {Roo.BasicDialog} this
14924 toFront : function(){
14925 Roo.DialogManager.bringToFront(this);
14930 * Sends this dialog to the back (under) of any other visible dialogs
14931 * @return {Roo.BasicDialog} this
14933 toBack : function(){
14934 Roo.DialogManager.sendToBack(this);
14939 * Centers this dialog in the viewport
14940 * @return {Roo.BasicDialog} this
14942 center : function(){
14943 var xy = this.el.getCenterXY(true);
14944 this.moveTo(xy[0], xy[1]);
14949 * Moves the dialog's top-left corner to the specified point
14950 * @param {Number} x
14951 * @param {Number} y
14952 * @return {Roo.BasicDialog} this
14954 moveTo : function(x, y){
14956 if(this.isVisible()){
14957 this.el.setXY(this.xy);
14958 this.adjustAssets();
14964 * Aligns the dialog to the specified element
14965 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14966 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14967 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14968 * @return {Roo.BasicDialog} this
14970 alignTo : function(element, position, offsets){
14971 this.xy = this.el.getAlignToXY(element, position, offsets);
14972 if(this.isVisible()){
14973 this.el.setXY(this.xy);
14974 this.adjustAssets();
14980 * Anchors an element to another element and realigns it when the window is resized.
14981 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14982 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14983 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14984 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14985 * is a number, it is used as the buffer delay (defaults to 50ms).
14986 * @return {Roo.BasicDialog} this
14988 anchorTo : function(el, alignment, offsets, monitorScroll){
14989 var action = function(){
14990 this.alignTo(el, alignment, offsets);
14992 Roo.EventManager.onWindowResize(action, this);
14993 var tm = typeof monitorScroll;
14994 if(tm != 'undefined'){
14995 Roo.EventManager.on(window, 'scroll', action, this,
14996 {buffer: tm == 'number' ? monitorScroll : 50});
15003 * Returns true if the dialog is visible
15004 * @return {Boolean}
15006 isVisible : function(){
15007 return this.el.isVisible();
15011 animHide : function(callback){
15012 var b = Roo.get(this.animateTarget).getBox();
15014 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15016 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15017 this.hideEl.createDelegate(this, [callback]));
15021 * Hides the dialog.
15022 * @param {Function} callback (optional) Function to call when the dialog is hidden
15023 * @return {Roo.BasicDialog} this
15025 hide : function(callback){
15026 if (this.fireEvent("beforehide", this) === false){
15030 this.shadow.hide();
15035 // sometimes animateTarget seems to get set.. causing problems...
15036 // this just double checks..
15037 if(this.animateTarget && Roo.get(this.animateTarget)) {
15038 this.animHide(callback);
15041 this.hideEl(callback);
15047 hideEl : function(callback){
15051 Roo.get(document.body).removeClass("x-body-masked");
15053 this.fireEvent("hide", this);
15054 if(typeof callback == "function"){
15060 hideAction : function(){
15061 this.setLeft("-10000px");
15062 this.setTop("-10000px");
15063 this.setStyle("visibility", "hidden");
15067 refreshSize : function(){
15068 this.size = this.el.getSize();
15069 this.xy = this.el.getXY();
15070 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15074 // z-index is managed by the DialogManager and may be overwritten at any time
15075 setZIndex : function(index){
15077 this.mask.setStyle("z-index", index);
15080 this.shim.setStyle("z-index", ++index);
15083 this.shadow.setZIndex(++index);
15085 this.el.setStyle("z-index", ++index);
15087 this.proxy.setStyle("z-index", ++index);
15090 this.resizer.proxy.setStyle("z-index", ++index);
15093 this.lastZIndex = index;
15097 * Returns the element for this dialog
15098 * @return {Roo.Element} The underlying dialog Element
15100 getEl : function(){
15106 * @class Roo.DialogManager
15107 * Provides global access to BasicDialogs that have been created and
15108 * support for z-indexing (layering) multiple open dialogs.
15110 Roo.DialogManager = function(){
15112 var accessList = [];
15116 var sortDialogs = function(d1, d2){
15117 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15121 var orderDialogs = function(){
15122 accessList.sort(sortDialogs);
15123 var seed = Roo.DialogManager.zseed;
15124 for(var i = 0, len = accessList.length; i < len; i++){
15125 var dlg = accessList[i];
15127 dlg.setZIndex(seed + (i*10));
15134 * The starting z-index for BasicDialogs (defaults to 9000)
15135 * @type Number The z-index value
15140 register : function(dlg){
15141 list[dlg.id] = dlg;
15142 accessList.push(dlg);
15146 unregister : function(dlg){
15147 delete list[dlg.id];
15150 if(!accessList.indexOf){
15151 for( i = 0, len = accessList.length; i < len; i++){
15152 if(accessList[i] == dlg){
15153 accessList.splice(i, 1);
15158 i = accessList.indexOf(dlg);
15160 accessList.splice(i, 1);
15166 * Gets a registered dialog by id
15167 * @param {String/Object} id The id of the dialog or a dialog
15168 * @return {Roo.BasicDialog} this
15170 get : function(id){
15171 return typeof id == "object" ? id : list[id];
15175 * Brings the specified dialog to the front
15176 * @param {String/Object} dlg The id of the dialog or a dialog
15177 * @return {Roo.BasicDialog} this
15179 bringToFront : function(dlg){
15180 dlg = this.get(dlg);
15183 dlg._lastAccess = new Date().getTime();
15190 * Sends the specified dialog to the back
15191 * @param {String/Object} dlg The id of the dialog or a dialog
15192 * @return {Roo.BasicDialog} this
15194 sendToBack : function(dlg){
15195 dlg = this.get(dlg);
15196 dlg._lastAccess = -(new Date().getTime());
15202 * Hides all dialogs
15204 hideAll : function(){
15205 for(var id in list){
15206 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15215 * @class Roo.LayoutDialog
15216 * @extends Roo.BasicDialog
15217 * Dialog which provides adjustments for working with a layout in a Dialog.
15218 * Add your necessary layout config options to the dialog's config.<br>
15219 * Example usage (including a nested layout):
15222 dialog = new Roo.LayoutDialog("download-dlg", {
15231 // layout config merges with the dialog config
15233 tabPosition: "top",
15234 alwaysShowTabs: true
15237 dialog.addKeyListener(27, dialog.hide, dialog);
15238 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15239 dialog.addButton("Build It!", this.getDownload, this);
15241 // we can even add nested layouts
15242 var innerLayout = new Roo.BorderLayout("dl-inner", {
15252 innerLayout.beginUpdate();
15253 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15254 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15255 innerLayout.endUpdate(true);
15257 var layout = dialog.getLayout();
15258 layout.beginUpdate();
15259 layout.add("center", new Roo.ContentPanel("standard-panel",
15260 {title: "Download the Source", fitToFrame:true}));
15261 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15262 {title: "Build your own roo.js"}));
15263 layout.getRegion("center").showPanel(sp);
15264 layout.endUpdate();
15268 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15269 * @param {Object} config configuration options
15271 Roo.LayoutDialog = function(el, cfg){
15274 if (typeof(cfg) == 'undefined') {
15275 config = Roo.apply({}, el);
15276 // not sure why we use documentElement here.. - it should always be body.
15277 // IE7 borks horribly if we use documentElement.
15278 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15279 //config.autoCreate = true;
15283 config.autoTabs = false;
15284 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15285 this.body.setStyle({overflow:"hidden", position:"relative"});
15286 this.layout = new Roo.BorderLayout(this.body.dom, config);
15287 this.layout.monitorWindowResize = false;
15288 this.el.addClass("x-dlg-auto-layout");
15289 // fix case when center region overwrites center function
15290 this.center = Roo.BasicDialog.prototype.center;
15291 this.on("show", this.layout.layout, this.layout, true);
15292 if (config.items) {
15293 var xitems = config.items;
15294 delete config.items;
15295 Roo.each(xitems, this.addxtype, this);
15300 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15302 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15305 endUpdate : function(){
15306 this.layout.endUpdate();
15310 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15313 beginUpdate : function(){
15314 this.layout.beginUpdate();
15318 * Get the BorderLayout for this dialog
15319 * @return {Roo.BorderLayout}
15321 getLayout : function(){
15322 return this.layout;
15325 showEl : function(){
15326 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15328 this.layout.layout();
15333 // Use the syncHeightBeforeShow config option to control this automatically
15334 syncBodyHeight : function(){
15335 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15336 if(this.layout){this.layout.layout();}
15340 * Add an xtype element (actually adds to the layout.)
15341 * @return {Object} xdata xtype object data.
15344 addxtype : function(c) {
15345 return this.layout.addxtype(c);
15349 * Ext JS Library 1.1.1
15350 * Copyright(c) 2006-2007, Ext JS, LLC.
15352 * Originally Released Under LGPL - original licence link has changed is not relivant.
15355 * <script type="text/javascript">
15359 * @class Roo.MessageBox
15360 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15364 Roo.Msg.alert('Status', 'Changes saved successfully.');
15366 // Prompt for user data:
15367 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15369 // process text value...
15373 // Show a dialog using config options:
15375 title:'Save Changes?',
15376 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15377 buttons: Roo.Msg.YESNOCANCEL,
15384 Roo.MessageBox = function(){
15385 var dlg, opt, mask, waitTimer;
15386 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15387 var buttons, activeTextEl, bwidth;
15390 var handleButton = function(button){
15392 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15396 var handleHide = function(){
15397 if(opt && opt.cls){
15398 dlg.el.removeClass(opt.cls);
15401 Roo.TaskMgr.stop(waitTimer);
15407 var updateButtons = function(b){
15410 buttons["ok"].hide();
15411 buttons["cancel"].hide();
15412 buttons["yes"].hide();
15413 buttons["no"].hide();
15414 dlg.footer.dom.style.display = 'none';
15417 dlg.footer.dom.style.display = '';
15418 for(var k in buttons){
15419 if(typeof buttons[k] != "function"){
15422 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15423 width += buttons[k].el.getWidth()+15;
15433 var handleEsc = function(d, k, e){
15434 if(opt && opt.closable !== false){
15444 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15445 * @return {Roo.BasicDialog} The BasicDialog element
15447 getDialog : function(){
15449 dlg = new Roo.BasicDialog("x-msg-box", {
15454 constraintoviewport:false,
15456 collapsible : false,
15459 width:400, height:100,
15460 buttonAlign:"center",
15461 closeClick : function(){
15462 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15463 handleButton("no");
15465 handleButton("cancel");
15469 dlg.on("hide", handleHide);
15471 dlg.addKeyListener(27, handleEsc);
15473 var bt = this.buttonText;
15474 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15475 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15476 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15477 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15478 bodyEl = dlg.body.createChild({
15480 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>'
15482 msgEl = bodyEl.dom.firstChild;
15483 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15484 textboxEl.enableDisplayMode();
15485 textboxEl.addKeyListener([10,13], function(){
15486 if(dlg.isVisible() && opt && opt.buttons){
15487 if(opt.buttons.ok){
15488 handleButton("ok");
15489 }else if(opt.buttons.yes){
15490 handleButton("yes");
15494 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15495 textareaEl.enableDisplayMode();
15496 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15497 progressEl.enableDisplayMode();
15498 var pf = progressEl.dom.firstChild;
15500 pp = Roo.get(pf.firstChild);
15501 pp.setHeight(pf.offsetHeight);
15509 * Updates the message box body text
15510 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15511 * the XHTML-compliant non-breaking space character '&#160;')
15512 * @return {Roo.MessageBox} This message box
15514 updateText : function(text){
15515 if(!dlg.isVisible() && !opt.width){
15516 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15518 msgEl.innerHTML = text || ' ';
15519 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15520 Math.max(opt.minWidth || this.minWidth, bwidth));
15522 activeTextEl.setWidth(w);
15524 if(dlg.isVisible()){
15525 dlg.fixedcenter = false;
15527 dlg.setContentSize(w, bodyEl.getHeight());
15528 if(dlg.isVisible()){
15529 dlg.fixedcenter = true;
15535 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15536 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15537 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15538 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15539 * @return {Roo.MessageBox} This message box
15541 updateProgress : function(value, text){
15543 this.updateText(text);
15545 if (pp) { // weird bug on my firefox - for some reason this is not defined
15546 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15552 * Returns true if the message box is currently displayed
15553 * @return {Boolean} True if the message box is visible, else false
15555 isVisible : function(){
15556 return dlg && dlg.isVisible();
15560 * Hides the message box if it is displayed
15563 if(this.isVisible()){
15569 * Displays a new message box, or reinitializes an existing message box, based on the config options
15570 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15571 * The following config object properties are supported:
15573 Property Type Description
15574 ---------- --------------- ------------------------------------------------------------------------------------
15575 animEl String/Element An id or Element from which the message box should animate as it opens and
15576 closes (defaults to undefined)
15577 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15578 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15579 closable Boolean False to hide the top-right close button (defaults to true). Note that
15580 progress and wait dialogs will ignore this property and always hide the
15581 close button as they can only be closed programmatically.
15582 cls String A custom CSS class to apply to the message box element
15583 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15584 displayed (defaults to 75)
15585 fn Function A callback function to execute after closing the dialog. The arguments to the
15586 function will be btn (the name of the button that was clicked, if applicable,
15587 e.g. "ok"), and text (the value of the active text field, if applicable).
15588 Progress and wait dialogs will ignore this option since they do not respond to
15589 user actions and can only be closed programmatically, so any required function
15590 should be called by the same code after it closes the dialog.
15591 icon String A CSS class that provides a background image to be used as an icon for
15592 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15593 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15594 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15595 modal Boolean False to allow user interaction with the page while the message box is
15596 displayed (defaults to true)
15597 msg String A string that will replace the existing message box body text (defaults
15598 to the XHTML-compliant non-breaking space character ' ')
15599 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15600 progress Boolean True to display a progress bar (defaults to false)
15601 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15602 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15603 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15604 title String The title text
15605 value String The string value to set into the active textbox element if displayed
15606 wait Boolean True to display a progress bar (defaults to false)
15607 width Number The width of the dialog in pixels
15614 msg: 'Please enter your address:',
15616 buttons: Roo.MessageBox.OKCANCEL,
15619 animEl: 'addAddressBtn'
15622 * @param {Object} config Configuration options
15623 * @return {Roo.MessageBox} This message box
15625 show : function(options){
15626 if(this.isVisible()){
15629 var d = this.getDialog();
15631 d.setTitle(opt.title || " ");
15632 d.close.setDisplayed(opt.closable !== false);
15633 activeTextEl = textboxEl;
15634 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15639 textareaEl.setHeight(typeof opt.multiline == "number" ?
15640 opt.multiline : this.defaultTextHeight);
15641 activeTextEl = textareaEl;
15650 progressEl.setDisplayed(opt.progress === true);
15651 this.updateProgress(0);
15652 activeTextEl.dom.value = opt.value || "";
15654 dlg.setDefaultButton(activeTextEl);
15656 var bs = opt.buttons;
15659 db = buttons["ok"];
15660 }else if(bs && bs.yes){
15661 db = buttons["yes"];
15663 dlg.setDefaultButton(db);
15665 bwidth = updateButtons(opt.buttons);
15666 this.updateText(opt.msg);
15668 d.el.addClass(opt.cls);
15670 d.proxyDrag = opt.proxyDrag === true;
15671 d.modal = opt.modal !== false;
15672 d.mask = opt.modal !== false ? mask : false;
15673 if(!d.isVisible()){
15674 // force it to the end of the z-index stack so it gets a cursor in FF
15675 document.body.appendChild(dlg.el.dom);
15676 d.animateTarget = null;
15677 d.show(options.animEl);
15683 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15684 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15685 * and closing the message box when the process is complete.
15686 * @param {String} title The title bar text
15687 * @param {String} msg The message box body text
15688 * @return {Roo.MessageBox} This message box
15690 progress : function(title, msg){
15697 minWidth: this.minProgressWidth,
15704 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15705 * If a callback function is passed it will be called after the user clicks the button, and the
15706 * id of the button that was clicked will be passed as the only parameter to the callback
15707 * (could also be the top-right close button).
15708 * @param {String} title The title bar text
15709 * @param {String} msg The message box body text
15710 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15711 * @param {Object} scope (optional) The scope of the callback function
15712 * @return {Roo.MessageBox} This message box
15714 alert : function(title, msg, fn, scope){
15727 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15728 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15729 * You are responsible for closing the message box when the process is complete.
15730 * @param {String} msg The message box body text
15731 * @param {String} title (optional) The title bar text
15732 * @return {Roo.MessageBox} This message box
15734 wait : function(msg, title){
15745 waitTimer = Roo.TaskMgr.start({
15747 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15755 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15756 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15757 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15758 * @param {String} title The title bar text
15759 * @param {String} msg The message box body text
15760 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15761 * @param {Object} scope (optional) The scope of the callback function
15762 * @return {Roo.MessageBox} This message box
15764 confirm : function(title, msg, fn, scope){
15768 buttons: this.YESNO,
15777 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15778 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15779 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15780 * (could also be the top-right close button) and the text that was entered will be passed as the two
15781 * parameters to the callback.
15782 * @param {String} title The title bar text
15783 * @param {String} msg The message box body text
15784 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15785 * @param {Object} scope (optional) The scope of the callback function
15786 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15787 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15788 * @return {Roo.MessageBox} This message box
15790 prompt : function(title, msg, fn, scope, multiline){
15794 buttons: this.OKCANCEL,
15799 multiline: multiline,
15806 * Button config that displays a single OK button
15811 * Button config that displays Yes and No buttons
15814 YESNO : {yes:true, no:true},
15816 * Button config that displays OK and Cancel buttons
15819 OKCANCEL : {ok:true, cancel:true},
15821 * Button config that displays Yes, No and Cancel buttons
15824 YESNOCANCEL : {yes:true, no:true, cancel:true},
15827 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15830 defaultTextHeight : 75,
15832 * The maximum width in pixels of the message box (defaults to 600)
15837 * The minimum width in pixels of the message box (defaults to 100)
15842 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15843 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15846 minProgressWidth : 250,
15848 * An object containing the default button text strings that can be overriden for localized language support.
15849 * Supported properties are: ok, cancel, yes and no.
15850 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15863 * Shorthand for {@link Roo.MessageBox}
15865 Roo.Msg = Roo.MessageBox;/*
15867 * Ext JS Library 1.1.1
15868 * Copyright(c) 2006-2007, Ext JS, LLC.
15870 * Originally Released Under LGPL - original licence link has changed is not relivant.
15873 * <script type="text/javascript">
15876 * @class Roo.QuickTips
15877 * Provides attractive and customizable tooltips for any element.
15880 Roo.QuickTips = function(){
15881 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15882 var ce, bd, xy, dd;
15883 var visible = false, disabled = true, inited = false;
15884 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15886 var onOver = function(e){
15890 var t = e.getTarget();
15891 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15894 if(ce && t == ce.el){
15895 clearTimeout(hideProc);
15898 if(t && tagEls[t.id]){
15899 tagEls[t.id].el = t;
15900 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15903 var ttp, et = Roo.fly(t);
15904 var ns = cfg.namespace;
15905 if(tm.interceptTitles && t.title){
15908 t.removeAttribute("title");
15909 e.preventDefault();
15911 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15914 showProc = show.defer(tm.showDelay, tm, [{
15917 width: et.getAttributeNS(ns, cfg.width),
15918 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15919 title: et.getAttributeNS(ns, cfg.title),
15920 cls: et.getAttributeNS(ns, cfg.cls)
15925 var onOut = function(e){
15926 clearTimeout(showProc);
15927 var t = e.getTarget();
15928 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15929 hideProc = setTimeout(hide, tm.hideDelay);
15933 var onMove = function(e){
15939 if(tm.trackMouse && ce){
15944 var onDown = function(e){
15945 clearTimeout(showProc);
15946 clearTimeout(hideProc);
15948 if(tm.hideOnClick){
15951 tm.enable.defer(100, tm);
15956 var getPad = function(){
15957 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15960 var show = function(o){
15964 clearTimeout(dismissProc);
15966 if(removeCls){ // in case manually hidden
15967 el.removeClass(removeCls);
15971 el.addClass(ce.cls);
15972 removeCls = ce.cls;
15975 tipTitle.update(ce.title);
15978 tipTitle.update('');
15981 el.dom.style.width = tm.maxWidth+'px';
15982 //tipBody.dom.style.width = '';
15983 tipBodyText.update(o.text);
15984 var p = getPad(), w = ce.width;
15986 var td = tipBodyText.dom;
15987 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15988 if(aw > tm.maxWidth){
15990 }else if(aw < tm.minWidth){
15996 //tipBody.setWidth(w);
15997 el.setWidth(parseInt(w, 10) + p);
15998 if(ce.autoHide === false){
15999 close.setDisplayed(true);
16004 close.setDisplayed(false);
16010 el.avoidY = xy[1]-18;
16015 el.setStyle("visibility", "visible");
16016 el.fadeIn({callback: afterShow});
16022 var afterShow = function(){
16026 if(tm.autoDismiss && ce.autoHide !== false){
16027 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16032 var hide = function(noanim){
16033 clearTimeout(dismissProc);
16034 clearTimeout(hideProc);
16036 if(el.isVisible()){
16038 if(noanim !== true && tm.animate){
16039 el.fadeOut({callback: afterHide});
16046 var afterHide = function(){
16049 el.removeClass(removeCls);
16056 * @cfg {Number} minWidth
16057 * The minimum width of the quick tip (defaults to 40)
16061 * @cfg {Number} maxWidth
16062 * The maximum width of the quick tip (defaults to 300)
16066 * @cfg {Boolean} interceptTitles
16067 * True to automatically use the element's DOM title value if available (defaults to false)
16069 interceptTitles : false,
16071 * @cfg {Boolean} trackMouse
16072 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16074 trackMouse : false,
16076 * @cfg {Boolean} hideOnClick
16077 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16079 hideOnClick : true,
16081 * @cfg {Number} showDelay
16082 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16086 * @cfg {Number} hideDelay
16087 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16091 * @cfg {Boolean} autoHide
16092 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16093 * Used in conjunction with hideDelay.
16098 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16099 * (defaults to true). Used in conjunction with autoDismissDelay.
16101 autoDismiss : true,
16104 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16106 autoDismissDelay : 5000,
16108 * @cfg {Boolean} animate
16109 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16114 * @cfg {String} title
16115 * Title text to display (defaults to ''). This can be any valid HTML markup.
16119 * @cfg {String} text
16120 * Body text to display (defaults to ''). This can be any valid HTML markup.
16124 * @cfg {String} cls
16125 * A CSS class to apply to the base quick tip element (defaults to '').
16129 * @cfg {Number} width
16130 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16131 * minWidth or maxWidth.
16136 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16137 * or display QuickTips in a page.
16140 tm = Roo.QuickTips;
16141 cfg = tm.tagConfig;
16143 if(!Roo.isReady){ // allow calling of init() before onReady
16144 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16147 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16148 el.fxDefaults = {stopFx: true};
16149 // maximum custom styling
16150 //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>');
16151 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>');
16152 tipTitle = el.child('h3');
16153 tipTitle.enableDisplayMode("block");
16154 tipBody = el.child('div.x-tip-bd');
16155 tipBodyText = el.child('div.x-tip-bd-inner');
16156 //bdLeft = el.child('div.x-tip-bd-left');
16157 //bdRight = el.child('div.x-tip-bd-right');
16158 close = el.child('div.x-tip-close');
16159 close.enableDisplayMode("block");
16160 close.on("click", hide);
16161 var d = Roo.get(document);
16162 d.on("mousedown", onDown);
16163 d.on("mouseover", onOver);
16164 d.on("mouseout", onOut);
16165 d.on("mousemove", onMove);
16166 esc = d.addKeyListener(27, hide);
16169 dd = el.initDD("default", null, {
16170 onDrag : function(){
16174 dd.setHandleElId(tipTitle.id);
16183 * Configures a new quick tip instance and assigns it to a target element. The following config options
16186 Property Type Description
16187 ---------- --------------------- ------------------------------------------------------------------------
16188 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16190 * @param {Object} config The config object
16192 register : function(config){
16193 var cs = config instanceof Array ? config : arguments;
16194 for(var i = 0, len = cs.length; i < len; i++) {
16196 var target = c.target;
16198 if(target instanceof Array){
16199 for(var j = 0, jlen = target.length; j < jlen; j++){
16200 tagEls[target[j]] = c;
16203 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16210 * Removes this quick tip from its element and destroys it.
16211 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16213 unregister : function(el){
16214 delete tagEls[Roo.id(el)];
16218 * Enable this quick tip.
16220 enable : function(){
16221 if(inited && disabled){
16223 if(locks.length < 1){
16230 * Disable this quick tip.
16232 disable : function(){
16234 clearTimeout(showProc);
16235 clearTimeout(hideProc);
16236 clearTimeout(dismissProc);
16244 * Returns true if the quick tip is enabled, else false.
16246 isEnabled : function(){
16253 attribute : "qtip",
16263 // backwards compat
16264 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16266 * Ext JS Library 1.1.1
16267 * Copyright(c) 2006-2007, Ext JS, LLC.
16269 * Originally Released Under LGPL - original licence link has changed is not relivant.
16272 * <script type="text/javascript">
16277 * @class Roo.tree.TreePanel
16278 * @extends Roo.data.Tree
16280 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16281 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16282 * @cfg {Boolean} enableDD true to enable drag and drop
16283 * @cfg {Boolean} enableDrag true to enable just drag
16284 * @cfg {Boolean} enableDrop true to enable just drop
16285 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16286 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16287 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16288 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16289 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16290 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16291 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16292 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16293 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16294 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16295 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16296 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16297 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16298 * @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>
16299 * @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>
16302 * @param {String/HTMLElement/Element} el The container element
16303 * @param {Object} config
16305 Roo.tree.TreePanel = function(el, config){
16307 var loader = false;
16309 root = config.root;
16310 delete config.root;
16312 if (config.loader) {
16313 loader = config.loader;
16314 delete config.loader;
16317 Roo.apply(this, config);
16318 Roo.tree.TreePanel.superclass.constructor.call(this);
16319 this.el = Roo.get(el);
16320 this.el.addClass('x-tree');
16321 //console.log(root);
16323 this.setRootNode( Roo.factory(root, Roo.tree));
16326 this.loader = Roo.factory(loader, Roo.tree);
16329 * Read-only. The id of the container element becomes this TreePanel's id.
16331 this.id = this.el.id;
16334 * @event beforeload
16335 * Fires before a node is loaded, return false to cancel
16336 * @param {Node} node The node being loaded
16338 "beforeload" : true,
16341 * Fires when a node is loaded
16342 * @param {Node} node The node that was loaded
16346 * @event textchange
16347 * Fires when the text for a node is changed
16348 * @param {Node} node The node
16349 * @param {String} text The new text
16350 * @param {String} oldText The old text
16352 "textchange" : true,
16354 * @event beforeexpand
16355 * Fires before a node is expanded, return false to cancel.
16356 * @param {Node} node The node
16357 * @param {Boolean} deep
16358 * @param {Boolean} anim
16360 "beforeexpand" : true,
16362 * @event beforecollapse
16363 * Fires before a node is collapsed, return false to cancel.
16364 * @param {Node} node The node
16365 * @param {Boolean} deep
16366 * @param {Boolean} anim
16368 "beforecollapse" : true,
16371 * Fires when a node is expanded
16372 * @param {Node} node The node
16376 * @event disabledchange
16377 * Fires when the disabled status of a node changes
16378 * @param {Node} node The node
16379 * @param {Boolean} disabled
16381 "disabledchange" : true,
16384 * Fires when a node is collapsed
16385 * @param {Node} node The node
16389 * @event beforeclick
16390 * Fires before click processing on a node. Return false to cancel the default action.
16391 * @param {Node} node The node
16392 * @param {Roo.EventObject} e The event object
16394 "beforeclick":true,
16396 * @event checkchange
16397 * Fires when a node with a checkbox's checked property changes
16398 * @param {Node} this This node
16399 * @param {Boolean} checked
16401 "checkchange":true,
16404 * Fires when a node is clicked
16405 * @param {Node} node The node
16406 * @param {Roo.EventObject} e The event object
16411 * Fires when a node is double clicked
16412 * @param {Node} node The node
16413 * @param {Roo.EventObject} e The event object
16417 * @event contextmenu
16418 * Fires when a node is right clicked
16419 * @param {Node} node The node
16420 * @param {Roo.EventObject} e The event object
16422 "contextmenu":true,
16424 * @event beforechildrenrendered
16425 * Fires right before the child nodes for a node are rendered
16426 * @param {Node} node The node
16428 "beforechildrenrendered":true,
16431 * Fires when a node starts being dragged
16432 * @param {Roo.tree.TreePanel} this
16433 * @param {Roo.tree.TreeNode} node
16434 * @param {event} e The raw browser event
16436 "startdrag" : true,
16439 * Fires when a drag operation is complete
16440 * @param {Roo.tree.TreePanel} this
16441 * @param {Roo.tree.TreeNode} node
16442 * @param {event} e The raw browser event
16447 * Fires when a dragged node is dropped on a valid DD target
16448 * @param {Roo.tree.TreePanel} this
16449 * @param {Roo.tree.TreeNode} node
16450 * @param {DD} dd The dd it was dropped on
16451 * @param {event} e The raw browser event
16455 * @event beforenodedrop
16456 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16457 * passed to handlers has the following properties:<br />
16458 * <ul style="padding:5px;padding-left:16px;">
16459 * <li>tree - The TreePanel</li>
16460 * <li>target - The node being targeted for the drop</li>
16461 * <li>data - The drag data from the drag source</li>
16462 * <li>point - The point of the drop - append, above or below</li>
16463 * <li>source - The drag source</li>
16464 * <li>rawEvent - Raw mouse event</li>
16465 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16466 * to be inserted by setting them on this object.</li>
16467 * <li>cancel - Set this to true to cancel the drop.</li>
16469 * @param {Object} dropEvent
16471 "beforenodedrop" : true,
16474 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16475 * passed to handlers has the following properties:<br />
16476 * <ul style="padding:5px;padding-left:16px;">
16477 * <li>tree - The TreePanel</li>
16478 * <li>target - The node being targeted for the drop</li>
16479 * <li>data - The drag data from the drag source</li>
16480 * <li>point - The point of the drop - append, above or below</li>
16481 * <li>source - The drag source</li>
16482 * <li>rawEvent - Raw mouse event</li>
16483 * <li>dropNode - Dropped node(s).</li>
16485 * @param {Object} dropEvent
16489 * @event nodedragover
16490 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16491 * passed to handlers has the following properties:<br />
16492 * <ul style="padding:5px;padding-left:16px;">
16493 * <li>tree - The TreePanel</li>
16494 * <li>target - The node being targeted for the drop</li>
16495 * <li>data - The drag data from the drag source</li>
16496 * <li>point - The point of the drop - append, above or below</li>
16497 * <li>source - The drag source</li>
16498 * <li>rawEvent - Raw mouse event</li>
16499 * <li>dropNode - Drop node(s) provided by the source.</li>
16500 * <li>cancel - Set this to true to signal drop not allowed.</li>
16502 * @param {Object} dragOverEvent
16504 "nodedragover" : true
16507 if(this.singleExpand){
16508 this.on("beforeexpand", this.restrictExpand, this);
16511 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16512 rootVisible : true,
16513 animate: Roo.enableFx,
16516 hlDrop : Roo.enableFx,
16520 rendererTip: false,
16522 restrictExpand : function(node){
16523 var p = node.parentNode;
16525 if(p.expandedChild && p.expandedChild.parentNode == p){
16526 p.expandedChild.collapse();
16528 p.expandedChild = node;
16532 // private override
16533 setRootNode : function(node){
16534 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16535 if(!this.rootVisible){
16536 node.ui = new Roo.tree.RootTreeNodeUI(node);
16542 * Returns the container element for this TreePanel
16544 getEl : function(){
16549 * Returns the default TreeLoader for this TreePanel
16551 getLoader : function(){
16552 return this.loader;
16558 expandAll : function(){
16559 this.root.expand(true);
16563 * Collapse all nodes
16565 collapseAll : function(){
16566 this.root.collapse(true);
16570 * Returns the selection model used by this TreePanel
16572 getSelectionModel : function(){
16573 if(!this.selModel){
16574 this.selModel = new Roo.tree.DefaultSelectionModel();
16576 return this.selModel;
16580 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16581 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16582 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16585 getChecked : function(a, startNode){
16586 startNode = startNode || this.root;
16588 var f = function(){
16589 if(this.attributes.checked){
16590 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16593 startNode.cascade(f);
16598 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16599 * @param {String} path
16600 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16601 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16602 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16604 expandPath : function(path, attr, callback){
16605 attr = attr || "id";
16606 var keys = path.split(this.pathSeparator);
16607 var curNode = this.root;
16608 if(curNode.attributes[attr] != keys[1]){ // invalid root
16610 callback(false, null);
16615 var f = function(){
16616 if(++index == keys.length){
16618 callback(true, curNode);
16622 var c = curNode.findChild(attr, keys[index]);
16625 callback(false, curNode);
16630 c.expand(false, false, f);
16632 curNode.expand(false, false, f);
16636 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16637 * @param {String} path
16638 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16639 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16640 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16642 selectPath : function(path, attr, callback){
16643 attr = attr || "id";
16644 var keys = path.split(this.pathSeparator);
16645 var v = keys.pop();
16646 if(keys.length > 0){
16647 var f = function(success, node){
16648 if(success && node){
16649 var n = node.findChild(attr, v);
16655 }else if(callback){
16656 callback(false, n);
16660 callback(false, n);
16664 this.expandPath(keys.join(this.pathSeparator), attr, f);
16666 this.root.select();
16668 callback(true, this.root);
16673 getTreeEl : function(){
16678 * Trigger rendering of this TreePanel
16680 render : function(){
16681 if (this.innerCt) {
16682 return this; // stop it rendering more than once!!
16685 this.innerCt = this.el.createChild({tag:"ul",
16686 cls:"x-tree-root-ct " +
16687 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16689 if(this.containerScroll){
16690 Roo.dd.ScrollManager.register(this.el);
16692 if((this.enableDD || this.enableDrop) && !this.dropZone){
16694 * The dropZone used by this tree if drop is enabled
16695 * @type Roo.tree.TreeDropZone
16697 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16698 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16701 if((this.enableDD || this.enableDrag) && !this.dragZone){
16703 * The dragZone used by this tree if drag is enabled
16704 * @type Roo.tree.TreeDragZone
16706 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16707 ddGroup: this.ddGroup || "TreeDD",
16708 scroll: this.ddScroll
16711 this.getSelectionModel().init(this);
16713 console.log("ROOT not set in tree");
16716 this.root.render();
16717 if(!this.rootVisible){
16718 this.root.renderChildren();
16724 * Ext JS Library 1.1.1
16725 * Copyright(c) 2006-2007, Ext JS, LLC.
16727 * Originally Released Under LGPL - original licence link has changed is not relivant.
16730 * <script type="text/javascript">
16735 * @class Roo.tree.DefaultSelectionModel
16736 * @extends Roo.util.Observable
16737 * The default single selection for a TreePanel.
16739 Roo.tree.DefaultSelectionModel = function(){
16740 this.selNode = null;
16744 * @event selectionchange
16745 * Fires when the selected node changes
16746 * @param {DefaultSelectionModel} this
16747 * @param {TreeNode} node the new selection
16749 "selectionchange" : true,
16752 * @event beforeselect
16753 * Fires before the selected node changes, return false to cancel the change
16754 * @param {DefaultSelectionModel} this
16755 * @param {TreeNode} node the new selection
16756 * @param {TreeNode} node the old selection
16758 "beforeselect" : true
16762 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16763 init : function(tree){
16765 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16766 tree.on("click", this.onNodeClick, this);
16769 onNodeClick : function(node, e){
16770 if (e.ctrlKey && this.selNode == node) {
16771 this.unselect(node);
16779 * @param {TreeNode} node The node to select
16780 * @return {TreeNode} The selected node
16782 select : function(node){
16783 var last = this.selNode;
16784 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16786 last.ui.onSelectedChange(false);
16788 this.selNode = node;
16789 node.ui.onSelectedChange(true);
16790 this.fireEvent("selectionchange", this, node, last);
16797 * @param {TreeNode} node The node to unselect
16799 unselect : function(node){
16800 if(this.selNode == node){
16801 this.clearSelections();
16806 * Clear all selections
16808 clearSelections : function(){
16809 var n = this.selNode;
16811 n.ui.onSelectedChange(false);
16812 this.selNode = null;
16813 this.fireEvent("selectionchange", this, null);
16819 * Get the selected node
16820 * @return {TreeNode} The selected node
16822 getSelectedNode : function(){
16823 return this.selNode;
16827 * Returns true if the node is selected
16828 * @param {TreeNode} node The node to check
16829 * @return {Boolean}
16831 isSelected : function(node){
16832 return this.selNode == node;
16836 * Selects the node above the selected node in the tree, intelligently walking the nodes
16837 * @return TreeNode The new selection
16839 selectPrevious : function(){
16840 var s = this.selNode || this.lastSelNode;
16844 var ps = s.previousSibling;
16846 if(!ps.isExpanded() || ps.childNodes.length < 1){
16847 return this.select(ps);
16849 var lc = ps.lastChild;
16850 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16853 return this.select(lc);
16855 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16856 return this.select(s.parentNode);
16862 * Selects the node above the selected node in the tree, intelligently walking the nodes
16863 * @return TreeNode The new selection
16865 selectNext : function(){
16866 var s = this.selNode || this.lastSelNode;
16870 if(s.firstChild && s.isExpanded()){
16871 return this.select(s.firstChild);
16872 }else if(s.nextSibling){
16873 return this.select(s.nextSibling);
16874 }else if(s.parentNode){
16876 s.parentNode.bubble(function(){
16877 if(this.nextSibling){
16878 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16887 onKeyDown : function(e){
16888 var s = this.selNode || this.lastSelNode;
16889 // undesirable, but required
16894 var k = e.getKey();
16902 this.selectPrevious();
16905 e.preventDefault();
16906 if(s.hasChildNodes()){
16907 if(!s.isExpanded()){
16909 }else if(s.firstChild){
16910 this.select(s.firstChild, e);
16915 e.preventDefault();
16916 if(s.hasChildNodes() && s.isExpanded()){
16918 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16919 this.select(s.parentNode, e);
16927 * @class Roo.tree.MultiSelectionModel
16928 * @extends Roo.util.Observable
16929 * Multi selection for a TreePanel.
16931 Roo.tree.MultiSelectionModel = function(){
16932 this.selNodes = [];
16936 * @event selectionchange
16937 * Fires when the selected nodes change
16938 * @param {MultiSelectionModel} this
16939 * @param {Array} nodes Array of the selected nodes
16941 "selectionchange" : true
16945 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16946 init : function(tree){
16948 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16949 tree.on("click", this.onNodeClick, this);
16952 onNodeClick : function(node, e){
16953 this.select(node, e, e.ctrlKey);
16958 * @param {TreeNode} node The node to select
16959 * @param {EventObject} e (optional) An event associated with the selection
16960 * @param {Boolean} keepExisting True to retain existing selections
16961 * @return {TreeNode} The selected node
16963 select : function(node, e, keepExisting){
16964 if(keepExisting !== true){
16965 this.clearSelections(true);
16967 if(this.isSelected(node)){
16968 this.lastSelNode = node;
16971 this.selNodes.push(node);
16972 this.selMap[node.id] = node;
16973 this.lastSelNode = node;
16974 node.ui.onSelectedChange(true);
16975 this.fireEvent("selectionchange", this, this.selNodes);
16981 * @param {TreeNode} node The node to unselect
16983 unselect : function(node){
16984 if(this.selMap[node.id]){
16985 node.ui.onSelectedChange(false);
16986 var sn = this.selNodes;
16989 index = sn.indexOf(node);
16991 for(var i = 0, len = sn.length; i < len; i++){
16999 this.selNodes.splice(index, 1);
17001 delete this.selMap[node.id];
17002 this.fireEvent("selectionchange", this, this.selNodes);
17007 * Clear all selections
17009 clearSelections : function(suppressEvent){
17010 var sn = this.selNodes;
17012 for(var i = 0, len = sn.length; i < len; i++){
17013 sn[i].ui.onSelectedChange(false);
17015 this.selNodes = [];
17017 if(suppressEvent !== true){
17018 this.fireEvent("selectionchange", this, this.selNodes);
17024 * Returns true if the node is selected
17025 * @param {TreeNode} node The node to check
17026 * @return {Boolean}
17028 isSelected : function(node){
17029 return this.selMap[node.id] ? true : false;
17033 * Returns an array of the selected nodes
17036 getSelectedNodes : function(){
17037 return this.selNodes;
17040 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17042 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17044 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17047 * Ext JS Library 1.1.1
17048 * Copyright(c) 2006-2007, Ext JS, LLC.
17050 * Originally Released Under LGPL - original licence link has changed is not relivant.
17053 * <script type="text/javascript">
17057 * @class Roo.tree.TreeNode
17058 * @extends Roo.data.Node
17059 * @cfg {String} text The text for this node
17060 * @cfg {Boolean} expanded true to start the node expanded
17061 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17062 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17063 * @cfg {Boolean} disabled true to start the node disabled
17064 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17065 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17066 * @cfg {String} cls A css class to be added to the node
17067 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17068 * @cfg {String} href URL of the link used for the node (defaults to #)
17069 * @cfg {String} hrefTarget target frame for the link
17070 * @cfg {String} qtip An Ext QuickTip for the node
17071 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17072 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17073 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17074 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17075 * (defaults to undefined with no checkbox rendered)
17077 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17079 Roo.tree.TreeNode = function(attributes){
17080 attributes = attributes || {};
17081 if(typeof attributes == "string"){
17082 attributes = {text: attributes};
17084 this.childrenRendered = false;
17085 this.rendered = false;
17086 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17087 this.expanded = attributes.expanded === true;
17088 this.isTarget = attributes.isTarget !== false;
17089 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17090 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17093 * Read-only. The text for this node. To change it use setText().
17096 this.text = attributes.text;
17098 * True if this node is disabled.
17101 this.disabled = attributes.disabled === true;
17105 * @event textchange
17106 * Fires when the text for this node is changed
17107 * @param {Node} this This node
17108 * @param {String} text The new text
17109 * @param {String} oldText The old text
17111 "textchange" : true,
17113 * @event beforeexpand
17114 * Fires before this node is expanded, return false to cancel.
17115 * @param {Node} this This node
17116 * @param {Boolean} deep
17117 * @param {Boolean} anim
17119 "beforeexpand" : true,
17121 * @event beforecollapse
17122 * Fires before this node is collapsed, return false to cancel.
17123 * @param {Node} this This node
17124 * @param {Boolean} deep
17125 * @param {Boolean} anim
17127 "beforecollapse" : true,
17130 * Fires when this node is expanded
17131 * @param {Node} this This node
17135 * @event disabledchange
17136 * Fires when the disabled status of this node changes
17137 * @param {Node} this This node
17138 * @param {Boolean} disabled
17140 "disabledchange" : true,
17143 * Fires when this node is collapsed
17144 * @param {Node} this This node
17148 * @event beforeclick
17149 * Fires before click processing. Return false to cancel the default action.
17150 * @param {Node} this This node
17151 * @param {Roo.EventObject} e The event object
17153 "beforeclick":true,
17155 * @event checkchange
17156 * Fires when a node with a checkbox's checked property changes
17157 * @param {Node} this This node
17158 * @param {Boolean} checked
17160 "checkchange":true,
17163 * Fires when this node is clicked
17164 * @param {Node} this This node
17165 * @param {Roo.EventObject} e The event object
17170 * Fires when this node is double clicked
17171 * @param {Node} this This node
17172 * @param {Roo.EventObject} e The event object
17176 * @event contextmenu
17177 * Fires when this node is right clicked
17178 * @param {Node} this This node
17179 * @param {Roo.EventObject} e The event object
17181 "contextmenu":true,
17183 * @event beforechildrenrendered
17184 * Fires right before the child nodes for this node are rendered
17185 * @param {Node} this This node
17187 "beforechildrenrendered":true
17190 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17193 * Read-only. The UI for this node
17196 this.ui = new uiClass(this);
17198 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17199 preventHScroll: true,
17201 * Returns true if this node is expanded
17202 * @return {Boolean}
17204 isExpanded : function(){
17205 return this.expanded;
17209 * Returns the UI object for this node
17210 * @return {TreeNodeUI}
17212 getUI : function(){
17216 // private override
17217 setFirstChild : function(node){
17218 var of = this.firstChild;
17219 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17220 if(this.childrenRendered && of && node != of){
17221 of.renderIndent(true, true);
17224 this.renderIndent(true, true);
17228 // private override
17229 setLastChild : function(node){
17230 var ol = this.lastChild;
17231 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17232 if(this.childrenRendered && ol && node != ol){
17233 ol.renderIndent(true, true);
17236 this.renderIndent(true, true);
17240 // these methods are overridden to provide lazy rendering support
17241 // private override
17242 appendChild : function(){
17243 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17244 if(node && this.childrenRendered){
17247 this.ui.updateExpandIcon();
17251 // private override
17252 removeChild : function(node){
17253 this.ownerTree.getSelectionModel().unselect(node);
17254 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17255 // if it's been rendered remove dom node
17256 if(this.childrenRendered){
17259 if(this.childNodes.length < 1){
17260 this.collapse(false, false);
17262 this.ui.updateExpandIcon();
17264 if(!this.firstChild) {
17265 this.childrenRendered = false;
17270 // private override
17271 insertBefore : function(node, refNode){
17272 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17273 if(newNode && refNode && this.childrenRendered){
17276 this.ui.updateExpandIcon();
17281 * Sets the text for this node
17282 * @param {String} text
17284 setText : function(text){
17285 var oldText = this.text;
17287 this.attributes.text = text;
17288 if(this.rendered){ // event without subscribing
17289 this.ui.onTextChange(this, text, oldText);
17291 this.fireEvent("textchange", this, text, oldText);
17295 * Triggers selection of this node
17297 select : function(){
17298 this.getOwnerTree().getSelectionModel().select(this);
17302 * Triggers deselection of this node
17304 unselect : function(){
17305 this.getOwnerTree().getSelectionModel().unselect(this);
17309 * Returns true if this node is selected
17310 * @return {Boolean}
17312 isSelected : function(){
17313 return this.getOwnerTree().getSelectionModel().isSelected(this);
17317 * Expand this node.
17318 * @param {Boolean} deep (optional) True to expand all children as well
17319 * @param {Boolean} anim (optional) false to cancel the default animation
17320 * @param {Function} callback (optional) A callback to be called when
17321 * expanding this node completes (does not wait for deep expand to complete).
17322 * Called with 1 parameter, this node.
17324 expand : function(deep, anim, callback){
17325 if(!this.expanded){
17326 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17329 if(!this.childrenRendered){
17330 this.renderChildren();
17332 this.expanded = true;
17333 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17334 this.ui.animExpand(function(){
17335 this.fireEvent("expand", this);
17336 if(typeof callback == "function"){
17340 this.expandChildNodes(true);
17342 }.createDelegate(this));
17346 this.fireEvent("expand", this);
17347 if(typeof callback == "function"){
17352 if(typeof callback == "function"){
17357 this.expandChildNodes(true);
17361 isHiddenRoot : function(){
17362 return this.isRoot && !this.getOwnerTree().rootVisible;
17366 * Collapse this node.
17367 * @param {Boolean} deep (optional) True to collapse all children as well
17368 * @param {Boolean} anim (optional) false to cancel the default animation
17370 collapse : function(deep, anim){
17371 if(this.expanded && !this.isHiddenRoot()){
17372 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17375 this.expanded = false;
17376 if((this.getOwnerTree().animate && anim !== false) || anim){
17377 this.ui.animCollapse(function(){
17378 this.fireEvent("collapse", this);
17380 this.collapseChildNodes(true);
17382 }.createDelegate(this));
17385 this.ui.collapse();
17386 this.fireEvent("collapse", this);
17390 var cs = this.childNodes;
17391 for(var i = 0, len = cs.length; i < len; i++) {
17392 cs[i].collapse(true, false);
17398 delayedExpand : function(delay){
17399 if(!this.expandProcId){
17400 this.expandProcId = this.expand.defer(delay, this);
17405 cancelExpand : function(){
17406 if(this.expandProcId){
17407 clearTimeout(this.expandProcId);
17409 this.expandProcId = false;
17413 * Toggles expanded/collapsed state of the node
17415 toggle : function(){
17424 * Ensures all parent nodes are expanded
17426 ensureVisible : function(callback){
17427 var tree = this.getOwnerTree();
17428 tree.expandPath(this.parentNode.getPath(), false, function(){
17429 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17430 Roo.callback(callback);
17431 }.createDelegate(this));
17435 * Expand all child nodes
17436 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17438 expandChildNodes : function(deep){
17439 var cs = this.childNodes;
17440 for(var i = 0, len = cs.length; i < len; i++) {
17441 cs[i].expand(deep);
17446 * Collapse all child nodes
17447 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17449 collapseChildNodes : function(deep){
17450 var cs = this.childNodes;
17451 for(var i = 0, len = cs.length; i < len; i++) {
17452 cs[i].collapse(deep);
17457 * Disables this node
17459 disable : function(){
17460 this.disabled = true;
17462 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17463 this.ui.onDisableChange(this, true);
17465 this.fireEvent("disabledchange", this, true);
17469 * Enables this node
17471 enable : function(){
17472 this.disabled = false;
17473 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17474 this.ui.onDisableChange(this, false);
17476 this.fireEvent("disabledchange", this, false);
17480 renderChildren : function(suppressEvent){
17481 if(suppressEvent !== false){
17482 this.fireEvent("beforechildrenrendered", this);
17484 var cs = this.childNodes;
17485 for(var i = 0, len = cs.length; i < len; i++){
17486 cs[i].render(true);
17488 this.childrenRendered = true;
17492 sort : function(fn, scope){
17493 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17494 if(this.childrenRendered){
17495 var cs = this.childNodes;
17496 for(var i = 0, len = cs.length; i < len; i++){
17497 cs[i].render(true);
17503 render : function(bulkRender){
17504 this.ui.render(bulkRender);
17505 if(!this.rendered){
17506 this.rendered = true;
17508 this.expanded = false;
17509 this.expand(false, false);
17515 renderIndent : function(deep, refresh){
17517 this.ui.childIndent = null;
17519 this.ui.renderIndent();
17520 if(deep === true && this.childrenRendered){
17521 var cs = this.childNodes;
17522 for(var i = 0, len = cs.length; i < len; i++){
17523 cs[i].renderIndent(true, refresh);
17529 * Ext JS Library 1.1.1
17530 * Copyright(c) 2006-2007, Ext JS, LLC.
17532 * Originally Released Under LGPL - original licence link has changed is not relivant.
17535 * <script type="text/javascript">
17539 * @class Roo.tree.AsyncTreeNode
17540 * @extends Roo.tree.TreeNode
17541 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17543 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17545 Roo.tree.AsyncTreeNode = function(config){
17546 this.loaded = false;
17547 this.loading = false;
17548 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17550 * @event beforeload
17551 * Fires before this node is loaded, return false to cancel
17552 * @param {Node} this This node
17554 this.addEvents({'beforeload':true, 'load': true});
17557 * Fires when this node is loaded
17558 * @param {Node} this This node
17561 * The loader used by this node (defaults to using the tree's defined loader)
17566 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17567 expand : function(deep, anim, callback){
17568 if(this.loading){ // if an async load is already running, waiting til it's done
17570 var f = function(){
17571 if(!this.loading){ // done loading
17572 clearInterval(timer);
17573 this.expand(deep, anim, callback);
17575 }.createDelegate(this);
17576 timer = setInterval(f, 200);
17580 if(this.fireEvent("beforeload", this) === false){
17583 this.loading = true;
17584 this.ui.beforeLoad(this);
17585 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17587 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17591 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17595 * Returns true if this node is currently loading
17596 * @return {Boolean}
17598 isLoading : function(){
17599 return this.loading;
17602 loadComplete : function(deep, anim, callback){
17603 this.loading = false;
17604 this.loaded = true;
17605 this.ui.afterLoad(this);
17606 this.fireEvent("load", this);
17607 this.expand(deep, anim, callback);
17611 * Returns true if this node has been loaded
17612 * @return {Boolean}
17614 isLoaded : function(){
17615 return this.loaded;
17618 hasChildNodes : function(){
17619 if(!this.isLeaf() && !this.loaded){
17622 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17627 * Trigger a reload for this node
17628 * @param {Function} callback
17630 reload : function(callback){
17631 this.collapse(false, false);
17632 while(this.firstChild){
17633 this.removeChild(this.firstChild);
17635 this.childrenRendered = false;
17636 this.loaded = false;
17637 if(this.isHiddenRoot()){
17638 this.expanded = false;
17640 this.expand(false, false, callback);
17644 * Ext JS Library 1.1.1
17645 * Copyright(c) 2006-2007, Ext JS, LLC.
17647 * Originally Released Under LGPL - original licence link has changed is not relivant.
17650 * <script type="text/javascript">
17654 * @class Roo.tree.TreeNodeUI
17656 * @param {Object} node The node to render
17657 * The TreeNode UI implementation is separate from the
17658 * tree implementation. Unless you are customizing the tree UI,
17659 * you should never have to use this directly.
17661 Roo.tree.TreeNodeUI = function(node){
17663 this.rendered = false;
17664 this.animating = false;
17665 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17668 Roo.tree.TreeNodeUI.prototype = {
17669 removeChild : function(node){
17671 this.ctNode.removeChild(node.ui.getEl());
17675 beforeLoad : function(){
17676 this.addClass("x-tree-node-loading");
17679 afterLoad : function(){
17680 this.removeClass("x-tree-node-loading");
17683 onTextChange : function(node, text, oldText){
17685 this.textNode.innerHTML = text;
17689 onDisableChange : function(node, state){
17690 this.disabled = state;
17692 this.addClass("x-tree-node-disabled");
17694 this.removeClass("x-tree-node-disabled");
17698 onSelectedChange : function(state){
17701 this.addClass("x-tree-selected");
17704 this.removeClass("x-tree-selected");
17708 onMove : function(tree, node, oldParent, newParent, index, refNode){
17709 this.childIndent = null;
17711 var targetNode = newParent.ui.getContainer();
17712 if(!targetNode){//target not rendered
17713 this.holder = document.createElement("div");
17714 this.holder.appendChild(this.wrap);
17717 var insertBefore = refNode ? refNode.ui.getEl() : null;
17719 targetNode.insertBefore(this.wrap, insertBefore);
17721 targetNode.appendChild(this.wrap);
17723 this.node.renderIndent(true);
17727 addClass : function(cls){
17729 Roo.fly(this.elNode).addClass(cls);
17733 removeClass : function(cls){
17735 Roo.fly(this.elNode).removeClass(cls);
17739 remove : function(){
17741 this.holder = document.createElement("div");
17742 this.holder.appendChild(this.wrap);
17746 fireEvent : function(){
17747 return this.node.fireEvent.apply(this.node, arguments);
17750 initEvents : function(){
17751 this.node.on("move", this.onMove, this);
17752 var E = Roo.EventManager;
17753 var a = this.anchor;
17755 var el = Roo.fly(a, '_treeui');
17757 if(Roo.isOpera){ // opera render bug ignores the CSS
17758 el.setStyle("text-decoration", "none");
17761 el.on("click", this.onClick, this);
17762 el.on("dblclick", this.onDblClick, this);
17765 Roo.EventManager.on(this.checkbox,
17766 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17769 el.on("contextmenu", this.onContextMenu, this);
17771 var icon = Roo.fly(this.iconNode);
17772 icon.on("click", this.onClick, this);
17773 icon.on("dblclick", this.onDblClick, this);
17774 icon.on("contextmenu", this.onContextMenu, this);
17775 E.on(this.ecNode, "click", this.ecClick, this, true);
17777 if(this.node.disabled){
17778 this.addClass("x-tree-node-disabled");
17780 if(this.node.hidden){
17781 this.addClass("x-tree-node-disabled");
17783 var ot = this.node.getOwnerTree();
17784 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17785 if(dd && (!this.node.isRoot || ot.rootVisible)){
17786 Roo.dd.Registry.register(this.elNode, {
17788 handles: this.getDDHandles(),
17794 getDDHandles : function(){
17795 return [this.iconNode, this.textNode];
17800 this.wrap.style.display = "none";
17806 this.wrap.style.display = "";
17810 onContextMenu : function(e){
17811 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17812 e.preventDefault();
17814 this.fireEvent("contextmenu", this.node, e);
17818 onClick : function(e){
17823 if(this.fireEvent("beforeclick", this.node, e) !== false){
17824 if(!this.disabled && this.node.attributes.href){
17825 this.fireEvent("click", this.node, e);
17828 e.preventDefault();
17833 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17834 this.node.toggle();
17837 this.fireEvent("click", this.node, e);
17843 onDblClick : function(e){
17844 e.preventDefault();
17849 this.toggleCheck();
17851 if(!this.animating && this.node.hasChildNodes()){
17852 this.node.toggle();
17854 this.fireEvent("dblclick", this.node, e);
17857 onCheckChange : function(){
17858 var checked = this.checkbox.checked;
17859 this.node.attributes.checked = checked;
17860 this.fireEvent('checkchange', this.node, checked);
17863 ecClick : function(e){
17864 if(!this.animating && this.node.hasChildNodes()){
17865 this.node.toggle();
17869 startDrop : function(){
17870 this.dropping = true;
17873 // delayed drop so the click event doesn't get fired on a drop
17874 endDrop : function(){
17875 setTimeout(function(){
17876 this.dropping = false;
17877 }.createDelegate(this), 50);
17880 expand : function(){
17881 this.updateExpandIcon();
17882 this.ctNode.style.display = "";
17885 focus : function(){
17886 if(!this.node.preventHScroll){
17887 try{this.anchor.focus();
17889 }else if(!Roo.isIE){
17891 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17892 var l = noscroll.scrollLeft;
17893 this.anchor.focus();
17894 noscroll.scrollLeft = l;
17899 toggleCheck : function(value){
17900 var cb = this.checkbox;
17902 cb.checked = (value === undefined ? !cb.checked : value);
17908 this.anchor.blur();
17912 animExpand : function(callback){
17913 var ct = Roo.get(this.ctNode);
17915 if(!this.node.hasChildNodes()){
17916 this.updateExpandIcon();
17917 this.ctNode.style.display = "";
17918 Roo.callback(callback);
17921 this.animating = true;
17922 this.updateExpandIcon();
17925 callback : function(){
17926 this.animating = false;
17927 Roo.callback(callback);
17930 duration: this.node.ownerTree.duration || .25
17934 highlight : function(){
17935 var tree = this.node.getOwnerTree();
17936 Roo.fly(this.wrap).highlight(
17937 tree.hlColor || "C3DAF9",
17938 {endColor: tree.hlBaseColor}
17942 collapse : function(){
17943 this.updateExpandIcon();
17944 this.ctNode.style.display = "none";
17947 animCollapse : function(callback){
17948 var ct = Roo.get(this.ctNode);
17949 ct.enableDisplayMode('block');
17952 this.animating = true;
17953 this.updateExpandIcon();
17956 callback : function(){
17957 this.animating = false;
17958 Roo.callback(callback);
17961 duration: this.node.ownerTree.duration || .25
17965 getContainer : function(){
17966 return this.ctNode;
17969 getEl : function(){
17973 appendDDGhost : function(ghostNode){
17974 ghostNode.appendChild(this.elNode.cloneNode(true));
17977 getDDRepairXY : function(){
17978 return Roo.lib.Dom.getXY(this.iconNode);
17981 onRender : function(){
17985 render : function(bulkRender){
17986 var n = this.node, a = n.attributes;
17987 var targetNode = n.parentNode ?
17988 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17990 if(!this.rendered){
17991 this.rendered = true;
17993 this.renderElements(n, a, targetNode, bulkRender);
17996 if(this.textNode.setAttributeNS){
17997 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17999 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
18002 this.textNode.setAttribute("ext:qtip", a.qtip);
18004 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
18007 }else if(a.qtipCfg){
18008 a.qtipCfg.target = Roo.id(this.textNode);
18009 Roo.QuickTips.register(a.qtipCfg);
18012 if(!this.node.expanded){
18013 this.updateExpandIcon();
18016 if(bulkRender === true) {
18017 targetNode.appendChild(this.wrap);
18022 renderElements : function(n, a, targetNode, bulkRender){
18023 // add some indent caching, this helps performance when rendering a large tree
18024 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18025 var t = n.getOwnerTree();
18026 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18027 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18028 var cb = typeof a.checked == 'boolean';
18029 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18030 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18031 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18032 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18033 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18034 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18035 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18036 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18037 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18038 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18041 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18042 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18043 n.nextSibling.ui.getEl(), buf.join(""));
18045 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18048 this.elNode = this.wrap.childNodes[0];
18049 this.ctNode = this.wrap.childNodes[1];
18050 var cs = this.elNode.childNodes;
18051 this.indentNode = cs[0];
18052 this.ecNode = cs[1];
18053 this.iconNode = cs[2];
18056 this.checkbox = cs[3];
18059 this.anchor = cs[index];
18060 this.textNode = cs[index].firstChild;
18063 getAnchor : function(){
18064 return this.anchor;
18067 getTextEl : function(){
18068 return this.textNode;
18071 getIconEl : function(){
18072 return this.iconNode;
18075 isChecked : function(){
18076 return this.checkbox ? this.checkbox.checked : false;
18079 updateExpandIcon : function(){
18081 var n = this.node, c1, c2;
18082 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18083 var hasChild = n.hasChildNodes();
18087 c1 = "x-tree-node-collapsed";
18088 c2 = "x-tree-node-expanded";
18091 c1 = "x-tree-node-expanded";
18092 c2 = "x-tree-node-collapsed";
18095 this.removeClass("x-tree-node-leaf");
18096 this.wasLeaf = false;
18098 if(this.c1 != c1 || this.c2 != c2){
18099 Roo.fly(this.elNode).replaceClass(c1, c2);
18100 this.c1 = c1; this.c2 = c2;
18104 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18107 this.wasLeaf = true;
18110 var ecc = "x-tree-ec-icon "+cls;
18111 if(this.ecc != ecc){
18112 this.ecNode.className = ecc;
18118 getChildIndent : function(){
18119 if(!this.childIndent){
18123 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18125 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18127 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18132 this.childIndent = buf.join("");
18134 return this.childIndent;
18137 renderIndent : function(){
18140 var p = this.node.parentNode;
18142 indent = p.ui.getChildIndent();
18144 if(this.indentMarkup != indent){ // don't rerender if not required
18145 this.indentNode.innerHTML = indent;
18146 this.indentMarkup = indent;
18148 this.updateExpandIcon();
18153 Roo.tree.RootTreeNodeUI = function(){
18154 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18156 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18157 render : function(){
18158 if(!this.rendered){
18159 var targetNode = this.node.ownerTree.innerCt.dom;
18160 this.node.expanded = true;
18161 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18162 this.wrap = this.ctNode = targetNode.firstChild;
18165 collapse : function(){
18167 expand : function(){
18171 * Ext JS Library 1.1.1
18172 * Copyright(c) 2006-2007, Ext JS, LLC.
18174 * Originally Released Under LGPL - original licence link has changed is not relivant.
18177 * <script type="text/javascript">
18180 * @class Roo.tree.TreeLoader
18181 * @extends Roo.util.Observable
18182 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18183 * nodes from a specified URL. The response must be a javascript Array definition
18184 * who's elements are node definition objects. eg:
18186 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18187 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18190 * A server request is sent, and child nodes are loaded only when a node is expanded.
18191 * The loading node's id is passed to the server under the parameter name "node" to
18192 * enable the server to produce the correct child nodes.
18194 * To pass extra parameters, an event handler may be attached to the "beforeload"
18195 * event, and the parameters specified in the TreeLoader's baseParams property:
18197 myTreeLoader.on("beforeload", function(treeLoader, node) {
18198 this.baseParams.category = node.attributes.category;
18201 * This would pass an HTTP parameter called "category" to the server containing
18202 * the value of the Node's "category" attribute.
18204 * Creates a new Treeloader.
18205 * @param {Object} config A config object containing config properties.
18207 Roo.tree.TreeLoader = function(config){
18208 this.baseParams = {};
18209 this.requestMethod = "POST";
18210 Roo.apply(this, config);
18215 * @event beforeload
18216 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18217 * @param {Object} This TreeLoader object.
18218 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18219 * @param {Object} callback The callback function specified in the {@link #load} call.
18224 * Fires when the node has been successfuly loaded.
18225 * @param {Object} This TreeLoader object.
18226 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18227 * @param {Object} response The response object containing the data from the server.
18231 * @event loadexception
18232 * Fires if the network request failed.
18233 * @param {Object} This TreeLoader object.
18234 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18235 * @param {Object} response The response object containing the data from the server.
18237 loadexception : true,
18240 * Fires before a node is created, enabling you to return custom Node types
18241 * @param {Object} This TreeLoader object.
18242 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18247 Roo.tree.TreeLoader.superclass.constructor.call(this);
18250 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18252 * @cfg {String} dataUrl The URL from which to request a Json string which
18253 * specifies an array of node definition object representing the child nodes
18257 * @cfg {Object} baseParams (optional) An object containing properties which
18258 * specify HTTP parameters to be passed to each request for child nodes.
18261 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18262 * created by this loader. If the attributes sent by the server have an attribute in this object,
18263 * they take priority.
18266 * @cfg {Object} uiProviders (optional) An object containing properties which
18268 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18269 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18270 * <i>uiProvider</i> attribute of a returned child node is a string rather
18271 * than a reference to a TreeNodeUI implementation, this that string value
18272 * is used as a property name in the uiProviders object. You can define the provider named
18273 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18278 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18279 * child nodes before loading.
18281 clearOnLoad : true,
18284 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18285 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18286 * Grid query { data : [ .....] }
18291 * @cfg {String} queryParam (optional)
18292 * Name of the query as it will be passed on the querystring (defaults to 'node')
18293 * eg. the request will be ?node=[id]
18300 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18301 * This is called automatically when a node is expanded, but may be used to reload
18302 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18303 * @param {Roo.tree.TreeNode} node
18304 * @param {Function} callback
18306 load : function(node, callback){
18307 if(this.clearOnLoad){
18308 while(node.firstChild){
18309 node.removeChild(node.firstChild);
18312 if(node.attributes.children){ // preloaded json children
18313 var cs = node.attributes.children;
18314 for(var i = 0, len = cs.length; i < len; i++){
18315 node.appendChild(this.createNode(cs[i]));
18317 if(typeof callback == "function"){
18320 }else if(this.dataUrl){
18321 this.requestData(node, callback);
18325 getParams: function(node){
18326 var buf = [], bp = this.baseParams;
18327 for(var key in bp){
18328 if(typeof bp[key] != "function"){
18329 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18332 var n = this.queryParam === false ? 'node' : this.queryParam;
18333 buf.push(n + "=", encodeURIComponent(node.id));
18334 return buf.join("");
18337 requestData : function(node, callback){
18338 if(this.fireEvent("beforeload", this, node, callback) !== false){
18339 this.transId = Roo.Ajax.request({
18340 method:this.requestMethod,
18341 url: this.dataUrl||this.url,
18342 success: this.handleResponse,
18343 failure: this.handleFailure,
18345 argument: {callback: callback, node: node},
18346 params: this.getParams(node)
18349 // if the load is cancelled, make sure we notify
18350 // the node that we are done
18351 if(typeof callback == "function"){
18357 isLoading : function(){
18358 return this.transId ? true : false;
18361 abort : function(){
18362 if(this.isLoading()){
18363 Roo.Ajax.abort(this.transId);
18368 createNode : function(attr){
18369 // apply baseAttrs, nice idea Corey!
18370 if(this.baseAttrs){
18371 Roo.applyIf(attr, this.baseAttrs);
18373 if(this.applyLoader !== false){
18374 attr.loader = this;
18376 // uiProvider = depreciated..
18378 if(typeof(attr.uiProvider) == 'string'){
18379 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18380 /** eval:var:attr */ eval(attr.uiProvider);
18382 if(typeof(this.uiProviders['default']) != 'undefined') {
18383 attr.uiProvider = this.uiProviders['default'];
18386 this.fireEvent('create', this, attr);
18388 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18390 new Roo.tree.TreeNode(attr) :
18391 new Roo.tree.AsyncTreeNode(attr));
18394 processResponse : function(response, node, callback){
18395 var json = response.responseText;
18398 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18399 if (this.root !== false) {
18403 for(var i = 0, len = o.length; i < len; i++){
18404 var n = this.createNode(o[i]);
18406 node.appendChild(n);
18409 if(typeof callback == "function"){
18410 callback(this, node);
18413 this.handleFailure(response);
18417 handleResponse : function(response){
18418 this.transId = false;
18419 var a = response.argument;
18420 this.processResponse(response, a.node, a.callback);
18421 this.fireEvent("load", this, a.node, response);
18424 handleFailure : function(response){
18425 this.transId = false;
18426 var a = response.argument;
18427 this.fireEvent("loadexception", this, a.node, response);
18428 if(typeof a.callback == "function"){
18429 a.callback(this, a.node);
18434 * Ext JS Library 1.1.1
18435 * Copyright(c) 2006-2007, Ext JS, LLC.
18437 * Originally Released Under LGPL - original licence link has changed is not relivant.
18440 * <script type="text/javascript">
18444 * @class Roo.tree.TreeFilter
18445 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18446 * @param {TreePanel} tree
18447 * @param {Object} config (optional)
18449 Roo.tree.TreeFilter = function(tree, config){
18451 this.filtered = {};
18452 Roo.apply(this, config);
18455 Roo.tree.TreeFilter.prototype = {
18462 * Filter the data by a specific attribute.
18463 * @param {String/RegExp} value Either string that the attribute value
18464 * should start with or a RegExp to test against the attribute
18465 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18466 * @param {TreeNode} startNode (optional) The node to start the filter at.
18468 filter : function(value, attr, startNode){
18469 attr = attr || "text";
18471 if(typeof value == "string"){
18472 var vlen = value.length;
18473 // auto clear empty filter
18474 if(vlen == 0 && this.clearBlank){
18478 value = value.toLowerCase();
18480 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18482 }else if(value.exec){ // regex?
18484 return value.test(n.attributes[attr]);
18487 throw 'Illegal filter type, must be string or regex';
18489 this.filterBy(f, null, startNode);
18493 * Filter by a function. The passed function will be called with each
18494 * node in the tree (or from the startNode). If the function returns true, the node is kept
18495 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18496 * @param {Function} fn The filter function
18497 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18499 filterBy : function(fn, scope, startNode){
18500 startNode = startNode || this.tree.root;
18501 if(this.autoClear){
18504 var af = this.filtered, rv = this.reverse;
18505 var f = function(n){
18506 if(n == startNode){
18512 var m = fn.call(scope || n, n);
18520 startNode.cascade(f);
18523 if(typeof id != "function"){
18525 if(n && n.parentNode){
18526 n.parentNode.removeChild(n);
18534 * Clears the current filter. Note: with the "remove" option
18535 * set a filter cannot be cleared.
18537 clear : function(){
18539 var af = this.filtered;
18541 if(typeof id != "function"){
18548 this.filtered = {};
18553 * Ext JS Library 1.1.1
18554 * Copyright(c) 2006-2007, Ext JS, LLC.
18556 * Originally Released Under LGPL - original licence link has changed is not relivant.
18559 * <script type="text/javascript">
18564 * @class Roo.tree.TreeSorter
18565 * Provides sorting of nodes in a TreePanel
18567 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18568 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18569 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18570 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18571 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18572 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18574 * @param {TreePanel} tree
18575 * @param {Object} config
18577 Roo.tree.TreeSorter = function(tree, config){
18578 Roo.apply(this, config);
18579 tree.on("beforechildrenrendered", this.doSort, this);
18580 tree.on("append", this.updateSort, this);
18581 tree.on("insert", this.updateSort, this);
18583 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18584 var p = this.property || "text";
18585 var sortType = this.sortType;
18586 var fs = this.folderSort;
18587 var cs = this.caseSensitive === true;
18588 var leafAttr = this.leafAttr || 'leaf';
18590 this.sortFn = function(n1, n2){
18592 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18595 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18599 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18600 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18602 return dsc ? +1 : -1;
18604 return dsc ? -1 : +1;
18611 Roo.tree.TreeSorter.prototype = {
18612 doSort : function(node){
18613 node.sort(this.sortFn);
18616 compareNodes : function(n1, n2){
18617 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18620 updateSort : function(tree, node){
18621 if(node.childrenRendered){
18622 this.doSort.defer(1, this, [node]);
18627 * Ext JS Library 1.1.1
18628 * Copyright(c) 2006-2007, Ext JS, LLC.
18630 * Originally Released Under LGPL - original licence link has changed is not relivant.
18633 * <script type="text/javascript">
18636 if(Roo.dd.DropZone){
18638 Roo.tree.TreeDropZone = function(tree, config){
18639 this.allowParentInsert = false;
18640 this.allowContainerDrop = false;
18641 this.appendOnly = false;
18642 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18644 this.lastInsertClass = "x-tree-no-status";
18645 this.dragOverData = {};
18648 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18649 ddGroup : "TreeDD",
18651 expandDelay : 1000,
18653 expandNode : function(node){
18654 if(node.hasChildNodes() && !node.isExpanded()){
18655 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18659 queueExpand : function(node){
18660 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18663 cancelExpand : function(){
18664 if(this.expandProcId){
18665 clearTimeout(this.expandProcId);
18666 this.expandProcId = false;
18670 isValidDropPoint : function(n, pt, dd, e, data){
18671 if(!n || !data){ return false; }
18672 var targetNode = n.node;
18673 var dropNode = data.node;
18674 // default drop rules
18675 if(!(targetNode && targetNode.isTarget && pt)){
18678 if(pt == "append" && targetNode.allowChildren === false){
18681 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18684 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18687 // reuse the object
18688 var overEvent = this.dragOverData;
18689 overEvent.tree = this.tree;
18690 overEvent.target = targetNode;
18691 overEvent.data = data;
18692 overEvent.point = pt;
18693 overEvent.source = dd;
18694 overEvent.rawEvent = e;
18695 overEvent.dropNode = dropNode;
18696 overEvent.cancel = false;
18697 var result = this.tree.fireEvent("nodedragover", overEvent);
18698 return overEvent.cancel === false && result !== false;
18701 getDropPoint : function(e, n, dd){
18704 return tn.allowChildren !== false ? "append" : false; // always append for root
18706 var dragEl = n.ddel;
18707 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18708 var y = Roo.lib.Event.getPageY(e);
18709 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18711 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18712 var noAppend = tn.allowChildren === false;
18713 if(this.appendOnly || tn.parentNode.allowChildren === false){
18714 return noAppend ? false : "append";
18716 var noBelow = false;
18717 if(!this.allowParentInsert){
18718 noBelow = tn.hasChildNodes() && tn.isExpanded();
18720 var q = (b - t) / (noAppend ? 2 : 3);
18721 if(y >= t && y < (t + q)){
18723 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18730 onNodeEnter : function(n, dd, e, data){
18731 this.cancelExpand();
18734 onNodeOver : function(n, dd, e, data){
18735 var pt = this.getDropPoint(e, n, dd);
18738 // auto node expand check
18739 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18740 this.queueExpand(node);
18741 }else if(pt != "append"){
18742 this.cancelExpand();
18745 // set the insert point style on the target node
18746 var returnCls = this.dropNotAllowed;
18747 if(this.isValidDropPoint(n, pt, dd, e, data)){
18752 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18753 cls = "x-tree-drag-insert-above";
18754 }else if(pt == "below"){
18755 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18756 cls = "x-tree-drag-insert-below";
18758 returnCls = "x-tree-drop-ok-append";
18759 cls = "x-tree-drag-append";
18761 if(this.lastInsertClass != cls){
18762 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18763 this.lastInsertClass = cls;
18770 onNodeOut : function(n, dd, e, data){
18771 this.cancelExpand();
18772 this.removeDropIndicators(n);
18775 onNodeDrop : function(n, dd, e, data){
18776 var point = this.getDropPoint(e, n, dd);
18777 var targetNode = n.node;
18778 targetNode.ui.startDrop();
18779 if(!this.isValidDropPoint(n, point, dd, e, data)){
18780 targetNode.ui.endDrop();
18783 // first try to find the drop node
18784 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18787 target: targetNode,
18792 dropNode: dropNode,
18795 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18796 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18797 targetNode.ui.endDrop();
18800 // allow target changing
18801 targetNode = dropEvent.target;
18802 if(point == "append" && !targetNode.isExpanded()){
18803 targetNode.expand(false, null, function(){
18804 this.completeDrop(dropEvent);
18805 }.createDelegate(this));
18807 this.completeDrop(dropEvent);
18812 completeDrop : function(de){
18813 var ns = de.dropNode, p = de.point, t = de.target;
18814 if(!(ns instanceof Array)){
18818 for(var i = 0, len = ns.length; i < len; i++){
18821 t.parentNode.insertBefore(n, t);
18822 }else if(p == "below"){
18823 t.parentNode.insertBefore(n, t.nextSibling);
18829 if(this.tree.hlDrop){
18833 this.tree.fireEvent("nodedrop", de);
18836 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18837 if(this.tree.hlDrop){
18838 dropNode.ui.focus();
18839 dropNode.ui.highlight();
18841 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18844 getTree : function(){
18848 removeDropIndicators : function(n){
18851 Roo.fly(el).removeClass([
18852 "x-tree-drag-insert-above",
18853 "x-tree-drag-insert-below",
18854 "x-tree-drag-append"]);
18855 this.lastInsertClass = "_noclass";
18859 beforeDragDrop : function(target, e, id){
18860 this.cancelExpand();
18864 afterRepair : function(data){
18865 if(data && Roo.enableFx){
18866 data.node.ui.highlight();
18875 * Ext JS Library 1.1.1
18876 * Copyright(c) 2006-2007, Ext JS, LLC.
18878 * Originally Released Under LGPL - original licence link has changed is not relivant.
18881 * <script type="text/javascript">
18885 if(Roo.dd.DragZone){
18886 Roo.tree.TreeDragZone = function(tree, config){
18887 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18891 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18892 ddGroup : "TreeDD",
18894 onBeforeDrag : function(data, e){
18896 return n && n.draggable && !n.disabled;
18899 onInitDrag : function(e){
18900 var data = this.dragData;
18901 this.tree.getSelectionModel().select(data.node);
18902 this.proxy.update("");
18903 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18904 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18907 getRepairXY : function(e, data){
18908 return data.node.ui.getDDRepairXY();
18911 onEndDrag : function(data, e){
18912 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18915 onValidDrop : function(dd, e, id){
18916 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18920 beforeInvalidDrop : function(e, id){
18921 // this scrolls the original position back into view
18922 var sm = this.tree.getSelectionModel();
18923 sm.clearSelections();
18924 sm.select(this.dragData.node);
18929 * Ext JS Library 1.1.1
18930 * Copyright(c) 2006-2007, Ext JS, LLC.
18932 * Originally Released Under LGPL - original licence link has changed is not relivant.
18935 * <script type="text/javascript">
18938 * @class Roo.tree.TreeEditor
18939 * @extends Roo.Editor
18940 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18941 * as the editor field.
18943 * @param {TreePanel} tree
18944 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18946 Roo.tree.TreeEditor = function(tree, config){
18947 config = config || {};
18948 var field = config.events ? config : new Roo.form.TextField(config);
18949 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18953 tree.on('beforeclick', this.beforeNodeClick, this);
18954 tree.getTreeEl().on('mousedown', this.hide, this);
18955 this.on('complete', this.updateNode, this);
18956 this.on('beforestartedit', this.fitToTree, this);
18957 this.on('startedit', this.bindScroll, this, {delay:10});
18958 this.on('specialkey', this.onSpecialKey, this);
18961 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18963 * @cfg {String} alignment
18964 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18970 * @cfg {Boolean} hideEl
18971 * True to hide the bound element while the editor is displayed (defaults to false)
18975 * @cfg {String} cls
18976 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18978 cls: "x-small-editor x-tree-editor",
18980 * @cfg {Boolean} shim
18981 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18987 * @cfg {Number} maxWidth
18988 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18989 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18990 * scroll and client offsets into account prior to each edit.
18997 fitToTree : function(ed, el){
18998 var td = this.tree.getTreeEl().dom, nd = el.dom;
18999 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
19000 td.scrollLeft = nd.offsetLeft;
19004 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
19005 this.setSize(w, '');
19009 triggerEdit : function(node){
19010 this.completeEdit();
19011 this.editNode = node;
19012 this.startEdit(node.ui.textNode, node.text);
19016 bindScroll : function(){
19017 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19021 beforeNodeClick : function(node, e){
19022 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19023 this.lastClick = new Date();
19024 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19026 this.triggerEdit(node);
19032 updateNode : function(ed, value){
19033 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19034 this.editNode.setText(value);
19038 onHide : function(){
19039 Roo.tree.TreeEditor.superclass.onHide.call(this);
19041 this.editNode.ui.focus();
19046 onSpecialKey : function(field, e){
19047 var k = e.getKey();
19051 }else if(k == e.ENTER && !e.hasModifier()){
19053 this.completeEdit();
19056 });//<Script type="text/javascript">
19059 * Ext JS Library 1.1.1
19060 * Copyright(c) 2006-2007, Ext JS, LLC.
19062 * Originally Released Under LGPL - original licence link has changed is not relivant.
19065 * <script type="text/javascript">
19069 * Not documented??? - probably should be...
19072 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19073 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19075 renderElements : function(n, a, targetNode, bulkRender){
19076 //consel.log("renderElements?");
19077 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19079 var t = n.getOwnerTree();
19080 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19082 var cols = t.columns;
19083 var bw = t.borderWidth;
19085 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19086 var cb = typeof a.checked == "boolean";
19087 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19088 var colcls = 'x-t-' + tid + '-c0';
19090 '<li class="x-tree-node">',
19093 '<div class="x-tree-node-el ', a.cls,'">',
19095 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19098 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19099 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19100 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19101 (a.icon ? ' x-tree-node-inline-icon' : ''),
19102 (a.iconCls ? ' '+a.iconCls : ''),
19103 '" unselectable="on" />',
19104 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19105 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19107 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19108 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19109 '<span unselectable="on" qtip="' + tx + '">',
19113 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19114 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19116 for(var i = 1, len = cols.length; i < len; i++){
19118 colcls = 'x-t-' + tid + '-c' +i;
19119 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19120 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19121 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19127 '<div class="x-clear"></div></div>',
19128 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19131 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19132 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19133 n.nextSibling.ui.getEl(), buf.join(""));
19135 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19137 var el = this.wrap.firstChild;
19139 this.elNode = el.firstChild;
19140 this.ranchor = el.childNodes[1];
19141 this.ctNode = this.wrap.childNodes[1];
19142 var cs = el.firstChild.childNodes;
19143 this.indentNode = cs[0];
19144 this.ecNode = cs[1];
19145 this.iconNode = cs[2];
19148 this.checkbox = cs[3];
19151 this.anchor = cs[index];
19153 this.textNode = cs[index].firstChild;
19155 //el.on("click", this.onClick, this);
19156 //el.on("dblclick", this.onDblClick, this);
19159 // console.log(this);
19161 initEvents : function(){
19162 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19165 var a = this.ranchor;
19167 var el = Roo.get(a);
19169 if(Roo.isOpera){ // opera render bug ignores the CSS
19170 el.setStyle("text-decoration", "none");
19173 el.on("click", this.onClick, this);
19174 el.on("dblclick", this.onDblClick, this);
19175 el.on("contextmenu", this.onContextMenu, this);
19179 /*onSelectedChange : function(state){
19182 this.addClass("x-tree-selected");
19185 this.removeClass("x-tree-selected");
19188 addClass : function(cls){
19190 Roo.fly(this.elRow).addClass(cls);
19196 removeClass : function(cls){
19198 Roo.fly(this.elRow).removeClass(cls);
19204 });//<Script type="text/javascript">
19208 * Ext JS Library 1.1.1
19209 * Copyright(c) 2006-2007, Ext JS, LLC.
19211 * Originally Released Under LGPL - original licence link has changed is not relivant.
19214 * <script type="text/javascript">
19219 * @class Roo.tree.ColumnTree
19220 * @extends Roo.data.TreePanel
19221 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19222 * @cfg {int} borderWidth compined right/left border allowance
19224 * @param {String/HTMLElement/Element} el The container element
19225 * @param {Object} config
19227 Roo.tree.ColumnTree = function(el, config)
19229 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19233 * Fire this event on a container when it resizes
19234 * @param {int} w Width
19235 * @param {int} h Height
19239 this.on('resize', this.onResize, this);
19242 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19246 borderWidth: Roo.isBorderBox ? 0 : 2,
19249 render : function(){
19250 // add the header.....
19252 Roo.tree.ColumnTree.superclass.render.apply(this);
19254 this.el.addClass('x-column-tree');
19256 this.headers = this.el.createChild(
19257 {cls:'x-tree-headers'},this.innerCt.dom);
19259 var cols = this.columns, c;
19260 var totalWidth = 0;
19262 var len = cols.length;
19263 for(var i = 0; i < len; i++){
19265 totalWidth += c.width;
19266 this.headEls.push(this.headers.createChild({
19267 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19269 cls:'x-tree-hd-text',
19272 style:'width:'+(c.width-this.borderWidth)+'px;'
19275 this.headers.createChild({cls:'x-clear'});
19276 // prevent floats from wrapping when clipped
19277 this.headers.setWidth(totalWidth);
19278 //this.innerCt.setWidth(totalWidth);
19279 this.innerCt.setStyle({ overflow: 'auto' });
19280 this.onResize(this.width, this.height);
19284 onResize : function(w,h)
19289 this.innerCt.setWidth(this.width);
19290 this.innerCt.setHeight(this.height-20);
19293 var cols = this.columns, c;
19294 var totalWidth = 0;
19296 var len = cols.length;
19297 for(var i = 0; i < len; i++){
19299 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19300 // it's the expander..
19301 expEl = this.headEls[i];
19304 totalWidth += c.width;
19308 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19310 this.headers.setWidth(w-20);
19319 * Ext JS Library 1.1.1
19320 * Copyright(c) 2006-2007, Ext JS, LLC.
19322 * Originally Released Under LGPL - original licence link has changed is not relivant.
19325 * <script type="text/javascript">
19329 * @class Roo.menu.Menu
19330 * @extends Roo.util.Observable
19331 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19332 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19334 * Creates a new Menu
19335 * @param {Object} config Configuration options
19337 Roo.menu.Menu = function(config){
19338 Roo.apply(this, config);
19339 this.id = this.id || Roo.id();
19342 * @event beforeshow
19343 * Fires before this menu is displayed
19344 * @param {Roo.menu.Menu} this
19348 * @event beforehide
19349 * Fires before this menu is hidden
19350 * @param {Roo.menu.Menu} this
19355 * Fires after this menu is displayed
19356 * @param {Roo.menu.Menu} this
19361 * Fires after this menu is hidden
19362 * @param {Roo.menu.Menu} this
19367 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19368 * @param {Roo.menu.Menu} this
19369 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19370 * @param {Roo.EventObject} e
19375 * Fires when the mouse is hovering over this menu
19376 * @param {Roo.menu.Menu} this
19377 * @param {Roo.EventObject} e
19378 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19383 * Fires when the mouse exits this menu
19384 * @param {Roo.menu.Menu} this
19385 * @param {Roo.EventObject} e
19386 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19391 * Fires when a menu item contained in this menu is clicked
19392 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19393 * @param {Roo.EventObject} e
19397 if (this.registerMenu) {
19398 Roo.menu.MenuMgr.register(this);
19401 var mis = this.items;
19402 this.items = new Roo.util.MixedCollection();
19404 this.add.apply(this, mis);
19408 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19410 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19414 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19415 * for bottom-right shadow (defaults to "sides")
19419 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19420 * this menu (defaults to "tl-tr?")
19422 subMenuAlign : "tl-tr?",
19424 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19425 * relative to its element of origin (defaults to "tl-bl?")
19427 defaultAlign : "tl-bl?",
19429 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19431 allowOtherMenus : false,
19433 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19435 registerMenu : true,
19440 render : function(){
19444 var el = this.el = new Roo.Layer({
19446 shadow:this.shadow,
19448 parentEl: this.parentEl || document.body,
19452 this.keyNav = new Roo.menu.MenuNav(this);
19455 el.addClass("x-menu-plain");
19458 el.addClass(this.cls);
19460 // generic focus element
19461 this.focusEl = el.createChild({
19462 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19464 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19465 ul.on("click", this.onClick, this);
19466 ul.on("mouseover", this.onMouseOver, this);
19467 ul.on("mouseout", this.onMouseOut, this);
19468 this.items.each(function(item){
19469 var li = document.createElement("li");
19470 li.className = "x-menu-list-item";
19471 ul.dom.appendChild(li);
19472 item.render(li, this);
19479 autoWidth : function(){
19480 var el = this.el, ul = this.ul;
19484 var w = this.width;
19487 }else if(Roo.isIE){
19488 el.setWidth(this.minWidth);
19489 var t = el.dom.offsetWidth; // force recalc
19490 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19495 delayAutoWidth : function(){
19498 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19500 this.awTask.delay(20);
19505 findTargetItem : function(e){
19506 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19507 if(t && t.menuItemId){
19508 return this.items.get(t.menuItemId);
19513 onClick : function(e){
19515 if(t = this.findTargetItem(e)){
19517 this.fireEvent("click", this, t, e);
19522 setActiveItem : function(item, autoExpand){
19523 if(item != this.activeItem){
19524 if(this.activeItem){
19525 this.activeItem.deactivate();
19527 this.activeItem = item;
19528 item.activate(autoExpand);
19529 }else if(autoExpand){
19535 tryActivate : function(start, step){
19536 var items = this.items;
19537 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19538 var item = items.get(i);
19539 if(!item.disabled && item.canActivate){
19540 this.setActiveItem(item, false);
19548 onMouseOver : function(e){
19550 if(t = this.findTargetItem(e)){
19551 if(t.canActivate && !t.disabled){
19552 this.setActiveItem(t, true);
19555 this.fireEvent("mouseover", this, e, t);
19559 onMouseOut : function(e){
19561 if(t = this.findTargetItem(e)){
19562 if(t == this.activeItem && t.shouldDeactivate(e)){
19563 this.activeItem.deactivate();
19564 delete this.activeItem;
19567 this.fireEvent("mouseout", this, e, t);
19571 * Read-only. Returns true if the menu is currently displayed, else false.
19574 isVisible : function(){
19575 return this.el && !this.hidden;
19579 * Displays this menu relative to another element
19580 * @param {String/HTMLElement/Roo.Element} element The element to align to
19581 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19582 * the element (defaults to this.defaultAlign)
19583 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19585 show : function(el, pos, parentMenu){
19586 this.parentMenu = parentMenu;
19590 this.fireEvent("beforeshow", this);
19591 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19595 * Displays this menu at a specific xy position
19596 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19597 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19599 showAt : function(xy, parentMenu, /* private: */_e){
19600 this.parentMenu = parentMenu;
19605 this.fireEvent("beforeshow", this);
19606 xy = this.el.adjustForConstraints(xy);
19610 this.hidden = false;
19612 this.fireEvent("show", this);
19615 focus : function(){
19617 this.doFocus.defer(50, this);
19621 doFocus : function(){
19623 this.focusEl.focus();
19628 * Hides this menu and optionally all parent menus
19629 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19631 hide : function(deep){
19632 if(this.el && this.isVisible()){
19633 this.fireEvent("beforehide", this);
19634 if(this.activeItem){
19635 this.activeItem.deactivate();
19636 this.activeItem = null;
19639 this.hidden = true;
19640 this.fireEvent("hide", this);
19642 if(deep === true && this.parentMenu){
19643 this.parentMenu.hide(true);
19648 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19649 * Any of the following are valid:
19651 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19652 * <li>An HTMLElement object which will be converted to a menu item</li>
19653 * <li>A menu item config object that will be created as a new menu item</li>
19654 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19655 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19660 var menu = new Roo.menu.Menu();
19662 // Create a menu item to add by reference
19663 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19665 // Add a bunch of items at once using different methods.
19666 // Only the last item added will be returned.
19667 var item = menu.add(
19668 menuItem, // add existing item by ref
19669 'Dynamic Item', // new TextItem
19670 '-', // new separator
19671 { text: 'Config Item' } // new item by config
19674 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19675 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19678 var a = arguments, l = a.length, item;
19679 for(var i = 0; i < l; i++){
19681 if ((typeof(el) == "object") && el.xtype && el.xns) {
19682 el = Roo.factory(el, Roo.menu);
19685 if(el.render){ // some kind of Item
19686 item = this.addItem(el);
19687 }else if(typeof el == "string"){ // string
19688 if(el == "separator" || el == "-"){
19689 item = this.addSeparator();
19691 item = this.addText(el);
19693 }else if(el.tagName || el.el){ // element
19694 item = this.addElement(el);
19695 }else if(typeof el == "object"){ // must be menu item config?
19696 item = this.addMenuItem(el);
19703 * Returns this menu's underlying {@link Roo.Element} object
19704 * @return {Roo.Element} The element
19706 getEl : function(){
19714 * Adds a separator bar to the menu
19715 * @return {Roo.menu.Item} The menu item that was added
19717 addSeparator : function(){
19718 return this.addItem(new Roo.menu.Separator());
19722 * Adds an {@link Roo.Element} object to the menu
19723 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19724 * @return {Roo.menu.Item} The menu item that was added
19726 addElement : function(el){
19727 return this.addItem(new Roo.menu.BaseItem(el));
19731 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19732 * @param {Roo.menu.Item} item The menu item to add
19733 * @return {Roo.menu.Item} The menu item that was added
19735 addItem : function(item){
19736 this.items.add(item);
19738 var li = document.createElement("li");
19739 li.className = "x-menu-list-item";
19740 this.ul.dom.appendChild(li);
19741 item.render(li, this);
19742 this.delayAutoWidth();
19748 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19749 * @param {Object} config A MenuItem config object
19750 * @return {Roo.menu.Item} The menu item that was added
19752 addMenuItem : function(config){
19753 if(!(config instanceof Roo.menu.Item)){
19754 if(typeof config.checked == "boolean"){ // must be check menu item config?
19755 config = new Roo.menu.CheckItem(config);
19757 config = new Roo.menu.Item(config);
19760 return this.addItem(config);
19764 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19765 * @param {String} text The text to display in the menu item
19766 * @return {Roo.menu.Item} The menu item that was added
19768 addText : function(text){
19769 return this.addItem(new Roo.menu.TextItem({ text : text }));
19773 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19774 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19775 * @param {Roo.menu.Item} item The menu item to add
19776 * @return {Roo.menu.Item} The menu item that was added
19778 insert : function(index, item){
19779 this.items.insert(index, item);
19781 var li = document.createElement("li");
19782 li.className = "x-menu-list-item";
19783 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19784 item.render(li, this);
19785 this.delayAutoWidth();
19791 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19792 * @param {Roo.menu.Item} item The menu item to remove
19794 remove : function(item){
19795 this.items.removeKey(item.id);
19800 * Removes and destroys all items in the menu
19802 removeAll : function(){
19804 while(f = this.items.first()){
19810 // MenuNav is a private utility class used internally by the Menu
19811 Roo.menu.MenuNav = function(menu){
19812 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19813 this.scope = this.menu = menu;
19816 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19817 doRelay : function(e, h){
19818 var k = e.getKey();
19819 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19820 this.menu.tryActivate(0, 1);
19823 return h.call(this.scope || this, e, this.menu);
19826 up : function(e, m){
19827 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19828 m.tryActivate(m.items.length-1, -1);
19832 down : function(e, m){
19833 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19834 m.tryActivate(0, 1);
19838 right : function(e, m){
19840 m.activeItem.expandMenu(true);
19844 left : function(e, m){
19846 if(m.parentMenu && m.parentMenu.activeItem){
19847 m.parentMenu.activeItem.activate();
19851 enter : function(e, m){
19853 e.stopPropagation();
19854 m.activeItem.onClick(e);
19855 m.fireEvent("click", this, m.activeItem);
19861 * Ext JS Library 1.1.1
19862 * Copyright(c) 2006-2007, Ext JS, LLC.
19864 * Originally Released Under LGPL - original licence link has changed is not relivant.
19867 * <script type="text/javascript">
19871 * @class Roo.menu.MenuMgr
19872 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19875 Roo.menu.MenuMgr = function(){
19876 var menus, active, groups = {}, attached = false, lastShow = new Date();
19878 // private - called when first menu is created
19881 active = new Roo.util.MixedCollection();
19882 Roo.get(document).addKeyListener(27, function(){
19883 if(active.length > 0){
19890 function hideAll(){
19891 if(active && active.length > 0){
19892 var c = active.clone();
19893 c.each(function(m){
19900 function onHide(m){
19902 if(active.length < 1){
19903 Roo.get(document).un("mousedown", onMouseDown);
19909 function onShow(m){
19910 var last = active.last();
19911 lastShow = new Date();
19914 Roo.get(document).on("mousedown", onMouseDown);
19918 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19919 m.parentMenu.activeChild = m;
19920 }else if(last && last.isVisible()){
19921 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19926 function onBeforeHide(m){
19928 m.activeChild.hide();
19930 if(m.autoHideTimer){
19931 clearTimeout(m.autoHideTimer);
19932 delete m.autoHideTimer;
19937 function onBeforeShow(m){
19938 var pm = m.parentMenu;
19939 if(!pm && !m.allowOtherMenus){
19941 }else if(pm && pm.activeChild && active != m){
19942 pm.activeChild.hide();
19947 function onMouseDown(e){
19948 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19954 function onBeforeCheck(mi, state){
19956 var g = groups[mi.group];
19957 for(var i = 0, l = g.length; i < l; i++){
19959 g[i].setChecked(false);
19968 * Hides all menus that are currently visible
19970 hideAll : function(){
19975 register : function(menu){
19979 menus[menu.id] = menu;
19980 menu.on("beforehide", onBeforeHide);
19981 menu.on("hide", onHide);
19982 menu.on("beforeshow", onBeforeShow);
19983 menu.on("show", onShow);
19984 var g = menu.group;
19985 if(g && menu.events["checkchange"]){
19989 groups[g].push(menu);
19990 menu.on("checkchange", onCheck);
19995 * Returns a {@link Roo.menu.Menu} object
19996 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19997 * be used to generate and return a new Menu instance.
19999 get : function(menu){
20000 if(typeof menu == "string"){ // menu id
20001 return menus[menu];
20002 }else if(menu.events){ // menu instance
20004 }else if(typeof menu.length == 'number'){ // array of menu items?
20005 return new Roo.menu.Menu({items:menu});
20006 }else{ // otherwise, must be a config
20007 return new Roo.menu.Menu(menu);
20012 unregister : function(menu){
20013 delete menus[menu.id];
20014 menu.un("beforehide", onBeforeHide);
20015 menu.un("hide", onHide);
20016 menu.un("beforeshow", onBeforeShow);
20017 menu.un("show", onShow);
20018 var g = menu.group;
20019 if(g && menu.events["checkchange"]){
20020 groups[g].remove(menu);
20021 menu.un("checkchange", onCheck);
20026 registerCheckable : function(menuItem){
20027 var g = menuItem.group;
20032 groups[g].push(menuItem);
20033 menuItem.on("beforecheckchange", onBeforeCheck);
20038 unregisterCheckable : function(menuItem){
20039 var g = menuItem.group;
20041 groups[g].remove(menuItem);
20042 menuItem.un("beforecheckchange", onBeforeCheck);
20048 * Ext JS Library 1.1.1
20049 * Copyright(c) 2006-2007, Ext JS, LLC.
20051 * Originally Released Under LGPL - original licence link has changed is not relivant.
20054 * <script type="text/javascript">
20059 * @class Roo.menu.BaseItem
20060 * @extends Roo.Component
20061 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20062 * management and base configuration options shared by all menu components.
20064 * Creates a new BaseItem
20065 * @param {Object} config Configuration options
20067 Roo.menu.BaseItem = function(config){
20068 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20073 * Fires when this item is clicked
20074 * @param {Roo.menu.BaseItem} this
20075 * @param {Roo.EventObject} e
20080 * Fires when this item is activated
20081 * @param {Roo.menu.BaseItem} this
20085 * @event deactivate
20086 * Fires when this item is deactivated
20087 * @param {Roo.menu.BaseItem} this
20093 this.on("click", this.handler, this.scope, true);
20097 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20099 * @cfg {Function} handler
20100 * A function that will handle the click event of this menu item (defaults to undefined)
20103 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20105 canActivate : false,
20107 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20109 activeClass : "x-menu-item-active",
20111 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20113 hideOnClick : true,
20115 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20120 ctype: "Roo.menu.BaseItem",
20123 actionMode : "container",
20126 render : function(container, parentMenu){
20127 this.parentMenu = parentMenu;
20128 Roo.menu.BaseItem.superclass.render.call(this, container);
20129 this.container.menuItemId = this.id;
20133 onRender : function(container, position){
20134 this.el = Roo.get(this.el);
20135 container.dom.appendChild(this.el.dom);
20139 onClick : function(e){
20140 if(!this.disabled && this.fireEvent("click", this, e) !== false
20141 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20142 this.handleClick(e);
20149 activate : function(){
20153 var li = this.container;
20154 li.addClass(this.activeClass);
20155 this.region = li.getRegion().adjust(2, 2, -2, -2);
20156 this.fireEvent("activate", this);
20161 deactivate : function(){
20162 this.container.removeClass(this.activeClass);
20163 this.fireEvent("deactivate", this);
20167 shouldDeactivate : function(e){
20168 return !this.region || !this.region.contains(e.getPoint());
20172 handleClick : function(e){
20173 if(this.hideOnClick){
20174 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20179 expandMenu : function(autoActivate){
20184 hideMenu : function(){
20189 * Ext JS Library 1.1.1
20190 * Copyright(c) 2006-2007, Ext JS, LLC.
20192 * Originally Released Under LGPL - original licence link has changed is not relivant.
20195 * <script type="text/javascript">
20199 * @class Roo.menu.Adapter
20200 * @extends Roo.menu.BaseItem
20201 * 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.
20202 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20204 * Creates a new Adapter
20205 * @param {Object} config Configuration options
20207 Roo.menu.Adapter = function(component, config){
20208 Roo.menu.Adapter.superclass.constructor.call(this, config);
20209 this.component = component;
20211 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20213 canActivate : true,
20216 onRender : function(container, position){
20217 this.component.render(container);
20218 this.el = this.component.getEl();
20222 activate : function(){
20226 this.component.focus();
20227 this.fireEvent("activate", this);
20232 deactivate : function(){
20233 this.fireEvent("deactivate", this);
20237 disable : function(){
20238 this.component.disable();
20239 Roo.menu.Adapter.superclass.disable.call(this);
20243 enable : function(){
20244 this.component.enable();
20245 Roo.menu.Adapter.superclass.enable.call(this);
20249 * Ext JS Library 1.1.1
20250 * Copyright(c) 2006-2007, Ext JS, LLC.
20252 * Originally Released Under LGPL - original licence link has changed is not relivant.
20255 * <script type="text/javascript">
20259 * @class Roo.menu.TextItem
20260 * @extends Roo.menu.BaseItem
20261 * Adds a static text string to a menu, usually used as either a heading or group separator.
20262 * Note: old style constructor with text is still supported.
20265 * Creates a new TextItem
20266 * @param {Object} cfg Configuration
20268 Roo.menu.TextItem = function(cfg){
20269 if (typeof(cfg) == 'string') {
20272 Roo.apply(this,cfg);
20275 Roo.menu.TextItem.superclass.constructor.call(this);
20278 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20280 * @cfg {Boolean} text Text to show on item.
20285 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20287 hideOnClick : false,
20289 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20291 itemCls : "x-menu-text",
20294 onRender : function(){
20295 var s = document.createElement("span");
20296 s.className = this.itemCls;
20297 s.innerHTML = this.text;
20299 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20303 * Ext JS Library 1.1.1
20304 * Copyright(c) 2006-2007, Ext JS, LLC.
20306 * Originally Released Under LGPL - original licence link has changed is not relivant.
20309 * <script type="text/javascript">
20313 * @class Roo.menu.Separator
20314 * @extends Roo.menu.BaseItem
20315 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20316 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20318 * @param {Object} config Configuration options
20320 Roo.menu.Separator = function(config){
20321 Roo.menu.Separator.superclass.constructor.call(this, config);
20324 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20326 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20328 itemCls : "x-menu-sep",
20330 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20332 hideOnClick : false,
20335 onRender : function(li){
20336 var s = document.createElement("span");
20337 s.className = this.itemCls;
20338 s.innerHTML = " ";
20340 li.addClass("x-menu-sep-li");
20341 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20345 * Ext JS Library 1.1.1
20346 * Copyright(c) 2006-2007, Ext JS, LLC.
20348 * Originally Released Under LGPL - original licence link has changed is not relivant.
20351 * <script type="text/javascript">
20354 * @class Roo.menu.Item
20355 * @extends Roo.menu.BaseItem
20356 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20357 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20358 * activation and click handling.
20360 * Creates a new Item
20361 * @param {Object} config Configuration options
20363 Roo.menu.Item = function(config){
20364 Roo.menu.Item.superclass.constructor.call(this, config);
20366 this.menu = Roo.menu.MenuMgr.get(this.menu);
20369 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20372 * @cfg {String} text
20373 * The text to show on the menu item.
20377 * @cfg {String} HTML to render in menu
20378 * The text to show on the menu item (HTML version).
20382 * @cfg {String} icon
20383 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20387 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20389 itemCls : "x-menu-item",
20391 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20393 canActivate : true,
20395 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20398 // doc'd in BaseItem
20402 ctype: "Roo.menu.Item",
20405 onRender : function(container, position){
20406 var el = document.createElement("a");
20407 el.hideFocus = true;
20408 el.unselectable = "on";
20409 el.href = this.href || "#";
20410 if(this.hrefTarget){
20411 el.target = this.hrefTarget;
20413 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20415 var html = this.html.length ? this.html : String.format('{0}',this.text);
20417 el.innerHTML = String.format(
20418 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20419 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20421 Roo.menu.Item.superclass.onRender.call(this, container, position);
20425 * Sets the text to display in this menu item
20426 * @param {String} text The text to display
20427 * @param {Boolean} isHTML true to indicate text is pure html.
20429 setText : function(text, isHTML){
20437 var html = this.html.length ? this.html : String.format('{0}',this.text);
20439 this.el.update(String.format(
20440 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20441 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20442 this.parentMenu.autoWidth();
20447 handleClick : function(e){
20448 if(!this.href){ // if no link defined, stop the event automatically
20451 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20455 activate : function(autoExpand){
20456 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20466 shouldDeactivate : function(e){
20467 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20468 if(this.menu && this.menu.isVisible()){
20469 return !this.menu.getEl().getRegion().contains(e.getPoint());
20477 deactivate : function(){
20478 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20483 expandMenu : function(autoActivate){
20484 if(!this.disabled && this.menu){
20485 clearTimeout(this.hideTimer);
20486 delete this.hideTimer;
20487 if(!this.menu.isVisible() && !this.showTimer){
20488 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20489 }else if (this.menu.isVisible() && autoActivate){
20490 this.menu.tryActivate(0, 1);
20496 deferExpand : function(autoActivate){
20497 delete this.showTimer;
20498 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20500 this.menu.tryActivate(0, 1);
20505 hideMenu : function(){
20506 clearTimeout(this.showTimer);
20507 delete this.showTimer;
20508 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20509 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20514 deferHide : function(){
20515 delete this.hideTimer;
20520 * Ext JS Library 1.1.1
20521 * Copyright(c) 2006-2007, Ext JS, LLC.
20523 * Originally Released Under LGPL - original licence link has changed is not relivant.
20526 * <script type="text/javascript">
20530 * @class Roo.menu.CheckItem
20531 * @extends Roo.menu.Item
20532 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20534 * Creates a new CheckItem
20535 * @param {Object} config Configuration options
20537 Roo.menu.CheckItem = function(config){
20538 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20541 * @event beforecheckchange
20542 * Fires before the checked value is set, providing an opportunity to cancel if needed
20543 * @param {Roo.menu.CheckItem} this
20544 * @param {Boolean} checked The new checked value that will be set
20546 "beforecheckchange" : true,
20548 * @event checkchange
20549 * Fires after the checked value has been set
20550 * @param {Roo.menu.CheckItem} this
20551 * @param {Boolean} checked The checked value that was set
20553 "checkchange" : true
20555 if(this.checkHandler){
20556 this.on('checkchange', this.checkHandler, this.scope);
20559 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20561 * @cfg {String} group
20562 * All check items with the same group name will automatically be grouped into a single-select
20563 * radio button group (defaults to '')
20566 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20568 itemCls : "x-menu-item x-menu-check-item",
20570 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20572 groupClass : "x-menu-group-item",
20575 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20576 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20577 * initialized with checked = true will be rendered as checked.
20582 ctype: "Roo.menu.CheckItem",
20585 onRender : function(c){
20586 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20588 this.el.addClass(this.groupClass);
20590 Roo.menu.MenuMgr.registerCheckable(this);
20592 this.checked = false;
20593 this.setChecked(true, true);
20598 destroy : function(){
20600 Roo.menu.MenuMgr.unregisterCheckable(this);
20602 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20606 * Set the checked state of this item
20607 * @param {Boolean} checked The new checked value
20608 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20610 setChecked : function(state, suppressEvent){
20611 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20612 if(this.container){
20613 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20615 this.checked = state;
20616 if(suppressEvent !== true){
20617 this.fireEvent("checkchange", this, state);
20623 handleClick : function(e){
20624 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20625 this.setChecked(!this.checked);
20627 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20631 * Ext JS Library 1.1.1
20632 * Copyright(c) 2006-2007, Ext JS, LLC.
20634 * Originally Released Under LGPL - original licence link has changed is not relivant.
20637 * <script type="text/javascript">
20641 * @class Roo.menu.DateItem
20642 * @extends Roo.menu.Adapter
20643 * A menu item that wraps the {@link Roo.DatPicker} component.
20645 * Creates a new DateItem
20646 * @param {Object} config Configuration options
20648 Roo.menu.DateItem = function(config){
20649 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20650 /** The Roo.DatePicker object @type Roo.DatePicker */
20651 this.picker = this.component;
20652 this.addEvents({select: true});
20654 this.picker.on("render", function(picker){
20655 picker.getEl().swallowEvent("click");
20656 picker.container.addClass("x-menu-date-item");
20659 this.picker.on("select", this.onSelect, this);
20662 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20664 onSelect : function(picker, date){
20665 this.fireEvent("select", this, date, picker);
20666 Roo.menu.DateItem.superclass.handleClick.call(this);
20670 * Ext JS Library 1.1.1
20671 * Copyright(c) 2006-2007, Ext JS, LLC.
20673 * Originally Released Under LGPL - original licence link has changed is not relivant.
20676 * <script type="text/javascript">
20680 * @class Roo.menu.ColorItem
20681 * @extends Roo.menu.Adapter
20682 * A menu item that wraps the {@link Roo.ColorPalette} component.
20684 * Creates a new ColorItem
20685 * @param {Object} config Configuration options
20687 Roo.menu.ColorItem = function(config){
20688 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20689 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20690 this.palette = this.component;
20691 this.relayEvents(this.palette, ["select"]);
20692 if(this.selectHandler){
20693 this.on('select', this.selectHandler, this.scope);
20696 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20698 * Ext JS Library 1.1.1
20699 * Copyright(c) 2006-2007, Ext JS, LLC.
20701 * Originally Released Under LGPL - original licence link has changed is not relivant.
20704 * <script type="text/javascript">
20709 * @class Roo.menu.DateMenu
20710 * @extends Roo.menu.Menu
20711 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20713 * Creates a new DateMenu
20714 * @param {Object} config Configuration options
20716 Roo.menu.DateMenu = function(config){
20717 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20719 var di = new Roo.menu.DateItem(config);
20722 * The {@link Roo.DatePicker} instance for this DateMenu
20725 this.picker = di.picker;
20728 * @param {DatePicker} picker
20729 * @param {Date} date
20731 this.relayEvents(di, ["select"]);
20733 this.on('beforeshow', function(){
20735 this.picker.hideMonthPicker(true);
20739 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20743 * Ext JS Library 1.1.1
20744 * Copyright(c) 2006-2007, Ext JS, LLC.
20746 * Originally Released Under LGPL - original licence link has changed is not relivant.
20749 * <script type="text/javascript">
20754 * @class Roo.menu.ColorMenu
20755 * @extends Roo.menu.Menu
20756 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20758 * Creates a new ColorMenu
20759 * @param {Object} config Configuration options
20761 Roo.menu.ColorMenu = function(config){
20762 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20764 var ci = new Roo.menu.ColorItem(config);
20767 * The {@link Roo.ColorPalette} instance for this ColorMenu
20768 * @type ColorPalette
20770 this.palette = ci.palette;
20773 * @param {ColorPalette} palette
20774 * @param {String} color
20776 this.relayEvents(ci, ["select"]);
20778 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20780 * Ext JS Library 1.1.1
20781 * Copyright(c) 2006-2007, Ext JS, LLC.
20783 * Originally Released Under LGPL - original licence link has changed is not relivant.
20786 * <script type="text/javascript">
20790 * @class Roo.form.Field
20791 * @extends Roo.BoxComponent
20792 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20794 * Creates a new Field
20795 * @param {Object} config Configuration options
20797 Roo.form.Field = function(config){
20798 Roo.form.Field.superclass.constructor.call(this, config);
20801 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20803 * @cfg {String} fieldLabel Label to use when rendering a form.
20806 * @cfg {String} qtip Mouse over tip
20810 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20812 invalidClass : "x-form-invalid",
20814 * @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")
20816 invalidText : "The value in this field is invalid",
20818 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20820 focusClass : "x-form-focus",
20822 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20823 automatic validation (defaults to "keyup").
20825 validationEvent : "keyup",
20827 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20829 validateOnBlur : true,
20831 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20833 validationDelay : 250,
20835 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20836 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20838 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20840 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20842 fieldClass : "x-form-field",
20844 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20847 ----------- ----------------------------------------------------------------------
20848 qtip Display a quick tip when the user hovers over the field
20849 title Display a default browser title attribute popup
20850 under Add a block div beneath the field containing the error text
20851 side Add an error icon to the right of the field with a popup on hover
20852 [element id] Add the error text directly to the innerHTML of the specified element
20855 msgTarget : 'qtip',
20857 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20862 * @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.
20867 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20872 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20874 inputType : undefined,
20877 * @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).
20879 tabIndex : undefined,
20882 isFormField : true,
20887 * @property {Roo.Element} fieldEl
20888 * Element Containing the rendered Field (with label etc.)
20891 * @cfg {Mixed} value A value to initialize this field with.
20896 * @cfg {String} name The field's HTML name attribute.
20899 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20903 initComponent : function(){
20904 Roo.form.Field.superclass.initComponent.call(this);
20908 * Fires when this field receives input focus.
20909 * @param {Roo.form.Field} this
20914 * Fires when this field loses input focus.
20915 * @param {Roo.form.Field} this
20919 * @event specialkey
20920 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20921 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20922 * @param {Roo.form.Field} this
20923 * @param {Roo.EventObject} e The event object
20928 * Fires just before the field blurs if the field value has changed.
20929 * @param {Roo.form.Field} this
20930 * @param {Mixed} newValue The new value
20931 * @param {Mixed} oldValue The original value
20936 * Fires after the field has been marked as invalid.
20937 * @param {Roo.form.Field} this
20938 * @param {String} msg The validation message
20943 * Fires after the field has been validated with no errors.
20944 * @param {Roo.form.Field} this
20949 * Fires after the key up
20950 * @param {Roo.form.Field} this
20951 * @param {Roo.EventObject} e The event Object
20958 * Returns the name attribute of the field if available
20959 * @return {String} name The field name
20961 getName: function(){
20962 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20966 onRender : function(ct, position){
20967 Roo.form.Field.superclass.onRender.call(this, ct, position);
20969 var cfg = this.getAutoCreate();
20971 cfg.name = this.name || this.id;
20973 if(this.inputType){
20974 cfg.type = this.inputType;
20976 this.el = ct.createChild(cfg, position);
20978 var type = this.el.dom.type;
20980 if(type == 'password'){
20983 this.el.addClass('x-form-'+type);
20986 this.el.dom.readOnly = true;
20988 if(this.tabIndex !== undefined){
20989 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20992 this.el.addClass([this.fieldClass, this.cls]);
20997 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20998 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20999 * @return {Roo.form.Field} this
21001 applyTo : function(target){
21002 this.allowDomMove = false;
21003 this.el = Roo.get(target);
21004 this.render(this.el.dom.parentNode);
21009 initValue : function(){
21010 if(this.value !== undefined){
21011 this.setValue(this.value);
21012 }else if(this.el.dom.value.length > 0){
21013 this.setValue(this.el.dom.value);
21018 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21020 isDirty : function() {
21021 if(this.disabled) {
21024 return String(this.getValue()) !== String(this.originalValue);
21028 afterRender : function(){
21029 Roo.form.Field.superclass.afterRender.call(this);
21034 fireKey : function(e){
21035 //Roo.log('field ' + e.getKey());
21036 if(e.isNavKeyPress()){
21037 this.fireEvent("specialkey", this, e);
21042 * Resets the current field value to the originally loaded value and clears any validation messages
21044 reset : function(){
21045 this.setValue(this.originalValue);
21046 this.clearInvalid();
21050 initEvents : function(){
21051 // safari killled keypress - so keydown is now used..
21052 this.el.on("keydown" , this.fireKey, this);
21053 this.el.on("focus", this.onFocus, this);
21054 this.el.on("blur", this.onBlur, this);
21055 this.el.relayEvent('keyup', this);
21057 // reference to original value for reset
21058 this.originalValue = this.getValue();
21062 onFocus : function(){
21063 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21064 this.el.addClass(this.focusClass);
21066 if(!this.hasFocus){
21067 this.hasFocus = true;
21068 this.startValue = this.getValue();
21069 this.fireEvent("focus", this);
21073 beforeBlur : Roo.emptyFn,
21076 onBlur : function(){
21078 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21079 this.el.removeClass(this.focusClass);
21081 this.hasFocus = false;
21082 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21085 var v = this.getValue();
21086 if(String(v) !== String(this.startValue)){
21087 this.fireEvent('change', this, v, this.startValue);
21089 this.fireEvent("blur", this);
21093 * Returns whether or not the field value is currently valid
21094 * @param {Boolean} preventMark True to disable marking the field invalid
21095 * @return {Boolean} True if the value is valid, else false
21097 isValid : function(preventMark){
21101 var restore = this.preventMark;
21102 this.preventMark = preventMark === true;
21103 var v = this.validateValue(this.processValue(this.getRawValue()));
21104 this.preventMark = restore;
21109 * Validates the field value
21110 * @return {Boolean} True if the value is valid, else false
21112 validate : function(){
21113 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21114 this.clearInvalid();
21120 processValue : function(value){
21125 // Subclasses should provide the validation implementation by overriding this
21126 validateValue : function(value){
21131 * Mark this field as invalid
21132 * @param {String} msg The validation message
21134 markInvalid : function(msg){
21135 if(!this.rendered || this.preventMark){ // not rendered
21138 this.el.addClass(this.invalidClass);
21139 msg = msg || this.invalidText;
21140 switch(this.msgTarget){
21142 this.el.dom.qtip = msg;
21143 this.el.dom.qclass = 'x-form-invalid-tip';
21144 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21145 Roo.QuickTips.enable();
21149 this.el.dom.title = msg;
21153 var elp = this.el.findParent('.x-form-element', 5, true);
21154 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21155 this.errorEl.setWidth(elp.getWidth(true)-20);
21157 this.errorEl.update(msg);
21158 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21161 if(!this.errorIcon){
21162 var elp = this.el.findParent('.x-form-element', 5, true);
21163 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21165 this.alignErrorIcon();
21166 this.errorIcon.dom.qtip = msg;
21167 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21168 this.errorIcon.show();
21169 this.on('resize', this.alignErrorIcon, this);
21172 var t = Roo.getDom(this.msgTarget);
21174 t.style.display = this.msgDisplay;
21177 this.fireEvent('invalid', this, msg);
21181 alignErrorIcon : function(){
21182 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21186 * Clear any invalid styles/messages for this field
21188 clearInvalid : function(){
21189 if(!this.rendered || this.preventMark){ // not rendered
21192 this.el.removeClass(this.invalidClass);
21193 switch(this.msgTarget){
21195 this.el.dom.qtip = '';
21198 this.el.dom.title = '';
21202 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21206 if(this.errorIcon){
21207 this.errorIcon.dom.qtip = '';
21208 this.errorIcon.hide();
21209 this.un('resize', this.alignErrorIcon, this);
21213 var t = Roo.getDom(this.msgTarget);
21215 t.style.display = 'none';
21218 this.fireEvent('valid', this);
21222 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21223 * @return {Mixed} value The field value
21225 getRawValue : function(){
21226 var v = this.el.getValue();
21227 if(v === this.emptyText){
21234 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21235 * @return {Mixed} value The field value
21237 getValue : function(){
21238 var v = this.el.getValue();
21239 if(v === this.emptyText || v === undefined){
21246 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21247 * @param {Mixed} value The value to set
21249 setRawValue : function(v){
21250 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21254 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21255 * @param {Mixed} value The value to set
21257 setValue : function(v){
21260 this.el.dom.value = (v === null || v === undefined ? '' : v);
21265 adjustSize : function(w, h){
21266 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21267 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21271 adjustWidth : function(tag, w){
21272 tag = tag.toLowerCase();
21273 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21274 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21275 if(tag == 'input'){
21278 if(tag = 'textarea'){
21281 }else if(Roo.isOpera){
21282 if(tag == 'input'){
21285 if(tag = 'textarea'){
21295 // anything other than normal should be considered experimental
21296 Roo.form.Field.msgFx = {
21298 show: function(msgEl, f){
21299 msgEl.setDisplayed('block');
21302 hide : function(msgEl, f){
21303 msgEl.setDisplayed(false).update('');
21308 show: function(msgEl, f){
21309 msgEl.slideIn('t', {stopFx:true});
21312 hide : function(msgEl, f){
21313 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21318 show: function(msgEl, f){
21319 msgEl.fixDisplay();
21320 msgEl.alignTo(f.el, 'tl-tr');
21321 msgEl.slideIn('l', {stopFx:true});
21324 hide : function(msgEl, f){
21325 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21330 * Ext JS Library 1.1.1
21331 * Copyright(c) 2006-2007, Ext JS, LLC.
21333 * Originally Released Under LGPL - original licence link has changed is not relivant.
21336 * <script type="text/javascript">
21341 * @class Roo.form.TextField
21342 * @extends Roo.form.Field
21343 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21344 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21346 * Creates a new TextField
21347 * @param {Object} config Configuration options
21349 Roo.form.TextField = function(config){
21350 Roo.form.TextField.superclass.constructor.call(this, config);
21354 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21355 * according to the default logic, but this event provides a hook for the developer to apply additional
21356 * logic at runtime to resize the field if needed.
21357 * @param {Roo.form.Field} this This text field
21358 * @param {Number} width The new field width
21364 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21366 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21370 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21374 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21378 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21382 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21386 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21388 disableKeyFilter : false,
21390 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21394 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21398 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21400 maxLength : Number.MAX_VALUE,
21402 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21404 minLengthText : "The minimum length for this field is {0}",
21406 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21408 maxLengthText : "The maximum length for this field is {0}",
21410 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21412 selectOnFocus : false,
21414 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21416 blankText : "This field is required",
21418 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21419 * If available, this function will be called only after the basic validators all return true, and will be passed the
21420 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21424 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21425 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21426 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21430 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21434 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21438 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21439 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21441 emptyClass : 'x-form-empty-field',
21444 initEvents : function(){
21445 Roo.form.TextField.superclass.initEvents.call(this);
21446 if(this.validationEvent == 'keyup'){
21447 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21448 this.el.on('keyup', this.filterValidation, this);
21450 else if(this.validationEvent !== false){
21451 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21453 if(this.selectOnFocus || this.emptyText){
21454 this.on("focus", this.preFocus, this);
21455 if(this.emptyText){
21456 this.on('blur', this.postBlur, this);
21457 this.applyEmptyText();
21460 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21461 this.el.on("keypress", this.filterKeys, this);
21464 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21465 this.el.on("click", this.autoSize, this);
21469 processValue : function(value){
21470 if(this.stripCharsRe){
21471 var newValue = value.replace(this.stripCharsRe, '');
21472 if(newValue !== value){
21473 this.setRawValue(newValue);
21480 filterValidation : function(e){
21481 if(!e.isNavKeyPress()){
21482 this.validationTask.delay(this.validationDelay);
21487 onKeyUp : function(e){
21488 if(!e.isNavKeyPress()){
21494 * Resets the current field value to the originally-loaded value and clears any validation messages.
21495 * Also adds emptyText and emptyClass if the original value was blank.
21497 reset : function(){
21498 Roo.form.TextField.superclass.reset.call(this);
21499 this.applyEmptyText();
21502 applyEmptyText : function(){
21503 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21504 this.setRawValue(this.emptyText);
21505 this.el.addClass(this.emptyClass);
21510 preFocus : function(){
21511 if(this.emptyText){
21512 if(this.el.dom.value == this.emptyText){
21513 this.setRawValue('');
21515 this.el.removeClass(this.emptyClass);
21517 if(this.selectOnFocus){
21518 this.el.dom.select();
21523 postBlur : function(){
21524 this.applyEmptyText();
21528 filterKeys : function(e){
21529 var k = e.getKey();
21530 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21533 var c = e.getCharCode(), cc = String.fromCharCode(c);
21534 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21537 if(!this.maskRe.test(cc)){
21542 setValue : function(v){
21543 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21544 this.el.removeClass(this.emptyClass);
21546 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21547 this.applyEmptyText();
21552 * Validates a value according to the field's validation rules and marks the field as invalid
21553 * if the validation fails
21554 * @param {Mixed} value The value to validate
21555 * @return {Boolean} True if the value is valid, else false
21557 validateValue : function(value){
21558 if(value.length < 1 || value === this.emptyText){ // if it's blank
21559 if(this.allowBlank){
21560 this.clearInvalid();
21563 this.markInvalid(this.blankText);
21567 if(value.length < this.minLength){
21568 this.markInvalid(String.format(this.minLengthText, this.minLength));
21571 if(value.length > this.maxLength){
21572 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21576 var vt = Roo.form.VTypes;
21577 if(!vt[this.vtype](value, this)){
21578 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21582 if(typeof this.validator == "function"){
21583 var msg = this.validator(value);
21585 this.markInvalid(msg);
21589 if(this.regex && !this.regex.test(value)){
21590 this.markInvalid(this.regexText);
21597 * Selects text in this field
21598 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21599 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21601 selectText : function(start, end){
21602 var v = this.getRawValue();
21604 start = start === undefined ? 0 : start;
21605 end = end === undefined ? v.length : end;
21606 var d = this.el.dom;
21607 if(d.setSelectionRange){
21608 d.setSelectionRange(start, end);
21609 }else if(d.createTextRange){
21610 var range = d.createTextRange();
21611 range.moveStart("character", start);
21612 range.moveEnd("character", v.length-end);
21619 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21620 * This only takes effect if grow = true, and fires the autosize event.
21622 autoSize : function(){
21623 if(!this.grow || !this.rendered){
21627 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21630 var v = el.dom.value;
21631 var d = document.createElement('div');
21632 d.appendChild(document.createTextNode(v));
21636 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21637 this.el.setWidth(w);
21638 this.fireEvent("autosize", this, w);
21642 * Ext JS Library 1.1.1
21643 * Copyright(c) 2006-2007, Ext JS, LLC.
21645 * Originally Released Under LGPL - original licence link has changed is not relivant.
21648 * <script type="text/javascript">
21652 * @class Roo.form.Hidden
21653 * @extends Roo.form.TextField
21654 * Simple Hidden element used on forms
21656 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21659 * Creates a new Hidden form element.
21660 * @param {Object} config Configuration options
21665 // easy hidden field...
21666 Roo.form.Hidden = function(config){
21667 Roo.form.Hidden.superclass.constructor.call(this, config);
21670 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21672 inputType: 'hidden',
21675 labelSeparator: '',
21677 itemCls : 'x-form-item-display-none'
21685 * Ext JS Library 1.1.1
21686 * Copyright(c) 2006-2007, Ext JS, LLC.
21688 * Originally Released Under LGPL - original licence link has changed is not relivant.
21691 * <script type="text/javascript">
21695 * @class Roo.form.TriggerField
21696 * @extends Roo.form.TextField
21697 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21698 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21699 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21700 * for which you can provide a custom implementation. For example:
21702 var trigger = new Roo.form.TriggerField();
21703 trigger.onTriggerClick = myTriggerFn;
21704 trigger.applyTo('my-field');
21707 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21708 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21709 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21710 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21712 * Create a new TriggerField.
21713 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21714 * to the base TextField)
21716 Roo.form.TriggerField = function(config){
21717 this.mimicing = false;
21718 Roo.form.TriggerField.superclass.constructor.call(this, config);
21721 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21723 * @cfg {String} triggerClass A CSS class to apply to the trigger
21726 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21727 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21729 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21731 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21735 /** @cfg {Boolean} grow @hide */
21736 /** @cfg {Number} growMin @hide */
21737 /** @cfg {Number} growMax @hide */
21743 autoSize: Roo.emptyFn,
21747 deferHeight : true,
21750 actionMode : 'wrap',
21752 onResize : function(w, h){
21753 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21754 if(typeof w == 'number'){
21755 var x = w - this.trigger.getWidth();
21756 this.el.setWidth(this.adjustWidth('input', x));
21757 this.trigger.setStyle('left', x+'px');
21762 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21765 getResizeEl : function(){
21770 getPositionEl : function(){
21775 alignErrorIcon : function(){
21776 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21780 onRender : function(ct, position){
21781 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21782 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21783 this.trigger = this.wrap.createChild(this.triggerConfig ||
21784 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21785 if(this.hideTrigger){
21786 this.trigger.setDisplayed(false);
21788 this.initTrigger();
21790 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21795 initTrigger : function(){
21796 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21797 this.trigger.addClassOnOver('x-form-trigger-over');
21798 this.trigger.addClassOnClick('x-form-trigger-click');
21802 onDestroy : function(){
21804 this.trigger.removeAllListeners();
21805 this.trigger.remove();
21808 this.wrap.remove();
21810 Roo.form.TriggerField.superclass.onDestroy.call(this);
21814 onFocus : function(){
21815 Roo.form.TriggerField.superclass.onFocus.call(this);
21816 if(!this.mimicing){
21817 this.wrap.addClass('x-trigger-wrap-focus');
21818 this.mimicing = true;
21819 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21820 if(this.monitorTab){
21821 this.el.on("keydown", this.checkTab, this);
21827 checkTab : function(e){
21828 if(e.getKey() == e.TAB){
21829 this.triggerBlur();
21834 onBlur : function(){
21839 mimicBlur : function(e, t){
21840 if(!this.wrap.contains(t) && this.validateBlur()){
21841 this.triggerBlur();
21846 triggerBlur : function(){
21847 this.mimicing = false;
21848 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21849 if(this.monitorTab){
21850 this.el.un("keydown", this.checkTab, this);
21852 this.wrap.removeClass('x-trigger-wrap-focus');
21853 Roo.form.TriggerField.superclass.onBlur.call(this);
21857 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21858 validateBlur : function(e, t){
21863 onDisable : function(){
21864 Roo.form.TriggerField.superclass.onDisable.call(this);
21866 this.wrap.addClass('x-item-disabled');
21871 onEnable : function(){
21872 Roo.form.TriggerField.superclass.onEnable.call(this);
21874 this.wrap.removeClass('x-item-disabled');
21879 onShow : function(){
21880 var ae = this.getActionEl();
21883 ae.dom.style.display = '';
21884 ae.dom.style.visibility = 'visible';
21890 onHide : function(){
21891 var ae = this.getActionEl();
21892 ae.dom.style.display = 'none';
21896 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21897 * by an implementing function.
21899 * @param {EventObject} e
21901 onTriggerClick : Roo.emptyFn
21904 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21905 // to be extended by an implementing class. For an example of implementing this class, see the custom
21906 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21907 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21908 initComponent : function(){
21909 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21911 this.triggerConfig = {
21912 tag:'span', cls:'x-form-twin-triggers', cn:[
21913 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21914 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21918 getTrigger : function(index){
21919 return this.triggers[index];
21922 initTrigger : function(){
21923 var ts = this.trigger.select('.x-form-trigger', true);
21924 this.wrap.setStyle('overflow', 'hidden');
21925 var triggerField = this;
21926 ts.each(function(t, all, index){
21927 t.hide = function(){
21928 var w = triggerField.wrap.getWidth();
21929 this.dom.style.display = 'none';
21930 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21932 t.show = function(){
21933 var w = triggerField.wrap.getWidth();
21934 this.dom.style.display = '';
21935 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21937 var triggerIndex = 'Trigger'+(index+1);
21939 if(this['hide'+triggerIndex]){
21940 t.dom.style.display = 'none';
21942 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21943 t.addClassOnOver('x-form-trigger-over');
21944 t.addClassOnClick('x-form-trigger-click');
21946 this.triggers = ts.elements;
21949 onTrigger1Click : Roo.emptyFn,
21950 onTrigger2Click : Roo.emptyFn
21953 * Ext JS Library 1.1.1
21954 * Copyright(c) 2006-2007, Ext JS, LLC.
21956 * Originally Released Under LGPL - original licence link has changed is not relivant.
21959 * <script type="text/javascript">
21963 * @class Roo.form.TextArea
21964 * @extends Roo.form.TextField
21965 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21966 * support for auto-sizing.
21968 * Creates a new TextArea
21969 * @param {Object} config Configuration options
21971 Roo.form.TextArea = function(config){
21972 Roo.form.TextArea.superclass.constructor.call(this, config);
21973 // these are provided exchanges for backwards compat
21974 // minHeight/maxHeight were replaced by growMin/growMax to be
21975 // compatible with TextField growing config values
21976 if(this.minHeight !== undefined){
21977 this.growMin = this.minHeight;
21979 if(this.maxHeight !== undefined){
21980 this.growMax = this.maxHeight;
21984 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
21986 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
21990 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
21994 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
21995 * in the field (equivalent to setting overflow: hidden, defaults to false)
21997 preventScrollbars: false,
21999 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
22000 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
22004 onRender : function(ct, position){
22006 this.defaultAutoCreate = {
22008 style:"width:300px;height:60px;",
22009 autocomplete: "off"
22012 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22014 this.textSizeEl = Roo.DomHelper.append(document.body, {
22015 tag: "pre", cls: "x-form-grow-sizer"
22017 if(this.preventScrollbars){
22018 this.el.setStyle("overflow", "hidden");
22020 this.el.setHeight(this.growMin);
22024 onDestroy : function(){
22025 if(this.textSizeEl){
22026 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22028 Roo.form.TextArea.superclass.onDestroy.call(this);
22032 onKeyUp : function(e){
22033 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22039 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22040 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22042 autoSize : function(){
22043 if(!this.grow || !this.textSizeEl){
22047 var v = el.dom.value;
22048 var ts = this.textSizeEl;
22051 ts.appendChild(document.createTextNode(v));
22054 Roo.fly(ts).setWidth(this.el.getWidth());
22056 v = "  ";
22059 v = v.replace(/\n/g, '<p> </p>');
22061 v += " \n ";
22064 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22065 if(h != this.lastHeight){
22066 this.lastHeight = h;
22067 this.el.setHeight(h);
22068 this.fireEvent("autosize", this, h);
22073 * Ext JS Library 1.1.1
22074 * Copyright(c) 2006-2007, Ext JS, LLC.
22076 * Originally Released Under LGPL - original licence link has changed is not relivant.
22079 * <script type="text/javascript">
22084 * @class Roo.form.NumberField
22085 * @extends Roo.form.TextField
22086 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22088 * Creates a new NumberField
22089 * @param {Object} config Configuration options
22091 Roo.form.NumberField = function(config){
22092 Roo.form.NumberField.superclass.constructor.call(this, config);
22095 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22097 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22099 fieldClass: "x-form-field x-form-num-field",
22101 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22103 allowDecimals : true,
22105 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22107 decimalSeparator : ".",
22109 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22111 decimalPrecision : 2,
22113 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22115 allowNegative : true,
22117 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22119 minValue : Number.NEGATIVE_INFINITY,
22121 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22123 maxValue : Number.MAX_VALUE,
22125 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22127 minText : "The minimum value for this field is {0}",
22129 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22131 maxText : "The maximum value for this field is {0}",
22133 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22134 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22136 nanText : "{0} is not a valid number",
22139 initEvents : function(){
22140 Roo.form.NumberField.superclass.initEvents.call(this);
22141 var allowed = "0123456789";
22142 if(this.allowDecimals){
22143 allowed += this.decimalSeparator;
22145 if(this.allowNegative){
22148 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22149 var keyPress = function(e){
22150 var k = e.getKey();
22151 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22154 var c = e.getCharCode();
22155 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22159 this.el.on("keypress", keyPress, this);
22163 validateValue : function(value){
22164 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22167 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22170 var num = this.parseValue(value);
22172 this.markInvalid(String.format(this.nanText, value));
22175 if(num < this.minValue){
22176 this.markInvalid(String.format(this.minText, this.minValue));
22179 if(num > this.maxValue){
22180 this.markInvalid(String.format(this.maxText, this.maxValue));
22186 getValue : function(){
22187 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22191 parseValue : function(value){
22192 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22193 return isNaN(value) ? '' : value;
22197 fixPrecision : function(value){
22198 var nan = isNaN(value);
22199 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22200 return nan ? '' : value;
22202 return parseFloat(value).toFixed(this.decimalPrecision);
22205 setValue : function(v){
22206 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22210 decimalPrecisionFcn : function(v){
22211 return Math.floor(v);
22214 beforeBlur : function(){
22215 var v = this.parseValue(this.getRawValue());
22217 this.setValue(this.fixPrecision(v));
22222 * Ext JS Library 1.1.1
22223 * Copyright(c) 2006-2007, Ext JS, LLC.
22225 * Originally Released Under LGPL - original licence link has changed is not relivant.
22228 * <script type="text/javascript">
22232 * @class Roo.form.DateField
22233 * @extends Roo.form.TriggerField
22234 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22236 * Create a new DateField
22237 * @param {Object} config
22239 Roo.form.DateField = function(config){
22240 Roo.form.DateField.superclass.constructor.call(this, config);
22246 * Fires when a date is selected
22247 * @param {Roo.form.DateField} combo This combo box
22248 * @param {Date} date The date selected
22255 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22256 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22257 this.ddMatch = null;
22258 if(this.disabledDates){
22259 var dd = this.disabledDates;
22261 for(var i = 0; i < dd.length; i++){
22263 if(i != dd.length-1) re += "|";
22265 this.ddMatch = new RegExp(re + ")");
22269 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22271 * @cfg {String} format
22272 * The default date format string which can be overriden for localization support. The format must be
22273 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22277 * @cfg {String} altFormats
22278 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22279 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22281 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22283 * @cfg {Array} disabledDays
22284 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22286 disabledDays : null,
22288 * @cfg {String} disabledDaysText
22289 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22291 disabledDaysText : "Disabled",
22293 * @cfg {Array} disabledDates
22294 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22295 * expression so they are very powerful. Some examples:
22297 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22298 * <li>["03/08", "09/16"] would disable those days for every year</li>
22299 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22300 * <li>["03/../2006"] would disable every day in March 2006</li>
22301 * <li>["^03"] would disable every day in every March</li>
22303 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22304 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22306 disabledDates : null,
22308 * @cfg {String} disabledDatesText
22309 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22311 disabledDatesText : "Disabled",
22313 * @cfg {Date/String} minValue
22314 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22315 * valid format (defaults to null).
22319 * @cfg {Date/String} maxValue
22320 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22321 * valid format (defaults to null).
22325 * @cfg {String} minText
22326 * The error text to display when the date in the cell is before minValue (defaults to
22327 * 'The date in this field must be after {minValue}').
22329 minText : "The date in this field must be equal to or after {0}",
22331 * @cfg {String} maxText
22332 * The error text to display when the date in the cell is after maxValue (defaults to
22333 * 'The date in this field must be before {maxValue}').
22335 maxText : "The date in this field must be equal to or before {0}",
22337 * @cfg {String} invalidText
22338 * The error text to display when the date in the field is invalid (defaults to
22339 * '{value} is not a valid date - it must be in the format {format}').
22341 invalidText : "{0} is not a valid date - it must be in the format {1}",
22343 * @cfg {String} triggerClass
22344 * An additional CSS class used to style the trigger button. The trigger will always get the
22345 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22346 * which displays a calendar icon).
22348 triggerClass : 'x-form-date-trigger',
22352 * @cfg {bool} useIso
22353 * if enabled, then the date field will use a hidden field to store the
22354 * real value as iso formated date. default (false)
22358 * @cfg {String/Object} autoCreate
22359 * A DomHelper element spec, or true for a default element spec (defaults to
22360 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22363 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22366 hiddenField: false,
22368 onRender : function(ct, position)
22370 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22372 this.el.dom.removeAttribute('name');
22373 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22375 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22376 // prevent input submission
22377 this.hiddenName = this.name;
22384 validateValue : function(value)
22386 value = this.formatDate(value);
22387 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22390 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22393 var svalue = value;
22394 value = this.parseDate(value);
22396 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22399 var time = value.getTime();
22400 if(this.minValue && time < this.minValue.getTime()){
22401 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22404 if(this.maxValue && time > this.maxValue.getTime()){
22405 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22408 if(this.disabledDays){
22409 var day = value.getDay();
22410 for(var i = 0; i < this.disabledDays.length; i++) {
22411 if(day === this.disabledDays[i]){
22412 this.markInvalid(this.disabledDaysText);
22417 var fvalue = this.formatDate(value);
22418 if(this.ddMatch && this.ddMatch.test(fvalue)){
22419 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22426 // Provides logic to override the default TriggerField.validateBlur which just returns true
22427 validateBlur : function(){
22428 return !this.menu || !this.menu.isVisible();
22432 * Returns the current date value of the date field.
22433 * @return {Date} The date value
22435 getValue : function(){
22437 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22441 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22442 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22443 * (the default format used is "m/d/y").
22446 //All of these calls set the same date value (May 4, 2006)
22448 //Pass a date object:
22449 var dt = new Date('5/4/06');
22450 dateField.setValue(dt);
22452 //Pass a date string (default format):
22453 dateField.setValue('5/4/06');
22455 //Pass a date string (custom format):
22456 dateField.format = 'Y-m-d';
22457 dateField.setValue('2006-5-4');
22459 * @param {String/Date} date The date or valid date string
22461 setValue : function(date){
22462 if (this.hiddenField) {
22463 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22465 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22469 parseDate : function(value){
22470 if(!value || value instanceof Date){
22473 var v = Date.parseDate(value, this.format);
22474 if(!v && this.altFormats){
22475 if(!this.altFormatsArray){
22476 this.altFormatsArray = this.altFormats.split("|");
22478 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22479 v = Date.parseDate(value, this.altFormatsArray[i]);
22486 formatDate : function(date, fmt){
22487 return (!date || !(date instanceof Date)) ?
22488 date : date.dateFormat(fmt || this.format);
22493 select: function(m, d){
22495 this.fireEvent('select', this, d);
22497 show : function(){ // retain focus styling
22501 this.focus.defer(10, this);
22502 var ml = this.menuListeners;
22503 this.menu.un("select", ml.select, this);
22504 this.menu.un("show", ml.show, this);
22505 this.menu.un("hide", ml.hide, this);
22510 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22511 onTriggerClick : function(){
22515 if(this.menu == null){
22516 this.menu = new Roo.menu.DateMenu();
22518 Roo.apply(this.menu.picker, {
22519 showClear: this.allowBlank,
22520 minDate : this.minValue,
22521 maxDate : this.maxValue,
22522 disabledDatesRE : this.ddMatch,
22523 disabledDatesText : this.disabledDatesText,
22524 disabledDays : this.disabledDays,
22525 disabledDaysText : this.disabledDaysText,
22526 format : this.format,
22527 minText : String.format(this.minText, this.formatDate(this.minValue)),
22528 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22530 this.menu.on(Roo.apply({}, this.menuListeners, {
22533 this.menu.picker.setValue(this.getValue() || new Date());
22534 this.menu.show(this.el, "tl-bl?");
22537 beforeBlur : function(){
22538 var v = this.parseDate(this.getRawValue());
22544 /** @cfg {Boolean} grow @hide */
22545 /** @cfg {Number} growMin @hide */
22546 /** @cfg {Number} growMax @hide */
22553 * Ext JS Library 1.1.1
22554 * Copyright(c) 2006-2007, Ext JS, LLC.
22556 * Originally Released Under LGPL - original licence link has changed is not relivant.
22559 * <script type="text/javascript">
22564 * @class Roo.form.ComboBox
22565 * @extends Roo.form.TriggerField
22566 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22568 * Create a new ComboBox.
22569 * @param {Object} config Configuration options
22571 Roo.form.ComboBox = function(config){
22572 Roo.form.ComboBox.superclass.constructor.call(this, config);
22576 * Fires when the dropdown list is expanded
22577 * @param {Roo.form.ComboBox} combo This combo box
22582 * Fires when the dropdown list is collapsed
22583 * @param {Roo.form.ComboBox} combo This combo box
22587 * @event beforeselect
22588 * Fires before a list item is selected. Return false to cancel the selection.
22589 * @param {Roo.form.ComboBox} combo This combo box
22590 * @param {Roo.data.Record} record The data record returned from the underlying store
22591 * @param {Number} index The index of the selected item in the dropdown list
22593 'beforeselect' : true,
22596 * Fires when a list item is selected
22597 * @param {Roo.form.ComboBox} combo This combo box
22598 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22599 * @param {Number} index The index of the selected item in the dropdown list
22603 * @event beforequery
22604 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22605 * The event object passed has these properties:
22606 * @param {Roo.form.ComboBox} combo This combo box
22607 * @param {String} query The query
22608 * @param {Boolean} forceAll true to force "all" query
22609 * @param {Boolean} cancel true to cancel the query
22610 * @param {Object} e The query event object
22612 'beforequery': true,
22615 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22616 * @param {Roo.form.ComboBox} combo This combo box
22621 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22622 * @param {Roo.form.ComboBox} combo This combo box
22623 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22629 if(this.transform){
22630 this.allowDomMove = false;
22631 var s = Roo.getDom(this.transform);
22632 if(!this.hiddenName){
22633 this.hiddenName = s.name;
22636 this.mode = 'local';
22637 var d = [], opts = s.options;
22638 for(var i = 0, len = opts.length;i < len; i++){
22640 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22642 this.value = value;
22644 d.push([value, o.text]);
22646 this.store = new Roo.data.SimpleStore({
22648 fields: ['value', 'text'],
22651 this.valueField = 'value';
22652 this.displayField = 'text';
22654 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22655 if(!this.lazyRender){
22656 this.target = true;
22657 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22658 s.parentNode.removeChild(s); // remove it
22659 this.render(this.el.parentNode);
22661 s.parentNode.removeChild(s); // remove it
22666 this.store = Roo.factory(this.store, Roo.data);
22669 this.selectedIndex = -1;
22670 if(this.mode == 'local'){
22671 if(config.queryDelay === undefined){
22672 this.queryDelay = 10;
22674 if(config.minChars === undefined){
22680 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22682 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22685 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22686 * rendering into an Roo.Editor, defaults to false)
22689 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22690 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22693 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22696 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22697 * the dropdown list (defaults to undefined, with no header element)
22701 * @cfg {String/Roo.Template} tpl The template to use to render the output
22705 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22707 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22709 listWidth: undefined,
22711 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22712 * mode = 'remote' or 'text' if mode = 'local')
22714 displayField: undefined,
22716 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22717 * mode = 'remote' or 'value' if mode = 'local').
22718 * Note: use of a valueField requires the user make a selection
22719 * in order for a value to be mapped.
22721 valueField: undefined,
22723 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22724 * field's data value (defaults to the underlying DOM element's name)
22726 hiddenName: undefined,
22728 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22732 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22734 selectedClass: 'x-combo-selected',
22736 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22737 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22738 * which displays a downward arrow icon).
22740 triggerClass : 'x-form-arrow-trigger',
22742 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22746 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22747 * anchor positions (defaults to 'tl-bl')
22749 listAlign: 'tl-bl?',
22751 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22755 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22756 * query specified by the allQuery config option (defaults to 'query')
22758 triggerAction: 'query',
22760 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22761 * (defaults to 4, does not apply if editable = false)
22765 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22766 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22770 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22771 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22775 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22776 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22780 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22781 * when editable = true (defaults to false)
22783 selectOnFocus:false,
22785 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22787 queryParam: 'query',
22789 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22790 * when mode = 'remote' (defaults to 'Loading...')
22792 loadingText: 'Loading...',
22794 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22798 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22802 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22803 * traditional select (defaults to true)
22807 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22811 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22815 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22816 * listWidth has a higher value)
22820 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22821 * allow the user to set arbitrary text into the field (defaults to false)
22823 forceSelection:false,
22825 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22826 * if typeAhead = true (defaults to 250)
22828 typeAheadDelay : 250,
22830 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22831 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22833 valueNotFoundText : undefined,
22835 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22837 blockFocus : false,
22840 * @cfg {Boolean} disableClear Disable showing of clear button.
22842 disableClear : false,
22844 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22846 alwaysQuery : false,
22854 onRender : function(ct, position){
22855 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22856 if(this.hiddenName){
22857 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22859 this.hiddenField.value =
22860 this.hiddenValue !== undefined ? this.hiddenValue :
22861 this.value !== undefined ? this.value : '';
22863 // prevent input submission
22864 this.el.dom.removeAttribute('name');
22867 this.el.dom.setAttribute('autocomplete', 'off');
22870 var cls = 'x-combo-list';
22872 this.list = new Roo.Layer({
22873 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22876 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22877 this.list.setWidth(lw);
22878 this.list.swallowEvent('mousewheel');
22879 this.assetHeight = 0;
22882 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22883 this.assetHeight += this.header.getHeight();
22886 this.innerList = this.list.createChild({cls:cls+'-inner'});
22887 this.innerList.on('mouseover', this.onViewOver, this);
22888 this.innerList.on('mousemove', this.onViewMove, this);
22889 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22891 if(this.allowBlank && !this.pageSize && !this.disableClear){
22892 this.footer = this.list.createChild({cls:cls+'-ft'});
22893 this.pageTb = new Roo.Toolbar(this.footer);
22897 this.footer = this.list.createChild({cls:cls+'-ft'});
22898 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22899 {pageSize: this.pageSize});
22903 if (this.pageTb && this.allowBlank && !this.disableClear) {
22905 this.pageTb.add(new Roo.Toolbar.Fill(), {
22906 cls: 'x-btn-icon x-btn-clear',
22908 handler: function()
22911 _this.clearValue();
22912 _this.onSelect(false, -1);
22917 this.assetHeight += this.footer.getHeight();
22922 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22925 this.view = new Roo.View(this.innerList, this.tpl, {
22926 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22929 this.view.on('click', this.onViewClick, this);
22931 this.store.on('beforeload', this.onBeforeLoad, this);
22932 this.store.on('load', this.onLoad, this);
22933 this.store.on('loadexception', this.collapse, this);
22935 if(this.resizable){
22936 this.resizer = new Roo.Resizable(this.list, {
22937 pinned:true, handles:'se'
22939 this.resizer.on('resize', function(r, w, h){
22940 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22941 this.listWidth = w;
22942 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22943 this.restrictHeight();
22945 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22947 if(!this.editable){
22948 this.editable = true;
22949 this.setEditable(false);
22953 if (typeof(this.events.add.listeners) != 'undefined') {
22955 this.addicon = this.wrap.createChild(
22956 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22958 this.addicon.on('click', function(e) {
22959 this.fireEvent('add', this);
22962 if (typeof(this.events.edit.listeners) != 'undefined') {
22964 this.editicon = this.wrap.createChild(
22965 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22966 if (this.addicon) {
22967 this.editicon.setStyle('margin-left', '40px');
22969 this.editicon.on('click', function(e) {
22971 // we fire even if inothing is selected..
22972 this.fireEvent('edit', this, this.lastData );
22982 initEvents : function(){
22983 Roo.form.ComboBox.superclass.initEvents.call(this);
22985 this.keyNav = new Roo.KeyNav(this.el, {
22986 "up" : function(e){
22987 this.inKeyMode = true;
22991 "down" : function(e){
22992 if(!this.isExpanded()){
22993 this.onTriggerClick();
22995 this.inKeyMode = true;
23000 "enter" : function(e){
23001 this.onViewClick();
23005 "esc" : function(e){
23009 "tab" : function(e){
23010 this.onViewClick(false);
23016 doRelay : function(foo, bar, hname){
23017 if(hname == 'down' || this.scope.isExpanded()){
23018 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23025 this.queryDelay = Math.max(this.queryDelay || 10,
23026 this.mode == 'local' ? 10 : 250);
23027 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23028 if(this.typeAhead){
23029 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23031 if(this.editable !== false){
23032 this.el.on("keyup", this.onKeyUp, this);
23034 if(this.forceSelection){
23035 this.on('blur', this.doForce, this);
23039 onDestroy : function(){
23041 this.view.setStore(null);
23042 this.view.el.removeAllListeners();
23043 this.view.el.remove();
23044 this.view.purgeListeners();
23047 this.list.destroy();
23050 this.store.un('beforeload', this.onBeforeLoad, this);
23051 this.store.un('load', this.onLoad, this);
23052 this.store.un('loadexception', this.collapse, this);
23054 Roo.form.ComboBox.superclass.onDestroy.call(this);
23058 fireKey : function(e){
23059 if(e.isNavKeyPress() && !this.list.isVisible()){
23060 this.fireEvent("specialkey", this, e);
23065 onResize: function(w, h){
23066 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23068 if(typeof w != 'number'){
23069 // we do not handle it!?!?
23072 var tw = this.trigger.getWidth();
23073 tw += this.addicon ? this.addicon.getWidth() : 0;
23074 tw += this.editicon ? this.editicon.getWidth() : 0;
23076 this.el.setWidth( this.adjustWidth('input', x));
23078 this.trigger.setStyle('left', x+'px');
23080 if(this.list && this.listWidth === undefined){
23081 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23082 this.list.setWidth(lw);
23083 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23091 * Allow or prevent the user from directly editing the field text. If false is passed,
23092 * the user will only be able to select from the items defined in the dropdown list. This method
23093 * is the runtime equivalent of setting the 'editable' config option at config time.
23094 * @param {Boolean} value True to allow the user to directly edit the field text
23096 setEditable : function(value){
23097 if(value == this.editable){
23100 this.editable = value;
23102 this.el.dom.setAttribute('readOnly', true);
23103 this.el.on('mousedown', this.onTriggerClick, this);
23104 this.el.addClass('x-combo-noedit');
23106 this.el.dom.setAttribute('readOnly', false);
23107 this.el.un('mousedown', this.onTriggerClick, this);
23108 this.el.removeClass('x-combo-noedit');
23113 onBeforeLoad : function(){
23114 if(!this.hasFocus){
23117 this.innerList.update(this.loadingText ?
23118 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23119 this.restrictHeight();
23120 this.selectedIndex = -1;
23124 onLoad : function(){
23125 if(!this.hasFocus){
23128 if(this.store.getCount() > 0){
23130 this.restrictHeight();
23131 if(this.lastQuery == this.allQuery){
23133 this.el.dom.select();
23135 if(!this.selectByValue(this.value, true)){
23136 this.select(0, true);
23140 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23141 this.taTask.delay(this.typeAheadDelay);
23145 this.onEmptyResults();
23151 onTypeAhead : function(){
23152 if(this.store.getCount() > 0){
23153 var r = this.store.getAt(0);
23154 var newValue = r.data[this.displayField];
23155 var len = newValue.length;
23156 var selStart = this.getRawValue().length;
23157 if(selStart != len){
23158 this.setRawValue(newValue);
23159 this.selectText(selStart, newValue.length);
23165 onSelect : function(record, index){
23166 if(this.fireEvent('beforeselect', this, record, index) !== false){
23167 this.setFromData(index > -1 ? record.data : false);
23169 this.fireEvent('select', this, record, index);
23174 * Returns the currently selected field value or empty string if no value is set.
23175 * @return {String} value The selected value
23177 getValue : function(){
23178 if(this.valueField){
23179 return typeof this.value != 'undefined' ? this.value : '';
23181 return Roo.form.ComboBox.superclass.getValue.call(this);
23186 * Clears any text/value currently set in the field
23188 clearValue : function(){
23189 if(this.hiddenField){
23190 this.hiddenField.value = '';
23193 this.setRawValue('');
23194 this.lastSelectionText = '';
23195 this.applyEmptyText();
23199 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23200 * will be displayed in the field. If the value does not match the data value of an existing item,
23201 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23202 * Otherwise the field will be blank (although the value will still be set).
23203 * @param {String} value The value to match
23205 setValue : function(v){
23207 if(this.valueField){
23208 var r = this.findRecord(this.valueField, v);
23210 text = r.data[this.displayField];
23211 }else if(this.valueNotFoundText !== undefined){
23212 text = this.valueNotFoundText;
23215 this.lastSelectionText = text;
23216 if(this.hiddenField){
23217 this.hiddenField.value = v;
23219 Roo.form.ComboBox.superclass.setValue.call(this, text);
23223 * @property {Object} the last set data for the element
23228 * Sets the value of the field based on a object which is related to the record format for the store.
23229 * @param {Object} value the value to set as. or false on reset?
23231 setFromData : function(o){
23232 var dv = ''; // display value
23233 var vv = ''; // value value..
23235 if (this.displayField) {
23236 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23238 // this is an error condition!!!
23239 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23242 if(this.valueField){
23243 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23245 if(this.hiddenField){
23246 this.hiddenField.value = vv;
23248 this.lastSelectionText = dv;
23249 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23253 // no hidden field.. - we store the value in 'value', but still display
23254 // display field!!!!
23255 this.lastSelectionText = dv;
23256 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23262 reset : function(){
23263 // overridden so that last data is reset..
23264 this.setValue(this.originalValue);
23265 this.clearInvalid();
23266 this.lastData = false;
23269 findRecord : function(prop, value){
23271 if(this.store.getCount() > 0){
23272 this.store.each(function(r){
23273 if(r.data[prop] == value){
23283 onViewMove : function(e, t){
23284 this.inKeyMode = false;
23288 onViewOver : function(e, t){
23289 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23292 var item = this.view.findItemFromChild(t);
23294 var index = this.view.indexOf(item);
23295 this.select(index, false);
23300 onViewClick : function(doFocus){
23301 var index = this.view.getSelectedIndexes()[0];
23302 var r = this.store.getAt(index);
23304 this.onSelect(r, index);
23306 if(doFocus !== false && !this.blockFocus){
23312 restrictHeight : function(){
23313 this.innerList.dom.style.height = '';
23314 var inner = this.innerList.dom;
23315 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23316 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23317 this.list.beginUpdate();
23318 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23319 this.list.alignTo(this.el, this.listAlign);
23320 this.list.endUpdate();
23324 onEmptyResults : function(){
23329 * Returns true if the dropdown list is expanded, else false.
23331 isExpanded : function(){
23332 return this.list.isVisible();
23336 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23337 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23338 * @param {String} value The data value of the item to select
23339 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23340 * selected item if it is not currently in view (defaults to true)
23341 * @return {Boolean} True if the value matched an item in the list, else false
23343 selectByValue : function(v, scrollIntoView){
23344 if(v !== undefined && v !== null){
23345 var r = this.findRecord(this.valueField || this.displayField, v);
23347 this.select(this.store.indexOf(r), scrollIntoView);
23355 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23356 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23357 * @param {Number} index The zero-based index of the list item to select
23358 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23359 * selected item if it is not currently in view (defaults to true)
23361 select : function(index, scrollIntoView){
23362 this.selectedIndex = index;
23363 this.view.select(index);
23364 if(scrollIntoView !== false){
23365 var el = this.view.getNode(index);
23367 this.innerList.scrollChildIntoView(el, false);
23373 selectNext : function(){
23374 var ct = this.store.getCount();
23376 if(this.selectedIndex == -1){
23378 }else if(this.selectedIndex < ct-1){
23379 this.select(this.selectedIndex+1);
23385 selectPrev : function(){
23386 var ct = this.store.getCount();
23388 if(this.selectedIndex == -1){
23390 }else if(this.selectedIndex != 0){
23391 this.select(this.selectedIndex-1);
23397 onKeyUp : function(e){
23398 if(this.editable !== false && !e.isSpecialKey()){
23399 this.lastKey = e.getKey();
23400 this.dqTask.delay(this.queryDelay);
23405 validateBlur : function(){
23406 return !this.list || !this.list.isVisible();
23410 initQuery : function(){
23411 this.doQuery(this.getRawValue());
23415 doForce : function(){
23416 if(this.el.dom.value.length > 0){
23417 this.el.dom.value =
23418 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23419 this.applyEmptyText();
23424 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23425 * query allowing the query action to be canceled if needed.
23426 * @param {String} query The SQL query to execute
23427 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23428 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23429 * saved in the current store (defaults to false)
23431 doQuery : function(q, forceAll){
23432 if(q === undefined || q === null){
23437 forceAll: forceAll,
23441 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23445 forceAll = qe.forceAll;
23446 if(forceAll === true || (q.length >= this.minChars)){
23447 if(this.lastQuery != q || this.alwaysQuery){
23448 this.lastQuery = q;
23449 if(this.mode == 'local'){
23450 this.selectedIndex = -1;
23452 this.store.clearFilter();
23454 this.store.filter(this.displayField, q);
23458 this.store.baseParams[this.queryParam] = q;
23460 params: this.getParams(q)
23465 this.selectedIndex = -1;
23472 getParams : function(q){
23474 //p[this.queryParam] = q;
23477 p.limit = this.pageSize;
23483 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23485 collapse : function(){
23486 if(!this.isExpanded()){
23490 Roo.get(document).un('mousedown', this.collapseIf, this);
23491 Roo.get(document).un('mousewheel', this.collapseIf, this);
23492 if (!this.editable) {
23493 Roo.get(document).un('keydown', this.listKeyPress, this);
23495 this.fireEvent('collapse', this);
23499 collapseIf : function(e){
23500 if(!e.within(this.wrap) && !e.within(this.list)){
23506 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23508 expand : function(){
23509 if(this.isExpanded() || !this.hasFocus){
23512 this.list.alignTo(this.el, this.listAlign);
23514 Roo.get(document).on('mousedown', this.collapseIf, this);
23515 Roo.get(document).on('mousewheel', this.collapseIf, this);
23516 if (!this.editable) {
23517 Roo.get(document).on('keydown', this.listKeyPress, this);
23520 this.fireEvent('expand', this);
23524 // Implements the default empty TriggerField.onTriggerClick function
23525 onTriggerClick : function(){
23529 if(this.isExpanded()){
23531 if (!this.blockFocus) {
23536 this.hasFocus = true;
23537 if(this.triggerAction == 'all') {
23538 this.doQuery(this.allQuery, true);
23540 this.doQuery(this.getRawValue());
23542 if (!this.blockFocus) {
23547 listKeyPress : function(e)
23549 //Roo.log('listkeypress');
23550 // scroll to first matching element based on key pres..
23551 if (e.isSpecialKey()) {
23554 var k = String.fromCharCode(e.getKey()).toUpperCase();
23557 var csel = this.view.getSelectedNodes();
23558 var cselitem = false;
23560 var ix = this.view.indexOf(csel[0]);
23561 cselitem = this.store.getAt(ix);
23562 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23568 this.store.each(function(v) {
23570 // start at existing selection.
23571 if (cselitem.id == v.id) {
23577 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23578 match = this.store.indexOf(v);
23583 if (match === false) {
23584 return true; // no more action?
23587 this.view.select(match);
23588 var sn = Roo.get(this.view.getSelectedNodes()[0])
23589 sn.scrollIntoView(sn.dom.parentNode, false);
23593 * @cfg {Boolean} grow
23597 * @cfg {Number} growMin
23601 * @cfg {Number} growMax
23610 * Ext JS Library 1.1.1
23611 * Copyright(c) 2006-2007, Ext JS, LLC.
23613 * Originally Released Under LGPL - original licence link has changed is not relivant.
23616 * <script type="text/javascript">
23619 * @class Roo.form.Checkbox
23620 * @extends Roo.form.Field
23621 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23623 * Creates a new Checkbox
23624 * @param {Object} config Configuration options
23626 Roo.form.Checkbox = function(config){
23627 Roo.form.Checkbox.superclass.constructor.call(this, config);
23631 * Fires when the checkbox is checked or unchecked.
23632 * @param {Roo.form.Checkbox} this This checkbox
23633 * @param {Boolean} checked The new checked value
23639 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23641 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23643 focusClass : undefined,
23645 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23647 fieldClass: "x-form-field",
23649 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23653 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23654 * {tag: "input", type: "checkbox", autocomplete: "off"})
23656 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23658 * @cfg {String} boxLabel The text that appears beside the checkbox
23662 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23666 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23668 valueOff: '0', // value when not checked..
23670 actionMode : 'viewEl',
23673 itemCls : 'x-menu-check-item x-form-item',
23674 groupClass : 'x-menu-group-item',
23675 inputType : 'hidden',
23678 inSetChecked: false, // check that we are not calling self...
23680 inputElement: false, // real input element?
23681 basedOn: false, // ????
23683 isFormField: true, // not sure where this is needed!!!!
23685 onResize : function(){
23686 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23687 if(!this.boxLabel){
23688 this.el.alignTo(this.wrap, 'c-c');
23692 initEvents : function(){
23693 Roo.form.Checkbox.superclass.initEvents.call(this);
23694 this.el.on("click", this.onClick, this);
23695 this.el.on("change", this.onClick, this);
23699 getResizeEl : function(){
23703 getPositionEl : function(){
23708 onRender : function(ct, position){
23709 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23711 if(this.inputValue !== undefined){
23712 this.el.dom.value = this.inputValue;
23715 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23716 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23717 var viewEl = this.wrap.createChild({
23718 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23719 this.viewEl = viewEl;
23720 this.wrap.on('click', this.onClick, this);
23722 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23723 this.el.on('propertychange', this.setFromHidden, this); //ie
23728 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23729 // viewEl.on('click', this.onClick, this);
23731 //if(this.checked){
23732 this.setChecked(this.checked);
23734 //this.checked = this.el.dom;
23740 initValue : Roo.emptyFn,
23743 * Returns the checked state of the checkbox.
23744 * @return {Boolean} True if checked, else false
23746 getValue : function(){
23748 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23750 return this.valueOff;
23755 onClick : function(){
23756 this.setChecked(!this.checked);
23758 //if(this.el.dom.checked != this.checked){
23759 // this.setValue(this.el.dom.checked);
23764 * Sets the checked state of the checkbox.
23765 * On is always based on a string comparison between inputValue and the param.
23766 * @param {Boolean/String} value - the value to set
23767 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23769 setValue : function(v,suppressEvent){
23772 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23773 //if(this.el && this.el.dom){
23774 // this.el.dom.checked = this.checked;
23775 // this.el.dom.defaultChecked = this.checked;
23777 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23778 //this.fireEvent("check", this, this.checked);
23781 setChecked : function(state,suppressEvent)
23783 if (this.inSetChecked) {
23784 this.checked = state;
23790 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23792 this.checked = state;
23793 if(suppressEvent !== true){
23794 this.fireEvent('check', this, state);
23796 this.inSetChecked = true;
23797 this.el.dom.value = state ? this.inputValue : this.valueOff;
23798 this.inSetChecked = false;
23801 // handle setting of hidden value by some other method!!?!?
23802 setFromHidden: function()
23807 //console.log("SET FROM HIDDEN");
23808 //alert('setFrom hidden');
23809 this.setValue(this.el.dom.value);
23812 onDestroy : function()
23815 Roo.get(this.viewEl).remove();
23818 Roo.form.Checkbox.superclass.onDestroy.call(this);
23823 * Ext JS Library 1.1.1
23824 * Copyright(c) 2006-2007, Ext JS, LLC.
23826 * Originally Released Under LGPL - original licence link has changed is not relivant.
23829 * <script type="text/javascript">
23833 * @class Roo.form.Radio
23834 * @extends Roo.form.Checkbox
23835 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23836 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23838 * Creates a new Radio
23839 * @param {Object} config Configuration options
23841 Roo.form.Radio = function(){
23842 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23844 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23845 inputType: 'radio',
23848 * If this radio is part of a group, it will return the selected value
23851 getGroupValue : function(){
23852 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23854 });//<script type="text/javascript">
23857 * Ext JS Library 1.1.1
23858 * Copyright(c) 2006-2007, Ext JS, LLC.
23859 * licensing@extjs.com
23861 * http://www.extjs.com/license
23867 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23868 * - IE ? - no idea how much works there.
23876 * @class Ext.form.HtmlEditor
23877 * @extends Ext.form.Field
23878 * Provides a lightweight HTML Editor component.
23879 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23881 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23882 * supported by this editor.</b><br/><br/>
23883 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23884 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23886 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23888 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23892 * @cfg {String} createLinkText The default text for the create link prompt
23894 createLinkText : 'Please enter the URL for the link:',
23896 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23898 defaultLinkValue : 'http:/'+'/',
23904 // private properties
23905 validationEvent : false,
23907 initialized : false,
23909 sourceEditMode : false,
23910 onFocus : Roo.emptyFn,
23912 hideMode:'offsets',
23913 defaultAutoCreate : {
23915 style:"width:500px;height:300px;",
23916 autocomplete: "off"
23920 initComponent : function(){
23923 * @event initialize
23924 * Fires when the editor is fully initialized (including the iframe)
23925 * @param {HtmlEditor} this
23930 * Fires when the editor is first receives the focus. Any insertion must wait
23931 * until after this event.
23932 * @param {HtmlEditor} this
23936 * @event beforesync
23937 * Fires before the textarea is updated with content from the editor iframe. Return false
23938 * to cancel the sync.
23939 * @param {HtmlEditor} this
23940 * @param {String} html
23944 * @event beforepush
23945 * Fires before the iframe editor is updated with content from the textarea. Return false
23946 * to cancel the push.
23947 * @param {HtmlEditor} this
23948 * @param {String} html
23953 * Fires when the textarea is updated with content from the editor iframe.
23954 * @param {HtmlEditor} this
23955 * @param {String} html
23960 * Fires when the iframe editor is updated with content from the textarea.
23961 * @param {HtmlEditor} this
23962 * @param {String} html
23966 * @event editmodechange
23967 * Fires when the editor switches edit modes
23968 * @param {HtmlEditor} this
23969 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23971 editmodechange: true,
23973 * @event editorevent
23974 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23975 * @param {HtmlEditor} this
23982 * Protected method that will not generally be called directly. It
23983 * is called when the editor creates its toolbar. Override this method if you need to
23984 * add custom toolbar buttons.
23985 * @param {HtmlEditor} editor
23987 createToolbar : function(editor){
23988 if (!editor.toolbars || !editor.toolbars.length) {
23989 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
23992 for (var i =0 ; i < editor.toolbars.length;i++) {
23993 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
23994 editor.toolbars[i].init(editor);
24001 * Protected method that will not generally be called directly. It
24002 * is called when the editor initializes the iframe with HTML contents. Override this method if you
24003 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
24005 getDocMarkup : function(){
24006 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
24010 onRender : function(ct, position){
24011 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24012 this.el.dom.style.border = '0 none';
24013 this.el.dom.setAttribute('tabIndex', -1);
24014 this.el.addClass('x-hidden');
24015 if(Roo.isIE){ // fix IE 1px bogus margin
24016 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24018 this.wrap = this.el.wrap({
24019 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24022 this.frameId = Roo.id();
24023 this.createToolbar(this);
24030 var iframe = this.wrap.createChild({
24033 name: this.frameId,
24034 frameBorder : 'no',
24035 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24038 // console.log(iframe);
24039 //this.wrap.dom.appendChild(iframe);
24041 this.iframe = iframe.dom;
24043 this.assignDocWin();
24045 this.doc.designMode = 'on';
24048 this.doc.write(this.getDocMarkup());
24052 var task = { // must defer to wait for browser to be ready
24054 //console.log("run task?" + this.doc.readyState);
24055 this.assignDocWin();
24056 if(this.doc.body || this.doc.readyState == 'complete'){
24058 this.doc.designMode="on";
24062 Roo.TaskMgr.stop(task);
24063 this.initEditor.defer(10, this);
24070 Roo.TaskMgr.start(task);
24073 this.setSize(this.el.getSize());
24078 onResize : function(w, h){
24079 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24080 if(this.el && this.iframe){
24081 if(typeof w == 'number'){
24082 var aw = w - this.wrap.getFrameWidth('lr');
24083 this.el.setWidth(this.adjustWidth('textarea', aw));
24084 this.iframe.style.width = aw + 'px';
24086 if(typeof h == 'number'){
24088 for (var i =0; i < this.toolbars.length;i++) {
24089 // fixme - ask toolbars for heights?
24090 tbh += this.toolbars[i].tb.el.getHeight();
24096 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24097 this.el.setHeight(this.adjustWidth('textarea', ah));
24098 this.iframe.style.height = ah + 'px';
24100 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24107 * Toggles the editor between standard and source edit mode.
24108 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24110 toggleSourceEdit : function(sourceEditMode){
24112 this.sourceEditMode = sourceEditMode === true;
24114 if(this.sourceEditMode){
24117 this.iframe.className = 'x-hidden';
24118 this.el.removeClass('x-hidden');
24119 this.el.dom.removeAttribute('tabIndex');
24124 this.iframe.className = '';
24125 this.el.addClass('x-hidden');
24126 this.el.dom.setAttribute('tabIndex', -1);
24129 this.setSize(this.wrap.getSize());
24130 this.fireEvent('editmodechange', this, this.sourceEditMode);
24133 // private used internally
24134 createLink : function(){
24135 var url = prompt(this.createLinkText, this.defaultLinkValue);
24136 if(url && url != 'http:/'+'/'){
24137 this.relayCmd('createlink', url);
24141 // private (for BoxComponent)
24142 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24144 // private (for BoxComponent)
24145 getResizeEl : function(){
24149 // private (for BoxComponent)
24150 getPositionEl : function(){
24155 initEvents : function(){
24156 this.originalValue = this.getValue();
24160 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24163 markInvalid : Roo.emptyFn,
24165 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24168 clearInvalid : Roo.emptyFn,
24170 setValue : function(v){
24171 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24176 * Protected method that will not generally be called directly. If you need/want
24177 * custom HTML cleanup, this is the method you should override.
24178 * @param {String} html The HTML to be cleaned
24179 * return {String} The cleaned HTML
24181 cleanHtml : function(html){
24182 html = String(html);
24183 if(html.length > 5){
24184 if(Roo.isSafari){ // strip safari nonsense
24185 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24188 if(html == ' '){
24195 * Protected method that will not generally be called directly. Syncs the contents
24196 * of the editor iframe with the textarea.
24198 syncValue : function(){
24199 if(this.initialized){
24200 var bd = (this.doc.body || this.doc.documentElement);
24201 var html = bd.innerHTML;
24203 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24204 var m = bs.match(/text-align:(.*?);/i);
24206 html = '<div style="'+m[0]+'">' + html + '</div>';
24209 html = this.cleanHtml(html);
24210 if(this.fireEvent('beforesync', this, html) !== false){
24211 this.el.dom.value = html;
24212 this.fireEvent('sync', this, html);
24218 * Protected method that will not generally be called directly. Pushes the value of the textarea
24219 * into the iframe editor.
24221 pushValue : function(){
24222 if(this.initialized){
24223 var v = this.el.dom.value;
24227 if(this.fireEvent('beforepush', this, v) !== false){
24228 (this.doc.body || this.doc.documentElement).innerHTML = v;
24229 this.fireEvent('push', this, v);
24235 deferFocus : function(){
24236 this.focus.defer(10, this);
24240 focus : function(){
24241 if(this.win && !this.sourceEditMode){
24248 assignDocWin: function()
24250 var iframe = this.iframe;
24253 this.doc = iframe.contentWindow.document;
24254 this.win = iframe.contentWindow;
24256 if (!Roo.get(this.frameId)) {
24259 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24260 this.win = Roo.get(this.frameId).dom.contentWindow;
24265 initEditor : function(){
24266 //console.log("INIT EDITOR");
24267 this.assignDocWin();
24271 this.doc.designMode="on";
24273 this.doc.write(this.getDocMarkup());
24276 var dbody = (this.doc.body || this.doc.documentElement);
24277 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24278 // this copies styles from the containing element into thsi one..
24279 // not sure why we need all of this..
24280 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24281 ss['background-attachment'] = 'fixed'; // w3c
24282 dbody.bgProperties = 'fixed'; // ie
24283 Roo.DomHelper.applyStyles(dbody, ss);
24284 Roo.EventManager.on(this.doc, {
24285 'mousedown': this.onEditorEvent,
24286 'dblclick': this.onEditorEvent,
24287 'click': this.onEditorEvent,
24288 'keyup': this.onEditorEvent,
24293 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24295 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24296 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24298 this.initialized = true;
24300 this.fireEvent('initialize', this);
24305 onDestroy : function(){
24311 for (var i =0; i < this.toolbars.length;i++) {
24312 // fixme - ask toolbars for heights?
24313 this.toolbars[i].onDestroy();
24316 this.wrap.dom.innerHTML = '';
24317 this.wrap.remove();
24322 onFirstFocus : function(){
24324 this.assignDocWin();
24327 this.activated = true;
24328 for (var i =0; i < this.toolbars.length;i++) {
24329 this.toolbars[i].onFirstFocus();
24332 if(Roo.isGecko){ // prevent silly gecko errors
24334 var s = this.win.getSelection();
24335 if(!s.focusNode || s.focusNode.nodeType != 3){
24336 var r = s.getRangeAt(0);
24337 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24342 this.execCmd('useCSS', true);
24343 this.execCmd('styleWithCSS', false);
24346 this.fireEvent('activate', this);
24350 adjustFont: function(btn){
24351 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24352 //if(Roo.isSafari){ // safari
24355 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24356 if(Roo.isSafari){ // safari
24357 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24358 v = (v < 10) ? 10 : v;
24359 v = (v > 48) ? 48 : v;
24360 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24365 v = Math.max(1, v+adjust);
24367 this.execCmd('FontSize', v );
24370 onEditorEvent : function(e){
24371 this.fireEvent('editorevent', this, e);
24372 // this.updateToolbar();
24376 insertTag : function(tg)
24378 // could be a bit smarter... -> wrap the current selected tRoo..
24380 this.execCmd("formatblock", tg);
24384 insertText : function(txt)
24388 range = this.createRange();
24389 range.deleteContents();
24390 //alert(Sender.getAttribute('label'));
24392 range.insertNode(this.doc.createTextNode(txt));
24396 relayBtnCmd : function(btn){
24397 this.relayCmd(btn.cmd);
24401 * Executes a Midas editor command on the editor document and performs necessary focus and
24402 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24403 * @param {String} cmd The Midas command
24404 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24406 relayCmd : function(cmd, value){
24408 this.execCmd(cmd, value);
24409 this.fireEvent('editorevent', this);
24410 //this.updateToolbar();
24415 * Executes a Midas editor command directly on the editor document.
24416 * For visual commands, you should use {@link #relayCmd} instead.
24417 * <b>This should only be called after the editor is initialized.</b>
24418 * @param {String} cmd The Midas command
24419 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24421 execCmd : function(cmd, value){
24422 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24428 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24430 * @param {String} text
24432 insertAtCursor : function(text){
24433 if(!this.activated){
24438 var r = this.doc.selection.createRange();
24445 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24447 this.execCmd('InsertHTML', text);
24452 mozKeyPress : function(e){
24454 var c = e.getCharCode(), cmd;
24457 c = String.fromCharCode(c).toLowerCase();
24468 this.cleanUpPaste.defer(100, this);
24476 e.preventDefault();
24484 fixKeys : function(){ // load time branching for fastest keydown performance
24486 return function(e){
24487 var k = e.getKey(), r;
24490 r = this.doc.selection.createRange();
24493 r.pasteHTML('    ');
24500 r = this.doc.selection.createRange();
24502 var target = r.parentElement();
24503 if(!target || target.tagName.toLowerCase() != 'li'){
24505 r.pasteHTML('<br />');
24511 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24512 this.cleanUpPaste.defer(100, this);
24518 }else if(Roo.isOpera){
24519 return function(e){
24520 var k = e.getKey();
24524 this.execCmd('InsertHTML','    ');
24527 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24528 this.cleanUpPaste.defer(100, this);
24533 }else if(Roo.isSafari){
24534 return function(e){
24535 var k = e.getKey();
24539 this.execCmd('InsertText','\t');
24543 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24544 this.cleanUpPaste.defer(100, this);
24552 getAllAncestors: function()
24554 var p = this.getSelectedNode();
24557 a.push(p); // push blank onto stack..
24558 p = this.getParentElement();
24562 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24566 a.push(this.doc.body);
24570 lastSelNode : false,
24573 getSelection : function()
24575 this.assignDocWin();
24576 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24579 getSelectedNode: function()
24581 // this may only work on Gecko!!!
24583 // should we cache this!!!!
24588 var range = this.createRange(this.getSelection());
24591 var parent = range.parentElement();
24593 var testRange = range.duplicate();
24594 testRange.moveToElementText(parent);
24595 if (testRange.inRange(range)) {
24598 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24601 parent = parent.parentElement;
24607 var ar = range.endContainer.childNodes;
24609 ar = range.commonAncestorContainer.childNodes;
24610 //alert(ar.length);
24613 var other_nodes = [];
24614 var has_other_nodes = false;
24615 for (var i=0;i<ar.length;i++) {
24616 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24619 // fullly contained node.
24621 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24626 // probably selected..
24627 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24628 other_nodes.push(ar[i]);
24631 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24636 has_other_nodes = true;
24638 if (!nodes.length && other_nodes.length) {
24639 nodes= other_nodes;
24641 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24647 createRange: function(sel)
24649 // this has strange effects when using with
24650 // top toolbar - not sure if it's a great idea.
24651 //this.editor.contentWindow.focus();
24652 if (typeof sel != "undefined") {
24654 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24656 return this.doc.createRange();
24659 return this.doc.createRange();
24662 getParentElement: function()
24665 this.assignDocWin();
24666 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24668 var range = this.createRange(sel);
24671 var p = range.commonAncestorContainer;
24672 while (p.nodeType == 3) { // text node
24684 // BC Hacks - cause I cant work out what i was trying to do..
24685 rangeIntersectsNode : function(range, node)
24687 var nodeRange = node.ownerDocument.createRange();
24689 nodeRange.selectNode(node);
24692 nodeRange.selectNodeContents(node);
24695 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24696 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24698 rangeCompareNode : function(range, node) {
24699 var nodeRange = node.ownerDocument.createRange();
24701 nodeRange.selectNode(node);
24703 nodeRange.selectNodeContents(node);
24705 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24706 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24708 if (nodeIsBefore && !nodeIsAfter)
24710 if (!nodeIsBefore && nodeIsAfter)
24712 if (nodeIsBefore && nodeIsAfter)
24718 // private? - in a new class?
24719 cleanUpPaste : function()
24721 // cleans up the whole document..
24722 // console.log('cleanuppaste');
24723 this.cleanUpChildren(this.doc.body)
24727 cleanUpChildren : function (n)
24729 if (!n.childNodes.length) {
24732 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24733 this.cleanUpChild(n.childNodes[i]);
24740 cleanUpChild : function (node)
24742 //console.log(node);
24743 if (node.nodeName == "#text") {
24744 // clean up silly Windows -- stuff?
24747 if (node.nodeName == "#comment") {
24748 node.parentNode.removeChild(node);
24749 // clean up silly Windows -- stuff?
24753 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24755 node.parentNode.removeChild(node);
24759 if (!node.attributes || !node.attributes.length) {
24760 this.cleanUpChildren(node);
24764 function cleanAttr(n,v)
24767 if (v.match(/^\./) || v.match(/^\//)) {
24770 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24773 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24774 node.removeAttribute(n);
24778 function cleanStyle(n,v)
24780 if (v.match(/expression/)) { //XSS?? should we even bother..
24781 node.removeAttribute(n);
24786 var parts = v.split(/;/);
24787 Roo.each(parts, function(p) {
24788 p = p.replace(/\s+/g,'');
24792 var l = p.split(':').shift().replace(/\s+/g,'');
24794 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24795 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24796 node.removeAttribute(n);
24805 for (var i = node.attributes.length-1; i > -1 ; i--) {
24806 var a = node.attributes[i];
24808 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24809 node.removeAttribute(a.name);
24812 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24813 cleanAttr(a.name,a.value); // fixme..
24816 if (a.name == 'style') {
24817 cleanStyle(a.name,a.value);
24819 /// clean up MS crap..
24820 if (a.name == 'class') {
24821 if (a.value.match(/^Mso/)) {
24822 node.className = '';
24832 this.cleanUpChildren(node);
24838 // hide stuff that is not compatible
24852 * @event specialkey
24856 * @cfg {String} fieldClass @hide
24859 * @cfg {String} focusClass @hide
24862 * @cfg {String} autoCreate @hide
24865 * @cfg {String} inputType @hide
24868 * @cfg {String} invalidClass @hide
24871 * @cfg {String} invalidText @hide
24874 * @cfg {String} msgFx @hide
24877 * @cfg {String} validateOnBlur @hide
24881 Roo.form.HtmlEditor.white = [
24882 'area', 'br', 'img', 'input', 'hr', 'wbr',
24884 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24885 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24886 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24887 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24888 'table', 'ul', 'xmp',
24890 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24893 'dir', 'menu', 'ol', 'ul', 'dl',
24899 Roo.form.HtmlEditor.black = [
24900 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24902 'base', 'basefont', 'bgsound', 'blink', 'body',
24903 'frame', 'frameset', 'head', 'html', 'ilayer',
24904 'iframe', 'layer', 'link', 'meta', 'object',
24905 'script', 'style' ,'title', 'xml' // clean later..
24907 Roo.form.HtmlEditor.clean = [
24908 'script', 'style', 'title', 'xml'
24913 Roo.form.HtmlEditor.ablack = [
24917 Roo.form.HtmlEditor.aclean = [
24918 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24922 Roo.form.HtmlEditor.pwhite= [
24923 'http', 'https', 'mailto'
24926 Roo.form.HtmlEditor.cwhite= [
24931 // <script type="text/javascript">
24934 * Ext JS Library 1.1.1
24935 * Copyright(c) 2006-2007, Ext JS, LLC.
24941 * @class Roo.form.HtmlEditorToolbar1
24946 new Roo.form.HtmlEditor({
24949 new Roo.form.HtmlEditorToolbar1({
24950 disable : { fonts: 1 , format: 1, ..., ... , ...],
24956 * @cfg {Object} disable List of elements to disable..
24957 * @cfg {Array} btns List of additional buttons.
24961 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24964 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24967 Roo.apply(this, config);
24968 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24969 // dont call parent... till later.
24972 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
24980 * @cfg {Object} disable List of toolbar elements to disable
24985 * @cfg {Array} fontFamilies An array of available font families
25003 // "á" , ?? a acute?
25008 "°" // , // degrees
25010 // "é" , // e ecute
25011 // "ú" , // u ecute?
25014 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25015 "input:submit", "input:button", "select", "textarea", "label" ],
25018 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25020 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25023 * @cfg {String} defaultFont default font to use.
25025 defaultFont: 'tahoma',
25027 fontSelect : false,
25030 formatCombo : false,
25032 init : function(editor)
25034 this.editor = editor;
25037 var fid = editor.frameId;
25039 function btn(id, toggle, handler){
25040 var xid = fid + '-'+ id ;
25044 cls : 'x-btn-icon x-edit-'+id,
25045 enableToggle:toggle !== false,
25046 scope: editor, // was editor...
25047 handler:handler||editor.relayBtnCmd,
25048 clickEvent:'mousedown',
25049 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25056 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25058 // stop form submits
25059 tb.el.on('click', function(e){
25060 e.preventDefault(); // what does this do?
25063 if(!this.disable.font && !Roo.isSafari){
25064 /* why no safari for fonts
25065 editor.fontSelect = tb.el.createChild({
25068 cls:'x-font-select',
25069 html: editor.createFontOptions()
25071 editor.fontSelect.on('change', function(){
25072 var font = editor.fontSelect.dom.value;
25073 editor.relayCmd('fontname', font);
25074 editor.deferFocus();
25077 editor.fontSelect.dom,
25082 if(!this.disable.formats){
25083 this.formatCombo = new Roo.form.ComboBox({
25084 store: new Roo.data.SimpleStore({
25087 data : this.formats // from states.js
25090 //autoCreate : {tag: "div", size: "20"},
25091 displayField:'tag',
25095 triggerAction: 'all',
25096 emptyText:'Add tag',
25097 selectOnFocus:true,
25100 'select': function(c, r, i) {
25101 editor.insertTag(r.get('tag'));
25107 tb.addField(this.formatCombo);
25111 if(!this.disable.format){
25118 if(!this.disable.fontSize){
25123 btn('increasefontsize', false, editor.adjustFont),
25124 btn('decreasefontsize', false, editor.adjustFont)
25129 if(this.disable.colors){
25132 id:editor.frameId +'-forecolor',
25133 cls:'x-btn-icon x-edit-forecolor',
25134 clickEvent:'mousedown',
25135 tooltip: this.buttonTips['forecolor'] || undefined,
25137 menu : new Roo.menu.ColorMenu({
25138 allowReselect: true,
25139 focus: Roo.emptyFn,
25142 selectHandler: function(cp, color){
25143 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25144 editor.deferFocus();
25147 clickEvent:'mousedown'
25150 id:editor.frameId +'backcolor',
25151 cls:'x-btn-icon x-edit-backcolor',
25152 clickEvent:'mousedown',
25153 tooltip: this.buttonTips['backcolor'] || undefined,
25155 menu : new Roo.menu.ColorMenu({
25156 focus: Roo.emptyFn,
25159 allowReselect: true,
25160 selectHandler: function(cp, color){
25162 editor.execCmd('useCSS', false);
25163 editor.execCmd('hilitecolor', color);
25164 editor.execCmd('useCSS', true);
25165 editor.deferFocus();
25167 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25168 Roo.isSafari || Roo.isIE ? '#'+color : color);
25169 editor.deferFocus();
25173 clickEvent:'mousedown'
25178 // now add all the items...
25181 if(!this.disable.alignments){
25184 btn('justifyleft'),
25185 btn('justifycenter'),
25186 btn('justifyright')
25190 //if(!Roo.isSafari){
25191 if(!this.disable.links){
25194 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25198 if(!this.disable.lists){
25201 btn('insertorderedlist'),
25202 btn('insertunorderedlist')
25205 if(!this.disable.sourceEdit){
25208 btn('sourceedit', true, function(btn){
25209 this.toggleSourceEdit(btn.pressed);
25216 // special menu.. - needs to be tidied up..
25217 if (!this.disable.special) {
25220 cls: 'x-edit-none',
25225 for (var i =0; i < this.specialChars.length; i++) {
25226 smenu.menu.items.push({
25228 html: this.specialChars[i],
25229 handler: function(a,b) {
25230 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25243 for(var i =0; i< this.btns.length;i++) {
25244 var b = this.btns[i];
25245 b.cls = 'x-edit-none';
25254 // disable everything...
25256 this.tb.items.each(function(item){
25257 if(item.id != editor.frameId+ '-sourceedit'){
25261 this.rendered = true;
25263 // the all the btns;
25264 editor.on('editorevent', this.updateToolbar, this);
25265 // other toolbars need to implement this..
25266 //editor.on('editmodechange', this.updateToolbar, this);
25272 * Protected method that will not generally be called directly. It triggers
25273 * a toolbar update by reading the markup state of the current selection in the editor.
25275 updateToolbar: function(){
25277 if(!this.editor.activated){
25278 this.editor.onFirstFocus();
25282 var btns = this.tb.items.map,
25283 doc = this.editor.doc,
25284 frameId = this.editor.frameId;
25286 if(!this.disable.font && !Roo.isSafari){
25288 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25289 if(name != this.fontSelect.dom.value){
25290 this.fontSelect.dom.value = name;
25294 if(!this.disable.format){
25295 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25296 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25297 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25299 if(!this.disable.alignments){
25300 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25301 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25302 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25304 if(!Roo.isSafari && !this.disable.lists){
25305 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25306 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25309 var ans = this.editor.getAllAncestors();
25310 if (this.formatCombo) {
25313 var store = this.formatCombo.store;
25314 this.formatCombo.setValue("");
25315 for (var i =0; i < ans.length;i++) {
25316 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25318 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25326 // hides menus... - so this cant be on a menu...
25327 Roo.menu.MenuMgr.hideAll();
25329 //this.editorsyncValue();
25333 createFontOptions : function(){
25334 var buf = [], fs = this.fontFamilies, ff, lc;
25335 for(var i = 0, len = fs.length; i< len; i++){
25337 lc = ff.toLowerCase();
25339 '<option value="',lc,'" style="font-family:',ff,';"',
25340 (this.defaultFont == lc ? ' selected="true">' : '>'),
25345 return buf.join('');
25348 toggleSourceEdit : function(sourceEditMode){
25349 if(sourceEditMode === undefined){
25350 sourceEditMode = !this.sourceEditMode;
25352 this.sourceEditMode = sourceEditMode === true;
25353 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25354 // just toggle the button?
25355 if(btn.pressed !== this.editor.sourceEditMode){
25356 btn.toggle(this.editor.sourceEditMode);
25360 if(this.sourceEditMode){
25361 this.tb.items.each(function(item){
25362 if(item.cmd != 'sourceedit'){
25368 if(this.initialized){
25369 this.tb.items.each(function(item){
25375 // tell the editor that it's been pressed..
25376 this.editor.toggleSourceEdit(sourceEditMode);
25380 * Object collection of toolbar tooltips for the buttons in the editor. The key
25381 * is the command id associated with that button and the value is a valid QuickTips object.
25386 title: 'Bold (Ctrl+B)',
25387 text: 'Make the selected text bold.',
25388 cls: 'x-html-editor-tip'
25391 title: 'Italic (Ctrl+I)',
25392 text: 'Make the selected text italic.',
25393 cls: 'x-html-editor-tip'
25401 title: 'Bold (Ctrl+B)',
25402 text: 'Make the selected text bold.',
25403 cls: 'x-html-editor-tip'
25406 title: 'Italic (Ctrl+I)',
25407 text: 'Make the selected text italic.',
25408 cls: 'x-html-editor-tip'
25411 title: 'Underline (Ctrl+U)',
25412 text: 'Underline the selected text.',
25413 cls: 'x-html-editor-tip'
25415 increasefontsize : {
25416 title: 'Grow Text',
25417 text: 'Increase the font size.',
25418 cls: 'x-html-editor-tip'
25420 decreasefontsize : {
25421 title: 'Shrink Text',
25422 text: 'Decrease the font size.',
25423 cls: 'x-html-editor-tip'
25426 title: 'Text Highlight Color',
25427 text: 'Change the background color of the selected text.',
25428 cls: 'x-html-editor-tip'
25431 title: 'Font Color',
25432 text: 'Change the color of the selected text.',
25433 cls: 'x-html-editor-tip'
25436 title: 'Align Text Left',
25437 text: 'Align text to the left.',
25438 cls: 'x-html-editor-tip'
25441 title: 'Center Text',
25442 text: 'Center text in the editor.',
25443 cls: 'x-html-editor-tip'
25446 title: 'Align Text Right',
25447 text: 'Align text to the right.',
25448 cls: 'x-html-editor-tip'
25450 insertunorderedlist : {
25451 title: 'Bullet List',
25452 text: 'Start a bulleted list.',
25453 cls: 'x-html-editor-tip'
25455 insertorderedlist : {
25456 title: 'Numbered List',
25457 text: 'Start a numbered list.',
25458 cls: 'x-html-editor-tip'
25461 title: 'Hyperlink',
25462 text: 'Make the selected text a hyperlink.',
25463 cls: 'x-html-editor-tip'
25466 title: 'Source Edit',
25467 text: 'Switch to source editing mode.',
25468 cls: 'x-html-editor-tip'
25472 onDestroy : function(){
25475 this.tb.items.each(function(item){
25477 item.menu.removeAll();
25479 item.menu.el.destroy();
25487 onFirstFocus: function() {
25488 this.tb.items.each(function(item){
25497 // <script type="text/javascript">
25500 * Ext JS Library 1.1.1
25501 * Copyright(c) 2006-2007, Ext JS, LLC.
25508 * @class Roo.form.HtmlEditor.ToolbarContext
25513 new Roo.form.HtmlEditor({
25516 new Roo.form.HtmlEditor.ToolbarStandard(),
25517 new Roo.form.HtmlEditor.ToolbarContext()
25522 * @config : {Object} disable List of elements to disable.. (not done yet.)
25527 Roo.form.HtmlEditor.ToolbarContext = function(config)
25530 Roo.apply(this, config);
25531 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25532 // dont call parent... till later.
25534 Roo.form.HtmlEditor.ToolbarContext.types = {
25546 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25608 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25613 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25677 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25685 * @cfg {Object} disable List of toolbar elements to disable
25694 init : function(editor)
25696 this.editor = editor;
25699 var fid = editor.frameId;
25701 function btn(id, toggle, handler){
25702 var xid = fid + '-'+ id ;
25706 cls : 'x-btn-icon x-edit-'+id,
25707 enableToggle:toggle !== false,
25708 scope: editor, // was editor...
25709 handler:handler||editor.relayBtnCmd,
25710 clickEvent:'mousedown',
25711 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25715 // create a new element.
25716 var wdiv = editor.wrap.createChild({
25718 }, editor.wrap.dom.firstChild.nextSibling, true);
25720 // can we do this more than once??
25722 // stop form submits
25725 // disable everything...
25726 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25727 this.toolbars = {};
25729 for (var i in ty) {
25731 this.toolbars[i] = this.buildToolbar(ty[i],i);
25733 this.tb = this.toolbars.BODY;
25737 this.rendered = true;
25739 // the all the btns;
25740 editor.on('editorevent', this.updateToolbar, this);
25741 // other toolbars need to implement this..
25742 //editor.on('editmodechange', this.updateToolbar, this);
25748 * Protected method that will not generally be called directly. It triggers
25749 * a toolbar update by reading the markup state of the current selection in the editor.
25751 updateToolbar: function(){
25753 if(!this.editor.activated){
25754 this.editor.onFirstFocus();
25759 var ans = this.editor.getAllAncestors();
25762 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25763 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25764 sel = sel ? sel : this.editor.doc.body;
25765 sel = sel.tagName.length ? sel : this.editor.doc.body;
25766 var tn = sel.tagName.toUpperCase();
25767 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25768 tn = sel.tagName.toUpperCase();
25769 if (this.tb.name == tn) {
25770 return; // no change
25773 ///console.log("show: " + tn);
25774 this.tb = this.toolbars[tn];
25776 this.tb.fields.each(function(e) {
25777 e.setValue(sel.getAttribute(e.name));
25779 this.tb.selectedNode = sel;
25782 Roo.menu.MenuMgr.hideAll();
25784 //this.editorsyncValue();
25789 onDestroy : function(){
25792 this.tb.items.each(function(item){
25794 item.menu.removeAll();
25796 item.menu.el.destroy();
25804 onFirstFocus: function() {
25805 // need to do this for all the toolbars..
25806 this.tb.items.each(function(item){
25810 buildToolbar: function(tlist, nm)
25812 var editor = this.editor;
25813 // create a new element.
25814 var wdiv = editor.wrap.createChild({
25816 }, editor.wrap.dom.firstChild.nextSibling, true);
25819 var tb = new Roo.Toolbar(wdiv);
25820 tb.add(nm+ ": ");
25821 for (var i in tlist) {
25822 var item = tlist[i];
25823 tb.add(item.title + ": ");
25828 tb.addField( new Roo.form.ComboBox({
25829 store: new Roo.data.SimpleStore({
25832 data : item.opts // from states.js
25835 displayField:'val',
25839 triggerAction: 'all',
25840 emptyText:'Select',
25841 selectOnFocus:true,
25842 width: item.width ? item.width : 130,
25844 'select': function(c, r, i) {
25845 tb.selectedNode.setAttribute(c.name, r.get('val'));
25856 tb.addField( new Roo.form.TextField({
25859 //allowBlank:false,
25864 tb.addField( new Roo.form.TextField({
25870 'change' : function(f, nv, ov) {
25871 tb.selectedNode.setAttribute(f.name, nv);
25877 tb.el.on('click', function(e){
25878 e.preventDefault(); // what does this do?
25880 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25883 // dont need to disable them... as they will get hidden
25900 * Ext JS Library 1.1.1
25901 * Copyright(c) 2006-2007, Ext JS, LLC.
25903 * Originally Released Under LGPL - original licence link has changed is not relivant.
25906 * <script type="text/javascript">
25910 * @class Roo.form.BasicForm
25911 * @extends Roo.util.Observable
25912 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25914 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25915 * @param {Object} config Configuration options
25917 Roo.form.BasicForm = function(el, config){
25918 this.allItems = [];
25919 this.childForms = [];
25920 Roo.apply(this, config);
25922 * The Roo.form.Field items in this form.
25923 * @type MixedCollection
25927 this.items = new Roo.util.MixedCollection(false, function(o){
25928 return o.id || (o.id = Roo.id());
25932 * @event beforeaction
25933 * Fires before any action is performed. Return false to cancel the action.
25934 * @param {Form} this
25935 * @param {Action} action The action to be performed
25937 beforeaction: true,
25939 * @event actionfailed
25940 * Fires when an action fails.
25941 * @param {Form} this
25942 * @param {Action} action The action that failed
25944 actionfailed : true,
25946 * @event actioncomplete
25947 * Fires when an action is completed.
25948 * @param {Form} this
25949 * @param {Action} action The action that completed
25951 actioncomplete : true
25956 Roo.form.BasicForm.superclass.constructor.call(this);
25959 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25961 * @cfg {String} method
25962 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25965 * @cfg {DataReader} reader
25966 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25967 * This is optional as there is built-in support for processing JSON.
25970 * @cfg {DataReader} errorReader
25971 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
25972 * This is completely optional as there is built-in support for processing JSON.
25975 * @cfg {String} url
25976 * The URL to use for form actions if one isn't supplied in the action options.
25979 * @cfg {Boolean} fileUpload
25980 * Set to true if this form is a file upload.
25983 * @cfg {Object} baseParams
25984 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
25987 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
25992 activeAction : null,
25995 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
25996 * or setValues() data instead of when the form was first created.
25998 trackResetOnLoad : false,
26002 * childForms - used for multi-tab forms
26005 childForms : false,
26008 * allItems - full list of fields.
26014 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26015 * element by passing it or its id or mask the form itself by passing in true.
26018 waitMsgTarget : undefined,
26021 initEl : function(el){
26022 this.el = Roo.get(el);
26023 this.id = this.el.id || Roo.id();
26024 this.el.on('submit', this.onSubmit, this);
26025 this.el.addClass('x-form');
26029 onSubmit : function(e){
26034 * Returns true if client-side validation on the form is successful.
26037 isValid : function(){
26039 this.items.each(function(f){
26048 * Returns true if any fields in this form have changed since their original load.
26051 isDirty : function(){
26053 this.items.each(function(f){
26063 * Performs a predefined action (submit or load) or custom actions you define on this form.
26064 * @param {String} actionName The name of the action type
26065 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26066 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26067 * accept other config options):
26069 Property Type Description
26070 ---------------- --------------- ----------------------------------------------------------------------------------
26071 url String The url for the action (defaults to the form's url)
26072 method String The form method to use (defaults to the form's method, or POST if not defined)
26073 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26074 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26075 validate the form on the client (defaults to false)
26077 * @return {BasicForm} this
26079 doAction : function(action, options){
26080 if(typeof action == 'string'){
26081 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26083 if(this.fireEvent('beforeaction', this, action) !== false){
26084 this.beforeAction(action);
26085 action.run.defer(100, action);
26091 * Shortcut to do a submit action.
26092 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26093 * @return {BasicForm} this
26095 submit : function(options){
26096 this.doAction('submit', options);
26101 * Shortcut to do a load action.
26102 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26103 * @return {BasicForm} this
26105 load : function(options){
26106 this.doAction('load', options);
26111 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26112 * @param {Record} record The record to edit
26113 * @return {BasicForm} this
26115 updateRecord : function(record){
26116 record.beginEdit();
26117 var fs = record.fields;
26118 fs.each(function(f){
26119 var field = this.findField(f.name);
26121 record.set(f.name, field.getValue());
26129 * Loads an Roo.data.Record into this form.
26130 * @param {Record} record The record to load
26131 * @return {BasicForm} this
26133 loadRecord : function(record){
26134 this.setValues(record.data);
26139 beforeAction : function(action){
26140 var o = action.options;
26142 if(this.waitMsgTarget === true){
26143 this.el.mask(o.waitMsg, 'x-mask-loading');
26144 }else if(this.waitMsgTarget){
26145 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26146 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
26148 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
26154 afterAction : function(action, success){
26155 this.activeAction = null;
26156 var o = action.options;
26158 if(this.waitMsgTarget === true){
26160 }else if(this.waitMsgTarget){
26161 this.waitMsgTarget.unmask();
26163 Roo.MessageBox.updateProgress(1);
26164 Roo.MessageBox.hide();
26171 Roo.callback(o.success, o.scope, [this, action]);
26172 this.fireEvent('actioncomplete', this, action);
26174 Roo.callback(o.failure, o.scope, [this, action]);
26175 this.fireEvent('actionfailed', this, action);
26180 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26181 * @param {String} id The value to search for
26184 findField : function(id){
26185 var field = this.items.get(id);
26187 this.items.each(function(f){
26188 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26194 return field || null;
26198 * Add a secondary form to this one,
26199 * Used to provide tabbed forms. One form is primary, with hidden values
26200 * which mirror the elements from the other forms.
26202 * @param {Roo.form.Form} form to add.
26205 addForm : function(form)
26208 if (this.childForms.indexOf(form) > -1) {
26212 this.childForms.push(form);
26214 Roo.each(form.allItems, function (fe) {
26216 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26217 if (this.findField(n)) { // already added..
26220 var add = new Roo.form.Hidden({
26223 add.render(this.el);
26230 * Mark fields in this form invalid in bulk.
26231 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26232 * @return {BasicForm} this
26234 markInvalid : function(errors){
26235 if(errors instanceof Array){
26236 for(var i = 0, len = errors.length; i < len; i++){
26237 var fieldError = errors[i];
26238 var f = this.findField(fieldError.id);
26240 f.markInvalid(fieldError.msg);
26246 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26247 field.markInvalid(errors[id]);
26251 Roo.each(this.childForms || [], function (f) {
26252 f.markInvalid(errors);
26259 * Set values for fields in this form in bulk.
26260 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26261 * @return {BasicForm} this
26263 setValues : function(values){
26264 if(values instanceof Array){ // array of objects
26265 for(var i = 0, len = values.length; i < len; i++){
26267 var f = this.findField(v.id);
26269 f.setValue(v.value);
26270 if(this.trackResetOnLoad){
26271 f.originalValue = f.getValue();
26275 }else{ // object hash
26278 if(typeof values[id] != 'function' && (field = this.findField(id))){
26280 if (field.setFromData &&
26281 field.valueField &&
26282 field.displayField &&
26283 // combos' with local stores can
26284 // be queried via setValue()
26285 // to set their value..
26286 (field.store && !field.store.isLocal)
26290 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26291 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26292 field.setFromData(sd);
26295 field.setValue(values[id]);
26299 if(this.trackResetOnLoad){
26300 field.originalValue = field.getValue();
26306 Roo.each(this.childForms || [], function (f) {
26307 f.setValues(values);
26314 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26315 * they are returned as an array.
26316 * @param {Boolean} asString
26319 getValues : function(asString){
26320 if (this.childForms) {
26321 // copy values from the child forms
26322 Roo.each(this.childForms, function (f) {
26323 this.setValues(f.getValues());
26329 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26330 if(asString === true){
26333 return Roo.urlDecode(fs);
26337 * Returns the fields in this form as an object with key/value pairs.
26338 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26341 getFieldValues : function()
26343 if (this.childForms) {
26344 // copy values from the child forms
26345 Roo.each(this.childForms, function (f) {
26346 this.setValues(f.getValues());
26351 this.items.each(function(f){
26352 if (!f.getName()) {
26355 var v = f.getValue();
26356 if ((typeof(v) == 'object') && f.getRawValue) {
26357 v = f.getRawValue() ; // dates..
26359 ret[f.getName()] = v;
26366 * Clears all invalid messages in this form.
26367 * @return {BasicForm} this
26369 clearInvalid : function(){
26370 this.items.each(function(f){
26374 Roo.each(this.childForms || [], function (f) {
26383 * Resets this form.
26384 * @return {BasicForm} this
26386 reset : function(){
26387 this.items.each(function(f){
26391 Roo.each(this.childForms || [], function (f) {
26400 * Add Roo.form components to this form.
26401 * @param {Field} field1
26402 * @param {Field} field2 (optional)
26403 * @param {Field} etc (optional)
26404 * @return {BasicForm} this
26407 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26413 * Removes a field from the items collection (does NOT remove its markup).
26414 * @param {Field} field
26415 * @return {BasicForm} this
26417 remove : function(field){
26418 this.items.remove(field);
26423 * Looks at the fields in this form, checks them for an id attribute,
26424 * and calls applyTo on the existing dom element with that id.
26425 * @return {BasicForm} this
26427 render : function(){
26428 this.items.each(function(f){
26429 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26437 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26438 * @param {Object} values
26439 * @return {BasicForm} this
26441 applyToFields : function(o){
26442 this.items.each(function(f){
26449 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26450 * @param {Object} values
26451 * @return {BasicForm} this
26453 applyIfToFields : function(o){
26454 this.items.each(function(f){
26462 Roo.BasicForm = Roo.form.BasicForm;/*
26464 * Ext JS Library 1.1.1
26465 * Copyright(c) 2006-2007, Ext JS, LLC.
26467 * Originally Released Under LGPL - original licence link has changed is not relivant.
26470 * <script type="text/javascript">
26474 * @class Roo.form.Form
26475 * @extends Roo.form.BasicForm
26476 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26478 * @param {Object} config Configuration options
26480 Roo.form.Form = function(config){
26482 if (config.items) {
26483 xitems = config.items;
26484 delete config.items;
26488 Roo.form.Form.superclass.constructor.call(this, null, config);
26489 this.url = this.url || this.action;
26491 this.root = new Roo.form.Layout(Roo.applyIf({
26495 this.active = this.root;
26497 * Array of all the buttons that have been added to this form via {@link addButton}
26501 this.allItems = [];
26504 * @event clientvalidation
26505 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26506 * @param {Form} this
26507 * @param {Boolean} valid true if the form has passed client-side validation
26509 clientvalidation: true,
26512 * Fires when the form is rendered
26513 * @param {Roo.form.Form} form
26518 if (this.progressUrl) {
26519 // push a hidden field onto the list of fields..
26523 name : 'UPLOAD_IDENTIFIER'
26528 Roo.each(xitems, this.addxtype, this);
26534 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26536 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26539 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26542 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26544 buttonAlign:'center',
26547 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26552 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26553 * This property cascades to child containers if not set.
26558 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26559 * fires a looping event with that state. This is required to bind buttons to the valid
26560 * state using the config value formBind:true on the button.
26562 monitorValid : false,
26565 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26570 * @cfg {String} progressUrl - Url to return progress data
26573 progressUrl : false,
26576 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26577 * fields are added and the column is closed. If no fields are passed the column remains open
26578 * until end() is called.
26579 * @param {Object} config The config to pass to the column
26580 * @param {Field} field1 (optional)
26581 * @param {Field} field2 (optional)
26582 * @param {Field} etc (optional)
26583 * @return Column The column container object
26585 column : function(c){
26586 var col = new Roo.form.Column(c);
26588 if(arguments.length > 1){ // duplicate code required because of Opera
26589 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26596 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26597 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26598 * until end() is called.
26599 * @param {Object} config The config to pass to the fieldset
26600 * @param {Field} field1 (optional)
26601 * @param {Field} field2 (optional)
26602 * @param {Field} etc (optional)
26603 * @return FieldSet The fieldset container object
26605 fieldset : function(c){
26606 var fs = new Roo.form.FieldSet(c);
26608 if(arguments.length > 1){ // duplicate code required because of Opera
26609 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26616 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26617 * fields are added and the container is closed. If no fields are passed the container remains open
26618 * until end() is called.
26619 * @param {Object} config The config to pass to the Layout
26620 * @param {Field} field1 (optional)
26621 * @param {Field} field2 (optional)
26622 * @param {Field} etc (optional)
26623 * @return Layout The container object
26625 container : function(c){
26626 var l = new Roo.form.Layout(c);
26628 if(arguments.length > 1){ // duplicate code required because of Opera
26629 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26636 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26637 * @param {Object} container A Roo.form.Layout or subclass of Layout
26638 * @return {Form} this
26640 start : function(c){
26641 // cascade label info
26642 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26643 this.active.stack.push(c);
26644 c.ownerCt = this.active;
26650 * Closes the current open container
26651 * @return {Form} this
26654 if(this.active == this.root){
26657 this.active = this.active.ownerCt;
26662 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26663 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26664 * as the label of the field.
26665 * @param {Field} field1
26666 * @param {Field} field2 (optional)
26667 * @param {Field} etc. (optional)
26668 * @return {Form} this
26671 this.active.stack.push.apply(this.active.stack, arguments);
26672 this.allItems.push.apply(this.allItems,arguments);
26674 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26675 if(a[i].isFormField){
26680 Roo.form.Form.superclass.add.apply(this, r);
26690 * Find any element that has been added to a form, using it's ID or name
26691 * This can include framesets, columns etc. along with regular fields..
26692 * @param {String} id - id or name to find.
26694 * @return {Element} e - or false if nothing found.
26696 findbyId : function(id)
26702 Ext.each(this.allItems, function(f){
26703 if (f.id == id || f.name == id ){
26714 * Render this form into the passed container. This should only be called once!
26715 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26716 * @return {Form} this
26718 render : function(ct)
26724 var o = this.autoCreate || {
26726 method : this.method || 'POST',
26727 id : this.id || Roo.id()
26729 this.initEl(ct.createChild(o));
26731 this.root.render(this.el);
26735 this.items.each(function(f){
26736 f.render('x-form-el-'+f.id);
26739 if(this.buttons.length > 0){
26740 // tables are required to maintain order and for correct IE layout
26741 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26742 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26743 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26745 var tr = tb.getElementsByTagName('tr')[0];
26746 for(var i = 0, len = this.buttons.length; i < len; i++) {
26747 var b = this.buttons[i];
26748 var td = document.createElement('td');
26749 td.className = 'x-form-btn-td';
26750 b.render(tr.appendChild(td));
26753 if(this.monitorValid){ // initialize after render
26754 this.startMonitoring();
26756 this.fireEvent('rendered', this);
26761 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26762 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26763 * object or a valid Roo.DomHelper element config
26764 * @param {Function} handler The function called when the button is clicked
26765 * @param {Object} scope (optional) The scope of the handler function
26766 * @return {Roo.Button}
26768 addButton : function(config, handler, scope){
26772 minWidth: this.minButtonWidth,
26775 if(typeof config == "string"){
26778 Roo.apply(bc, config);
26780 var btn = new Roo.Button(null, bc);
26781 this.buttons.push(btn);
26786 * Adds a series of form elements (using the xtype property as the factory method.
26787 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26788 * @param {Object} config
26791 addxtype : function()
26793 var ar = Array.prototype.slice.call(arguments, 0);
26795 for(var i = 0; i < ar.length; i++) {
26797 continue; // skip -- if this happends something invalid got sent, we
26798 // should ignore it, as basically that interface element will not show up
26799 // and that should be pretty obvious!!
26802 if (Roo.form[ar[i].xtype]) {
26804 var fe = Roo.factory(ar[i], Roo.form);
26810 fe.store.form = this;
26815 this.allItems.push(fe);
26816 if (fe.items && fe.addxtype) {
26817 fe.addxtype.apply(fe, fe.items);
26827 // console.log('adding ' + ar[i].xtype);
26829 if (ar[i].xtype == 'Button') {
26830 //console.log('adding button');
26831 //console.log(ar[i]);
26832 this.addButton(ar[i]);
26833 this.allItems.push(fe);
26837 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26838 alert('end is not supported on xtype any more, use items');
26840 // //console.log('adding end');
26848 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26849 * option "monitorValid"
26851 startMonitoring : function(){
26854 Roo.TaskMgr.start({
26855 run : this.bindHandler,
26856 interval : this.monitorPoll || 200,
26863 * Stops monitoring of the valid state of this form
26865 stopMonitoring : function(){
26866 this.bound = false;
26870 bindHandler : function(){
26872 return false; // stops binding
26875 this.items.each(function(f){
26876 if(!f.isValid(true)){
26881 for(var i = 0, len = this.buttons.length; i < len; i++){
26882 var btn = this.buttons[i];
26883 if(btn.formBind === true && btn.disabled === valid){
26884 btn.setDisabled(!valid);
26887 this.fireEvent('clientvalidation', this, valid);
26901 Roo.Form = Roo.form.Form;
26904 * Ext JS Library 1.1.1
26905 * Copyright(c) 2006-2007, Ext JS, LLC.
26907 * Originally Released Under LGPL - original licence link has changed is not relivant.
26910 * <script type="text/javascript">
26914 * @class Roo.form.Action
26915 * Internal Class used to handle form actions
26917 * @param {Roo.form.BasicForm} el The form element or its id
26918 * @param {Object} config Configuration options
26922 // define the action interface
26923 Roo.form.Action = function(form, options){
26925 this.options = options || {};
26928 * Client Validation Failed
26931 Roo.form.Action.CLIENT_INVALID = 'client';
26933 * Server Validation Failed
26936 Roo.form.Action.SERVER_INVALID = 'server';
26938 * Connect to Server Failed
26941 Roo.form.Action.CONNECT_FAILURE = 'connect';
26943 * Reading Data from Server Failed
26946 Roo.form.Action.LOAD_FAILURE = 'load';
26948 Roo.form.Action.prototype = {
26950 failureType : undefined,
26951 response : undefined,
26952 result : undefined,
26954 // interface method
26955 run : function(options){
26959 // interface method
26960 success : function(response){
26964 // interface method
26965 handleResponse : function(response){
26969 // default connection failure
26970 failure : function(response){
26971 this.response = response;
26972 this.failureType = Roo.form.Action.CONNECT_FAILURE;
26973 this.form.afterAction(this, false);
26976 processResponse : function(response){
26977 this.response = response;
26978 if(!response.responseText){
26981 this.result = this.handleResponse(response);
26982 return this.result;
26985 // utility functions used internally
26986 getUrl : function(appendParams){
26987 var url = this.options.url || this.form.url || this.form.el.dom.action;
26989 var p = this.getParams();
26991 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
26997 getMethod : function(){
26998 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
27001 getParams : function(){
27002 var bp = this.form.baseParams;
27003 var p = this.options.params;
27005 if(typeof p == "object"){
27006 p = Roo.urlEncode(Roo.applyIf(p, bp));
27007 }else if(typeof p == 'string' && bp){
27008 p += '&' + Roo.urlEncode(bp);
27011 p = Roo.urlEncode(bp);
27016 createCallback : function(){
27018 success: this.success,
27019 failure: this.failure,
27021 timeout: (this.form.timeout*1000),
27022 upload: this.form.fileUpload ? this.success : undefined
27027 Roo.form.Action.Submit = function(form, options){
27028 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27031 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27034 haveProgress : false,
27035 uploadComplete : false,
27037 // uploadProgress indicator.
27038 uploadProgress : function()
27040 if (!this.form.progressUrl) {
27044 if (!this.haveProgress) {
27045 Roo.MessageBox.progress("Uploading", "Uploading");
27047 if (this.uploadComplete) {
27048 Roo.MessageBox.hide();
27052 this.haveProgress = true;
27054 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27056 var c = new Roo.data.Connection();
27058 url : this.form.progressUrl,
27063 success : function(req){
27064 //console.log(data);
27068 rdata = Roo.decode(req.responseText)
27070 Roo.log("Invalid data from server..");
27074 if (!rdata || !rdata.success) {
27078 var data = rdata.data;
27080 if (this.uploadComplete) {
27081 Roo.MessageBox.hide();
27086 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27087 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27090 this.uploadProgress.defer(2000,this);
27093 failure: function(data) {
27094 Roo.log('progress url failed ');
27105 // run get Values on the form, so it syncs any secondary forms.
27106 this.form.getValues();
27108 var o = this.options;
27109 var method = this.getMethod();
27110 var isPost = method == 'POST';
27111 if(o.clientValidation === false || this.form.isValid()){
27113 if (this.form.progressUrl) {
27114 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27115 (new Date() * 1) + '' + Math.random());
27119 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27120 form:this.form.el.dom,
27121 url:this.getUrl(!isPost),
27123 params:isPost ? this.getParams() : null,
27124 isUpload: this.form.fileUpload
27127 this.uploadProgress();
27129 }else if (o.clientValidation !== false){ // client validation failed
27130 this.failureType = Roo.form.Action.CLIENT_INVALID;
27131 this.form.afterAction(this, false);
27135 success : function(response)
27137 this.uploadComplete= true;
27138 if (this.haveProgress) {
27139 Roo.MessageBox.hide();
27142 var result = this.processResponse(response);
27143 if(result === true || result.success){
27144 this.form.afterAction(this, true);
27148 this.form.markInvalid(result.errors);
27149 this.failureType = Roo.form.Action.SERVER_INVALID;
27151 this.form.afterAction(this, false);
27153 failure : function(response)
27155 this.uploadComplete= true;
27156 if (this.haveProgress) {
27157 Roo.MessageBox.hide();
27160 this.response = response;
27161 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27162 this.form.afterAction(this, false);
27165 handleResponse : function(response){
27166 if(this.form.errorReader){
27167 var rs = this.form.errorReader.read(response);
27170 for(var i = 0, len = rs.records.length; i < len; i++) {
27171 var r = rs.records[i];
27172 errors[i] = r.data;
27175 if(errors.length < 1){
27179 success : rs.success,
27185 ret = Roo.decode(response.responseText);
27189 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27199 Roo.form.Action.Load = function(form, options){
27200 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27201 this.reader = this.form.reader;
27204 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27208 Roo.Ajax.request(Roo.apply(
27209 this.createCallback(), {
27210 method:this.getMethod(),
27211 url:this.getUrl(false),
27212 params:this.getParams()
27216 success : function(response){
27217 var result = this.processResponse(response);
27218 if(result === true || !result.success || !result.data){
27219 this.failureType = Roo.form.Action.LOAD_FAILURE;
27220 this.form.afterAction(this, false);
27223 this.form.clearInvalid();
27224 this.form.setValues(result.data);
27225 this.form.afterAction(this, true);
27228 handleResponse : function(response){
27229 if(this.form.reader){
27230 var rs = this.form.reader.read(response);
27231 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27233 success : rs.success,
27237 return Roo.decode(response.responseText);
27241 Roo.form.Action.ACTION_TYPES = {
27242 'load' : Roo.form.Action.Load,
27243 'submit' : Roo.form.Action.Submit
27246 * Ext JS Library 1.1.1
27247 * Copyright(c) 2006-2007, Ext JS, LLC.
27249 * Originally Released Under LGPL - original licence link has changed is not relivant.
27252 * <script type="text/javascript">
27256 * @class Roo.form.Layout
27257 * @extends Roo.Component
27258 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27260 * @param {Object} config Configuration options
27262 Roo.form.Layout = function(config){
27264 if (config.items) {
27265 xitems = config.items;
27266 delete config.items;
27268 Roo.form.Layout.superclass.constructor.call(this, config);
27270 Roo.each(xitems, this.addxtype, this);
27274 Roo.extend(Roo.form.Layout, Roo.Component, {
27276 * @cfg {String/Object} autoCreate
27277 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27280 * @cfg {String/Object/Function} style
27281 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27282 * a function which returns such a specification.
27285 * @cfg {String} labelAlign
27286 * Valid values are "left," "top" and "right" (defaults to "left")
27289 * @cfg {Number} labelWidth
27290 * Fixed width in pixels of all field labels (defaults to undefined)
27293 * @cfg {Boolean} clear
27294 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27298 * @cfg {String} labelSeparator
27299 * The separator to use after field labels (defaults to ':')
27301 labelSeparator : ':',
27303 * @cfg {Boolean} hideLabels
27304 * True to suppress the display of field labels in this layout (defaults to false)
27306 hideLabels : false,
27309 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27314 onRender : function(ct, position){
27315 if(this.el){ // from markup
27316 this.el = Roo.get(this.el);
27317 }else { // generate
27318 var cfg = this.getAutoCreate();
27319 this.el = ct.createChild(cfg, position);
27322 this.el.applyStyles(this.style);
27324 if(this.labelAlign){
27325 this.el.addClass('x-form-label-'+this.labelAlign);
27327 if(this.hideLabels){
27328 this.labelStyle = "display:none";
27329 this.elementStyle = "padding-left:0;";
27331 if(typeof this.labelWidth == 'number'){
27332 this.labelStyle = "width:"+this.labelWidth+"px;";
27333 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27335 if(this.labelAlign == 'top'){
27336 this.labelStyle = "width:auto;";
27337 this.elementStyle = "padding-left:0;";
27340 var stack = this.stack;
27341 var slen = stack.length;
27343 if(!this.fieldTpl){
27344 var t = new Roo.Template(
27345 '<div class="x-form-item {5}">',
27346 '<label for="{0}" style="{2}">{1}{4}</label>',
27347 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27349 '</div><div class="x-form-clear-left"></div>'
27351 t.disableFormats = true;
27353 Roo.form.Layout.prototype.fieldTpl = t;
27355 for(var i = 0; i < slen; i++) {
27356 if(stack[i].isFormField){
27357 this.renderField(stack[i]);
27359 this.renderComponent(stack[i]);
27364 this.el.createChild({cls:'x-form-clear'});
27369 renderField : function(f){
27370 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27373 f.labelStyle||this.labelStyle||'', //2
27374 this.elementStyle||'', //3
27375 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27376 f.itemCls||this.itemCls||'' //5
27377 ], true).getPrevSibling());
27381 renderComponent : function(c){
27382 c.render(c.isLayout ? this.el : this.el.createChild());
27385 * Adds a object form elements (using the xtype property as the factory method.)
27386 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27387 * @param {Object} config
27389 addxtype : function(o)
27391 // create the lement.
27392 o.form = this.form;
27393 var fe = Roo.factory(o, Roo.form);
27394 this.form.allItems.push(fe);
27395 this.stack.push(fe);
27397 if (fe.isFormField) {
27398 this.form.items.add(fe);
27406 * @class Roo.form.Column
27407 * @extends Roo.form.Layout
27408 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27410 * @param {Object} config Configuration options
27412 Roo.form.Column = function(config){
27413 Roo.form.Column.superclass.constructor.call(this, config);
27416 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27418 * @cfg {Number/String} width
27419 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27422 * @cfg {String/Object} autoCreate
27423 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27427 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27430 onRender : function(ct, position){
27431 Roo.form.Column.superclass.onRender.call(this, ct, position);
27433 this.el.setWidth(this.width);
27440 * @class Roo.form.Row
27441 * @extends Roo.form.Layout
27442 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27444 * @param {Object} config Configuration options
27448 Roo.form.Row = function(config){
27449 Roo.form.Row.superclass.constructor.call(this, config);
27452 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27454 * @cfg {Number/String} width
27455 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27458 * @cfg {Number/String} height
27459 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27461 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27465 onRender : function(ct, position){
27466 //console.log('row render');
27468 var t = new Roo.Template(
27469 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27470 '<label for="{0}" style="{2}">{1}{4}</label>',
27471 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27475 t.disableFormats = true;
27477 Roo.form.Layout.prototype.rowTpl = t;
27479 this.fieldTpl = this.rowTpl;
27481 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27482 var labelWidth = 100;
27484 if ((this.labelAlign != 'top')) {
27485 if (typeof this.labelWidth == 'number') {
27486 labelWidth = this.labelWidth
27488 this.padWidth = 20 + labelWidth;
27492 Roo.form.Column.superclass.onRender.call(this, ct, position);
27494 this.el.setWidth(this.width);
27497 this.el.setHeight(this.height);
27502 renderField : function(f){
27503 f.fieldEl = this.fieldTpl.append(this.el, [
27504 f.id, f.fieldLabel,
27505 f.labelStyle||this.labelStyle||'',
27506 this.elementStyle||'',
27507 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27508 f.itemCls||this.itemCls||'',
27509 f.width ? f.width + this.padWidth : 160 + this.padWidth
27516 * @class Roo.form.FieldSet
27517 * @extends Roo.form.Layout
27518 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27520 * @param {Object} config Configuration options
27522 Roo.form.FieldSet = function(config){
27523 Roo.form.FieldSet.superclass.constructor.call(this, config);
27526 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27528 * @cfg {String} legend
27529 * The text to display as the legend for the FieldSet (defaults to '')
27532 * @cfg {String/Object} autoCreate
27533 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27537 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27540 onRender : function(ct, position){
27541 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27543 this.setLegend(this.legend);
27548 setLegend : function(text){
27550 this.el.child('legend').update(text);
27555 * Ext JS Library 1.1.1
27556 * Copyright(c) 2006-2007, Ext JS, LLC.
27558 * Originally Released Under LGPL - original licence link has changed is not relivant.
27561 * <script type="text/javascript">
27564 * @class Roo.form.VTypes
27565 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27568 Roo.form.VTypes = function(){
27569 // closure these in so they are only created once.
27570 var alpha = /^[a-zA-Z_]+$/;
27571 var alphanum = /^[a-zA-Z0-9_]+$/;
27572 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27573 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27575 // All these messages and functions are configurable
27578 * The function used to validate email addresses
27579 * @param {String} value The email address
27581 'email' : function(v){
27582 return email.test(v);
27585 * The error text to display when the email validation function returns false
27588 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27590 * The keystroke filter mask to be applied on email input
27593 'emailMask' : /[a-z0-9_\.\-@]/i,
27596 * The function used to validate URLs
27597 * @param {String} value The URL
27599 'url' : function(v){
27600 return url.test(v);
27603 * The error text to display when the url validation function returns false
27606 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27609 * The function used to validate alpha values
27610 * @param {String} value The value
27612 'alpha' : function(v){
27613 return alpha.test(v);
27616 * The error text to display when the alpha validation function returns false
27619 'alphaText' : 'This field should only contain letters and _',
27621 * The keystroke filter mask to be applied on alpha input
27624 'alphaMask' : /[a-z_]/i,
27627 * The function used to validate alphanumeric values
27628 * @param {String} value The value
27630 'alphanum' : function(v){
27631 return alphanum.test(v);
27634 * The error text to display when the alphanumeric validation function returns false
27637 'alphanumText' : 'This field should only contain letters, numbers and _',
27639 * The keystroke filter mask to be applied on alphanumeric input
27642 'alphanumMask' : /[a-z0-9_]/i
27644 }();//<script type="text/javascript">
27647 * @class Roo.form.FCKeditor
27648 * @extends Roo.form.TextArea
27649 * Wrapper around the FCKEditor http://www.fckeditor.net
27651 * Creates a new FCKeditor
27652 * @param {Object} config Configuration options
27654 Roo.form.FCKeditor = function(config){
27655 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27658 * @event editorinit
27659 * Fired when the editor is initialized - you can add extra handlers here..
27660 * @param {FCKeditor} this
27661 * @param {Object} the FCK object.
27668 Roo.form.FCKeditor.editors = { };
27669 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27671 //defaultAutoCreate : {
27672 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27676 * @cfg {Object} fck options - see fck manual for details.
27681 * @cfg {Object} fck toolbar set (Basic or Default)
27683 toolbarSet : 'Basic',
27685 * @cfg {Object} fck BasePath
27687 basePath : '/fckeditor/',
27695 onRender : function(ct, position)
27698 this.defaultAutoCreate = {
27700 style:"width:300px;height:60px;",
27701 autocomplete: "off"
27704 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27707 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27708 if(this.preventScrollbars){
27709 this.el.setStyle("overflow", "hidden");
27711 this.el.setHeight(this.growMin);
27714 //console.log('onrender' + this.getId() );
27715 Roo.form.FCKeditor.editors[this.getId()] = this;
27718 this.replaceTextarea() ;
27722 getEditor : function() {
27723 return this.fckEditor;
27726 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27727 * @param {Mixed} value The value to set
27731 setValue : function(value)
27733 //console.log('setValue: ' + value);
27735 if(typeof(value) == 'undefined') { // not sure why this is happending...
27738 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27740 //if(!this.el || !this.getEditor()) {
27741 // this.value = value;
27742 //this.setValue.defer(100,this,[value]);
27746 if(!this.getEditor()) {
27750 this.getEditor().SetData(value);
27757 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27758 * @return {Mixed} value The field value
27760 getValue : function()
27763 if (this.frame && this.frame.dom.style.display == 'none') {
27764 return Roo.form.FCKeditor.superclass.getValue.call(this);
27767 if(!this.el || !this.getEditor()) {
27769 // this.getValue.defer(100,this);
27774 var value=this.getEditor().GetData();
27775 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27776 return Roo.form.FCKeditor.superclass.getValue.call(this);
27782 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27783 * @return {Mixed} value The field value
27785 getRawValue : function()
27787 if (this.frame && this.frame.dom.style.display == 'none') {
27788 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27791 if(!this.el || !this.getEditor()) {
27792 //this.getRawValue.defer(100,this);
27799 var value=this.getEditor().GetData();
27800 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27801 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27805 setSize : function(w,h) {
27809 //if (this.frame && this.frame.dom.style.display == 'none') {
27810 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27813 //if(!this.el || !this.getEditor()) {
27814 // this.setSize.defer(100,this, [w,h]);
27820 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27822 this.frame.dom.setAttribute('width', w);
27823 this.frame.dom.setAttribute('height', h);
27824 this.frame.setSize(w,h);
27828 toggleSourceEdit : function(value) {
27832 this.el.dom.style.display = value ? '' : 'none';
27833 this.frame.dom.style.display = value ? 'none' : '';
27838 focus: function(tag)
27840 if (this.frame.dom.style.display == 'none') {
27841 return Roo.form.FCKeditor.superclass.focus.call(this);
27843 if(!this.el || !this.getEditor()) {
27844 this.focus.defer(100,this, [tag]);
27851 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27852 this.getEditor().Focus();
27854 if (!this.getEditor().Selection.GetSelection()) {
27855 this.focus.defer(100,this, [tag]);
27860 var r = this.getEditor().EditorDocument.createRange();
27861 r.setStart(tgs[0],0);
27862 r.setEnd(tgs[0],0);
27863 this.getEditor().Selection.GetSelection().removeAllRanges();
27864 this.getEditor().Selection.GetSelection().addRange(r);
27865 this.getEditor().Focus();
27872 replaceTextarea : function()
27874 if ( document.getElementById( this.getId() + '___Frame' ) )
27876 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27878 // We must check the elements firstly using the Id and then the name.
27879 var oTextarea = document.getElementById( this.getId() );
27881 var colElementsByName = document.getElementsByName( this.getId() ) ;
27883 oTextarea.style.display = 'none' ;
27885 if ( oTextarea.tabIndex ) {
27886 this.TabIndex = oTextarea.tabIndex ;
27889 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27890 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27891 this.frame = Roo.get(this.getId() + '___Frame')
27894 _getConfigHtml : function()
27898 for ( var o in this.fckconfig ) {
27899 sConfig += sConfig.length > 0 ? '&' : '';
27900 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27903 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27907 _getIFrameHtml : function()
27909 var sFile = 'fckeditor.html' ;
27910 /* no idea what this is about..
27913 if ( (/fcksource=true/i).test( window.top.location.search ) )
27914 sFile = 'fckeditor.original.html' ;
27919 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27920 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27923 var html = '<iframe id="' + this.getId() +
27924 '___Frame" src="' + sLink +
27925 '" width="' + this.width +
27926 '" height="' + this.height + '"' +
27927 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27928 ' frameborder="0" scrolling="no"></iframe>' ;
27933 _insertHtmlBefore : function( html, element )
27935 if ( element.insertAdjacentHTML ) {
27937 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27939 var oRange = document.createRange() ;
27940 oRange.setStartBefore( element ) ;
27941 var oFragment = oRange.createContextualFragment( html );
27942 element.parentNode.insertBefore( oFragment, element ) ;
27955 //Roo.reg('fckeditor', Roo.form.FCKeditor);
27957 function FCKeditor_OnComplete(editorInstance){
27958 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
27959 f.fckEditor = editorInstance;
27960 //console.log("loaded");
27961 f.fireEvent('editorinit', f, editorInstance);
27981 //<script type="text/javascript">
27983 * @class Roo.form.GridField
27984 * @extends Roo.form.Field
27985 * Embed a grid (or editable grid into a form)
27988 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
27990 * xgrid.store = Roo.data.Store
27991 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
27992 * xgrid.store.reader = Roo.data.JsonReader
27996 * Creates a new GridField
27997 * @param {Object} config Configuration options
27999 Roo.form.GridField = function(config){
28000 Roo.form.GridField.superclass.constructor.call(this, config);
28004 Roo.extend(Roo.form.GridField, Roo.form.Field, {
28006 * @cfg {Number} width - used to restrict width of grid..
28010 * @cfg {Number} height - used to restrict height of grid..
28014 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28020 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28021 * {tag: "input", type: "checkbox", autocomplete: "off"})
28023 // defaultAutoCreate : { tag: 'div' },
28024 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28026 * @cfg {String} addTitle Text to include for adding a title.
28030 onResize : function(){
28031 Roo.form.Field.superclass.onResize.apply(this, arguments);
28034 initEvents : function(){
28035 // Roo.form.Checkbox.superclass.initEvents.call(this);
28036 // has no events...
28041 getResizeEl : function(){
28045 getPositionEl : function(){
28050 onRender : function(ct, position){
28052 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28053 var style = this.style;
28056 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28057 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28058 this.viewEl = this.wrap.createChild({ tag: 'div' });
28060 this.viewEl.applyStyles(style);
28063 this.viewEl.setWidth(this.width);
28066 this.viewEl.setHeight(this.height);
28068 //if(this.inputValue !== undefined){
28069 //this.setValue(this.value);
28072 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28075 this.grid.render();
28076 this.grid.getDataSource().on('remove', this.refreshValue, this);
28077 this.grid.getDataSource().on('update', this.refreshValue, this);
28078 this.grid.on('afteredit', this.refreshValue, this);
28084 * Sets the value of the item.
28085 * @param {String} either an object or a string..
28087 setValue : function(v){
28089 v = v || []; // empty set..
28090 // this does not seem smart - it really only affects memoryproxy grids..
28091 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28092 var ds = this.grid.getDataSource();
28093 // assumes a json reader..
28095 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28096 ds.loadData( data);
28098 Roo.form.GridField.superclass.setValue.call(this, v);
28099 this.refreshValue();
28100 // should load data in the grid really....
28104 refreshValue: function() {
28106 this.grid.getDataSource().each(function(r) {
28109 this.el.dom.value = Roo.encode(val);
28117 * Ext JS Library 1.1.1
28118 * Copyright(c) 2006-2007, Ext JS, LLC.
28120 * Originally Released Under LGPL - original licence link has changed is not relivant.
28123 * <script type="text/javascript">
28126 * @class Roo.form.DisplayField
28127 * @extends Roo.form.Field
28128 * A generic Field to display non-editable data.
28130 * Creates a new Display Field item.
28131 * @param {Object} config Configuration options
28133 Roo.form.DisplayField = function(config){
28134 Roo.form.DisplayField.superclass.constructor.call(this, config);
28138 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28139 inputType: 'hidden',
28145 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28147 focusClass : undefined,
28149 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28151 fieldClass: 'x-form-field',
28154 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28156 valueRenderer: undefined,
28160 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28161 * {tag: "input", type: "checkbox", autocomplete: "off"})
28164 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28166 onResize : function(){
28167 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28171 initEvents : function(){
28172 // Roo.form.Checkbox.superclass.initEvents.call(this);
28173 // has no events...
28178 getResizeEl : function(){
28182 getPositionEl : function(){
28187 onRender : function(ct, position){
28189 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28190 //if(this.inputValue !== undefined){
28191 this.wrap = this.el.wrap();
28193 this.viewEl = this.wrap.createChild({ tag: 'div'});
28195 if (this.bodyStyle) {
28196 this.viewEl.applyStyles(this.bodyStyle);
28198 //this.viewEl.setStyle('padding', '2px');
28200 this.setValue(this.value);
28205 initValue : Roo.emptyFn,
28210 onClick : function(){
28215 * Sets the checked state of the checkbox.
28216 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28218 setValue : function(v){
28220 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28221 // this might be called before we have a dom element..
28222 if (!this.viewEl) {
28225 this.viewEl.dom.innerHTML = html;
28226 Roo.form.DisplayField.superclass.setValue.call(this, v);
28229 });//<script type="text/javasscript">
28233 * @class Roo.DDView
28234 * A DnD enabled version of Roo.View.
28235 * @param {Element/String} container The Element in which to create the View.
28236 * @param {String} tpl The template string used to create the markup for each element of the View
28237 * @param {Object} config The configuration properties. These include all the config options of
28238 * {@link Roo.View} plus some specific to this class.<br>
28240 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28241 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28243 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28244 .x-view-drag-insert-above {
28245 border-top:1px dotted #3366cc;
28247 .x-view-drag-insert-below {
28248 border-bottom:1px dotted #3366cc;
28254 Roo.DDView = function(container, tpl, config) {
28255 Roo.DDView.superclass.constructor.apply(this, arguments);
28256 this.getEl().setStyle("outline", "0px none");
28257 this.getEl().unselectable();
28258 if (this.dragGroup) {
28259 this.setDraggable(this.dragGroup.split(","));
28261 if (this.dropGroup) {
28262 this.setDroppable(this.dropGroup.split(","));
28264 if (this.deletable) {
28265 this.setDeletable();
28267 this.isDirtyFlag = false;
28273 Roo.extend(Roo.DDView, Roo.View, {
28274 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28275 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28276 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28277 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28281 reset: Roo.emptyFn,
28283 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28285 validate: function() {
28289 destroy: function() {
28290 this.purgeListeners();
28291 this.getEl.removeAllListeners();
28292 this.getEl().remove();
28293 if (this.dragZone) {
28294 if (this.dragZone.destroy) {
28295 this.dragZone.destroy();
28298 if (this.dropZone) {
28299 if (this.dropZone.destroy) {
28300 this.dropZone.destroy();
28305 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28306 getName: function() {
28310 /** Loads the View from a JSON string representing the Records to put into the Store. */
28311 setValue: function(v) {
28313 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28316 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28317 this.store.proxy = new Roo.data.MemoryProxy(data);
28321 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28322 getValue: function() {
28324 this.store.each(function(rec) {
28325 result += rec.id + ',';
28327 return result.substr(0, result.length - 1) + ')';
28330 getIds: function() {
28331 var i = 0, result = new Array(this.store.getCount());
28332 this.store.each(function(rec) {
28333 result[i++] = rec.id;
28338 isDirty: function() {
28339 return this.isDirtyFlag;
28343 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28344 * whole Element becomes the target, and this causes the drop gesture to append.
28346 getTargetFromEvent : function(e) {
28347 var target = e.getTarget();
28348 while ((target !== null) && (target.parentNode != this.el.dom)) {
28349 target = target.parentNode;
28352 target = this.el.dom.lastChild || this.el.dom;
28358 * Create the drag data which consists of an object which has the property "ddel" as
28359 * the drag proxy element.
28361 getDragData : function(e) {
28362 var target = this.findItemFromChild(e.getTarget());
28364 this.handleSelection(e);
28365 var selNodes = this.getSelectedNodes();
28368 copy: this.copy || (this.allowCopy && e.ctrlKey),
28372 var selectedIndices = this.getSelectedIndexes();
28373 for (var i = 0; i < selectedIndices.length; i++) {
28374 dragData.records.push(this.store.getAt(selectedIndices[i]));
28376 if (selNodes.length == 1) {
28377 dragData.ddel = target.cloneNode(true); // the div element
28379 var div = document.createElement('div'); // create the multi element drag "ghost"
28380 div.className = 'multi-proxy';
28381 for (var i = 0, len = selNodes.length; i < len; i++) {
28382 div.appendChild(selNodes[i].cloneNode(true));
28384 dragData.ddel = div;
28386 //console.log(dragData)
28387 //console.log(dragData.ddel.innerHTML)
28390 //console.log('nodragData')
28394 /** Specify to which ddGroup items in this DDView may be dragged. */
28395 setDraggable: function(ddGroup) {
28396 if (ddGroup instanceof Array) {
28397 Roo.each(ddGroup, this.setDraggable, this);
28400 if (this.dragZone) {
28401 this.dragZone.addToGroup(ddGroup);
28403 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28404 containerScroll: true,
28408 // Draggability implies selection. DragZone's mousedown selects the element.
28409 if (!this.multiSelect) { this.singleSelect = true; }
28411 // Wire the DragZone's handlers up to methods in *this*
28412 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28416 /** Specify from which ddGroup this DDView accepts drops. */
28417 setDroppable: function(ddGroup) {
28418 if (ddGroup instanceof Array) {
28419 Roo.each(ddGroup, this.setDroppable, this);
28422 if (this.dropZone) {
28423 this.dropZone.addToGroup(ddGroup);
28425 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28426 containerScroll: true,
28430 // Wire the DropZone's handlers up to methods in *this*
28431 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28432 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28433 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28434 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28435 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28439 /** Decide whether to drop above or below a View node. */
28440 getDropPoint : function(e, n, dd){
28441 if (n == this.el.dom) { return "above"; }
28442 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28443 var c = t + (b - t) / 2;
28444 var y = Roo.lib.Event.getPageY(e);
28452 onNodeEnter : function(n, dd, e, data){
28456 onNodeOver : function(n, dd, e, data){
28457 var pt = this.getDropPoint(e, n, dd);
28458 // set the insert point style on the target node
28459 var dragElClass = this.dropNotAllowed;
28462 if (pt == "above"){
28463 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28464 targetElClass = "x-view-drag-insert-above";
28466 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28467 targetElClass = "x-view-drag-insert-below";
28469 if (this.lastInsertClass != targetElClass){
28470 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28471 this.lastInsertClass = targetElClass;
28474 return dragElClass;
28477 onNodeOut : function(n, dd, e, data){
28478 this.removeDropIndicators(n);
28481 onNodeDrop : function(n, dd, e, data){
28482 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28485 var pt = this.getDropPoint(e, n, dd);
28486 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28487 if (pt == "below") { insertAt++; }
28488 for (var i = 0; i < data.records.length; i++) {
28489 var r = data.records[i];
28490 var dup = this.store.getById(r.id);
28491 if (dup && (dd != this.dragZone)) {
28492 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28495 this.store.insert(insertAt++, r.copy());
28497 data.source.isDirtyFlag = true;
28499 this.store.insert(insertAt++, r);
28501 this.isDirtyFlag = true;
28504 this.dragZone.cachedTarget = null;
28508 removeDropIndicators : function(n){
28510 Roo.fly(n).removeClass([
28511 "x-view-drag-insert-above",
28512 "x-view-drag-insert-below"]);
28513 this.lastInsertClass = "_noclass";
28518 * Utility method. Add a delete option to the DDView's context menu.
28519 * @param {String} imageUrl The URL of the "delete" icon image.
28521 setDeletable: function(imageUrl) {
28522 if (!this.singleSelect && !this.multiSelect) {
28523 this.singleSelect = true;
28525 var c = this.getContextMenu();
28526 this.contextMenu.on("itemclick", function(item) {
28529 this.remove(this.getSelectedIndexes());
28533 this.contextMenu.add({
28540 /** Return the context menu for this DDView. */
28541 getContextMenu: function() {
28542 if (!this.contextMenu) {
28543 // Create the View's context menu
28544 this.contextMenu = new Roo.menu.Menu({
28545 id: this.id + "-contextmenu"
28547 this.el.on("contextmenu", this.showContextMenu, this);
28549 return this.contextMenu;
28552 disableContextMenu: function() {
28553 if (this.contextMenu) {
28554 this.el.un("contextmenu", this.showContextMenu, this);
28558 showContextMenu: function(e, item) {
28559 item = this.findItemFromChild(e.getTarget());
28562 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28563 this.contextMenu.showAt(e.getXY());
28568 * Remove {@link Roo.data.Record}s at the specified indices.
28569 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28571 remove: function(selectedIndices) {
28572 selectedIndices = [].concat(selectedIndices);
28573 for (var i = 0; i < selectedIndices.length; i++) {
28574 var rec = this.store.getAt(selectedIndices[i]);
28575 this.store.remove(rec);
28580 * Double click fires the event, but also, if this is draggable, and there is only one other
28581 * related DropZone, it transfers the selected node.
28583 onDblClick : function(e){
28584 var item = this.findItemFromChild(e.getTarget());
28586 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28589 if (this.dragGroup) {
28590 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28591 while (targets.indexOf(this.dropZone) > -1) {
28592 targets.remove(this.dropZone);
28594 if (targets.length == 1) {
28595 this.dragZone.cachedTarget = null;
28596 var el = Roo.get(targets[0].getEl());
28597 var box = el.getBox(true);
28598 targets[0].onNodeDrop(el.dom, {
28600 xy: [box.x, box.y + box.height - 1]
28601 }, null, this.getDragData(e));
28607 handleSelection: function(e) {
28608 this.dragZone.cachedTarget = null;
28609 var item = this.findItemFromChild(e.getTarget());
28611 this.clearSelections(true);
28614 if (item && (this.multiSelect || this.singleSelect)){
28615 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28616 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28617 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28618 this.unselect(item);
28620 this.select(item, this.multiSelect && e.ctrlKey);
28621 this.lastSelection = item;
28626 onItemClick : function(item, index, e){
28627 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28633 unselect : function(nodeInfo, suppressEvent){
28634 var node = this.getNode(nodeInfo);
28635 if(node && this.isSelected(node)){
28636 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28637 Roo.fly(node).removeClass(this.selectedClass);
28638 this.selections.remove(node);
28639 if(!suppressEvent){
28640 this.fireEvent("selectionchange", this, this.selections);
28648 * Ext JS Library 1.1.1
28649 * Copyright(c) 2006-2007, Ext JS, LLC.
28651 * Originally Released Under LGPL - original licence link has changed is not relivant.
28654 * <script type="text/javascript">
28658 * @class Roo.LayoutManager
28659 * @extends Roo.util.Observable
28660 * Base class for layout managers.
28662 Roo.LayoutManager = function(container, config){
28663 Roo.LayoutManager.superclass.constructor.call(this);
28664 this.el = Roo.get(container);
28665 // ie scrollbar fix
28666 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28667 document.body.scroll = "no";
28668 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28669 this.el.position('relative');
28671 this.id = this.el.id;
28672 this.el.addClass("x-layout-container");
28673 /** false to disable window resize monitoring @type Boolean */
28674 this.monitorWindowResize = true;
28679 * Fires when a layout is performed.
28680 * @param {Roo.LayoutManager} this
28684 * @event regionresized
28685 * Fires when the user resizes a region.
28686 * @param {Roo.LayoutRegion} region The resized region
28687 * @param {Number} newSize The new size (width for east/west, height for north/south)
28689 "regionresized" : true,
28691 * @event regioncollapsed
28692 * Fires when a region is collapsed.
28693 * @param {Roo.LayoutRegion} region The collapsed region
28695 "regioncollapsed" : true,
28697 * @event regionexpanded
28698 * Fires when a region is expanded.
28699 * @param {Roo.LayoutRegion} region The expanded region
28701 "regionexpanded" : true
28703 this.updating = false;
28704 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28707 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28709 * Returns true if this layout is currently being updated
28710 * @return {Boolean}
28712 isUpdating : function(){
28713 return this.updating;
28717 * Suspend the LayoutManager from doing auto-layouts while
28718 * making multiple add or remove calls
28720 beginUpdate : function(){
28721 this.updating = true;
28725 * Restore auto-layouts and optionally disable the manager from performing a layout
28726 * @param {Boolean} noLayout true to disable a layout update
28728 endUpdate : function(noLayout){
28729 this.updating = false;
28735 layout: function(){
28739 onRegionResized : function(region, newSize){
28740 this.fireEvent("regionresized", region, newSize);
28744 onRegionCollapsed : function(region){
28745 this.fireEvent("regioncollapsed", region);
28748 onRegionExpanded : function(region){
28749 this.fireEvent("regionexpanded", region);
28753 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28754 * performs box-model adjustments.
28755 * @return {Object} The size as an object {width: (the width), height: (the height)}
28757 getViewSize : function(){
28759 if(this.el.dom != document.body){
28760 size = this.el.getSize();
28762 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28764 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28765 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28770 * Returns the Element this layout is bound to.
28771 * @return {Roo.Element}
28773 getEl : function(){
28778 * Returns the specified region.
28779 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
28780 * @return {Roo.LayoutRegion}
28782 getRegion : function(target){
28783 return this.regions[target.toLowerCase()];
28786 onWindowResize : function(){
28787 if(this.monitorWindowResize){
28793 * Ext JS Library 1.1.1
28794 * Copyright(c) 2006-2007, Ext JS, LLC.
28796 * Originally Released Under LGPL - original licence link has changed is not relivant.
28799 * <script type="text/javascript">
28802 * @class Roo.BorderLayout
28803 * @extends Roo.LayoutManager
28804 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
28805 * please see: <br><br>
28806 * <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>
28807 * <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>
28810 var layout = new Roo.BorderLayout(document.body, {
28844 preferredTabWidth: 150
28849 var CP = Roo.ContentPanel;
28851 layout.beginUpdate();
28852 layout.add("north", new CP("north", "North"));
28853 layout.add("south", new CP("south", {title: "South", closable: true}));
28854 layout.add("west", new CP("west", {title: "West"}));
28855 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
28856 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
28857 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
28858 layout.getRegion("center").showPanel("center1");
28859 layout.endUpdate();
28862 <b>The container the layout is rendered into can be either the body element or any other element.
28863 If it is not the body element, the container needs to either be an absolute positioned element,
28864 or you will need to add "position:relative" to the css of the container. You will also need to specify
28865 the container size if it is not the body element.</b>
28868 * Create a new BorderLayout
28869 * @param {String/HTMLElement/Element} container The container this layout is bound to
28870 * @param {Object} config Configuration options
28872 Roo.BorderLayout = function(container, config){
28873 config = config || {};
28874 Roo.BorderLayout.superclass.constructor.call(this, container, config);
28875 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
28876 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
28877 var target = this.factory.validRegions[i];
28878 if(config[target]){
28879 this.addRegion(target, config[target]);
28884 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
28886 * Creates and adds a new region if it doesn't already exist.
28887 * @param {String} target The target region key (north, south, east, west or center).
28888 * @param {Object} config The regions config object
28889 * @return {BorderLayoutRegion} The new region
28891 addRegion : function(target, config){
28892 if(!this.regions[target]){
28893 var r = this.factory.create(target, this, config);
28894 this.bindRegion(target, r);
28896 return this.regions[target];
28900 bindRegion : function(name, r){
28901 this.regions[name] = r;
28902 r.on("visibilitychange", this.layout, this);
28903 r.on("paneladded", this.layout, this);
28904 r.on("panelremoved", this.layout, this);
28905 r.on("invalidated", this.layout, this);
28906 r.on("resized", this.onRegionResized, this);
28907 r.on("collapsed", this.onRegionCollapsed, this);
28908 r.on("expanded", this.onRegionExpanded, this);
28912 * Performs a layout update.
28914 layout : function(){
28915 if(this.updating) return;
28916 var size = this.getViewSize();
28917 var w = size.width;
28918 var h = size.height;
28923 //var x = 0, y = 0;
28925 var rs = this.regions;
28926 var north = rs["north"];
28927 var south = rs["south"];
28928 var west = rs["west"];
28929 var east = rs["east"];
28930 var center = rs["center"];
28931 //if(this.hideOnLayout){ // not supported anymore
28932 //c.el.setStyle("display", "none");
28934 if(north && north.isVisible()){
28935 var b = north.getBox();
28936 var m = north.getMargins();
28937 b.width = w - (m.left+m.right);
28940 centerY = b.height + b.y + m.bottom;
28941 centerH -= centerY;
28942 north.updateBox(this.safeBox(b));
28944 if(south && south.isVisible()){
28945 var b = south.getBox();
28946 var m = south.getMargins();
28947 b.width = w - (m.left+m.right);
28949 var totalHeight = (b.height + m.top + m.bottom);
28950 b.y = h - totalHeight + m.top;
28951 centerH -= totalHeight;
28952 south.updateBox(this.safeBox(b));
28954 if(west && west.isVisible()){
28955 var b = west.getBox();
28956 var m = west.getMargins();
28957 b.height = centerH - (m.top+m.bottom);
28959 b.y = centerY + m.top;
28960 var totalWidth = (b.width + m.left + m.right);
28961 centerX += totalWidth;
28962 centerW -= totalWidth;
28963 west.updateBox(this.safeBox(b));
28965 if(east && east.isVisible()){
28966 var b = east.getBox();
28967 var m = east.getMargins();
28968 b.height = centerH - (m.top+m.bottom);
28969 var totalWidth = (b.width + m.left + m.right);
28970 b.x = w - totalWidth + m.left;
28971 b.y = centerY + m.top;
28972 centerW -= totalWidth;
28973 east.updateBox(this.safeBox(b));
28976 var m = center.getMargins();
28978 x: centerX + m.left,
28979 y: centerY + m.top,
28980 width: centerW - (m.left+m.right),
28981 height: centerH - (m.top+m.bottom)
28983 //if(this.hideOnLayout){
28984 //center.el.setStyle("display", "block");
28986 center.updateBox(this.safeBox(centerBox));
28989 this.fireEvent("layout", this);
28993 safeBox : function(box){
28994 box.width = Math.max(0, box.width);
28995 box.height = Math.max(0, box.height);
29000 * Adds a ContentPanel (or subclass) to this layout.
29001 * @param {String} target The target region key (north, south, east, west or center).
29002 * @param {Roo.ContentPanel} panel The panel to add
29003 * @return {Roo.ContentPanel} The added panel
29005 add : function(target, panel){
29007 target = target.toLowerCase();
29008 return this.regions[target].add(panel);
29012 * Remove a ContentPanel (or subclass) to this layout.
29013 * @param {String} target The target region key (north, south, east, west or center).
29014 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29015 * @return {Roo.ContentPanel} The removed panel
29017 remove : function(target, panel){
29018 target = target.toLowerCase();
29019 return this.regions[target].remove(panel);
29023 * Searches all regions for a panel with the specified id
29024 * @param {String} panelId
29025 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29027 findPanel : function(panelId){
29028 var rs = this.regions;
29029 for(var target in rs){
29030 if(typeof rs[target] != "function"){
29031 var p = rs[target].getPanel(panelId);
29041 * Searches all regions for a panel with the specified id and activates (shows) it.
29042 * @param {String/ContentPanel} panelId The panels id or the panel itself
29043 * @return {Roo.ContentPanel} The shown panel or null
29045 showPanel : function(panelId) {
29046 var rs = this.regions;
29047 for(var target in rs){
29048 var r = rs[target];
29049 if(typeof r != "function"){
29050 if(r.hasPanel(panelId)){
29051 return r.showPanel(panelId);
29059 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29060 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29062 restoreState : function(provider){
29064 provider = Roo.state.Manager;
29066 var sm = new Roo.LayoutStateManager();
29067 sm.init(this, provider);
29071 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29072 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29073 * a valid ContentPanel config object. Example:
29075 // Create the main layout
29076 var layout = new Roo.BorderLayout('main-ct', {
29087 // Create and add multiple ContentPanels at once via configs
29090 id: 'source-files',
29092 title:'Ext Source Files',
29105 * @param {Object} regions An object containing ContentPanel configs by region name
29107 batchAdd : function(regions){
29108 this.beginUpdate();
29109 for(var rname in regions){
29110 var lr = this.regions[rname];
29112 this.addTypedPanels(lr, regions[rname]);
29119 addTypedPanels : function(lr, ps){
29120 if(typeof ps == 'string'){
29121 lr.add(new Roo.ContentPanel(ps));
29123 else if(ps instanceof Array){
29124 for(var i =0, len = ps.length; i < len; i++){
29125 this.addTypedPanels(lr, ps[i]);
29128 else if(!ps.events){ // raw config?
29130 delete ps.el; // prevent conflict
29131 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29133 else { // panel object assumed!
29138 * Adds a xtype elements to the layout.
29142 xtype : 'ContentPanel',
29149 xtype : 'NestedLayoutPanel',
29155 items : [ ... list of content panels or nested layout panels.. ]
29159 * @param {Object} cfg Xtype definition of item to add.
29161 addxtype : function(cfg)
29163 // basically accepts a pannel...
29164 // can accept a layout region..!?!?
29165 // console.log('BorderLayout add ' + cfg.xtype)
29167 if (!cfg.xtype.match(/Panel$/)) {
29171 var region = cfg.region;
29177 xitems = cfg.items;
29184 case 'ContentPanel': // ContentPanel (el, cfg)
29185 case 'ScrollPanel': // ContentPanel (el, cfg)
29186 if(cfg.autoCreate) {
29187 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29189 var el = this.el.createChild();
29190 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29193 this.add(region, ret);
29197 case 'TreePanel': // our new panel!
29198 cfg.el = this.el.createChild();
29199 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29200 this.add(region, ret);
29203 case 'NestedLayoutPanel':
29204 // create a new Layout (which is a Border Layout...
29205 var el = this.el.createChild();
29206 var clayout = cfg.layout;
29208 clayout.items = clayout.items || [];
29209 // replace this exitems with the clayout ones..
29210 xitems = clayout.items;
29213 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29214 cfg.background = false;
29216 var layout = new Roo.BorderLayout(el, clayout);
29218 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29219 //console.log('adding nested layout panel ' + cfg.toSource());
29220 this.add(region, ret);
29226 // needs grid and region
29228 //var el = this.getRegion(region).el.createChild();
29229 var el = this.el.createChild();
29230 // create the grid first...
29232 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29234 if (region == 'center' && this.active ) {
29235 cfg.background = false;
29237 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29239 this.add(region, ret);
29240 if (cfg.background) {
29241 ret.on('activate', function(gp) {
29242 if (!gp.grid.rendered) {
29255 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29257 // GridPanel (grid, cfg)
29260 this.beginUpdate();
29262 Roo.each(xitems, function(i) {
29272 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29273 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29274 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29275 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29278 var CP = Roo.ContentPanel;
29280 var layout = Roo.BorderLayout.create({
29284 panels: [new CP("north", "North")]
29293 panels: [new CP("west", {title: "West"})]
29302 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29311 panels: [new CP("south", {title: "South", closable: true})]
29318 preferredTabWidth: 150,
29320 new CP("center1", {title: "Close Me", closable: true}),
29321 new CP("center2", {title: "Center Panel", closable: false})
29326 layout.getRegion("center").showPanel("center1");
29331 Roo.BorderLayout.create = function(config, targetEl){
29332 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29333 layout.beginUpdate();
29334 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29335 for(var j = 0, jlen = regions.length; j < jlen; j++){
29336 var lr = regions[j];
29337 if(layout.regions[lr] && config[lr].panels){
29338 var r = layout.regions[lr];
29339 var ps = config[lr].panels;
29340 layout.addTypedPanels(r, ps);
29343 layout.endUpdate();
29348 Roo.BorderLayout.RegionFactory = {
29350 validRegions : ["north","south","east","west","center"],
29353 create : function(target, mgr, config){
29354 target = target.toLowerCase();
29355 if(config.lightweight || config.basic){
29356 return new Roo.BasicLayoutRegion(mgr, config, target);
29360 return new Roo.NorthLayoutRegion(mgr, config);
29362 return new Roo.SouthLayoutRegion(mgr, config);
29364 return new Roo.EastLayoutRegion(mgr, config);
29366 return new Roo.WestLayoutRegion(mgr, config);
29368 return new Roo.CenterLayoutRegion(mgr, config);
29370 throw 'Layout region "'+target+'" not supported.';
29374 * Ext JS Library 1.1.1
29375 * Copyright(c) 2006-2007, Ext JS, LLC.
29377 * Originally Released Under LGPL - original licence link has changed is not relivant.
29380 * <script type="text/javascript">
29384 * @class Roo.BasicLayoutRegion
29385 * @extends Roo.util.Observable
29386 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29387 * and does not have a titlebar, tabs or any other features. All it does is size and position
29388 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29390 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29392 this.position = pos;
29395 * @scope Roo.BasicLayoutRegion
29399 * @event beforeremove
29400 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29401 * @param {Roo.LayoutRegion} this
29402 * @param {Roo.ContentPanel} panel The panel
29403 * @param {Object} e The cancel event object
29405 "beforeremove" : true,
29407 * @event invalidated
29408 * Fires when the layout for this region is changed.
29409 * @param {Roo.LayoutRegion} this
29411 "invalidated" : true,
29413 * @event visibilitychange
29414 * Fires when this region is shown or hidden
29415 * @param {Roo.LayoutRegion} this
29416 * @param {Boolean} visibility true or false
29418 "visibilitychange" : true,
29420 * @event paneladded
29421 * Fires when a panel is added.
29422 * @param {Roo.LayoutRegion} this
29423 * @param {Roo.ContentPanel} panel The panel
29425 "paneladded" : true,
29427 * @event panelremoved
29428 * Fires when a panel is removed.
29429 * @param {Roo.LayoutRegion} this
29430 * @param {Roo.ContentPanel} panel The panel
29432 "panelremoved" : true,
29435 * Fires when this region is collapsed.
29436 * @param {Roo.LayoutRegion} this
29438 "collapsed" : true,
29441 * Fires when this region is expanded.
29442 * @param {Roo.LayoutRegion} this
29447 * Fires when this region is slid into view.
29448 * @param {Roo.LayoutRegion} this
29450 "slideshow" : true,
29453 * Fires when this region slides out of view.
29454 * @param {Roo.LayoutRegion} this
29456 "slidehide" : true,
29458 * @event panelactivated
29459 * Fires when a panel is activated.
29460 * @param {Roo.LayoutRegion} this
29461 * @param {Roo.ContentPanel} panel The activated panel
29463 "panelactivated" : true,
29466 * Fires when the user resizes this region.
29467 * @param {Roo.LayoutRegion} this
29468 * @param {Number} newSize The new size (width for east/west, height for north/south)
29472 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29473 this.panels = new Roo.util.MixedCollection();
29474 this.panels.getKey = this.getPanelId.createDelegate(this);
29476 this.activePanel = null;
29477 // ensure listeners are added...
29479 if (config.listeners || config.events) {
29480 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29481 listeners : config.listeners || {},
29482 events : config.events || {}
29486 if(skipConfig !== true){
29487 this.applyConfig(config);
29491 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29492 getPanelId : function(p){
29496 applyConfig : function(config){
29497 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29498 this.config = config;
29503 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29504 * the width, for horizontal (north, south) the height.
29505 * @param {Number} newSize The new width or height
29507 resizeTo : function(newSize){
29508 var el = this.el ? this.el :
29509 (this.activePanel ? this.activePanel.getEl() : null);
29511 switch(this.position){
29514 el.setWidth(newSize);
29515 this.fireEvent("resized", this, newSize);
29519 el.setHeight(newSize);
29520 this.fireEvent("resized", this, newSize);
29526 getBox : function(){
29527 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29530 getMargins : function(){
29531 return this.margins;
29534 updateBox : function(box){
29536 var el = this.activePanel.getEl();
29537 el.dom.style.left = box.x + "px";
29538 el.dom.style.top = box.y + "px";
29539 this.activePanel.setSize(box.width, box.height);
29543 * Returns the container element for this region.
29544 * @return {Roo.Element}
29546 getEl : function(){
29547 return this.activePanel;
29551 * Returns true if this region is currently visible.
29552 * @return {Boolean}
29554 isVisible : function(){
29555 return this.activePanel ? true : false;
29558 setActivePanel : function(panel){
29559 panel = this.getPanel(panel);
29560 if(this.activePanel && this.activePanel != panel){
29561 this.activePanel.setActiveState(false);
29562 this.activePanel.getEl().setLeftTop(-10000,-10000);
29564 this.activePanel = panel;
29565 panel.setActiveState(true);
29567 panel.setSize(this.box.width, this.box.height);
29569 this.fireEvent("panelactivated", this, panel);
29570 this.fireEvent("invalidated");
29574 * Show the specified panel.
29575 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29576 * @return {Roo.ContentPanel} The shown panel or null
29578 showPanel : function(panel){
29579 if(panel = this.getPanel(panel)){
29580 this.setActivePanel(panel);
29586 * Get the active panel for this region.
29587 * @return {Roo.ContentPanel} The active panel or null
29589 getActivePanel : function(){
29590 return this.activePanel;
29594 * Add the passed ContentPanel(s)
29595 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29596 * @return {Roo.ContentPanel} The panel added (if only one was added)
29598 add : function(panel){
29599 if(arguments.length > 1){
29600 for(var i = 0, len = arguments.length; i < len; i++) {
29601 this.add(arguments[i]);
29605 if(this.hasPanel(panel)){
29606 this.showPanel(panel);
29609 var el = panel.getEl();
29610 if(el.dom.parentNode != this.mgr.el.dom){
29611 this.mgr.el.dom.appendChild(el.dom);
29613 if(panel.setRegion){
29614 panel.setRegion(this);
29616 this.panels.add(panel);
29617 el.setStyle("position", "absolute");
29618 if(!panel.background){
29619 this.setActivePanel(panel);
29620 if(this.config.initialSize && this.panels.getCount()==1){
29621 this.resizeTo(this.config.initialSize);
29624 this.fireEvent("paneladded", this, panel);
29629 * Returns true if the panel is in this region.
29630 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29631 * @return {Boolean}
29633 hasPanel : function(panel){
29634 if(typeof panel == "object"){ // must be panel obj
29635 panel = panel.getId();
29637 return this.getPanel(panel) ? true : false;
29641 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29642 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29643 * @param {Boolean} preservePanel Overrides the config preservePanel option
29644 * @return {Roo.ContentPanel} The panel that was removed
29646 remove : function(panel, preservePanel){
29647 panel = this.getPanel(panel);
29652 this.fireEvent("beforeremove", this, panel, e);
29653 if(e.cancel === true){
29656 var panelId = panel.getId();
29657 this.panels.removeKey(panelId);
29662 * Returns the panel specified or null if it's not in this region.
29663 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29664 * @return {Roo.ContentPanel}
29666 getPanel : function(id){
29667 if(typeof id == "object"){ // must be panel obj
29670 return this.panels.get(id);
29674 * Returns this regions position (north/south/east/west/center).
29677 getPosition: function(){
29678 return this.position;
29682 * Ext JS Library 1.1.1
29683 * Copyright(c) 2006-2007, Ext JS, LLC.
29685 * Originally Released Under LGPL - original licence link has changed is not relivant.
29688 * <script type="text/javascript">
29692 * @class Roo.LayoutRegion
29693 * @extends Roo.BasicLayoutRegion
29694 * This class represents a region in a layout manager.
29695 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29696 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29697 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29698 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29699 * @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})
29700 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29701 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29702 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29703 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29704 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29705 * @cfg {String} title The title for the region (overrides panel titles)
29706 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29707 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29708 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29709 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29710 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29711 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29712 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29713 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29714 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29715 * @cfg {Boolean} showPin True to show a pin button
29716 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29717 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29718 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29719 * @cfg {Number} width For East/West panels
29720 * @cfg {Number} height For North/South panels
29721 * @cfg {Boolean} split To show the splitter
29723 Roo.LayoutRegion = function(mgr, config, pos){
29724 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29725 var dh = Roo.DomHelper;
29726 /** This region's container element
29727 * @type Roo.Element */
29728 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29729 /** This region's title element
29730 * @type Roo.Element */
29732 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29733 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29734 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29736 this.titleEl.enableDisplayMode();
29737 /** This region's title text element
29738 * @type HTMLElement */
29739 this.titleTextEl = this.titleEl.dom.firstChild;
29740 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29741 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29742 this.closeBtn.enableDisplayMode();
29743 this.closeBtn.on("click", this.closeClicked, this);
29744 this.closeBtn.hide();
29746 this.createBody(config);
29747 this.visible = true;
29748 this.collapsed = false;
29750 if(config.hideWhenEmpty){
29752 this.on("paneladded", this.validateVisibility, this);
29753 this.on("panelremoved", this.validateVisibility, this);
29755 this.applyConfig(config);
29758 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29760 createBody : function(){
29761 /** This region's body element
29762 * @type Roo.Element */
29763 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29766 applyConfig : function(c){
29767 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29768 var dh = Roo.DomHelper;
29769 if(c.titlebar !== false){
29770 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
29771 this.collapseBtn.on("click", this.collapse, this);
29772 this.collapseBtn.enableDisplayMode();
29774 if(c.showPin === true || this.showPin){
29775 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
29776 this.stickBtn.enableDisplayMode();
29777 this.stickBtn.on("click", this.expand, this);
29778 this.stickBtn.hide();
29781 /** This region's collapsed element
29782 * @type Roo.Element */
29783 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
29784 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
29786 if(c.floatable !== false){
29787 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
29788 this.collapsedEl.on("click", this.collapseClick, this);
29791 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
29792 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
29793 id: "message", unselectable: "on", style:{"float":"left"}});
29794 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
29796 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
29797 this.expandBtn.on("click", this.expand, this);
29799 if(this.collapseBtn){
29800 this.collapseBtn.setVisible(c.collapsible == true);
29802 this.cmargins = c.cmargins || this.cmargins ||
29803 (this.position == "west" || this.position == "east" ?
29804 {top: 0, left: 2, right:2, bottom: 0} :
29805 {top: 2, left: 0, right:0, bottom: 2});
29806 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29807 this.bottomTabs = c.tabPosition != "top";
29808 this.autoScroll = c.autoScroll || false;
29809 if(this.autoScroll){
29810 this.bodyEl.setStyle("overflow", "auto");
29812 this.bodyEl.setStyle("overflow", "hidden");
29814 //if(c.titlebar !== false){
29815 if((!c.titlebar && !c.title) || c.titlebar === false){
29816 this.titleEl.hide();
29818 this.titleEl.show();
29820 this.titleTextEl.innerHTML = c.title;
29824 this.duration = c.duration || .30;
29825 this.slideDuration = c.slideDuration || .45;
29828 this.collapse(true);
29835 * Returns true if this region is currently visible.
29836 * @return {Boolean}
29838 isVisible : function(){
29839 return this.visible;
29843 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
29844 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
29846 setCollapsedTitle : function(title){
29847 title = title || " ";
29848 if(this.collapsedTitleTextEl){
29849 this.collapsedTitleTextEl.innerHTML = title;
29853 getBox : function(){
29855 if(!this.collapsed){
29856 b = this.el.getBox(false, true);
29858 b = this.collapsedEl.getBox(false, true);
29863 getMargins : function(){
29864 return this.collapsed ? this.cmargins : this.margins;
29867 highlight : function(){
29868 this.el.addClass("x-layout-panel-dragover");
29871 unhighlight : function(){
29872 this.el.removeClass("x-layout-panel-dragover");
29875 updateBox : function(box){
29877 if(!this.collapsed){
29878 this.el.dom.style.left = box.x + "px";
29879 this.el.dom.style.top = box.y + "px";
29880 this.updateBody(box.width, box.height);
29882 this.collapsedEl.dom.style.left = box.x + "px";
29883 this.collapsedEl.dom.style.top = box.y + "px";
29884 this.collapsedEl.setSize(box.width, box.height);
29887 this.tabs.autoSizeTabs();
29891 updateBody : function(w, h){
29893 this.el.setWidth(w);
29894 w -= this.el.getBorderWidth("rl");
29895 if(this.config.adjustments){
29896 w += this.config.adjustments[0];
29900 this.el.setHeight(h);
29901 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
29902 h -= this.el.getBorderWidth("tb");
29903 if(this.config.adjustments){
29904 h += this.config.adjustments[1];
29906 this.bodyEl.setHeight(h);
29908 h = this.tabs.syncHeight(h);
29911 if(this.panelSize){
29912 w = w !== null ? w : this.panelSize.width;
29913 h = h !== null ? h : this.panelSize.height;
29915 if(this.activePanel){
29916 var el = this.activePanel.getEl();
29917 w = w !== null ? w : el.getWidth();
29918 h = h !== null ? h : el.getHeight();
29919 this.panelSize = {width: w, height: h};
29920 this.activePanel.setSize(w, h);
29922 if(Roo.isIE && this.tabs){
29923 this.tabs.el.repaint();
29928 * Returns the container element for this region.
29929 * @return {Roo.Element}
29931 getEl : function(){
29936 * Hides this region.
29939 if(!this.collapsed){
29940 this.el.dom.style.left = "-2000px";
29943 this.collapsedEl.dom.style.left = "-2000px";
29944 this.collapsedEl.hide();
29946 this.visible = false;
29947 this.fireEvent("visibilitychange", this, false);
29951 * Shows this region if it was previously hidden.
29954 if(!this.collapsed){
29957 this.collapsedEl.show();
29959 this.visible = true;
29960 this.fireEvent("visibilitychange", this, true);
29963 closeClicked : function(){
29964 if(this.activePanel){
29965 this.remove(this.activePanel);
29969 collapseClick : function(e){
29971 e.stopPropagation();
29974 e.stopPropagation();
29980 * Collapses this region.
29981 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
29983 collapse : function(skipAnim){
29984 if(this.collapsed) return;
29985 this.collapsed = true;
29987 this.split.el.hide();
29989 if(this.config.animate && skipAnim !== true){
29990 this.fireEvent("invalidated", this);
29991 this.animateCollapse();
29993 this.el.setLocation(-20000,-20000);
29995 this.collapsedEl.show();
29996 this.fireEvent("collapsed", this);
29997 this.fireEvent("invalidated", this);
30001 animateCollapse : function(){
30006 * Expands this region if it was previously collapsed.
30007 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
30008 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
30010 expand : function(e, skipAnim){
30011 if(e) e.stopPropagation();
30012 if(!this.collapsed || this.el.hasActiveFx()) return;
30014 this.afterSlideIn();
30017 this.collapsed = false;
30018 if(this.config.animate && skipAnim !== true){
30019 this.animateExpand();
30023 this.split.el.show();
30025 this.collapsedEl.setLocation(-2000,-2000);
30026 this.collapsedEl.hide();
30027 this.fireEvent("invalidated", this);
30028 this.fireEvent("expanded", this);
30032 animateExpand : function(){
30036 initTabs : function(){
30037 this.bodyEl.setStyle("overflow", "hidden");
30038 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30039 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30040 disableTooltips: this.config.disableTabTips
30042 if(this.config.hideTabs){
30043 ts.stripWrap.setDisplayed(false);
30046 ts.resizeTabs = this.config.resizeTabs === true;
30047 ts.minTabWidth = this.config.minTabWidth || 40;
30048 ts.maxTabWidth = this.config.maxTabWidth || 250;
30049 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30050 ts.monitorResize = false;
30051 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30052 ts.bodyEl.addClass('x-layout-tabs-body');
30053 this.panels.each(this.initPanelAsTab, this);
30056 initPanelAsTab : function(panel){
30057 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30058 this.config.closeOnTab && panel.isClosable());
30059 if(panel.tabTip !== undefined){
30060 ti.setTooltip(panel.tabTip);
30062 ti.on("activate", function(){
30063 this.setActivePanel(panel);
30065 if(this.config.closeOnTab){
30066 ti.on("beforeclose", function(t, e){
30068 this.remove(panel);
30074 updatePanelTitle : function(panel, title){
30075 if(this.activePanel == panel){
30076 this.updateTitle(title);
30079 var ti = this.tabs.getTab(panel.getEl().id);
30081 if(panel.tabTip !== undefined){
30082 ti.setTooltip(panel.tabTip);
30087 updateTitle : function(title){
30088 if(this.titleTextEl && !this.config.title){
30089 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30093 setActivePanel : function(panel){
30094 panel = this.getPanel(panel);
30095 if(this.activePanel && this.activePanel != panel){
30096 this.activePanel.setActiveState(false);
30098 this.activePanel = panel;
30099 panel.setActiveState(true);
30100 if(this.panelSize){
30101 panel.setSize(this.panelSize.width, this.panelSize.height);
30104 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30106 this.updateTitle(panel.getTitle());
30108 this.fireEvent("invalidated", this);
30110 this.fireEvent("panelactivated", this, panel);
30114 * Shows the specified panel.
30115 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30116 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30118 showPanel : function(panel){
30119 if(panel = this.getPanel(panel)){
30121 var tab = this.tabs.getTab(panel.getEl().id);
30122 if(tab.isHidden()){
30123 this.tabs.unhideTab(tab.id);
30127 this.setActivePanel(panel);
30134 * Get the active panel for this region.
30135 * @return {Roo.ContentPanel} The active panel or null
30137 getActivePanel : function(){
30138 return this.activePanel;
30141 validateVisibility : function(){
30142 if(this.panels.getCount() < 1){
30143 this.updateTitle(" ");
30144 this.closeBtn.hide();
30147 if(!this.isVisible()){
30154 * Adds the passed ContentPanel(s) to this region.
30155 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30156 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30158 add : function(panel){
30159 if(arguments.length > 1){
30160 for(var i = 0, len = arguments.length; i < len; i++) {
30161 this.add(arguments[i]);
30165 if(this.hasPanel(panel)){
30166 this.showPanel(panel);
30169 panel.setRegion(this);
30170 this.panels.add(panel);
30171 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30172 this.bodyEl.dom.appendChild(panel.getEl().dom);
30173 if(panel.background !== true){
30174 this.setActivePanel(panel);
30176 this.fireEvent("paneladded", this, panel);
30182 this.initPanelAsTab(panel);
30184 if(panel.background !== true){
30185 this.tabs.activate(panel.getEl().id);
30187 this.fireEvent("paneladded", this, panel);
30192 * Hides the tab for the specified panel.
30193 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30195 hidePanel : function(panel){
30196 if(this.tabs && (panel = this.getPanel(panel))){
30197 this.tabs.hideTab(panel.getEl().id);
30202 * Unhides the tab for a previously hidden panel.
30203 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30205 unhidePanel : function(panel){
30206 if(this.tabs && (panel = this.getPanel(panel))){
30207 this.tabs.unhideTab(panel.getEl().id);
30211 clearPanels : function(){
30212 while(this.panels.getCount() > 0){
30213 this.remove(this.panels.first());
30218 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30219 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30220 * @param {Boolean} preservePanel Overrides the config preservePanel option
30221 * @return {Roo.ContentPanel} The panel that was removed
30223 remove : function(panel, preservePanel){
30224 panel = this.getPanel(panel);
30229 this.fireEvent("beforeremove", this, panel, e);
30230 if(e.cancel === true){
30233 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30234 var panelId = panel.getId();
30235 this.panels.removeKey(panelId);
30237 document.body.appendChild(panel.getEl().dom);
30240 this.tabs.removeTab(panel.getEl().id);
30241 }else if (!preservePanel){
30242 this.bodyEl.dom.removeChild(panel.getEl().dom);
30244 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30245 var p = this.panels.first();
30246 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30247 tempEl.appendChild(p.getEl().dom);
30248 this.bodyEl.update("");
30249 this.bodyEl.dom.appendChild(p.getEl().dom);
30251 this.updateTitle(p.getTitle());
30253 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30254 this.setActivePanel(p);
30256 panel.setRegion(null);
30257 if(this.activePanel == panel){
30258 this.activePanel = null;
30260 if(this.config.autoDestroy !== false && preservePanel !== true){
30261 try{panel.destroy();}catch(e){}
30263 this.fireEvent("panelremoved", this, panel);
30268 * Returns the TabPanel component used by this region
30269 * @return {Roo.TabPanel}
30271 getTabs : function(){
30275 createTool : function(parentEl, className){
30276 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30277 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30278 btn.addClassOnOver("x-layout-tools-button-over");
30283 * Ext JS Library 1.1.1
30284 * Copyright(c) 2006-2007, Ext JS, LLC.
30286 * Originally Released Under LGPL - original licence link has changed is not relivant.
30289 * <script type="text/javascript">
30295 * @class Roo.SplitLayoutRegion
30296 * @extends Roo.LayoutRegion
30297 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30299 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30300 this.cursor = cursor;
30301 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30304 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30305 splitTip : "Drag to resize.",
30306 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30307 useSplitTips : false,
30309 applyConfig : function(config){
30310 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30313 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30314 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30315 /** The SplitBar for this region
30316 * @type Roo.SplitBar */
30317 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30318 this.split.on("moved", this.onSplitMove, this);
30319 this.split.useShim = config.useShim === true;
30320 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30321 if(this.useSplitTips){
30322 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30324 if(config.collapsible){
30325 this.split.el.on("dblclick", this.collapse, this);
30328 if(typeof config.minSize != "undefined"){
30329 this.split.minSize = config.minSize;
30331 if(typeof config.maxSize != "undefined"){
30332 this.split.maxSize = config.maxSize;
30334 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30335 this.hideSplitter();
30340 getHMaxSize : function(){
30341 var cmax = this.config.maxSize || 10000;
30342 var center = this.mgr.getRegion("center");
30343 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30346 getVMaxSize : function(){
30347 var cmax = this.config.maxSize || 10000;
30348 var center = this.mgr.getRegion("center");
30349 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30352 onSplitMove : function(split, newSize){
30353 this.fireEvent("resized", this, newSize);
30357 * Returns the {@link Roo.SplitBar} for this region.
30358 * @return {Roo.SplitBar}
30360 getSplitBar : function(){
30365 this.hideSplitter();
30366 Roo.SplitLayoutRegion.superclass.hide.call(this);
30369 hideSplitter : function(){
30371 this.split.el.setLocation(-2000,-2000);
30372 this.split.el.hide();
30378 this.split.el.show();
30380 Roo.SplitLayoutRegion.superclass.show.call(this);
30383 beforeSlide: function(){
30384 if(Roo.isGecko){// firefox overflow auto bug workaround
30385 this.bodyEl.clip();
30386 if(this.tabs) this.tabs.bodyEl.clip();
30387 if(this.activePanel){
30388 this.activePanel.getEl().clip();
30390 if(this.activePanel.beforeSlide){
30391 this.activePanel.beforeSlide();
30397 afterSlide : function(){
30398 if(Roo.isGecko){// firefox overflow auto bug workaround
30399 this.bodyEl.unclip();
30400 if(this.tabs) this.tabs.bodyEl.unclip();
30401 if(this.activePanel){
30402 this.activePanel.getEl().unclip();
30403 if(this.activePanel.afterSlide){
30404 this.activePanel.afterSlide();
30410 initAutoHide : function(){
30411 if(this.autoHide !== false){
30412 if(!this.autoHideHd){
30413 var st = new Roo.util.DelayedTask(this.slideIn, this);
30414 this.autoHideHd = {
30415 "mouseout": function(e){
30416 if(!e.within(this.el, true)){
30420 "mouseover" : function(e){
30426 this.el.on(this.autoHideHd);
30430 clearAutoHide : function(){
30431 if(this.autoHide !== false){
30432 this.el.un("mouseout", this.autoHideHd.mouseout);
30433 this.el.un("mouseover", this.autoHideHd.mouseover);
30437 clearMonitor : function(){
30438 Roo.get(document).un("click", this.slideInIf, this);
30441 // these names are backwards but not changed for compat
30442 slideOut : function(){
30443 if(this.isSlid || this.el.hasActiveFx()){
30446 this.isSlid = true;
30447 if(this.collapseBtn){
30448 this.collapseBtn.hide();
30450 this.closeBtnState = this.closeBtn.getStyle('display');
30451 this.closeBtn.hide();
30453 this.stickBtn.show();
30456 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30457 this.beforeSlide();
30458 this.el.setStyle("z-index", 10001);
30459 this.el.slideIn(this.getSlideAnchor(), {
30460 callback: function(){
30462 this.initAutoHide();
30463 Roo.get(document).on("click", this.slideInIf, this);
30464 this.fireEvent("slideshow", this);
30471 afterSlideIn : function(){
30472 this.clearAutoHide();
30473 this.isSlid = false;
30474 this.clearMonitor();
30475 this.el.setStyle("z-index", "");
30476 if(this.collapseBtn){
30477 this.collapseBtn.show();
30479 this.closeBtn.setStyle('display', this.closeBtnState);
30481 this.stickBtn.hide();
30483 this.fireEvent("slidehide", this);
30486 slideIn : function(cb){
30487 if(!this.isSlid || this.el.hasActiveFx()){
30491 this.isSlid = false;
30492 this.beforeSlide();
30493 this.el.slideOut(this.getSlideAnchor(), {
30494 callback: function(){
30495 this.el.setLeftTop(-10000, -10000);
30497 this.afterSlideIn();
30505 slideInIf : function(e){
30506 if(!e.within(this.el)){
30511 animateCollapse : function(){
30512 this.beforeSlide();
30513 this.el.setStyle("z-index", 20000);
30514 var anchor = this.getSlideAnchor();
30515 this.el.slideOut(anchor, {
30516 callback : function(){
30517 this.el.setStyle("z-index", "");
30518 this.collapsedEl.slideIn(anchor, {duration:.3});
30520 this.el.setLocation(-10000,-10000);
30522 this.fireEvent("collapsed", this);
30529 animateExpand : function(){
30530 this.beforeSlide();
30531 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30532 this.el.setStyle("z-index", 20000);
30533 this.collapsedEl.hide({
30536 this.el.slideIn(this.getSlideAnchor(), {
30537 callback : function(){
30538 this.el.setStyle("z-index", "");
30541 this.split.el.show();
30543 this.fireEvent("invalidated", this);
30544 this.fireEvent("expanded", this);
30572 getAnchor : function(){
30573 return this.anchors[this.position];
30576 getCollapseAnchor : function(){
30577 return this.canchors[this.position];
30580 getSlideAnchor : function(){
30581 return this.sanchors[this.position];
30584 getAlignAdj : function(){
30585 var cm = this.cmargins;
30586 switch(this.position){
30602 getExpandAdj : function(){
30603 var c = this.collapsedEl, cm = this.cmargins;
30604 switch(this.position){
30606 return [-(cm.right+c.getWidth()+cm.left), 0];
30609 return [cm.right+c.getWidth()+cm.left, 0];
30612 return [0, -(cm.top+cm.bottom+c.getHeight())];
30615 return [0, cm.top+cm.bottom+c.getHeight()];
30621 * Ext JS Library 1.1.1
30622 * Copyright(c) 2006-2007, Ext JS, LLC.
30624 * Originally Released Under LGPL - original licence link has changed is not relivant.
30627 * <script type="text/javascript">
30630 * These classes are private internal classes
30632 Roo.CenterLayoutRegion = function(mgr, config){
30633 Roo.LayoutRegion.call(this, mgr, config, "center");
30634 this.visible = true;
30635 this.minWidth = config.minWidth || 20;
30636 this.minHeight = config.minHeight || 20;
30639 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30641 // center panel can't be hidden
30645 // center panel can't be hidden
30648 getMinWidth: function(){
30649 return this.minWidth;
30652 getMinHeight: function(){
30653 return this.minHeight;
30658 Roo.NorthLayoutRegion = function(mgr, config){
30659 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30661 this.split.placement = Roo.SplitBar.TOP;
30662 this.split.orientation = Roo.SplitBar.VERTICAL;
30663 this.split.el.addClass("x-layout-split-v");
30665 var size = config.initialSize || config.height;
30666 if(typeof size != "undefined"){
30667 this.el.setHeight(size);
30670 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30671 orientation: Roo.SplitBar.VERTICAL,
30672 getBox : function(){
30673 if(this.collapsed){
30674 return this.collapsedEl.getBox();
30676 var box = this.el.getBox();
30678 box.height += this.split.el.getHeight();
30683 updateBox : function(box){
30684 if(this.split && !this.collapsed){
30685 box.height -= this.split.el.getHeight();
30686 this.split.el.setLeft(box.x);
30687 this.split.el.setTop(box.y+box.height);
30688 this.split.el.setWidth(box.width);
30690 if(this.collapsed){
30691 this.updateBody(box.width, null);
30693 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30697 Roo.SouthLayoutRegion = function(mgr, config){
30698 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30700 this.split.placement = Roo.SplitBar.BOTTOM;
30701 this.split.orientation = Roo.SplitBar.VERTICAL;
30702 this.split.el.addClass("x-layout-split-v");
30704 var size = config.initialSize || config.height;
30705 if(typeof size != "undefined"){
30706 this.el.setHeight(size);
30709 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30710 orientation: Roo.SplitBar.VERTICAL,
30711 getBox : function(){
30712 if(this.collapsed){
30713 return this.collapsedEl.getBox();
30715 var box = this.el.getBox();
30717 var sh = this.split.el.getHeight();
30724 updateBox : function(box){
30725 if(this.split && !this.collapsed){
30726 var sh = this.split.el.getHeight();
30729 this.split.el.setLeft(box.x);
30730 this.split.el.setTop(box.y-sh);
30731 this.split.el.setWidth(box.width);
30733 if(this.collapsed){
30734 this.updateBody(box.width, null);
30736 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30740 Roo.EastLayoutRegion = function(mgr, config){
30741 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
30743 this.split.placement = Roo.SplitBar.RIGHT;
30744 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30745 this.split.el.addClass("x-layout-split-h");
30747 var size = config.initialSize || config.width;
30748 if(typeof size != "undefined"){
30749 this.el.setWidth(size);
30752 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
30753 orientation: Roo.SplitBar.HORIZONTAL,
30754 getBox : function(){
30755 if(this.collapsed){
30756 return this.collapsedEl.getBox();
30758 var box = this.el.getBox();
30760 var sw = this.split.el.getWidth();
30767 updateBox : function(box){
30768 if(this.split && !this.collapsed){
30769 var sw = this.split.el.getWidth();
30771 this.split.el.setLeft(box.x);
30772 this.split.el.setTop(box.y);
30773 this.split.el.setHeight(box.height);
30776 if(this.collapsed){
30777 this.updateBody(null, box.height);
30779 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30783 Roo.WestLayoutRegion = function(mgr, config){
30784 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
30786 this.split.placement = Roo.SplitBar.LEFT;
30787 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30788 this.split.el.addClass("x-layout-split-h");
30790 var size = config.initialSize || config.width;
30791 if(typeof size != "undefined"){
30792 this.el.setWidth(size);
30795 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
30796 orientation: Roo.SplitBar.HORIZONTAL,
30797 getBox : function(){
30798 if(this.collapsed){
30799 return this.collapsedEl.getBox();
30801 var box = this.el.getBox();
30803 box.width += this.split.el.getWidth();
30808 updateBox : function(box){
30809 if(this.split && !this.collapsed){
30810 var sw = this.split.el.getWidth();
30812 this.split.el.setLeft(box.x+box.width);
30813 this.split.el.setTop(box.y);
30814 this.split.el.setHeight(box.height);
30816 if(this.collapsed){
30817 this.updateBody(null, box.height);
30819 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30824 * Ext JS Library 1.1.1
30825 * Copyright(c) 2006-2007, Ext JS, LLC.
30827 * Originally Released Under LGPL - original licence link has changed is not relivant.
30830 * <script type="text/javascript">
30835 * Private internal class for reading and applying state
30837 Roo.LayoutStateManager = function(layout){
30838 // default empty state
30847 Roo.LayoutStateManager.prototype = {
30848 init : function(layout, provider){
30849 this.provider = provider;
30850 var state = provider.get(layout.id+"-layout-state");
30852 var wasUpdating = layout.isUpdating();
30854 layout.beginUpdate();
30856 for(var key in state){
30857 if(typeof state[key] != "function"){
30858 var rstate = state[key];
30859 var r = layout.getRegion(key);
30862 r.resizeTo(rstate.size);
30864 if(rstate.collapsed == true){
30867 r.expand(null, true);
30873 layout.endUpdate();
30875 this.state = state;
30877 this.layout = layout;
30878 layout.on("regionresized", this.onRegionResized, this);
30879 layout.on("regioncollapsed", this.onRegionCollapsed, this);
30880 layout.on("regionexpanded", this.onRegionExpanded, this);
30883 storeState : function(){
30884 this.provider.set(this.layout.id+"-layout-state", this.state);
30887 onRegionResized : function(region, newSize){
30888 this.state[region.getPosition()].size = newSize;
30892 onRegionCollapsed : function(region){
30893 this.state[region.getPosition()].collapsed = true;
30897 onRegionExpanded : function(region){
30898 this.state[region.getPosition()].collapsed = false;
30903 * Ext JS Library 1.1.1
30904 * Copyright(c) 2006-2007, Ext JS, LLC.
30906 * Originally Released Under LGPL - original licence link has changed is not relivant.
30909 * <script type="text/javascript">
30912 * @class Roo.ContentPanel
30913 * @extends Roo.util.Observable
30914 * A basic ContentPanel element.
30915 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
30916 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
30917 * @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
30918 * @cfg {Boolean} closable True if the panel can be closed/removed
30919 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
30920 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
30921 * @cfg {Toolbar} toolbar A toolbar for this panel
30922 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
30923 * @cfg {String} title The title for this panel
30924 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
30925 * @cfg {String} url Calls {@link #setUrl} with this value
30926 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
30927 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
30928 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
30930 * Create a new ContentPanel.
30931 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
30932 * @param {String/Object} config A string to set only the title or a config object
30933 * @param {String} content (optional) Set the HTML content for this panel
30934 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
30936 Roo.ContentPanel = function(el, config, content){
30940 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
30944 if (config && config.parentLayout) {
30945 el = config.parentLayout.el.createChild();
30948 if(el.autoCreate){ // xtype is available if this is called from factory
30952 this.el = Roo.get(el);
30953 if(!this.el && config && config.autoCreate){
30954 if(typeof config.autoCreate == "object"){
30955 if(!config.autoCreate.id){
30956 config.autoCreate.id = config.id||el;
30958 this.el = Roo.DomHelper.append(document.body,
30959 config.autoCreate, true);
30961 this.el = Roo.DomHelper.append(document.body,
30962 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
30965 this.closable = false;
30966 this.loaded = false;
30967 this.active = false;
30968 if(typeof config == "string"){
30969 this.title = config;
30971 Roo.apply(this, config);
30974 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
30975 this.wrapEl = this.el.wrap();
30976 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
30983 this.resizeEl = Roo.get(this.resizeEl, true);
30985 this.resizeEl = this.el;
30990 * Fires when this panel is activated.
30991 * @param {Roo.ContentPanel} this
30995 * @event deactivate
30996 * Fires when this panel is activated.
30997 * @param {Roo.ContentPanel} this
30999 "deactivate" : true,
31003 * Fires when this panel is resized if fitToFrame is true.
31004 * @param {Roo.ContentPanel} this
31005 * @param {Number} width The width after any component adjustments
31006 * @param {Number} height The height after any component adjustments
31010 if(this.autoScroll){
31011 this.resizeEl.setStyle("overflow", "auto");
31013 // fix randome scrolling
31014 this.el.on('scroll', function() {
31015 this.scrollTo('top',0);
31018 content = content || this.content;
31020 this.setContent(content);
31022 if(config && config.url){
31023 this.setUrl(this.url, this.params, this.loadOnce);
31028 Roo.ContentPanel.superclass.constructor.call(this);
31031 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31033 setRegion : function(region){
31034 this.region = region;
31036 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31038 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31043 * Returns the toolbar for this Panel if one was configured.
31044 * @return {Roo.Toolbar}
31046 getToolbar : function(){
31047 return this.toolbar;
31050 setActiveState : function(active){
31051 this.active = active;
31053 this.fireEvent("deactivate", this);
31055 this.fireEvent("activate", this);
31059 * Updates this panel's element
31060 * @param {String} content The new content
31061 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31063 setContent : function(content, loadScripts){
31064 this.el.update(content, loadScripts);
31067 ignoreResize : function(w, h){
31068 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31071 this.lastSize = {width: w, height: h};
31076 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31077 * @return {Roo.UpdateManager} The UpdateManager
31079 getUpdateManager : function(){
31080 return this.el.getUpdateManager();
31083 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31084 * @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:
31087 url: "your-url.php",
31088 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31089 callback: yourFunction,
31090 scope: yourObject, //(optional scope)
31093 text: "Loading...",
31098 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31099 * 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.
31100 * @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}
31101 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31102 * @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.
31103 * @return {Roo.ContentPanel} this
31106 var um = this.el.getUpdateManager();
31107 um.update.apply(um, arguments);
31113 * 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.
31114 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31115 * @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)
31116 * @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)
31117 * @return {Roo.UpdateManager} The UpdateManager
31119 setUrl : function(url, params, loadOnce){
31120 if(this.refreshDelegate){
31121 this.removeListener("activate", this.refreshDelegate);
31123 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31124 this.on("activate", this.refreshDelegate);
31125 return this.el.getUpdateManager();
31128 _handleRefresh : function(url, params, loadOnce){
31129 if(!loadOnce || !this.loaded){
31130 var updater = this.el.getUpdateManager();
31131 updater.update(url, params, this._setLoaded.createDelegate(this));
31135 _setLoaded : function(){
31136 this.loaded = true;
31140 * Returns this panel's id
31143 getId : function(){
31148 * Returns this panel's element - used by regiosn to add.
31149 * @return {Roo.Element}
31151 getEl : function(){
31152 return this.wrapEl || this.el;
31155 adjustForComponents : function(width, height){
31156 if(this.resizeEl != this.el){
31157 width -= this.el.getFrameWidth('lr');
31158 height -= this.el.getFrameWidth('tb');
31161 var te = this.toolbar.getEl();
31162 height -= te.getHeight();
31163 te.setWidth(width);
31165 if(this.adjustments){
31166 width += this.adjustments[0];
31167 height += this.adjustments[1];
31169 return {"width": width, "height": height};
31172 setSize : function(width, height){
31173 if(this.fitToFrame && !this.ignoreResize(width, height)){
31174 if(this.fitContainer && this.resizeEl != this.el){
31175 this.el.setSize(width, height);
31177 var size = this.adjustForComponents(width, height);
31178 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31179 this.fireEvent('resize', this, size.width, size.height);
31184 * Returns this panel's title
31187 getTitle : function(){
31192 * Set this panel's title
31193 * @param {String} title
31195 setTitle : function(title){
31196 this.title = title;
31198 this.region.updatePanelTitle(this, title);
31203 * Returns true is this panel was configured to be closable
31204 * @return {Boolean}
31206 isClosable : function(){
31207 return this.closable;
31210 beforeSlide : function(){
31212 this.resizeEl.clip();
31215 afterSlide : function(){
31217 this.resizeEl.unclip();
31221 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31222 * Will fail silently if the {@link #setUrl} method has not been called.
31223 * This does not activate the panel, just updates its content.
31225 refresh : function(){
31226 if(this.refreshDelegate){
31227 this.loaded = false;
31228 this.refreshDelegate();
31233 * Destroys this panel
31235 destroy : function(){
31236 this.el.removeAllListeners();
31237 var tempEl = document.createElement("span");
31238 tempEl.appendChild(this.el.dom);
31239 tempEl.innerHTML = "";
31245 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31255 * @param {Object} cfg Xtype definition of item to add.
31258 addxtype : function(cfg) {
31260 if (cfg.xtype.match(/^Form$/)) {
31261 var el = this.el.createChild();
31263 this.form = new Roo.form.Form(cfg);
31266 if ( this.form.allItems.length) this.form.render(el.dom);
31269 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
31271 cfg.el = this.el.appendChild(document.createElement("div"));
31273 var ret = new Roo[cfg.xtype](cfg);
31274 ret.render(false, ''); // render blank..
31284 * @class Roo.GridPanel
31285 * @extends Roo.ContentPanel
31287 * Create a new GridPanel.
31288 * @param {Roo.grid.Grid} grid The grid for this panel
31289 * @param {String/Object} config A string to set only the panel's title, or a config object
31291 Roo.GridPanel = function(grid, config){
31294 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31295 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31297 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31299 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31302 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31304 // xtype created footer. - not sure if will work as we normally have to render first..
31305 if (this.footer && !this.footer.el && this.footer.xtype) {
31307 this.footer.container = this.grid.getView().getFooterPanel(true);
31308 this.footer.dataSource = this.grid.dataSource;
31309 this.footer = Roo.factory(this.footer, Roo);
31313 grid.monitorWindowResize = false; // turn off autosizing
31314 grid.autoHeight = false;
31315 grid.autoWidth = false;
31317 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31320 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31321 getId : function(){
31322 return this.grid.id;
31326 * Returns the grid for this panel
31327 * @return {Roo.grid.Grid}
31329 getGrid : function(){
31333 setSize : function(width, height){
31334 if(!this.ignoreResize(width, height)){
31335 var grid = this.grid;
31336 var size = this.adjustForComponents(width, height);
31337 grid.getGridEl().setSize(size.width, size.height);
31342 beforeSlide : function(){
31343 this.grid.getView().scroller.clip();
31346 afterSlide : function(){
31347 this.grid.getView().scroller.unclip();
31350 destroy : function(){
31351 this.grid.destroy();
31353 Roo.GridPanel.superclass.destroy.call(this);
31359 * @class Roo.NestedLayoutPanel
31360 * @extends Roo.ContentPanel
31362 * Create a new NestedLayoutPanel.
31365 * @param {Roo.BorderLayout} layout The layout for this panel
31366 * @param {String/Object} config A string to set only the title or a config object
31368 Roo.NestedLayoutPanel = function(layout, config)
31370 // construct with only one argument..
31371 /* FIXME - implement nicer consturctors
31372 if (layout.layout) {
31374 layout = config.layout;
31375 delete config.layout;
31377 if (layout.xtype && !layout.getEl) {
31378 // then layout needs constructing..
31379 layout = Roo.factory(layout, Roo);
31384 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31386 layout.monitorWindowResize = false; // turn off autosizing
31387 this.layout = layout;
31388 this.layout.getEl().addClass("x-layout-nested-layout");
31395 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31397 setSize : function(width, height){
31398 if(!this.ignoreResize(width, height)){
31399 var size = this.adjustForComponents(width, height);
31400 var el = this.layout.getEl();
31401 el.setSize(size.width, size.height);
31402 var touch = el.dom.offsetWidth;
31403 this.layout.layout();
31404 // ie requires a double layout on the first pass
31405 if(Roo.isIE && !this.initialized){
31406 this.initialized = true;
31407 this.layout.layout();
31412 // activate all subpanels if not currently active..
31414 setActiveState : function(active){
31415 this.active = active;
31417 this.fireEvent("deactivate", this);
31421 this.fireEvent("activate", this);
31422 // not sure if this should happen before or after..
31423 if (!this.layout) {
31424 return; // should not happen..
31427 for (var r in this.layout.regions) {
31428 reg = this.layout.getRegion(r);
31429 if (reg.getActivePanel()) {
31430 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31431 reg.setActivePanel(reg.getActivePanel());
31434 if (!reg.panels.length) {
31437 reg.showPanel(reg.getPanel(0));
31446 * Returns the nested BorderLayout for this panel
31447 * @return {Roo.BorderLayout}
31449 getLayout : function(){
31450 return this.layout;
31454 * Adds a xtype elements to the layout of the nested panel
31458 xtype : 'ContentPanel',
31465 xtype : 'NestedLayoutPanel',
31471 items : [ ... list of content panels or nested layout panels.. ]
31475 * @param {Object} cfg Xtype definition of item to add.
31477 addxtype : function(cfg) {
31478 return this.layout.addxtype(cfg);
31483 Roo.ScrollPanel = function(el, config, content){
31484 config = config || {};
31485 config.fitToFrame = true;
31486 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31488 this.el.dom.style.overflow = "hidden";
31489 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31490 this.el.removeClass("x-layout-inactive-content");
31491 this.el.on("mousewheel", this.onWheel, this);
31493 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31494 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31495 up.unselectable(); down.unselectable();
31496 up.on("click", this.scrollUp, this);
31497 down.on("click", this.scrollDown, this);
31498 up.addClassOnOver("x-scroller-btn-over");
31499 down.addClassOnOver("x-scroller-btn-over");
31500 up.addClassOnClick("x-scroller-btn-click");
31501 down.addClassOnClick("x-scroller-btn-click");
31502 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31504 this.resizeEl = this.el;
31505 this.el = wrap; this.up = up; this.down = down;
31508 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31510 wheelIncrement : 5,
31511 scrollUp : function(){
31512 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31515 scrollDown : function(){
31516 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31519 afterScroll : function(){
31520 var el = this.resizeEl;
31521 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31522 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31523 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31526 setSize : function(){
31527 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31528 this.afterScroll();
31531 onWheel : function(e){
31532 var d = e.getWheelDelta();
31533 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31534 this.afterScroll();
31538 setContent : function(content, loadScripts){
31539 this.resizeEl.update(content, loadScripts);
31553 * @class Roo.TreePanel
31554 * @extends Roo.ContentPanel
31556 * Create a new TreePanel. - defaults to fit/scoll contents.
31557 * @param {String/Object} config A string to set only the panel's title, or a config object
31558 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31560 Roo.TreePanel = function(config){
31561 var el = config.el;
31562 var tree = config.tree;
31563 delete config.tree;
31564 delete config.el; // hopefull!
31566 // wrapper for IE7 strict & safari scroll issue
31568 var treeEl = el.createChild();
31569 config.resizeEl = treeEl;
31573 Roo.TreePanel.superclass.constructor.call(this, el, config);
31576 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31577 //console.log(tree);
31578 this.on('activate', function()
31580 if (this.tree.rendered) {
31583 //console.log('render tree');
31584 this.tree.render();
31587 this.on('resize', function (cp, w, h) {
31588 this.tree.innerCt.setWidth(w);
31589 this.tree.innerCt.setHeight(h);
31590 this.tree.innerCt.setStyle('overflow-y', 'auto');
31597 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31614 * Ext JS Library 1.1.1
31615 * Copyright(c) 2006-2007, Ext JS, LLC.
31617 * Originally Released Under LGPL - original licence link has changed is not relivant.
31620 * <script type="text/javascript">
31625 * @class Roo.ReaderLayout
31626 * @extends Roo.BorderLayout
31627 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31628 * center region containing two nested regions (a top one for a list view and one for item preview below),
31629 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31630 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31631 * expedites the setup of the overall layout and regions for this common application style.
31634 var reader = new Roo.ReaderLayout();
31635 var CP = Roo.ContentPanel; // shortcut for adding
31637 reader.beginUpdate();
31638 reader.add("north", new CP("north", "North"));
31639 reader.add("west", new CP("west", {title: "West"}));
31640 reader.add("east", new CP("east", {title: "East"}));
31642 reader.regions.listView.add(new CP("listView", "List"));
31643 reader.regions.preview.add(new CP("preview", "Preview"));
31644 reader.endUpdate();
31647 * Create a new ReaderLayout
31648 * @param {Object} config Configuration options
31649 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31650 * document.body if omitted)
31652 Roo.ReaderLayout = function(config, renderTo){
31653 var c = config || {size:{}};
31654 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31655 north: c.north !== false ? Roo.apply({
31659 }, c.north) : false,
31660 west: c.west !== false ? Roo.apply({
31668 margins:{left:5,right:0,bottom:5,top:5},
31669 cmargins:{left:5,right:5,bottom:5,top:5}
31670 }, c.west) : false,
31671 east: c.east !== false ? Roo.apply({
31679 margins:{left:0,right:5,bottom:5,top:5},
31680 cmargins:{left:5,right:5,bottom:5,top:5}
31681 }, c.east) : false,
31682 center: Roo.apply({
31683 tabPosition: 'top',
31687 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31691 this.el.addClass('x-reader');
31693 this.beginUpdate();
31695 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31696 south: c.preview !== false ? Roo.apply({
31703 cmargins:{top:5,left:0, right:0, bottom:0}
31704 }, c.preview) : false,
31705 center: Roo.apply({
31711 this.add('center', new Roo.NestedLayoutPanel(inner,
31712 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31716 this.regions.preview = inner.getRegion('south');
31717 this.regions.listView = inner.getRegion('center');
31720 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31722 * Ext JS Library 1.1.1
31723 * Copyright(c) 2006-2007, Ext JS, LLC.
31725 * Originally Released Under LGPL - original licence link has changed is not relivant.
31728 * <script type="text/javascript">
31732 * @class Roo.grid.Grid
31733 * @extends Roo.util.Observable
31734 * This class represents the primary interface of a component based grid control.
31735 * <br><br>Usage:<pre><code>
31736 var grid = new Roo.grid.Grid("my-container-id", {
31739 selModel: mySelectionModel,
31740 autoSizeColumns: true,
31741 monitorWindowResize: false,
31742 trackMouseOver: true
31747 * <b>Common Problems:</b><br/>
31748 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
31749 * element will correct this<br/>
31750 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
31751 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
31752 * are unpredictable.<br/>
31753 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
31754 * grid to calculate dimensions/offsets.<br/>
31756 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
31757 * The container MUST have some type of size defined for the grid to fill. The container will be
31758 * automatically set to position relative if it isn't already.
31759 * @param {Object} config A config object that sets properties on this grid.
31761 Roo.grid.Grid = function(container, config){
31762 // initialize the container
31763 this.container = Roo.get(container);
31764 this.container.update("");
31765 this.container.setStyle("overflow", "hidden");
31766 this.container.addClass('x-grid-container');
31768 this.id = this.container.id;
31770 Roo.apply(this, config);
31771 // check and correct shorthanded configs
31773 this.dataSource = this.ds;
31777 this.colModel = this.cm;
31781 this.selModel = this.sm;
31785 if (this.selModel) {
31786 this.selModel = Roo.factory(this.selModel, Roo.grid);
31787 this.sm = this.selModel;
31788 this.sm.xmodule = this.xmodule || false;
31790 if (typeof(this.colModel.config) == 'undefined') {
31791 this.colModel = new Roo.grid.ColumnModel(this.colModel);
31792 this.cm = this.colModel;
31793 this.cm.xmodule = this.xmodule || false;
31795 if (this.dataSource) {
31796 this.dataSource= Roo.factory(this.dataSource, Roo.data);
31797 this.ds = this.dataSource;
31798 this.ds.xmodule = this.xmodule || false;
31805 this.container.setWidth(this.width);
31809 this.container.setHeight(this.height);
31816 * The raw click event for the entire grid.
31817 * @param {Roo.EventObject} e
31822 * The raw dblclick event for the entire grid.
31823 * @param {Roo.EventObject} e
31827 * @event contextmenu
31828 * The raw contextmenu event for the entire grid.
31829 * @param {Roo.EventObject} e
31831 "contextmenu" : true,
31834 * The raw mousedown event for the entire grid.
31835 * @param {Roo.EventObject} e
31837 "mousedown" : true,
31840 * The raw mouseup event for the entire grid.
31841 * @param {Roo.EventObject} e
31846 * The raw mouseover event for the entire grid.
31847 * @param {Roo.EventObject} e
31849 "mouseover" : true,
31852 * The raw mouseout event for the entire grid.
31853 * @param {Roo.EventObject} e
31858 * The raw keypress event for the entire grid.
31859 * @param {Roo.EventObject} e
31864 * The raw keydown event for the entire grid.
31865 * @param {Roo.EventObject} e
31873 * Fires when a cell is clicked
31874 * @param {Grid} this
31875 * @param {Number} rowIndex
31876 * @param {Number} columnIndex
31877 * @param {Roo.EventObject} e
31879 "cellclick" : true,
31881 * @event celldblclick
31882 * Fires when a cell is double clicked
31883 * @param {Grid} this
31884 * @param {Number} rowIndex
31885 * @param {Number} columnIndex
31886 * @param {Roo.EventObject} e
31888 "celldblclick" : true,
31891 * Fires when a row is clicked
31892 * @param {Grid} this
31893 * @param {Number} rowIndex
31894 * @param {Roo.EventObject} e
31898 * @event rowdblclick
31899 * Fires when a row is double clicked
31900 * @param {Grid} this
31901 * @param {Number} rowIndex
31902 * @param {Roo.EventObject} e
31904 "rowdblclick" : true,
31906 * @event headerclick
31907 * Fires when a header is clicked
31908 * @param {Grid} this
31909 * @param {Number} columnIndex
31910 * @param {Roo.EventObject} e
31912 "headerclick" : true,
31914 * @event headerdblclick
31915 * Fires when a header cell is double clicked
31916 * @param {Grid} this
31917 * @param {Number} columnIndex
31918 * @param {Roo.EventObject} e
31920 "headerdblclick" : true,
31922 * @event rowcontextmenu
31923 * Fires when a row is right clicked
31924 * @param {Grid} this
31925 * @param {Number} rowIndex
31926 * @param {Roo.EventObject} e
31928 "rowcontextmenu" : true,
31930 * @event cellcontextmenu
31931 * Fires when a cell is right clicked
31932 * @param {Grid} this
31933 * @param {Number} rowIndex
31934 * @param {Number} cellIndex
31935 * @param {Roo.EventObject} e
31937 "cellcontextmenu" : true,
31939 * @event headercontextmenu
31940 * Fires when a header is right clicked
31941 * @param {Grid} this
31942 * @param {Number} columnIndex
31943 * @param {Roo.EventObject} e
31945 "headercontextmenu" : true,
31947 * @event bodyscroll
31948 * Fires when the body element is scrolled
31949 * @param {Number} scrollLeft
31950 * @param {Number} scrollTop
31952 "bodyscroll" : true,
31954 * @event columnresize
31955 * Fires when the user resizes a column
31956 * @param {Number} columnIndex
31957 * @param {Number} newSize
31959 "columnresize" : true,
31961 * @event columnmove
31962 * Fires when the user moves a column
31963 * @param {Number} oldIndex
31964 * @param {Number} newIndex
31966 "columnmove" : true,
31969 * Fires when row(s) start being dragged
31970 * @param {Grid} this
31971 * @param {Roo.GridDD} dd The drag drop object
31972 * @param {event} e The raw browser event
31974 "startdrag" : true,
31977 * Fires when a drag operation is complete
31978 * @param {Grid} this
31979 * @param {Roo.GridDD} dd The drag drop object
31980 * @param {event} e The raw browser event
31985 * Fires when dragged row(s) are dropped on a valid DD target
31986 * @param {Grid} this
31987 * @param {Roo.GridDD} dd The drag drop object
31988 * @param {String} targetId The target drag drop object
31989 * @param {event} e The raw browser event
31994 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
31995 * @param {Grid} this
31996 * @param {Roo.GridDD} dd The drag drop object
31997 * @param {String} targetId The target drag drop object
31998 * @param {event} e The raw browser event
32003 * Fires when the dragged row(s) first cross another DD target while being dragged
32004 * @param {Grid} this
32005 * @param {Roo.GridDD} dd The drag drop object
32006 * @param {String} targetId The target drag drop object
32007 * @param {event} e The raw browser event
32009 "dragenter" : true,
32012 * Fires when the dragged row(s) leave another DD target while being dragged
32013 * @param {Grid} this
32014 * @param {Roo.GridDD} dd The drag drop object
32015 * @param {String} targetId The target drag drop object
32016 * @param {event} e The raw browser event
32021 * Fires when the grid is rendered
32022 * @param {Grid} grid
32027 Roo.grid.Grid.superclass.constructor.call(this);
32029 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32032 * @cfg {String} ddGroup - drag drop group.
32036 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32038 minColumnWidth : 25,
32041 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32042 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32043 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32045 autoSizeColumns : false,
32048 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32050 autoSizeHeaders : true,
32053 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32055 monitorWindowResize : true,
32058 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32059 * rows measured to get a columns size. Default is 0 (all rows).
32061 maxRowsToMeasure : 0,
32064 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32066 trackMouseOver : true,
32069 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32073 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32075 enableDragDrop : false,
32078 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32080 enableColumnMove : true,
32083 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32085 enableColumnHide : true,
32088 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32090 enableRowHeightSync : false,
32093 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32098 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32100 autoHeight : false,
32103 * @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.
32105 autoExpandColumn : false,
32108 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32111 autoExpandMin : 50,
32114 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32116 autoExpandMax : 1000,
32119 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32124 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32128 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
32135 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32136 * of a fixed width. Default is false.
32139 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32142 * Called once after all setup has been completed and the grid is ready to be rendered.
32143 * @return {Roo.grid.Grid} this
32145 render : function(){
32146 var c = this.container;
32147 // try to detect autoHeight/width mode
32148 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32149 this.autoHeight = true;
32151 var view = this.getView();
32154 c.on("click", this.onClick, this);
32155 c.on("dblclick", this.onDblClick, this);
32156 c.on("contextmenu", this.onContextMenu, this);
32157 c.on("keydown", this.onKeyDown, this);
32159 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32161 this.getSelectionModel().init(this);
32166 this.loadMask = new Roo.LoadMask(this.container,
32167 Roo.apply({store:this.dataSource}, this.loadMask));
32171 if (this.toolbar && this.toolbar.xtype) {
32172 this.toolbar.container = this.getView().getHeaderPanel(true);
32173 this.toolbar = new Ext.Toolbar(this.toolbar);
32175 if (this.footer && this.footer.xtype) {
32176 this.footer.dataSource = this.getDataSource();
32177 this.footer.container = this.getView().getFooterPanel(true);
32178 this.footer = Roo.factory(this.footer, Roo);
32180 if (this.dropTarget && this.dropTarget.xtype) {
32181 delete this.dropTarget.xtype;
32182 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
32186 this.rendered = true;
32187 this.fireEvent('render', this);
32192 * Reconfigures the grid to use a different Store and Column Model.
32193 * The View will be bound to the new objects and refreshed.
32194 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32195 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32197 reconfigure : function(dataSource, colModel){
32199 this.loadMask.destroy();
32200 this.loadMask = new Roo.LoadMask(this.container,
32201 Roo.apply({store:dataSource}, this.loadMask));
32203 this.view.bind(dataSource, colModel);
32204 this.dataSource = dataSource;
32205 this.colModel = colModel;
32206 this.view.refresh(true);
32210 onKeyDown : function(e){
32211 this.fireEvent("keydown", e);
32215 * Destroy this grid.
32216 * @param {Boolean} removeEl True to remove the element
32218 destroy : function(removeEl, keepListeners){
32220 this.loadMask.destroy();
32222 var c = this.container;
32223 c.removeAllListeners();
32224 this.view.destroy();
32225 this.colModel.purgeListeners();
32226 if(!keepListeners){
32227 this.purgeListeners();
32230 if(removeEl === true){
32236 processEvent : function(name, e){
32237 this.fireEvent(name, e);
32238 var t = e.getTarget();
32240 var header = v.findHeaderIndex(t);
32241 if(header !== false){
32242 this.fireEvent("header" + name, this, header, e);
32244 var row = v.findRowIndex(t);
32245 var cell = v.findCellIndex(t);
32247 this.fireEvent("row" + name, this, row, e);
32248 if(cell !== false){
32249 this.fireEvent("cell" + name, this, row, cell, e);
32256 onClick : function(e){
32257 this.processEvent("click", e);
32261 onContextMenu : function(e, t){
32262 this.processEvent("contextmenu", e);
32266 onDblClick : function(e){
32267 this.processEvent("dblclick", e);
32271 walkCells : function(row, col, step, fn, scope){
32272 var cm = this.colModel, clen = cm.getColumnCount();
32273 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32285 if(fn.call(scope || this, row, col, cm) === true){
32303 if(fn.call(scope || this, row, col, cm) === true){
32315 getSelections : function(){
32316 return this.selModel.getSelections();
32320 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32321 * but if manual update is required this method will initiate it.
32323 autoSize : function(){
32325 this.view.layout();
32326 if(this.view.adjustForScroll){
32327 this.view.adjustForScroll();
32333 * Returns the grid's underlying element.
32334 * @return {Element} The element
32336 getGridEl : function(){
32337 return this.container;
32340 // private for compatibility, overridden by editor grid
32341 stopEditing : function(){},
32344 * Returns the grid's SelectionModel.
32345 * @return {SelectionModel}
32347 getSelectionModel : function(){
32348 if(!this.selModel){
32349 this.selModel = new Roo.grid.RowSelectionModel();
32351 return this.selModel;
32355 * Returns the grid's DataSource.
32356 * @return {DataSource}
32358 getDataSource : function(){
32359 return this.dataSource;
32363 * Returns the grid's ColumnModel.
32364 * @return {ColumnModel}
32366 getColumnModel : function(){
32367 return this.colModel;
32371 * Returns the grid's GridView object.
32372 * @return {GridView}
32374 getView : function(){
32376 this.view = new Roo.grid.GridView(this.viewConfig);
32381 * Called to get grid's drag proxy text, by default returns this.ddText.
32384 getDragDropText : function(){
32385 var count = this.selModel.getCount();
32386 return String.format(this.ddText, count, count == 1 ? '' : 's');
32390 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32391 * %0 is replaced with the number of selected rows.
32394 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32396 * Ext JS Library 1.1.1
32397 * Copyright(c) 2006-2007, Ext JS, LLC.
32399 * Originally Released Under LGPL - original licence link has changed is not relivant.
32402 * <script type="text/javascript">
32405 Roo.grid.AbstractGridView = function(){
32409 "beforerowremoved" : true,
32410 "beforerowsinserted" : true,
32411 "beforerefresh" : true,
32412 "rowremoved" : true,
32413 "rowsinserted" : true,
32414 "rowupdated" : true,
32417 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32420 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32421 rowClass : "x-grid-row",
32422 cellClass : "x-grid-cell",
32423 tdClass : "x-grid-td",
32424 hdClass : "x-grid-hd",
32425 splitClass : "x-grid-hd-split",
32427 init: function(grid){
32429 var cid = this.grid.getGridEl().id;
32430 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32431 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32432 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32433 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32436 getColumnRenderers : function(){
32437 var renderers = [];
32438 var cm = this.grid.colModel;
32439 var colCount = cm.getColumnCount();
32440 for(var i = 0; i < colCount; i++){
32441 renderers[i] = cm.getRenderer(i);
32446 getColumnIds : function(){
32448 var cm = this.grid.colModel;
32449 var colCount = cm.getColumnCount();
32450 for(var i = 0; i < colCount; i++){
32451 ids[i] = cm.getColumnId(i);
32456 getDataIndexes : function(){
32457 if(!this.indexMap){
32458 this.indexMap = this.buildIndexMap();
32460 return this.indexMap.colToData;
32463 getColumnIndexByDataIndex : function(dataIndex){
32464 if(!this.indexMap){
32465 this.indexMap = this.buildIndexMap();
32467 return this.indexMap.dataToCol[dataIndex];
32471 * Set a css style for a column dynamically.
32472 * @param {Number} colIndex The index of the column
32473 * @param {String} name The css property name
32474 * @param {String} value The css value
32476 setCSSStyle : function(colIndex, name, value){
32477 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32478 Roo.util.CSS.updateRule(selector, name, value);
32481 generateRules : function(cm){
32482 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32483 Roo.util.CSS.removeStyleSheet(rulesId);
32484 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32485 var cid = cm.getColumnId(i);
32486 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32487 this.tdSelector, cid, " {\n}\n",
32488 this.hdSelector, cid, " {\n}\n",
32489 this.splitSelector, cid, " {\n}\n");
32491 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32495 * Ext JS Library 1.1.1
32496 * Copyright(c) 2006-2007, Ext JS, LLC.
32498 * Originally Released Under LGPL - original licence link has changed is not relivant.
32501 * <script type="text/javascript">
32505 // This is a support class used internally by the Grid components
32506 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32508 this.view = grid.getView();
32509 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32510 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32512 this.setHandleElId(Roo.id(hd));
32513 this.setOuterHandleElId(Roo.id(hd2));
32515 this.scroll = false;
32517 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32519 getDragData : function(e){
32520 var t = Roo.lib.Event.getTarget(e);
32521 var h = this.view.findHeaderCell(t);
32523 return {ddel: h.firstChild, header:h};
32528 onInitDrag : function(e){
32529 this.view.headersDisabled = true;
32530 var clone = this.dragData.ddel.cloneNode(true);
32531 clone.id = Roo.id();
32532 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32533 this.proxy.update(clone);
32537 afterValidDrop : function(){
32539 setTimeout(function(){
32540 v.headersDisabled = false;
32544 afterInvalidDrop : function(){
32546 setTimeout(function(){
32547 v.headersDisabled = false;
32553 * Ext JS Library 1.1.1
32554 * Copyright(c) 2006-2007, Ext JS, LLC.
32556 * Originally Released Under LGPL - original licence link has changed is not relivant.
32559 * <script type="text/javascript">
32562 // This is a support class used internally by the Grid components
32563 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32565 this.view = grid.getView();
32566 // split the proxies so they don't interfere with mouse events
32567 this.proxyTop = Roo.DomHelper.append(document.body, {
32568 cls:"col-move-top", html:" "
32570 this.proxyBottom = Roo.DomHelper.append(document.body, {
32571 cls:"col-move-bottom", html:" "
32573 this.proxyTop.hide = this.proxyBottom.hide = function(){
32574 this.setLeftTop(-100,-100);
32575 this.setStyle("visibility", "hidden");
32577 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32578 // temporarily disabled
32579 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32580 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32582 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32583 proxyOffsets : [-4, -9],
32584 fly: Roo.Element.fly,
32586 getTargetFromEvent : function(e){
32587 var t = Roo.lib.Event.getTarget(e);
32588 var cindex = this.view.findCellIndex(t);
32589 if(cindex !== false){
32590 return this.view.getHeaderCell(cindex);
32594 nextVisible : function(h){
32595 var v = this.view, cm = this.grid.colModel;
32598 if(!cm.isHidden(v.getCellIndex(h))){
32606 prevVisible : function(h){
32607 var v = this.view, cm = this.grid.colModel;
32610 if(!cm.isHidden(v.getCellIndex(h))){
32618 positionIndicator : function(h, n, e){
32619 var x = Roo.lib.Event.getPageX(e);
32620 var r = Roo.lib.Dom.getRegion(n.firstChild);
32621 var px, pt, py = r.top + this.proxyOffsets[1];
32622 if((r.right - x) <= (r.right-r.left)/2){
32623 px = r.right+this.view.borderWidth;
32629 var oldIndex = this.view.getCellIndex(h);
32630 var newIndex = this.view.getCellIndex(n);
32632 if(this.grid.colModel.isFixed(newIndex)){
32636 var locked = this.grid.colModel.isLocked(newIndex);
32641 if(oldIndex < newIndex){
32644 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32647 px += this.proxyOffsets[0];
32648 this.proxyTop.setLeftTop(px, py);
32649 this.proxyTop.show();
32650 if(!this.bottomOffset){
32651 this.bottomOffset = this.view.mainHd.getHeight();
32653 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32654 this.proxyBottom.show();
32658 onNodeEnter : function(n, dd, e, data){
32659 if(data.header != n){
32660 this.positionIndicator(data.header, n, e);
32664 onNodeOver : function(n, dd, e, data){
32665 var result = false;
32666 if(data.header != n){
32667 result = this.positionIndicator(data.header, n, e);
32670 this.proxyTop.hide();
32671 this.proxyBottom.hide();
32673 return result ? this.dropAllowed : this.dropNotAllowed;
32676 onNodeOut : function(n, dd, e, data){
32677 this.proxyTop.hide();
32678 this.proxyBottom.hide();
32681 onNodeDrop : function(n, dd, e, data){
32682 var h = data.header;
32684 var cm = this.grid.colModel;
32685 var x = Roo.lib.Event.getPageX(e);
32686 var r = Roo.lib.Dom.getRegion(n.firstChild);
32687 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32688 var oldIndex = this.view.getCellIndex(h);
32689 var newIndex = this.view.getCellIndex(n);
32690 var locked = cm.isLocked(newIndex);
32694 if(oldIndex < newIndex){
32697 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32700 cm.setLocked(oldIndex, locked, true);
32701 cm.moveColumn(oldIndex, newIndex);
32702 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32710 * Ext JS Library 1.1.1
32711 * Copyright(c) 2006-2007, Ext JS, LLC.
32713 * Originally Released Under LGPL - original licence link has changed is not relivant.
32716 * <script type="text/javascript">
32720 * @class Roo.grid.GridView
32721 * @extends Roo.util.Observable
32724 * @param {Object} config
32726 Roo.grid.GridView = function(config){
32727 Roo.grid.GridView.superclass.constructor.call(this);
32730 Roo.apply(this, config);
32733 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
32736 * Override this function to apply custom css classes to rows during rendering
32737 * @param {Record} record The record
32738 * @param {Number} index
32739 * @method getRowClass
32741 rowClass : "x-grid-row",
32743 cellClass : "x-grid-col",
32745 tdClass : "x-grid-td",
32747 hdClass : "x-grid-hd",
32749 splitClass : "x-grid-split",
32751 sortClasses : ["sort-asc", "sort-desc"],
32753 enableMoveAnim : false,
32757 dh : Roo.DomHelper,
32759 fly : Roo.Element.fly,
32761 css : Roo.util.CSS,
32767 scrollIncrement : 22,
32769 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
32771 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
32773 bind : function(ds, cm){
32775 this.ds.un("load", this.onLoad, this);
32776 this.ds.un("datachanged", this.onDataChange, this);
32777 this.ds.un("add", this.onAdd, this);
32778 this.ds.un("remove", this.onRemove, this);
32779 this.ds.un("update", this.onUpdate, this);
32780 this.ds.un("clear", this.onClear, this);
32783 ds.on("load", this.onLoad, this);
32784 ds.on("datachanged", this.onDataChange, this);
32785 ds.on("add", this.onAdd, this);
32786 ds.on("remove", this.onRemove, this);
32787 ds.on("update", this.onUpdate, this);
32788 ds.on("clear", this.onClear, this);
32793 this.cm.un("widthchange", this.onColWidthChange, this);
32794 this.cm.un("headerchange", this.onHeaderChange, this);
32795 this.cm.un("hiddenchange", this.onHiddenChange, this);
32796 this.cm.un("columnmoved", this.onColumnMove, this);
32797 this.cm.un("columnlockchange", this.onColumnLock, this);
32800 this.generateRules(cm);
32801 cm.on("widthchange", this.onColWidthChange, this);
32802 cm.on("headerchange", this.onHeaderChange, this);
32803 cm.on("hiddenchange", this.onHiddenChange, this);
32804 cm.on("columnmoved", this.onColumnMove, this);
32805 cm.on("columnlockchange", this.onColumnLock, this);
32810 init: function(grid){
32811 Roo.grid.GridView.superclass.init.call(this, grid);
32813 this.bind(grid.dataSource, grid.colModel);
32815 grid.on("headerclick", this.handleHeaderClick, this);
32817 if(grid.trackMouseOver){
32818 grid.on("mouseover", this.onRowOver, this);
32819 grid.on("mouseout", this.onRowOut, this);
32821 grid.cancelTextSelection = function(){};
32822 this.gridId = grid.id;
32824 var tpls = this.templates || {};
32827 tpls.master = new Roo.Template(
32828 '<div class="x-grid" hidefocus="true">',
32829 '<div class="x-grid-topbar"></div>',
32830 '<div class="x-grid-scroller"><div></div></div>',
32831 '<div class="x-grid-locked">',
32832 '<div class="x-grid-header">{lockedHeader}</div>',
32833 '<div class="x-grid-body">{lockedBody}</div>',
32835 '<div class="x-grid-viewport">',
32836 '<div class="x-grid-header">{header}</div>',
32837 '<div class="x-grid-body">{body}</div>',
32839 '<div class="x-grid-bottombar"></div>',
32840 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
32841 '<div class="x-grid-resize-proxy"> </div>',
32844 tpls.master.disableformats = true;
32848 tpls.header = new Roo.Template(
32849 '<table border="0" cellspacing="0" cellpadding="0">',
32850 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
32853 tpls.header.disableformats = true;
32855 tpls.header.compile();
32858 tpls.hcell = new Roo.Template(
32859 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
32860 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
32863 tpls.hcell.disableFormats = true;
32865 tpls.hcell.compile();
32868 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
32869 tpls.hsplit.disableFormats = true;
32871 tpls.hsplit.compile();
32874 tpls.body = new Roo.Template(
32875 '<table border="0" cellspacing="0" cellpadding="0">',
32876 "<tbody>{rows}</tbody>",
32879 tpls.body.disableFormats = true;
32881 tpls.body.compile();
32884 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
32885 tpls.row.disableFormats = true;
32887 tpls.row.compile();
32890 tpls.cell = new Roo.Template(
32891 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
32892 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
32895 tpls.cell.disableFormats = true;
32897 tpls.cell.compile();
32899 this.templates = tpls;
32902 // remap these for backwards compat
32903 onColWidthChange : function(){
32904 this.updateColumns.apply(this, arguments);
32906 onHeaderChange : function(){
32907 this.updateHeaders.apply(this, arguments);
32909 onHiddenChange : function(){
32910 this.handleHiddenChange.apply(this, arguments);
32912 onColumnMove : function(){
32913 this.handleColumnMove.apply(this, arguments);
32915 onColumnLock : function(){
32916 this.handleLockChange.apply(this, arguments);
32919 onDataChange : function(){
32921 this.updateHeaderSortState();
32924 onClear : function(){
32928 onUpdate : function(ds, record){
32929 this.refreshRow(record);
32932 refreshRow : function(record){
32933 var ds = this.ds, index;
32934 if(typeof record == 'number'){
32936 record = ds.getAt(index);
32938 index = ds.indexOf(record);
32940 this.insertRows(ds, index, index, true);
32941 this.onRemove(ds, record, index+1, true);
32942 this.syncRowHeights(index, index);
32944 this.fireEvent("rowupdated", this, index, record);
32947 onAdd : function(ds, records, index){
32948 this.insertRows(ds, index, index + (records.length-1));
32951 onRemove : function(ds, record, index, isUpdate){
32952 if(isUpdate !== true){
32953 this.fireEvent("beforerowremoved", this, index, record);
32955 var bt = this.getBodyTable(), lt = this.getLockedTable();
32956 if(bt.rows[index]){
32957 bt.firstChild.removeChild(bt.rows[index]);
32959 if(lt.rows[index]){
32960 lt.firstChild.removeChild(lt.rows[index]);
32962 if(isUpdate !== true){
32963 this.stripeRows(index);
32964 this.syncRowHeights(index, index);
32966 this.fireEvent("rowremoved", this, index, record);
32970 onLoad : function(){
32971 this.scrollToTop();
32975 * Scrolls the grid to the top
32977 scrollToTop : function(){
32979 this.scroller.dom.scrollTop = 0;
32985 * Gets a panel in the header of the grid that can be used for toolbars etc.
32986 * After modifying the contents of this panel a call to grid.autoSize() may be
32987 * required to register any changes in size.
32988 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
32989 * @return Roo.Element
32991 getHeaderPanel : function(doShow){
32993 this.headerPanel.show();
32995 return this.headerPanel;
32999 * Gets a panel in the footer of the grid that can be used for toolbars etc.
33000 * After modifying the contents of this panel a call to grid.autoSize() may be
33001 * required to register any changes in size.
33002 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
33003 * @return Roo.Element
33005 getFooterPanel : function(doShow){
33007 this.footerPanel.show();
33009 return this.footerPanel;
33012 initElements : function(){
33013 var E = Roo.Element;
33014 var el = this.grid.getGridEl().dom.firstChild;
33015 var cs = el.childNodes;
33017 this.el = new E(el);
33018 this.headerPanel = new E(el.firstChild);
33019 this.headerPanel.enableDisplayMode("block");
33021 this.scroller = new E(cs[1]);
33022 this.scrollSizer = new E(this.scroller.dom.firstChild);
33024 this.lockedWrap = new E(cs[2]);
33025 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33026 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33028 this.mainWrap = new E(cs[3]);
33029 this.mainHd = new E(this.mainWrap.dom.firstChild);
33030 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33032 this.footerPanel = new E(cs[4]);
33033 this.footerPanel.enableDisplayMode("block");
33035 this.focusEl = new E(cs[5]);
33036 this.focusEl.swallowEvent("click", true);
33037 this.resizeProxy = new E(cs[6]);
33039 this.headerSelector = String.format(
33040 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33041 this.lockedHd.id, this.mainHd.id
33044 this.splitterSelector = String.format(
33045 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33046 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33049 idToCssName : function(s)
33051 return s.replace(/[^a-z0-9]+/ig, '-');
33054 getHeaderCell : function(index){
33055 return Roo.DomQuery.select(this.headerSelector)[index];
33058 getHeaderCellMeasure : function(index){
33059 return this.getHeaderCell(index).firstChild;
33062 getHeaderCellText : function(index){
33063 return this.getHeaderCell(index).firstChild.firstChild;
33066 getLockedTable : function(){
33067 return this.lockedBody.dom.firstChild;
33070 getBodyTable : function(){
33071 return this.mainBody.dom.firstChild;
33074 getLockedRow : function(index){
33075 return this.getLockedTable().rows[index];
33078 getRow : function(index){
33079 return this.getBodyTable().rows[index];
33082 getRowComposite : function(index){
33084 this.rowEl = new Roo.CompositeElementLite();
33086 var els = [], lrow, mrow;
33087 if(lrow = this.getLockedRow(index)){
33090 if(mrow = this.getRow(index)){
33093 this.rowEl.elements = els;
33097 getCell : function(rowIndex, colIndex){
33098 var locked = this.cm.getLockedCount();
33100 if(colIndex < locked){
33101 source = this.lockedBody.dom.firstChild;
33103 source = this.mainBody.dom.firstChild;
33104 colIndex -= locked;
33106 return source.rows[rowIndex].childNodes[colIndex];
33109 getCellText : function(rowIndex, colIndex){
33110 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33113 getCellBox : function(cell){
33114 var b = this.fly(cell).getBox();
33115 if(Roo.isOpera){ // opera fails to report the Y
33116 b.y = cell.offsetTop + this.mainBody.getY();
33121 getCellIndex : function(cell){
33122 var id = String(cell.className).match(this.cellRE);
33124 return parseInt(id[1], 10);
33129 findHeaderIndex : function(n){
33130 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33131 return r ? this.getCellIndex(r) : false;
33134 findHeaderCell : function(n){
33135 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33136 return r ? r : false;
33139 findRowIndex : function(n){
33143 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33144 return r ? r.rowIndex : false;
33147 findCellIndex : function(node){
33148 var stop = this.el.dom;
33149 while(node && node != stop){
33150 if(this.findRE.test(node.className)){
33151 return this.getCellIndex(node);
33153 node = node.parentNode;
33158 getColumnId : function(index){
33159 return this.cm.getColumnId(index);
33162 getSplitters : function(){
33163 if(this.splitterSelector){
33164 return Roo.DomQuery.select(this.splitterSelector);
33170 getSplitter : function(index){
33171 return this.getSplitters()[index];
33174 onRowOver : function(e, t){
33176 if((row = this.findRowIndex(t)) !== false){
33177 this.getRowComposite(row).addClass("x-grid-row-over");
33181 onRowOut : function(e, t){
33183 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33184 this.getRowComposite(row).removeClass("x-grid-row-over");
33188 renderHeaders : function(){
33190 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33191 var cb = [], lb = [], sb = [], lsb = [], p = {};
33192 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33193 p.cellId = "x-grid-hd-0-" + i;
33194 p.splitId = "x-grid-csplit-0-" + i;
33195 p.id = cm.getColumnId(i);
33196 p.title = cm.getColumnTooltip(i) || "";
33197 p.value = cm.getColumnHeader(i) || "";
33198 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33199 if(!cm.isLocked(i)){
33200 cb[cb.length] = ct.apply(p);
33201 sb[sb.length] = st.apply(p);
33203 lb[lb.length] = ct.apply(p);
33204 lsb[lsb.length] = st.apply(p);
33207 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33208 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33211 updateHeaders : function(){
33212 var html = this.renderHeaders();
33213 this.lockedHd.update(html[0]);
33214 this.mainHd.update(html[1]);
33218 * Focuses the specified row.
33219 * @param {Number} row The row index
33221 focusRow : function(row){
33222 var x = this.scroller.dom.scrollLeft;
33223 this.focusCell(row, 0, false);
33224 this.scroller.dom.scrollLeft = x;
33228 * Focuses the specified cell.
33229 * @param {Number} row The row index
33230 * @param {Number} col The column index
33231 * @param {Boolean} hscroll false to disable horizontal scrolling
33233 focusCell : function(row, col, hscroll){
33234 var el = this.ensureVisible(row, col, hscroll);
33235 this.focusEl.alignTo(el, "tl-tl");
33237 this.focusEl.focus();
33239 this.focusEl.focus.defer(1, this.focusEl);
33244 * Scrolls the specified cell into view
33245 * @param {Number} row The row index
33246 * @param {Number} col The column index
33247 * @param {Boolean} hscroll false to disable horizontal scrolling
33249 ensureVisible : function(row, col, hscroll){
33250 if(typeof row != "number"){
33251 row = row.rowIndex;
33253 if(row < 0 && row >= this.ds.getCount()){
33256 col = (col !== undefined ? col : 0);
33257 var cm = this.grid.colModel;
33258 while(cm.isHidden(col)){
33262 var el = this.getCell(row, col);
33266 var c = this.scroller.dom;
33268 var ctop = parseInt(el.offsetTop, 10);
33269 var cleft = parseInt(el.offsetLeft, 10);
33270 var cbot = ctop + el.offsetHeight;
33271 var cright = cleft + el.offsetWidth;
33273 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33274 var stop = parseInt(c.scrollTop, 10);
33275 var sleft = parseInt(c.scrollLeft, 10);
33276 var sbot = stop + ch;
33277 var sright = sleft + c.clientWidth;
33280 c.scrollTop = ctop;
33281 }else if(cbot > sbot){
33282 c.scrollTop = cbot-ch;
33285 if(hscroll !== false){
33287 c.scrollLeft = cleft;
33288 }else if(cright > sright){
33289 c.scrollLeft = cright-c.clientWidth;
33295 updateColumns : function(){
33296 this.grid.stopEditing();
33297 var cm = this.grid.colModel, colIds = this.getColumnIds();
33298 //var totalWidth = cm.getTotalWidth();
33300 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33301 //if(cm.isHidden(i)) continue;
33302 var w = cm.getColumnWidth(i);
33303 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33304 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33306 this.updateSplitters();
33309 generateRules : function(cm){
33310 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33311 Roo.util.CSS.removeStyleSheet(rulesId);
33312 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33313 var cid = cm.getColumnId(i);
33315 if(cm.config[i].align){
33316 align = 'text-align:'+cm.config[i].align+';';
33319 if(cm.isHidden(i)){
33320 hidden = 'display:none;';
33322 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33324 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33325 this.hdSelector, cid, " {\n", align, width, "}\n",
33326 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33327 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33329 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33332 updateSplitters : function(){
33333 var cm = this.cm, s = this.getSplitters();
33334 if(s){ // splitters not created yet
33335 var pos = 0, locked = true;
33336 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33337 if(cm.isHidden(i)) continue;
33338 var w = cm.getColumnWidth(i);
33339 if(!cm.isLocked(i) && locked){
33344 s[i].style.left = (pos-this.splitOffset) + "px";
33349 handleHiddenChange : function(colModel, colIndex, hidden){
33351 this.hideColumn(colIndex);
33353 this.unhideColumn(colIndex);
33357 hideColumn : function(colIndex){
33358 var cid = this.getColumnId(colIndex);
33359 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33360 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33362 this.updateHeaders();
33364 this.updateSplitters();
33368 unhideColumn : function(colIndex){
33369 var cid = this.getColumnId(colIndex);
33370 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33371 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33374 this.updateHeaders();
33376 this.updateSplitters();
33380 insertRows : function(dm, firstRow, lastRow, isUpdate){
33381 if(firstRow == 0 && lastRow == dm.getCount()-1){
33385 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33387 var s = this.getScrollState();
33388 var markup = this.renderRows(firstRow, lastRow);
33389 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33390 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33391 this.restoreScroll(s);
33393 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33394 this.syncRowHeights(firstRow, lastRow);
33395 this.stripeRows(firstRow);
33401 bufferRows : function(markup, target, index){
33402 var before = null, trows = target.rows, tbody = target.tBodies[0];
33403 if(index < trows.length){
33404 before = trows[index];
33406 var b = document.createElement("div");
33407 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33408 var rows = b.firstChild.rows;
33409 for(var i = 0, len = rows.length; i < len; i++){
33411 tbody.insertBefore(rows[0], before);
33413 tbody.appendChild(rows[0]);
33420 deleteRows : function(dm, firstRow, lastRow){
33421 if(dm.getRowCount()<1){
33422 this.fireEvent("beforerefresh", this);
33423 this.mainBody.update("");
33424 this.lockedBody.update("");
33425 this.fireEvent("refresh", this);
33427 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33428 var bt = this.getBodyTable();
33429 var tbody = bt.firstChild;
33430 var rows = bt.rows;
33431 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33432 tbody.removeChild(rows[firstRow]);
33434 this.stripeRows(firstRow);
33435 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33439 updateRows : function(dataSource, firstRow, lastRow){
33440 var s = this.getScrollState();
33442 this.restoreScroll(s);
33445 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33449 this.updateHeaderSortState();
33452 getScrollState : function(){
33453 var sb = this.scroller.dom;
33454 return {left: sb.scrollLeft, top: sb.scrollTop};
33457 stripeRows : function(startRow){
33458 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33461 startRow = startRow || 0;
33462 var rows = this.getBodyTable().rows;
33463 var lrows = this.getLockedTable().rows;
33464 var cls = ' x-grid-row-alt ';
33465 for(var i = startRow, len = rows.length; i < len; i++){
33466 var row = rows[i], lrow = lrows[i];
33467 var isAlt = ((i+1) % 2 == 0);
33468 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33469 if(isAlt == hasAlt){
33473 row.className += " x-grid-row-alt";
33475 row.className = row.className.replace("x-grid-row-alt", "");
33478 lrow.className = row.className;
33483 restoreScroll : function(state){
33484 var sb = this.scroller.dom;
33485 sb.scrollLeft = state.left;
33486 sb.scrollTop = state.top;
33490 syncScroll : function(){
33491 var sb = this.scroller.dom;
33492 var sh = this.mainHd.dom;
33493 var bs = this.mainBody.dom;
33494 var lv = this.lockedBody.dom;
33495 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33496 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33499 handleScroll : function(e){
33501 var sb = this.scroller.dom;
33502 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33506 handleWheel : function(e){
33507 var d = e.getWheelDelta();
33508 this.scroller.dom.scrollTop -= d*22;
33509 // set this here to prevent jumpy scrolling on large tables
33510 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33514 renderRows : function(startRow, endRow){
33515 // pull in all the crap needed to render rows
33516 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33517 var colCount = cm.getColumnCount();
33519 if(ds.getCount() < 1){
33523 // build a map for all the columns
33525 for(var i = 0; i < colCount; i++){
33526 var name = cm.getDataIndex(i);
33528 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33529 renderer : cm.getRenderer(i),
33530 id : cm.getColumnId(i),
33531 locked : cm.isLocked(i)
33535 startRow = startRow || 0;
33536 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33538 // records to render
33539 var rs = ds.getRange(startRow, endRow);
33541 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33544 // As much as I hate to duplicate code, this was branched because FireFox really hates
33545 // [].join("") on strings. The performance difference was substantial enough to
33546 // branch this function
33547 doRender : Roo.isGecko ?
33548 function(cs, rs, ds, startRow, colCount, stripe){
33549 var ts = this.templates, ct = ts.cell, rt = ts.row;
33551 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33552 for(var j = 0, len = rs.length; j < len; j++){
33553 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33554 for(var i = 0; i < colCount; i++){
33556 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33558 p.css = p.attr = "";
33559 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33560 if(p.value == undefined || p.value === "") p.value = " ";
33561 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33562 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33564 var markup = ct.apply(p);
33572 if(stripe && ((rowIndex+1) % 2 == 0)){
33573 alt[0] = "x-grid-row-alt";
33576 alt[1] = " x-grid-dirty-row";
33579 if(this.getRowClass){
33580 alt[2] = this.getRowClass(r, rowIndex);
33582 rp.alt = alt.join(" ");
33583 lbuf+= rt.apply(rp);
33585 buf+= rt.apply(rp);
33587 return [lbuf, buf];
33589 function(cs, rs, ds, startRow, colCount, stripe){
33590 var ts = this.templates, ct = ts.cell, rt = ts.row;
33592 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33593 for(var j = 0, len = rs.length; j < len; j++){
33594 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33595 for(var i = 0; i < colCount; i++){
33597 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33599 p.css = p.attr = "";
33600 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33601 if(p.value == undefined || p.value === "") p.value = " ";
33602 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33603 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33605 var markup = ct.apply(p);
33607 cb[cb.length] = markup;
33609 lcb[lcb.length] = markup;
33613 if(stripe && ((rowIndex+1) % 2 == 0)){
33614 alt[0] = "x-grid-row-alt";
33617 alt[1] = " x-grid-dirty-row";
33620 if(this.getRowClass){
33621 alt[2] = this.getRowClass(r, rowIndex);
33623 rp.alt = alt.join(" ");
33624 rp.cells = lcb.join("");
33625 lbuf[lbuf.length] = rt.apply(rp);
33626 rp.cells = cb.join("");
33627 buf[buf.length] = rt.apply(rp);
33629 return [lbuf.join(""), buf.join("")];
33632 renderBody : function(){
33633 var markup = this.renderRows();
33634 var bt = this.templates.body;
33635 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33639 * Refreshes the grid
33640 * @param {Boolean} headersToo
33642 refresh : function(headersToo){
33643 this.fireEvent("beforerefresh", this);
33644 this.grid.stopEditing();
33645 var result = this.renderBody();
33646 this.lockedBody.update(result[0]);
33647 this.mainBody.update(result[1]);
33648 if(headersToo === true){
33649 this.updateHeaders();
33650 this.updateColumns();
33651 this.updateSplitters();
33652 this.updateHeaderSortState();
33654 this.syncRowHeights();
33656 this.fireEvent("refresh", this);
33659 handleColumnMove : function(cm, oldIndex, newIndex){
33660 this.indexMap = null;
33661 var s = this.getScrollState();
33662 this.refresh(true);
33663 this.restoreScroll(s);
33664 this.afterMove(newIndex);
33667 afterMove : function(colIndex){
33668 if(this.enableMoveAnim && Roo.enableFx){
33669 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
33673 updateCell : function(dm, rowIndex, dataIndex){
33674 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
33675 if(typeof colIndex == "undefined"){ // not present in grid
33678 var cm = this.grid.colModel;
33679 var cell = this.getCell(rowIndex, colIndex);
33680 var cellText = this.getCellText(rowIndex, colIndex);
33683 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
33684 id : cm.getColumnId(colIndex),
33685 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
33687 var renderer = cm.getRenderer(colIndex);
33688 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
33689 if(typeof val == "undefined" || val === "") val = " ";
33690 cellText.innerHTML = val;
33691 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
33692 this.syncRowHeights(rowIndex, rowIndex);
33695 calcColumnWidth : function(colIndex, maxRowsToMeasure){
33697 if(this.grid.autoSizeHeaders){
33698 var h = this.getHeaderCellMeasure(colIndex);
33699 maxWidth = Math.max(maxWidth, h.scrollWidth);
33702 if(this.cm.isLocked(colIndex)){
33703 tb = this.getLockedTable();
33706 tb = this.getBodyTable();
33707 index = colIndex - this.cm.getLockedCount();
33710 var rows = tb.rows;
33711 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
33712 for(var i = 0; i < stopIndex; i++){
33713 var cell = rows[i].childNodes[index].firstChild;
33714 maxWidth = Math.max(maxWidth, cell.scrollWidth);
33717 return maxWidth + /*margin for error in IE*/ 5;
33720 * Autofit a column to its content.
33721 * @param {Number} colIndex
33722 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
33724 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
33725 if(this.cm.isHidden(colIndex)){
33726 return; // can't calc a hidden column
33729 var cid = this.cm.getColumnId(colIndex);
33730 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
33731 if(this.grid.autoSizeHeaders){
33732 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
33735 var newWidth = this.calcColumnWidth(colIndex);
33736 this.cm.setColumnWidth(colIndex,
33737 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
33738 if(!suppressEvent){
33739 this.grid.fireEvent("columnresize", colIndex, newWidth);
33744 * Autofits all columns to their content and then expands to fit any extra space in the grid
33746 autoSizeColumns : function(){
33747 var cm = this.grid.colModel;
33748 var colCount = cm.getColumnCount();
33749 for(var i = 0; i < colCount; i++){
33750 this.autoSizeColumn(i, true, true);
33752 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
33755 this.updateColumns();
33761 * Autofits all columns to the grid's width proportionate with their current size
33762 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
33764 fitColumns : function(reserveScrollSpace){
33765 var cm = this.grid.colModel;
33766 var colCount = cm.getColumnCount();
33770 for (i = 0; i < colCount; i++){
33771 if(!cm.isHidden(i) && !cm.isFixed(i)){
33772 w = cm.getColumnWidth(i);
33778 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
33779 if(reserveScrollSpace){
33782 var frac = (avail - cm.getTotalWidth())/width;
33783 while (cols.length){
33786 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
33788 this.updateColumns();
33792 onRowSelect : function(rowIndex){
33793 var row = this.getRowComposite(rowIndex);
33794 row.addClass("x-grid-row-selected");
33797 onRowDeselect : function(rowIndex){
33798 var row = this.getRowComposite(rowIndex);
33799 row.removeClass("x-grid-row-selected");
33802 onCellSelect : function(row, col){
33803 var cell = this.getCell(row, col);
33805 Roo.fly(cell).addClass("x-grid-cell-selected");
33809 onCellDeselect : function(row, col){
33810 var cell = this.getCell(row, col);
33812 Roo.fly(cell).removeClass("x-grid-cell-selected");
33816 updateHeaderSortState : function(){
33817 var state = this.ds.getSortState();
33821 this.sortState = state;
33822 var sortColumn = this.cm.findColumnIndex(state.field);
33823 if(sortColumn != -1){
33824 var sortDir = state.direction;
33825 var sc = this.sortClasses;
33826 var hds = this.el.select(this.headerSelector).removeClass(sc);
33827 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
33831 handleHeaderClick : function(g, index){
33832 if(this.headersDisabled){
33835 var dm = g.dataSource, cm = g.colModel;
33836 if(!cm.isSortable(index)){
33840 dm.sort(cm.getDataIndex(index));
33844 destroy : function(){
33846 this.colMenu.removeAll();
33847 Roo.menu.MenuMgr.unregister(this.colMenu);
33848 this.colMenu.getEl().remove();
33849 delete this.colMenu;
33852 this.hmenu.removeAll();
33853 Roo.menu.MenuMgr.unregister(this.hmenu);
33854 this.hmenu.getEl().remove();
33857 if(this.grid.enableColumnMove){
33858 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33860 for(var dd in dds){
33861 if(!dds[dd].config.isTarget && dds[dd].dragElId){
33862 var elid = dds[dd].dragElId;
33864 Roo.get(elid).remove();
33865 } else if(dds[dd].config.isTarget){
33866 dds[dd].proxyTop.remove();
33867 dds[dd].proxyBottom.remove();
33870 if(Roo.dd.DDM.locationCache[dd]){
33871 delete Roo.dd.DDM.locationCache[dd];
33874 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33877 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
33878 this.bind(null, null);
33879 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
33882 handleLockChange : function(){
33883 this.refresh(true);
33886 onDenyColumnLock : function(){
33890 onDenyColumnHide : function(){
33894 handleHdMenuClick : function(item){
33895 var index = this.hdCtxIndex;
33896 var cm = this.cm, ds = this.ds;
33899 ds.sort(cm.getDataIndex(index), "ASC");
33902 ds.sort(cm.getDataIndex(index), "DESC");
33905 var lc = cm.getLockedCount();
33906 if(cm.getColumnCount(true) <= lc+1){
33907 this.onDenyColumnLock();
33911 cm.setLocked(index, true, true);
33912 cm.moveColumn(index, lc);
33913 this.grid.fireEvent("columnmove", index, lc);
33915 cm.setLocked(index, true);
33919 var lc = cm.getLockedCount();
33920 if((lc-1) != index){
33921 cm.setLocked(index, false, true);
33922 cm.moveColumn(index, lc-1);
33923 this.grid.fireEvent("columnmove", index, lc-1);
33925 cm.setLocked(index, false);
33929 index = cm.getIndexById(item.id.substr(4));
33931 if(item.checked && cm.getColumnCount(true) <= 1){
33932 this.onDenyColumnHide();
33935 cm.setHidden(index, item.checked);
33941 beforeColMenuShow : function(){
33942 var cm = this.cm, colCount = cm.getColumnCount();
33943 this.colMenu.removeAll();
33944 for(var i = 0; i < colCount; i++){
33945 this.colMenu.add(new Roo.menu.CheckItem({
33946 id: "col-"+cm.getColumnId(i),
33947 text: cm.getColumnHeader(i),
33948 checked: !cm.isHidden(i),
33954 handleHdCtx : function(g, index, e){
33956 var hd = this.getHeaderCell(index);
33957 this.hdCtxIndex = index;
33958 var ms = this.hmenu.items, cm = this.cm;
33959 ms.get("asc").setDisabled(!cm.isSortable(index));
33960 ms.get("desc").setDisabled(!cm.isSortable(index));
33961 if(this.grid.enableColLock !== false){
33962 ms.get("lock").setDisabled(cm.isLocked(index));
33963 ms.get("unlock").setDisabled(!cm.isLocked(index));
33965 this.hmenu.show(hd, "tl-bl");
33968 handleHdOver : function(e){
33969 var hd = this.findHeaderCell(e.getTarget());
33970 if(hd && !this.headersDisabled){
33971 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
33972 this.fly(hd).addClass("x-grid-hd-over");
33977 handleHdOut : function(e){
33978 var hd = this.findHeaderCell(e.getTarget());
33980 this.fly(hd).removeClass("x-grid-hd-over");
33984 handleSplitDblClick : function(e, t){
33985 var i = this.getCellIndex(t);
33986 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
33987 this.autoSizeColumn(i, true);
33992 render : function(){
33995 var colCount = cm.getColumnCount();
33997 if(this.grid.monitorWindowResize === true){
33998 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
34000 var header = this.renderHeaders();
34001 var body = this.templates.body.apply({rows:""});
34002 var html = this.templates.master.apply({
34005 lockedHeader: header[0],
34009 //this.updateColumns();
34011 this.grid.getGridEl().dom.innerHTML = html;
34013 this.initElements();
34015 // a kludge to fix the random scolling effect in webkit
34016 this.el.on("scroll", function() {
34017 this.el.dom.scrollTop=0; // hopefully not recursive..
34020 this.scroller.on("scroll", this.handleScroll, this);
34021 this.lockedBody.on("mousewheel", this.handleWheel, this);
34022 this.mainBody.on("mousewheel", this.handleWheel, this);
34024 this.mainHd.on("mouseover", this.handleHdOver, this);
34025 this.mainHd.on("mouseout", this.handleHdOut, this);
34026 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34027 {delegate: "."+this.splitClass});
34029 this.lockedHd.on("mouseover", this.handleHdOver, this);
34030 this.lockedHd.on("mouseout", this.handleHdOut, this);
34031 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34032 {delegate: "."+this.splitClass});
34034 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34035 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34038 this.updateSplitters();
34040 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34041 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34042 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34045 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34046 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34048 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34049 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34051 if(this.grid.enableColLock !== false){
34052 this.hmenu.add('-',
34053 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34054 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34057 if(this.grid.enableColumnHide !== false){
34059 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34060 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34061 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34063 this.hmenu.add('-',
34064 {id:"columns", text: this.columnsText, menu: this.colMenu}
34067 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34069 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34072 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34073 this.dd = new Roo.grid.GridDragZone(this.grid, {
34074 ddGroup : this.grid.ddGroup || 'GridDD'
34079 for(var i = 0; i < colCount; i++){
34080 if(cm.isHidden(i)){
34081 this.hideColumn(i);
34083 if(cm.config[i].align){
34084 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34085 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34089 this.updateHeaderSortState();
34091 this.beforeInitialResize();
34094 // two part rendering gives faster view to the user
34095 this.renderPhase2.defer(1, this);
34098 renderPhase2 : function(){
34099 // render the rows now
34101 if(this.grid.autoSizeColumns){
34102 this.autoSizeColumns();
34106 beforeInitialResize : function(){
34110 onColumnSplitterMoved : function(i, w){
34111 this.userResized = true;
34112 var cm = this.grid.colModel;
34113 cm.setColumnWidth(i, w, true);
34114 var cid = cm.getColumnId(i);
34115 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34116 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34117 this.updateSplitters();
34119 this.grid.fireEvent("columnresize", i, w);
34122 syncRowHeights : function(startIndex, endIndex){
34123 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34124 startIndex = startIndex || 0;
34125 var mrows = this.getBodyTable().rows;
34126 var lrows = this.getLockedTable().rows;
34127 var len = mrows.length-1;
34128 endIndex = Math.min(endIndex || len, len);
34129 for(var i = startIndex; i <= endIndex; i++){
34130 var m = mrows[i], l = lrows[i];
34131 var h = Math.max(m.offsetHeight, l.offsetHeight);
34132 m.style.height = l.style.height = h + "px";
34137 layout : function(initialRender, is2ndPass){
34139 var auto = g.autoHeight;
34140 var scrollOffset = 16;
34141 var c = g.getGridEl(), cm = this.cm,
34142 expandCol = g.autoExpandColumn,
34144 //c.beginMeasure();
34146 if(!c.dom.offsetWidth){ // display:none?
34148 this.lockedWrap.show();
34149 this.mainWrap.show();
34154 var hasLock = this.cm.isLocked(0);
34156 var tbh = this.headerPanel.getHeight();
34157 var bbh = this.footerPanel.getHeight();
34160 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34161 var newHeight = ch + c.getBorderWidth("tb");
34163 newHeight = Math.min(g.maxHeight, newHeight);
34165 c.setHeight(newHeight);
34169 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34172 var s = this.scroller;
34174 var csize = c.getSize(true);
34176 this.el.setSize(csize.width, csize.height);
34178 this.headerPanel.setWidth(csize.width);
34179 this.footerPanel.setWidth(csize.width);
34181 var hdHeight = this.mainHd.getHeight();
34182 var vw = csize.width;
34183 var vh = csize.height - (tbh + bbh);
34187 var bt = this.getBodyTable();
34188 var ltWidth = hasLock ?
34189 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34191 var scrollHeight = bt.offsetHeight;
34192 var scrollWidth = ltWidth + bt.offsetWidth;
34193 var vscroll = false, hscroll = false;
34195 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34197 var lw = this.lockedWrap, mw = this.mainWrap;
34198 var lb = this.lockedBody, mb = this.mainBody;
34200 setTimeout(function(){
34201 var t = s.dom.offsetTop;
34202 var w = s.dom.clientWidth,
34203 h = s.dom.clientHeight;
34206 lw.setSize(ltWidth, h);
34208 mw.setLeftTop(ltWidth, t);
34209 mw.setSize(w-ltWidth, h);
34211 lb.setHeight(h-hdHeight);
34212 mb.setHeight(h-hdHeight);
34214 if(is2ndPass !== true && !gv.userResized && expandCol){
34215 // high speed resize without full column calculation
34217 var ci = cm.getIndexById(expandCol);
34219 ci = cm.findColumnIndex(expandCol);
34221 ci = Math.max(0, ci); // make sure it's got at least the first col.
34222 var expandId = cm.getColumnId(ci);
34223 var tw = cm.getTotalWidth(false);
34224 var currentWidth = cm.getColumnWidth(ci);
34225 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34226 if(currentWidth != cw){
34227 cm.setColumnWidth(ci, cw, true);
34228 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34229 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34230 gv.updateSplitters();
34231 gv.layout(false, true);
34243 onWindowResize : function(){
34244 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34250 appendFooter : function(parentEl){
34254 sortAscText : "Sort Ascending",
34255 sortDescText : "Sort Descending",
34256 lockText : "Lock Column",
34257 unlockText : "Unlock Column",
34258 columnsText : "Columns"
34262 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34263 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34264 this.proxy.el.addClass('x-grid3-col-dd');
34267 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34268 handleMouseDown : function(e){
34272 callHandleMouseDown : function(e){
34273 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34278 * Ext JS Library 1.1.1
34279 * Copyright(c) 2006-2007, Ext JS, LLC.
34281 * Originally Released Under LGPL - original licence link has changed is not relivant.
34284 * <script type="text/javascript">
34288 // This is a support class used internally by the Grid components
34289 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34291 this.view = grid.getView();
34292 this.proxy = this.view.resizeProxy;
34293 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34294 "gridSplitters" + this.grid.getGridEl().id, {
34295 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34297 this.setHandleElId(Roo.id(hd));
34298 this.setOuterHandleElId(Roo.id(hd2));
34299 this.scroll = false;
34301 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34302 fly: Roo.Element.fly,
34304 b4StartDrag : function(x, y){
34305 this.view.headersDisabled = true;
34306 this.proxy.setHeight(this.view.mainWrap.getHeight());
34307 var w = this.cm.getColumnWidth(this.cellIndex);
34308 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34309 this.resetConstraints();
34310 this.setXConstraint(minw, 1000);
34311 this.setYConstraint(0, 0);
34312 this.minX = x - minw;
34313 this.maxX = x + 1000;
34315 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34319 handleMouseDown : function(e){
34320 ev = Roo.EventObject.setEvent(e);
34321 var t = this.fly(ev.getTarget());
34322 if(t.hasClass("x-grid-split")){
34323 this.cellIndex = this.view.getCellIndex(t.dom);
34324 this.split = t.dom;
34325 this.cm = this.grid.colModel;
34326 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34327 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34332 endDrag : function(e){
34333 this.view.headersDisabled = false;
34334 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34335 var diff = endX - this.startPos;
34336 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34339 autoOffset : function(){
34340 this.setDelta(0,0);
34344 * Ext JS Library 1.1.1
34345 * Copyright(c) 2006-2007, Ext JS, LLC.
34347 * Originally Released Under LGPL - original licence link has changed is not relivant.
34350 * <script type="text/javascript">
34354 // This is a support class used internally by the Grid components
34355 Roo.grid.GridDragZone = function(grid, config){
34356 this.view = grid.getView();
34357 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34358 if(this.view.lockedBody){
34359 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34360 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34362 this.scroll = false;
34364 this.ddel = document.createElement('div');
34365 this.ddel.className = 'x-grid-dd-wrap';
34368 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34369 ddGroup : "GridDD",
34371 getDragData : function(e){
34372 var t = Roo.lib.Event.getTarget(e);
34373 var rowIndex = this.view.findRowIndex(t);
34374 if(rowIndex !== false){
34375 var sm = this.grid.selModel;
34376 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34377 // sm.mouseDown(e, t);
34379 if (e.hasModifier()){
34380 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34382 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34387 onInitDrag : function(e){
34388 var data = this.dragData;
34389 this.ddel.innerHTML = this.grid.getDragDropText();
34390 this.proxy.update(this.ddel);
34391 // fire start drag?
34394 afterRepair : function(){
34395 this.dragging = false;
34398 getRepairXY : function(e, data){
34402 onEndDrag : function(data, e){
34406 onValidDrop : function(dd, e, id){
34411 beforeInvalidDrop : function(e, id){
34416 * Ext JS Library 1.1.1
34417 * Copyright(c) 2006-2007, Ext JS, LLC.
34419 * Originally Released Under LGPL - original licence link has changed is not relivant.
34422 * <script type="text/javascript">
34427 * @class Roo.grid.ColumnModel
34428 * @extends Roo.util.Observable
34429 * This is the default implementation of a ColumnModel used by the Grid. It defines
34430 * the columns in the grid.
34433 var colModel = new Roo.grid.ColumnModel([
34434 {header: "Ticker", width: 60, sortable: true, locked: true},
34435 {header: "Company Name", width: 150, sortable: true},
34436 {header: "Market Cap.", width: 100, sortable: true},
34437 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34438 {header: "Employees", width: 100, sortable: true, resizable: false}
34443 * The config options listed for this class are options which may appear in each
34444 * individual column definition.
34445 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34447 * @param {Object} config An Array of column config objects. See this class's
34448 * config objects for details.
34450 Roo.grid.ColumnModel = function(config){
34452 * The config passed into the constructor
34454 this.config = config;
34457 // if no id, create one
34458 // if the column does not have a dataIndex mapping,
34459 // map it to the order it is in the config
34460 for(var i = 0, len = config.length; i < len; i++){
34462 if(typeof c.dataIndex == "undefined"){
34465 if(typeof c.renderer == "string"){
34466 c.renderer = Roo.util.Format[c.renderer];
34468 if(typeof c.id == "undefined"){
34471 if(c.editor && c.editor.xtype){
34472 c.editor = Roo.factory(c.editor, Roo.grid);
34474 if(c.editor && c.editor.isFormField){
34475 c.editor = new Roo.grid.GridEditor(c.editor);
34477 this.lookup[c.id] = c;
34481 * The width of columns which have no width specified (defaults to 100)
34484 this.defaultWidth = 100;
34487 * Default sortable of columns which have no sortable specified (defaults to false)
34490 this.defaultSortable = false;
34494 * @event widthchange
34495 * Fires when the width of a column changes.
34496 * @param {ColumnModel} this
34497 * @param {Number} columnIndex The column index
34498 * @param {Number} newWidth The new width
34500 "widthchange": true,
34502 * @event headerchange
34503 * Fires when the text of a header changes.
34504 * @param {ColumnModel} this
34505 * @param {Number} columnIndex The column index
34506 * @param {Number} newText The new header text
34508 "headerchange": true,
34510 * @event hiddenchange
34511 * Fires when a column is hidden or "unhidden".
34512 * @param {ColumnModel} this
34513 * @param {Number} columnIndex The column index
34514 * @param {Boolean} hidden true if hidden, false otherwise
34516 "hiddenchange": true,
34518 * @event columnmoved
34519 * Fires when a column is moved.
34520 * @param {ColumnModel} this
34521 * @param {Number} oldIndex
34522 * @param {Number} newIndex
34524 "columnmoved" : true,
34526 * @event columlockchange
34527 * Fires when a column's locked state is changed
34528 * @param {ColumnModel} this
34529 * @param {Number} colIndex
34530 * @param {Boolean} locked true if locked
34532 "columnlockchange" : true
34534 Roo.grid.ColumnModel.superclass.constructor.call(this);
34536 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34538 * @cfg {String} header The header text to display in the Grid view.
34541 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34542 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34543 * specified, the column's index is used as an index into the Record's data Array.
34546 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34547 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34550 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34551 * Defaults to the value of the {@link #defaultSortable} property.
34552 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34555 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34558 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34561 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34564 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34567 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34568 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34569 * default renderer uses the raw data value.
34572 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34575 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34579 * Returns the id of the column at the specified index.
34580 * @param {Number} index The column index
34581 * @return {String} the id
34583 getColumnId : function(index){
34584 return this.config[index].id;
34588 * Returns the column for a specified id.
34589 * @param {String} id The column id
34590 * @return {Object} the column
34592 getColumnById : function(id){
34593 return this.lookup[id];
34598 * Returns the column for a specified dataIndex.
34599 * @param {String} dataIndex The column dataIndex
34600 * @return {Object|Boolean} the column or false if not found
34602 getColumnByDataIndex: function(dataIndex){
34603 var index = this.findColumnIndex(dataIndex);
34604 return index > -1 ? this.config[index] : false;
34608 * Returns the index for a specified column id.
34609 * @param {String} id The column id
34610 * @return {Number} the index, or -1 if not found
34612 getIndexById : function(id){
34613 for(var i = 0, len = this.config.length; i < len; i++){
34614 if(this.config[i].id == id){
34622 * Returns the index for a specified column dataIndex.
34623 * @param {String} dataIndex The column dataIndex
34624 * @return {Number} the index, or -1 if not found
34627 findColumnIndex : function(dataIndex){
34628 for(var i = 0, len = this.config.length; i < len; i++){
34629 if(this.config[i].dataIndex == dataIndex){
34637 moveColumn : function(oldIndex, newIndex){
34638 var c = this.config[oldIndex];
34639 this.config.splice(oldIndex, 1);
34640 this.config.splice(newIndex, 0, c);
34641 this.dataMap = null;
34642 this.fireEvent("columnmoved", this, oldIndex, newIndex);
34645 isLocked : function(colIndex){
34646 return this.config[colIndex].locked === true;
34649 setLocked : function(colIndex, value, suppressEvent){
34650 if(this.isLocked(colIndex) == value){
34653 this.config[colIndex].locked = value;
34654 if(!suppressEvent){
34655 this.fireEvent("columnlockchange", this, colIndex, value);
34659 getTotalLockedWidth : function(){
34660 var totalWidth = 0;
34661 for(var i = 0; i < this.config.length; i++){
34662 if(this.isLocked(i) && !this.isHidden(i)){
34663 this.totalWidth += this.getColumnWidth(i);
34669 getLockedCount : function(){
34670 for(var i = 0, len = this.config.length; i < len; i++){
34671 if(!this.isLocked(i)){
34678 * Returns the number of columns.
34681 getColumnCount : function(visibleOnly){
34682 if(visibleOnly === true){
34684 for(var i = 0, len = this.config.length; i < len; i++){
34685 if(!this.isHidden(i)){
34691 return this.config.length;
34695 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
34696 * @param {Function} fn
34697 * @param {Object} scope (optional)
34698 * @return {Array} result
34700 getColumnsBy : function(fn, scope){
34702 for(var i = 0, len = this.config.length; i < len; i++){
34703 var c = this.config[i];
34704 if(fn.call(scope||this, c, i) === true){
34712 * Returns true if the specified column is sortable.
34713 * @param {Number} col The column index
34714 * @return {Boolean}
34716 isSortable : function(col){
34717 if(typeof this.config[col].sortable == "undefined"){
34718 return this.defaultSortable;
34720 return this.config[col].sortable;
34724 * Returns the rendering (formatting) function defined for the column.
34725 * @param {Number} col The column index.
34726 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
34728 getRenderer : function(col){
34729 if(!this.config[col].renderer){
34730 return Roo.grid.ColumnModel.defaultRenderer;
34732 return this.config[col].renderer;
34736 * Sets the rendering (formatting) function for a column.
34737 * @param {Number} col The column index
34738 * @param {Function} fn The function to use to process the cell's raw data
34739 * to return HTML markup for the grid view. The render function is called with
34740 * the following parameters:<ul>
34741 * <li>Data value.</li>
34742 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
34743 * <li>css A CSS style string to apply to the table cell.</li>
34744 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
34745 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
34746 * <li>Row index</li>
34747 * <li>Column index</li>
34748 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
34750 setRenderer : function(col, fn){
34751 this.config[col].renderer = fn;
34755 * Returns the width for the specified column.
34756 * @param {Number} col The column index
34759 getColumnWidth : function(col){
34760 return this.config[col].width || this.defaultWidth;
34764 * Sets the width for a column.
34765 * @param {Number} col The column index
34766 * @param {Number} width The new width
34768 setColumnWidth : function(col, width, suppressEvent){
34769 this.config[col].width = width;
34770 this.totalWidth = null;
34771 if(!suppressEvent){
34772 this.fireEvent("widthchange", this, col, width);
34777 * Returns the total width of all columns.
34778 * @param {Boolean} includeHidden True to include hidden column widths
34781 getTotalWidth : function(includeHidden){
34782 if(!this.totalWidth){
34783 this.totalWidth = 0;
34784 for(var i = 0, len = this.config.length; i < len; i++){
34785 if(includeHidden || !this.isHidden(i)){
34786 this.totalWidth += this.getColumnWidth(i);
34790 return this.totalWidth;
34794 * Returns the header for the specified column.
34795 * @param {Number} col The column index
34798 getColumnHeader : function(col){
34799 return this.config[col].header;
34803 * Sets the header for a column.
34804 * @param {Number} col The column index
34805 * @param {String} header The new header
34807 setColumnHeader : function(col, header){
34808 this.config[col].header = header;
34809 this.fireEvent("headerchange", this, col, header);
34813 * Returns the tooltip for the specified column.
34814 * @param {Number} col The column index
34817 getColumnTooltip : function(col){
34818 return this.config[col].tooltip;
34821 * Sets the tooltip for a column.
34822 * @param {Number} col The column index
34823 * @param {String} tooltip The new tooltip
34825 setColumnTooltip : function(col, tooltip){
34826 this.config[col].tooltip = tooltip;
34830 * Returns the dataIndex for the specified column.
34831 * @param {Number} col The column index
34834 getDataIndex : function(col){
34835 return this.config[col].dataIndex;
34839 * Sets the dataIndex for a column.
34840 * @param {Number} col The column index
34841 * @param {Number} dataIndex The new dataIndex
34843 setDataIndex : function(col, dataIndex){
34844 this.config[col].dataIndex = dataIndex;
34850 * Returns true if the cell is editable.
34851 * @param {Number} colIndex The column index
34852 * @param {Number} rowIndex The row index
34853 * @return {Boolean}
34855 isCellEditable : function(colIndex, rowIndex){
34856 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
34860 * Returns the editor defined for the cell/column.
34861 * return false or null to disable editing.
34862 * @param {Number} colIndex The column index
34863 * @param {Number} rowIndex The row index
34866 getCellEditor : function(colIndex, rowIndex){
34867 return this.config[colIndex].editor;
34871 * Sets if a column is editable.
34872 * @param {Number} col The column index
34873 * @param {Boolean} editable True if the column is editable
34875 setEditable : function(col, editable){
34876 this.config[col].editable = editable;
34881 * Returns true if the column is hidden.
34882 * @param {Number} colIndex The column index
34883 * @return {Boolean}
34885 isHidden : function(colIndex){
34886 return this.config[colIndex].hidden;
34891 * Returns true if the column width cannot be changed
34893 isFixed : function(colIndex){
34894 return this.config[colIndex].fixed;
34898 * Returns true if the column can be resized
34899 * @return {Boolean}
34901 isResizable : function(colIndex){
34902 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
34905 * Sets if a column is hidden.
34906 * @param {Number} colIndex The column index
34907 * @param {Boolean} hidden True if the column is hidden
34909 setHidden : function(colIndex, hidden){
34910 this.config[colIndex].hidden = hidden;
34911 this.totalWidth = null;
34912 this.fireEvent("hiddenchange", this, colIndex, hidden);
34916 * Sets the editor for a column.
34917 * @param {Number} col The column index
34918 * @param {Object} editor The editor object
34920 setEditor : function(col, editor){
34921 this.config[col].editor = editor;
34925 Roo.grid.ColumnModel.defaultRenderer = function(value){
34926 if(typeof value == "string" && value.length < 1){
34932 // Alias for backwards compatibility
34933 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
34936 * Ext JS Library 1.1.1
34937 * Copyright(c) 2006-2007, Ext JS, LLC.
34939 * Originally Released Under LGPL - original licence link has changed is not relivant.
34942 * <script type="text/javascript">
34946 * @class Roo.grid.AbstractSelectionModel
34947 * @extends Roo.util.Observable
34948 * Abstract base class for grid SelectionModels. It provides the interface that should be
34949 * implemented by descendant classes. This class should not be directly instantiated.
34952 Roo.grid.AbstractSelectionModel = function(){
34953 this.locked = false;
34954 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
34957 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
34958 /** @ignore Called by the grid automatically. Do not call directly. */
34959 init : function(grid){
34965 * Locks the selections.
34968 this.locked = true;
34972 * Unlocks the selections.
34974 unlock : function(){
34975 this.locked = false;
34979 * Returns true if the selections are locked.
34980 * @return {Boolean}
34982 isLocked : function(){
34983 return this.locked;
34987 * Ext JS Library 1.1.1
34988 * Copyright(c) 2006-2007, Ext JS, LLC.
34990 * Originally Released Under LGPL - original licence link has changed is not relivant.
34993 * <script type="text/javascript">
34996 * @extends Roo.grid.AbstractSelectionModel
34997 * @class Roo.grid.RowSelectionModel
34998 * The default SelectionModel used by {@link Roo.grid.Grid}.
34999 * It supports multiple selections and keyboard selection/navigation.
35001 * @param {Object} config
35003 Roo.grid.RowSelectionModel = function(config){
35004 Roo.apply(this, config);
35005 this.selections = new Roo.util.MixedCollection(false, function(o){
35010 this.lastActive = false;
35014 * @event selectionchange
35015 * Fires when the selection changes
35016 * @param {SelectionModel} this
35018 "selectionchange" : true,
35020 * @event afterselectionchange
35021 * Fires after the selection changes (eg. by key press or clicking)
35022 * @param {SelectionModel} this
35024 "afterselectionchange" : true,
35026 * @event beforerowselect
35027 * Fires when a row is selected being selected, return false to cancel.
35028 * @param {SelectionModel} this
35029 * @param {Number} rowIndex The selected index
35030 * @param {Boolean} keepExisting False if other selections will be cleared
35032 "beforerowselect" : true,
35035 * Fires when a row is selected.
35036 * @param {SelectionModel} this
35037 * @param {Number} rowIndex The selected index
35038 * @param {Roo.data.Record} r The record
35040 "rowselect" : true,
35042 * @event rowdeselect
35043 * Fires when a row is deselected.
35044 * @param {SelectionModel} this
35045 * @param {Number} rowIndex The selected index
35047 "rowdeselect" : true
35049 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35050 this.locked = false;
35053 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35055 * @cfg {Boolean} singleSelect
35056 * True to allow selection of only one row at a time (defaults to false)
35058 singleSelect : false,
35061 initEvents : function(){
35063 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35064 this.grid.on("mousedown", this.handleMouseDown, this);
35065 }else{ // allow click to work like normal
35066 this.grid.on("rowclick", this.handleDragableRowClick, this);
35069 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35070 "up" : function(e){
35072 this.selectPrevious(e.shiftKey);
35073 }else if(this.last !== false && this.lastActive !== false){
35074 var last = this.last;
35075 this.selectRange(this.last, this.lastActive-1);
35076 this.grid.getView().focusRow(this.lastActive);
35077 if(last !== false){
35081 this.selectFirstRow();
35083 this.fireEvent("afterselectionchange", this);
35085 "down" : function(e){
35087 this.selectNext(e.shiftKey);
35088 }else if(this.last !== false && this.lastActive !== false){
35089 var last = this.last;
35090 this.selectRange(this.last, this.lastActive+1);
35091 this.grid.getView().focusRow(this.lastActive);
35092 if(last !== false){
35096 this.selectFirstRow();
35098 this.fireEvent("afterselectionchange", this);
35103 var view = this.grid.view;
35104 view.on("refresh", this.onRefresh, this);
35105 view.on("rowupdated", this.onRowUpdated, this);
35106 view.on("rowremoved", this.onRemove, this);
35110 onRefresh : function(){
35111 var ds = this.grid.dataSource, i, v = this.grid.view;
35112 var s = this.selections;
35113 s.each(function(r){
35114 if((i = ds.indexOfId(r.id)) != -1){
35123 onRemove : function(v, index, r){
35124 this.selections.remove(r);
35128 onRowUpdated : function(v, index, r){
35129 if(this.isSelected(r)){
35130 v.onRowSelect(index);
35136 * @param {Array} records The records to select
35137 * @param {Boolean} keepExisting (optional) True to keep existing selections
35139 selectRecords : function(records, keepExisting){
35141 this.clearSelections();
35143 var ds = this.grid.dataSource;
35144 for(var i = 0, len = records.length; i < len; i++){
35145 this.selectRow(ds.indexOf(records[i]), true);
35150 * Gets the number of selected rows.
35153 getCount : function(){
35154 return this.selections.length;
35158 * Selects the first row in the grid.
35160 selectFirstRow : function(){
35165 * Select the last row.
35166 * @param {Boolean} keepExisting (optional) True to keep existing selections
35168 selectLastRow : function(keepExisting){
35169 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35173 * Selects the row immediately following the last selected row.
35174 * @param {Boolean} keepExisting (optional) True to keep existing selections
35176 selectNext : function(keepExisting){
35177 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35178 this.selectRow(this.last+1, keepExisting);
35179 this.grid.getView().focusRow(this.last);
35184 * Selects the row that precedes the last selected row.
35185 * @param {Boolean} keepExisting (optional) True to keep existing selections
35187 selectPrevious : function(keepExisting){
35189 this.selectRow(this.last-1, keepExisting);
35190 this.grid.getView().focusRow(this.last);
35195 * Returns the selected records
35196 * @return {Array} Array of selected records
35198 getSelections : function(){
35199 return [].concat(this.selections.items);
35203 * Returns the first selected record.
35206 getSelected : function(){
35207 return this.selections.itemAt(0);
35212 * Clears all selections.
35214 clearSelections : function(fast){
35215 if(this.locked) return;
35217 var ds = this.grid.dataSource;
35218 var s = this.selections;
35219 s.each(function(r){
35220 this.deselectRow(ds.indexOfId(r.id));
35224 this.selections.clear();
35231 * Selects all rows.
35233 selectAll : function(){
35234 if(this.locked) return;
35235 this.selections.clear();
35236 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35237 this.selectRow(i, true);
35242 * Returns True if there is a selection.
35243 * @return {Boolean}
35245 hasSelection : function(){
35246 return this.selections.length > 0;
35250 * Returns True if the specified row is selected.
35251 * @param {Number/Record} record The record or index of the record to check
35252 * @return {Boolean}
35254 isSelected : function(index){
35255 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35256 return (r && this.selections.key(r.id) ? true : false);
35260 * Returns True if the specified record id is selected.
35261 * @param {String} id The id of record to check
35262 * @return {Boolean}
35264 isIdSelected : function(id){
35265 return (this.selections.key(id) ? true : false);
35269 handleMouseDown : function(e, t){
35270 var view = this.grid.getView(), rowIndex;
35271 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35274 if(e.shiftKey && this.last !== false){
35275 var last = this.last;
35276 this.selectRange(last, rowIndex, e.ctrlKey);
35277 this.last = last; // reset the last
35278 view.focusRow(rowIndex);
35280 var isSelected = this.isSelected(rowIndex);
35281 if(e.button !== 0 && isSelected){
35282 view.focusRow(rowIndex);
35283 }else if(e.ctrlKey && isSelected){
35284 this.deselectRow(rowIndex);
35285 }else if(!isSelected){
35286 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35287 view.focusRow(rowIndex);
35290 this.fireEvent("afterselectionchange", this);
35293 handleDragableRowClick : function(grid, rowIndex, e)
35295 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35296 this.selectRow(rowIndex, false);
35297 grid.view.focusRow(rowIndex);
35298 this.fireEvent("afterselectionchange", this);
35303 * Selects multiple rows.
35304 * @param {Array} rows Array of the indexes of the row to select
35305 * @param {Boolean} keepExisting (optional) True to keep existing selections
35307 selectRows : function(rows, keepExisting){
35309 this.clearSelections();
35311 for(var i = 0, len = rows.length; i < len; i++){
35312 this.selectRow(rows[i], true);
35317 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35318 * @param {Number} startRow The index of the first row in the range
35319 * @param {Number} endRow The index of the last row in the range
35320 * @param {Boolean} keepExisting (optional) True to retain existing selections
35322 selectRange : function(startRow, endRow, keepExisting){
35323 if(this.locked) return;
35325 this.clearSelections();
35327 if(startRow <= endRow){
35328 for(var i = startRow; i <= endRow; i++){
35329 this.selectRow(i, true);
35332 for(var i = startRow; i >= endRow; i--){
35333 this.selectRow(i, true);
35339 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35340 * @param {Number} startRow The index of the first row in the range
35341 * @param {Number} endRow The index of the last row in the range
35343 deselectRange : function(startRow, endRow, preventViewNotify){
35344 if(this.locked) return;
35345 for(var i = startRow; i <= endRow; i++){
35346 this.deselectRow(i, preventViewNotify);
35352 * @param {Number} row The index of the row to select
35353 * @param {Boolean} keepExisting (optional) True to keep existing selections
35355 selectRow : function(index, keepExisting, preventViewNotify){
35356 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35357 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35358 if(!keepExisting || this.singleSelect){
35359 this.clearSelections();
35361 var r = this.grid.dataSource.getAt(index);
35362 this.selections.add(r);
35363 this.last = this.lastActive = index;
35364 if(!preventViewNotify){
35365 this.grid.getView().onRowSelect(index);
35367 this.fireEvent("rowselect", this, index, r);
35368 this.fireEvent("selectionchange", this);
35374 * @param {Number} row The index of the row to deselect
35376 deselectRow : function(index, preventViewNotify){
35377 if(this.locked) return;
35378 if(this.last == index){
35381 if(this.lastActive == index){
35382 this.lastActive = false;
35384 var r = this.grid.dataSource.getAt(index);
35385 this.selections.remove(r);
35386 if(!preventViewNotify){
35387 this.grid.getView().onRowDeselect(index);
35389 this.fireEvent("rowdeselect", this, index);
35390 this.fireEvent("selectionchange", this);
35394 restoreLast : function(){
35396 this.last = this._last;
35401 acceptsNav : function(row, col, cm){
35402 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35406 onEditorKey : function(field, e){
35407 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35412 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35414 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35416 }else if(k == e.ENTER && !e.ctrlKey){
35420 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35422 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35424 }else if(k == e.ESC){
35428 g.startEditing(newCell[0], newCell[1]);
35433 * Ext JS Library 1.1.1
35434 * Copyright(c) 2006-2007, Ext JS, LLC.
35436 * Originally Released Under LGPL - original licence link has changed is not relivant.
35439 * <script type="text/javascript">
35442 * @class Roo.grid.CellSelectionModel
35443 * @extends Roo.grid.AbstractSelectionModel
35444 * This class provides the basic implementation for cell selection in a grid.
35446 * @param {Object} config The object containing the configuration of this model.
35448 Roo.grid.CellSelectionModel = function(config){
35449 Roo.apply(this, config);
35451 this.selection = null;
35455 * @event beforerowselect
35456 * Fires before a cell is selected.
35457 * @param {SelectionModel} this
35458 * @param {Number} rowIndex The selected row index
35459 * @param {Number} colIndex The selected cell index
35461 "beforecellselect" : true,
35463 * @event cellselect
35464 * Fires when a cell is selected.
35465 * @param {SelectionModel} this
35466 * @param {Number} rowIndex The selected row index
35467 * @param {Number} colIndex The selected cell index
35469 "cellselect" : true,
35471 * @event selectionchange
35472 * Fires when the active selection changes.
35473 * @param {SelectionModel} this
35474 * @param {Object} selection null for no selection or an object (o) with two properties
35476 <li>o.record: the record object for the row the selection is in</li>
35477 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35480 "selectionchange" : true
35482 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35485 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35488 initEvents : function(){
35489 this.grid.on("mousedown", this.handleMouseDown, this);
35490 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35491 var view = this.grid.view;
35492 view.on("refresh", this.onViewChange, this);
35493 view.on("rowupdated", this.onRowUpdated, this);
35494 view.on("beforerowremoved", this.clearSelections, this);
35495 view.on("beforerowsinserted", this.clearSelections, this);
35496 if(this.grid.isEditor){
35497 this.grid.on("beforeedit", this.beforeEdit, this);
35502 beforeEdit : function(e){
35503 this.select(e.row, e.column, false, true, e.record);
35507 onRowUpdated : function(v, index, r){
35508 if(this.selection && this.selection.record == r){
35509 v.onCellSelect(index, this.selection.cell[1]);
35514 onViewChange : function(){
35515 this.clearSelections(true);
35519 * Returns the currently selected cell,.
35520 * @return {Array} The selected cell (row, column) or null if none selected.
35522 getSelectedCell : function(){
35523 return this.selection ? this.selection.cell : null;
35527 * Clears all selections.
35528 * @param {Boolean} true to prevent the gridview from being notified about the change.
35530 clearSelections : function(preventNotify){
35531 var s = this.selection;
35533 if(preventNotify !== true){
35534 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35536 this.selection = null;
35537 this.fireEvent("selectionchange", this, null);
35542 * Returns true if there is a selection.
35543 * @return {Boolean}
35545 hasSelection : function(){
35546 return this.selection ? true : false;
35550 handleMouseDown : function(e, t){
35551 var v = this.grid.getView();
35552 if(this.isLocked()){
35555 var row = v.findRowIndex(t);
35556 var cell = v.findCellIndex(t);
35557 if(row !== false && cell !== false){
35558 this.select(row, cell);
35564 * @param {Number} rowIndex
35565 * @param {Number} collIndex
35567 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35568 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35569 this.clearSelections();
35570 r = r || this.grid.dataSource.getAt(rowIndex);
35573 cell : [rowIndex, colIndex]
35575 if(!preventViewNotify){
35576 var v = this.grid.getView();
35577 v.onCellSelect(rowIndex, colIndex);
35578 if(preventFocus !== true){
35579 v.focusCell(rowIndex, colIndex);
35582 this.fireEvent("cellselect", this, rowIndex, colIndex);
35583 this.fireEvent("selectionchange", this, this.selection);
35588 isSelectable : function(rowIndex, colIndex, cm){
35589 return !cm.isHidden(colIndex);
35593 handleKeyDown : function(e){
35594 Roo.log('Cell Sel Model handleKeyDown');
35595 if(!e.isNavKeyPress()){
35598 var g = this.grid, s = this.selection;
35601 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35603 this.select(cell[0], cell[1]);
35608 var walk = function(row, col, step){
35609 return g.walkCells(row, col, step, sm.isSelectable, sm);
35611 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
35616 // handled by onEditorKey
35617 if (g.isEditor && g.editing) {
35621 newCell = walk(r, c-1, -1);
35623 newCell = walk(r, c+1, 1);
35627 newCell = walk(r+1, c, 1);
35630 newCell = walk(r-1, c, -1);
35633 newCell = walk(r, c+1, 1);
35636 newCell = walk(r, c-1, -1);
35639 if(g.isEditor && !g.editing){
35640 g.startEditing(r, c);
35647 this.select(newCell[0], newCell[1]);
35652 acceptsNav : function(row, col, cm){
35653 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35656 onEditorKey : function(field, e){
35658 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35659 ///Roo.log('onEditorKey' + k);
35663 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35665 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35668 }else if(k == e.ENTER && !e.ctrlKey){
35671 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35672 }else if(k == e.ESC){
35678 //Roo.log('next cell after edit');
35679 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
35684 * Ext JS Library 1.1.1
35685 * Copyright(c) 2006-2007, Ext JS, LLC.
35687 * Originally Released Under LGPL - original licence link has changed is not relivant.
35690 * <script type="text/javascript">
35694 * @class Roo.grid.EditorGrid
35695 * @extends Roo.grid.Grid
35696 * Class for creating and editable grid.
35697 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35698 * The container MUST have some type of size defined for the grid to fill. The container will be
35699 * automatically set to position relative if it isn't already.
35700 * @param {Object} dataSource The data model to bind to
35701 * @param {Object} colModel The column model with info about this grid's columns
35703 Roo.grid.EditorGrid = function(container, config){
35704 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
35705 this.getGridEl().addClass("xedit-grid");
35707 if(!this.selModel){
35708 this.selModel = new Roo.grid.CellSelectionModel();
35711 this.activeEditor = null;
35715 * @event beforeedit
35716 * Fires before cell editing is triggered. The edit event object has the following properties <br />
35717 * <ul style="padding:5px;padding-left:16px;">
35718 * <li>grid - This grid</li>
35719 * <li>record - The record being edited</li>
35720 * <li>field - The field name being edited</li>
35721 * <li>value - The value for the field being edited.</li>
35722 * <li>row - The grid row index</li>
35723 * <li>column - The grid column index</li>
35724 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35726 * @param {Object} e An edit event (see above for description)
35728 "beforeedit" : true,
35731 * Fires after a cell is edited. <br />
35732 * <ul style="padding:5px;padding-left:16px;">
35733 * <li>grid - This grid</li>
35734 * <li>record - The record being edited</li>
35735 * <li>field - The field name being edited</li>
35736 * <li>value - The value being set</li>
35737 * <li>originalValue - The original value for the field, before the edit.</li>
35738 * <li>row - The grid row index</li>
35739 * <li>column - The grid column index</li>
35741 * @param {Object} e An edit event (see above for description)
35743 "afteredit" : true,
35745 * @event validateedit
35746 * Fires after a cell is edited, but before the value is set in the record.
35747 * You can use this to modify the value being set in the field, Return false
35748 * to cancel the change. The edit event object has the following properties <br />
35749 * <ul style="padding:5px;padding-left:16px;">
35750 * <li>editor - This editor</li>
35751 * <li>grid - This grid</li>
35752 * <li>record - The record being edited</li>
35753 * <li>field - The field name being edited</li>
35754 * <li>value - The value being set</li>
35755 * <li>originalValue - The original value for the field, before the edit.</li>
35756 * <li>row - The grid row index</li>
35757 * <li>column - The grid column index</li>
35758 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35760 * @param {Object} e An edit event (see above for description)
35762 "validateedit" : true
35764 this.on("bodyscroll", this.stopEditing, this);
35765 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
35768 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
35770 * @cfg {Number} clicksToEdit
35771 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
35778 trackMouseOver: false, // causes very odd FF errors
35780 onCellDblClick : function(g, row, col){
35781 this.startEditing(row, col);
35784 onEditComplete : function(ed, value, startValue){
35785 this.editing = false;
35786 this.activeEditor = null;
35787 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
35789 var field = this.colModel.getDataIndex(ed.col);
35794 originalValue: startValue,
35801 if(String(value) !== String(startValue)){
35803 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
35804 r.set(field, e.value);
35805 // if we are dealing with a combo box..
35806 // then we also set the 'name' colum to be the displayField
35807 if (ed.field.displayField && ed.field.name) {
35808 r.set(ed.field.name, ed.field.el.dom.value);
35811 delete e.cancel; //?? why!!!
35812 this.fireEvent("afteredit", e);
35815 this.fireEvent("afteredit", e); // always fire it!
35817 this.view.focusCell(ed.row, ed.col);
35821 * Starts editing the specified for the specified row/column
35822 * @param {Number} rowIndex
35823 * @param {Number} colIndex
35825 startEditing : function(row, col){
35826 this.stopEditing();
35827 if(this.colModel.isCellEditable(col, row)){
35828 this.view.ensureVisible(row, col, true);
35829 var r = this.dataSource.getAt(row);
35830 var field = this.colModel.getDataIndex(col);
35835 value: r.data[field],
35840 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
35841 this.editing = true;
35842 var ed = this.colModel.getCellEditor(col, row);
35848 ed.render(ed.parentEl || document.body);
35851 (function(){ // complex but required for focus issues in safari, ie and opera
35855 ed.on("complete", this.onEditComplete, this, {single: true});
35856 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
35857 this.activeEditor = ed;
35858 var v = r.data[field];
35859 ed.startEdit(this.view.getCell(row, col), v);
35860 // combo's with 'displayField and name set
35861 if (ed.field.displayField && ed.field.name) {
35862 ed.field.el.dom.value = r.data[ed.field.name];
35866 }).defer(50, this);
35872 * Stops any active editing
35874 stopEditing : function(){
35875 if(this.activeEditor){
35876 this.activeEditor.completeEdit();
35878 this.activeEditor = null;
35882 * Ext JS Library 1.1.1
35883 * Copyright(c) 2006-2007, Ext JS, LLC.
35885 * Originally Released Under LGPL - original licence link has changed is not relivant.
35888 * <script type="text/javascript">
35891 // private - not really -- you end up using it !
35892 // This is a support class used internally by the Grid components
35895 * @class Roo.grid.GridEditor
35896 * @extends Roo.Editor
35897 * Class for creating and editable grid elements.
35898 * @param {Object} config any settings (must include field)
35900 Roo.grid.GridEditor = function(field, config){
35901 if (!config && field.field) {
35903 field = Roo.factory(config.field, Roo.form);
35905 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
35906 field.monitorTab = false;
35909 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
35912 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
35915 alignment: "tl-tl",
35918 cls: "x-small-editor x-grid-editor",
35923 * Ext JS Library 1.1.1
35924 * Copyright(c) 2006-2007, Ext JS, LLC.
35926 * Originally Released Under LGPL - original licence link has changed is not relivant.
35929 * <script type="text/javascript">
35934 Roo.grid.PropertyRecord = Roo.data.Record.create([
35935 {name:'name',type:'string'}, 'value'
35939 Roo.grid.PropertyStore = function(grid, source){
35941 this.store = new Roo.data.Store({
35942 recordType : Roo.grid.PropertyRecord
35944 this.store.on('update', this.onUpdate, this);
35946 this.setSource(source);
35948 Roo.grid.PropertyStore.superclass.constructor.call(this);
35953 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
35954 setSource : function(o){
35956 this.store.removeAll();
35959 if(this.isEditableValue(o[k])){
35960 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
35963 this.store.loadRecords({records: data}, {}, true);
35966 onUpdate : function(ds, record, type){
35967 if(type == Roo.data.Record.EDIT){
35968 var v = record.data['value'];
35969 var oldValue = record.modified['value'];
35970 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
35971 this.source[record.id] = v;
35973 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
35980 getProperty : function(row){
35981 return this.store.getAt(row);
35984 isEditableValue: function(val){
35985 if(val && val instanceof Date){
35987 }else if(typeof val == 'object' || typeof val == 'function'){
35993 setValue : function(prop, value){
35994 this.source[prop] = value;
35995 this.store.getById(prop).set('value', value);
35998 getSource : function(){
35999 return this.source;
36003 Roo.grid.PropertyColumnModel = function(grid, store){
36006 g.PropertyColumnModel.superclass.constructor.call(this, [
36007 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
36008 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
36010 this.store = store;
36011 this.bselect = Roo.DomHelper.append(document.body, {
36012 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
36013 {tag: 'option', value: 'true', html: 'true'},
36014 {tag: 'option', value: 'false', html: 'false'}
36017 Roo.id(this.bselect);
36020 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
36021 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
36022 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
36023 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
36024 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36026 this.renderCellDelegate = this.renderCell.createDelegate(this);
36027 this.renderPropDelegate = this.renderProp.createDelegate(this);
36030 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36034 valueText : 'Value',
36036 dateFormat : 'm/j/Y',
36039 renderDate : function(dateVal){
36040 return dateVal.dateFormat(this.dateFormat);
36043 renderBool : function(bVal){
36044 return bVal ? 'true' : 'false';
36047 isCellEditable : function(colIndex, rowIndex){
36048 return colIndex == 1;
36051 getRenderer : function(col){
36053 this.renderCellDelegate : this.renderPropDelegate;
36056 renderProp : function(v){
36057 return this.getPropertyName(v);
36060 renderCell : function(val){
36062 if(val instanceof Date){
36063 rv = this.renderDate(val);
36064 }else if(typeof val == 'boolean'){
36065 rv = this.renderBool(val);
36067 return Roo.util.Format.htmlEncode(rv);
36070 getPropertyName : function(name){
36071 var pn = this.grid.propertyNames;
36072 return pn && pn[name] ? pn[name] : name;
36075 getCellEditor : function(colIndex, rowIndex){
36076 var p = this.store.getProperty(rowIndex);
36077 var n = p.data['name'], val = p.data['value'];
36079 if(typeof(this.grid.customEditors[n]) == 'string'){
36080 return this.editors[this.grid.customEditors[n]];
36082 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36083 return this.grid.customEditors[n];
36085 if(val instanceof Date){
36086 return this.editors['date'];
36087 }else if(typeof val == 'number'){
36088 return this.editors['number'];
36089 }else if(typeof val == 'boolean'){
36090 return this.editors['boolean'];
36092 return this.editors['string'];
36098 * @class Roo.grid.PropertyGrid
36099 * @extends Roo.grid.EditorGrid
36100 * This class represents the interface of a component based property grid control.
36101 * <br><br>Usage:<pre><code>
36102 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36110 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36111 * The container MUST have some type of size defined for the grid to fill. The container will be
36112 * automatically set to position relative if it isn't already.
36113 * @param {Object} config A config object that sets properties on this grid.
36115 Roo.grid.PropertyGrid = function(container, config){
36116 config = config || {};
36117 var store = new Roo.grid.PropertyStore(this);
36118 this.store = store;
36119 var cm = new Roo.grid.PropertyColumnModel(this, store);
36120 store.store.sort('name', 'ASC');
36121 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36124 enableColLock:false,
36125 enableColumnMove:false,
36127 trackMouseOver: false,
36130 this.getGridEl().addClass('x-props-grid');
36131 this.lastEditRow = null;
36132 this.on('columnresize', this.onColumnResize, this);
36135 * @event beforepropertychange
36136 * Fires before a property changes (return false to stop?)
36137 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36138 * @param {String} id Record Id
36139 * @param {String} newval New Value
36140 * @param {String} oldval Old Value
36142 "beforepropertychange": true,
36144 * @event propertychange
36145 * Fires after a property changes
36146 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36147 * @param {String} id Record Id
36148 * @param {String} newval New Value
36149 * @param {String} oldval Old Value
36151 "propertychange": true
36153 this.customEditors = this.customEditors || {};
36155 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36158 * @cfg {Object} customEditors map of colnames=> custom editors.
36159 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36160 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36161 * false disables editing of the field.
36165 * @cfg {Object} propertyNames map of property Names to their displayed value
36168 render : function(){
36169 Roo.grid.PropertyGrid.superclass.render.call(this);
36170 this.autoSize.defer(100, this);
36173 autoSize : function(){
36174 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36176 this.view.fitColumns();
36180 onColumnResize : function(){
36181 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36185 * Sets the data for the Grid
36186 * accepts a Key => Value object of all the elements avaiable.
36187 * @param {Object} data to appear in grid.
36189 setSource : function(source){
36190 this.store.setSource(source);
36194 * Gets all the data from the grid.
36195 * @return {Object} data data stored in grid
36197 getSource : function(){
36198 return this.store.getSource();
36202 * Ext JS Library 1.1.1
36203 * Copyright(c) 2006-2007, Ext JS, LLC.
36205 * Originally Released Under LGPL - original licence link has changed is not relivant.
36208 * <script type="text/javascript">
36212 * @class Roo.LoadMask
36213 * A simple utility class for generically masking elements while loading data. If the element being masked has
36214 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36215 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36216 * element's UpdateManager load indicator and will be destroyed after the initial load.
36218 * Create a new LoadMask
36219 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36220 * @param {Object} config The config object
36222 Roo.LoadMask = function(el, config){
36223 this.el = Roo.get(el);
36224 Roo.apply(this, config);
36226 this.store.on('beforeload', this.onBeforeLoad, this);
36227 this.store.on('load', this.onLoad, this);
36228 this.store.on('loadexception', this.onLoad, this);
36229 this.removeMask = false;
36231 var um = this.el.getUpdateManager();
36232 um.showLoadIndicator = false; // disable the default indicator
36233 um.on('beforeupdate', this.onBeforeLoad, this);
36234 um.on('update', this.onLoad, this);
36235 um.on('failure', this.onLoad, this);
36236 this.removeMask = true;
36240 Roo.LoadMask.prototype = {
36242 * @cfg {Boolean} removeMask
36243 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36244 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36247 * @cfg {String} msg
36248 * The text to display in a centered loading message box (defaults to 'Loading...')
36250 msg : 'Loading...',
36252 * @cfg {String} msgCls
36253 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36255 msgCls : 'x-mask-loading',
36258 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36264 * Disables the mask to prevent it from being displayed
36266 disable : function(){
36267 this.disabled = true;
36271 * Enables the mask so that it can be displayed
36273 enable : function(){
36274 this.disabled = false;
36278 onLoad : function(){
36279 this.el.unmask(this.removeMask);
36283 onBeforeLoad : function(){
36284 if(!this.disabled){
36285 this.el.mask(this.msg, this.msgCls);
36290 destroy : function(){
36292 this.store.un('beforeload', this.onBeforeLoad, this);
36293 this.store.un('load', this.onLoad, this);
36294 this.store.un('loadexception', this.onLoad, this);
36296 var um = this.el.getUpdateManager();
36297 um.un('beforeupdate', this.onBeforeLoad, this);
36298 um.un('update', this.onLoad, this);
36299 um.un('failure', this.onLoad, this);
36304 * Ext JS Library 1.1.1
36305 * Copyright(c) 2006-2007, Ext JS, LLC.
36307 * Originally Released Under LGPL - original licence link has changed is not relivant.
36310 * <script type="text/javascript">
36312 Roo.XTemplate = function(){
36313 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36316 s = ['<tpl>', s, '</tpl>'].join('');
36318 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36320 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36321 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36322 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36326 while(m = s.match(re)){
36327 var m2 = m[0].match(nameRe);
36328 var m3 = m[0].match(ifRe);
36329 var m4 = m[0].match(execRe);
36330 var exp = null, fn = null, exec = null;
36331 var name = m2 && m2[1] ? m2[1] : '';
36333 exp = m3 && m3[1] ? m3[1] : null;
36335 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36339 exp = m4 && m4[1] ? m4[1] : null;
36341 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36346 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36347 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36348 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36358 s = s.replace(m[0], '{xtpl'+ id + '}');
36361 for(var i = tpls.length-1; i >= 0; --i){
36362 this.compileTpl(tpls[i]);
36364 this.master = tpls[tpls.length-1];
36367 Roo.extend(Roo.XTemplate, Roo.Template, {
36369 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36371 applySubTemplate : function(id, values, parent){
36372 var t = this.tpls[id];
36373 if(t.test && !t.test.call(this, values, parent)){
36376 if(t.exec && t.exec.call(this, values, parent)){
36379 var vs = t.target ? t.target.call(this, values, parent) : values;
36380 parent = t.target ? values : parent;
36381 if(t.target && vs instanceof Array){
36383 for(var i = 0, len = vs.length; i < len; i++){
36384 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36386 return buf.join('');
36388 return t.compiled.call(this, vs, parent);
36391 compileTpl : function(tpl){
36392 var fm = Roo.util.Format;
36393 var useF = this.disableFormats !== true;
36394 var sep = Roo.isGecko ? "+" : ",";
36395 var fn = function(m, name, format, args){
36396 if(name.substr(0, 4) == 'xtpl'){
36397 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36400 if(name.indexOf('.') != -1){
36403 v = "values['" + name + "']";
36405 if(format && useF){
36406 args = args ? ',' + args : "";
36407 if(format.substr(0, 5) != "this."){
36408 format = "fm." + format + '(';
36410 format = 'this.call("'+ format.substr(5) + '", ';
36414 args= ''; format = "("+v+" === undefined ? '' : ";
36416 return "'"+ sep + format + v + args + ")"+sep+"'";
36419 // branched to use + in gecko and [].join() in others
36421 body = "tpl.compiled = function(values, parent){ return '" +
36422 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36425 body = ["tpl.compiled = function(values, parent){ return ['"];
36426 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36427 body.push("'].join('');};");
36428 body = body.join('');
36430 /** eval:var:zzzzzzz */
36435 applyTemplate : function(values){
36436 return this.master.compiled.call(this, values, {});
36440 apply : function(){
36441 return this.applyTemplate.apply(this, arguments);
36444 compile : function(){return this;}
36447 Roo.XTemplate.from = function(el){
36448 el = Roo.getDom(el);
36449 return new Roo.XTemplate(el.value || el.innerHTML);
36451 * Original code for Roojs - LGPL
36452 * <script type="text/javascript">
36456 * @class Roo.XComponent
36457 * A delayed Element creator...
36459 * Mypart.xyx = new Roo.XComponent({
36461 parent : 'Mypart.xyz', // empty == document.element.!!
36465 disabled : function() {}
36467 tree : function() { // return an tree of xtype declared components
36471 xtype : 'NestedLayoutPanel',
36476 * @extends Roo.util.Observable
36478 * @param cfg {Object} configuration of component
36481 Roo.XComponent = function(cfg) {
36482 Roo.apply(this, cfg);
36486 * Fires when this the componnt is built
36487 * @param {Roo.XComponent} c the component
36491 * @event buildcomplete
36492 * Fires on the top level element when all elements have been built
36493 * @param {Roo.XComponent} c the top level component.
36495 'buildcomplete' : true
36499 Roo.XComponent.register(this);
36500 this.modules = false;
36501 this.el = false; // where the layout goes..
36505 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36508 * The created element (with Roo.factory())
36509 * @type {Roo.Layout}
36515 * for BC - use el in new code
36516 * @type {Roo.Layout}
36522 * for BC - use el in new code
36523 * @type {Roo.Layout}
36528 * @cfg {Function|boolean} disabled
36529 * If this module is disabled by some rule, return true from the funtion
36534 * @cfg {String} parent
36535 * Name of parent element which it get xtype added to..
36540 * @cfg {String} order
36541 * Used to set the order in which elements are created (usefull for multiple tabs)
36546 * @cfg {String} name
36547 * String to display while loading.
36551 * @cfg {Array} items
36552 * A single item array - the first element is the root of the tree..
36553 * It's done this way to stay compatible with the Xtype system...
36561 Roo.apply(Roo.XComponent, {
36564 * @property buildCompleted
36565 * True when the builder has completed building the interface.
36568 buildCompleted : false,
36571 * @property topModule
36572 * the upper most module - uses document.element as it's constructor.
36579 * @property modules
36580 * array of modules to be created by registration system.
36581 * @type Roo.XComponent
36588 * Register components to be built later.
36590 * This solves the following issues
36591 * - Building is not done on page load, but after an authentication process has occured.
36592 * - Interface elements are registered on page load
36593 * - Parent Interface elements may not be loaded before child, so this handles that..
36600 module : 'Pman.Tab.projectMgr',
36602 parent : 'Pman.layout',
36603 disabled : false, // or use a function..
36606 * * @param {Object} details about module
36608 register : function(obj) {
36609 this.modules.push(obj);
36613 * convert a string to an object..
36617 toObject : function(str)
36619 if (!str || typeof(str) == 'object') {
36622 var ar = str.split('.');
36626 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
36628 throw "Module not found : " + str;
36630 Roo.each(ar, function(e) {
36631 if (typeof(o[e]) == 'undefined') {
36632 throw "Module not found : " + str;
36642 * move modules into their correct place in the tree..
36645 preBuild : function ()
36648 Roo.each(this.modules , function (obj)
36650 obj.parent = this.toObject(obj.parent);
36653 this.topModule = obj;
36657 if (!obj.parent.modules) {
36658 obj.parent.modules = new Roo.util.MixedCollection(false,
36659 function(o) { return o.order + '' }
36663 obj.parent.modules.add(obj);
36668 * make a list of modules to build.
36669 * @return {Array} list of modules.
36672 buildOrder : function()
36675 var cmp = function(a,b) {
36676 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
36679 if (!this.topModule || !this.topModule.modules) {
36680 throw "No top level modules to build";
36683 // make a flat list in order of modules to build.
36684 var mods = [ this.topModule ];
36687 // add modules to their parents..
36688 var addMod = function(m) {
36689 // Roo.debug && Roo.log(m.modKey);
36693 m.modules.keySort('ASC', cmp );
36694 m.modules.each(addMod);
36696 // not sure if this is used any more..
36698 m.finalize.name = m.name + " (clean up) ";
36699 mods.push(m.finalize);
36703 this.topModule.modules.keySort('ASC', cmp );
36704 this.topModule.modules.each(addMod);
36709 * Build the registered modules.
36710 * @param {Object} parent element.
36711 * @param {Function} optional method to call after module has been added.
36719 var mods = this.buildOrder();
36721 //this.allmods = mods;
36722 //Roo.debug && Roo.log(mods);
36724 if (!mods.length) { // should not happen
36725 throw "NO modules!!!";
36730 // flash it up as modal - so we store the mask!?
36731 Roo.MessageBox.show({ title: 'loading' });
36732 Roo.MessageBox.show({
36733 title: "Please wait...",
36734 msg: "Building Interface...",
36741 var total = mods.length;
36744 var progressRun = function() {
36745 if (!mods.length) {
36746 Roo.debug && Roo.log('hide?');
36747 Roo.MessageBox.hide();
36748 _this.topModule.fireEvent('buildcomplete', _this.topModule);
36752 var m = mods.shift();
36753 Roo.debug && Roo.log(m);
36754 if (typeof(m) == 'function') { // not sure if this is supported any more..
36756 return progressRun.defer(10, _this);
36759 Roo.MessageBox.updateProgress(
36760 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
36762 (m.name ? (' - ' + m.name) : '')
36767 var disabled = (typeof(m.disabled) == 'function') ?
36768 m.disabled.call(m.module.disabled) : m.disabled;
36772 return progressRun(); // we do not update the display!
36776 // it's a top level one..
36777 var layoutbase = new Ext.BorderLayout(document.body, {
36783 tabPosition: 'top',
36784 //resizeTabs: true,
36785 alwaysShowTabs: true,
36789 var tree = m.tree();
36790 tree.region = 'center';
36791 m.el = layoutbase.addxtype(tree);
36793 m.layout = m.panel.layout;
36794 return progressRun.defer(10, _this);
36797 var tree = m.tree();
36798 tree.region = tree.region || m.region;
36799 m.el = m.parent.el.addxtype(tree);
36800 m.fireEvent('built', m);
36802 m.layout = m.panel.layout;
36803 progressRun.defer(10, _this);
36806 progressRun.defer(1, _this);
36816 //<script type="text/javascript">
36821 * @extends Roo.LayoutDialog
36822 * A generic Login Dialog..... - only one needed in theory!?!?
36824 * Fires XComponent builder on success...
36827 * username,password, lang = for login actions.
36828 * check = 1 for periodic checking that sesion is valid.
36829 * passwordRequest = email request password
36830 * logout = 1 = to logout
36832 * Affects: (this id="????" elements)
36833 * loading (removed) (used to indicate application is loading)
36834 * loading-mask (hides) (used to hide application when it's building loading)
36840 * Myapp.login = Roo.Login({
36856 Roo.Login = function(cfg)
36862 Roo.apply(this,cfg);
36864 Roo.onReady(function() {
36870 Roo.Login.superclass.constructor.call(this, this);
36871 //this.addxtype(this.items[0]);
36877 Roo.extend(Roo.Login, Roo.LayoutDialog, {
36880 * @cfg {String} method
36881 * Method used to query for login details.
36886 * @cfg {String} url
36887 * URL to query login data. - eg. baseURL + '/Login.php'
36893 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
36898 * @property checkFails
36899 * Number of times we have attempted to get authentication check, and failed.
36904 * @property intervalID
36905 * The window interval that does the constant login checking.
36911 onLoad : function() // called on page load...
36915 if (Roo.get('loading')) { // clear any loading indicator..
36916 Roo.get('loading').remove();
36919 //this.switchLang('en'); // set the language to english..
36922 success: function(response, opts) { // check successfull...
36924 var res = this.processResponse(response);
36925 this.checkFails =0;
36926 if (!res.success) { // error!
36927 this.checkFails = 5;
36928 //console.log('call failure');
36929 return this.failure(response,opts);
36932 if (!res.data.id) { // id=0 == login failure.
36933 return this.show();
36937 //console.log(success);
36938 this.fillAuth(res.data);
36939 this.checkFails =0;
36940 Roo.XComponent.build();
36942 failure : this.show
36948 check: function(cfg) // called every so often to refresh cookie etc..
36950 if (cfg.again) { // could be undefined..
36953 this.checkFails = 0;
36956 if (this.sending) {
36957 if ( this.checkFails > 4) {
36958 Roo.MessageBox.alert("Error",
36959 "Error getting authentication status. - try reloading, or wait a while", function() {
36960 _this.sending = false;
36965 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
36968 this.sending = true;
36975 method: this.method,
36976 success: cfg.success || this.success,
36977 failure : cfg.failure || this.failure,
36987 window.onbeforeunload = function() { }; // false does not work for IE..
36997 failure : function() {
36998 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
36999 document.location = document.location.toString() + '?ts=' + Math.random();
37003 success : function() {
37004 _this.user = false;
37005 this.checkFails =0;
37007 document.location = document.location.toString() + '?ts=' + Math.random();
37014 processResponse : function (response)
37018 res = Roo.decode(response.responseText);
37020 if (typeof(res) != 'object') {
37021 res = { success : false, errorMsg : res, errors : true };
37023 if (typeof(res.success) == 'undefined') {
37024 res.success = false;
37028 res = { success : false, errorMsg : response.responseText, errors : true };
37033 success : function(response, opts) // check successfull...
37035 this.sending = false;
37036 var res = this.processResponse(response);
37037 if (!res.success) {
37038 return this.failure(response, opts);
37040 if (!res.data || !res.data.id) {
37041 return this.failure(response,opts);
37043 //console.log(res);
37044 this.fillAuth(res.data);
37046 this.checkFails =0;
37051 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37053 this.authUser = -1;
37054 this.sending = false;
37055 var res = this.processResponse(response);
37056 //console.log(res);
37057 if ( this.checkFails > 2) {
37059 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37060 "Error getting authentication status. - try reloading");
37063 opts.callCfg.again = true;
37064 this.check.defer(1000, this, [ opts.callCfg ]);
37070 fillAuth: function(au) {
37071 this.startAuthCheck();
37072 this.authUserId = au.id;
37073 this.authUser = au;
37074 this.lastChecked = new Date();
37075 this.fireEvent('refreshed', au);
37076 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37077 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37078 au.lang = au.lang || 'en';
37079 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37080 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37081 this.switchLang(au.lang );
37084 // open system... - -on setyp..
37085 if (this.authUserId < 0) {
37086 Roo.MessageBox.alert("Warning",
37087 "This is an open system - please set up a admin user with a password.");
37090 //Pman.onload(); // which should do nothing if it's a re-auth result...
37095 startAuthCheck : function() // starter for timeout checking..
37097 if (this.intervalID) { // timer already in place...
37101 this.intervalID = window.setInterval(function() {
37102 _this.check(false);
37103 }, 120000); // every 120 secs = 2mins..
37109 switchLang : function (lang)
37111 _T = typeof(_T) == 'undefined' ? false : _T;
37112 if (!_T || !lang.length) {
37116 if (!_T && lang != 'en') {
37117 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37121 if (typeof(_T.en) == 'undefined') {
37123 Roo.apply(_T.en, _T);
37126 if (typeof(_T[lang]) == 'undefined') {
37127 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37132 Roo.apply(_T, _T[lang]);
37133 // just need to set the text values for everything...
37135 /* this will not work ...
37139 function formLabel(name, val) {
37140 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37143 formLabel('password', "Password"+':');
37144 formLabel('username', "Email Address"+':');
37145 formLabel('lang', "Language"+':');
37146 this.dialog.setTitle("Login");
37147 this.dialog.buttons[0].setText("Forgot Password");
37148 this.dialog.buttons[1].setText("Login");
37167 collapsible: false,
37169 center: { // needed??
37172 // tabPosition: 'top',
37175 alwaysShowTabs: false
37179 show : function(dlg)
37181 //console.log(this);
37182 this.form = this.layout.getRegion('center').activePanel.form;
37183 this.form.dialog = dlg;
37184 this.buttons[0].form = this.form;
37185 this.buttons[0].dialog = dlg;
37186 this.buttons[1].form = this.form;
37187 this.buttons[1].dialog = dlg;
37189 //this.resizeToLogo.defer(1000,this);
37190 // this is all related to resizing for logos..
37191 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37193 // this.resizeToLogo.defer(1000,this);
37196 //var w = Ext.lib.Dom.getViewWidth() - 100;
37197 //var h = Ext.lib.Dom.getViewHeight() - 100;
37198 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37200 if (this.disabled) {
37205 if (this.user.id < 0) { // used for inital setup situations.
37209 if (this.intervalID) {
37210 // remove the timer
37211 window.clearInterval(this.intervalID);
37212 this.intervalID = false;
37216 if (Roo.get('loading')) {
37217 Roo.get('loading').remove();
37219 if (Roo.get('loading-mask')) {
37220 Roo.get('loading-mask').hide();
37223 //incomming._node = tnode;
37225 //this.dialog.modal = !modal;
37226 //this.dialog.show();
37230 this.form.setValues({
37231 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37232 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37235 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37236 if (this.form.findField('username').getValue().length > 0 ){
37237 this.form.findField('password').focus();
37239 this.form.findField('username').focus();
37247 xtype : 'ContentPanel',
37259 style : 'margin: 10px;',
37262 actionfailed : function(f, act) {
37263 // form can return { errors: .... }
37265 //act.result.errors // invalid form element list...
37266 //act.result.errorMsg// invalid form element list...
37268 this.dialog.el.unmask();
37269 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37270 "Login failed - communication error - try again.");
37273 actioncomplete: function(re, act) {
37275 Roo.state.Manager.set(
37276 this.dialog.realm + '.username',
37277 this.findField('username').getValue()
37279 Roo.state.Manager.set(
37280 this.dialog.realm + '.lang',
37281 this.findField('lang').getValue()
37284 this.dialog.fillAuth(act.result.data);
37286 this.dialog.hide();
37288 if (Roo.get('loading-mask')) {
37289 Roo.get('loading-mask').show();
37291 Roo.XComponent.build();
37299 xtype : 'TextField',
37301 fieldLabel: "Email Address",
37304 autoCreate : {tag: "input", type: "text", size: "20"}
37307 xtype : 'TextField',
37309 fieldLabel: "Password",
37310 inputType: 'password',
37313 autoCreate : {tag: "input", type: "text", size: "20"},
37315 specialkey : function(e,ev) {
37316 if (ev.keyCode == 13) {
37317 this.form.dialog.el.mask("Logging in");
37318 this.form.doAction('submit', {
37319 url: this.form.dialog.url,
37320 method: this.form.dialog.method
37327 xtype : 'ComboBox',
37329 fieldLabel: "Language",
37332 xtype : 'SimpleStore',
37333 fields: ['lang', 'ldisp'],
37335 [ 'en', 'English' ],
37336 [ 'zh_HK' , '\u7E41\u4E2D' ],
37337 [ 'zh_CN', '\u7C21\u4E2D' ]
37341 valueField : 'lang',
37342 hiddenName: 'lang',
37344 displayField:'ldisp',
37348 triggerAction: 'all',
37349 emptyText:'Select a Language...',
37350 selectOnFocus:true,
37352 select : function(cb, rec, ix) {
37353 this.form.switchLang(rec.data.lang);
37369 text : "Forgot Password",
37371 click : function() {
37372 //console.log(this);
37373 var n = this.form.findField('username').getValue();
37375 Roo.MessageBox.alert("Error", "Fill in your email address");
37379 url: this.dialog.url,
37383 method: this.dialog.method,
37384 success: function(response, opts) { // check successfull...
37386 var res = this.dialog.processResponse(response);
37387 if (!res.success) { // error!
37388 Roo.MessageBox.alert("Error" ,
37389 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37392 Roo.MessageBox.alert("Notice" ,
37393 "Please check you email for the Password Reset message");
37395 failure : function() {
37396 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37409 click : function () {
37411 this.dialog.el.mask("Logging in");
37412 this.form.doAction('submit', {
37413 url: this.dialog.url,
37414 method: this.dialog.method