4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 Roo.dd.DropTarget.superclass.constructor.call( this,
3902 this.ddGroup || this.group,
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
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973 * @cfg {String} overClass
3974 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3977 * @cfg {String} dropAllowed
3978 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3980 dropAllowed : "x-dd-drop-ok",
3982 * @cfg {String} dropNotAllowed
3983 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3985 dropNotAllowed : "x-dd-drop-nodrop",
3987 * @cfg {boolean} success
3988 * set this after drop listener..
3992 * @cfg {boolean} valid
3993 * if the drop point is valid for over/enter..
4000 isNotifyTarget : true,
4004 notifyEnter : function(dd, e, data){
4006 this.fireEvent('enter', this, dd, e, data);
4008 this.el.addClass(this.overClass);
4010 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4015 notifyOver : function(dd, e, data){
4017 this.fireEvent('over', this, dd, e, data);
4018 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOut : function(dd, e, data){
4023 this.fireEvent('out', this, dd, e, data);
4025 this.el.removeClass(this.overClass);
4030 notifyDrop : function(dd, e, data){
4031 this.success = false;
4032 this.fireEvent('drop', this, dd, e, data);
4033 return this.success;
4037 * Ext JS Library 1.1.1
4038 * Copyright(c) 2006-2007, Ext JS, LLC.
4040 * Originally Released Under LGPL - original licence link has changed is not relivant.
4043 * <script type="text/javascript">
4048 * @class Roo.dd.DragZone
4049 * @extends Roo.dd.DragSource
4050 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4051 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4053 * @param {String/HTMLElement/Element} el The container element
4054 * @param {Object} config
4056 Roo.dd.DragZone = function(el, config){
4057 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4058 if(this.containerScroll){
4059 Roo.dd.ScrollManager.register(this.el);
4063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4065 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4066 * for auto scrolling during drag operations.
4069 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4070 * method after a failed drop (defaults to "c3daf9" - light blue)
4074 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4075 * for a valid target to drag based on the mouse down. Override this method
4076 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4077 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4078 * @param {EventObject} e The mouse down event
4079 * @return {Object} The dragData
4081 getDragData : function(e){
4082 return Roo.dd.Registry.getHandleFromEvent(e);
4086 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4087 * this.dragData.ddel
4088 * @param {Number} x The x position of the click on the dragged object
4089 * @param {Number} y The y position of the click on the dragged object
4090 * @return {Boolean} true to continue the drag, false to cancel
4092 onInitDrag : function(x, y){
4093 this.proxy.update(this.dragData.ddel.cloneNode(true));
4094 this.onStartDrag(x, y);
4099 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4101 afterRepair : function(){
4103 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4105 this.dragging = false;
4109 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4110 * the XY of this.dragData.ddel
4111 * @param {EventObject} e The mouse up event
4112 * @return {Array} The xy location (e.g. [100, 200])
4114 getRepairXY : function(e){
4115 return Roo.Element.fly(this.dragData.ddel).getXY();
4119 * Ext JS Library 1.1.1
4120 * Copyright(c) 2006-2007, Ext JS, LLC.
4122 * Originally Released Under LGPL - original licence link has changed is not relivant.
4125 * <script type="text/javascript">
4128 * @class Roo.dd.DropZone
4129 * @extends Roo.dd.DropTarget
4130 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4131 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4133 * @param {String/HTMLElement/Element} el The container element
4134 * @param {Object} config
4136 Roo.dd.DropZone = function(el, config){
4137 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4142 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4143 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4144 * provide your own custom lookup.
4145 * @param {Event} e The event
4146 * @return {Object} data The custom data
4148 getTargetFromEvent : function(e){
4149 return Roo.dd.Registry.getTargetFromEvent(e);
4153 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4154 * that it has registered. This method has no default implementation and should be overridden to provide
4155 * node-specific processing if necessary.
4156 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4157 * {@link #getTargetFromEvent} for this node)
4158 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4159 * @param {Event} e The event
4160 * @param {Object} data An object containing arbitrary data supplied by the drag source
4162 onNodeEnter : function(n, dd, e, data){
4167 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4168 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4169 * overridden to provide the proper feedback.
4170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4171 * {@link #getTargetFromEvent} for this node)
4172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4173 * @param {Event} e The event
4174 * @param {Object} data An object containing arbitrary data supplied by the drag source
4175 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4176 * underlying {@link Roo.dd.StatusProxy} can be updated
4178 onNodeOver : function(n, dd, e, data){
4179 return this.dropAllowed;
4183 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4184 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4185 * node-specific processing if necessary.
4186 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4187 * {@link #getTargetFromEvent} for this node)
4188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4189 * @param {Event} e The event
4190 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 onNodeOut : function(n, dd, e, data){
4197 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4198 * the drop node. The default implementation returns false, so it should be overridden to provide the
4199 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4200 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4201 * {@link #getTargetFromEvent} for this node)
4202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4203 * @param {Event} e The event
4204 * @param {Object} data An object containing arbitrary data supplied by the drag source
4205 * @return {Boolean} True if the drop was valid, else false
4207 onNodeDrop : function(n, dd, e, data){
4212 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4213 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4214 * it should be overridden to provide the proper feedback if necessary.
4215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216 * @param {Event} e The event
4217 * @param {Object} data An object containing arbitrary data supplied by the drag source
4218 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4219 * underlying {@link Roo.dd.StatusProxy} can be updated
4221 onContainerOver : function(dd, e, data){
4222 return this.dropNotAllowed;
4226 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4227 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4228 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4229 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4231 * @param {Event} e The event
4232 * @param {Object} data An object containing arbitrary data supplied by the drag source
4233 * @return {Boolean} True if the drop was valid, else false
4235 onContainerDrop : function(dd, e, data){
4240 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4241 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4242 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4243 * you should override this method and provide a custom implementation.
4244 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4245 * @param {Event} e The event
4246 * @param {Object} data An object containing arbitrary data supplied by the drag source
4247 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4248 * underlying {@link Roo.dd.StatusProxy} can be updated
4250 notifyEnter : function(dd, e, data){
4251 return this.dropNotAllowed;
4255 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4256 * This method will be called on every mouse movement while the drag source is over the drop zone.
4257 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4258 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4259 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4260 * registered node, it will call {@link #onContainerOver}.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyOver : function(dd, e, data){
4268 var n = this.getTargetFromEvent(e);
4269 if(!n){ // not over valid drop target
4270 if(this.lastOverNode){
4271 this.onNodeOut(this.lastOverNode, dd, e, data);
4272 this.lastOverNode = null;
4274 return this.onContainerOver(dd, e, data);
4276 if(this.lastOverNode != n){
4277 if(this.lastOverNode){
4278 this.onNodeOut(this.lastOverNode, dd, e, data);
4280 this.onNodeEnter(n, dd, e, data);
4281 this.lastOverNode = n;
4283 return this.onNodeOver(n, dd, e, data);
4287 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4288 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4289 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4291 * @param {Event} e The event
4292 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4294 notifyOut : function(dd, e, data){
4295 if(this.lastOverNode){
4296 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.lastOverNode = null;
4302 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4303 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4304 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4305 * otherwise it will call {@link #onContainerDrop}.
4306 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4307 * @param {Event} e The event
4308 * @param {Object} data An object containing arbitrary data supplied by the drag source
4309 * @return {Boolean} True if the drop was valid, else false
4311 notifyDrop : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4316 var n = this.getTargetFromEvent(e);
4318 this.onNodeDrop(n, dd, e, data) :
4319 this.onContainerDrop(dd, e, data);
4323 triggerCacheRefresh : function(){
4324 Roo.dd.DDM.refreshCache(this.groups);
4328 * Ext JS Library 1.1.1
4329 * Copyright(c) 2006-2007, Ext JS, LLC.
4331 * Originally Released Under LGPL - original licence link has changed is not relivant.
4334 * <script type="text/javascript">
4339 * @class Roo.data.SortTypes
4341 * Defines the default sorting (casting?) comparison functions used when sorting data.
4343 Roo.data.SortTypes = {
4345 * Default sort that does nothing
4346 * @param {Mixed} s The value being converted
4347 * @return {Mixed} The comparison value
4354 * The regular expression used to strip tags
4358 stripTagsRE : /<\/?[^>]+>/gi,
4361 * Strips all HTML tags to sort on text only
4362 * @param {Mixed} s The value being converted
4363 * @return {String} The comparison value
4365 asText : function(s){
4366 return String(s).replace(this.stripTagsRE, "");
4370 * Strips all HTML tags to sort on text only - Case insensitive
4371 * @param {Mixed} s The value being converted
4372 * @return {String} The comparison value
4374 asUCText : function(s){
4375 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4379 * Case insensitive string
4380 * @param {Mixed} s The value being converted
4381 * @return {String} The comparison value
4383 asUCString : function(s) {
4384 return String(s).toUpperCase();
4389 * @param {Mixed} s The value being converted
4390 * @return {Number} The comparison value
4392 asDate : function(s) {
4396 if(s instanceof Date){
4399 return Date.parse(String(s));
4404 * @param {Mixed} s The value being converted
4405 * @return {Float} The comparison value
4407 asFloat : function(s) {
4408 var val = parseFloat(String(s).replace(/,/g, ""));
4409 if(isNaN(val)) val = 0;
4415 * @param {Mixed} s The value being converted
4416 * @return {Number} The comparison value
4418 asInt : function(s) {
4419 var val = parseInt(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4425 * Ext JS Library 1.1.1
4426 * Copyright(c) 2006-2007, Ext JS, LLC.
4428 * Originally Released Under LGPL - original licence link has changed is not relivant.
4431 * <script type="text/javascript">
4435 * @class Roo.data.Record
4436 * Instances of this class encapsulate both record <em>definition</em> information, and record
4437 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4438 * to access Records cached in an {@link Roo.data.Store} object.<br>
4440 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4441 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4444 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4446 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4447 * {@link #create}. The parameters are the same.
4448 * @param {Array} data An associative Array of data values keyed by the field name.
4449 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4450 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4451 * not specified an integer id is generated.
4453 Roo.data.Record = function(data, id){
4454 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4459 * Generate a constructor for a specific record layout.
4460 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4461 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4462 * Each field definition object may contain the following properties: <ul>
4463 * <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,
4464 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4465 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4466 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4467 * is being used, then this is a string containing the javascript expression to reference the data relative to
4468 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4469 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4470 * this may be omitted.</p></li>
4471 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4472 * <ul><li>auto (Default, implies no conversion)</li>
4477 * <li>date</li></ul></p></li>
4478 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4479 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4480 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4481 * by the Reader into an object that will be stored in the Record. It is passed the
4482 * following parameters:<ul>
4483 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4485 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4487 * <br>usage:<br><pre><code>
4488 var TopicRecord = Roo.data.Record.create(
4489 {name: 'title', mapping: 'topic_title'},
4490 {name: 'author', mapping: 'username'},
4491 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4492 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4493 {name: 'lastPoster', mapping: 'user2'},
4494 {name: 'excerpt', mapping: 'post_text'}
4497 var myNewRecord = new TopicRecord({
4498 title: 'Do my job please',
4501 lastPost: new Date(),
4502 lastPoster: 'Animal',
4503 excerpt: 'No way dude!'
4505 myStore.add(myNewRecord);
4510 Roo.data.Record.create = function(o){
4512 f.superclass.constructor.apply(this, arguments);
4514 Roo.extend(f, Roo.data.Record);
4515 var p = f.prototype;
4516 p.fields = new Roo.util.MixedCollection(false, function(field){
4519 for(var i = 0, len = o.length; i < len; i++){
4520 p.fields.add(new Roo.data.Field(o[i]));
4522 f.getField = function(name){
4523 return p.fields.get(name);
4528 Roo.data.Record.AUTO_ID = 1000;
4529 Roo.data.Record.EDIT = 'edit';
4530 Roo.data.Record.REJECT = 'reject';
4531 Roo.data.Record.COMMIT = 'commit';
4533 Roo.data.Record.prototype = {
4535 * Readonly flag - true if this record has been modified.
4544 join : function(store){
4549 * Set the named field to the specified value.
4550 * @param {String} name The name of the field to set.
4551 * @param {Object} value The value to set the field to.
4553 set : function(name, value){
4554 if(this.data[name] == value){
4561 if(typeof this.modified[name] == 'undefined'){
4562 this.modified[name] = this.data[name];
4564 this.data[name] = value;
4566 this.store.afterEdit(this);
4571 * Get the value of the named field.
4572 * @param {String} name The name of the field to get the value of.
4573 * @return {Object} The value of the field.
4575 get : function(name){
4576 return this.data[name];
4580 beginEdit : function(){
4581 this.editing = true;
4586 cancelEdit : function(){
4587 this.editing = false;
4588 delete this.modified;
4592 endEdit : function(){
4593 this.editing = false;
4594 if(this.dirty && this.store){
4595 this.store.afterEdit(this);
4600 * Usually called by the {@link Roo.data.Store} which owns the Record.
4601 * Rejects all changes made to the Record since either creation, or the last commit operation.
4602 * Modified fields are reverted to their original values.
4604 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4605 * of reject operations.
4607 reject : function(){
4608 var m = this.modified;
4610 if(typeof m[n] != "function"){
4611 this.data[n] = m[n];
4615 delete this.modified;
4616 this.editing = false;
4618 this.store.afterReject(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Commits all changes made to the Record since either creation, or the last commit operation.
4626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627 * of commit operations.
4629 commit : function(){
4631 delete this.modified;
4632 this.editing = false;
4634 this.store.afterCommit(this);
4639 hasError : function(){
4640 return this.error != null;
4644 clearError : function(){
4649 * Creates a copy of this record.
4650 * @param {String} id (optional) A new record id if you don't want to use this record's id
4653 copy : function(newId) {
4654 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4658 * Ext JS Library 1.1.1
4659 * Copyright(c) 2006-2007, Ext JS, LLC.
4661 * Originally Released Under LGPL - original licence link has changed is not relivant.
4664 * <script type="text/javascript">
4670 * @class Roo.data.Store
4671 * @extends Roo.util.Observable
4672 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4673 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4675 * 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
4676 * has no knowledge of the format of the data returned by the Proxy.<br>
4678 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4679 * instances from the data object. These records are cached and made available through accessor functions.
4681 * Creates a new Store.
4682 * @param {Object} config A config object containing the objects needed for the Store to access data,
4683 * and read the data into Records.
4685 Roo.data.Store = function(config){
4686 this.data = new Roo.util.MixedCollection(false);
4687 this.data.getKey = function(o){
4690 this.baseParams = {};
4699 if(config && config.data){
4700 this.inlineData = config.data;
4704 Roo.apply(this, config);
4706 if(this.reader){ // reader passed
4707 this.reader = Roo.factory(this.reader, Roo.data);
4708 this.reader.xmodule = this.xmodule || false;
4709 if(!this.recordType){
4710 this.recordType = this.reader.recordType;
4712 if(this.reader.onMetaChange){
4713 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4717 if(this.recordType){
4718 this.fields = this.recordType.prototype.fields;
4724 * @event datachanged
4725 * Fires when the data cache has changed, and a widget which is using this Store
4726 * as a Record cache should refresh its view.
4727 * @param {Store} this
4732 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4733 * @param {Store} this
4734 * @param {Object} meta The JSON metadata
4739 * Fires when Records have been added to the Store
4740 * @param {Store} this
4741 * @param {Roo.data.Record[]} records The array of Records added
4742 * @param {Number} index The index at which the record(s) were added
4747 * Fires when a Record has been removed from the Store
4748 * @param {Store} this
4749 * @param {Roo.data.Record} record The Record that was removed
4750 * @param {Number} index The index at which the record was removed
4755 * Fires when a Record has been updated
4756 * @param {Store} this
4757 * @param {Roo.data.Record} record The Record that was updated
4758 * @param {String} operation The update operation being performed. Value may be one of:
4760 Roo.data.Record.EDIT
4761 Roo.data.Record.REJECT
4762 Roo.data.Record.COMMIT
4768 * Fires when the data cache has been cleared.
4769 * @param {Store} this
4774 * Fires before a request is made for a new data object. If the beforeload handler returns false
4775 * the load action will be canceled.
4776 * @param {Store} this
4777 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4782 * Fires after a new set of Records has been loaded.
4783 * @param {Store} this
4784 * @param {Roo.data.Record[]} records The Records that were loaded
4785 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4789 * @event loadexception
4790 * Fires if an exception occurs in the Proxy during loading.
4791 * Called with the signature of the Proxy's "loadexception" event.
4792 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4795 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4796 * @param {Object} load options
4797 * @param {Object} jsonData from your request (normally this contains the Exception)
4799 loadexception : true
4803 this.proxy = Roo.factory(this.proxy, Roo.data);
4804 this.proxy.xmodule = this.xmodule || false;
4805 this.relayEvents(this.proxy, ["loadexception"]);
4807 this.sortToggle = {};
4809 Roo.data.Store.superclass.constructor.call(this);
4811 if(this.inlineData){
4812 this.loadData(this.inlineData);
4813 delete this.inlineData;
4816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4818 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4819 * without a remote query - used by combo/forms at present.
4823 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4826 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4829 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4830 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4833 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4834 * on any HTTP request
4837 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4840 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4841 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4846 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4847 * loaded or when a record is removed. (defaults to false).
4849 pruneModifiedRecords : false,
4855 * Add Records to the Store and fires the add event.
4856 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4858 add : function(records){
4859 records = [].concat(records);
4860 for(var i = 0, len = records.length; i < len; i++){
4861 records[i].join(this);
4863 var index = this.data.length;
4864 this.data.addAll(records);
4865 this.fireEvent("add", this, records, index);
4869 * Remove a Record from the Store and fires the remove event.
4870 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4872 remove : function(record){
4873 var index = this.data.indexOf(record);
4874 this.data.removeAt(index);
4875 if(this.pruneModifiedRecords){
4876 this.modified.remove(record);
4878 this.fireEvent("remove", this, record, index);
4882 * Remove all Records from the Store and fires the clear event.
4884 removeAll : function(){
4886 if(this.pruneModifiedRecords){
4889 this.fireEvent("clear", this);
4893 * Inserts Records to the Store at the given index and fires the add event.
4894 * @param {Number} index The start index at which to insert the passed Records.
4895 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4897 insert : function(index, records){
4898 records = [].concat(records);
4899 for(var i = 0, len = records.length; i < len; i++){
4900 this.data.insert(index, records[i]);
4901 records[i].join(this);
4903 this.fireEvent("add", this, records, index);
4907 * Get the index within the cache of the passed Record.
4908 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4909 * @return {Number} The index of the passed Record. Returns -1 if not found.
4911 indexOf : function(record){
4912 return this.data.indexOf(record);
4916 * Get the index within the cache of the Record with the passed id.
4917 * @param {String} id The id of the Record to find.
4918 * @return {Number} The index of the Record. Returns -1 if not found.
4920 indexOfId : function(id){
4921 return this.data.indexOfKey(id);
4925 * Get the Record with the specified id.
4926 * @param {String} id The id of the Record to find.
4927 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4929 getById : function(id){
4930 return this.data.key(id);
4934 * Get the Record at the specified index.
4935 * @param {Number} index The index of the Record to find.
4936 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4938 getAt : function(index){
4939 return this.data.itemAt(index);
4943 * Returns a range of Records between specified indices.
4944 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4945 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4946 * @return {Roo.data.Record[]} An array of Records
4948 getRange : function(start, end){
4949 return this.data.getRange(start, end);
4953 storeOptions : function(o){
4954 o = Roo.apply({}, o);
4957 this.lastOptions = o;
4961 * Loads the Record cache from the configured Proxy using the configured Reader.
4963 * If using remote paging, then the first load call must specify the <em>start</em>
4964 * and <em>limit</em> properties in the options.params property to establish the initial
4965 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4967 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4968 * and this call will return before the new data has been loaded. Perform any post-processing
4969 * in a callback function, or in a "load" event handler.</strong>
4971 * @param {Object} options An object containing properties which control loading options:<ul>
4972 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4973 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4974 * passed the following arguments:<ul>
4975 * <li>r : Roo.data.Record[]</li>
4976 * <li>options: Options object from the load call</li>
4977 * <li>success: Boolean success indicator</li></ul></li>
4978 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4979 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4982 load : function(options){
4983 options = options || {};
4984 if(this.fireEvent("beforeload", this, options) !== false){
4985 this.storeOptions(options);
4986 var p = Roo.apply(options.params || {}, this.baseParams);
4987 // if meta was not loaded from remote source.. try requesting it.
4988 if (!this.reader.metaFromRemote) {
4991 if(this.sortInfo && this.remoteSort){
4992 var pn = this.paramNames;
4993 p[pn["sort"]] = this.sortInfo.field;
4994 p[pn["dir"]] = this.sortInfo.direction;
4996 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5001 * Reloads the Record cache from the configured Proxy using the configured Reader and
5002 * the options from the last load operation performed.
5003 * @param {Object} options (optional) An object containing properties which may override the options
5004 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5005 * the most recently used options are reused).
5007 reload : function(options){
5008 this.load(Roo.applyIf(options||{}, this.lastOptions));
5012 // Called as a callback by the Reader during a load operation.
5013 loadRecords : function(o, options, success){
5014 if(!o || success === false){
5015 if(success !== false){
5016 this.fireEvent("load", this, [], options);
5018 if(options.callback){
5019 options.callback.call(options.scope || this, [], options, false);
5023 // if data returned failure - throw an exception.
5024 if (o.success === false) {
5025 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5028 var r = o.records, t = o.totalRecords || r.length;
5029 if(!options || options.add !== true){
5030 if(this.pruneModifiedRecords){
5033 for(var i = 0, len = r.length; i < len; i++){
5037 this.data = this.snapshot;
5038 delete this.snapshot;
5041 this.data.addAll(r);
5042 this.totalLength = t;
5044 this.fireEvent("datachanged", this);
5046 this.totalLength = Math.max(t, this.data.length+r.length);
5049 this.fireEvent("load", this, r, options);
5050 if(options.callback){
5051 options.callback.call(options.scope || this, r, options, true);
5056 * Loads data from a passed data block. A Reader which understands the format of the data
5057 * must have been configured in the constructor.
5058 * @param {Object} data The data block from which to read the Records. The format of the data expected
5059 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5060 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5062 loadData : function(o, append){
5063 var r = this.reader.readRecords(o);
5064 this.loadRecords(r, {add: append}, true);
5068 * Gets the number of cached records.
5070 * <em>If using paging, this may not be the total size of the dataset. If the data object
5071 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5072 * the data set size</em>
5074 getCount : function(){
5075 return this.data.length || 0;
5079 * Gets the total number of records in the dataset as returned by the server.
5081 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5082 * the dataset size</em>
5084 getTotalCount : function(){
5085 return this.totalLength || 0;
5089 * Returns the sort state of the Store as an object with two properties:
5091 field {String} The name of the field by which the Records are sorted
5092 direction {String} The sort order, "ASC" or "DESC"
5095 getSortState : function(){
5096 return this.sortInfo;
5100 applySort : function(){
5101 if(this.sortInfo && !this.remoteSort){
5102 var s = this.sortInfo, f = s.field;
5103 var st = this.fields.get(f).sortType;
5104 var fn = function(r1, r2){
5105 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5106 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5108 this.data.sort(s.direction, fn);
5109 if(this.snapshot && this.snapshot != this.data){
5110 this.snapshot.sort(s.direction, fn);
5116 * Sets the default sort column and order to be used by the next load operation.
5117 * @param {String} fieldName The name of the field to sort by.
5118 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5120 setDefaultSort : function(field, dir){
5121 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5126 * If remote sorting is used, the sort is performed on the server, and the cache is
5127 * reloaded. If local sorting is used, the cache is sorted internally.
5128 * @param {String} fieldName The name of the field to sort by.
5129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131 sort : function(fieldName, dir){
5132 var f = this.fields.get(fieldName);
5134 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5135 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5140 this.sortToggle[f.name] = dir;
5141 this.sortInfo = {field: f.name, direction: dir};
5142 if(!this.remoteSort){
5144 this.fireEvent("datachanged", this);
5146 this.load(this.lastOptions);
5151 * Calls the specified function for each of the Records in the cache.
5152 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5153 * Returning <em>false</em> aborts and exits the iteration.
5154 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5156 each : function(fn, scope){
5157 this.data.each(fn, scope);
5161 * Gets all records modified since the last commit. Modified records are persisted across load operations
5162 * (e.g., during paging).
5163 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5165 getModifiedRecords : function(){
5166 return this.modified;
5170 createFilterFn : function(property, value, anyMatch){
5171 if(!value.exec){ // not a regex
5172 value = String(value);
5173 if(value.length == 0){
5176 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5179 return value.test(r.data[property]);
5184 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5185 * @param {String} property A field on your records
5186 * @param {Number} start The record index to start at (defaults to 0)
5187 * @param {Number} end The last record index to include (defaults to length - 1)
5188 * @return {Number} The sum
5190 sum : function(property, start, end){
5191 var rs = this.data.items, v = 0;
5193 end = (end || end === 0) ? end : rs.length-1;
5195 for(var i = start; i <= end; i++){
5196 v += (rs[i].data[property] || 0);
5202 * Filter the records by a specified property.
5203 * @param {String} field A field on your records
5204 * @param {String/RegExp} value Either a string that the field
5205 * should start with or a RegExp to test against the field
5206 * @param {Boolean} anyMatch True to match any part not just the beginning
5208 filter : function(property, value, anyMatch){
5209 var fn = this.createFilterFn(property, value, anyMatch);
5210 return fn ? this.filterBy(fn) : this.clearFilter();
5214 * Filter by a function. The specified function will be called with each
5215 * record in this data source. If the function returns true the record is included,
5216 * otherwise it is filtered.
5217 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5218 * @param {Object} scope (optional) The scope of the function (defaults to this)
5220 filterBy : function(fn, scope){
5221 this.snapshot = this.snapshot || this.data;
5222 this.data = this.queryBy(fn, scope||this);
5223 this.fireEvent("datachanged", this);
5227 * Query the records by a specified property.
5228 * @param {String} field A field on your records
5229 * @param {String/RegExp} value Either a string that the field
5230 * should start with or a RegExp to test against the field
5231 * @param {Boolean} anyMatch True to match any part not just the beginning
5232 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5234 query : function(property, value, anyMatch){
5235 var fn = this.createFilterFn(property, value, anyMatch);
5236 return fn ? this.queryBy(fn) : this.data.clone();
5240 * Query by a function. The specified function will be called with each
5241 * record in this data source. If the function returns true the record is included
5243 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5244 * @param {Object} scope (optional) The scope of the function (defaults to this)
5245 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5247 queryBy : function(fn, scope){
5248 var data = this.snapshot || this.data;
5249 return data.filterBy(fn, scope||this);
5253 * Collects unique values for a particular dataIndex from this store.
5254 * @param {String} dataIndex The property to collect
5255 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5256 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5257 * @return {Array} An array of the unique values
5259 collect : function(dataIndex, allowNull, bypassFilter){
5260 var d = (bypassFilter === true && this.snapshot) ?
5261 this.snapshot.items : this.data.items;
5262 var v, sv, r = [], l = {};
5263 for(var i = 0, len = d.length; i < len; i++){
5264 v = d[i].data[dataIndex];
5266 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5275 * Revert to a view of the Record cache with no filtering applied.
5276 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5278 clearFilter : function(suppressEvent){
5279 if(this.snapshot && this.snapshot != this.data){
5280 this.data = this.snapshot;
5281 delete this.snapshot;
5282 if(suppressEvent !== true){
5283 this.fireEvent("datachanged", this);
5289 afterEdit : function(record){
5290 if(this.modified.indexOf(record) == -1){
5291 this.modified.push(record);
5293 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5297 afterReject : function(record){
5298 this.modified.remove(record);
5299 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5303 afterCommit : function(record){
5304 this.modified.remove(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5309 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5310 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5312 commitChanges : function(){
5313 var m = this.modified.slice(0);
5315 for(var i = 0, len = m.length; i < len; i++){
5321 * Cancel outstanding changes on all changed records.
5323 rejectChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5331 onMetaChange : function(meta, rtype, o){
5332 this.recordType = rtype;
5333 this.fields = rtype.prototype.fields;
5334 delete this.snapshot;
5335 this.sortInfo = meta.sortInfo || this.sortInfo;
5337 this.fireEvent('metachange', this, this.reader.meta);
5341 * Ext JS Library 1.1.1
5342 * Copyright(c) 2006-2007, Ext JS, LLC.
5344 * Originally Released Under LGPL - original licence link has changed is not relivant.
5347 * <script type="text/javascript">
5351 * @class Roo.data.SimpleStore
5352 * @extends Roo.data.Store
5353 * Small helper class to make creating Stores from Array data easier.
5354 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5355 * @cfg {Array} fields An array of field definition objects, or field name strings.
5356 * @cfg {Array} data The multi-dimensional array of data
5358 * @param {Object} config
5360 Roo.data.SimpleStore = function(config){
5361 Roo.data.SimpleStore.superclass.constructor.call(this, {
5363 reader: new Roo.data.ArrayReader({
5366 Roo.data.Record.create(config.fields)
5368 proxy : new Roo.data.MemoryProxy(config.data)
5372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5374 * Ext JS Library 1.1.1
5375 * Copyright(c) 2006-2007, Ext JS, LLC.
5377 * Originally Released Under LGPL - original licence link has changed is not relivant.
5380 * <script type="text/javascript">
5385 * @extends Roo.data.Store
5386 * @class Roo.data.JsonStore
5387 * Small helper class to make creating Stores for JSON data easier. <br/>
5389 var store = new Roo.data.JsonStore({
5390 url: 'get-images.php',
5392 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5395 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5396 * JsonReader and HttpProxy (unless inline data is provided).</b>
5397 * @cfg {Array} fields An array of field definition objects, or field name strings.
5399 * @param {Object} config
5401 Roo.data.JsonStore = function(c){
5402 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5403 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5404 reader: new Roo.data.JsonReader(c, c.fields)
5407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5409 * Ext JS Library 1.1.1
5410 * Copyright(c) 2006-2007, Ext JS, LLC.
5412 * Originally Released Under LGPL - original licence link has changed is not relivant.
5415 * <script type="text/javascript">
5419 Roo.data.Field = function(config){
5420 if(typeof config == "string"){
5421 config = {name: config};
5423 Roo.apply(this, config);
5429 var st = Roo.data.SortTypes;
5430 // named sortTypes are supported, here we look them up
5431 if(typeof this.sortType == "string"){
5432 this.sortType = st[this.sortType];
5435 // set default sortType for strings and dates
5439 this.sortType = st.asUCString;
5442 this.sortType = st.asDate;
5445 this.sortType = st.none;
5450 var stripRe = /[\$,%]/g;
5452 // prebuilt conversion function for this field, instead of
5453 // switching every time we're reading a value
5455 var cv, dateFormat = this.dateFormat;
5460 cv = function(v){ return v; };
5463 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5467 return v !== undefined && v !== null && v !== '' ?
5468 parseInt(String(v).replace(stripRe, ""), 10) : '';
5473 return v !== undefined && v !== null && v !== '' ?
5474 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5479 cv = function(v){ return v === true || v === "true" || v == 1; };
5486 if(v instanceof Date){
5490 if(dateFormat == "timestamp"){
5491 return new Date(v*1000);
5493 return Date.parseDate(v, dateFormat);
5495 var parsed = Date.parse(v);
5496 return parsed ? new Date(parsed) : null;
5505 Roo.data.Field.prototype = {
5513 * Ext JS Library 1.1.1
5514 * Copyright(c) 2006-2007, Ext JS, LLC.
5516 * Originally Released Under LGPL - original licence link has changed is not relivant.
5519 * <script type="text/javascript">
5522 // Base class for reading structured data from a data source. This class is intended to be
5523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5526 * @class Roo.data.DataReader
5527 * Base class for reading structured data from a data source. This class is intended to be
5528 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5531 Roo.data.DataReader = function(meta, recordType){
5535 this.recordType = recordType instanceof Array ?
5536 Roo.data.Record.create(recordType) : recordType;
5539 Roo.data.DataReader.prototype = {
5541 * Create an empty record
5542 * @param {Object} data (optional) - overlay some values
5543 * @return {Roo.data.Record} record created.
5545 newRow : function(d) {
5547 this.recordType.prototype.fields.each(function(c) {
5549 case 'int' : da[c.name] = 0; break;
5550 case 'date' : da[c.name] = new Date(); break;
5551 case 'float' : da[c.name] = 0.0; break;
5552 case 'boolean' : da[c.name] = false; break;
5553 default : da[c.name] = ""; break;
5557 return new this.recordType(Roo.apply(da, d));
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.data.DataProxy
5573 * @extends Roo.data.Observable
5574 * This class is an abstract base class for implementations which provide retrieval of
5575 * unformatted data objects.<br>
5577 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5578 * (of the appropriate type which knows how to parse the data object) to provide a block of
5579 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5581 * Custom implementations must implement the load method as described in
5582 * {@link Roo.data.HttpProxy#load}.
5584 Roo.data.DataProxy = function(){
5588 * Fires before a network request is made to retrieve a data object.
5589 * @param {Object} This DataProxy object.
5590 * @param {Object} params The params parameter to the load function.
5595 * Fires before the load method's callback is called.
5596 * @param {Object} This DataProxy object.
5597 * @param {Object} o The data object.
5598 * @param {Object} arg The callback argument object passed to the load function.
5602 * @event loadexception
5603 * Fires if an Exception occurs during data retrieval.
5604 * @param {Object} This DataProxy object.
5605 * @param {Object} o The data object.
5606 * @param {Object} arg The callback argument object passed to the load function.
5607 * @param {Object} e The Exception.
5609 loadexception : true
5611 Roo.data.DataProxy.superclass.constructor.call(this);
5614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5617 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5621 * Ext JS Library 1.1.1
5622 * Copyright(c) 2006-2007, Ext JS, LLC.
5624 * Originally Released Under LGPL - original licence link has changed is not relivant.
5627 * <script type="text/javascript">
5630 * @class Roo.data.MemoryProxy
5631 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5632 * to the Reader when its load method is called.
5634 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5636 Roo.data.MemoryProxy = function(data){
5640 Roo.data.MemoryProxy.superclass.constructor.call(this);
5644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5646 * Load data from the requested source (in this case an in-memory
5647 * data object passed to the constructor), read the data object into
5648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5649 * process that block using the passed callback.
5650 * @param {Object} params This parameter is not used by the MemoryProxy class.
5651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652 * object into a block of Roo.data.Records.
5653 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5654 * The function must be passed <ul>
5655 * <li>The Record block object</li>
5656 * <li>The "arg" argument from the load function</li>
5657 * <li>A boolean success indicator</li>
5659 * @param {Object} scope The scope in which to call the callback
5660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5662 load : function(params, reader, callback, scope, arg){
5663 params = params || {};
5666 result = reader.readRecords(this.data);
5668 this.fireEvent("loadexception", this, arg, null, e);
5669 callback.call(scope, null, arg, false);
5672 callback.call(scope, result, arg, true);
5676 update : function(params, records){
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5690 * @class Roo.data.HttpProxy
5691 * @extends Roo.data.DataProxy
5692 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5693 * configured to reference a certain URL.<br><br>
5695 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5696 * from which the running page was served.<br><br>
5698 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5700 * Be aware that to enable the browser to parse an XML document, the server must set
5701 * the Content-Type header in the HTTP response to "text/xml".
5703 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5704 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5705 * will be used to make the request.
5707 Roo.data.HttpProxy = function(conn){
5708 Roo.data.HttpProxy.superclass.constructor.call(this);
5709 // is conn a conn config or a real conn?
5711 this.useAjax = !conn || !conn.events;
5715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5716 // thse are take from connection...
5719 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5722 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5723 * extra parameters to each request made by this object. (defaults to undefined)
5726 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5727 * to each request made by this object. (defaults to undefined)
5730 * @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)
5733 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5736 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5742 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5746 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5747 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5748 * a finer-grained basis than the DataProxy events.
5750 getConnection : function(){
5751 return this.useAjax ? Roo.Ajax : this.conn;
5755 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5756 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5757 * process that block using the passed callback.
5758 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5759 * for the request to the remote server.
5760 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5761 * object into a block of Roo.data.Records.
5762 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5763 * The function must be passed <ul>
5764 * <li>The Record block object</li>
5765 * <li>The "arg" argument from the load function</li>
5766 * <li>A boolean success indicator</li>
5768 * @param {Object} scope The scope in which to call the callback
5769 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5771 load : function(params, reader, callback, scope, arg){
5772 if(this.fireEvent("beforeload", this, params) !== false){
5774 params : params || {},
5776 callback : callback,
5781 callback : this.loadResponse,
5785 Roo.applyIf(o, this.conn);
5786 if(this.activeRequest){
5787 Roo.Ajax.abort(this.activeRequest);
5789 this.activeRequest = Roo.Ajax.request(o);
5791 this.conn.request(o);
5794 callback.call(scope||this, null, arg, false);
5799 loadResponse : function(o, success, response){
5800 delete this.activeRequest;
5802 this.fireEvent("loadexception", this, o, response);
5803 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5808 result = o.reader.read(response);
5810 this.fireEvent("loadexception", this, o, response, e);
5811 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5815 this.fireEvent("load", this, o, o.request.arg);
5816 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5820 update : function(dataSet){
5825 updateResponse : function(dataSet){
5830 * Ext JS Library 1.1.1
5831 * Copyright(c) 2006-2007, Ext JS, LLC.
5833 * Originally Released Under LGPL - original licence link has changed is not relivant.
5836 * <script type="text/javascript">
5840 * @class Roo.data.ScriptTagProxy
5841 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5842 * other than the originating domain of the running page.<br><br>
5844 * <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
5845 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5847 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5848 * source code that is used as the source inside a <script> tag.<br><br>
5850 * In order for the browser to process the returned data, the server must wrap the data object
5851 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5852 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5853 * depending on whether the callback name was passed:
5856 boolean scriptTag = false;
5857 String cb = request.getParameter("callback");
5860 response.setContentType("text/javascript");
5862 response.setContentType("application/x-json");
5864 Writer out = response.getWriter();
5866 out.write(cb + "(");
5868 out.print(dataBlock.toJsonString());
5875 * @param {Object} config A configuration object.
5877 Roo.data.ScriptTagProxy = function(config){
5878 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5879 Roo.apply(this, config);
5880 this.head = document.getElementsByTagName("head")[0];
5883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5887 * @cfg {String} url The URL from which to request the data object.
5890 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5894 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5895 * the server the name of the callback function set up by the load call to process the returned data object.
5896 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5897 * javascript output which calls this named function passing the data object as its only parameter.
5899 callbackParam : "callback",
5901 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5902 * name to the request.
5907 * Load data from the configured URL, read the data object into
5908 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5909 * process that block using the passed callback.
5910 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5911 * for the request to the remote server.
5912 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5913 * object into a block of Roo.data.Records.
5914 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5915 * The function must be passed <ul>
5916 * <li>The Record block object</li>
5917 * <li>The "arg" argument from the load function</li>
5918 * <li>A boolean success indicator</li>
5920 * @param {Object} scope The scope in which to call the callback
5921 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5923 load : function(params, reader, callback, scope, arg){
5924 if(this.fireEvent("beforeload", this, params) !== false){
5926 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5929 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5931 url += "&_dc=" + (new Date().getTime());
5933 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5936 cb : "stcCallback"+transId,
5937 scriptId : "stcScript"+transId,
5941 callback : callback,
5947 window[trans.cb] = function(o){
5948 conn.handleResponse(o, trans);
5951 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5953 if(this.autoAbort !== false){
5957 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5959 var script = document.createElement("script");
5960 script.setAttribute("src", url);
5961 script.setAttribute("type", "text/javascript");
5962 script.setAttribute("id", trans.scriptId);
5963 this.head.appendChild(script);
5967 callback.call(scope||this, null, arg, false);
5972 isLoading : function(){
5973 return this.trans ? true : false;
5977 * Abort the current server request.
5980 if(this.isLoading()){
5981 this.destroyTrans(this.trans);
5986 destroyTrans : function(trans, isLoaded){
5987 this.head.removeChild(document.getElementById(trans.scriptId));
5988 clearTimeout(trans.timeoutId);
5990 window[trans.cb] = undefined;
5992 delete window[trans.cb];
5995 // if hasn't been loaded, wait for load to remove it to prevent script error
5996 window[trans.cb] = function(){
5997 window[trans.cb] = undefined;
5999 delete window[trans.cb];
6006 handleResponse : function(o, trans){
6008 this.destroyTrans(trans, true);
6011 result = trans.reader.readRecords(o);
6013 this.fireEvent("loadexception", this, o, trans.arg, e);
6014 trans.callback.call(trans.scope||window, null, trans.arg, false);
6017 this.fireEvent("load", this, o, trans.arg);
6018 trans.callback.call(trans.scope||window, result, trans.arg, true);
6022 handleFailure : function(trans){
6024 this.destroyTrans(trans, false);
6025 this.fireEvent("loadexception", this, null, trans.arg);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6040 * @class Roo.data.JsonReader
6041 * @extends Roo.data.DataReader
6042 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6043 * based on mappings in a provided Roo.data.Record constructor.
6045 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6046 * in the reply previously.
6051 var RecordDef = Roo.data.Record.create([
6052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6053 {name: 'occupation'} // This field will use "occupation" as the mapping.
6055 var myReader = new Roo.data.JsonReader({
6056 totalProperty: "results", // The property which contains the total dataset size (optional)
6057 root: "rows", // The property which contains an Array of row objects
6058 id: "id" // The property within each row object that provides an ID for the record (optional)
6062 * This would consume a JSON file like this:
6064 { 'results': 2, 'rows': [
6065 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6066 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6069 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6070 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6071 * paged from the remote server.
6072 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6073 * @cfg {String} root name of the property which contains the Array of row objects.
6074 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6076 * Create a new JsonReader
6077 * @param {Object} meta Metadata configuration options
6078 * @param {Object} recordType Either an Array of field definition objects,
6079 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6081 Roo.data.JsonReader = function(meta, recordType){
6084 // set some defaults:
6086 totalProperty: 'total',
6087 successProperty : 'success',
6092 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6097 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6098 * Used by Store query builder to append _requestMeta to params.
6101 metaFromRemote : false,
6103 * This method is only used by a DataProxy which has retrieved data from a remote server.
6104 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6105 * @return {Object} data A data block which is used by an Roo.data.Store object as
6106 * a cache of Roo.data.Records.
6108 read : function(response){
6109 var json = response.responseText;
6111 var o = /* eval:var:o */ eval("("+json+")");
6113 throw {message: "JsonReader.read: Json object not found"};
6119 this.metaFromRemote = true;
6120 this.meta = o.metaData;
6121 this.recordType = Roo.data.Record.create(o.metaData.fields);
6122 this.onMetaChange(this.meta, this.recordType, o);
6124 return this.readRecords(o);
6127 // private function a store will implement
6128 onMetaChange : function(meta, recordType, o){
6135 simpleAccess: function(obj, subsc) {
6142 getJsonAccessor: function(){
6144 return function(expr) {
6146 return(re.test(expr))
6147 ? new Function("obj", "return obj." + expr)
6157 * Create a data block containing Roo.data.Records from an XML document.
6158 * @param {Object} o An object which contains an Array of row objects in the property specified
6159 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6160 * which contains the total size of the dataset.
6161 * @return {Object} data A data block which is used by an Roo.data.Store object as
6162 * a cache of Roo.data.Records.
6164 readRecords : function(o){
6166 * After any data loads, the raw JSON data is available for further custom processing.
6170 var s = this.meta, Record = this.recordType,
6171 f = Record.prototype.fields, fi = f.items, fl = f.length;
6173 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6175 if(s.totalProperty) {
6176 this.getTotal = this.getJsonAccessor(s.totalProperty);
6178 if(s.successProperty) {
6179 this.getSuccess = this.getJsonAccessor(s.successProperty);
6181 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6183 var g = this.getJsonAccessor(s.id);
6184 this.getId = function(rec) {
6186 return (r === undefined || r === "") ? null : r;
6189 this.getId = function(){return null;};
6192 for(var jj = 0; jj < fl; jj++){
6194 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6195 this.ef[jj] = this.getJsonAccessor(map);
6199 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6200 if(s.totalProperty){
6201 var vt = parseInt(this.getTotal(o), 10);
6206 if(s.successProperty){
6207 var vs = this.getSuccess(o);
6208 if(vs === false || vs === 'false'){
6213 for(var i = 0; i < c; i++){
6216 var id = this.getId(n);
6217 for(var j = 0; j < fl; j++){
6219 var v = this.ef[j](n);
6221 Roo.log('missing convert for ' + f.name);
6225 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6227 var record = new Record(values, id);
6229 records[i] = record;
6234 totalRecords : totalRecords
6239 * Ext JS Library 1.1.1
6240 * Copyright(c) 2006-2007, Ext JS, LLC.
6242 * Originally Released Under LGPL - original licence link has changed is not relivant.
6245 * <script type="text/javascript">
6249 * @class Roo.data.XmlReader
6250 * @extends Roo.data.DataReader
6251 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6252 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6254 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6255 * header in the HTTP response must be set to "text/xml".</em>
6259 var RecordDef = Roo.data.Record.create([
6260 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6261 {name: 'occupation'} // This field will use "occupation" as the mapping.
6263 var myReader = new Roo.data.XmlReader({
6264 totalRecords: "results", // The element which contains the total dataset size (optional)
6265 record: "row", // The repeated element which contains row information
6266 id: "id" // The element within the row that provides an ID for the record (optional)
6270 * This would consume an XML file like this:
6274 <results>2</results>
6277 <name>Bill</name>
6278 <occupation>Gardener</occupation>
6282 <name>Ben</name>
6283 <occupation>Horticulturalist</occupation>
6287 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6288 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6289 * paged from the remote server.
6290 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6291 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6292 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6293 * a record identifier value.
6295 * Create a new XmlReader
6296 * @param {Object} meta Metadata configuration options
6297 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6298 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6299 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6301 Roo.data.XmlReader = function(meta, recordType){
6303 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6305 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6307 * This method is only used by a DataProxy which has retrieved data from a remote server.
6308 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6309 * to contain a method called 'responseXML' that returns an XML document object.
6310 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6311 * a cache of Roo.data.Records.
6313 read : function(response){
6314 var doc = response.responseXML;
6316 throw {message: "XmlReader.read: XML Document not available"};
6318 return this.readRecords(doc);
6322 * Create a data block containing Roo.data.Records from an XML document.
6323 * @param {Object} doc A parsed XML document.
6324 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6325 * a cache of Roo.data.Records.
6327 readRecords : function(doc){
6329 * After any data loads/reads, the raw XML Document is available for further custom processing.
6333 var root = doc.documentElement || doc;
6334 var q = Roo.DomQuery;
6335 var recordType = this.recordType, fields = recordType.prototype.fields;
6336 var sid = this.meta.id;
6337 var totalRecords = 0, success = true;
6338 if(this.meta.totalRecords){
6339 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6342 if(this.meta.success){
6343 var sv = q.selectValue(this.meta.success, root, true);
6344 success = sv !== false && sv !== 'false';
6347 var ns = q.select(this.meta.record, root);
6348 for(var i = 0, len = ns.length; i < len; i++) {
6351 var id = sid ? q.selectValue(sid, n) : undefined;
6352 for(var j = 0, jlen = fields.length; j < jlen; j++){
6353 var f = fields.items[j];
6354 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6358 var record = new recordType(values, id);
6360 records[records.length] = record;
6366 totalRecords : totalRecords || records.length
6371 * Ext JS Library 1.1.1
6372 * Copyright(c) 2006-2007, Ext JS, LLC.
6374 * Originally Released Under LGPL - original licence link has changed is not relivant.
6377 * <script type="text/javascript">
6381 * @class Roo.data.ArrayReader
6382 * @extends Roo.data.DataReader
6383 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6384 * Each element of that Array represents a row of data fields. The
6385 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6386 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6390 var RecordDef = Roo.data.Record.create([
6391 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6392 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6394 var myReader = new Roo.data.ArrayReader({
6395 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6399 * This would consume an Array like this:
6401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6403 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6405 * Create a new JsonReader
6406 * @param {Object} meta Metadata configuration options.
6407 * @param {Object} recordType Either an Array of field definition objects
6408 * as specified to {@link Roo.data.Record#create},
6409 * or an {@link Roo.data.Record} object
6410 * created using {@link Roo.data.Record#create}.
6412 Roo.data.ArrayReader = function(meta, recordType){
6413 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6418 * Create a data block containing Roo.data.Records from an XML document.
6419 * @param {Object} o An Array of row objects which represents the dataset.
6420 * @return {Object} data A data block which is used by an Roo.data.Store object as
6421 * a cache of Roo.data.Records.
6423 readRecords : function(o){
6424 var sid = this.meta ? this.meta.id : null;
6425 var recordType = this.recordType, fields = recordType.prototype.fields;
6428 for(var i = 0; i < root.length; i++){
6431 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6432 for(var j = 0, jlen = fields.length; j < jlen; j++){
6433 var f = fields.items[j];
6434 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6435 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6439 var record = new recordType(values, id);
6441 records[records.length] = record;
6445 totalRecords : records.length
6450 * Ext JS Library 1.1.1
6451 * Copyright(c) 2006-2007, Ext JS, LLC.
6453 * Originally Released Under LGPL - original licence link has changed is not relivant.
6456 * <script type="text/javascript">
6461 * @class Roo.data.Tree
6462 * @extends Roo.util.Observable
6463 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6464 * in the tree have most standard DOM functionality.
6466 * @param {Node} root (optional) The root node
6468 Roo.data.Tree = function(root){
6471 * The root node for this tree
6476 this.setRootNode(root);
6481 * Fires when a new child node is appended to a node in this tree.
6482 * @param {Tree} tree The owner tree
6483 * @param {Node} parent The parent node
6484 * @param {Node} node The newly appended node
6485 * @param {Number} index The index of the newly appended node
6490 * Fires when a child node is removed from a node in this tree.
6491 * @param {Tree} tree The owner tree
6492 * @param {Node} parent The parent node
6493 * @param {Node} node The child node removed
6498 * Fires when a node is moved to a new location in the tree
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} node The node moved
6501 * @param {Node} oldParent The old parent of this node
6502 * @param {Node} newParent The new parent of this node
6503 * @param {Number} index The index it was moved to
6508 * Fires when a new child node is inserted in a node in this tree.
6509 * @param {Tree} tree The owner tree
6510 * @param {Node} parent The parent node
6511 * @param {Node} node The child node inserted
6512 * @param {Node} refNode The child node the node was inserted before
6516 * @event beforeappend
6517 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6518 * @param {Tree} tree The owner tree
6519 * @param {Node} parent The parent node
6520 * @param {Node} node The child node to be appended
6522 "beforeappend" : true,
6524 * @event beforeremove
6525 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node to be removed
6530 "beforeremove" : true,
6533 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6534 * @param {Tree} tree The owner tree
6535 * @param {Node} node The node being moved
6536 * @param {Node} oldParent The parent of the node
6537 * @param {Node} newParent The new parent the node is moving to
6538 * @param {Number} index The index it is being moved to
6540 "beforemove" : true,
6542 * @event beforeinsert
6543 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6544 * @param {Tree} tree The owner tree
6545 * @param {Node} parent The parent node
6546 * @param {Node} node The child node to be inserted
6547 * @param {Node} refNode The child node the node is being inserted before
6549 "beforeinsert" : true
6552 Roo.data.Tree.superclass.constructor.call(this);
6555 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6558 proxyNodeEvent : function(){
6559 return this.fireEvent.apply(this, arguments);
6563 * Returns the root node for this tree.
6566 getRootNode : function(){
6571 * Sets the root node for this tree.
6572 * @param {Node} node
6575 setRootNode : function(node){
6577 node.ownerTree = this;
6579 this.registerNode(node);
6584 * Gets a node in this tree by its id.
6585 * @param {String} id
6588 getNodeById : function(id){
6589 return this.nodeHash[id];
6592 registerNode : function(node){
6593 this.nodeHash[node.id] = node;
6596 unregisterNode : function(node){
6597 delete this.nodeHash[node.id];
6600 toString : function(){
6601 return "[Tree"+(this.id?" "+this.id:"")+"]";
6606 * @class Roo.data.Node
6607 * @extends Roo.util.Observable
6608 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6609 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6611 * @param {Object} attributes The attributes/config for the node
6613 Roo.data.Node = function(attributes){
6615 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6618 this.attributes = attributes || {};
6619 this.leaf = this.attributes.leaf;
6621 * The node id. @type String
6623 this.id = this.attributes.id;
6625 this.id = Roo.id(null, "ynode-");
6626 this.attributes.id = this.id;
6629 * All child nodes of this node. @type Array
6631 this.childNodes = [];
6632 if(!this.childNodes.indexOf){ // indexOf is a must
6633 this.childNodes.indexOf = function(o){
6634 for(var i = 0, len = this.length; i < len; i++){
6643 * The parent node for this node. @type Node
6645 this.parentNode = null;
6647 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6649 this.firstChild = null;
6651 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6653 this.lastChild = null;
6655 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6657 this.previousSibling = null;
6659 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6661 this.nextSibling = null;
6666 * Fires when a new child node is appended
6667 * @param {Tree} tree The owner tree
6668 * @param {Node} this This node
6669 * @param {Node} node The newly appended node
6670 * @param {Number} index The index of the newly appended node
6675 * Fires when a child node is removed
6676 * @param {Tree} tree The owner tree
6677 * @param {Node} this This node
6678 * @param {Node} node The removed node
6683 * Fires when this node is moved to a new location in the tree
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} oldParent The old parent of this node
6687 * @param {Node} newParent The new parent of this node
6688 * @param {Number} index The index it was moved to
6693 * Fires when a new child node is inserted.
6694 * @param {Tree} tree The owner tree
6695 * @param {Node} this This node
6696 * @param {Node} node The child node inserted
6697 * @param {Node} refNode The child node the node was inserted before
6701 * @event beforeappend
6702 * Fires before a new child is appended, return false to cancel the append.
6703 * @param {Tree} tree The owner tree
6704 * @param {Node} this This node
6705 * @param {Node} node The child node to be appended
6707 "beforeappend" : true,
6709 * @event beforeremove
6710 * Fires before a child is removed, return false to cancel the remove.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node to be removed
6715 "beforeremove" : true,
6718 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6719 * @param {Tree} tree The owner tree
6720 * @param {Node} this This node
6721 * @param {Node} oldParent The parent of this node
6722 * @param {Node} newParent The new parent this node is moving to
6723 * @param {Number} index The index it is being moved to
6725 "beforemove" : true,
6727 * @event beforeinsert
6728 * Fires before a new child is inserted, return false to cancel the insert.
6729 * @param {Tree} tree The owner tree
6730 * @param {Node} this This node
6731 * @param {Node} node The child node to be inserted
6732 * @param {Node} refNode The child node the node is being inserted before
6734 "beforeinsert" : true
6736 this.listeners = this.attributes.listeners;
6737 Roo.data.Node.superclass.constructor.call(this);
6740 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6741 fireEvent : function(evtName){
6742 // first do standard event for this node
6743 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6746 // then bubble it up to the tree if the event wasn't cancelled
6747 var ot = this.getOwnerTree();
6749 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6757 * Returns true if this node is a leaf
6760 isLeaf : function(){
6761 return this.leaf === true;
6765 setFirstChild : function(node){
6766 this.firstChild = node;
6770 setLastChild : function(node){
6771 this.lastChild = node;
6776 * Returns true if this node is the last child of its parent
6779 isLast : function(){
6780 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6784 * Returns true if this node is the first child of its parent
6787 isFirst : function(){
6788 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6791 hasChildNodes : function(){
6792 return !this.isLeaf() && this.childNodes.length > 0;
6796 * Insert node(s) as the last child node of this node.
6797 * @param {Node/Array} node The node or Array of nodes to append
6798 * @return {Node} The appended node if single append, or null if an array was passed
6800 appendChild : function(node){
6802 if(node instanceof Array){
6804 }else if(arguments.length > 1){
6807 // if passed an array or multiple args do them one by one
6809 for(var i = 0, len = multi.length; i < len; i++) {
6810 this.appendChild(multi[i]);
6813 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6816 var index = this.childNodes.length;
6817 var oldParent = node.parentNode;
6818 // it's a move, make sure we move it cleanly
6820 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6823 oldParent.removeChild(node);
6825 index = this.childNodes.length;
6827 this.setFirstChild(node);
6829 this.childNodes.push(node);
6830 node.parentNode = this;
6831 var ps = this.childNodes[index-1];
6833 node.previousSibling = ps;
6834 ps.nextSibling = node;
6836 node.previousSibling = null;
6838 node.nextSibling = null;
6839 this.setLastChild(node);
6840 node.setOwnerTree(this.getOwnerTree());
6841 this.fireEvent("append", this.ownerTree, this, node, index);
6843 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6850 * Removes a child node from this node.
6851 * @param {Node} node The node to remove
6852 * @return {Node} The removed node
6854 removeChild : function(node){
6855 var index = this.childNodes.indexOf(node);
6859 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6863 // remove it from childNodes collection
6864 this.childNodes.splice(index, 1);
6867 if(node.previousSibling){
6868 node.previousSibling.nextSibling = node.nextSibling;
6870 if(node.nextSibling){
6871 node.nextSibling.previousSibling = node.previousSibling;
6874 // update child refs
6875 if(this.firstChild == node){
6876 this.setFirstChild(node.nextSibling);
6878 if(this.lastChild == node){
6879 this.setLastChild(node.previousSibling);
6882 node.setOwnerTree(null);
6883 // clear any references from the node
6884 node.parentNode = null;
6885 node.previousSibling = null;
6886 node.nextSibling = null;
6887 this.fireEvent("remove", this.ownerTree, this, node);
6892 * Inserts the first node before the second node in this nodes childNodes collection.
6893 * @param {Node} node The node to insert
6894 * @param {Node} refNode The node to insert before (if null the node is appended)
6895 * @return {Node} The inserted node
6897 insertBefore : function(node, refNode){
6898 if(!refNode){ // like standard Dom, refNode can be null for append
6899 return this.appendChild(node);
6902 if(node == refNode){
6906 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6909 var index = this.childNodes.indexOf(refNode);
6910 var oldParent = node.parentNode;
6911 var refIndex = index;
6913 // when moving internally, indexes will change after remove
6914 if(oldParent == this && this.childNodes.indexOf(node) < index){
6918 // it's a move, make sure we move it cleanly
6920 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6923 oldParent.removeChild(node);
6926 this.setFirstChild(node);
6928 this.childNodes.splice(refIndex, 0, node);
6929 node.parentNode = this;
6930 var ps = this.childNodes[refIndex-1];
6932 node.previousSibling = ps;
6933 ps.nextSibling = node;
6935 node.previousSibling = null;
6937 node.nextSibling = refNode;
6938 refNode.previousSibling = node;
6939 node.setOwnerTree(this.getOwnerTree());
6940 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6942 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6948 * Returns the child node at the specified index.
6949 * @param {Number} index
6952 item : function(index){
6953 return this.childNodes[index];
6957 * Replaces one child node in this node with another.
6958 * @param {Node} newChild The replacement node
6959 * @param {Node} oldChild The node to replace
6960 * @return {Node} The replaced node
6962 replaceChild : function(newChild, oldChild){
6963 this.insertBefore(newChild, oldChild);
6964 this.removeChild(oldChild);
6969 * Returns the index of a child node
6970 * @param {Node} node
6971 * @return {Number} The index of the node or -1 if it was not found
6973 indexOf : function(child){
6974 return this.childNodes.indexOf(child);
6978 * Returns the tree this node is in.
6981 getOwnerTree : function(){
6982 // if it doesn't have one, look for one
6983 if(!this.ownerTree){
6987 this.ownerTree = p.ownerTree;
6993 return this.ownerTree;
6997 * Returns depth of this node (the root node has a depth of 0)
7000 getDepth : function(){
7003 while(p.parentNode){
7011 setOwnerTree : function(tree){
7012 // if it's move, we need to update everyone
7013 if(tree != this.ownerTree){
7015 this.ownerTree.unregisterNode(this);
7017 this.ownerTree = tree;
7018 var cs = this.childNodes;
7019 for(var i = 0, len = cs.length; i < len; i++) {
7020 cs[i].setOwnerTree(tree);
7023 tree.registerNode(this);
7029 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7030 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7031 * @return {String} The path
7033 getPath : function(attr){
7034 attr = attr || "id";
7035 var p = this.parentNode;
7036 var b = [this.attributes[attr]];
7038 b.unshift(p.attributes[attr]);
7041 var sep = this.getOwnerTree().pathSeparator;
7042 return sep + b.join(sep);
7046 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7047 * function call will be the scope provided or the current node. The arguments to the function
7048 * will be the args provided or the current node. If the function returns false at any point,
7049 * the bubble is stopped.
7050 * @param {Function} fn The function to call
7051 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7052 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7054 bubble : function(fn, scope, args){
7057 if(fn.call(scope || p, args || p) === false){
7065 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7066 * function call will be the scope provided or the current node. The arguments to the function
7067 * will be the args provided or the current node. If the function returns false at any point,
7068 * the cascade is stopped on that branch.
7069 * @param {Function} fn The function to call
7070 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7071 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7073 cascade : function(fn, scope, args){
7074 if(fn.call(scope || this, args || this) !== false){
7075 var cs = this.childNodes;
7076 for(var i = 0, len = cs.length; i < len; i++) {
7077 cs[i].cascade(fn, scope, args);
7083 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7084 * function call will be the scope provided or the current node. The arguments to the function
7085 * will be the args provided or the current node. If the function returns false at any point,
7086 * the iteration stops.
7087 * @param {Function} fn The function to call
7088 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7091 eachChild : function(fn, scope, args){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 if(fn.call(scope || this, args || cs[i]) === false){
7101 * Finds the first child that has the attribute with the specified value.
7102 * @param {String} attribute The attribute name
7103 * @param {Mixed} value The value to search for
7104 * @return {Node} The found child or null if none was found
7106 findChild : function(attribute, value){
7107 var cs = this.childNodes;
7108 for(var i = 0, len = cs.length; i < len; i++) {
7109 if(cs[i].attributes[attribute] == value){
7117 * Finds the first child by a custom function. The child matches if the function passed
7119 * @param {Function} fn
7120 * @param {Object} scope (optional)
7121 * @return {Node} The found child or null if none was found
7123 findChildBy : function(fn, scope){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(fn.call(scope||cs[i], cs[i]) === true){
7134 * Sorts this nodes children using the supplied sort function
7135 * @param {Function} fn
7136 * @param {Object} scope (optional)
7138 sort : function(fn, scope){
7139 var cs = this.childNodes;
7140 var len = cs.length;
7142 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7144 for(var i = 0; i < len; i++){
7146 n.previousSibling = cs[i-1];
7147 n.nextSibling = cs[i+1];
7149 this.setFirstChild(n);
7152 this.setLastChild(n);
7159 * Returns true if this node is an ancestor (at any point) of the passed node.
7160 * @param {Node} node
7163 contains : function(node){
7164 return node.isAncestor(this);
7168 * Returns true if the passed node is an ancestor (at any point) of this node.
7169 * @param {Node} node
7172 isAncestor : function(node){
7173 var p = this.parentNode;
7183 toString : function(){
7184 return "[Node"+(this.id?" "+this.id:"")+"]";
7188 * Ext JS Library 1.1.1
7189 * Copyright(c) 2006-2007, Ext JS, LLC.
7191 * Originally Released Under LGPL - original licence link has changed is not relivant.
7194 * <script type="text/javascript">
7199 * @class Roo.ComponentMgr
7200 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7203 Roo.ComponentMgr = function(){
7204 var all = new Roo.util.MixedCollection();
7208 * Registers a component.
7209 * @param {Roo.Component} c The component
7211 register : function(c){
7216 * Unregisters a component.
7217 * @param {Roo.Component} c The component
7219 unregister : function(c){
7224 * Returns a component by id
7225 * @param {String} id The component id
7232 * Registers a function that will be called when a specified component is added to ComponentMgr
7233 * @param {String} id The component id
7234 * @param {Funtction} fn The callback function
7235 * @param {Object} scope The scope of the callback
7237 onAvailable : function(id, fn, scope){
7238 all.on("add", function(index, o){
7240 fn.call(scope || o, o);
7241 all.un("add", fn, scope);
7248 * Ext JS Library 1.1.1
7249 * Copyright(c) 2006-2007, Ext JS, LLC.
7251 * Originally Released Under LGPL - original licence link has changed is not relivant.
7254 * <script type="text/javascript">
7258 * @class Roo.Component
7259 * @extends Roo.util.Observable
7260 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7261 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7262 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7263 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7264 * All visual components (widgets) that require rendering into a layout should subclass Component.
7266 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7267 * 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
7268 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7270 Roo.Component = function(config){
7271 config = config || {};
7272 if(config.tagName || config.dom || typeof config == "string"){ // element object
7273 config = {el: config, id: config.id || config};
7275 this.initialConfig = config;
7277 Roo.apply(this, config);
7281 * Fires after the component is disabled.
7282 * @param {Roo.Component} this
7287 * Fires after the component is enabled.
7288 * @param {Roo.Component} this
7293 * Fires before the component is shown. Return false to stop the show.
7294 * @param {Roo.Component} this
7299 * Fires after the component is shown.
7300 * @param {Roo.Component} this
7305 * Fires before the component is hidden. Return false to stop the hide.
7306 * @param {Roo.Component} this
7311 * Fires after the component is hidden.
7312 * @param {Roo.Component} this
7316 * @event beforerender
7317 * Fires before the component is rendered. Return false to stop the render.
7318 * @param {Roo.Component} this
7320 beforerender : true,
7323 * Fires after the component is rendered.
7324 * @param {Roo.Component} this
7328 * @event beforedestroy
7329 * Fires before the component is destroyed. Return false to stop the destroy.
7330 * @param {Roo.Component} this
7332 beforedestroy : true,
7335 * Fires after the component is destroyed.
7336 * @param {Roo.Component} this
7341 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7343 Roo.ComponentMgr.register(this);
7344 Roo.Component.superclass.constructor.call(this);
7345 this.initComponent();
7346 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7347 this.render(this.renderTo);
7348 delete this.renderTo;
7353 Roo.Component.AUTO_ID = 1000;
7355 Roo.extend(Roo.Component, Roo.util.Observable, {
7357 * @property {Boolean} hidden
7358 * true if this component is hidden. Read-only.
7362 * true if this component is disabled. Read-only.
7366 * true if this component has been rendered. Read-only.
7370 /** @cfg {String} disableClass
7371 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7373 disabledClass : "x-item-disabled",
7374 /** @cfg {Boolean} allowDomMove
7375 * Whether the component can move the Dom node when rendering (defaults to true).
7377 allowDomMove : true,
7378 /** @cfg {String} hideMode
7379 * How this component should hidden. Supported values are
7380 * "visibility" (css visibility), "offsets" (negative offset position) and
7381 * "display" (css display) - defaults to "display".
7383 hideMode: 'display',
7386 ctype : "Roo.Component",
7388 /** @cfg {String} actionMode
7389 * which property holds the element that used for hide() / show() / disable() / enable()
7395 getActionEl : function(){
7396 return this[this.actionMode];
7399 initComponent : Roo.emptyFn,
7401 * If this is a lazy rendering component, render it to its container element.
7402 * @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.
7404 render : function(container, position){
7405 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7406 if(!container && this.el){
7407 this.el = Roo.get(this.el);
7408 container = this.el.dom.parentNode;
7409 this.allowDomMove = false;
7411 this.container = Roo.get(container);
7412 this.rendered = true;
7413 if(position !== undefined){
7414 if(typeof position == 'number'){
7415 position = this.container.dom.childNodes[position];
7417 position = Roo.getDom(position);
7420 this.onRender(this.container, position || null);
7422 this.el.addClass(this.cls);
7426 this.el.applyStyles(this.style);
7429 this.fireEvent("render", this);
7430 this.afterRender(this.container);
7442 // default function is not really useful
7443 onRender : function(ct, position){
7445 this.el = Roo.get(this.el);
7446 if(this.allowDomMove !== false){
7447 ct.dom.insertBefore(this.el.dom, position);
7453 getAutoCreate : function(){
7454 var cfg = typeof this.autoCreate == "object" ?
7455 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7456 if(this.id && !cfg.id){
7463 afterRender : Roo.emptyFn,
7466 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7467 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7469 destroy : function(){
7470 if(this.fireEvent("beforedestroy", this) !== false){
7471 this.purgeListeners();
7472 this.beforeDestroy();
7474 this.el.removeAllListeners();
7476 if(this.actionMode == "container"){
7477 this.container.remove();
7481 Roo.ComponentMgr.unregister(this);
7482 this.fireEvent("destroy", this);
7487 beforeDestroy : function(){
7492 onDestroy : function(){
7497 * Returns the underlying {@link Roo.Element}.
7498 * @return {Roo.Element} The element
7505 * Returns the id of this component.
7513 * Try to focus this component.
7514 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7515 * @return {Roo.Component} this
7517 focus : function(selectText){
7520 if(selectText === true){
7521 this.el.dom.select();
7536 * Disable this component.
7537 * @return {Roo.Component} this
7539 disable : function(){
7543 this.disabled = true;
7544 this.fireEvent("disable", this);
7549 onDisable : function(){
7550 this.getActionEl().addClass(this.disabledClass);
7551 this.el.dom.disabled = true;
7555 * Enable this component.
7556 * @return {Roo.Component} this
7558 enable : function(){
7562 this.disabled = false;
7563 this.fireEvent("enable", this);
7568 onEnable : function(){
7569 this.getActionEl().removeClass(this.disabledClass);
7570 this.el.dom.disabled = false;
7574 * Convenience function for setting disabled/enabled by boolean.
7575 * @param {Boolean} disabled
7577 setDisabled : function(disabled){
7578 this[disabled ? "disable" : "enable"]();
7582 * Show this component.
7583 * @return {Roo.Component} this
7586 if(this.fireEvent("beforeshow", this) !== false){
7587 this.hidden = false;
7591 this.fireEvent("show", this);
7597 onShow : function(){
7598 var ae = this.getActionEl();
7599 if(this.hideMode == 'visibility'){
7600 ae.dom.style.visibility = "visible";
7601 }else if(this.hideMode == 'offsets'){
7602 ae.removeClass('x-hidden');
7604 ae.dom.style.display = "";
7609 * Hide this component.
7610 * @return {Roo.Component} this
7613 if(this.fireEvent("beforehide", this) !== false){
7618 this.fireEvent("hide", this);
7624 onHide : function(){
7625 var ae = this.getActionEl();
7626 if(this.hideMode == 'visibility'){
7627 ae.dom.style.visibility = "hidden";
7628 }else if(this.hideMode == 'offsets'){
7629 ae.addClass('x-hidden');
7631 ae.dom.style.display = "none";
7636 * Convenience function to hide or show this component by boolean.
7637 * @param {Boolean} visible True to show, false to hide
7638 * @return {Roo.Component} this
7640 setVisible: function(visible){
7650 * Returns true if this component is visible.
7652 isVisible : function(){
7653 return this.getActionEl().isVisible();
7656 cloneConfig : function(overrides){
7657 overrides = overrides || {};
7658 var id = overrides.id || Roo.id();
7659 var cfg = Roo.applyIf(overrides, this.initialConfig);
7660 cfg.id = id; // prevent dup id
7661 return new this.constructor(cfg);
7665 * Ext JS Library 1.1.1
7666 * Copyright(c) 2006-2007, Ext JS, LLC.
7668 * Originally Released Under LGPL - original licence link has changed is not relivant.
7671 * <script type="text/javascript">
7676 * @extends Roo.Element
7677 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7678 * automatic maintaining of shadow/shim positions.
7679 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7680 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7681 * you can pass a string with a CSS class name. False turns off the shadow.
7682 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7683 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7684 * @cfg {String} cls CSS class to add to the element
7685 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7686 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7688 * @param {Object} config An object with config options.
7689 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7692 Roo.Layer = function(config, existingEl){
7693 config = config || {};
7694 var dh = Roo.DomHelper;
7695 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7697 this.dom = Roo.getDom(existingEl);
7700 var o = config.dh || {tag: "div", cls: "x-layer"};
7701 this.dom = dh.append(pel, o);
7704 this.addClass(config.cls);
7706 this.constrain = config.constrain !== false;
7707 this.visibilityMode = Roo.Element.VISIBILITY;
7709 this.id = this.dom.id = config.id;
7711 this.id = Roo.id(this.dom);
7713 this.zindex = config.zindex || this.getZIndex();
7714 this.position("absolute", this.zindex);
7716 this.shadowOffset = config.shadowOffset || 4;
7717 this.shadow = new Roo.Shadow({
7718 offset : this.shadowOffset,
7719 mode : config.shadow
7722 this.shadowOffset = 0;
7724 this.useShim = config.shim !== false && Roo.useShims;
7725 this.useDisplay = config.useDisplay;
7729 var supr = Roo.Element.prototype;
7731 // shims are shared among layer to keep from having 100 iframes
7734 Roo.extend(Roo.Layer, Roo.Element, {
7736 getZIndex : function(){
7737 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7740 getShim : function(){
7747 var shim = shims.shift();
7749 shim = this.createShim();
7750 shim.enableDisplayMode('block');
7751 shim.dom.style.display = 'none';
7752 shim.dom.style.visibility = 'visible';
7754 var pn = this.dom.parentNode;
7755 if(shim.dom.parentNode != pn){
7756 pn.insertBefore(shim.dom, this.dom);
7758 shim.setStyle('z-index', this.getZIndex()-2);
7763 hideShim : function(){
7765 this.shim.setDisplayed(false);
7766 shims.push(this.shim);
7771 disableShadow : function(){
7773 this.shadowDisabled = true;
7775 this.lastShadowOffset = this.shadowOffset;
7776 this.shadowOffset = 0;
7780 enableShadow : function(show){
7782 this.shadowDisabled = false;
7783 this.shadowOffset = this.lastShadowOffset;
7784 delete this.lastShadowOffset;
7792 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7793 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7794 sync : function(doShow){
7795 var sw = this.shadow;
7796 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7797 var sh = this.getShim();
7799 var w = this.getWidth(),
7800 h = this.getHeight();
7802 var l = this.getLeft(true),
7803 t = this.getTop(true);
7805 if(sw && !this.shadowDisabled){
7806 if(doShow && !sw.isVisible()){
7809 sw.realign(l, t, w, h);
7815 // fit the shim behind the shadow, so it is shimmed too
7816 var a = sw.adjusts, s = sh.dom.style;
7817 s.left = (Math.min(l, l+a.l))+"px";
7818 s.top = (Math.min(t, t+a.t))+"px";
7819 s.width = (w+a.w)+"px";
7820 s.height = (h+a.h)+"px";
7827 sh.setLeftTop(l, t);
7834 destroy : function(){
7839 this.removeAllListeners();
7840 var pn = this.dom.parentNode;
7842 pn.removeChild(this.dom);
7844 Roo.Element.uncache(this.id);
7847 remove : function(){
7852 beginUpdate : function(){
7853 this.updating = true;
7857 endUpdate : function(){
7858 this.updating = false;
7863 hideUnders : function(negOffset){
7871 constrainXY : function(){
7873 var vw = Roo.lib.Dom.getViewWidth(),
7874 vh = Roo.lib.Dom.getViewHeight();
7875 var s = Roo.get(document).getScroll();
7877 var xy = this.getXY();
7878 var x = xy[0], y = xy[1];
7879 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7880 // only move it if it needs it
7882 // first validate right/bottom
7883 if((x + w) > vw+s.left){
7884 x = vw - w - this.shadowOffset;
7887 if((y + h) > vh+s.top){
7888 y = vh - h - this.shadowOffset;
7891 // then make sure top/left isn't negative
7902 var ay = this.avoidY;
7903 if(y <= ay && (y+h) >= ay){
7909 supr.setXY.call(this, xy);
7915 isVisible : function(){
7916 return this.visible;
7920 showAction : function(){
7921 this.visible = true; // track visibility to prevent getStyle calls
7922 if(this.useDisplay === true){
7923 this.setDisplayed("");
7924 }else if(this.lastXY){
7925 supr.setXY.call(this, this.lastXY);
7926 }else if(this.lastLT){
7927 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7932 hideAction : function(){
7933 this.visible = false;
7934 if(this.useDisplay === true){
7935 this.setDisplayed(false);
7937 this.setLeftTop(-10000,-10000);
7941 // overridden Element method
7942 setVisible : function(v, a, d, c, e){
7947 var cb = function(){
7952 }.createDelegate(this);
7953 supr.setVisible.call(this, true, true, d, cb, e);
7956 this.hideUnders(true);
7965 }.createDelegate(this);
7967 supr.setVisible.call(this, v, a, d, cb, e);
7976 storeXY : function(xy){
7981 storeLeftTop : function(left, top){
7983 this.lastLT = [left, top];
7987 beforeFx : function(){
7988 this.beforeAction();
7989 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
7993 afterFx : function(){
7994 Roo.Layer.superclass.afterFx.apply(this, arguments);
7995 this.sync(this.isVisible());
7999 beforeAction : function(){
8000 if(!this.updating && this.shadow){
8005 // overridden Element method
8006 setLeft : function(left){
8007 this.storeLeftTop(left, this.getTop(true));
8008 supr.setLeft.apply(this, arguments);
8012 setTop : function(top){
8013 this.storeLeftTop(this.getLeft(true), top);
8014 supr.setTop.apply(this, arguments);
8018 setLeftTop : function(left, top){
8019 this.storeLeftTop(left, top);
8020 supr.setLeftTop.apply(this, arguments);
8024 setXY : function(xy, a, d, c, e){
8026 this.beforeAction();
8028 var cb = this.createCB(c);
8029 supr.setXY.call(this, xy, a, d, cb, e);
8036 createCB : function(c){
8047 // overridden Element method
8048 setX : function(x, a, d, c, e){
8049 this.setXY([x, this.getY()], a, d, c, e);
8052 // overridden Element method
8053 setY : function(y, a, d, c, e){
8054 this.setXY([this.getX(), y], a, d, c, e);
8057 // overridden Element method
8058 setSize : function(w, h, a, d, c, e){
8059 this.beforeAction();
8060 var cb = this.createCB(c);
8061 supr.setSize.call(this, w, h, a, d, cb, e);
8067 // overridden Element method
8068 setWidth : function(w, a, d, c, e){
8069 this.beforeAction();
8070 var cb = this.createCB(c);
8071 supr.setWidth.call(this, w, a, d, cb, e);
8077 // overridden Element method
8078 setHeight : function(h, a, d, c, e){
8079 this.beforeAction();
8080 var cb = this.createCB(c);
8081 supr.setHeight.call(this, h, a, d, cb, e);
8087 // overridden Element method
8088 setBounds : function(x, y, w, h, a, d, c, e){
8089 this.beforeAction();
8090 var cb = this.createCB(c);
8092 this.storeXY([x, y]);
8093 supr.setXY.call(this, [x, y]);
8094 supr.setSize.call(this, w, h, a, d, cb, e);
8097 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8103 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8104 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8105 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8106 * @param {Number} zindex The new z-index to set
8107 * @return {this} The Layer
8109 setZIndex : function(zindex){
8110 this.zindex = zindex;
8111 this.setStyle("z-index", zindex + 2);
8113 this.shadow.setZIndex(zindex + 1);
8116 this.shim.setStyle("z-index", zindex);
8122 * Ext JS Library 1.1.1
8123 * Copyright(c) 2006-2007, Ext JS, LLC.
8125 * Originally Released Under LGPL - original licence link has changed is not relivant.
8128 * <script type="text/javascript">
8134 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8135 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8136 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8138 * Create a new Shadow
8139 * @param {Object} config The config object
8141 Roo.Shadow = function(config){
8142 Roo.apply(this, config);
8143 if(typeof this.mode != "string"){
8144 this.mode = this.defaultMode;
8146 var o = this.offset, a = {h: 0};
8147 var rad = Math.floor(this.offset/2);
8148 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8154 a.l -= this.offset + rad;
8155 a.t -= this.offset + rad;
8166 a.l -= (this.offset - rad);
8167 a.t -= this.offset + rad;
8169 a.w -= (this.offset - rad)*2;
8180 a.l -= (this.offset - rad);
8181 a.t -= (this.offset - rad);
8183 a.w -= (this.offset + rad + 1);
8184 a.h -= (this.offset + rad);
8193 Roo.Shadow.prototype = {
8195 * @cfg {String} mode
8196 * The shadow display mode. Supports the following options:<br />
8197 * sides: Shadow displays on both sides and bottom only<br />
8198 * frame: Shadow displays equally on all four sides<br />
8199 * drop: Traditional bottom-right drop shadow (default)
8202 * @cfg {String} offset
8203 * The number of pixels to offset the shadow from the element (defaults to 4)
8208 defaultMode: "drop",
8211 * Displays the shadow under the target element
8212 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8214 show : function(target){
8215 target = Roo.get(target);
8217 this.el = Roo.Shadow.Pool.pull();
8218 if(this.el.dom.nextSibling != target.dom){
8219 this.el.insertBefore(target);
8222 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8224 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8227 target.getLeft(true),
8228 target.getTop(true),
8232 this.el.dom.style.display = "block";
8236 * Returns true if the shadow is visible, else false
8238 isVisible : function(){
8239 return this.el ? true : false;
8243 * Direct alignment when values are already available. Show must be called at least once before
8244 * calling this method to ensure it is initialized.
8245 * @param {Number} left The target element left position
8246 * @param {Number} top The target element top position
8247 * @param {Number} width The target element width
8248 * @param {Number} height The target element height
8250 realign : function(l, t, w, h){
8254 var a = this.adjusts, d = this.el.dom, s = d.style;
8256 s.left = (l+a.l)+"px";
8257 s.top = (t+a.t)+"px";
8258 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8260 if(s.width != sws || s.height != shs){
8264 var cn = d.childNodes;
8265 var sww = Math.max(0, (sw-12))+"px";
8266 cn[0].childNodes[1].style.width = sww;
8267 cn[1].childNodes[1].style.width = sww;
8268 cn[2].childNodes[1].style.width = sww;
8269 cn[1].style.height = Math.max(0, (sh-12))+"px";
8279 this.el.dom.style.display = "none";
8280 Roo.Shadow.Pool.push(this.el);
8286 * Adjust the z-index of this shadow
8287 * @param {Number} zindex The new z-index
8289 setZIndex : function(z){
8292 this.el.setStyle("z-index", z);
8297 // Private utility class that manages the internal Shadow cache
8298 Roo.Shadow.Pool = function(){
8300 var markup = Roo.isIE ?
8301 '<div class="x-ie-shadow"></div>' :
8302 '<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>';
8307 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8308 sh.autoBoxAdjust = false;
8313 push : function(sh){
8319 * Ext JS Library 1.1.1
8320 * Copyright(c) 2006-2007, Ext JS, LLC.
8322 * Originally Released Under LGPL - original licence link has changed is not relivant.
8325 * <script type="text/javascript">
8329 * @class Roo.BoxComponent
8330 * @extends Roo.Component
8331 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8332 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8333 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8334 * layout containers.
8336 * @param {Roo.Element/String/Object} config The configuration options.
8338 Roo.BoxComponent = function(config){
8339 Roo.Component.call(this, config);
8343 * Fires after the component is resized.
8344 * @param {Roo.Component} this
8345 * @param {Number} adjWidth The box-adjusted width that was set
8346 * @param {Number} adjHeight The box-adjusted height that was set
8347 * @param {Number} rawWidth The width that was originally specified
8348 * @param {Number} rawHeight The height that was originally specified
8353 * Fires after the component is moved.
8354 * @param {Roo.Component} this
8355 * @param {Number} x The new x position
8356 * @param {Number} y The new y position
8362 Roo.extend(Roo.BoxComponent, Roo.Component, {
8363 // private, set in afterRender to signify that the component has been rendered
8365 // private, used to defer height settings to subclasses
8367 /** @cfg {Number} width
8368 * width (optional) size of component
8370 /** @cfg {Number} height
8371 * height (optional) size of component
8375 * Sets the width and height of the component. This method fires the resize event. This method can accept
8376 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8377 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8378 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8379 * @return {Roo.BoxComponent} this
8381 setSize : function(w, h){
8382 // support for standard size objects
8383 if(typeof w == 'object'){
8394 // prevent recalcs when not needed
8395 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8398 this.lastSize = {width: w, height: h};
8400 var adj = this.adjustSize(w, h);
8401 var aw = adj.width, ah = adj.height;
8402 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8403 var rz = this.getResizeEl();
8404 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8406 }else if(!this.deferHeight && ah !== undefined){
8408 }else if(aw !== undefined){
8411 this.onResize(aw, ah, w, h);
8412 this.fireEvent('resize', this, aw, ah, w, h);
8418 * Gets the current size of the component's underlying element.
8419 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8421 getSize : function(){
8422 return this.el.getSize();
8426 * Gets the current XY position of the component's underlying element.
8427 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8428 * @return {Array} The XY position of the element (e.g., [100, 200])
8430 getPosition : function(local){
8432 return [this.el.getLeft(true), this.el.getTop(true)];
8434 return this.xy || this.el.getXY();
8438 * Gets the current box measurements of the component's underlying element.
8439 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8440 * @returns {Object} box An object in the format {x, y, width, height}
8442 getBox : function(local){
8443 var s = this.el.getSize();
8445 s.x = this.el.getLeft(true);
8446 s.y = this.el.getTop(true);
8448 var xy = this.xy || this.el.getXY();
8456 * Sets the current box measurements of the component's underlying element.
8457 * @param {Object} box An object in the format {x, y, width, height}
8458 * @returns {Roo.BoxComponent} this
8460 updateBox : function(box){
8461 this.setSize(box.width, box.height);
8462 this.setPagePosition(box.x, box.y);
8467 getResizeEl : function(){
8468 return this.resizeEl || this.el;
8472 getPositionEl : function(){
8473 return this.positionEl || this.el;
8477 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8478 * This method fires the move event.
8479 * @param {Number} left The new left
8480 * @param {Number} top The new top
8481 * @returns {Roo.BoxComponent} this
8483 setPosition : function(x, y){
8489 var adj = this.adjustPosition(x, y);
8490 var ax = adj.x, ay = adj.y;
8492 var el = this.getPositionEl();
8493 if(ax !== undefined || ay !== undefined){
8494 if(ax !== undefined && ay !== undefined){
8495 el.setLeftTop(ax, ay);
8496 }else if(ax !== undefined){
8498 }else if(ay !== undefined){
8501 this.onPosition(ax, ay);
8502 this.fireEvent('move', this, ax, ay);
8508 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8509 * This method fires the move event.
8510 * @param {Number} x The new x position
8511 * @param {Number} y The new y position
8512 * @returns {Roo.BoxComponent} this
8514 setPagePosition : function(x, y){
8520 if(x === undefined || y === undefined){ // cannot translate undefined points
8523 var p = this.el.translatePoints(x, y);
8524 this.setPosition(p.left, p.top);
8529 onRender : function(ct, position){
8530 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8532 this.resizeEl = Roo.get(this.resizeEl);
8534 if(this.positionEl){
8535 this.positionEl = Roo.get(this.positionEl);
8540 afterRender : function(){
8541 Roo.BoxComponent.superclass.afterRender.call(this);
8542 this.boxReady = true;
8543 this.setSize(this.width, this.height);
8544 if(this.x || this.y){
8545 this.setPosition(this.x, this.y);
8547 if(this.pageX || this.pageY){
8548 this.setPagePosition(this.pageX, this.pageY);
8553 * Force the component's size to recalculate based on the underlying element's current height and width.
8554 * @returns {Roo.BoxComponent} this
8556 syncSize : function(){
8557 delete this.lastSize;
8558 this.setSize(this.el.getWidth(), this.el.getHeight());
8563 * Called after the component is resized, this method is empty by default but can be implemented by any
8564 * subclass that needs to perform custom logic after a resize occurs.
8565 * @param {Number} adjWidth The box-adjusted width that was set
8566 * @param {Number} adjHeight The box-adjusted height that was set
8567 * @param {Number} rawWidth The width that was originally specified
8568 * @param {Number} rawHeight The height that was originally specified
8570 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8575 * Called after the component is moved, this method is empty by default but can be implemented by any
8576 * subclass that needs to perform custom logic after a move occurs.
8577 * @param {Number} x The new x position
8578 * @param {Number} y The new y position
8580 onPosition : function(x, y){
8585 adjustSize : function(w, h){
8589 if(this.autoHeight){
8592 return {width : w, height: h};
8596 adjustPosition : function(x, y){
8597 return {x : x, y: y};
8601 * Ext JS Library 1.1.1
8602 * Copyright(c) 2006-2007, Ext JS, LLC.
8604 * Originally Released Under LGPL - original licence link has changed is not relivant.
8607 * <script type="text/javascript">
8612 * @class Roo.SplitBar
8613 * @extends Roo.util.Observable
8614 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8618 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8619 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8620 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8621 split.minSize = 100;
8622 split.maxSize = 600;
8623 split.animate = true;
8624 split.on('moved', splitterMoved);
8627 * Create a new SplitBar
8628 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8629 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8630 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8631 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8632 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8633 position of the SplitBar).
8635 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8638 this.el = Roo.get(dragElement, true);
8639 this.el.dom.unselectable = "on";
8641 this.resizingEl = Roo.get(resizingElement, true);
8645 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8646 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8649 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8652 * The minimum size of the resizing element. (Defaults to 0)
8658 * The maximum size of the resizing element. (Defaults to 2000)
8661 this.maxSize = 2000;
8664 * Whether to animate the transition to the new size
8667 this.animate = false;
8670 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8673 this.useShim = false;
8680 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8682 this.proxy = Roo.get(existingProxy).dom;
8685 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8688 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8691 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8694 this.dragSpecs = {};
8697 * @private The adapter to use to positon and resize elements
8699 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8700 this.adapter.init(this);
8702 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8704 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8705 this.el.addClass("x-splitbar-h");
8708 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8709 this.el.addClass("x-splitbar-v");
8715 * Fires when the splitter is moved (alias for {@link #event-moved})
8716 * @param {Roo.SplitBar} this
8717 * @param {Number} newSize the new width or height
8722 * Fires when the splitter is moved
8723 * @param {Roo.SplitBar} this
8724 * @param {Number} newSize the new width or height
8728 * @event beforeresize
8729 * Fires before the splitter is dragged
8730 * @param {Roo.SplitBar} this
8732 "beforeresize" : true,
8734 "beforeapply" : true
8737 Roo.util.Observable.call(this);
8740 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8741 onStartProxyDrag : function(x, y){
8742 this.fireEvent("beforeresize", this);
8744 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8746 o.enableDisplayMode("block");
8747 // all splitbars share the same overlay
8748 Roo.SplitBar.prototype.overlay = o;
8750 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8751 this.overlay.show();
8752 Roo.get(this.proxy).setDisplayed("block");
8753 var size = this.adapter.getElementSize(this);
8754 this.activeMinSize = this.getMinimumSize();;
8755 this.activeMaxSize = this.getMaximumSize();;
8756 var c1 = size - this.activeMinSize;
8757 var c2 = Math.max(this.activeMaxSize - size, 0);
8758 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8759 this.dd.resetConstraints();
8760 this.dd.setXConstraint(
8761 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8762 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8764 this.dd.setYConstraint(0, 0);
8766 this.dd.resetConstraints();
8767 this.dd.setXConstraint(0, 0);
8768 this.dd.setYConstraint(
8769 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8770 this.placement == Roo.SplitBar.TOP ? c2 : c1
8773 this.dragSpecs.startSize = size;
8774 this.dragSpecs.startPoint = [x, y];
8775 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8779 * @private Called after the drag operation by the DDProxy
8781 onEndProxyDrag : function(e){
8782 Roo.get(this.proxy).setDisplayed(false);
8783 var endPoint = Roo.lib.Event.getXY(e);
8785 this.overlay.hide();
8788 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8789 newSize = this.dragSpecs.startSize +
8790 (this.placement == Roo.SplitBar.LEFT ?
8791 endPoint[0] - this.dragSpecs.startPoint[0] :
8792 this.dragSpecs.startPoint[0] - endPoint[0]
8795 newSize = this.dragSpecs.startSize +
8796 (this.placement == Roo.SplitBar.TOP ?
8797 endPoint[1] - this.dragSpecs.startPoint[1] :
8798 this.dragSpecs.startPoint[1] - endPoint[1]
8801 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8802 if(newSize != this.dragSpecs.startSize){
8803 if(this.fireEvent('beforeapply', this, newSize) !== false){
8804 this.adapter.setElementSize(this, newSize);
8805 this.fireEvent("moved", this, newSize);
8806 this.fireEvent("resize", this, newSize);
8812 * Get the adapter this SplitBar uses
8813 * @return The adapter object
8815 getAdapter : function(){
8816 return this.adapter;
8820 * Set the adapter this SplitBar uses
8821 * @param {Object} adapter A SplitBar adapter object
8823 setAdapter : function(adapter){
8824 this.adapter = adapter;
8825 this.adapter.init(this);
8829 * Gets the minimum size for the resizing element
8830 * @return {Number} The minimum size
8832 getMinimumSize : function(){
8833 return this.minSize;
8837 * Sets the minimum size for the resizing element
8838 * @param {Number} minSize The minimum size
8840 setMinimumSize : function(minSize){
8841 this.minSize = minSize;
8845 * Gets the maximum size for the resizing element
8846 * @return {Number} The maximum size
8848 getMaximumSize : function(){
8849 return this.maxSize;
8853 * Sets the maximum size for the resizing element
8854 * @param {Number} maxSize The maximum size
8856 setMaximumSize : function(maxSize){
8857 this.maxSize = maxSize;
8861 * Sets the initialize size for the resizing element
8862 * @param {Number} size The initial size
8864 setCurrentSize : function(size){
8865 var oldAnimate = this.animate;
8866 this.animate = false;
8867 this.adapter.setElementSize(this, size);
8868 this.animate = oldAnimate;
8872 * Destroy this splitbar.
8873 * @param {Boolean} removeEl True to remove the element
8875 destroy : function(removeEl){
8880 this.proxy.parentNode.removeChild(this.proxy);
8888 * @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.
8890 Roo.SplitBar.createProxy = function(dir){
8891 var proxy = new Roo.Element(document.createElement("div"));
8892 proxy.unselectable();
8893 var cls = 'x-splitbar-proxy';
8894 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8895 document.body.appendChild(proxy.dom);
8900 * @class Roo.SplitBar.BasicLayoutAdapter
8901 * Default Adapter. It assumes the splitter and resizing element are not positioned
8902 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8904 Roo.SplitBar.BasicLayoutAdapter = function(){
8907 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8908 // do nothing for now
8913 * Called before drag operations to get the current size of the resizing element.
8914 * @param {Roo.SplitBar} s The SplitBar using this adapter
8916 getElementSize : function(s){
8917 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8918 return s.resizingEl.getWidth();
8920 return s.resizingEl.getHeight();
8925 * Called after drag operations to set the size of the resizing element.
8926 * @param {Roo.SplitBar} s The SplitBar using this adapter
8927 * @param {Number} newSize The new size to set
8928 * @param {Function} onComplete A function to be invoked when resizing is complete
8930 setElementSize : function(s, newSize, onComplete){
8931 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8933 s.resizingEl.setWidth(newSize);
8935 onComplete(s, newSize);
8938 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8943 s.resizingEl.setHeight(newSize);
8945 onComplete(s, newSize);
8948 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8955 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8956 * @extends Roo.SplitBar.BasicLayoutAdapter
8957 * Adapter that moves the splitter element to align with the resized sizing element.
8958 * Used with an absolute positioned SplitBar.
8959 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8960 * document.body, make sure you assign an id to the body element.
8962 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8963 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8964 this.container = Roo.get(container);
8967 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8972 getElementSize : function(s){
8973 return this.basic.getElementSize(s);
8976 setElementSize : function(s, newSize, onComplete){
8977 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8980 moveSplitter : function(s){
8981 var yes = Roo.SplitBar;
8982 switch(s.placement){
8984 s.el.setX(s.resizingEl.getRight());
8987 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
8990 s.el.setY(s.resizingEl.getBottom());
8993 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9000 * Orientation constant - Create a vertical SplitBar
9004 Roo.SplitBar.VERTICAL = 1;
9007 * Orientation constant - Create a horizontal SplitBar
9011 Roo.SplitBar.HORIZONTAL = 2;
9014 * Placement constant - The resizing element is to the left of the splitter element
9018 Roo.SplitBar.LEFT = 1;
9021 * Placement constant - The resizing element is to the right of the splitter element
9025 Roo.SplitBar.RIGHT = 2;
9028 * Placement constant - The resizing element is positioned above the splitter element
9032 Roo.SplitBar.TOP = 3;
9035 * Placement constant - The resizing element is positioned under splitter element
9039 Roo.SplitBar.BOTTOM = 4;
9042 * Ext JS Library 1.1.1
9043 * Copyright(c) 2006-2007, Ext JS, LLC.
9045 * Originally Released Under LGPL - original licence link has changed is not relivant.
9048 * <script type="text/javascript">
9053 * @extends Roo.util.Observable
9054 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9055 * This class also supports single and multi selection modes. <br>
9056 * Create a data model bound view:
9058 var store = new Roo.data.Store(...);
9060 var view = new Roo.View({
9062 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9065 selectedClass: "ydataview-selected",
9069 // listen for node click?
9070 view.on("click", function(vw, index, node, e){
9071 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9075 dataModel.load("foobar.xml");
9077 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9079 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9080 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9082 * Note: old style constructor is still suported (container, template, config)
9086 * @param {Object} config The config object
9089 Roo.View = function(config, depreciated_tpl, depreciated_config){
9091 if (typeof(depreciated_tpl) == 'undefined') {
9092 // new way.. - universal constructor.
9093 Roo.apply(this, config);
9094 this.el = Roo.get(this.el);
9097 this.el = Roo.get(config);
9098 this.tpl = depreciated_tpl;
9099 Roo.apply(this, depreciated_config);
9103 if(typeof(this.tpl) == "string"){
9104 this.tpl = new Roo.Template(this.tpl);
9106 // support xtype ctors..
9107 this.tpl = new Roo.factory(this.tpl, Roo);
9118 * @event beforeclick
9119 * Fires before a click is processed. Returns false to cancel the default action.
9120 * @param {Roo.View} this
9121 * @param {Number} index The index of the target node
9122 * @param {HTMLElement} node The target node
9123 * @param {Roo.EventObject} e The raw event object
9125 "beforeclick" : true,
9128 * Fires when a template node is clicked.
9129 * @param {Roo.View} this
9130 * @param {Number} index The index of the target node
9131 * @param {HTMLElement} node The target node
9132 * @param {Roo.EventObject} e The raw event object
9137 * Fires when a template node is double clicked.
9138 * @param {Roo.View} this
9139 * @param {Number} index The index of the target node
9140 * @param {HTMLElement} node The target node
9141 * @param {Roo.EventObject} e The raw event object
9145 * @event contextmenu
9146 * Fires when a template node is right clicked.
9147 * @param {Roo.View} this
9148 * @param {Number} index The index of the target node
9149 * @param {HTMLElement} node The target node
9150 * @param {Roo.EventObject} e The raw event object
9152 "contextmenu" : true,
9154 * @event selectionchange
9155 * Fires when the selected nodes change.
9156 * @param {Roo.View} this
9157 * @param {Array} selections Array of the selected nodes
9159 "selectionchange" : true,
9162 * @event beforeselect
9163 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9164 * @param {Roo.View} this
9165 * @param {HTMLElement} node The node to be selected
9166 * @param {Array} selections Array of currently selected nodes
9168 "beforeselect" : true
9172 "click": this.onClick,
9173 "dblclick": this.onDblClick,
9174 "contextmenu": this.onContextMenu,
9178 this.selections = [];
9180 this.cmp = new Roo.CompositeElementLite([]);
9182 this.store = Roo.factory(this.store, Roo.data);
9183 this.setStore(this.store, true);
9185 Roo.View.superclass.constructor.call(this);
9188 Roo.extend(Roo.View, Roo.util.Observable, {
9191 * @cfg {Roo.data.Store} store Data store to load data from.
9196 * @cfg {String|Roo.Element} el The container element.
9201 * @cfg {String|Roo.Template} tpl The template used by this View
9206 * @cfg {String} selectedClass The css class to add to selected nodes
9208 selectedClass : "x-view-selected",
9210 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9214 * @cfg {Boolean} multiSelect Allow multiple selection
9217 multiSelect : false,
9219 * @cfg {Boolean} singleSelect Allow single selection
9221 singleSelect: false,
9224 * Returns the element this view is bound to.
9225 * @return {Roo.Element}
9232 * Refreshes the view.
9234 refresh : function(){
9236 this.clearSelections();
9239 var records = this.store.getRange();
9240 if(records.length < 1){
9241 this.el.update(this.emptyText);
9244 for(var i = 0, len = records.length; i < len; i++){
9245 var data = this.prepareData(records[i].data, i, records[i]);
9246 html[html.length] = t.apply(data);
9248 this.el.update(html.join(""));
9249 this.nodes = this.el.dom.childNodes;
9250 this.updateIndexes(0);
9254 * Function to override to reformat the data that is sent to
9255 * the template for each node.
9256 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9257 * a JSON object for an UpdateManager bound view).
9259 prepareData : function(data){
9263 onUpdate : function(ds, record){
9264 this.clearSelections();
9265 var index = this.store.indexOf(record);
9266 var n = this.nodes[index];
9267 this.tpl.insertBefore(n, this.prepareData(record.data));
9268 n.parentNode.removeChild(n);
9269 this.updateIndexes(index, index);
9272 onAdd : function(ds, records, index){
9273 this.clearSelections();
9274 if(this.nodes.length == 0){
9278 var n = this.nodes[index];
9279 for(var i = 0, len = records.length; i < len; i++){
9280 var d = this.prepareData(records[i].data);
9282 this.tpl.insertBefore(n, d);
9284 this.tpl.append(this.el, d);
9287 this.updateIndexes(index);
9290 onRemove : function(ds, record, index){
9291 this.clearSelections();
9292 this.el.dom.removeChild(this.nodes[index]);
9293 this.updateIndexes(index);
9297 * Refresh an individual node.
9298 * @param {Number} index
9300 refreshNode : function(index){
9301 this.onUpdate(this.store, this.store.getAt(index));
9304 updateIndexes : function(startIndex, endIndex){
9305 var ns = this.nodes;
9306 startIndex = startIndex || 0;
9307 endIndex = endIndex || ns.length - 1;
9308 for(var i = startIndex; i <= endIndex; i++){
9309 ns[i].nodeIndex = i;
9314 * Changes the data store this view uses and refresh the view.
9315 * @param {Store} store
9317 setStore : function(store, initial){
9318 if(!initial && this.store){
9319 this.store.un("datachanged", this.refresh);
9320 this.store.un("add", this.onAdd);
9321 this.store.un("remove", this.onRemove);
9322 this.store.un("update", this.onUpdate);
9323 this.store.un("clear", this.refresh);
9327 store.on("datachanged", this.refresh, this);
9328 store.on("add", this.onAdd, this);
9329 store.on("remove", this.onRemove, this);
9330 store.on("update", this.onUpdate, this);
9331 store.on("clear", this.refresh, this);
9340 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9341 * @param {HTMLElement} node
9342 * @return {HTMLElement} The template node
9344 findItemFromChild : function(node){
9345 var el = this.el.dom;
9346 if(!node || node.parentNode == el){
9349 var p = node.parentNode;
9350 while(p && p != el){
9351 if(p.parentNode == el){
9360 onClick : function(e){
9361 var item = this.findItemFromChild(e.getTarget());
9363 var index = this.indexOf(item);
9364 if(this.onItemClick(item, index, e) !== false){
9365 this.fireEvent("click", this, index, item, e);
9368 this.clearSelections();
9373 onContextMenu : function(e){
9374 var item = this.findItemFromChild(e.getTarget());
9376 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9381 onDblClick : function(e){
9382 var item = this.findItemFromChild(e.getTarget());
9384 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9388 onItemClick : function(item, index, e){
9389 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9392 if(this.multiSelect || this.singleSelect){
9393 if(this.multiSelect && e.shiftKey && this.lastSelection){
9394 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9396 this.select(item, this.multiSelect && e.ctrlKey);
9397 this.lastSelection = item;
9405 * Get the number of selected nodes.
9408 getSelectionCount : function(){
9409 return this.selections.length;
9413 * Get the currently selected nodes.
9414 * @return {Array} An array of HTMLElements
9416 getSelectedNodes : function(){
9417 return this.selections;
9421 * Get the indexes of the selected nodes.
9424 getSelectedIndexes : function(){
9425 var indexes = [], s = this.selections;
9426 for(var i = 0, len = s.length; i < len; i++){
9427 indexes.push(s[i].nodeIndex);
9433 * Clear all selections
9434 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9436 clearSelections : function(suppressEvent){
9437 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9438 this.cmp.elements = this.selections;
9439 this.cmp.removeClass(this.selectedClass);
9440 this.selections = [];
9442 this.fireEvent("selectionchange", this, this.selections);
9448 * Returns true if the passed node is selected
9449 * @param {HTMLElement/Number} node The node or node index
9452 isSelected : function(node){
9453 var s = this.selections;
9457 node = this.getNode(node);
9458 return s.indexOf(node) !== -1;
9463 * @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
9464 * @param {Boolean} keepExisting (optional) true to keep existing selections
9465 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9467 select : function(nodeInfo, keepExisting, suppressEvent){
9468 if(nodeInfo instanceof Array){
9470 this.clearSelections(true);
9472 for(var i = 0, len = nodeInfo.length; i < len; i++){
9473 this.select(nodeInfo[i], true, true);
9476 var node = this.getNode(nodeInfo);
9477 if(node && !this.isSelected(node)){
9479 this.clearSelections(true);
9481 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9482 Roo.fly(node).addClass(this.selectedClass);
9483 this.selections.push(node);
9485 this.fireEvent("selectionchange", this, this.selections);
9493 * Gets a template node.
9494 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9495 * @return {HTMLElement} The node or null if it wasn't found
9497 getNode : function(nodeInfo){
9498 if(typeof nodeInfo == "string"){
9499 return document.getElementById(nodeInfo);
9500 }else if(typeof nodeInfo == "number"){
9501 return this.nodes[nodeInfo];
9507 * Gets a range template nodes.
9508 * @param {Number} startIndex
9509 * @param {Number} endIndex
9510 * @return {Array} An array of nodes
9512 getNodes : function(start, end){
9513 var ns = this.nodes;
9515 end = typeof end == "undefined" ? ns.length - 1 : end;
9518 for(var i = start; i <= end; i++){
9522 for(var i = start; i >= end; i--){
9530 * Finds the index of the passed node
9531 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9532 * @return {Number} The index of the node or -1
9534 indexOf : function(node){
9535 node = this.getNode(node);
9536 if(typeof node.nodeIndex == "number"){
9537 return node.nodeIndex;
9539 var ns = this.nodes;
9540 for(var i = 0, len = ns.length; i < len; i++){
9550 * Ext JS Library 1.1.1
9551 * Copyright(c) 2006-2007, Ext JS, LLC.
9553 * Originally Released Under LGPL - original licence link has changed is not relivant.
9556 * <script type="text/javascript">
9560 * @class Roo.JsonView
9562 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9564 var view = new Roo.JsonView({
9565 container: "my-element",
9566 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9571 // listen for node click?
9572 view.on("click", function(vw, index, node, e){
9573 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9576 // direct load of JSON data
9577 view.load("foobar.php");
9579 // Example from my blog list
9580 var tpl = new Roo.Template(
9581 '<div class="entry">' +
9582 '<a class="entry-title" href="{link}">{title}</a>' +
9583 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9584 "</div><hr />"
9587 var moreView = new Roo.JsonView({
9588 container : "entry-list",
9592 moreView.on("beforerender", this.sortEntries, this);
9594 url: "/blog/get-posts.php",
9595 params: "allposts=true",
9596 text: "Loading Blog Entries..."
9600 * Note: old code is supported with arguments : (container, template, config)
9604 * Create a new JsonView
9606 * @param {Object} config The config object
9609 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9612 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9614 var um = this.el.getUpdateManager();
9615 um.setRenderer(this);
9616 um.on("update", this.onLoad, this);
9617 um.on("failure", this.onLoadException, this);
9620 * @event beforerender
9621 * Fires before rendering of the downloaded JSON data.
9622 * @param {Roo.JsonView} this
9623 * @param {Object} data The JSON data loaded
9627 * Fires when data is loaded.
9628 * @param {Roo.JsonView} this
9629 * @param {Object} data The JSON data loaded
9630 * @param {Object} response The raw Connect response object
9633 * @event loadexception
9634 * Fires when loading fails.
9635 * @param {Roo.JsonView} this
9636 * @param {Object} response The raw Connect response object
9639 'beforerender' : true,
9641 'loadexception' : true
9644 Roo.extend(Roo.JsonView, Roo.View, {
9646 * @type {String} The root property in the loaded JSON object that contains the data
9651 * Refreshes the view.
9653 refresh : function(){
9654 this.clearSelections();
9657 var o = this.jsonData;
9658 if(o && o.length > 0){
9659 for(var i = 0, len = o.length; i < len; i++){
9660 var data = this.prepareData(o[i], i, o);
9661 html[html.length] = this.tpl.apply(data);
9664 html.push(this.emptyText);
9666 this.el.update(html.join(""));
9667 this.nodes = this.el.dom.childNodes;
9668 this.updateIndexes(0);
9672 * 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.
9673 * @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:
9676 url: "your-url.php",
9677 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9678 callback: yourFunction,
9679 scope: yourObject, //(optional scope)
9687 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9688 * 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.
9689 * @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}
9690 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9691 * @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.
9694 var um = this.el.getUpdateManager();
9695 um.update.apply(um, arguments);
9698 render : function(el, response){
9699 this.clearSelections();
9703 o = Roo.util.JSON.decode(response.responseText);
9706 o = o[this.jsonRoot];
9711 * The current JSON data or null
9714 this.beforeRender();
9719 * Get the number of records in the current JSON dataset
9722 getCount : function(){
9723 return this.jsonData ? this.jsonData.length : 0;
9727 * Returns the JSON object for the specified node(s)
9728 * @param {HTMLElement/Array} node The node or an array of nodes
9729 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9730 * you get the JSON object for the node
9732 getNodeData : function(node){
9733 if(node instanceof Array){
9735 for(var i = 0, len = node.length; i < len; i++){
9736 data.push(this.getNodeData(node[i]));
9740 return this.jsonData[this.indexOf(node)] || null;
9743 beforeRender : function(){
9744 this.snapshot = this.jsonData;
9746 this.sort.apply(this, this.sortInfo);
9748 this.fireEvent("beforerender", this, this.jsonData);
9751 onLoad : function(el, o){
9752 this.fireEvent("load", this, this.jsonData, o);
9755 onLoadException : function(el, o){
9756 this.fireEvent("loadexception", this, o);
9760 * Filter the data by a specific property.
9761 * @param {String} property A property on your JSON objects
9762 * @param {String/RegExp} value Either string that the property values
9763 * should start with, or a RegExp to test against the property
9765 filter : function(property, value){
9768 var ss = this.snapshot;
9769 if(typeof value == "string"){
9770 var vlen = value.length;
9775 value = value.toLowerCase();
9776 for(var i = 0, len = ss.length; i < len; i++){
9778 if(o[property].substr(0, vlen).toLowerCase() == value){
9782 } else if(value.exec){ // regex?
9783 for(var i = 0, len = ss.length; i < len; i++){
9785 if(value.test(o[property])){
9792 this.jsonData = data;
9798 * Filter by a function. The passed function will be called with each
9799 * object in the current dataset. If the function returns true the value is kept,
9800 * otherwise it is filtered.
9801 * @param {Function} fn
9802 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9804 filterBy : function(fn, scope){
9807 var ss = this.snapshot;
9808 for(var i = 0, len = ss.length; i < len; i++){
9810 if(fn.call(scope || this, o)){
9814 this.jsonData = data;
9820 * Clears the current filter.
9822 clearFilter : function(){
9823 if(this.snapshot && this.jsonData != this.snapshot){
9824 this.jsonData = this.snapshot;
9831 * Sorts the data for this view and refreshes it.
9832 * @param {String} property A property on your JSON objects to sort on
9833 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9834 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9836 sort : function(property, dir, sortType){
9837 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9840 var dsc = dir && dir.toLowerCase() == "desc";
9841 var f = function(o1, o2){
9842 var v1 = sortType ? sortType(o1[p]) : o1[p];
9843 var v2 = sortType ? sortType(o2[p]) : o2[p];
9846 return dsc ? +1 : -1;
9848 return dsc ? -1 : +1;
9853 this.jsonData.sort(f);
9855 if(this.jsonData != this.snapshot){
9856 this.snapshot.sort(f);
9862 * Ext JS Library 1.1.1
9863 * Copyright(c) 2006-2007, Ext JS, LLC.
9865 * Originally Released Under LGPL - original licence link has changed is not relivant.
9868 * <script type="text/javascript">
9873 * @class Roo.ColorPalette
9874 * @extends Roo.Component
9875 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9876 * Here's an example of typical usage:
9878 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9879 cp.render('my-div');
9881 cp.on('select', function(palette, selColor){
9882 // do something with selColor
9886 * Create a new ColorPalette
9887 * @param {Object} config The config object
9889 Roo.ColorPalette = function(config){
9890 Roo.ColorPalette.superclass.constructor.call(this, config);
9894 * Fires when a color is selected
9895 * @param {ColorPalette} this
9896 * @param {String} color The 6-digit color hex code (without the # symbol)
9902 this.on("select", this.handler, this.scope, true);
9905 Roo.extend(Roo.ColorPalette, Roo.Component, {
9907 * @cfg {String} itemCls
9908 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9910 itemCls : "x-color-palette",
9912 * @cfg {String} value
9913 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9914 * the hex codes are case-sensitive.
9919 ctype: "Roo.ColorPalette",
9922 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9924 allowReselect : false,
9927 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9928 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9929 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9930 * of colors with the width setting until the box is symmetrical.</p>
9931 * <p>You can override individual colors if needed:</p>
9933 var cp = new Roo.ColorPalette();
9934 cp.colors[0] = "FF0000"; // change the first box to red
9937 Or you can provide a custom array of your own for complete control:
9939 var cp = new Roo.ColorPalette();
9940 cp.colors = ["000000", "993300", "333300"];
9945 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9946 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9947 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9948 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9949 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9953 onRender : function(container, position){
9954 var t = new Roo.MasterTemplate(
9955 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9957 var c = this.colors;
9958 for(var i = 0, len = c.length; i < len; i++){
9961 var el = document.createElement("div");
9962 el.className = this.itemCls;
9964 container.dom.insertBefore(el, position);
9965 this.el = Roo.get(el);
9966 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9967 if(this.clickEvent != 'click'){
9968 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9973 afterRender : function(){
9974 Roo.ColorPalette.superclass.afterRender.call(this);
9983 handleClick : function(e, t){
9986 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9987 this.select(c.toUpperCase());
9992 * Selects the specified color in the palette (fires the select event)
9993 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
9995 select : function(color){
9996 color = color.replace("#", "");
9997 if(color != this.value || this.allowReselect){
10000 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10002 el.child("a.color-"+color).addClass("x-color-palette-sel");
10003 this.value = color;
10004 this.fireEvent("select", this, color);
10009 * Ext JS Library 1.1.1
10010 * Copyright(c) 2006-2007, Ext JS, LLC.
10012 * Originally Released Under LGPL - original licence link has changed is not relivant.
10015 * <script type="text/javascript">
10019 * @class Roo.DatePicker
10020 * @extends Roo.Component
10021 * Simple date picker class.
10023 * Create a new DatePicker
10024 * @param {Object} config The config object
10026 Roo.DatePicker = function(config){
10027 Roo.DatePicker.superclass.constructor.call(this, config);
10029 this.value = config && config.value ?
10030 config.value.clearTime() : new Date().clearTime();
10035 * Fires when a date is selected
10036 * @param {DatePicker} this
10037 * @param {Date} date The selected date
10043 this.on("select", this.handler, this.scope || this);
10045 // build the disabledDatesRE
10046 if(!this.disabledDatesRE && this.disabledDates){
10047 var dd = this.disabledDates;
10049 for(var i = 0; i < dd.length; i++){
10051 if(i != dd.length-1) re += "|";
10053 this.disabledDatesRE = new RegExp(re + ")");
10057 Roo.extend(Roo.DatePicker, Roo.Component, {
10059 * @cfg {String} todayText
10060 * The text to display on the button that selects the current date (defaults to "Today")
10062 todayText : "Today",
10064 * @cfg {String} okText
10065 * The text to display on the ok button
10067 okText : " OK ", //   to give the user extra clicking room
10069 * @cfg {String} cancelText
10070 * The text to display on the cancel button
10072 cancelText : "Cancel",
10074 * @cfg {String} todayTip
10075 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10077 todayTip : "{0} (Spacebar)",
10079 * @cfg {Date} minDate
10080 * Minimum allowable date (JavaScript date object, defaults to null)
10084 * @cfg {Date} maxDate
10085 * Maximum allowable date (JavaScript date object, defaults to null)
10089 * @cfg {String} minText
10090 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10092 minText : "This date is before the minimum date",
10094 * @cfg {String} maxText
10095 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10097 maxText : "This date is after the maximum date",
10099 * @cfg {String} format
10100 * The default date format string which can be overriden for localization support. The format must be
10101 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10105 * @cfg {Array} disabledDays
10106 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10108 disabledDays : null,
10110 * @cfg {String} disabledDaysText
10111 * The tooltip to display when the date falls on a disabled day (defaults to "")
10113 disabledDaysText : "",
10115 * @cfg {RegExp} disabledDatesRE
10116 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10118 disabledDatesRE : null,
10120 * @cfg {String} disabledDatesText
10121 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10123 disabledDatesText : "",
10125 * @cfg {Boolean} constrainToViewport
10126 * True to constrain the date picker to the viewport (defaults to true)
10128 constrainToViewport : true,
10130 * @cfg {Array} monthNames
10131 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10133 monthNames : Date.monthNames,
10135 * @cfg {Array} dayNames
10136 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10138 dayNames : Date.dayNames,
10140 * @cfg {String} nextText
10141 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10143 nextText: 'Next Month (Control+Right)',
10145 * @cfg {String} prevText
10146 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10148 prevText: 'Previous Month (Control+Left)',
10150 * @cfg {String} monthYearText
10151 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10153 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10155 * @cfg {Number} startDay
10156 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10160 * @cfg {Bool} showClear
10161 * Show a clear button (usefull for date form elements that can be blank.)
10167 * Sets the value of the date field
10168 * @param {Date} value The date to set
10170 setValue : function(value){
10171 var old = this.value;
10172 this.value = value.clearTime(true);
10174 this.update(this.value);
10179 * Gets the current selected value of the date field
10180 * @return {Date} The selected date
10182 getValue : function(){
10187 focus : function(){
10189 this.update(this.activeDate);
10194 onRender : function(container, position){
10196 '<table cellspacing="0">',
10197 '<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>',
10198 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10199 var dn = this.dayNames;
10200 for(var i = 0; i < 7; i++){
10201 var d = this.startDay+i;
10205 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10207 m[m.length] = "</tr></thead><tbody><tr>";
10208 for(var i = 0; i < 42; i++) {
10209 if(i % 7 == 0 && i != 0){
10210 m[m.length] = "</tr><tr>";
10212 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10214 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10215 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10217 var el = document.createElement("div");
10218 el.className = "x-date-picker";
10219 el.innerHTML = m.join("");
10221 container.dom.insertBefore(el, position);
10223 this.el = Roo.get(el);
10224 this.eventEl = Roo.get(el.firstChild);
10226 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10227 handler: this.showPrevMonth,
10229 preventDefault:true,
10233 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10234 handler: this.showNextMonth,
10236 preventDefault:true,
10240 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10242 this.monthPicker = this.el.down('div.x-date-mp');
10243 this.monthPicker.enableDisplayMode('block');
10245 var kn = new Roo.KeyNav(this.eventEl, {
10246 "left" : function(e){
10248 this.showPrevMonth() :
10249 this.update(this.activeDate.add("d", -1));
10252 "right" : function(e){
10254 this.showNextMonth() :
10255 this.update(this.activeDate.add("d", 1));
10258 "up" : function(e){
10260 this.showNextYear() :
10261 this.update(this.activeDate.add("d", -7));
10264 "down" : function(e){
10266 this.showPrevYear() :
10267 this.update(this.activeDate.add("d", 7));
10270 "pageUp" : function(e){
10271 this.showNextMonth();
10274 "pageDown" : function(e){
10275 this.showPrevMonth();
10278 "enter" : function(e){
10279 e.stopPropagation();
10286 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10288 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10290 this.el.unselectable();
10292 this.cells = this.el.select("table.x-date-inner tbody td");
10293 this.textNodes = this.el.query("table.x-date-inner tbody span");
10295 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10297 tooltip: this.monthYearText
10300 this.mbtn.on('click', this.showMonthPicker, this);
10301 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10304 var today = (new Date()).dateFormat(this.format);
10306 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10307 if (this.showClear) {
10308 baseTb.add( new Roo.Toolbar.Fill());
10311 text: String.format(this.todayText, today),
10312 tooltip: String.format(this.todayTip, today),
10313 handler: this.selectToday,
10317 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10320 if (this.showClear) {
10322 baseTb.add( new Roo.Toolbar.Fill());
10325 cls: 'x-btn-icon x-btn-clear',
10326 handler: function() {
10328 this.fireEvent("select", this, '');
10338 this.update(this.value);
10341 createMonthPicker : function(){
10342 if(!this.monthPicker.dom.firstChild){
10343 var buf = ['<table border="0" cellspacing="0">'];
10344 for(var i = 0; i < 6; i++){
10346 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10347 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10349 '<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>' :
10350 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10354 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10356 '</button><button type="button" class="x-date-mp-cancel">',
10358 '</button></td></tr>',
10361 this.monthPicker.update(buf.join(''));
10362 this.monthPicker.on('click', this.onMonthClick, this);
10363 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10365 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10366 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10368 this.mpMonths.each(function(m, a, i){
10371 m.dom.xmonth = 5 + Math.round(i * .5);
10373 m.dom.xmonth = Math.round((i-1) * .5);
10379 showMonthPicker : function(){
10380 this.createMonthPicker();
10381 var size = this.el.getSize();
10382 this.monthPicker.setSize(size);
10383 this.monthPicker.child('table').setSize(size);
10385 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10386 this.updateMPMonth(this.mpSelMonth);
10387 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10388 this.updateMPYear(this.mpSelYear);
10390 this.monthPicker.slideIn('t', {duration:.2});
10393 updateMPYear : function(y){
10395 var ys = this.mpYears.elements;
10396 for(var i = 1; i <= 10; i++){
10397 var td = ys[i-1], y2;
10399 y2 = y + Math.round(i * .5);
10400 td.firstChild.innerHTML = y2;
10403 y2 = y - (5-Math.round(i * .5));
10404 td.firstChild.innerHTML = y2;
10407 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10411 updateMPMonth : function(sm){
10412 this.mpMonths.each(function(m, a, i){
10413 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10417 selectMPMonth: function(m){
10421 onMonthClick : function(e, t){
10423 var el = new Roo.Element(t), pn;
10424 if(el.is('button.x-date-mp-cancel')){
10425 this.hideMonthPicker();
10427 else if(el.is('button.x-date-mp-ok')){
10428 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10429 this.hideMonthPicker();
10431 else if(pn = el.up('td.x-date-mp-month', 2)){
10432 this.mpMonths.removeClass('x-date-mp-sel');
10433 pn.addClass('x-date-mp-sel');
10434 this.mpSelMonth = pn.dom.xmonth;
10436 else if(pn = el.up('td.x-date-mp-year', 2)){
10437 this.mpYears.removeClass('x-date-mp-sel');
10438 pn.addClass('x-date-mp-sel');
10439 this.mpSelYear = pn.dom.xyear;
10441 else if(el.is('a.x-date-mp-prev')){
10442 this.updateMPYear(this.mpyear-10);
10444 else if(el.is('a.x-date-mp-next')){
10445 this.updateMPYear(this.mpyear+10);
10449 onMonthDblClick : function(e, t){
10451 var el = new Roo.Element(t), pn;
10452 if(pn = el.up('td.x-date-mp-month', 2)){
10453 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10454 this.hideMonthPicker();
10456 else if(pn = el.up('td.x-date-mp-year', 2)){
10457 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10458 this.hideMonthPicker();
10462 hideMonthPicker : function(disableAnim){
10463 if(this.monthPicker){
10464 if(disableAnim === true){
10465 this.monthPicker.hide();
10467 this.monthPicker.slideOut('t', {duration:.2});
10473 showPrevMonth : function(e){
10474 this.update(this.activeDate.add("mo", -1));
10478 showNextMonth : function(e){
10479 this.update(this.activeDate.add("mo", 1));
10483 showPrevYear : function(){
10484 this.update(this.activeDate.add("y", -1));
10488 showNextYear : function(){
10489 this.update(this.activeDate.add("y", 1));
10493 handleMouseWheel : function(e){
10494 var delta = e.getWheelDelta();
10496 this.showPrevMonth();
10498 } else if(delta < 0){
10499 this.showNextMonth();
10505 handleDateClick : function(e, t){
10507 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10508 this.setValue(new Date(t.dateValue));
10509 this.fireEvent("select", this, this.value);
10514 selectToday : function(){
10515 this.setValue(new Date().clearTime());
10516 this.fireEvent("select", this, this.value);
10520 update : function(date){
10521 var vd = this.activeDate;
10522 this.activeDate = date;
10524 var t = date.getTime();
10525 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10526 this.cells.removeClass("x-date-selected");
10527 this.cells.each(function(c){
10528 if(c.dom.firstChild.dateValue == t){
10529 c.addClass("x-date-selected");
10530 setTimeout(function(){
10531 try{c.dom.firstChild.focus();}catch(e){}
10539 var days = date.getDaysInMonth();
10540 var firstOfMonth = date.getFirstDateOfMonth();
10541 var startingPos = firstOfMonth.getDay()-this.startDay;
10543 if(startingPos <= this.startDay){
10547 var pm = date.add("mo", -1);
10548 var prevStart = pm.getDaysInMonth()-startingPos;
10550 var cells = this.cells.elements;
10551 var textEls = this.textNodes;
10552 days += startingPos;
10554 // convert everything to numbers so it's fast
10555 var day = 86400000;
10556 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10557 var today = new Date().clearTime().getTime();
10558 var sel = date.clearTime().getTime();
10559 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10560 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10561 var ddMatch = this.disabledDatesRE;
10562 var ddText = this.disabledDatesText;
10563 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10564 var ddaysText = this.disabledDaysText;
10565 var format = this.format;
10567 var setCellClass = function(cal, cell){
10569 var t = d.getTime();
10570 cell.firstChild.dateValue = t;
10572 cell.className += " x-date-today";
10573 cell.title = cal.todayText;
10576 cell.className += " x-date-selected";
10577 setTimeout(function(){
10578 try{cell.firstChild.focus();}catch(e){}
10583 cell.className = " x-date-disabled";
10584 cell.title = cal.minText;
10588 cell.className = " x-date-disabled";
10589 cell.title = cal.maxText;
10593 if(ddays.indexOf(d.getDay()) != -1){
10594 cell.title = ddaysText;
10595 cell.className = " x-date-disabled";
10598 if(ddMatch && format){
10599 var fvalue = d.dateFormat(format);
10600 if(ddMatch.test(fvalue)){
10601 cell.title = ddText.replace("%0", fvalue);
10602 cell.className = " x-date-disabled";
10608 for(; i < startingPos; i++) {
10609 textEls[i].innerHTML = (++prevStart);
10610 d.setDate(d.getDate()+1);
10611 cells[i].className = "x-date-prevday";
10612 setCellClass(this, cells[i]);
10614 for(; i < days; i++){
10615 intDay = i - startingPos + 1;
10616 textEls[i].innerHTML = (intDay);
10617 d.setDate(d.getDate()+1);
10618 cells[i].className = "x-date-active";
10619 setCellClass(this, cells[i]);
10622 for(; i < 42; i++) {
10623 textEls[i].innerHTML = (++extraDays);
10624 d.setDate(d.getDate()+1);
10625 cells[i].className = "x-date-nextday";
10626 setCellClass(this, cells[i]);
10629 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10631 if(!this.internalRender){
10632 var main = this.el.dom.firstChild;
10633 var w = main.offsetWidth;
10634 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10635 Roo.fly(main).setWidth(w);
10636 this.internalRender = true;
10637 // opera does not respect the auto grow header center column
10638 // then, after it gets a width opera refuses to recalculate
10639 // without a second pass
10640 if(Roo.isOpera && !this.secondPass){
10641 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10642 this.secondPass = true;
10643 this.update.defer(10, this, [date]);
10649 * Ext JS Library 1.1.1
10650 * Copyright(c) 2006-2007, Ext JS, LLC.
10652 * Originally Released Under LGPL - original licence link has changed is not relivant.
10655 * <script type="text/javascript">
10658 * @class Roo.TabPanel
10659 * @extends Roo.util.Observable
10660 * A lightweight tab container.
10664 // basic tabs 1, built from existing content
10665 var tabs = new Roo.TabPanel("tabs1");
10666 tabs.addTab("script", "View Script");
10667 tabs.addTab("markup", "View Markup");
10668 tabs.activate("script");
10670 // more advanced tabs, built from javascript
10671 var jtabs = new Roo.TabPanel("jtabs");
10672 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10674 // set up the UpdateManager
10675 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10676 var updater = tab2.getUpdateManager();
10677 updater.setDefaultUrl("ajax1.htm");
10678 tab2.on('activate', updater.refresh, updater, true);
10680 // Use setUrl for Ajax loading
10681 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10682 tab3.setUrl("ajax2.htm", null, true);
10685 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10688 jtabs.activate("jtabs-1");
10691 * Create a new TabPanel.
10692 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10693 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10695 Roo.TabPanel = function(container, config){
10697 * The container element for this TabPanel.
10698 * @type Roo.Element
10700 this.el = Roo.get(container, true);
10702 if(typeof config == "boolean"){
10703 this.tabPosition = config ? "bottom" : "top";
10705 Roo.apply(this, config);
10708 if(this.tabPosition == "bottom"){
10709 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10710 this.el.addClass("x-tabs-bottom");
10712 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10713 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10714 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10716 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10718 if(this.tabPosition != "bottom"){
10719 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10720 * @type Roo.Element
10722 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10723 this.el.addClass("x-tabs-top");
10727 this.bodyEl.setStyle("position", "relative");
10729 this.active = null;
10730 this.activateDelegate = this.activate.createDelegate(this);
10735 * Fires when the active tab changes
10736 * @param {Roo.TabPanel} this
10737 * @param {Roo.TabPanelItem} activePanel The new active tab
10741 * @event beforetabchange
10742 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10743 * @param {Roo.TabPanel} this
10744 * @param {Object} e Set cancel to true on this object to cancel the tab change
10745 * @param {Roo.TabPanelItem} tab The tab being changed to
10747 "beforetabchange" : true
10750 Roo.EventManager.onWindowResize(this.onResize, this);
10751 this.cpad = this.el.getPadding("lr");
10752 this.hiddenCount = 0;
10754 Roo.TabPanel.superclass.constructor.call(this);
10757 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10759 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10761 tabPosition : "top",
10763 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10765 currentTabWidth : 0,
10767 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10771 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10775 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10777 preferredTabWidth : 175,
10779 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10781 resizeTabs : false,
10783 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10785 monitorResize : true,
10788 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10789 * @param {String} id The id of the div to use <b>or create</b>
10790 * @param {String} text The text for the tab
10791 * @param {String} content (optional) Content to put in the TabPanelItem body
10792 * @param {Boolean} closable (optional) True to create a close icon on the tab
10793 * @return {Roo.TabPanelItem} The created TabPanelItem
10795 addTab : function(id, text, content, closable){
10796 var item = new Roo.TabPanelItem(this, id, text, closable);
10797 this.addTabItem(item);
10799 item.setContent(content);
10805 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10806 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10807 * @return {Roo.TabPanelItem}
10809 getTab : function(id){
10810 return this.items[id];
10814 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10815 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10817 hideTab : function(id){
10818 var t = this.items[id];
10821 this.hiddenCount++;
10822 this.autoSizeTabs();
10827 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10828 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10830 unhideTab : function(id){
10831 var t = this.items[id];
10833 t.setHidden(false);
10834 this.hiddenCount--;
10835 this.autoSizeTabs();
10840 * Adds an existing {@link Roo.TabPanelItem}.
10841 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10843 addTabItem : function(item){
10844 this.items[item.id] = item;
10845 this.items.push(item);
10846 if(this.resizeTabs){
10847 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10848 this.autoSizeTabs();
10855 * Removes a {@link Roo.TabPanelItem}.
10856 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10858 removeTab : function(id){
10859 var items = this.items;
10860 var tab = items[id];
10861 if(!tab) { return; }
10862 var index = items.indexOf(tab);
10863 if(this.active == tab && items.length > 1){
10864 var newTab = this.getNextAvailable(index);
10869 this.stripEl.dom.removeChild(tab.pnode.dom);
10870 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10871 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10873 items.splice(index, 1);
10874 delete this.items[tab.id];
10875 tab.fireEvent("close", tab);
10876 tab.purgeListeners();
10877 this.autoSizeTabs();
10880 getNextAvailable : function(start){
10881 var items = this.items;
10883 // look for a next tab that will slide over to
10884 // replace the one being removed
10885 while(index < items.length){
10886 var item = items[++index];
10887 if(item && !item.isHidden()){
10891 // if one isn't found select the previous tab (on the left)
10894 var item = items[--index];
10895 if(item && !item.isHidden()){
10903 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10904 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10906 disableTab : function(id){
10907 var tab = this.items[id];
10908 if(tab && this.active != tab){
10914 * Enables a {@link Roo.TabPanelItem} that is disabled.
10915 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10917 enableTab : function(id){
10918 var tab = this.items[id];
10923 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10924 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10925 * @return {Roo.TabPanelItem} The TabPanelItem.
10927 activate : function(id){
10928 var tab = this.items[id];
10932 if(tab == this.active || tab.disabled){
10936 this.fireEvent("beforetabchange", this, e, tab);
10937 if(e.cancel !== true && !tab.disabled){
10939 this.active.hide();
10941 this.active = this.items[id];
10942 this.active.show();
10943 this.fireEvent("tabchange", this, this.active);
10949 * Gets the active {@link Roo.TabPanelItem}.
10950 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10952 getActiveTab : function(){
10953 return this.active;
10957 * Updates the tab body element to fit the height of the container element
10958 * for overflow scrolling
10959 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10961 syncHeight : function(targetHeight){
10962 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10963 var bm = this.bodyEl.getMargins();
10964 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10965 this.bodyEl.setHeight(newHeight);
10969 onResize : function(){
10970 if(this.monitorResize){
10971 this.autoSizeTabs();
10976 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10978 beginUpdate : function(){
10979 this.updating = true;
10983 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10985 endUpdate : function(){
10986 this.updating = false;
10987 this.autoSizeTabs();
10991 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
10993 autoSizeTabs : function(){
10994 var count = this.items.length;
10995 var vcount = count - this.hiddenCount;
10996 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
10997 var w = Math.max(this.el.getWidth() - this.cpad, 10);
10998 var availWidth = Math.floor(w / vcount);
10999 var b = this.stripBody;
11000 if(b.getWidth() > w){
11001 var tabs = this.items;
11002 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11003 if(availWidth < this.minTabWidth){
11004 /*if(!this.sleft){ // incomplete scrolling code
11005 this.createScrollButtons();
11008 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11011 if(this.currentTabWidth < this.preferredTabWidth){
11012 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11018 * Returns the number of tabs in this TabPanel.
11021 getCount : function(){
11022 return this.items.length;
11026 * Resizes all the tabs to the passed width
11027 * @param {Number} The new width
11029 setTabWidth : function(width){
11030 this.currentTabWidth = width;
11031 for(var i = 0, len = this.items.length; i < len; i++) {
11032 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11037 * Destroys this TabPanel
11038 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11040 destroy : function(removeEl){
11041 Roo.EventManager.removeResizeListener(this.onResize, this);
11042 for(var i = 0, len = this.items.length; i < len; i++){
11043 this.items[i].purgeListeners();
11045 if(removeEl === true){
11046 this.el.update("");
11053 * @class Roo.TabPanelItem
11054 * @extends Roo.util.Observable
11055 * Represents an individual item (tab plus body) in a TabPanel.
11056 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11057 * @param {String} id The id of this TabPanelItem
11058 * @param {String} text The text for the tab of this TabPanelItem
11059 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11061 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11063 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11064 * @type Roo.TabPanel
11066 this.tabPanel = tabPanel;
11068 * The id for this TabPanelItem
11073 this.disabled = false;
11077 this.loaded = false;
11078 this.closable = closable;
11081 * The body element for this TabPanelItem.
11082 * @type Roo.Element
11084 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11085 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11086 this.bodyEl.setStyle("display", "block");
11087 this.bodyEl.setStyle("zoom", "1");
11090 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11092 this.el = Roo.get(els.el, true);
11093 this.inner = Roo.get(els.inner, true);
11094 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11095 this.pnode = Roo.get(els.el.parentNode, true);
11096 this.el.on("mousedown", this.onTabMouseDown, this);
11097 this.el.on("click", this.onTabClick, this);
11100 var c = Roo.get(els.close, true);
11101 c.dom.title = this.closeText;
11102 c.addClassOnOver("close-over");
11103 c.on("click", this.closeClick, this);
11109 * Fires when this tab becomes the active tab.
11110 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11111 * @param {Roo.TabPanelItem} this
11115 * @event beforeclose
11116 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11117 * @param {Roo.TabPanelItem} this
11118 * @param {Object} e Set cancel to true on this object to cancel the close.
11120 "beforeclose": true,
11123 * Fires when this tab is closed.
11124 * @param {Roo.TabPanelItem} this
11128 * @event deactivate
11129 * Fires when this tab is no longer the active tab.
11130 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11131 * @param {Roo.TabPanelItem} this
11133 "deactivate" : true
11135 this.hidden = false;
11137 Roo.TabPanelItem.superclass.constructor.call(this);
11140 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11141 purgeListeners : function(){
11142 Roo.util.Observable.prototype.purgeListeners.call(this);
11143 this.el.removeAllListeners();
11146 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11149 this.pnode.addClass("on");
11152 this.tabPanel.stripWrap.repaint();
11154 this.fireEvent("activate", this.tabPanel, this);
11158 * Returns true if this tab is the active tab.
11159 * @return {Boolean}
11161 isActive : function(){
11162 return this.tabPanel.getActiveTab() == this;
11166 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11169 this.pnode.removeClass("on");
11171 this.fireEvent("deactivate", this.tabPanel, this);
11174 hideAction : function(){
11175 this.bodyEl.hide();
11176 this.bodyEl.setStyle("position", "absolute");
11177 this.bodyEl.setLeft("-20000px");
11178 this.bodyEl.setTop("-20000px");
11181 showAction : function(){
11182 this.bodyEl.setStyle("position", "relative");
11183 this.bodyEl.setTop("");
11184 this.bodyEl.setLeft("");
11185 this.bodyEl.show();
11189 * Set the tooltip for the tab.
11190 * @param {String} tooltip The tab's tooltip
11192 setTooltip : function(text){
11193 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11194 this.textEl.dom.qtip = text;
11195 this.textEl.dom.removeAttribute('title');
11197 this.textEl.dom.title = text;
11201 onTabClick : function(e){
11202 e.preventDefault();
11203 this.tabPanel.activate(this.id);
11206 onTabMouseDown : function(e){
11207 e.preventDefault();
11208 this.tabPanel.activate(this.id);
11211 getWidth : function(){
11212 return this.inner.getWidth();
11215 setWidth : function(width){
11216 var iwidth = width - this.pnode.getPadding("lr");
11217 this.inner.setWidth(iwidth);
11218 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11219 this.pnode.setWidth(width);
11223 * Show or hide the tab
11224 * @param {Boolean} hidden True to hide or false to show.
11226 setHidden : function(hidden){
11227 this.hidden = hidden;
11228 this.pnode.setStyle("display", hidden ? "none" : "");
11232 * Returns true if this tab is "hidden"
11233 * @return {Boolean}
11235 isHidden : function(){
11236 return this.hidden;
11240 * Returns the text for this tab
11243 getText : function(){
11247 autoSize : function(){
11248 //this.el.beginMeasure();
11249 this.textEl.setWidth(1);
11250 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11251 //this.el.endMeasure();
11255 * Sets the text for the tab (Note: this also sets the tooltip text)
11256 * @param {String} text The tab's text and tooltip
11258 setText : function(text){
11260 this.textEl.update(text);
11261 this.setTooltip(text);
11262 if(!this.tabPanel.resizeTabs){
11267 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11269 activate : function(){
11270 this.tabPanel.activate(this.id);
11274 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11276 disable : function(){
11277 if(this.tabPanel.active != this){
11278 this.disabled = true;
11279 this.pnode.addClass("disabled");
11284 * Enables this TabPanelItem if it was previously disabled.
11286 enable : function(){
11287 this.disabled = false;
11288 this.pnode.removeClass("disabled");
11292 * Sets the content for this TabPanelItem.
11293 * @param {String} content The content
11294 * @param {Boolean} loadScripts true to look for and load scripts
11296 setContent : function(content, loadScripts){
11297 this.bodyEl.update(content, loadScripts);
11301 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11302 * @return {Roo.UpdateManager} The UpdateManager
11304 getUpdateManager : function(){
11305 return this.bodyEl.getUpdateManager();
11309 * Set a URL to be used to load the content for this TabPanelItem.
11310 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11311 * @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)
11312 * @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)
11313 * @return {Roo.UpdateManager} The UpdateManager
11315 setUrl : function(url, params, loadOnce){
11316 if(this.refreshDelegate){
11317 this.un('activate', this.refreshDelegate);
11319 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11320 this.on("activate", this.refreshDelegate);
11321 return this.bodyEl.getUpdateManager();
11325 _handleRefresh : function(url, params, loadOnce){
11326 if(!loadOnce || !this.loaded){
11327 var updater = this.bodyEl.getUpdateManager();
11328 updater.update(url, params, this._setLoaded.createDelegate(this));
11333 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11334 * Will fail silently if the setUrl method has not been called.
11335 * This does not activate the panel, just updates its content.
11337 refresh : function(){
11338 if(this.refreshDelegate){
11339 this.loaded = false;
11340 this.refreshDelegate();
11345 _setLoaded : function(){
11346 this.loaded = true;
11350 closeClick : function(e){
11353 this.fireEvent("beforeclose", this, o);
11354 if(o.cancel !== true){
11355 this.tabPanel.removeTab(this.id);
11359 * The text displayed in the tooltip for the close icon.
11362 closeText : "Close this tab"
11366 Roo.TabPanel.prototype.createStrip = function(container){
11367 var strip = document.createElement("div");
11368 strip.className = "x-tabs-wrap";
11369 container.appendChild(strip);
11373 Roo.TabPanel.prototype.createStripList = function(strip){
11374 // div wrapper for retard IE
11375 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>';
11376 return strip.firstChild.firstChild.firstChild.firstChild;
11379 Roo.TabPanel.prototype.createBody = function(container){
11380 var body = document.createElement("div");
11381 Roo.id(body, "tab-body");
11382 Roo.fly(body).addClass("x-tabs-body");
11383 container.appendChild(body);
11387 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11388 var body = Roo.getDom(id);
11390 body = document.createElement("div");
11393 Roo.fly(body).addClass("x-tabs-item-body");
11394 bodyEl.insertBefore(body, bodyEl.firstChild);
11398 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11399 var td = document.createElement("td");
11400 stripEl.appendChild(td);
11402 td.className = "x-tabs-closable";
11403 if(!this.closeTpl){
11404 this.closeTpl = new Roo.Template(
11405 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11406 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11407 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11410 var el = this.closeTpl.overwrite(td, {"text": text});
11411 var close = el.getElementsByTagName("div")[0];
11412 var inner = el.getElementsByTagName("em")[0];
11413 return {"el": el, "close": close, "inner": inner};
11416 this.tabTpl = new Roo.Template(
11417 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11418 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11421 var el = this.tabTpl.overwrite(td, {"text": text});
11422 var inner = el.getElementsByTagName("em")[0];
11423 return {"el": el, "inner": inner};
11427 * Ext JS Library 1.1.1
11428 * Copyright(c) 2006-2007, Ext JS, LLC.
11430 * Originally Released Under LGPL - original licence link has changed is not relivant.
11433 * <script type="text/javascript">
11437 * @class Roo.Button
11438 * @extends Roo.util.Observable
11439 * Simple Button class
11440 * @cfg {String} text The button text
11441 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11442 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11443 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11444 * @cfg {Object} scope The scope of the handler
11445 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11446 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11447 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11448 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11449 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11450 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11451 applies if enableToggle = true)
11452 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11453 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11454 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11456 * Create a new button
11457 * @param {Object} config The config object
11459 Roo.Button = function(renderTo, config)
11463 renderTo = config.renderTo || false;
11466 Roo.apply(this, config);
11470 * Fires when this button is clicked
11471 * @param {Button} this
11472 * @param {EventObject} e The click event
11477 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11478 * @param {Button} this
11479 * @param {Boolean} pressed
11484 * Fires when the mouse hovers over the button
11485 * @param {Button} this
11486 * @param {Event} e The event object
11488 'mouseover' : true,
11491 * Fires when the mouse exits the button
11492 * @param {Button} this
11493 * @param {Event} e The event object
11498 * Fires when the button is rendered
11499 * @param {Button} this
11504 this.menu = Roo.menu.MenuMgr.get(this.menu);
11506 // register listeners first!! - so render can be captured..
11507 Roo.util.Observable.call(this);
11509 this.render(renderTo);
11515 Roo.extend(Roo.Button, Roo.util.Observable, {
11521 * Read-only. True if this button is hidden
11526 * Read-only. True if this button is disabled
11531 * Read-only. True if this button is pressed (only if enableToggle = true)
11537 * @cfg {Number} tabIndex
11538 * The DOM tabIndex for this button (defaults to undefined)
11540 tabIndex : undefined,
11543 * @cfg {Boolean} enableToggle
11544 * True to enable pressed/not pressed toggling (defaults to false)
11546 enableToggle: false,
11548 * @cfg {Mixed} menu
11549 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11553 * @cfg {String} menuAlign
11554 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11556 menuAlign : "tl-bl?",
11559 * @cfg {String} iconCls
11560 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11562 iconCls : undefined,
11564 * @cfg {String} type
11565 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11570 menuClassTarget: 'tr',
11573 * @cfg {String} clickEvent
11574 * The type of event to map to the button's event handler (defaults to 'click')
11576 clickEvent : 'click',
11579 * @cfg {Boolean} handleMouseEvents
11580 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11582 handleMouseEvents : true,
11585 * @cfg {String} tooltipType
11586 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11588 tooltipType : 'qtip',
11591 * @cfg {String} cls
11592 * A CSS class to apply to the button's main element.
11596 * @cfg {Roo.Template} template (Optional)
11597 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11598 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11599 * require code modifications if required elements (e.g. a button) aren't present.
11603 render : function(renderTo){
11605 if(this.hideParent){
11606 this.parentEl = Roo.get(renderTo);
11608 if(!this.dhconfig){
11609 if(!this.template){
11610 if(!Roo.Button.buttonTemplate){
11611 // hideous table template
11612 Roo.Button.buttonTemplate = new Roo.Template(
11613 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11614 '<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>',
11615 "</tr></tbody></table>");
11617 this.template = Roo.Button.buttonTemplate;
11619 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11620 var btnEl = btn.child("button:first");
11621 btnEl.on('focus', this.onFocus, this);
11622 btnEl.on('blur', this.onBlur, this);
11624 btn.addClass(this.cls);
11627 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11630 btnEl.addClass(this.iconCls);
11632 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11635 if(this.tabIndex !== undefined){
11636 btnEl.dom.tabIndex = this.tabIndex;
11639 if(typeof this.tooltip == 'object'){
11640 Roo.QuickTips.tips(Roo.apply({
11644 btnEl.dom[this.tooltipType] = this.tooltip;
11648 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11652 this.el.dom.id = this.el.id = this.id;
11655 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11656 this.menu.on("show", this.onMenuShow, this);
11657 this.menu.on("hide", this.onMenuHide, this);
11659 btn.addClass("x-btn");
11660 if(Roo.isIE && !Roo.isIE7){
11661 this.autoWidth.defer(1, this);
11665 if(this.handleMouseEvents){
11666 btn.on("mouseover", this.onMouseOver, this);
11667 btn.on("mouseout", this.onMouseOut, this);
11668 btn.on("mousedown", this.onMouseDown, this);
11670 btn.on(this.clickEvent, this.onClick, this);
11671 //btn.on("mouseup", this.onMouseUp, this);
11678 Roo.ButtonToggleMgr.register(this);
11680 this.el.addClass("x-btn-pressed");
11683 var repeater = new Roo.util.ClickRepeater(btn,
11684 typeof this.repeat == "object" ? this.repeat : {}
11686 repeater.on("click", this.onClick, this);
11689 this.fireEvent('render', this);
11693 * Returns the button's underlying element
11694 * @return {Roo.Element} The element
11696 getEl : function(){
11701 * Destroys this Button and removes any listeners.
11703 destroy : function(){
11704 Roo.ButtonToggleMgr.unregister(this);
11705 this.el.removeAllListeners();
11706 this.purgeListeners();
11711 autoWidth : function(){
11713 this.el.setWidth("auto");
11714 if(Roo.isIE7 && Roo.isStrict){
11715 var ib = this.el.child('button');
11716 if(ib && ib.getWidth() > 20){
11718 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11723 this.el.beginMeasure();
11725 if(this.el.getWidth() < this.minWidth){
11726 this.el.setWidth(this.minWidth);
11729 this.el.endMeasure();
11736 * Assigns this button's click handler
11737 * @param {Function} handler The function to call when the button is clicked
11738 * @param {Object} scope (optional) Scope for the function passed in
11740 setHandler : function(handler, scope){
11741 this.handler = handler;
11742 this.scope = scope;
11746 * Sets this button's text
11747 * @param {String} text The button text
11749 setText : function(text){
11752 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11758 * Gets the text for this button
11759 * @return {String} The button text
11761 getText : function(){
11769 this.hidden = false;
11771 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11779 this.hidden = true;
11781 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11786 * Convenience function for boolean show/hide
11787 * @param {Boolean} visible True to show, false to hide
11789 setVisible: function(visible){
11798 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11799 * @param {Boolean} state (optional) Force a particular state
11801 toggle : function(state){
11802 state = state === undefined ? !this.pressed : state;
11803 if(state != this.pressed){
11805 this.el.addClass("x-btn-pressed");
11806 this.pressed = true;
11807 this.fireEvent("toggle", this, true);
11809 this.el.removeClass("x-btn-pressed");
11810 this.pressed = false;
11811 this.fireEvent("toggle", this, false);
11813 if(this.toggleHandler){
11814 this.toggleHandler.call(this.scope || this, this, state);
11822 focus : function(){
11823 this.el.child('button:first').focus();
11827 * Disable this button
11829 disable : function(){
11831 this.el.addClass("x-btn-disabled");
11833 this.disabled = true;
11837 * Enable this button
11839 enable : function(){
11841 this.el.removeClass("x-btn-disabled");
11843 this.disabled = false;
11847 * Convenience function for boolean enable/disable
11848 * @param {Boolean} enabled True to enable, false to disable
11850 setDisabled : function(v){
11851 this[v !== true ? "enable" : "disable"]();
11855 onClick : function(e){
11857 e.preventDefault();
11862 if(!this.disabled){
11863 if(this.enableToggle){
11866 if(this.menu && !this.menu.isVisible()){
11867 this.menu.show(this.el, this.menuAlign);
11869 this.fireEvent("click", this, e);
11871 this.el.removeClass("x-btn-over");
11872 this.handler.call(this.scope || this, this, e);
11877 onMouseOver : function(e){
11878 if(!this.disabled){
11879 this.el.addClass("x-btn-over");
11880 this.fireEvent('mouseover', this, e);
11884 onMouseOut : function(e){
11885 if(!e.within(this.el, true)){
11886 this.el.removeClass("x-btn-over");
11887 this.fireEvent('mouseout', this, e);
11891 onFocus : function(e){
11892 if(!this.disabled){
11893 this.el.addClass("x-btn-focus");
11897 onBlur : function(e){
11898 this.el.removeClass("x-btn-focus");
11901 onMouseDown : function(e){
11902 if(!this.disabled && e.button == 0){
11903 this.el.addClass("x-btn-click");
11904 Roo.get(document).on('mouseup', this.onMouseUp, this);
11908 onMouseUp : function(e){
11910 this.el.removeClass("x-btn-click");
11911 Roo.get(document).un('mouseup', this.onMouseUp, this);
11915 onMenuShow : function(e){
11916 this.el.addClass("x-btn-menu-active");
11919 onMenuHide : function(e){
11920 this.el.removeClass("x-btn-menu-active");
11924 // Private utility class used by Button
11925 Roo.ButtonToggleMgr = function(){
11928 function toggleGroup(btn, state){
11930 var g = groups[btn.toggleGroup];
11931 for(var i = 0, l = g.length; i < l; i++){
11933 g[i].toggle(false);
11940 register : function(btn){
11941 if(!btn.toggleGroup){
11944 var g = groups[btn.toggleGroup];
11946 g = groups[btn.toggleGroup] = [];
11949 btn.on("toggle", toggleGroup);
11952 unregister : function(btn){
11953 if(!btn.toggleGroup){
11956 var g = groups[btn.toggleGroup];
11959 btn.un("toggle", toggleGroup);
11965 * Ext JS Library 1.1.1
11966 * Copyright(c) 2006-2007, Ext JS, LLC.
11968 * Originally Released Under LGPL - original licence link has changed is not relivant.
11971 * <script type="text/javascript">
11975 * @class Roo.SplitButton
11976 * @extends Roo.Button
11977 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11978 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11979 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11980 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11981 * @cfg {String} arrowTooltip The title attribute of the arrow
11983 * Create a new menu button
11984 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11985 * @param {Object} config The config object
11987 Roo.SplitButton = function(renderTo, config){
11988 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
11990 * @event arrowclick
11991 * Fires when this button's arrow is clicked
11992 * @param {SplitButton} this
11993 * @param {EventObject} e The click event
11995 this.addEvents({"arrowclick":true});
11998 Roo.extend(Roo.SplitButton, Roo.Button, {
11999 render : function(renderTo){
12000 // this is one sweet looking template!
12001 var tpl = new Roo.Template(
12002 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12003 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12004 '<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>',
12005 "</tbody></table></td><td>",
12006 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12007 '<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>',
12008 "</tbody></table></td></tr></table>"
12010 var btn = tpl.append(renderTo, [this.text, this.type], true);
12011 var btnEl = btn.child("button");
12013 btn.addClass(this.cls);
12016 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12019 btnEl.addClass(this.iconCls);
12021 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12025 if(this.handleMouseEvents){
12026 btn.on("mouseover", this.onMouseOver, this);
12027 btn.on("mouseout", this.onMouseOut, this);
12028 btn.on("mousedown", this.onMouseDown, this);
12029 btn.on("mouseup", this.onMouseUp, this);
12031 btn.on(this.clickEvent, this.onClick, this);
12033 if(typeof this.tooltip == 'object'){
12034 Roo.QuickTips.tips(Roo.apply({
12038 btnEl.dom[this.tooltipType] = this.tooltip;
12041 if(this.arrowTooltip){
12042 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12051 this.el.addClass("x-btn-pressed");
12053 if(Roo.isIE && !Roo.isIE7){
12054 this.autoWidth.defer(1, this);
12059 this.menu.on("show", this.onMenuShow, this);
12060 this.menu.on("hide", this.onMenuHide, this);
12062 this.fireEvent('render', this);
12066 autoWidth : function(){
12068 var tbl = this.el.child("table:first");
12069 var tbl2 = this.el.child("table:last");
12070 this.el.setWidth("auto");
12071 tbl.setWidth("auto");
12072 if(Roo.isIE7 && Roo.isStrict){
12073 var ib = this.el.child('button:first');
12074 if(ib && ib.getWidth() > 20){
12076 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12081 this.el.beginMeasure();
12083 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12084 tbl.setWidth(this.minWidth-tbl2.getWidth());
12087 this.el.endMeasure();
12090 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12094 * Sets this button's click handler
12095 * @param {Function} handler The function to call when the button is clicked
12096 * @param {Object} scope (optional) Scope for the function passed above
12098 setHandler : function(handler, scope){
12099 this.handler = handler;
12100 this.scope = scope;
12104 * Sets this button's arrow click handler
12105 * @param {Function} handler The function to call when the arrow is clicked
12106 * @param {Object} scope (optional) Scope for the function passed above
12108 setArrowHandler : function(handler, scope){
12109 this.arrowHandler = handler;
12110 this.scope = scope;
12116 focus : function(){
12118 this.el.child("button:first").focus();
12123 onClick : function(e){
12124 e.preventDefault();
12125 if(!this.disabled){
12126 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12127 if(this.menu && !this.menu.isVisible()){
12128 this.menu.show(this.el, this.menuAlign);
12130 this.fireEvent("arrowclick", this, e);
12131 if(this.arrowHandler){
12132 this.arrowHandler.call(this.scope || this, this, e);
12135 this.fireEvent("click", this, e);
12137 this.handler.call(this.scope || this, this, e);
12143 onMouseDown : function(e){
12144 if(!this.disabled){
12145 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12149 onMouseUp : function(e){
12150 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12155 // backwards compat
12156 Roo.MenuButton = Roo.SplitButton;/*
12158 * Ext JS Library 1.1.1
12159 * Copyright(c) 2006-2007, Ext JS, LLC.
12161 * Originally Released Under LGPL - original licence link has changed is not relivant.
12164 * <script type="text/javascript">
12168 * @class Roo.Toolbar
12169 * Basic Toolbar class.
12171 * Creates a new Toolbar
12172 * @param {Object} config The config object
12174 Roo.Toolbar = function(container, buttons, config)
12176 /// old consturctor format still supported..
12177 if(container instanceof Array){ // omit the container for later rendering
12178 buttons = container;
12182 if (typeof(container) == 'object' && container.xtype) {
12183 config = container;
12184 container = config.container;
12185 buttons = config.buttons; // not really - use items!!
12188 if (config && config.items) {
12189 xitems = config.items;
12190 delete config.items;
12192 Roo.apply(this, config);
12193 this.buttons = buttons;
12196 this.render(container);
12198 Roo.each(xitems, function(b) {
12204 Roo.Toolbar.prototype = {
12206 * @cfg {Roo.data.Store} items
12207 * array of button configs or elements to add
12211 * @cfg {String/HTMLElement/Element} container
12212 * The id or element that will contain the toolbar
12215 render : function(ct){
12216 this.el = Roo.get(ct);
12218 this.el.addClass(this.cls);
12220 // using a table allows for vertical alignment
12221 // 100% width is needed by Safari...
12222 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12223 this.tr = this.el.child("tr", true);
12225 this.items = new Roo.util.MixedCollection(false, function(o){
12226 return o.id || ("item" + (++autoId));
12229 this.add.apply(this, this.buttons);
12230 delete this.buttons;
12235 * Adds element(s) to the toolbar -- this function takes a variable number of
12236 * arguments of mixed type and adds them to the toolbar.
12237 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12239 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12240 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12241 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12242 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12243 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12244 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12245 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12246 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12247 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12249 * @param {Mixed} arg2
12250 * @param {Mixed} etc.
12253 var a = arguments, l = a.length;
12254 for(var i = 0; i < l; i++){
12259 _add : function(el) {
12262 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12265 if (el.applyTo){ // some kind of form field
12266 return this.addField(el);
12268 if (el.render){ // some kind of Toolbar.Item
12269 return this.addItem(el);
12271 if (typeof el == "string"){ // string
12272 if(el == "separator" || el == "-"){
12273 return this.addSeparator();
12276 return this.addSpacer();
12279 return this.addFill();
12281 return this.addText(el);
12284 if(el.tagName){ // element
12285 return this.addElement(el);
12287 if(typeof el == "object"){ // must be button config?
12288 return this.addButton(el);
12290 // and now what?!?!
12296 * Add an Xtype element
12297 * @param {Object} xtype Xtype Object
12298 * @return {Object} created Object
12300 addxtype : function(e){
12301 return this.add(e);
12305 * Returns the Element for this toolbar.
12306 * @return {Roo.Element}
12308 getEl : function(){
12314 * @return {Roo.Toolbar.Item} The separator item
12316 addSeparator : function(){
12317 return this.addItem(new Roo.Toolbar.Separator());
12321 * Adds a spacer element
12322 * @return {Roo.Toolbar.Spacer} The spacer item
12324 addSpacer : function(){
12325 return this.addItem(new Roo.Toolbar.Spacer());
12329 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12330 * @return {Roo.Toolbar.Fill} The fill item
12332 addFill : function(){
12333 return this.addItem(new Roo.Toolbar.Fill());
12337 * Adds any standard HTML element to the toolbar
12338 * @param {String/HTMLElement/Element} el The element or id of the element to add
12339 * @return {Roo.Toolbar.Item} The element's item
12341 addElement : function(el){
12342 return this.addItem(new Roo.Toolbar.Item(el));
12345 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12346 * @type Roo.util.MixedCollection
12351 * Adds any Toolbar.Item or subclass
12352 * @param {Roo.Toolbar.Item} item
12353 * @return {Roo.Toolbar.Item} The item
12355 addItem : function(item){
12356 var td = this.nextBlock();
12358 this.items.add(item);
12363 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12364 * @param {Object/Array} config A button config or array of configs
12365 * @return {Roo.Toolbar.Button/Array}
12367 addButton : function(config){
12368 if(config instanceof Array){
12370 for(var i = 0, len = config.length; i < len; i++) {
12371 buttons.push(this.addButton(config[i]));
12376 if(!(config instanceof Roo.Toolbar.Button)){
12378 new Roo.Toolbar.SplitButton(config) :
12379 new Roo.Toolbar.Button(config);
12381 var td = this.nextBlock();
12388 * Adds text to the toolbar
12389 * @param {String} text The text to add
12390 * @return {Roo.Toolbar.Item} The element's item
12392 addText : function(text){
12393 return this.addItem(new Roo.Toolbar.TextItem(text));
12397 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12398 * @param {Number} index The index where the item is to be inserted
12399 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12400 * @return {Roo.Toolbar.Button/Item}
12402 insertButton : function(index, item){
12403 if(item instanceof Array){
12405 for(var i = 0, len = item.length; i < len; i++) {
12406 buttons.push(this.insertButton(index + i, item[i]));
12410 if (!(item instanceof Roo.Toolbar.Button)){
12411 item = new Roo.Toolbar.Button(item);
12413 var td = document.createElement("td");
12414 this.tr.insertBefore(td, this.tr.childNodes[index]);
12416 this.items.insert(index, item);
12421 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12422 * @param {Object} config
12423 * @return {Roo.Toolbar.Item} The element's item
12425 addDom : function(config, returnEl){
12426 var td = this.nextBlock();
12427 Roo.DomHelper.overwrite(td, config);
12428 var ti = new Roo.Toolbar.Item(td.firstChild);
12430 this.items.add(ti);
12435 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12436 * @type Roo.util.MixedCollection
12441 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12442 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12443 * @param {Roo.form.Field} field
12444 * @return {Roo.ToolbarItem}
12448 addField : function(field) {
12449 if (!this.fields) {
12451 this.fields = new Roo.util.MixedCollection(false, function(o){
12452 return o.id || ("item" + (++autoId));
12457 var td = this.nextBlock();
12459 var ti = new Roo.Toolbar.Item(td.firstChild);
12461 this.items.add(ti);
12462 this.fields.add(field);
12473 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12474 this.el.child('div').hide();
12482 this.el.child('div').show();
12486 nextBlock : function(){
12487 var td = document.createElement("td");
12488 this.tr.appendChild(td);
12493 destroy : function(){
12494 if(this.items){ // rendered?
12495 Roo.destroy.apply(Roo, this.items.items);
12497 if(this.fields){ // rendered?
12498 Roo.destroy.apply(Roo, this.fields.items);
12500 Roo.Element.uncache(this.el, this.tr);
12505 * @class Roo.Toolbar.Item
12506 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12508 * Creates a new Item
12509 * @param {HTMLElement} el
12511 Roo.Toolbar.Item = function(el){
12512 this.el = Roo.getDom(el);
12513 this.id = Roo.id(this.el);
12514 this.hidden = false;
12517 Roo.Toolbar.Item.prototype = {
12520 * Get this item's HTML Element
12521 * @return {HTMLElement}
12523 getEl : function(){
12528 render : function(td){
12530 td.appendChild(this.el);
12534 * Removes and destroys this item.
12536 destroy : function(){
12537 this.td.parentNode.removeChild(this.td);
12544 this.hidden = false;
12545 this.td.style.display = "";
12552 this.hidden = true;
12553 this.td.style.display = "none";
12557 * Convenience function for boolean show/hide.
12558 * @param {Boolean} visible true to show/false to hide
12560 setVisible: function(visible){
12569 * Try to focus this item.
12571 focus : function(){
12572 Roo.fly(this.el).focus();
12576 * Disables this item.
12578 disable : function(){
12579 Roo.fly(this.td).addClass("x-item-disabled");
12580 this.disabled = true;
12581 this.el.disabled = true;
12585 * Enables this item.
12587 enable : function(){
12588 Roo.fly(this.td).removeClass("x-item-disabled");
12589 this.disabled = false;
12590 this.el.disabled = false;
12596 * @class Roo.Toolbar.Separator
12597 * @extends Roo.Toolbar.Item
12598 * A simple toolbar separator class
12600 * Creates a new Separator
12602 Roo.Toolbar.Separator = function(){
12603 var s = document.createElement("span");
12604 s.className = "ytb-sep";
12605 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12607 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12608 enable:Roo.emptyFn,
12609 disable:Roo.emptyFn,
12614 * @class Roo.Toolbar.Spacer
12615 * @extends Roo.Toolbar.Item
12616 * A simple element that adds extra horizontal space to a toolbar.
12618 * Creates a new Spacer
12620 Roo.Toolbar.Spacer = function(){
12621 var s = document.createElement("div");
12622 s.className = "ytb-spacer";
12623 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12625 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12626 enable:Roo.emptyFn,
12627 disable:Roo.emptyFn,
12632 * @class Roo.Toolbar.Fill
12633 * @extends Roo.Toolbar.Spacer
12634 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12636 * Creates a new Spacer
12638 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12640 render : function(td){
12641 td.style.width = '100%';
12642 Roo.Toolbar.Fill.superclass.render.call(this, td);
12647 * @class Roo.Toolbar.TextItem
12648 * @extends Roo.Toolbar.Item
12649 * A simple class that renders text directly into a toolbar.
12651 * Creates a new TextItem
12652 * @param {String} text
12654 Roo.Toolbar.TextItem = function(text){
12655 if (typeof(text) == 'object') {
12658 var s = document.createElement("span");
12659 s.className = "ytb-text";
12660 s.innerHTML = text;
12661 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12663 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12664 enable:Roo.emptyFn,
12665 disable:Roo.emptyFn,
12670 * @class Roo.Toolbar.Button
12671 * @extends Roo.Button
12672 * A button that renders into a toolbar.
12674 * Creates a new Button
12675 * @param {Object} config A standard {@link Roo.Button} config object
12677 Roo.Toolbar.Button = function(config){
12678 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12680 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12681 render : function(td){
12683 Roo.Toolbar.Button.superclass.render.call(this, td);
12687 * Removes and destroys this button
12689 destroy : function(){
12690 Roo.Toolbar.Button.superclass.destroy.call(this);
12691 this.td.parentNode.removeChild(this.td);
12695 * Shows this button
12698 this.hidden = false;
12699 this.td.style.display = "";
12703 * Hides this button
12706 this.hidden = true;
12707 this.td.style.display = "none";
12711 * Disables this item
12713 disable : function(){
12714 Roo.fly(this.td).addClass("x-item-disabled");
12715 this.disabled = true;
12719 * Enables this item
12721 enable : function(){
12722 Roo.fly(this.td).removeClass("x-item-disabled");
12723 this.disabled = false;
12726 // backwards compat
12727 Roo.ToolbarButton = Roo.Toolbar.Button;
12730 * @class Roo.Toolbar.SplitButton
12731 * @extends Roo.SplitButton
12732 * A menu button that renders into a toolbar.
12734 * Creates a new SplitButton
12735 * @param {Object} config A standard {@link Roo.SplitButton} config object
12737 Roo.Toolbar.SplitButton = function(config){
12738 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12740 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12741 render : function(td){
12743 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12747 * Removes and destroys this button
12749 destroy : function(){
12750 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12751 this.td.parentNode.removeChild(this.td);
12755 * Shows this button
12758 this.hidden = false;
12759 this.td.style.display = "";
12763 * Hides this button
12766 this.hidden = true;
12767 this.td.style.display = "none";
12771 // backwards compat
12772 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12774 * Ext JS Library 1.1.1
12775 * Copyright(c) 2006-2007, Ext JS, LLC.
12777 * Originally Released Under LGPL - original licence link has changed is not relivant.
12780 * <script type="text/javascript">
12784 * @class Roo.PagingToolbar
12785 * @extends Roo.Toolbar
12786 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12788 * Create a new PagingToolbar
12789 * @param {Object} config The config object
12791 Roo.PagingToolbar = function(el, ds, config)
12793 // old args format still supported... - xtype is prefered..
12794 if (typeof(el) == 'object' && el.xtype) {
12795 // created from xtype...
12797 ds = el.dataSource;
12798 el = config.container;
12801 if (config.items) {
12802 items = config.items;
12806 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12809 this.renderButtons(this.el);
12812 // supprot items array.
12814 Roo.each(items, function(e) {
12815 this.add(Roo.factory(e));
12820 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12822 * @cfg {Roo.data.Store} dataSource
12823 * The underlying data store providing the paged data
12826 * @cfg {String/HTMLElement/Element} container
12827 * container The id or element that will contain the toolbar
12830 * @cfg {Boolean} displayInfo
12831 * True to display the displayMsg (defaults to false)
12834 * @cfg {Number} pageSize
12835 * The number of records to display per page (defaults to 20)
12839 * @cfg {String} displayMsg
12840 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12842 displayMsg : 'Displaying {0} - {1} of {2}',
12844 * @cfg {String} emptyMsg
12845 * The message to display when no records are found (defaults to "No data to display")
12847 emptyMsg : 'No data to display',
12849 * Customizable piece of the default paging text (defaults to "Page")
12852 beforePageText : "Page",
12854 * Customizable piece of the default paging text (defaults to "of %0")
12857 afterPageText : "of {0}",
12859 * Customizable piece of the default paging text (defaults to "First Page")
12862 firstText : "First Page",
12864 * Customizable piece of the default paging text (defaults to "Previous Page")
12867 prevText : "Previous Page",
12869 * Customizable piece of the default paging text (defaults to "Next Page")
12872 nextText : "Next Page",
12874 * Customizable piece of the default paging text (defaults to "Last Page")
12877 lastText : "Last Page",
12879 * Customizable piece of the default paging text (defaults to "Refresh")
12882 refreshText : "Refresh",
12885 renderButtons : function(el){
12886 Roo.PagingToolbar.superclass.render.call(this, el);
12887 this.first = this.addButton({
12888 tooltip: this.firstText,
12889 cls: "x-btn-icon x-grid-page-first",
12891 handler: this.onClick.createDelegate(this, ["first"])
12893 this.prev = this.addButton({
12894 tooltip: this.prevText,
12895 cls: "x-btn-icon x-grid-page-prev",
12897 handler: this.onClick.createDelegate(this, ["prev"])
12899 //this.addSeparator();
12900 this.add(this.beforePageText);
12901 this.field = Roo.get(this.addDom({
12906 cls: "x-grid-page-number"
12908 this.field.on("keydown", this.onPagingKeydown, this);
12909 this.field.on("focus", function(){this.dom.select();});
12910 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12911 this.field.setHeight(18);
12912 //this.addSeparator();
12913 this.next = this.addButton({
12914 tooltip: this.nextText,
12915 cls: "x-btn-icon x-grid-page-next",
12917 handler: this.onClick.createDelegate(this, ["next"])
12919 this.last = this.addButton({
12920 tooltip: this.lastText,
12921 cls: "x-btn-icon x-grid-page-last",
12923 handler: this.onClick.createDelegate(this, ["last"])
12925 //this.addSeparator();
12926 this.loading = this.addButton({
12927 tooltip: this.refreshText,
12928 cls: "x-btn-icon x-grid-loading",
12929 handler: this.onClick.createDelegate(this, ["refresh"])
12932 if(this.displayInfo){
12933 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12938 updateInfo : function(){
12939 if(this.displayEl){
12940 var count = this.ds.getCount();
12941 var msg = count == 0 ?
12945 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12947 this.displayEl.update(msg);
12952 onLoad : function(ds, r, o){
12953 this.cursor = o.params ? o.params.start : 0;
12954 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12956 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12957 this.field.dom.value = ap;
12958 this.first.setDisabled(ap == 1);
12959 this.prev.setDisabled(ap == 1);
12960 this.next.setDisabled(ap == ps);
12961 this.last.setDisabled(ap == ps);
12962 this.loading.enable();
12967 getPageData : function(){
12968 var total = this.ds.getTotalCount();
12971 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12972 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12977 onLoadError : function(){
12978 this.loading.enable();
12982 onPagingKeydown : function(e){
12983 var k = e.getKey();
12984 var d = this.getPageData();
12986 var v = this.field.dom.value, pageNum;
12987 if(!v || isNaN(pageNum = parseInt(v, 10))){
12988 this.field.dom.value = d.activePage;
12991 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
12992 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
12995 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))
12997 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
12998 this.field.dom.value = pageNum;
12999 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13002 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13004 var v = this.field.dom.value, pageNum;
13005 var increment = (e.shiftKey) ? 10 : 1;
13006 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13008 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13009 this.field.dom.value = d.activePage;
13012 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13014 this.field.dom.value = parseInt(v, 10) + increment;
13015 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13016 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13023 beforeLoad : function(){
13025 this.loading.disable();
13030 onClick : function(which){
13034 ds.load({params:{start: 0, limit: this.pageSize}});
13037 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13040 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13043 var total = ds.getTotalCount();
13044 var extra = total % this.pageSize;
13045 var lastStart = extra ? (total - extra) : total-this.pageSize;
13046 ds.load({params:{start: lastStart, limit: this.pageSize}});
13049 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13055 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13056 * @param {Roo.data.Store} store The data store to unbind
13058 unbind : function(ds){
13059 ds.un("beforeload", this.beforeLoad, this);
13060 ds.un("load", this.onLoad, this);
13061 ds.un("loadexception", this.onLoadError, this);
13062 ds.un("remove", this.updateInfo, this);
13063 ds.un("add", this.updateInfo, this);
13064 this.ds = undefined;
13068 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13069 * @param {Roo.data.Store} store The data store to bind
13071 bind : function(ds){
13072 ds.on("beforeload", this.beforeLoad, this);
13073 ds.on("load", this.onLoad, this);
13074 ds.on("loadexception", this.onLoadError, this);
13075 ds.on("remove", this.updateInfo, this);
13076 ds.on("add", this.updateInfo, this);
13081 * Ext JS Library 1.1.1
13082 * Copyright(c) 2006-2007, Ext JS, LLC.
13084 * Originally Released Under LGPL - original licence link has changed is not relivant.
13087 * <script type="text/javascript">
13091 * @class Roo.Resizable
13092 * @extends Roo.util.Observable
13093 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13094 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13095 * 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
13096 * the element will be wrapped for you automatically.</p>
13097 * <p>Here is the list of valid resize handles:</p>
13100 ------ -------------------
13109 'hd' horizontal drag
13112 * <p>Here's an example showing the creation of a typical Resizable:</p>
13114 var resizer = new Roo.Resizable("element-id", {
13122 resizer.on("resize", myHandler);
13124 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13125 * resizer.east.setDisplayed(false);</p>
13126 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13127 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13128 * resize operation's new size (defaults to [0, 0])
13129 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13130 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13131 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13132 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13133 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13134 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13135 * @cfg {Number} width The width of the element in pixels (defaults to null)
13136 * @cfg {Number} height The height of the element in pixels (defaults to null)
13137 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13138 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13139 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13140 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13141 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13142 * in favor of the handles config option (defaults to false)
13143 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13144 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13145 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13146 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13147 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13148 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13149 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13150 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13151 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13152 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13153 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13155 * Create a new resizable component
13156 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13157 * @param {Object} config configuration options
13159 Roo.Resizable = function(el, config)
13161 this.el = Roo.get(el);
13163 if(config && config.wrap){
13164 config.resizeChild = this.el;
13165 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13166 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13167 this.el.setStyle("overflow", "hidden");
13168 this.el.setPositioning(config.resizeChild.getPositioning());
13169 config.resizeChild.clearPositioning();
13170 if(!config.width || !config.height){
13171 var csize = config.resizeChild.getSize();
13172 this.el.setSize(csize.width, csize.height);
13174 if(config.pinned && !config.adjustments){
13175 config.adjustments = "auto";
13179 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13180 this.proxy.unselectable();
13181 this.proxy.enableDisplayMode('block');
13183 Roo.apply(this, config);
13186 this.disableTrackOver = true;
13187 this.el.addClass("x-resizable-pinned");
13189 // if the element isn't positioned, make it relative
13190 var position = this.el.getStyle("position");
13191 if(position != "absolute" && position != "fixed"){
13192 this.el.setStyle("position", "relative");
13194 if(!this.handles){ // no handles passed, must be legacy style
13195 this.handles = 's,e,se';
13196 if(this.multiDirectional){
13197 this.handles += ',n,w';
13200 if(this.handles == "all"){
13201 this.handles = "n s e w ne nw se sw";
13203 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13204 var ps = Roo.Resizable.positions;
13205 for(var i = 0, len = hs.length; i < len; i++){
13206 if(hs[i] && ps[hs[i]]){
13207 var pos = ps[hs[i]];
13208 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13212 this.corner = this.southeast;
13214 // updateBox = the box can move..
13215 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13216 this.updateBox = true;
13219 this.activeHandle = null;
13221 if(this.resizeChild){
13222 if(typeof this.resizeChild == "boolean"){
13223 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13225 this.resizeChild = Roo.get(this.resizeChild, true);
13229 if(this.adjustments == "auto"){
13230 var rc = this.resizeChild;
13231 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13232 if(rc && (hw || hn)){
13233 rc.position("relative");
13234 rc.setLeft(hw ? hw.el.getWidth() : 0);
13235 rc.setTop(hn ? hn.el.getHeight() : 0);
13237 this.adjustments = [
13238 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13239 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13243 if(this.draggable){
13244 this.dd = this.dynamic ?
13245 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13246 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13252 * @event beforeresize
13253 * Fired before resize is allowed. Set enabled to false to cancel resize.
13254 * @param {Roo.Resizable} this
13255 * @param {Roo.EventObject} e The mousedown event
13257 "beforeresize" : true,
13260 * Fired after a resize.
13261 * @param {Roo.Resizable} this
13262 * @param {Number} width The new width
13263 * @param {Number} height The new height
13264 * @param {Roo.EventObject} e The mouseup event
13269 if(this.width !== null && this.height !== null){
13270 this.resizeTo(this.width, this.height);
13272 this.updateChildSize();
13275 this.el.dom.style.zoom = 1;
13277 Roo.Resizable.superclass.constructor.call(this);
13280 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13281 resizeChild : false,
13282 adjustments : [0, 0],
13292 multiDirectional : false,
13293 disableTrackOver : false,
13294 easing : 'easeOutStrong',
13295 widthIncrement : 0,
13296 heightIncrement : 0,
13300 preserveRatio : false,
13301 transparent: false,
13307 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13309 constrainTo: undefined,
13311 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13313 resizeRegion: undefined,
13317 * Perform a manual resize
13318 * @param {Number} width
13319 * @param {Number} height
13321 resizeTo : function(width, height){
13322 this.el.setSize(width, height);
13323 this.updateChildSize();
13324 this.fireEvent("resize", this, width, height, null);
13328 startSizing : function(e, handle){
13329 this.fireEvent("beforeresize", this, e);
13330 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13333 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13334 this.overlay.unselectable();
13335 this.overlay.enableDisplayMode("block");
13336 this.overlay.on("mousemove", this.onMouseMove, this);
13337 this.overlay.on("mouseup", this.onMouseUp, this);
13339 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13341 this.resizing = true;
13342 this.startBox = this.el.getBox();
13343 this.startPoint = e.getXY();
13344 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13345 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13347 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13348 this.overlay.show();
13350 if(this.constrainTo) {
13351 var ct = Roo.get(this.constrainTo);
13352 this.resizeRegion = ct.getRegion().adjust(
13353 ct.getFrameWidth('t'),
13354 ct.getFrameWidth('l'),
13355 -ct.getFrameWidth('b'),
13356 -ct.getFrameWidth('r')
13360 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13362 this.proxy.setBox(this.startBox);
13364 this.proxy.setStyle('visibility', 'visible');
13370 onMouseDown : function(handle, e){
13373 this.activeHandle = handle;
13374 this.startSizing(e, handle);
13379 onMouseUp : function(e){
13380 var size = this.resizeElement();
13381 this.resizing = false;
13383 this.overlay.hide();
13385 this.fireEvent("resize", this, size.width, size.height, e);
13389 updateChildSize : function(){
13390 if(this.resizeChild){
13392 var child = this.resizeChild;
13393 var adj = this.adjustments;
13394 if(el.dom.offsetWidth){
13395 var b = el.getSize(true);
13396 child.setSize(b.width+adj[0], b.height+adj[1]);
13398 // Second call here for IE
13399 // The first call enables instant resizing and
13400 // the second call corrects scroll bars if they
13403 setTimeout(function(){
13404 if(el.dom.offsetWidth){
13405 var b = el.getSize(true);
13406 child.setSize(b.width+adj[0], b.height+adj[1]);
13414 snap : function(value, inc, min){
13415 if(!inc || !value) return value;
13416 var newValue = value;
13417 var m = value % inc;
13420 newValue = value + (inc-m);
13422 newValue = value - m;
13425 return Math.max(min, newValue);
13429 resizeElement : function(){
13430 var box = this.proxy.getBox();
13431 if(this.updateBox){
13432 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13434 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13436 this.updateChildSize();
13444 constrain : function(v, diff, m, mx){
13447 }else if(v - diff > mx){
13454 onMouseMove : function(e){
13456 try{// try catch so if something goes wrong the user doesn't get hung
13458 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13462 //var curXY = this.startPoint;
13463 var curSize = this.curSize || this.startBox;
13464 var x = this.startBox.x, y = this.startBox.y;
13465 var ox = x, oy = y;
13466 var w = curSize.width, h = curSize.height;
13467 var ow = w, oh = h;
13468 var mw = this.minWidth, mh = this.minHeight;
13469 var mxw = this.maxWidth, mxh = this.maxHeight;
13470 var wi = this.widthIncrement;
13471 var hi = this.heightIncrement;
13473 var eventXY = e.getXY();
13474 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13475 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13477 var pos = this.activeHandle.position;
13482 w = Math.min(Math.max(mw, w), mxw);
13487 h = Math.min(Math.max(mh, h), mxh);
13492 w = Math.min(Math.max(mw, w), mxw);
13493 h = Math.min(Math.max(mh, h), mxh);
13496 diffY = this.constrain(h, diffY, mh, mxh);
13503 var adiffX = Math.abs(diffX);
13504 var sub = (adiffX % wi); // how much
13505 if (sub > (wi/2)) { // far enough to snap
13506 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13508 // remove difference..
13509 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13513 x = Math.max(this.minX, x);
13516 diffX = this.constrain(w, diffX, mw, mxw);
13522 w = Math.min(Math.max(mw, w), mxw);
13523 diffY = this.constrain(h, diffY, mh, mxh);
13528 diffX = this.constrain(w, diffX, mw, mxw);
13529 diffY = this.constrain(h, diffY, mh, mxh);
13536 diffX = this.constrain(w, diffX, mw, mxw);
13538 h = Math.min(Math.max(mh, h), mxh);
13544 var sw = this.snap(w, wi, mw);
13545 var sh = this.snap(h, hi, mh);
13546 if(sw != w || sh != h){
13569 if(this.preserveRatio){
13574 h = Math.min(Math.max(mh, h), mxh);
13579 w = Math.min(Math.max(mw, w), mxw);
13584 w = Math.min(Math.max(mw, w), mxw);
13590 w = Math.min(Math.max(mw, w), mxw);
13596 h = Math.min(Math.max(mh, h), mxh);
13604 h = Math.min(Math.max(mh, h), mxh);
13614 h = Math.min(Math.max(mh, h), mxh);
13622 if (pos == 'hdrag') {
13625 this.proxy.setBounds(x, y, w, h);
13627 this.resizeElement();
13634 handleOver : function(){
13636 this.el.addClass("x-resizable-over");
13641 handleOut : function(){
13642 if(!this.resizing){
13643 this.el.removeClass("x-resizable-over");
13648 * Returns the element this component is bound to.
13649 * @return {Roo.Element}
13651 getEl : function(){
13656 * Returns the resizeChild element (or null).
13657 * @return {Roo.Element}
13659 getResizeChild : function(){
13660 return this.resizeChild;
13664 * Destroys this resizable. If the element was wrapped and
13665 * removeEl is not true then the element remains.
13666 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13668 destroy : function(removeEl){
13669 this.proxy.remove();
13671 this.overlay.removeAllListeners();
13672 this.overlay.remove();
13674 var ps = Roo.Resizable.positions;
13676 if(typeof ps[k] != "function" && this[ps[k]]){
13677 var h = this[ps[k]];
13678 h.el.removeAllListeners();
13683 this.el.update("");
13690 // hash to map config positions to true positions
13691 Roo.Resizable.positions = {
13692 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13697 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13699 // only initialize the template if resizable is used
13700 var tpl = Roo.DomHelper.createTemplate(
13701 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13704 Roo.Resizable.Handle.prototype.tpl = tpl;
13706 this.position = pos;
13708 // show north drag fro topdra
13709 var handlepos = pos == 'hdrag' ? 'north' : pos;
13711 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13712 if (pos == 'hdrag') {
13713 this.el.setStyle('cursor', 'pointer');
13715 this.el.unselectable();
13717 this.el.setOpacity(0);
13719 this.el.on("mousedown", this.onMouseDown, this);
13720 if(!disableTrackOver){
13721 this.el.on("mouseover", this.onMouseOver, this);
13722 this.el.on("mouseout", this.onMouseOut, this);
13727 Roo.Resizable.Handle.prototype = {
13728 afterResize : function(rz){
13732 onMouseDown : function(e){
13733 this.rz.onMouseDown(this, e);
13736 onMouseOver : function(e){
13737 this.rz.handleOver(this, e);
13740 onMouseOut : function(e){
13741 this.rz.handleOut(this, e);
13745 * Ext JS Library 1.1.1
13746 * Copyright(c) 2006-2007, Ext JS, LLC.
13748 * Originally Released Under LGPL - original licence link has changed is not relivant.
13751 * <script type="text/javascript">
13755 * @class Roo.Editor
13756 * @extends Roo.Component
13757 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13759 * Create a new Editor
13760 * @param {Roo.form.Field} field The Field object (or descendant)
13761 * @param {Object} config The config object
13763 Roo.Editor = function(field, config){
13764 Roo.Editor.superclass.constructor.call(this, config);
13765 this.field = field;
13768 * @event beforestartedit
13769 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13770 * false from the handler of this event.
13771 * @param {Editor} this
13772 * @param {Roo.Element} boundEl The underlying element bound to this editor
13773 * @param {Mixed} value The field value being set
13775 "beforestartedit" : true,
13778 * Fires when this editor is displayed
13779 * @param {Roo.Element} boundEl The underlying element bound to this editor
13780 * @param {Mixed} value The starting field value
13782 "startedit" : true,
13784 * @event beforecomplete
13785 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13786 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13787 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13788 * event will not fire since no edit actually occurred.
13789 * @param {Editor} this
13790 * @param {Mixed} value The current field value
13791 * @param {Mixed} startValue The original field value
13793 "beforecomplete" : true,
13796 * Fires after editing is complete and any changed value has been written to the underlying field.
13797 * @param {Editor} this
13798 * @param {Mixed} value The current field value
13799 * @param {Mixed} startValue The original field value
13803 * @event specialkey
13804 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13805 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13806 * @param {Roo.form.Field} this
13807 * @param {Roo.EventObject} e The event object
13809 "specialkey" : true
13813 Roo.extend(Roo.Editor, Roo.Component, {
13815 * @cfg {Boolean/String} autosize
13816 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13817 * or "height" to adopt the height only (defaults to false)
13820 * @cfg {Boolean} revertInvalid
13821 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13822 * validation fails (defaults to true)
13825 * @cfg {Boolean} ignoreNoChange
13826 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13827 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13828 * will never be ignored.
13831 * @cfg {Boolean} hideEl
13832 * False to keep the bound element visible while the editor is displayed (defaults to true)
13835 * @cfg {Mixed} value
13836 * The data value of the underlying field (defaults to "")
13840 * @cfg {String} alignment
13841 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13845 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13846 * for bottom-right shadow (defaults to "frame")
13850 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13854 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13856 completeOnEnter : false,
13858 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13860 cancelOnEsc : false,
13862 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13867 onRender : function(ct, position){
13868 this.el = new Roo.Layer({
13869 shadow: this.shadow,
13875 constrain: this.constrain
13877 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13878 if(this.field.msgTarget != 'title'){
13879 this.field.msgTarget = 'qtip';
13881 this.field.render(this.el);
13883 this.field.el.dom.setAttribute('autocomplete', 'off');
13885 this.field.on("specialkey", this.onSpecialKey, this);
13886 if(this.swallowKeys){
13887 this.field.el.swallowEvent(['keydown','keypress']);
13890 this.field.on("blur", this.onBlur, this);
13891 if(this.field.grow){
13892 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13896 onSpecialKey : function(field, e){
13897 //Roo.log('editor onSpecialKey');
13898 if(this.completeOnEnter && e.getKey() == e.ENTER){
13900 this.completeEdit();
13901 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13904 this.fireEvent('specialkey', field, e);
13909 * Starts the editing process and shows the editor.
13910 * @param {String/HTMLElement/Element} el The element to edit
13911 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13912 * to the innerHTML of el.
13914 startEdit : function(el, value){
13916 this.completeEdit();
13918 this.boundEl = Roo.get(el);
13919 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13920 if(!this.rendered){
13921 this.render(this.parentEl || document.body);
13923 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13926 this.startValue = v;
13927 this.field.setValue(v);
13929 var sz = this.boundEl.getSize();
13930 switch(this.autoSize){
13932 this.setSize(sz.width, "");
13935 this.setSize("", sz.height);
13938 this.setSize(sz.width, sz.height);
13941 this.el.alignTo(this.boundEl, this.alignment);
13942 this.editing = true;
13944 Roo.QuickTips.disable();
13950 * Sets the height and width of this editor.
13951 * @param {Number} width The new width
13952 * @param {Number} height The new height
13954 setSize : function(w, h){
13955 this.field.setSize(w, h);
13962 * Realigns the editor to the bound field based on the current alignment config value.
13964 realign : function(){
13965 this.el.alignTo(this.boundEl, this.alignment);
13969 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13970 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13972 completeEdit : function(remainVisible){
13976 var v = this.getValue();
13977 if(this.revertInvalid !== false && !this.field.isValid()){
13978 v = this.startValue;
13979 this.cancelEdit(true);
13981 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13982 this.editing = false;
13986 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13987 this.editing = false;
13988 if(this.updateEl && this.boundEl){
13989 this.boundEl.update(v);
13991 if(remainVisible !== true){
13994 this.fireEvent("complete", this, v, this.startValue);
13999 onShow : function(){
14001 if(this.hideEl !== false){
14002 this.boundEl.hide();
14005 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14006 this.fixIEFocus = true;
14007 this.deferredFocus.defer(50, this);
14009 this.field.focus();
14011 this.fireEvent("startedit", this.boundEl, this.startValue);
14014 deferredFocus : function(){
14016 this.field.focus();
14021 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14022 * reverted to the original starting value.
14023 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14024 * cancel (defaults to false)
14026 cancelEdit : function(remainVisible){
14028 this.setValue(this.startValue);
14029 if(remainVisible !== true){
14036 onBlur : function(){
14037 if(this.allowBlur !== true && this.editing){
14038 this.completeEdit();
14043 onHide : function(){
14045 this.completeEdit();
14049 if(this.field.collapse){
14050 this.field.collapse();
14053 if(this.hideEl !== false){
14054 this.boundEl.show();
14057 Roo.QuickTips.enable();
14062 * Sets the data value of the editor
14063 * @param {Mixed} value Any valid value supported by the underlying field
14065 setValue : function(v){
14066 this.field.setValue(v);
14070 * Gets the data value of the editor
14071 * @return {Mixed} The data value
14073 getValue : function(){
14074 return this.field.getValue();
14078 * Ext JS Library 1.1.1
14079 * Copyright(c) 2006-2007, Ext JS, LLC.
14081 * Originally Released Under LGPL - original licence link has changed is not relivant.
14084 * <script type="text/javascript">
14088 * @class Roo.BasicDialog
14089 * @extends Roo.util.Observable
14090 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14092 var dlg = new Roo.BasicDialog("my-dlg", {
14101 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14102 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14103 dlg.addButton('Cancel', dlg.hide, dlg);
14106 <b>A Dialog should always be a direct child of the body element.</b>
14107 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14108 * @cfg {String} title Default text to display in the title bar (defaults to null)
14109 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14110 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14111 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14112 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14113 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14114 * (defaults to null with no animation)
14115 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14116 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14117 * property for valid values (defaults to 'all')
14118 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14119 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14120 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14121 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14122 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14123 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14124 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14125 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14126 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14127 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14128 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14129 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14130 * draggable = true (defaults to false)
14131 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14132 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14133 * shadow (defaults to false)
14134 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14135 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14136 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14137 * @cfg {Array} buttons Array of buttons
14138 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14140 * Create a new BasicDialog.
14141 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14142 * @param {Object} config Configuration options
14144 Roo.BasicDialog = function(el, config){
14145 this.el = Roo.get(el);
14146 var dh = Roo.DomHelper;
14147 if(!this.el && config && config.autoCreate){
14148 if(typeof config.autoCreate == "object"){
14149 if(!config.autoCreate.id){
14150 config.autoCreate.id = el;
14152 this.el = dh.append(document.body,
14153 config.autoCreate, true);
14155 this.el = dh.append(document.body,
14156 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14160 el.setDisplayed(true);
14161 el.hide = this.hideAction;
14163 el.addClass("x-dlg");
14165 Roo.apply(this, config);
14167 this.proxy = el.createProxy("x-dlg-proxy");
14168 this.proxy.hide = this.hideAction;
14169 this.proxy.setOpacity(.5);
14173 el.setWidth(config.width);
14176 el.setHeight(config.height);
14178 this.size = el.getSize();
14179 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14180 this.xy = [config.x,config.y];
14182 this.xy = el.getCenterXY(true);
14184 /** The header element @type Roo.Element */
14185 this.header = el.child("> .x-dlg-hd");
14186 /** The body element @type Roo.Element */
14187 this.body = el.child("> .x-dlg-bd");
14188 /** The footer element @type Roo.Element */
14189 this.footer = el.child("> .x-dlg-ft");
14192 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14195 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14198 this.header.unselectable();
14200 this.header.update(this.title);
14202 // this element allows the dialog to be focused for keyboard event
14203 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14204 this.focusEl.swallowEvent("click", true);
14206 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14208 // wrap the body and footer for special rendering
14209 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14211 this.bwrap.dom.appendChild(this.footer.dom);
14214 this.bg = this.el.createChild({
14215 tag: "div", cls:"x-dlg-bg",
14216 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14218 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14221 if(this.autoScroll !== false && !this.autoTabs){
14222 this.body.setStyle("overflow", "auto");
14225 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14227 if(this.closable !== false){
14228 this.el.addClass("x-dlg-closable");
14229 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14230 this.close.on("click", this.closeClick, this);
14231 this.close.addClassOnOver("x-dlg-close-over");
14233 if(this.collapsible !== false){
14234 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14235 this.collapseBtn.on("click", this.collapseClick, this);
14236 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14237 this.header.on("dblclick", this.collapseClick, this);
14239 if(this.resizable !== false){
14240 this.el.addClass("x-dlg-resizable");
14241 this.resizer = new Roo.Resizable(el, {
14242 minWidth: this.minWidth || 80,
14243 minHeight:this.minHeight || 80,
14244 handles: this.resizeHandles || "all",
14247 this.resizer.on("beforeresize", this.beforeResize, this);
14248 this.resizer.on("resize", this.onResize, this);
14250 if(this.draggable !== false){
14251 el.addClass("x-dlg-draggable");
14252 if (!this.proxyDrag) {
14253 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14256 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14258 dd.setHandleElId(this.header.id);
14259 dd.endDrag = this.endMove.createDelegate(this);
14260 dd.startDrag = this.startMove.createDelegate(this);
14261 dd.onDrag = this.onDrag.createDelegate(this);
14266 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14267 this.mask.enableDisplayMode("block");
14269 this.el.addClass("x-dlg-modal");
14272 this.shadow = new Roo.Shadow({
14273 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14274 offset : this.shadowOffset
14277 this.shadowOffset = 0;
14279 if(Roo.useShims && this.shim !== false){
14280 this.shim = this.el.createShim();
14281 this.shim.hide = this.hideAction;
14289 if (this.buttons) {
14290 var bts= this.buttons;
14292 Roo.each(bts, function(b) {
14301 * Fires when a key is pressed
14302 * @param {Roo.BasicDialog} this
14303 * @param {Roo.EventObject} e
14308 * Fires when this dialog is moved by the user.
14309 * @param {Roo.BasicDialog} this
14310 * @param {Number} x The new page X
14311 * @param {Number} y The new page Y
14316 * Fires when this dialog is resized by the user.
14317 * @param {Roo.BasicDialog} this
14318 * @param {Number} width The new width
14319 * @param {Number} height The new height
14323 * @event beforehide
14324 * Fires before this dialog is hidden.
14325 * @param {Roo.BasicDialog} this
14327 "beforehide" : true,
14330 * Fires when this dialog is hidden.
14331 * @param {Roo.BasicDialog} this
14335 * @event beforeshow
14336 * Fires before this dialog is shown.
14337 * @param {Roo.BasicDialog} this
14339 "beforeshow" : true,
14342 * Fires when this dialog is shown.
14343 * @param {Roo.BasicDialog} this
14347 el.on("keydown", this.onKeyDown, this);
14348 el.on("mousedown", this.toFront, this);
14349 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14351 Roo.DialogManager.register(this);
14352 Roo.BasicDialog.superclass.constructor.call(this);
14355 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14356 shadowOffset: Roo.isIE ? 6 : 5,
14359 minButtonWidth: 75,
14360 defaultButton: null,
14361 buttonAlign: "right",
14366 * Sets the dialog title text
14367 * @param {String} text The title text to display
14368 * @return {Roo.BasicDialog} this
14370 setTitle : function(text){
14371 this.header.update(text);
14376 closeClick : function(){
14381 collapseClick : function(){
14382 this[this.collapsed ? "expand" : "collapse"]();
14386 * Collapses the dialog to its minimized state (only the title bar is visible).
14387 * Equivalent to the user clicking the collapse dialog button.
14389 collapse : function(){
14390 if(!this.collapsed){
14391 this.collapsed = true;
14392 this.el.addClass("x-dlg-collapsed");
14393 this.restoreHeight = this.el.getHeight();
14394 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14399 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14400 * clicking the expand dialog button.
14402 expand : function(){
14403 if(this.collapsed){
14404 this.collapsed = false;
14405 this.el.removeClass("x-dlg-collapsed");
14406 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14411 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14412 * @return {Roo.TabPanel} The tabs component
14414 initTabs : function(){
14415 var tabs = this.getTabs();
14416 while(tabs.getTab(0)){
14419 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14421 tabs.addTab(Roo.id(dom), dom.title);
14429 beforeResize : function(){
14430 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14434 onResize : function(){
14435 this.refreshSize();
14436 this.syncBodyHeight();
14437 this.adjustAssets();
14439 this.fireEvent("resize", this, this.size.width, this.size.height);
14443 onKeyDown : function(e){
14444 if(this.isVisible()){
14445 this.fireEvent("keydown", this, e);
14450 * Resizes the dialog.
14451 * @param {Number} width
14452 * @param {Number} height
14453 * @return {Roo.BasicDialog} this
14455 resizeTo : function(width, height){
14456 this.el.setSize(width, height);
14457 this.size = {width: width, height: height};
14458 this.syncBodyHeight();
14459 if(this.fixedcenter){
14462 if(this.isVisible()){
14463 this.constrainXY();
14464 this.adjustAssets();
14466 this.fireEvent("resize", this, width, height);
14472 * Resizes the dialog to fit the specified content size.
14473 * @param {Number} width
14474 * @param {Number} height
14475 * @return {Roo.BasicDialog} this
14477 setContentSize : function(w, h){
14478 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14479 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14480 //if(!this.el.isBorderBox()){
14481 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14482 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14485 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14486 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14488 this.resizeTo(w, h);
14493 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14494 * executed in response to a particular key being pressed while the dialog is active.
14495 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14496 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14497 * @param {Function} fn The function to call
14498 * @param {Object} scope (optional) The scope of the function
14499 * @return {Roo.BasicDialog} this
14501 addKeyListener : function(key, fn, scope){
14502 var keyCode, shift, ctrl, alt;
14503 if(typeof key == "object" && !(key instanceof Array)){
14504 keyCode = key["key"];
14505 shift = key["shift"];
14506 ctrl = key["ctrl"];
14511 var handler = function(dlg, e){
14512 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14513 var k = e.getKey();
14514 if(keyCode instanceof Array){
14515 for(var i = 0, len = keyCode.length; i < len; i++){
14516 if(keyCode[i] == k){
14517 fn.call(scope || window, dlg, k, e);
14523 fn.call(scope || window, dlg, k, e);
14528 this.on("keydown", handler);
14533 * Returns the TabPanel component (creates it if it doesn't exist).
14534 * Note: If you wish to simply check for the existence of tabs without creating them,
14535 * check for a null 'tabs' property.
14536 * @return {Roo.TabPanel} The tabs component
14538 getTabs : function(){
14540 this.el.addClass("x-dlg-auto-tabs");
14541 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14542 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14548 * Adds a button to the footer section of the dialog.
14549 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14550 * object or a valid Roo.DomHelper element config
14551 * @param {Function} handler The function called when the button is clicked
14552 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14553 * @return {Roo.Button} The new button
14555 addButton : function(config, handler, scope){
14556 var dh = Roo.DomHelper;
14558 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14560 if(!this.btnContainer){
14561 var tb = this.footer.createChild({
14563 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14564 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14566 this.btnContainer = tb.firstChild.firstChild.firstChild;
14571 minWidth: this.minButtonWidth,
14574 if(typeof config == "string"){
14575 bconfig.text = config;
14578 bconfig.dhconfig = config;
14580 Roo.apply(bconfig, config);
14584 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14585 bconfig.position = Math.max(0, bconfig.position);
14586 fc = this.btnContainer.childNodes[bconfig.position];
14589 var btn = new Roo.Button(
14591 this.btnContainer.insertBefore(document.createElement("td"),fc)
14592 : this.btnContainer.appendChild(document.createElement("td")),
14593 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14596 this.syncBodyHeight();
14599 * Array of all the buttons that have been added to this dialog via addButton
14604 this.buttons.push(btn);
14609 * Sets the default button to be focused when the dialog is displayed.
14610 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14611 * @return {Roo.BasicDialog} this
14613 setDefaultButton : function(btn){
14614 this.defaultButton = btn;
14619 getHeaderFooterHeight : function(safe){
14622 height += this.header.getHeight();
14625 var fm = this.footer.getMargins();
14626 height += (this.footer.getHeight()+fm.top+fm.bottom);
14628 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14629 height += this.centerBg.getPadding("tb");
14634 syncBodyHeight : function(){
14635 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14636 var height = this.size.height - this.getHeaderFooterHeight(false);
14637 bd.setHeight(height-bd.getMargins("tb"));
14638 var hh = this.header.getHeight();
14639 var h = this.size.height-hh;
14641 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14642 bw.setHeight(h-cb.getPadding("tb"));
14643 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14644 bd.setWidth(bw.getWidth(true));
14646 this.tabs.syncHeight();
14648 this.tabs.el.repaint();
14654 * Restores the previous state of the dialog if Roo.state is configured.
14655 * @return {Roo.BasicDialog} this
14657 restoreState : function(){
14658 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14659 if(box && box.width){
14660 this.xy = [box.x, box.y];
14661 this.resizeTo(box.width, box.height);
14667 beforeShow : function(){
14669 if(this.fixedcenter){
14670 this.xy = this.el.getCenterXY(true);
14673 Roo.get(document.body).addClass("x-body-masked");
14674 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14677 this.constrainXY();
14681 animShow : function(){
14682 var b = Roo.get(this.animateTarget).getBox();
14683 this.proxy.setSize(b.width, b.height);
14684 this.proxy.setLocation(b.x, b.y);
14686 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14687 true, .35, this.showEl.createDelegate(this));
14691 * Shows the dialog.
14692 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14693 * @return {Roo.BasicDialog} this
14695 show : function(animateTarget){
14696 if (this.fireEvent("beforeshow", this) === false){
14699 if(this.syncHeightBeforeShow){
14700 this.syncBodyHeight();
14701 }else if(this.firstShow){
14702 this.firstShow = false;
14703 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14705 this.animateTarget = animateTarget || this.animateTarget;
14706 if(!this.el.isVisible()){
14708 if(this.animateTarget && Roo.get(this.animateTarget)){
14718 showEl : function(){
14720 this.el.setXY(this.xy);
14722 this.adjustAssets(true);
14725 // IE peekaboo bug - fix found by Dave Fenwick
14729 this.fireEvent("show", this);
14733 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14734 * dialog itself will receive focus.
14736 focus : function(){
14737 if(this.defaultButton){
14738 this.defaultButton.focus();
14740 this.focusEl.focus();
14745 constrainXY : function(){
14746 if(this.constraintoviewport !== false){
14747 if(!this.viewSize){
14748 if(this.container){
14749 var s = this.container.getSize();
14750 this.viewSize = [s.width, s.height];
14752 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14755 var s = Roo.get(this.container||document).getScroll();
14757 var x = this.xy[0], y = this.xy[1];
14758 var w = this.size.width, h = this.size.height;
14759 var vw = this.viewSize[0], vh = this.viewSize[1];
14760 // only move it if it needs it
14762 // first validate right/bottom
14763 if(x + w > vw+s.left){
14767 if(y + h > vh+s.top){
14771 // then make sure top/left isn't negative
14783 if(this.isVisible()){
14784 this.el.setLocation(x, y);
14785 this.adjustAssets();
14792 onDrag : function(){
14793 if(!this.proxyDrag){
14794 this.xy = this.el.getXY();
14795 this.adjustAssets();
14800 adjustAssets : function(doShow){
14801 var x = this.xy[0], y = this.xy[1];
14802 var w = this.size.width, h = this.size.height;
14803 if(doShow === true){
14805 this.shadow.show(this.el);
14811 if(this.shadow && this.shadow.isVisible()){
14812 this.shadow.show(this.el);
14814 if(this.shim && this.shim.isVisible()){
14815 this.shim.setBounds(x, y, w, h);
14820 adjustViewport : function(w, h){
14822 w = Roo.lib.Dom.getViewWidth();
14823 h = Roo.lib.Dom.getViewHeight();
14826 this.viewSize = [w, h];
14827 if(this.modal && this.mask.isVisible()){
14828 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14829 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14831 if(this.isVisible()){
14832 this.constrainXY();
14837 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14838 * shadow, proxy, mask, etc.) Also removes all event listeners.
14839 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14841 destroy : function(removeEl){
14842 if(this.isVisible()){
14843 this.animateTarget = null;
14846 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14848 this.tabs.destroy(removeEl);
14861 for(var i = 0, len = this.buttons.length; i < len; i++){
14862 this.buttons[i].destroy();
14865 this.el.removeAllListeners();
14866 if(removeEl === true){
14867 this.el.update("");
14870 Roo.DialogManager.unregister(this);
14874 startMove : function(){
14875 if(this.proxyDrag){
14878 if(this.constraintoviewport !== false){
14879 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14884 endMove : function(){
14885 if(!this.proxyDrag){
14886 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14888 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14891 this.refreshSize();
14892 this.adjustAssets();
14894 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14898 * Brings this dialog to the front of any other visible dialogs
14899 * @return {Roo.BasicDialog} this
14901 toFront : function(){
14902 Roo.DialogManager.bringToFront(this);
14907 * Sends this dialog to the back (under) of any other visible dialogs
14908 * @return {Roo.BasicDialog} this
14910 toBack : function(){
14911 Roo.DialogManager.sendToBack(this);
14916 * Centers this dialog in the viewport
14917 * @return {Roo.BasicDialog} this
14919 center : function(){
14920 var xy = this.el.getCenterXY(true);
14921 this.moveTo(xy[0], xy[1]);
14926 * Moves the dialog's top-left corner to the specified point
14927 * @param {Number} x
14928 * @param {Number} y
14929 * @return {Roo.BasicDialog} this
14931 moveTo : function(x, y){
14933 if(this.isVisible()){
14934 this.el.setXY(this.xy);
14935 this.adjustAssets();
14941 * Aligns the dialog to the specified element
14942 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14943 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14944 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14945 * @return {Roo.BasicDialog} this
14947 alignTo : function(element, position, offsets){
14948 this.xy = this.el.getAlignToXY(element, position, offsets);
14949 if(this.isVisible()){
14950 this.el.setXY(this.xy);
14951 this.adjustAssets();
14957 * Anchors an element to another element and realigns it when the window is resized.
14958 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14959 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14960 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14961 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14962 * is a number, it is used as the buffer delay (defaults to 50ms).
14963 * @return {Roo.BasicDialog} this
14965 anchorTo : function(el, alignment, offsets, monitorScroll){
14966 var action = function(){
14967 this.alignTo(el, alignment, offsets);
14969 Roo.EventManager.onWindowResize(action, this);
14970 var tm = typeof monitorScroll;
14971 if(tm != 'undefined'){
14972 Roo.EventManager.on(window, 'scroll', action, this,
14973 {buffer: tm == 'number' ? monitorScroll : 50});
14980 * Returns true if the dialog is visible
14981 * @return {Boolean}
14983 isVisible : function(){
14984 return this.el.isVisible();
14988 animHide : function(callback){
14989 var b = Roo.get(this.animateTarget).getBox();
14991 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
14993 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
14994 this.hideEl.createDelegate(this, [callback]));
14998 * Hides the dialog.
14999 * @param {Function} callback (optional) Function to call when the dialog is hidden
15000 * @return {Roo.BasicDialog} this
15002 hide : function(callback){
15003 if (this.fireEvent("beforehide", this) === false){
15007 this.shadow.hide();
15012 // sometimes animateTarget seems to get set.. causing problems...
15013 // this just double checks..
15014 if(this.animateTarget && Roo.get(this.animateTarget)) {
15015 this.animHide(callback);
15018 this.hideEl(callback);
15024 hideEl : function(callback){
15028 Roo.get(document.body).removeClass("x-body-masked");
15030 this.fireEvent("hide", this);
15031 if(typeof callback == "function"){
15037 hideAction : function(){
15038 this.setLeft("-10000px");
15039 this.setTop("-10000px");
15040 this.setStyle("visibility", "hidden");
15044 refreshSize : function(){
15045 this.size = this.el.getSize();
15046 this.xy = this.el.getXY();
15047 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15051 // z-index is managed by the DialogManager and may be overwritten at any time
15052 setZIndex : function(index){
15054 this.mask.setStyle("z-index", index);
15057 this.shim.setStyle("z-index", ++index);
15060 this.shadow.setZIndex(++index);
15062 this.el.setStyle("z-index", ++index);
15064 this.proxy.setStyle("z-index", ++index);
15067 this.resizer.proxy.setStyle("z-index", ++index);
15070 this.lastZIndex = index;
15074 * Returns the element for this dialog
15075 * @return {Roo.Element} The underlying dialog Element
15077 getEl : function(){
15083 * @class Roo.DialogManager
15084 * Provides global access to BasicDialogs that have been created and
15085 * support for z-indexing (layering) multiple open dialogs.
15087 Roo.DialogManager = function(){
15089 var accessList = [];
15093 var sortDialogs = function(d1, d2){
15094 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15098 var orderDialogs = function(){
15099 accessList.sort(sortDialogs);
15100 var seed = Roo.DialogManager.zseed;
15101 for(var i = 0, len = accessList.length; i < len; i++){
15102 var dlg = accessList[i];
15104 dlg.setZIndex(seed + (i*10));
15111 * The starting z-index for BasicDialogs (defaults to 9000)
15112 * @type Number The z-index value
15117 register : function(dlg){
15118 list[dlg.id] = dlg;
15119 accessList.push(dlg);
15123 unregister : function(dlg){
15124 delete list[dlg.id];
15127 if(!accessList.indexOf){
15128 for( i = 0, len = accessList.length; i < len; i++){
15129 if(accessList[i] == dlg){
15130 accessList.splice(i, 1);
15135 i = accessList.indexOf(dlg);
15137 accessList.splice(i, 1);
15143 * Gets a registered dialog by id
15144 * @param {String/Object} id The id of the dialog or a dialog
15145 * @return {Roo.BasicDialog} this
15147 get : function(id){
15148 return typeof id == "object" ? id : list[id];
15152 * Brings the specified dialog to the front
15153 * @param {String/Object} dlg The id of the dialog or a dialog
15154 * @return {Roo.BasicDialog} this
15156 bringToFront : function(dlg){
15157 dlg = this.get(dlg);
15160 dlg._lastAccess = new Date().getTime();
15167 * Sends the specified dialog to the back
15168 * @param {String/Object} dlg The id of the dialog or a dialog
15169 * @return {Roo.BasicDialog} this
15171 sendToBack : function(dlg){
15172 dlg = this.get(dlg);
15173 dlg._lastAccess = -(new Date().getTime());
15179 * Hides all dialogs
15181 hideAll : function(){
15182 for(var id in list){
15183 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15192 * @class Roo.LayoutDialog
15193 * @extends Roo.BasicDialog
15194 * Dialog which provides adjustments for working with a layout in a Dialog.
15195 * Add your necessary layout config options to the dialog's config.<br>
15196 * Example usage (including a nested layout):
15199 dialog = new Roo.LayoutDialog("download-dlg", {
15208 // layout config merges with the dialog config
15210 tabPosition: "top",
15211 alwaysShowTabs: true
15214 dialog.addKeyListener(27, dialog.hide, dialog);
15215 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15216 dialog.addButton("Build It!", this.getDownload, this);
15218 // we can even add nested layouts
15219 var innerLayout = new Roo.BorderLayout("dl-inner", {
15229 innerLayout.beginUpdate();
15230 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15231 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15232 innerLayout.endUpdate(true);
15234 var layout = dialog.getLayout();
15235 layout.beginUpdate();
15236 layout.add("center", new Roo.ContentPanel("standard-panel",
15237 {title: "Download the Source", fitToFrame:true}));
15238 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15239 {title: "Build your own roo.js"}));
15240 layout.getRegion("center").showPanel(sp);
15241 layout.endUpdate();
15245 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15246 * @param {Object} config configuration options
15248 Roo.LayoutDialog = function(el, cfg){
15251 if (typeof(cfg) == 'undefined') {
15252 config = Roo.apply({}, el);
15253 // not sure why we use documentElement here.. - it should always be body.
15254 // IE7 borks horribly if we use documentElement.
15255 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15256 //config.autoCreate = true;
15260 config.autoTabs = false;
15261 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15262 this.body.setStyle({overflow:"hidden", position:"relative"});
15263 this.layout = new Roo.BorderLayout(this.body.dom, config);
15264 this.layout.monitorWindowResize = false;
15265 this.el.addClass("x-dlg-auto-layout");
15266 // fix case when center region overwrites center function
15267 this.center = Roo.BasicDialog.prototype.center;
15268 this.on("show", this.layout.layout, this.layout, true);
15269 if (config.items) {
15270 var xitems = config.items;
15271 delete config.items;
15272 Roo.each(xitems, this.addxtype, this);
15277 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15279 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15282 endUpdate : function(){
15283 this.layout.endUpdate();
15287 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15290 beginUpdate : function(){
15291 this.layout.beginUpdate();
15295 * Get the BorderLayout for this dialog
15296 * @return {Roo.BorderLayout}
15298 getLayout : function(){
15299 return this.layout;
15302 showEl : function(){
15303 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15305 this.layout.layout();
15310 // Use the syncHeightBeforeShow config option to control this automatically
15311 syncBodyHeight : function(){
15312 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15313 if(this.layout){this.layout.layout();}
15317 * Add an xtype element (actually adds to the layout.)
15318 * @return {Object} xdata xtype object data.
15321 addxtype : function(c) {
15322 return this.layout.addxtype(c);
15326 * Ext JS Library 1.1.1
15327 * Copyright(c) 2006-2007, Ext JS, LLC.
15329 * Originally Released Under LGPL - original licence link has changed is not relivant.
15332 * <script type="text/javascript">
15336 * @class Roo.MessageBox
15337 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15341 Roo.Msg.alert('Status', 'Changes saved successfully.');
15343 // Prompt for user data:
15344 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15346 // process text value...
15350 // Show a dialog using config options:
15352 title:'Save Changes?',
15353 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15354 buttons: Roo.Msg.YESNOCANCEL,
15361 Roo.MessageBox = function(){
15362 var dlg, opt, mask, waitTimer;
15363 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15364 var buttons, activeTextEl, bwidth;
15367 var handleButton = function(button){
15369 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15373 var handleHide = function(){
15374 if(opt && opt.cls){
15375 dlg.el.removeClass(opt.cls);
15378 Roo.TaskMgr.stop(waitTimer);
15384 var updateButtons = function(b){
15387 buttons["ok"].hide();
15388 buttons["cancel"].hide();
15389 buttons["yes"].hide();
15390 buttons["no"].hide();
15391 dlg.footer.dom.style.display = 'none';
15394 dlg.footer.dom.style.display = '';
15395 for(var k in buttons){
15396 if(typeof buttons[k] != "function"){
15399 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15400 width += buttons[k].el.getWidth()+15;
15410 var handleEsc = function(d, k, e){
15411 if(opt && opt.closable !== false){
15421 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15422 * @return {Roo.BasicDialog} The BasicDialog element
15424 getDialog : function(){
15426 dlg = new Roo.BasicDialog("x-msg-box", {
15431 constraintoviewport:false,
15433 collapsible : false,
15436 width:400, height:100,
15437 buttonAlign:"center",
15438 closeClick : function(){
15439 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15440 handleButton("no");
15442 handleButton("cancel");
15446 dlg.on("hide", handleHide);
15448 dlg.addKeyListener(27, handleEsc);
15450 var bt = this.buttonText;
15451 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15452 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15453 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15454 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15455 bodyEl = dlg.body.createChild({
15457 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>'
15459 msgEl = bodyEl.dom.firstChild;
15460 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15461 textboxEl.enableDisplayMode();
15462 textboxEl.addKeyListener([10,13], function(){
15463 if(dlg.isVisible() && opt && opt.buttons){
15464 if(opt.buttons.ok){
15465 handleButton("ok");
15466 }else if(opt.buttons.yes){
15467 handleButton("yes");
15471 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15472 textareaEl.enableDisplayMode();
15473 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15474 progressEl.enableDisplayMode();
15475 var pf = progressEl.dom.firstChild;
15477 pp = Roo.get(pf.firstChild);
15478 pp.setHeight(pf.offsetHeight);
15486 * Updates the message box body text
15487 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15488 * the XHTML-compliant non-breaking space character '&#160;')
15489 * @return {Roo.MessageBox} This message box
15491 updateText : function(text){
15492 if(!dlg.isVisible() && !opt.width){
15493 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15495 msgEl.innerHTML = text || ' ';
15496 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15497 Math.max(opt.minWidth || this.minWidth, bwidth));
15499 activeTextEl.setWidth(w);
15501 if(dlg.isVisible()){
15502 dlg.fixedcenter = false;
15504 dlg.setContentSize(w, bodyEl.getHeight());
15505 if(dlg.isVisible()){
15506 dlg.fixedcenter = true;
15512 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15513 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15514 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15515 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15516 * @return {Roo.MessageBox} This message box
15518 updateProgress : function(value, text){
15520 this.updateText(text);
15522 if (pp) { // weird bug on my firefox - for some reason this is not defined
15523 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15529 * Returns true if the message box is currently displayed
15530 * @return {Boolean} True if the message box is visible, else false
15532 isVisible : function(){
15533 return dlg && dlg.isVisible();
15537 * Hides the message box if it is displayed
15540 if(this.isVisible()){
15546 * Displays a new message box, or reinitializes an existing message box, based on the config options
15547 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15548 * The following config object properties are supported:
15550 Property Type Description
15551 ---------- --------------- ------------------------------------------------------------------------------------
15552 animEl String/Element An id or Element from which the message box should animate as it opens and
15553 closes (defaults to undefined)
15554 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15555 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15556 closable Boolean False to hide the top-right close button (defaults to true). Note that
15557 progress and wait dialogs will ignore this property and always hide the
15558 close button as they can only be closed programmatically.
15559 cls String A custom CSS class to apply to the message box element
15560 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15561 displayed (defaults to 75)
15562 fn Function A callback function to execute after closing the dialog. The arguments to the
15563 function will be btn (the name of the button that was clicked, if applicable,
15564 e.g. "ok"), and text (the value of the active text field, if applicable).
15565 Progress and wait dialogs will ignore this option since they do not respond to
15566 user actions and can only be closed programmatically, so any required function
15567 should be called by the same code after it closes the dialog.
15568 icon String A CSS class that provides a background image to be used as an icon for
15569 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15570 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15571 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15572 modal Boolean False to allow user interaction with the page while the message box is
15573 displayed (defaults to true)
15574 msg String A string that will replace the existing message box body text (defaults
15575 to the XHTML-compliant non-breaking space character ' ')
15576 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15577 progress Boolean True to display a progress bar (defaults to false)
15578 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15579 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15580 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15581 title String The title text
15582 value String The string value to set into the active textbox element if displayed
15583 wait Boolean True to display a progress bar (defaults to false)
15584 width Number The width of the dialog in pixels
15591 msg: 'Please enter your address:',
15593 buttons: Roo.MessageBox.OKCANCEL,
15596 animEl: 'addAddressBtn'
15599 * @param {Object} config Configuration options
15600 * @return {Roo.MessageBox} This message box
15602 show : function(options){
15603 if(this.isVisible()){
15606 var d = this.getDialog();
15608 d.setTitle(opt.title || " ");
15609 d.close.setDisplayed(opt.closable !== false);
15610 activeTextEl = textboxEl;
15611 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15616 textareaEl.setHeight(typeof opt.multiline == "number" ?
15617 opt.multiline : this.defaultTextHeight);
15618 activeTextEl = textareaEl;
15627 progressEl.setDisplayed(opt.progress === true);
15628 this.updateProgress(0);
15629 activeTextEl.dom.value = opt.value || "";
15631 dlg.setDefaultButton(activeTextEl);
15633 var bs = opt.buttons;
15636 db = buttons["ok"];
15637 }else if(bs && bs.yes){
15638 db = buttons["yes"];
15640 dlg.setDefaultButton(db);
15642 bwidth = updateButtons(opt.buttons);
15643 this.updateText(opt.msg);
15645 d.el.addClass(opt.cls);
15647 d.proxyDrag = opt.proxyDrag === true;
15648 d.modal = opt.modal !== false;
15649 d.mask = opt.modal !== false ? mask : false;
15650 if(!d.isVisible()){
15651 // force it to the end of the z-index stack so it gets a cursor in FF
15652 document.body.appendChild(dlg.el.dom);
15653 d.animateTarget = null;
15654 d.show(options.animEl);
15660 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15661 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15662 * and closing the message box when the process is complete.
15663 * @param {String} title The title bar text
15664 * @param {String} msg The message box body text
15665 * @return {Roo.MessageBox} This message box
15667 progress : function(title, msg){
15674 minWidth: this.minProgressWidth,
15681 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15682 * If a callback function is passed it will be called after the user clicks the button, and the
15683 * id of the button that was clicked will be passed as the only parameter to the callback
15684 * (could also be the top-right close button).
15685 * @param {String} title The title bar text
15686 * @param {String} msg The message box body text
15687 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15688 * @param {Object} scope (optional) The scope of the callback function
15689 * @return {Roo.MessageBox} This message box
15691 alert : function(title, msg, fn, scope){
15704 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15705 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15706 * You are responsible for closing the message box when the process is complete.
15707 * @param {String} msg The message box body text
15708 * @param {String} title (optional) The title bar text
15709 * @return {Roo.MessageBox} This message box
15711 wait : function(msg, title){
15722 waitTimer = Roo.TaskMgr.start({
15724 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15732 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15733 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15734 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15735 * @param {String} title The title bar text
15736 * @param {String} msg The message box body text
15737 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15738 * @param {Object} scope (optional) The scope of the callback function
15739 * @return {Roo.MessageBox} This message box
15741 confirm : function(title, msg, fn, scope){
15745 buttons: this.YESNO,
15754 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15755 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15756 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15757 * (could also be the top-right close button) and the text that was entered will be passed as the two
15758 * parameters to the callback.
15759 * @param {String} title The title bar text
15760 * @param {String} msg The message box body text
15761 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15762 * @param {Object} scope (optional) The scope of the callback function
15763 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15764 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15765 * @return {Roo.MessageBox} This message box
15767 prompt : function(title, msg, fn, scope, multiline){
15771 buttons: this.OKCANCEL,
15776 multiline: multiline,
15783 * Button config that displays a single OK button
15788 * Button config that displays Yes and No buttons
15791 YESNO : {yes:true, no:true},
15793 * Button config that displays OK and Cancel buttons
15796 OKCANCEL : {ok:true, cancel:true},
15798 * Button config that displays Yes, No and Cancel buttons
15801 YESNOCANCEL : {yes:true, no:true, cancel:true},
15804 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15807 defaultTextHeight : 75,
15809 * The maximum width in pixels of the message box (defaults to 600)
15814 * The minimum width in pixels of the message box (defaults to 100)
15819 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15820 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15823 minProgressWidth : 250,
15825 * An object containing the default button text strings that can be overriden for localized language support.
15826 * Supported properties are: ok, cancel, yes and no.
15827 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15840 * Shorthand for {@link Roo.MessageBox}
15842 Roo.Msg = Roo.MessageBox;/*
15844 * Ext JS Library 1.1.1
15845 * Copyright(c) 2006-2007, Ext JS, LLC.
15847 * Originally Released Under LGPL - original licence link has changed is not relivant.
15850 * <script type="text/javascript">
15853 * @class Roo.QuickTips
15854 * Provides attractive and customizable tooltips for any element.
15857 Roo.QuickTips = function(){
15858 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15859 var ce, bd, xy, dd;
15860 var visible = false, disabled = true, inited = false;
15861 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15863 var onOver = function(e){
15867 var t = e.getTarget();
15868 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15871 if(ce && t == ce.el){
15872 clearTimeout(hideProc);
15875 if(t && tagEls[t.id]){
15876 tagEls[t.id].el = t;
15877 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15880 var ttp, et = Roo.fly(t);
15881 var ns = cfg.namespace;
15882 if(tm.interceptTitles && t.title){
15885 t.removeAttribute("title");
15886 e.preventDefault();
15888 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15891 showProc = show.defer(tm.showDelay, tm, [{
15894 width: et.getAttributeNS(ns, cfg.width),
15895 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15896 title: et.getAttributeNS(ns, cfg.title),
15897 cls: et.getAttributeNS(ns, cfg.cls)
15902 var onOut = function(e){
15903 clearTimeout(showProc);
15904 var t = e.getTarget();
15905 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15906 hideProc = setTimeout(hide, tm.hideDelay);
15910 var onMove = function(e){
15916 if(tm.trackMouse && ce){
15921 var onDown = function(e){
15922 clearTimeout(showProc);
15923 clearTimeout(hideProc);
15925 if(tm.hideOnClick){
15928 tm.enable.defer(100, tm);
15933 var getPad = function(){
15934 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15937 var show = function(o){
15941 clearTimeout(dismissProc);
15943 if(removeCls){ // in case manually hidden
15944 el.removeClass(removeCls);
15948 el.addClass(ce.cls);
15949 removeCls = ce.cls;
15952 tipTitle.update(ce.title);
15955 tipTitle.update('');
15958 el.dom.style.width = tm.maxWidth+'px';
15959 //tipBody.dom.style.width = '';
15960 tipBodyText.update(o.text);
15961 var p = getPad(), w = ce.width;
15963 var td = tipBodyText.dom;
15964 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15965 if(aw > tm.maxWidth){
15967 }else if(aw < tm.minWidth){
15973 //tipBody.setWidth(w);
15974 el.setWidth(parseInt(w, 10) + p);
15975 if(ce.autoHide === false){
15976 close.setDisplayed(true);
15981 close.setDisplayed(false);
15987 el.avoidY = xy[1]-18;
15992 el.setStyle("visibility", "visible");
15993 el.fadeIn({callback: afterShow});
15999 var afterShow = function(){
16003 if(tm.autoDismiss && ce.autoHide !== false){
16004 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16009 var hide = function(noanim){
16010 clearTimeout(dismissProc);
16011 clearTimeout(hideProc);
16013 if(el.isVisible()){
16015 if(noanim !== true && tm.animate){
16016 el.fadeOut({callback: afterHide});
16023 var afterHide = function(){
16026 el.removeClass(removeCls);
16033 * @cfg {Number} minWidth
16034 * The minimum width of the quick tip (defaults to 40)
16038 * @cfg {Number} maxWidth
16039 * The maximum width of the quick tip (defaults to 300)
16043 * @cfg {Boolean} interceptTitles
16044 * True to automatically use the element's DOM title value if available (defaults to false)
16046 interceptTitles : false,
16048 * @cfg {Boolean} trackMouse
16049 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16051 trackMouse : false,
16053 * @cfg {Boolean} hideOnClick
16054 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16056 hideOnClick : true,
16058 * @cfg {Number} showDelay
16059 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16063 * @cfg {Number} hideDelay
16064 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16068 * @cfg {Boolean} autoHide
16069 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16070 * Used in conjunction with hideDelay.
16075 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16076 * (defaults to true). Used in conjunction with autoDismissDelay.
16078 autoDismiss : true,
16081 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16083 autoDismissDelay : 5000,
16085 * @cfg {Boolean} animate
16086 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16091 * @cfg {String} title
16092 * Title text to display (defaults to ''). This can be any valid HTML markup.
16096 * @cfg {String} text
16097 * Body text to display (defaults to ''). This can be any valid HTML markup.
16101 * @cfg {String} cls
16102 * A CSS class to apply to the base quick tip element (defaults to '').
16106 * @cfg {Number} width
16107 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16108 * minWidth or maxWidth.
16113 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16114 * or display QuickTips in a page.
16117 tm = Roo.QuickTips;
16118 cfg = tm.tagConfig;
16120 if(!Roo.isReady){ // allow calling of init() before onReady
16121 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16124 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16125 el.fxDefaults = {stopFx: true};
16126 // maximum custom styling
16127 //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>');
16128 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>');
16129 tipTitle = el.child('h3');
16130 tipTitle.enableDisplayMode("block");
16131 tipBody = el.child('div.x-tip-bd');
16132 tipBodyText = el.child('div.x-tip-bd-inner');
16133 //bdLeft = el.child('div.x-tip-bd-left');
16134 //bdRight = el.child('div.x-tip-bd-right');
16135 close = el.child('div.x-tip-close');
16136 close.enableDisplayMode("block");
16137 close.on("click", hide);
16138 var d = Roo.get(document);
16139 d.on("mousedown", onDown);
16140 d.on("mouseover", onOver);
16141 d.on("mouseout", onOut);
16142 d.on("mousemove", onMove);
16143 esc = d.addKeyListener(27, hide);
16146 dd = el.initDD("default", null, {
16147 onDrag : function(){
16151 dd.setHandleElId(tipTitle.id);
16160 * Configures a new quick tip instance and assigns it to a target element. The following config options
16163 Property Type Description
16164 ---------- --------------------- ------------------------------------------------------------------------
16165 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16167 * @param {Object} config The config object
16169 register : function(config){
16170 var cs = config instanceof Array ? config : arguments;
16171 for(var i = 0, len = cs.length; i < len; i++) {
16173 var target = c.target;
16175 if(target instanceof Array){
16176 for(var j = 0, jlen = target.length; j < jlen; j++){
16177 tagEls[target[j]] = c;
16180 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16187 * Removes this quick tip from its element and destroys it.
16188 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16190 unregister : function(el){
16191 delete tagEls[Roo.id(el)];
16195 * Enable this quick tip.
16197 enable : function(){
16198 if(inited && disabled){
16200 if(locks.length < 1){
16207 * Disable this quick tip.
16209 disable : function(){
16211 clearTimeout(showProc);
16212 clearTimeout(hideProc);
16213 clearTimeout(dismissProc);
16221 * Returns true if the quick tip is enabled, else false.
16223 isEnabled : function(){
16230 attribute : "qtip",
16240 // backwards compat
16241 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16243 * Ext JS Library 1.1.1
16244 * Copyright(c) 2006-2007, Ext JS, LLC.
16246 * Originally Released Under LGPL - original licence link has changed is not relivant.
16249 * <script type="text/javascript">
16254 * @class Roo.tree.TreePanel
16255 * @extends Roo.data.Tree
16257 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16258 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16259 * @cfg {Boolean} enableDD true to enable drag and drop
16260 * @cfg {Boolean} enableDrag true to enable just drag
16261 * @cfg {Boolean} enableDrop true to enable just drop
16262 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16263 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16264 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16265 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16266 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16267 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16268 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16269 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16270 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16271 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16272 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16273 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16274 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16275 * @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>
16276 * @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>
16279 * @param {String/HTMLElement/Element} el The container element
16280 * @param {Object} config
16282 Roo.tree.TreePanel = function(el, config){
16284 var loader = false;
16286 root = config.root;
16287 delete config.root;
16289 if (config.loader) {
16290 loader = config.loader;
16291 delete config.loader;
16294 Roo.apply(this, config);
16295 Roo.tree.TreePanel.superclass.constructor.call(this);
16296 this.el = Roo.get(el);
16297 this.el.addClass('x-tree');
16298 //console.log(root);
16300 this.setRootNode( Roo.factory(root, Roo.tree));
16303 this.loader = Roo.factory(loader, Roo.tree);
16306 * Read-only. The id of the container element becomes this TreePanel's id.
16308 this.id = this.el.id;
16311 * @event beforeload
16312 * Fires before a node is loaded, return false to cancel
16313 * @param {Node} node The node being loaded
16315 "beforeload" : true,
16318 * Fires when a node is loaded
16319 * @param {Node} node The node that was loaded
16323 * @event textchange
16324 * Fires when the text for a node is changed
16325 * @param {Node} node The node
16326 * @param {String} text The new text
16327 * @param {String} oldText The old text
16329 "textchange" : true,
16331 * @event beforeexpand
16332 * Fires before a node is expanded, return false to cancel.
16333 * @param {Node} node The node
16334 * @param {Boolean} deep
16335 * @param {Boolean} anim
16337 "beforeexpand" : true,
16339 * @event beforecollapse
16340 * Fires before a node is collapsed, return false to cancel.
16341 * @param {Node} node The node
16342 * @param {Boolean} deep
16343 * @param {Boolean} anim
16345 "beforecollapse" : true,
16348 * Fires when a node is expanded
16349 * @param {Node} node The node
16353 * @event disabledchange
16354 * Fires when the disabled status of a node changes
16355 * @param {Node} node The node
16356 * @param {Boolean} disabled
16358 "disabledchange" : true,
16361 * Fires when a node is collapsed
16362 * @param {Node} node The node
16366 * @event beforeclick
16367 * Fires before click processing on a node. Return false to cancel the default action.
16368 * @param {Node} node The node
16369 * @param {Roo.EventObject} e The event object
16371 "beforeclick":true,
16373 * @event checkchange
16374 * Fires when a node with a checkbox's checked property changes
16375 * @param {Node} this This node
16376 * @param {Boolean} checked
16378 "checkchange":true,
16381 * Fires when a node is clicked
16382 * @param {Node} node The node
16383 * @param {Roo.EventObject} e The event object
16388 * Fires when a node is double clicked
16389 * @param {Node} node The node
16390 * @param {Roo.EventObject} e The event object
16394 * @event contextmenu
16395 * Fires when a node is right clicked
16396 * @param {Node} node The node
16397 * @param {Roo.EventObject} e The event object
16399 "contextmenu":true,
16401 * @event beforechildrenrendered
16402 * Fires right before the child nodes for a node are rendered
16403 * @param {Node} node The node
16405 "beforechildrenrendered":true,
16408 * Fires when a node starts being dragged
16409 * @param {Roo.tree.TreePanel} this
16410 * @param {Roo.tree.TreeNode} node
16411 * @param {event} e The raw browser event
16413 "startdrag" : true,
16416 * Fires when a drag operation is complete
16417 * @param {Roo.tree.TreePanel} this
16418 * @param {Roo.tree.TreeNode} node
16419 * @param {event} e The raw browser event
16424 * Fires when a dragged node is dropped on a valid DD target
16425 * @param {Roo.tree.TreePanel} this
16426 * @param {Roo.tree.TreeNode} node
16427 * @param {DD} dd The dd it was dropped on
16428 * @param {event} e The raw browser event
16432 * @event beforenodedrop
16433 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16434 * passed to handlers has the following properties:<br />
16435 * <ul style="padding:5px;padding-left:16px;">
16436 * <li>tree - The TreePanel</li>
16437 * <li>target - The node being targeted for the drop</li>
16438 * <li>data - The drag data from the drag source</li>
16439 * <li>point - The point of the drop - append, above or below</li>
16440 * <li>source - The drag source</li>
16441 * <li>rawEvent - Raw mouse event</li>
16442 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16443 * to be inserted by setting them on this object.</li>
16444 * <li>cancel - Set this to true to cancel the drop.</li>
16446 * @param {Object} dropEvent
16448 "beforenodedrop" : true,
16451 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16452 * passed to handlers has the following properties:<br />
16453 * <ul style="padding:5px;padding-left:16px;">
16454 * <li>tree - The TreePanel</li>
16455 * <li>target - The node being targeted for the drop</li>
16456 * <li>data - The drag data from the drag source</li>
16457 * <li>point - The point of the drop - append, above or below</li>
16458 * <li>source - The drag source</li>
16459 * <li>rawEvent - Raw mouse event</li>
16460 * <li>dropNode - Dropped node(s).</li>
16462 * @param {Object} dropEvent
16466 * @event nodedragover
16467 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16468 * passed to handlers has the following properties:<br />
16469 * <ul style="padding:5px;padding-left:16px;">
16470 * <li>tree - The TreePanel</li>
16471 * <li>target - The node being targeted for the drop</li>
16472 * <li>data - The drag data from the drag source</li>
16473 * <li>point - The point of the drop - append, above or below</li>
16474 * <li>source - The drag source</li>
16475 * <li>rawEvent - Raw mouse event</li>
16476 * <li>dropNode - Drop node(s) provided by the source.</li>
16477 * <li>cancel - Set this to true to signal drop not allowed.</li>
16479 * @param {Object} dragOverEvent
16481 "nodedragover" : true
16484 if(this.singleExpand){
16485 this.on("beforeexpand", this.restrictExpand, this);
16488 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16489 rootVisible : true,
16490 animate: Roo.enableFx,
16493 hlDrop : Roo.enableFx,
16497 rendererTip: false,
16499 restrictExpand : function(node){
16500 var p = node.parentNode;
16502 if(p.expandedChild && p.expandedChild.parentNode == p){
16503 p.expandedChild.collapse();
16505 p.expandedChild = node;
16509 // private override
16510 setRootNode : function(node){
16511 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16512 if(!this.rootVisible){
16513 node.ui = new Roo.tree.RootTreeNodeUI(node);
16519 * Returns the container element for this TreePanel
16521 getEl : function(){
16526 * Returns the default TreeLoader for this TreePanel
16528 getLoader : function(){
16529 return this.loader;
16535 expandAll : function(){
16536 this.root.expand(true);
16540 * Collapse all nodes
16542 collapseAll : function(){
16543 this.root.collapse(true);
16547 * Returns the selection model used by this TreePanel
16549 getSelectionModel : function(){
16550 if(!this.selModel){
16551 this.selModel = new Roo.tree.DefaultSelectionModel();
16553 return this.selModel;
16557 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16558 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16559 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16562 getChecked : function(a, startNode){
16563 startNode = startNode || this.root;
16565 var f = function(){
16566 if(this.attributes.checked){
16567 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16570 startNode.cascade(f);
16575 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16576 * @param {String} path
16577 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16578 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16579 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16581 expandPath : function(path, attr, callback){
16582 attr = attr || "id";
16583 var keys = path.split(this.pathSeparator);
16584 var curNode = this.root;
16585 if(curNode.attributes[attr] != keys[1]){ // invalid root
16587 callback(false, null);
16592 var f = function(){
16593 if(++index == keys.length){
16595 callback(true, curNode);
16599 var c = curNode.findChild(attr, keys[index]);
16602 callback(false, curNode);
16607 c.expand(false, false, f);
16609 curNode.expand(false, false, f);
16613 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16614 * @param {String} path
16615 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16616 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16617 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16619 selectPath : function(path, attr, callback){
16620 attr = attr || "id";
16621 var keys = path.split(this.pathSeparator);
16622 var v = keys.pop();
16623 if(keys.length > 0){
16624 var f = function(success, node){
16625 if(success && node){
16626 var n = node.findChild(attr, v);
16632 }else if(callback){
16633 callback(false, n);
16637 callback(false, n);
16641 this.expandPath(keys.join(this.pathSeparator), attr, f);
16643 this.root.select();
16645 callback(true, this.root);
16650 getTreeEl : function(){
16655 * Trigger rendering of this TreePanel
16657 render : function(){
16658 if (this.innerCt) {
16659 return this; // stop it rendering more than once!!
16662 this.innerCt = this.el.createChild({tag:"ul",
16663 cls:"x-tree-root-ct " +
16664 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16666 if(this.containerScroll){
16667 Roo.dd.ScrollManager.register(this.el);
16669 if((this.enableDD || this.enableDrop) && !this.dropZone){
16671 * The dropZone used by this tree if drop is enabled
16672 * @type Roo.tree.TreeDropZone
16674 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16675 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16678 if((this.enableDD || this.enableDrag) && !this.dragZone){
16680 * The dragZone used by this tree if drag is enabled
16681 * @type Roo.tree.TreeDragZone
16683 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16684 ddGroup: this.ddGroup || "TreeDD",
16685 scroll: this.ddScroll
16688 this.getSelectionModel().init(this);
16690 console.log("ROOT not set in tree");
16693 this.root.render();
16694 if(!this.rootVisible){
16695 this.root.renderChildren();
16701 * Ext JS Library 1.1.1
16702 * Copyright(c) 2006-2007, Ext JS, LLC.
16704 * Originally Released Under LGPL - original licence link has changed is not relivant.
16707 * <script type="text/javascript">
16712 * @class Roo.tree.DefaultSelectionModel
16713 * @extends Roo.util.Observable
16714 * The default single selection for a TreePanel.
16716 Roo.tree.DefaultSelectionModel = function(){
16717 this.selNode = null;
16721 * @event selectionchange
16722 * Fires when the selected node changes
16723 * @param {DefaultSelectionModel} this
16724 * @param {TreeNode} node the new selection
16726 "selectionchange" : true,
16729 * @event beforeselect
16730 * Fires before the selected node changes, return false to cancel the change
16731 * @param {DefaultSelectionModel} this
16732 * @param {TreeNode} node the new selection
16733 * @param {TreeNode} node the old selection
16735 "beforeselect" : true
16739 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16740 init : function(tree){
16742 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16743 tree.on("click", this.onNodeClick, this);
16746 onNodeClick : function(node, e){
16747 if (e.ctrlKey && this.selNode == node) {
16748 this.unselect(node);
16756 * @param {TreeNode} node The node to select
16757 * @return {TreeNode} The selected node
16759 select : function(node){
16760 var last = this.selNode;
16761 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16763 last.ui.onSelectedChange(false);
16765 this.selNode = node;
16766 node.ui.onSelectedChange(true);
16767 this.fireEvent("selectionchange", this, node, last);
16774 * @param {TreeNode} node The node to unselect
16776 unselect : function(node){
16777 if(this.selNode == node){
16778 this.clearSelections();
16783 * Clear all selections
16785 clearSelections : function(){
16786 var n = this.selNode;
16788 n.ui.onSelectedChange(false);
16789 this.selNode = null;
16790 this.fireEvent("selectionchange", this, null);
16796 * Get the selected node
16797 * @return {TreeNode} The selected node
16799 getSelectedNode : function(){
16800 return this.selNode;
16804 * Returns true if the node is selected
16805 * @param {TreeNode} node The node to check
16806 * @return {Boolean}
16808 isSelected : function(node){
16809 return this.selNode == node;
16813 * Selects the node above the selected node in the tree, intelligently walking the nodes
16814 * @return TreeNode The new selection
16816 selectPrevious : function(){
16817 var s = this.selNode || this.lastSelNode;
16821 var ps = s.previousSibling;
16823 if(!ps.isExpanded() || ps.childNodes.length < 1){
16824 return this.select(ps);
16826 var lc = ps.lastChild;
16827 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16830 return this.select(lc);
16832 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16833 return this.select(s.parentNode);
16839 * Selects the node above the selected node in the tree, intelligently walking the nodes
16840 * @return TreeNode The new selection
16842 selectNext : function(){
16843 var s = this.selNode || this.lastSelNode;
16847 if(s.firstChild && s.isExpanded()){
16848 return this.select(s.firstChild);
16849 }else if(s.nextSibling){
16850 return this.select(s.nextSibling);
16851 }else if(s.parentNode){
16853 s.parentNode.bubble(function(){
16854 if(this.nextSibling){
16855 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16864 onKeyDown : function(e){
16865 var s = this.selNode || this.lastSelNode;
16866 // undesirable, but required
16871 var k = e.getKey();
16879 this.selectPrevious();
16882 e.preventDefault();
16883 if(s.hasChildNodes()){
16884 if(!s.isExpanded()){
16886 }else if(s.firstChild){
16887 this.select(s.firstChild, e);
16892 e.preventDefault();
16893 if(s.hasChildNodes() && s.isExpanded()){
16895 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16896 this.select(s.parentNode, e);
16904 * @class Roo.tree.MultiSelectionModel
16905 * @extends Roo.util.Observable
16906 * Multi selection for a TreePanel.
16908 Roo.tree.MultiSelectionModel = function(){
16909 this.selNodes = [];
16913 * @event selectionchange
16914 * Fires when the selected nodes change
16915 * @param {MultiSelectionModel} this
16916 * @param {Array} nodes Array of the selected nodes
16918 "selectionchange" : true
16922 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16923 init : function(tree){
16925 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16926 tree.on("click", this.onNodeClick, this);
16929 onNodeClick : function(node, e){
16930 this.select(node, e, e.ctrlKey);
16935 * @param {TreeNode} node The node to select
16936 * @param {EventObject} e (optional) An event associated with the selection
16937 * @param {Boolean} keepExisting True to retain existing selections
16938 * @return {TreeNode} The selected node
16940 select : function(node, e, keepExisting){
16941 if(keepExisting !== true){
16942 this.clearSelections(true);
16944 if(this.isSelected(node)){
16945 this.lastSelNode = node;
16948 this.selNodes.push(node);
16949 this.selMap[node.id] = node;
16950 this.lastSelNode = node;
16951 node.ui.onSelectedChange(true);
16952 this.fireEvent("selectionchange", this, this.selNodes);
16958 * @param {TreeNode} node The node to unselect
16960 unselect : function(node){
16961 if(this.selMap[node.id]){
16962 node.ui.onSelectedChange(false);
16963 var sn = this.selNodes;
16966 index = sn.indexOf(node);
16968 for(var i = 0, len = sn.length; i < len; i++){
16976 this.selNodes.splice(index, 1);
16978 delete this.selMap[node.id];
16979 this.fireEvent("selectionchange", this, this.selNodes);
16984 * Clear all selections
16986 clearSelections : function(suppressEvent){
16987 var sn = this.selNodes;
16989 for(var i = 0, len = sn.length; i < len; i++){
16990 sn[i].ui.onSelectedChange(false);
16992 this.selNodes = [];
16994 if(suppressEvent !== true){
16995 this.fireEvent("selectionchange", this, this.selNodes);
17001 * Returns true if the node is selected
17002 * @param {TreeNode} node The node to check
17003 * @return {Boolean}
17005 isSelected : function(node){
17006 return this.selMap[node.id] ? true : false;
17010 * Returns an array of the selected nodes
17013 getSelectedNodes : function(){
17014 return this.selNodes;
17017 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17019 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17021 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17024 * Ext JS Library 1.1.1
17025 * Copyright(c) 2006-2007, Ext JS, LLC.
17027 * Originally Released Under LGPL - original licence link has changed is not relivant.
17030 * <script type="text/javascript">
17034 * @class Roo.tree.TreeNode
17035 * @extends Roo.data.Node
17036 * @cfg {String} text The text for this node
17037 * @cfg {Boolean} expanded true to start the node expanded
17038 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17039 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17040 * @cfg {Boolean} disabled true to start the node disabled
17041 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17042 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17043 * @cfg {String} cls A css class to be added to the node
17044 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17045 * @cfg {String} href URL of the link used for the node (defaults to #)
17046 * @cfg {String} hrefTarget target frame for the link
17047 * @cfg {String} qtip An Ext QuickTip for the node
17048 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17049 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17050 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17051 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17052 * (defaults to undefined with no checkbox rendered)
17054 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17056 Roo.tree.TreeNode = function(attributes){
17057 attributes = attributes || {};
17058 if(typeof attributes == "string"){
17059 attributes = {text: attributes};
17061 this.childrenRendered = false;
17062 this.rendered = false;
17063 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17064 this.expanded = attributes.expanded === true;
17065 this.isTarget = attributes.isTarget !== false;
17066 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17067 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17070 * Read-only. The text for this node. To change it use setText().
17073 this.text = attributes.text;
17075 * True if this node is disabled.
17078 this.disabled = attributes.disabled === true;
17082 * @event textchange
17083 * Fires when the text for this node is changed
17084 * @param {Node} this This node
17085 * @param {String} text The new text
17086 * @param {String} oldText The old text
17088 "textchange" : true,
17090 * @event beforeexpand
17091 * Fires before this node is expanded, return false to cancel.
17092 * @param {Node} this This node
17093 * @param {Boolean} deep
17094 * @param {Boolean} anim
17096 "beforeexpand" : true,
17098 * @event beforecollapse
17099 * Fires before this node is collapsed, return false to cancel.
17100 * @param {Node} this This node
17101 * @param {Boolean} deep
17102 * @param {Boolean} anim
17104 "beforecollapse" : true,
17107 * Fires when this node is expanded
17108 * @param {Node} this This node
17112 * @event disabledchange
17113 * Fires when the disabled status of this node changes
17114 * @param {Node} this This node
17115 * @param {Boolean} disabled
17117 "disabledchange" : true,
17120 * Fires when this node is collapsed
17121 * @param {Node} this This node
17125 * @event beforeclick
17126 * Fires before click processing. Return false to cancel the default action.
17127 * @param {Node} this This node
17128 * @param {Roo.EventObject} e The event object
17130 "beforeclick":true,
17132 * @event checkchange
17133 * Fires when a node with a checkbox's checked property changes
17134 * @param {Node} this This node
17135 * @param {Boolean} checked
17137 "checkchange":true,
17140 * Fires when this node is clicked
17141 * @param {Node} this This node
17142 * @param {Roo.EventObject} e The event object
17147 * Fires when this node is double clicked
17148 * @param {Node} this This node
17149 * @param {Roo.EventObject} e The event object
17153 * @event contextmenu
17154 * Fires when this node is right clicked
17155 * @param {Node} this This node
17156 * @param {Roo.EventObject} e The event object
17158 "contextmenu":true,
17160 * @event beforechildrenrendered
17161 * Fires right before the child nodes for this node are rendered
17162 * @param {Node} this This node
17164 "beforechildrenrendered":true
17167 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17170 * Read-only. The UI for this node
17173 this.ui = new uiClass(this);
17175 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17176 preventHScroll: true,
17178 * Returns true if this node is expanded
17179 * @return {Boolean}
17181 isExpanded : function(){
17182 return this.expanded;
17186 * Returns the UI object for this node
17187 * @return {TreeNodeUI}
17189 getUI : function(){
17193 // private override
17194 setFirstChild : function(node){
17195 var of = this.firstChild;
17196 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17197 if(this.childrenRendered && of && node != of){
17198 of.renderIndent(true, true);
17201 this.renderIndent(true, true);
17205 // private override
17206 setLastChild : function(node){
17207 var ol = this.lastChild;
17208 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17209 if(this.childrenRendered && ol && node != ol){
17210 ol.renderIndent(true, true);
17213 this.renderIndent(true, true);
17217 // these methods are overridden to provide lazy rendering support
17218 // private override
17219 appendChild : function(){
17220 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17221 if(node && this.childrenRendered){
17224 this.ui.updateExpandIcon();
17228 // private override
17229 removeChild : function(node){
17230 this.ownerTree.getSelectionModel().unselect(node);
17231 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17232 // if it's been rendered remove dom node
17233 if(this.childrenRendered){
17236 if(this.childNodes.length < 1){
17237 this.collapse(false, false);
17239 this.ui.updateExpandIcon();
17241 if(!this.firstChild) {
17242 this.childrenRendered = false;
17247 // private override
17248 insertBefore : function(node, refNode){
17249 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17250 if(newNode && refNode && this.childrenRendered){
17253 this.ui.updateExpandIcon();
17258 * Sets the text for this node
17259 * @param {String} text
17261 setText : function(text){
17262 var oldText = this.text;
17264 this.attributes.text = text;
17265 if(this.rendered){ // event without subscribing
17266 this.ui.onTextChange(this, text, oldText);
17268 this.fireEvent("textchange", this, text, oldText);
17272 * Triggers selection of this node
17274 select : function(){
17275 this.getOwnerTree().getSelectionModel().select(this);
17279 * Triggers deselection of this node
17281 unselect : function(){
17282 this.getOwnerTree().getSelectionModel().unselect(this);
17286 * Returns true if this node is selected
17287 * @return {Boolean}
17289 isSelected : function(){
17290 return this.getOwnerTree().getSelectionModel().isSelected(this);
17294 * Expand this node.
17295 * @param {Boolean} deep (optional) True to expand all children as well
17296 * @param {Boolean} anim (optional) false to cancel the default animation
17297 * @param {Function} callback (optional) A callback to be called when
17298 * expanding this node completes (does not wait for deep expand to complete).
17299 * Called with 1 parameter, this node.
17301 expand : function(deep, anim, callback){
17302 if(!this.expanded){
17303 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17306 if(!this.childrenRendered){
17307 this.renderChildren();
17309 this.expanded = true;
17310 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17311 this.ui.animExpand(function(){
17312 this.fireEvent("expand", this);
17313 if(typeof callback == "function"){
17317 this.expandChildNodes(true);
17319 }.createDelegate(this));
17323 this.fireEvent("expand", this);
17324 if(typeof callback == "function"){
17329 if(typeof callback == "function"){
17334 this.expandChildNodes(true);
17338 isHiddenRoot : function(){
17339 return this.isRoot && !this.getOwnerTree().rootVisible;
17343 * Collapse this node.
17344 * @param {Boolean} deep (optional) True to collapse all children as well
17345 * @param {Boolean} anim (optional) false to cancel the default animation
17347 collapse : function(deep, anim){
17348 if(this.expanded && !this.isHiddenRoot()){
17349 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17352 this.expanded = false;
17353 if((this.getOwnerTree().animate && anim !== false) || anim){
17354 this.ui.animCollapse(function(){
17355 this.fireEvent("collapse", this);
17357 this.collapseChildNodes(true);
17359 }.createDelegate(this));
17362 this.ui.collapse();
17363 this.fireEvent("collapse", this);
17367 var cs = this.childNodes;
17368 for(var i = 0, len = cs.length; i < len; i++) {
17369 cs[i].collapse(true, false);
17375 delayedExpand : function(delay){
17376 if(!this.expandProcId){
17377 this.expandProcId = this.expand.defer(delay, this);
17382 cancelExpand : function(){
17383 if(this.expandProcId){
17384 clearTimeout(this.expandProcId);
17386 this.expandProcId = false;
17390 * Toggles expanded/collapsed state of the node
17392 toggle : function(){
17401 * Ensures all parent nodes are expanded
17403 ensureVisible : function(callback){
17404 var tree = this.getOwnerTree();
17405 tree.expandPath(this.parentNode.getPath(), false, function(){
17406 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17407 Roo.callback(callback);
17408 }.createDelegate(this));
17412 * Expand all child nodes
17413 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17415 expandChildNodes : function(deep){
17416 var cs = this.childNodes;
17417 for(var i = 0, len = cs.length; i < len; i++) {
17418 cs[i].expand(deep);
17423 * Collapse all child nodes
17424 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17426 collapseChildNodes : function(deep){
17427 var cs = this.childNodes;
17428 for(var i = 0, len = cs.length; i < len; i++) {
17429 cs[i].collapse(deep);
17434 * Disables this node
17436 disable : function(){
17437 this.disabled = true;
17439 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17440 this.ui.onDisableChange(this, true);
17442 this.fireEvent("disabledchange", this, true);
17446 * Enables this node
17448 enable : function(){
17449 this.disabled = false;
17450 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17451 this.ui.onDisableChange(this, false);
17453 this.fireEvent("disabledchange", this, false);
17457 renderChildren : function(suppressEvent){
17458 if(suppressEvent !== false){
17459 this.fireEvent("beforechildrenrendered", this);
17461 var cs = this.childNodes;
17462 for(var i = 0, len = cs.length; i < len; i++){
17463 cs[i].render(true);
17465 this.childrenRendered = true;
17469 sort : function(fn, scope){
17470 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17471 if(this.childrenRendered){
17472 var cs = this.childNodes;
17473 for(var i = 0, len = cs.length; i < len; i++){
17474 cs[i].render(true);
17480 render : function(bulkRender){
17481 this.ui.render(bulkRender);
17482 if(!this.rendered){
17483 this.rendered = true;
17485 this.expanded = false;
17486 this.expand(false, false);
17492 renderIndent : function(deep, refresh){
17494 this.ui.childIndent = null;
17496 this.ui.renderIndent();
17497 if(deep === true && this.childrenRendered){
17498 var cs = this.childNodes;
17499 for(var i = 0, len = cs.length; i < len; i++){
17500 cs[i].renderIndent(true, refresh);
17506 * Ext JS Library 1.1.1
17507 * Copyright(c) 2006-2007, Ext JS, LLC.
17509 * Originally Released Under LGPL - original licence link has changed is not relivant.
17512 * <script type="text/javascript">
17516 * @class Roo.tree.AsyncTreeNode
17517 * @extends Roo.tree.TreeNode
17518 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17520 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17522 Roo.tree.AsyncTreeNode = function(config){
17523 this.loaded = false;
17524 this.loading = false;
17525 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17527 * @event beforeload
17528 * Fires before this node is loaded, return false to cancel
17529 * @param {Node} this This node
17531 this.addEvents({'beforeload':true, 'load': true});
17534 * Fires when this node is loaded
17535 * @param {Node} this This node
17538 * The loader used by this node (defaults to using the tree's defined loader)
17543 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17544 expand : function(deep, anim, callback){
17545 if(this.loading){ // if an async load is already running, waiting til it's done
17547 var f = function(){
17548 if(!this.loading){ // done loading
17549 clearInterval(timer);
17550 this.expand(deep, anim, callback);
17552 }.createDelegate(this);
17553 timer = setInterval(f, 200);
17557 if(this.fireEvent("beforeload", this) === false){
17560 this.loading = true;
17561 this.ui.beforeLoad(this);
17562 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17564 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17568 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17572 * Returns true if this node is currently loading
17573 * @return {Boolean}
17575 isLoading : function(){
17576 return this.loading;
17579 loadComplete : function(deep, anim, callback){
17580 this.loading = false;
17581 this.loaded = true;
17582 this.ui.afterLoad(this);
17583 this.fireEvent("load", this);
17584 this.expand(deep, anim, callback);
17588 * Returns true if this node has been loaded
17589 * @return {Boolean}
17591 isLoaded : function(){
17592 return this.loaded;
17595 hasChildNodes : function(){
17596 if(!this.isLeaf() && !this.loaded){
17599 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17604 * Trigger a reload for this node
17605 * @param {Function} callback
17607 reload : function(callback){
17608 this.collapse(false, false);
17609 while(this.firstChild){
17610 this.removeChild(this.firstChild);
17612 this.childrenRendered = false;
17613 this.loaded = false;
17614 if(this.isHiddenRoot()){
17615 this.expanded = false;
17617 this.expand(false, false, callback);
17621 * Ext JS Library 1.1.1
17622 * Copyright(c) 2006-2007, Ext JS, LLC.
17624 * Originally Released Under LGPL - original licence link has changed is not relivant.
17627 * <script type="text/javascript">
17631 * @class Roo.tree.TreeNodeUI
17633 * @param {Object} node The node to render
17634 * The TreeNode UI implementation is separate from the
17635 * tree implementation. Unless you are customizing the tree UI,
17636 * you should never have to use this directly.
17638 Roo.tree.TreeNodeUI = function(node){
17640 this.rendered = false;
17641 this.animating = false;
17642 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17645 Roo.tree.TreeNodeUI.prototype = {
17646 removeChild : function(node){
17648 this.ctNode.removeChild(node.ui.getEl());
17652 beforeLoad : function(){
17653 this.addClass("x-tree-node-loading");
17656 afterLoad : function(){
17657 this.removeClass("x-tree-node-loading");
17660 onTextChange : function(node, text, oldText){
17662 this.textNode.innerHTML = text;
17666 onDisableChange : function(node, state){
17667 this.disabled = state;
17669 this.addClass("x-tree-node-disabled");
17671 this.removeClass("x-tree-node-disabled");
17675 onSelectedChange : function(state){
17678 this.addClass("x-tree-selected");
17681 this.removeClass("x-tree-selected");
17685 onMove : function(tree, node, oldParent, newParent, index, refNode){
17686 this.childIndent = null;
17688 var targetNode = newParent.ui.getContainer();
17689 if(!targetNode){//target not rendered
17690 this.holder = document.createElement("div");
17691 this.holder.appendChild(this.wrap);
17694 var insertBefore = refNode ? refNode.ui.getEl() : null;
17696 targetNode.insertBefore(this.wrap, insertBefore);
17698 targetNode.appendChild(this.wrap);
17700 this.node.renderIndent(true);
17704 addClass : function(cls){
17706 Roo.fly(this.elNode).addClass(cls);
17710 removeClass : function(cls){
17712 Roo.fly(this.elNode).removeClass(cls);
17716 remove : function(){
17718 this.holder = document.createElement("div");
17719 this.holder.appendChild(this.wrap);
17723 fireEvent : function(){
17724 return this.node.fireEvent.apply(this.node, arguments);
17727 initEvents : function(){
17728 this.node.on("move", this.onMove, this);
17729 var E = Roo.EventManager;
17730 var a = this.anchor;
17732 var el = Roo.fly(a, '_treeui');
17734 if(Roo.isOpera){ // opera render bug ignores the CSS
17735 el.setStyle("text-decoration", "none");
17738 el.on("click", this.onClick, this);
17739 el.on("dblclick", this.onDblClick, this);
17742 Roo.EventManager.on(this.checkbox,
17743 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17746 el.on("contextmenu", this.onContextMenu, this);
17748 var icon = Roo.fly(this.iconNode);
17749 icon.on("click", this.onClick, this);
17750 icon.on("dblclick", this.onDblClick, this);
17751 icon.on("contextmenu", this.onContextMenu, this);
17752 E.on(this.ecNode, "click", this.ecClick, this, true);
17754 if(this.node.disabled){
17755 this.addClass("x-tree-node-disabled");
17757 if(this.node.hidden){
17758 this.addClass("x-tree-node-disabled");
17760 var ot = this.node.getOwnerTree();
17761 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17762 if(dd && (!this.node.isRoot || ot.rootVisible)){
17763 Roo.dd.Registry.register(this.elNode, {
17765 handles: this.getDDHandles(),
17771 getDDHandles : function(){
17772 return [this.iconNode, this.textNode];
17777 this.wrap.style.display = "none";
17783 this.wrap.style.display = "";
17787 onContextMenu : function(e){
17788 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17789 e.preventDefault();
17791 this.fireEvent("contextmenu", this.node, e);
17795 onClick : function(e){
17800 if(this.fireEvent("beforeclick", this.node, e) !== false){
17801 if(!this.disabled && this.node.attributes.href){
17802 this.fireEvent("click", this.node, e);
17805 e.preventDefault();
17810 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17811 this.node.toggle();
17814 this.fireEvent("click", this.node, e);
17820 onDblClick : function(e){
17821 e.preventDefault();
17826 this.toggleCheck();
17828 if(!this.animating && this.node.hasChildNodes()){
17829 this.node.toggle();
17831 this.fireEvent("dblclick", this.node, e);
17834 onCheckChange : function(){
17835 var checked = this.checkbox.checked;
17836 this.node.attributes.checked = checked;
17837 this.fireEvent('checkchange', this.node, checked);
17840 ecClick : function(e){
17841 if(!this.animating && this.node.hasChildNodes()){
17842 this.node.toggle();
17846 startDrop : function(){
17847 this.dropping = true;
17850 // delayed drop so the click event doesn't get fired on a drop
17851 endDrop : function(){
17852 setTimeout(function(){
17853 this.dropping = false;
17854 }.createDelegate(this), 50);
17857 expand : function(){
17858 this.updateExpandIcon();
17859 this.ctNode.style.display = "";
17862 focus : function(){
17863 if(!this.node.preventHScroll){
17864 try{this.anchor.focus();
17866 }else if(!Roo.isIE){
17868 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17869 var l = noscroll.scrollLeft;
17870 this.anchor.focus();
17871 noscroll.scrollLeft = l;
17876 toggleCheck : function(value){
17877 var cb = this.checkbox;
17879 cb.checked = (value === undefined ? !cb.checked : value);
17885 this.anchor.blur();
17889 animExpand : function(callback){
17890 var ct = Roo.get(this.ctNode);
17892 if(!this.node.hasChildNodes()){
17893 this.updateExpandIcon();
17894 this.ctNode.style.display = "";
17895 Roo.callback(callback);
17898 this.animating = true;
17899 this.updateExpandIcon();
17902 callback : function(){
17903 this.animating = false;
17904 Roo.callback(callback);
17907 duration: this.node.ownerTree.duration || .25
17911 highlight : function(){
17912 var tree = this.node.getOwnerTree();
17913 Roo.fly(this.wrap).highlight(
17914 tree.hlColor || "C3DAF9",
17915 {endColor: tree.hlBaseColor}
17919 collapse : function(){
17920 this.updateExpandIcon();
17921 this.ctNode.style.display = "none";
17924 animCollapse : function(callback){
17925 var ct = Roo.get(this.ctNode);
17926 ct.enableDisplayMode('block');
17929 this.animating = true;
17930 this.updateExpandIcon();
17933 callback : function(){
17934 this.animating = false;
17935 Roo.callback(callback);
17938 duration: this.node.ownerTree.duration || .25
17942 getContainer : function(){
17943 return this.ctNode;
17946 getEl : function(){
17950 appendDDGhost : function(ghostNode){
17951 ghostNode.appendChild(this.elNode.cloneNode(true));
17954 getDDRepairXY : function(){
17955 return Roo.lib.Dom.getXY(this.iconNode);
17958 onRender : function(){
17962 render : function(bulkRender){
17963 var n = this.node, a = n.attributes;
17964 var targetNode = n.parentNode ?
17965 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17967 if(!this.rendered){
17968 this.rendered = true;
17970 this.renderElements(n, a, targetNode, bulkRender);
17973 if(this.textNode.setAttributeNS){
17974 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17976 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17979 this.textNode.setAttribute("ext:qtip", a.qtip);
17981 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17984 }else if(a.qtipCfg){
17985 a.qtipCfg.target = Roo.id(this.textNode);
17986 Roo.QuickTips.register(a.qtipCfg);
17989 if(!this.node.expanded){
17990 this.updateExpandIcon();
17993 if(bulkRender === true) {
17994 targetNode.appendChild(this.wrap);
17999 renderElements : function(n, a, targetNode, bulkRender){
18000 // add some indent caching, this helps performance when rendering a large tree
18001 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18002 var t = n.getOwnerTree();
18003 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18004 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18005 var cb = typeof a.checked == 'boolean';
18006 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18007 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18008 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18009 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18010 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18011 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18012 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18013 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18014 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18015 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18018 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18019 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18020 n.nextSibling.ui.getEl(), buf.join(""));
18022 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18025 this.elNode = this.wrap.childNodes[0];
18026 this.ctNode = this.wrap.childNodes[1];
18027 var cs = this.elNode.childNodes;
18028 this.indentNode = cs[0];
18029 this.ecNode = cs[1];
18030 this.iconNode = cs[2];
18033 this.checkbox = cs[3];
18036 this.anchor = cs[index];
18037 this.textNode = cs[index].firstChild;
18040 getAnchor : function(){
18041 return this.anchor;
18044 getTextEl : function(){
18045 return this.textNode;
18048 getIconEl : function(){
18049 return this.iconNode;
18052 isChecked : function(){
18053 return this.checkbox ? this.checkbox.checked : false;
18056 updateExpandIcon : function(){
18058 var n = this.node, c1, c2;
18059 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18060 var hasChild = n.hasChildNodes();
18064 c1 = "x-tree-node-collapsed";
18065 c2 = "x-tree-node-expanded";
18068 c1 = "x-tree-node-expanded";
18069 c2 = "x-tree-node-collapsed";
18072 this.removeClass("x-tree-node-leaf");
18073 this.wasLeaf = false;
18075 if(this.c1 != c1 || this.c2 != c2){
18076 Roo.fly(this.elNode).replaceClass(c1, c2);
18077 this.c1 = c1; this.c2 = c2;
18081 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18084 this.wasLeaf = true;
18087 var ecc = "x-tree-ec-icon "+cls;
18088 if(this.ecc != ecc){
18089 this.ecNode.className = ecc;
18095 getChildIndent : function(){
18096 if(!this.childIndent){
18100 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18102 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18104 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18109 this.childIndent = buf.join("");
18111 return this.childIndent;
18114 renderIndent : function(){
18117 var p = this.node.parentNode;
18119 indent = p.ui.getChildIndent();
18121 if(this.indentMarkup != indent){ // don't rerender if not required
18122 this.indentNode.innerHTML = indent;
18123 this.indentMarkup = indent;
18125 this.updateExpandIcon();
18130 Roo.tree.RootTreeNodeUI = function(){
18131 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18133 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18134 render : function(){
18135 if(!this.rendered){
18136 var targetNode = this.node.ownerTree.innerCt.dom;
18137 this.node.expanded = true;
18138 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18139 this.wrap = this.ctNode = targetNode.firstChild;
18142 collapse : function(){
18144 expand : function(){
18148 * Ext JS Library 1.1.1
18149 * Copyright(c) 2006-2007, Ext JS, LLC.
18151 * Originally Released Under LGPL - original licence link has changed is not relivant.
18154 * <script type="text/javascript">
18157 * @class Roo.tree.TreeLoader
18158 * @extends Roo.util.Observable
18159 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18160 * nodes from a specified URL. The response must be a javascript Array definition
18161 * who's elements are node definition objects. eg:
18163 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18164 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18167 * A server request is sent, and child nodes are loaded only when a node is expanded.
18168 * The loading node's id is passed to the server under the parameter name "node" to
18169 * enable the server to produce the correct child nodes.
18171 * To pass extra parameters, an event handler may be attached to the "beforeload"
18172 * event, and the parameters specified in the TreeLoader's baseParams property:
18174 myTreeLoader.on("beforeload", function(treeLoader, node) {
18175 this.baseParams.category = node.attributes.category;
18178 * This would pass an HTTP parameter called "category" to the server containing
18179 * the value of the Node's "category" attribute.
18181 * Creates a new Treeloader.
18182 * @param {Object} config A config object containing config properties.
18184 Roo.tree.TreeLoader = function(config){
18185 this.baseParams = {};
18186 this.requestMethod = "POST";
18187 Roo.apply(this, config);
18192 * @event beforeload
18193 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18194 * @param {Object} This TreeLoader object.
18195 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18196 * @param {Object} callback The callback function specified in the {@link #load} call.
18201 * Fires when the node has been successfuly loaded.
18202 * @param {Object} This TreeLoader object.
18203 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18204 * @param {Object} response The response object containing the data from the server.
18208 * @event loadexception
18209 * Fires if the network request failed.
18210 * @param {Object} This TreeLoader object.
18211 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18212 * @param {Object} response The response object containing the data from the server.
18214 loadexception : true,
18217 * Fires before a node is created, enabling you to return custom Node types
18218 * @param {Object} This TreeLoader object.
18219 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18224 Roo.tree.TreeLoader.superclass.constructor.call(this);
18227 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18229 * @cfg {String} dataUrl The URL from which to request a Json string which
18230 * specifies an array of node definition object representing the child nodes
18234 * @cfg {Object} baseParams (optional) An object containing properties which
18235 * specify HTTP parameters to be passed to each request for child nodes.
18238 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18239 * created by this loader. If the attributes sent by the server have an attribute in this object,
18240 * they take priority.
18243 * @cfg {Object} uiProviders (optional) An object containing properties which
18245 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18246 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18247 * <i>uiProvider</i> attribute of a returned child node is a string rather
18248 * than a reference to a TreeNodeUI implementation, this that string value
18249 * is used as a property name in the uiProviders object. You can define the provider named
18250 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18255 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18256 * child nodes before loading.
18258 clearOnLoad : true,
18261 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18262 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18263 * Grid query { data : [ .....] }
18268 * @cfg {String} queryParam (optional)
18269 * Name of the query as it will be passed on the querystring (defaults to 'node')
18270 * eg. the request will be ?node=[id]
18277 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18278 * This is called automatically when a node is expanded, but may be used to reload
18279 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18280 * @param {Roo.tree.TreeNode} node
18281 * @param {Function} callback
18283 load : function(node, callback){
18284 if(this.clearOnLoad){
18285 while(node.firstChild){
18286 node.removeChild(node.firstChild);
18289 if(node.attributes.children){ // preloaded json children
18290 var cs = node.attributes.children;
18291 for(var i = 0, len = cs.length; i < len; i++){
18292 node.appendChild(this.createNode(cs[i]));
18294 if(typeof callback == "function"){
18297 }else if(this.dataUrl){
18298 this.requestData(node, callback);
18302 getParams: function(node){
18303 var buf = [], bp = this.baseParams;
18304 for(var key in bp){
18305 if(typeof bp[key] != "function"){
18306 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18309 var n = this.queryParam === false ? 'node' : this.queryParam;
18310 buf.push(n + "=", encodeURIComponent(node.id));
18311 return buf.join("");
18314 requestData : function(node, callback){
18315 if(this.fireEvent("beforeload", this, node, callback) !== false){
18316 this.transId = Roo.Ajax.request({
18317 method:this.requestMethod,
18318 url: this.dataUrl||this.url,
18319 success: this.handleResponse,
18320 failure: this.handleFailure,
18322 argument: {callback: callback, node: node},
18323 params: this.getParams(node)
18326 // if the load is cancelled, make sure we notify
18327 // the node that we are done
18328 if(typeof callback == "function"){
18334 isLoading : function(){
18335 return this.transId ? true : false;
18338 abort : function(){
18339 if(this.isLoading()){
18340 Roo.Ajax.abort(this.transId);
18345 createNode : function(attr){
18346 // apply baseAttrs, nice idea Corey!
18347 if(this.baseAttrs){
18348 Roo.applyIf(attr, this.baseAttrs);
18350 if(this.applyLoader !== false){
18351 attr.loader = this;
18353 // uiProvider = depreciated..
18355 if(typeof(attr.uiProvider) == 'string'){
18356 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18357 /** eval:var:attr */ eval(attr.uiProvider);
18359 if(typeof(this.uiProviders['default']) != 'undefined') {
18360 attr.uiProvider = this.uiProviders['default'];
18363 this.fireEvent('create', this, attr);
18365 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18367 new Roo.tree.TreeNode(attr) :
18368 new Roo.tree.AsyncTreeNode(attr));
18371 processResponse : function(response, node, callback){
18372 var json = response.responseText;
18375 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18376 if (this.root !== false) {
18380 for(var i = 0, len = o.length; i < len; i++){
18381 var n = this.createNode(o[i]);
18383 node.appendChild(n);
18386 if(typeof callback == "function"){
18387 callback(this, node);
18390 this.handleFailure(response);
18394 handleResponse : function(response){
18395 this.transId = false;
18396 var a = response.argument;
18397 this.processResponse(response, a.node, a.callback);
18398 this.fireEvent("load", this, a.node, response);
18401 handleFailure : function(response){
18402 this.transId = false;
18403 var a = response.argument;
18404 this.fireEvent("loadexception", this, a.node, response);
18405 if(typeof a.callback == "function"){
18406 a.callback(this, a.node);
18411 * Ext JS Library 1.1.1
18412 * Copyright(c) 2006-2007, Ext JS, LLC.
18414 * Originally Released Under LGPL - original licence link has changed is not relivant.
18417 * <script type="text/javascript">
18421 * @class Roo.tree.TreeFilter
18422 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18423 * @param {TreePanel} tree
18424 * @param {Object} config (optional)
18426 Roo.tree.TreeFilter = function(tree, config){
18428 this.filtered = {};
18429 Roo.apply(this, config);
18432 Roo.tree.TreeFilter.prototype = {
18439 * Filter the data by a specific attribute.
18440 * @param {String/RegExp} value Either string that the attribute value
18441 * should start with or a RegExp to test against the attribute
18442 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18443 * @param {TreeNode} startNode (optional) The node to start the filter at.
18445 filter : function(value, attr, startNode){
18446 attr = attr || "text";
18448 if(typeof value == "string"){
18449 var vlen = value.length;
18450 // auto clear empty filter
18451 if(vlen == 0 && this.clearBlank){
18455 value = value.toLowerCase();
18457 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18459 }else if(value.exec){ // regex?
18461 return value.test(n.attributes[attr]);
18464 throw 'Illegal filter type, must be string or regex';
18466 this.filterBy(f, null, startNode);
18470 * Filter by a function. The passed function will be called with each
18471 * node in the tree (or from the startNode). If the function returns true, the node is kept
18472 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18473 * @param {Function} fn The filter function
18474 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18476 filterBy : function(fn, scope, startNode){
18477 startNode = startNode || this.tree.root;
18478 if(this.autoClear){
18481 var af = this.filtered, rv = this.reverse;
18482 var f = function(n){
18483 if(n == startNode){
18489 var m = fn.call(scope || n, n);
18497 startNode.cascade(f);
18500 if(typeof id != "function"){
18502 if(n && n.parentNode){
18503 n.parentNode.removeChild(n);
18511 * Clears the current filter. Note: with the "remove" option
18512 * set a filter cannot be cleared.
18514 clear : function(){
18516 var af = this.filtered;
18518 if(typeof id != "function"){
18525 this.filtered = {};
18530 * Ext JS Library 1.1.1
18531 * Copyright(c) 2006-2007, Ext JS, LLC.
18533 * Originally Released Under LGPL - original licence link has changed is not relivant.
18536 * <script type="text/javascript">
18541 * @class Roo.tree.TreeSorter
18542 * Provides sorting of nodes in a TreePanel
18544 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18545 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18546 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18547 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18548 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18549 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18551 * @param {TreePanel} tree
18552 * @param {Object} config
18554 Roo.tree.TreeSorter = function(tree, config){
18555 Roo.apply(this, config);
18556 tree.on("beforechildrenrendered", this.doSort, this);
18557 tree.on("append", this.updateSort, this);
18558 tree.on("insert", this.updateSort, this);
18560 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18561 var p = this.property || "text";
18562 var sortType = this.sortType;
18563 var fs = this.folderSort;
18564 var cs = this.caseSensitive === true;
18565 var leafAttr = this.leafAttr || 'leaf';
18567 this.sortFn = function(n1, n2){
18569 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18572 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18576 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18577 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18579 return dsc ? +1 : -1;
18581 return dsc ? -1 : +1;
18588 Roo.tree.TreeSorter.prototype = {
18589 doSort : function(node){
18590 node.sort(this.sortFn);
18593 compareNodes : function(n1, n2){
18594 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18597 updateSort : function(tree, node){
18598 if(node.childrenRendered){
18599 this.doSort.defer(1, this, [node]);
18604 * Ext JS Library 1.1.1
18605 * Copyright(c) 2006-2007, Ext JS, LLC.
18607 * Originally Released Under LGPL - original licence link has changed is not relivant.
18610 * <script type="text/javascript">
18613 if(Roo.dd.DropZone){
18615 Roo.tree.TreeDropZone = function(tree, config){
18616 this.allowParentInsert = false;
18617 this.allowContainerDrop = false;
18618 this.appendOnly = false;
18619 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18621 this.lastInsertClass = "x-tree-no-status";
18622 this.dragOverData = {};
18625 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18626 ddGroup : "TreeDD",
18628 expandDelay : 1000,
18630 expandNode : function(node){
18631 if(node.hasChildNodes() && !node.isExpanded()){
18632 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18636 queueExpand : function(node){
18637 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18640 cancelExpand : function(){
18641 if(this.expandProcId){
18642 clearTimeout(this.expandProcId);
18643 this.expandProcId = false;
18647 isValidDropPoint : function(n, pt, dd, e, data){
18648 if(!n || !data){ return false; }
18649 var targetNode = n.node;
18650 var dropNode = data.node;
18651 // default drop rules
18652 if(!(targetNode && targetNode.isTarget && pt)){
18655 if(pt == "append" && targetNode.allowChildren === false){
18658 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18661 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18664 // reuse the object
18665 var overEvent = this.dragOverData;
18666 overEvent.tree = this.tree;
18667 overEvent.target = targetNode;
18668 overEvent.data = data;
18669 overEvent.point = pt;
18670 overEvent.source = dd;
18671 overEvent.rawEvent = e;
18672 overEvent.dropNode = dropNode;
18673 overEvent.cancel = false;
18674 var result = this.tree.fireEvent("nodedragover", overEvent);
18675 return overEvent.cancel === false && result !== false;
18678 getDropPoint : function(e, n, dd){
18681 return tn.allowChildren !== false ? "append" : false; // always append for root
18683 var dragEl = n.ddel;
18684 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18685 var y = Roo.lib.Event.getPageY(e);
18686 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18688 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18689 var noAppend = tn.allowChildren === false;
18690 if(this.appendOnly || tn.parentNode.allowChildren === false){
18691 return noAppend ? false : "append";
18693 var noBelow = false;
18694 if(!this.allowParentInsert){
18695 noBelow = tn.hasChildNodes() && tn.isExpanded();
18697 var q = (b - t) / (noAppend ? 2 : 3);
18698 if(y >= t && y < (t + q)){
18700 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18707 onNodeEnter : function(n, dd, e, data){
18708 this.cancelExpand();
18711 onNodeOver : function(n, dd, e, data){
18712 var pt = this.getDropPoint(e, n, dd);
18715 // auto node expand check
18716 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18717 this.queueExpand(node);
18718 }else if(pt != "append"){
18719 this.cancelExpand();
18722 // set the insert point style on the target node
18723 var returnCls = this.dropNotAllowed;
18724 if(this.isValidDropPoint(n, pt, dd, e, data)){
18729 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18730 cls = "x-tree-drag-insert-above";
18731 }else if(pt == "below"){
18732 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18733 cls = "x-tree-drag-insert-below";
18735 returnCls = "x-tree-drop-ok-append";
18736 cls = "x-tree-drag-append";
18738 if(this.lastInsertClass != cls){
18739 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18740 this.lastInsertClass = cls;
18747 onNodeOut : function(n, dd, e, data){
18748 this.cancelExpand();
18749 this.removeDropIndicators(n);
18752 onNodeDrop : function(n, dd, e, data){
18753 var point = this.getDropPoint(e, n, dd);
18754 var targetNode = n.node;
18755 targetNode.ui.startDrop();
18756 if(!this.isValidDropPoint(n, point, dd, e, data)){
18757 targetNode.ui.endDrop();
18760 // first try to find the drop node
18761 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18764 target: targetNode,
18769 dropNode: dropNode,
18772 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18773 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18774 targetNode.ui.endDrop();
18777 // allow target changing
18778 targetNode = dropEvent.target;
18779 if(point == "append" && !targetNode.isExpanded()){
18780 targetNode.expand(false, null, function(){
18781 this.completeDrop(dropEvent);
18782 }.createDelegate(this));
18784 this.completeDrop(dropEvent);
18789 completeDrop : function(de){
18790 var ns = de.dropNode, p = de.point, t = de.target;
18791 if(!(ns instanceof Array)){
18795 for(var i = 0, len = ns.length; i < len; i++){
18798 t.parentNode.insertBefore(n, t);
18799 }else if(p == "below"){
18800 t.parentNode.insertBefore(n, t.nextSibling);
18806 if(this.tree.hlDrop){
18810 this.tree.fireEvent("nodedrop", de);
18813 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18814 if(this.tree.hlDrop){
18815 dropNode.ui.focus();
18816 dropNode.ui.highlight();
18818 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18821 getTree : function(){
18825 removeDropIndicators : function(n){
18828 Roo.fly(el).removeClass([
18829 "x-tree-drag-insert-above",
18830 "x-tree-drag-insert-below",
18831 "x-tree-drag-append"]);
18832 this.lastInsertClass = "_noclass";
18836 beforeDragDrop : function(target, e, id){
18837 this.cancelExpand();
18841 afterRepair : function(data){
18842 if(data && Roo.enableFx){
18843 data.node.ui.highlight();
18852 * Ext JS Library 1.1.1
18853 * Copyright(c) 2006-2007, Ext JS, LLC.
18855 * Originally Released Under LGPL - original licence link has changed is not relivant.
18858 * <script type="text/javascript">
18862 if(Roo.dd.DragZone){
18863 Roo.tree.TreeDragZone = function(tree, config){
18864 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18868 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18869 ddGroup : "TreeDD",
18871 onBeforeDrag : function(data, e){
18873 return n && n.draggable && !n.disabled;
18876 onInitDrag : function(e){
18877 var data = this.dragData;
18878 this.tree.getSelectionModel().select(data.node);
18879 this.proxy.update("");
18880 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18881 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18884 getRepairXY : function(e, data){
18885 return data.node.ui.getDDRepairXY();
18888 onEndDrag : function(data, e){
18889 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18892 onValidDrop : function(dd, e, id){
18893 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18897 beforeInvalidDrop : function(e, id){
18898 // this scrolls the original position back into view
18899 var sm = this.tree.getSelectionModel();
18900 sm.clearSelections();
18901 sm.select(this.dragData.node);
18906 * Ext JS Library 1.1.1
18907 * Copyright(c) 2006-2007, Ext JS, LLC.
18909 * Originally Released Under LGPL - original licence link has changed is not relivant.
18912 * <script type="text/javascript">
18915 * @class Roo.tree.TreeEditor
18916 * @extends Roo.Editor
18917 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18918 * as the editor field.
18920 * @param {TreePanel} tree
18921 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18923 Roo.tree.TreeEditor = function(tree, config){
18924 config = config || {};
18925 var field = config.events ? config : new Roo.form.TextField(config);
18926 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18930 tree.on('beforeclick', this.beforeNodeClick, this);
18931 tree.getTreeEl().on('mousedown', this.hide, this);
18932 this.on('complete', this.updateNode, this);
18933 this.on('beforestartedit', this.fitToTree, this);
18934 this.on('startedit', this.bindScroll, this, {delay:10});
18935 this.on('specialkey', this.onSpecialKey, this);
18938 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18940 * @cfg {String} alignment
18941 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18947 * @cfg {Boolean} hideEl
18948 * True to hide the bound element while the editor is displayed (defaults to false)
18952 * @cfg {String} cls
18953 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18955 cls: "x-small-editor x-tree-editor",
18957 * @cfg {Boolean} shim
18958 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18964 * @cfg {Number} maxWidth
18965 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18966 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18967 * scroll and client offsets into account prior to each edit.
18974 fitToTree : function(ed, el){
18975 var td = this.tree.getTreeEl().dom, nd = el.dom;
18976 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
18977 td.scrollLeft = nd.offsetLeft;
18981 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
18982 this.setSize(w, '');
18986 triggerEdit : function(node){
18987 this.completeEdit();
18988 this.editNode = node;
18989 this.startEdit(node.ui.textNode, node.text);
18993 bindScroll : function(){
18994 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
18998 beforeNodeClick : function(node, e){
18999 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19000 this.lastClick = new Date();
19001 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19003 this.triggerEdit(node);
19009 updateNode : function(ed, value){
19010 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19011 this.editNode.setText(value);
19015 onHide : function(){
19016 Roo.tree.TreeEditor.superclass.onHide.call(this);
19018 this.editNode.ui.focus();
19023 onSpecialKey : function(field, e){
19024 var k = e.getKey();
19028 }else if(k == e.ENTER && !e.hasModifier()){
19030 this.completeEdit();
19033 });//<Script type="text/javascript">
19036 * Ext JS Library 1.1.1
19037 * Copyright(c) 2006-2007, Ext JS, LLC.
19039 * Originally Released Under LGPL - original licence link has changed is not relivant.
19042 * <script type="text/javascript">
19046 * Not documented??? - probably should be...
19049 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19050 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19052 renderElements : function(n, a, targetNode, bulkRender){
19053 //consel.log("renderElements?");
19054 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19056 var t = n.getOwnerTree();
19057 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19059 var cols = t.columns;
19060 var bw = t.borderWidth;
19062 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19063 var cb = typeof a.checked == "boolean";
19064 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19065 var colcls = 'x-t-' + tid + '-c0';
19067 '<li class="x-tree-node">',
19070 '<div class="x-tree-node-el ', a.cls,'">',
19072 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19075 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19076 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19077 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19078 (a.icon ? ' x-tree-node-inline-icon' : ''),
19079 (a.iconCls ? ' '+a.iconCls : ''),
19080 '" unselectable="on" />',
19081 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19082 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19084 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19085 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19086 '<span unselectable="on" qtip="' + tx + '">',
19090 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19091 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19093 for(var i = 1, len = cols.length; i < len; i++){
19095 colcls = 'x-t-' + tid + '-c' +i;
19096 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19097 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19098 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19104 '<div class="x-clear"></div></div>',
19105 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19108 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19109 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19110 n.nextSibling.ui.getEl(), buf.join(""));
19112 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19114 var el = this.wrap.firstChild;
19116 this.elNode = el.firstChild;
19117 this.ranchor = el.childNodes[1];
19118 this.ctNode = this.wrap.childNodes[1];
19119 var cs = el.firstChild.childNodes;
19120 this.indentNode = cs[0];
19121 this.ecNode = cs[1];
19122 this.iconNode = cs[2];
19125 this.checkbox = cs[3];
19128 this.anchor = cs[index];
19130 this.textNode = cs[index].firstChild;
19132 //el.on("click", this.onClick, this);
19133 //el.on("dblclick", this.onDblClick, this);
19136 // console.log(this);
19138 initEvents : function(){
19139 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19142 var a = this.ranchor;
19144 var el = Roo.get(a);
19146 if(Roo.isOpera){ // opera render bug ignores the CSS
19147 el.setStyle("text-decoration", "none");
19150 el.on("click", this.onClick, this);
19151 el.on("dblclick", this.onDblClick, this);
19152 el.on("contextmenu", this.onContextMenu, this);
19156 /*onSelectedChange : function(state){
19159 this.addClass("x-tree-selected");
19162 this.removeClass("x-tree-selected");
19165 addClass : function(cls){
19167 Roo.fly(this.elRow).addClass(cls);
19173 removeClass : function(cls){
19175 Roo.fly(this.elRow).removeClass(cls);
19181 });//<Script type="text/javascript">
19185 * Ext JS Library 1.1.1
19186 * Copyright(c) 2006-2007, Ext JS, LLC.
19188 * Originally Released Under LGPL - original licence link has changed is not relivant.
19191 * <script type="text/javascript">
19196 * @class Roo.tree.ColumnTree
19197 * @extends Roo.data.TreePanel
19198 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19199 * @cfg {int} borderWidth compined right/left border allowance
19201 * @param {String/HTMLElement/Element} el The container element
19202 * @param {Object} config
19204 Roo.tree.ColumnTree = function(el, config)
19206 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19210 * Fire this event on a container when it resizes
19211 * @param {int} w Width
19212 * @param {int} h Height
19216 this.on('resize', this.onResize, this);
19219 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19223 borderWidth: Roo.isBorderBox ? 0 : 2,
19226 render : function(){
19227 // add the header.....
19229 Roo.tree.ColumnTree.superclass.render.apply(this);
19231 this.el.addClass('x-column-tree');
19233 this.headers = this.el.createChild(
19234 {cls:'x-tree-headers'},this.innerCt.dom);
19236 var cols = this.columns, c;
19237 var totalWidth = 0;
19239 var len = cols.length;
19240 for(var i = 0; i < len; i++){
19242 totalWidth += c.width;
19243 this.headEls.push(this.headers.createChild({
19244 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19246 cls:'x-tree-hd-text',
19249 style:'width:'+(c.width-this.borderWidth)+'px;'
19252 this.headers.createChild({cls:'x-clear'});
19253 // prevent floats from wrapping when clipped
19254 this.headers.setWidth(totalWidth);
19255 //this.innerCt.setWidth(totalWidth);
19256 this.innerCt.setStyle({ overflow: 'auto' });
19257 this.onResize(this.width, this.height);
19261 onResize : function(w,h)
19266 this.innerCt.setWidth(this.width);
19267 this.innerCt.setHeight(this.height-20);
19270 var cols = this.columns, c;
19271 var totalWidth = 0;
19273 var len = cols.length;
19274 for(var i = 0; i < len; i++){
19276 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19277 // it's the expander..
19278 expEl = this.headEls[i];
19281 totalWidth += c.width;
19285 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19287 this.headers.setWidth(w-20);
19296 * Ext JS Library 1.1.1
19297 * Copyright(c) 2006-2007, Ext JS, LLC.
19299 * Originally Released Under LGPL - original licence link has changed is not relivant.
19302 * <script type="text/javascript">
19306 * @class Roo.menu.Menu
19307 * @extends Roo.util.Observable
19308 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19309 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19311 * Creates a new Menu
19312 * @param {Object} config Configuration options
19314 Roo.menu.Menu = function(config){
19315 Roo.apply(this, config);
19316 this.id = this.id || Roo.id();
19319 * @event beforeshow
19320 * Fires before this menu is displayed
19321 * @param {Roo.menu.Menu} this
19325 * @event beforehide
19326 * Fires before this menu is hidden
19327 * @param {Roo.menu.Menu} this
19332 * Fires after this menu is displayed
19333 * @param {Roo.menu.Menu} this
19338 * Fires after this menu is hidden
19339 * @param {Roo.menu.Menu} this
19344 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19345 * @param {Roo.menu.Menu} this
19346 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19347 * @param {Roo.EventObject} e
19352 * Fires when the mouse is hovering over this menu
19353 * @param {Roo.menu.Menu} this
19354 * @param {Roo.EventObject} e
19355 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19360 * Fires when the mouse exits this menu
19361 * @param {Roo.menu.Menu} this
19362 * @param {Roo.EventObject} e
19363 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19368 * Fires when a menu item contained in this menu is clicked
19369 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19370 * @param {Roo.EventObject} e
19374 if (this.registerMenu) {
19375 Roo.menu.MenuMgr.register(this);
19378 var mis = this.items;
19379 this.items = new Roo.util.MixedCollection();
19381 this.add.apply(this, mis);
19385 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19387 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19391 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19392 * for bottom-right shadow (defaults to "sides")
19396 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19397 * this menu (defaults to "tl-tr?")
19399 subMenuAlign : "tl-tr?",
19401 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19402 * relative to its element of origin (defaults to "tl-bl?")
19404 defaultAlign : "tl-bl?",
19406 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19408 allowOtherMenus : false,
19410 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19412 registerMenu : true,
19417 render : function(){
19421 var el = this.el = new Roo.Layer({
19423 shadow:this.shadow,
19425 parentEl: this.parentEl || document.body,
19429 this.keyNav = new Roo.menu.MenuNav(this);
19432 el.addClass("x-menu-plain");
19435 el.addClass(this.cls);
19437 // generic focus element
19438 this.focusEl = el.createChild({
19439 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19441 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19442 ul.on("click", this.onClick, this);
19443 ul.on("mouseover", this.onMouseOver, this);
19444 ul.on("mouseout", this.onMouseOut, this);
19445 this.items.each(function(item){
19446 var li = document.createElement("li");
19447 li.className = "x-menu-list-item";
19448 ul.dom.appendChild(li);
19449 item.render(li, this);
19456 autoWidth : function(){
19457 var el = this.el, ul = this.ul;
19461 var w = this.width;
19464 }else if(Roo.isIE){
19465 el.setWidth(this.minWidth);
19466 var t = el.dom.offsetWidth; // force recalc
19467 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19472 delayAutoWidth : function(){
19475 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19477 this.awTask.delay(20);
19482 findTargetItem : function(e){
19483 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19484 if(t && t.menuItemId){
19485 return this.items.get(t.menuItemId);
19490 onClick : function(e){
19492 if(t = this.findTargetItem(e)){
19494 this.fireEvent("click", this, t, e);
19499 setActiveItem : function(item, autoExpand){
19500 if(item != this.activeItem){
19501 if(this.activeItem){
19502 this.activeItem.deactivate();
19504 this.activeItem = item;
19505 item.activate(autoExpand);
19506 }else if(autoExpand){
19512 tryActivate : function(start, step){
19513 var items = this.items;
19514 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19515 var item = items.get(i);
19516 if(!item.disabled && item.canActivate){
19517 this.setActiveItem(item, false);
19525 onMouseOver : function(e){
19527 if(t = this.findTargetItem(e)){
19528 if(t.canActivate && !t.disabled){
19529 this.setActiveItem(t, true);
19532 this.fireEvent("mouseover", this, e, t);
19536 onMouseOut : function(e){
19538 if(t = this.findTargetItem(e)){
19539 if(t == this.activeItem && t.shouldDeactivate(e)){
19540 this.activeItem.deactivate();
19541 delete this.activeItem;
19544 this.fireEvent("mouseout", this, e, t);
19548 * Read-only. Returns true if the menu is currently displayed, else false.
19551 isVisible : function(){
19552 return this.el && !this.hidden;
19556 * Displays this menu relative to another element
19557 * @param {String/HTMLElement/Roo.Element} element The element to align to
19558 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19559 * the element (defaults to this.defaultAlign)
19560 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19562 show : function(el, pos, parentMenu){
19563 this.parentMenu = parentMenu;
19567 this.fireEvent("beforeshow", this);
19568 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19572 * Displays this menu at a specific xy position
19573 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19574 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19576 showAt : function(xy, parentMenu, /* private: */_e){
19577 this.parentMenu = parentMenu;
19582 this.fireEvent("beforeshow", this);
19583 xy = this.el.adjustForConstraints(xy);
19587 this.hidden = false;
19589 this.fireEvent("show", this);
19592 focus : function(){
19594 this.doFocus.defer(50, this);
19598 doFocus : function(){
19600 this.focusEl.focus();
19605 * Hides this menu and optionally all parent menus
19606 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19608 hide : function(deep){
19609 if(this.el && this.isVisible()){
19610 this.fireEvent("beforehide", this);
19611 if(this.activeItem){
19612 this.activeItem.deactivate();
19613 this.activeItem = null;
19616 this.hidden = true;
19617 this.fireEvent("hide", this);
19619 if(deep === true && this.parentMenu){
19620 this.parentMenu.hide(true);
19625 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19626 * Any of the following are valid:
19628 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19629 * <li>An HTMLElement object which will be converted to a menu item</li>
19630 * <li>A menu item config object that will be created as a new menu item</li>
19631 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19632 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19637 var menu = new Roo.menu.Menu();
19639 // Create a menu item to add by reference
19640 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19642 // Add a bunch of items at once using different methods.
19643 // Only the last item added will be returned.
19644 var item = menu.add(
19645 menuItem, // add existing item by ref
19646 'Dynamic Item', // new TextItem
19647 '-', // new separator
19648 { text: 'Config Item' } // new item by config
19651 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19652 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19655 var a = arguments, l = a.length, item;
19656 for(var i = 0; i < l; i++){
19658 if ((typeof(el) == "object") && el.xtype && el.xns) {
19659 el = Roo.factory(el, Roo.menu);
19662 if(el.render){ // some kind of Item
19663 item = this.addItem(el);
19664 }else if(typeof el == "string"){ // string
19665 if(el == "separator" || el == "-"){
19666 item = this.addSeparator();
19668 item = this.addText(el);
19670 }else if(el.tagName || el.el){ // element
19671 item = this.addElement(el);
19672 }else if(typeof el == "object"){ // must be menu item config?
19673 item = this.addMenuItem(el);
19680 * Returns this menu's underlying {@link Roo.Element} object
19681 * @return {Roo.Element} The element
19683 getEl : function(){
19691 * Adds a separator bar to the menu
19692 * @return {Roo.menu.Item} The menu item that was added
19694 addSeparator : function(){
19695 return this.addItem(new Roo.menu.Separator());
19699 * Adds an {@link Roo.Element} object to the menu
19700 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19701 * @return {Roo.menu.Item} The menu item that was added
19703 addElement : function(el){
19704 return this.addItem(new Roo.menu.BaseItem(el));
19708 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19709 * @param {Roo.menu.Item} item The menu item to add
19710 * @return {Roo.menu.Item} The menu item that was added
19712 addItem : function(item){
19713 this.items.add(item);
19715 var li = document.createElement("li");
19716 li.className = "x-menu-list-item";
19717 this.ul.dom.appendChild(li);
19718 item.render(li, this);
19719 this.delayAutoWidth();
19725 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19726 * @param {Object} config A MenuItem config object
19727 * @return {Roo.menu.Item} The menu item that was added
19729 addMenuItem : function(config){
19730 if(!(config instanceof Roo.menu.Item)){
19731 if(typeof config.checked == "boolean"){ // must be check menu item config?
19732 config = new Roo.menu.CheckItem(config);
19734 config = new Roo.menu.Item(config);
19737 return this.addItem(config);
19741 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19742 * @param {String} text The text to display in the menu item
19743 * @return {Roo.menu.Item} The menu item that was added
19745 addText : function(text){
19746 return this.addItem(new Roo.menu.TextItem({ text : text }));
19750 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19751 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19752 * @param {Roo.menu.Item} item The menu item to add
19753 * @return {Roo.menu.Item} The menu item that was added
19755 insert : function(index, item){
19756 this.items.insert(index, item);
19758 var li = document.createElement("li");
19759 li.className = "x-menu-list-item";
19760 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19761 item.render(li, this);
19762 this.delayAutoWidth();
19768 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19769 * @param {Roo.menu.Item} item The menu item to remove
19771 remove : function(item){
19772 this.items.removeKey(item.id);
19777 * Removes and destroys all items in the menu
19779 removeAll : function(){
19781 while(f = this.items.first()){
19787 // MenuNav is a private utility class used internally by the Menu
19788 Roo.menu.MenuNav = function(menu){
19789 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19790 this.scope = this.menu = menu;
19793 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19794 doRelay : function(e, h){
19795 var k = e.getKey();
19796 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19797 this.menu.tryActivate(0, 1);
19800 return h.call(this.scope || this, e, this.menu);
19803 up : function(e, m){
19804 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19805 m.tryActivate(m.items.length-1, -1);
19809 down : function(e, m){
19810 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19811 m.tryActivate(0, 1);
19815 right : function(e, m){
19817 m.activeItem.expandMenu(true);
19821 left : function(e, m){
19823 if(m.parentMenu && m.parentMenu.activeItem){
19824 m.parentMenu.activeItem.activate();
19828 enter : function(e, m){
19830 e.stopPropagation();
19831 m.activeItem.onClick(e);
19832 m.fireEvent("click", this, m.activeItem);
19838 * Ext JS Library 1.1.1
19839 * Copyright(c) 2006-2007, Ext JS, LLC.
19841 * Originally Released Under LGPL - original licence link has changed is not relivant.
19844 * <script type="text/javascript">
19848 * @class Roo.menu.MenuMgr
19849 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19852 Roo.menu.MenuMgr = function(){
19853 var menus, active, groups = {}, attached = false, lastShow = new Date();
19855 // private - called when first menu is created
19858 active = new Roo.util.MixedCollection();
19859 Roo.get(document).addKeyListener(27, function(){
19860 if(active.length > 0){
19867 function hideAll(){
19868 if(active && active.length > 0){
19869 var c = active.clone();
19870 c.each(function(m){
19877 function onHide(m){
19879 if(active.length < 1){
19880 Roo.get(document).un("mousedown", onMouseDown);
19886 function onShow(m){
19887 var last = active.last();
19888 lastShow = new Date();
19891 Roo.get(document).on("mousedown", onMouseDown);
19895 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19896 m.parentMenu.activeChild = m;
19897 }else if(last && last.isVisible()){
19898 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19903 function onBeforeHide(m){
19905 m.activeChild.hide();
19907 if(m.autoHideTimer){
19908 clearTimeout(m.autoHideTimer);
19909 delete m.autoHideTimer;
19914 function onBeforeShow(m){
19915 var pm = m.parentMenu;
19916 if(!pm && !m.allowOtherMenus){
19918 }else if(pm && pm.activeChild && active != m){
19919 pm.activeChild.hide();
19924 function onMouseDown(e){
19925 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19931 function onBeforeCheck(mi, state){
19933 var g = groups[mi.group];
19934 for(var i = 0, l = g.length; i < l; i++){
19936 g[i].setChecked(false);
19945 * Hides all menus that are currently visible
19947 hideAll : function(){
19952 register : function(menu){
19956 menus[menu.id] = menu;
19957 menu.on("beforehide", onBeforeHide);
19958 menu.on("hide", onHide);
19959 menu.on("beforeshow", onBeforeShow);
19960 menu.on("show", onShow);
19961 var g = menu.group;
19962 if(g && menu.events["checkchange"]){
19966 groups[g].push(menu);
19967 menu.on("checkchange", onCheck);
19972 * Returns a {@link Roo.menu.Menu} object
19973 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19974 * be used to generate and return a new Menu instance.
19976 get : function(menu){
19977 if(typeof menu == "string"){ // menu id
19978 return menus[menu];
19979 }else if(menu.events){ // menu instance
19981 }else if(typeof menu.length == 'number'){ // array of menu items?
19982 return new Roo.menu.Menu({items:menu});
19983 }else{ // otherwise, must be a config
19984 return new Roo.menu.Menu(menu);
19989 unregister : function(menu){
19990 delete menus[menu.id];
19991 menu.un("beforehide", onBeforeHide);
19992 menu.un("hide", onHide);
19993 menu.un("beforeshow", onBeforeShow);
19994 menu.un("show", onShow);
19995 var g = menu.group;
19996 if(g && menu.events["checkchange"]){
19997 groups[g].remove(menu);
19998 menu.un("checkchange", onCheck);
20003 registerCheckable : function(menuItem){
20004 var g = menuItem.group;
20009 groups[g].push(menuItem);
20010 menuItem.on("beforecheckchange", onBeforeCheck);
20015 unregisterCheckable : function(menuItem){
20016 var g = menuItem.group;
20018 groups[g].remove(menuItem);
20019 menuItem.un("beforecheckchange", onBeforeCheck);
20025 * Ext JS Library 1.1.1
20026 * Copyright(c) 2006-2007, Ext JS, LLC.
20028 * Originally Released Under LGPL - original licence link has changed is not relivant.
20031 * <script type="text/javascript">
20036 * @class Roo.menu.BaseItem
20037 * @extends Roo.Component
20038 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20039 * management and base configuration options shared by all menu components.
20041 * Creates a new BaseItem
20042 * @param {Object} config Configuration options
20044 Roo.menu.BaseItem = function(config){
20045 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20050 * Fires when this item is clicked
20051 * @param {Roo.menu.BaseItem} this
20052 * @param {Roo.EventObject} e
20057 * Fires when this item is activated
20058 * @param {Roo.menu.BaseItem} this
20062 * @event deactivate
20063 * Fires when this item is deactivated
20064 * @param {Roo.menu.BaseItem} this
20070 this.on("click", this.handler, this.scope, true);
20074 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20076 * @cfg {Function} handler
20077 * A function that will handle the click event of this menu item (defaults to undefined)
20080 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20082 canActivate : false,
20084 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20086 activeClass : "x-menu-item-active",
20088 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20090 hideOnClick : true,
20092 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20097 ctype: "Roo.menu.BaseItem",
20100 actionMode : "container",
20103 render : function(container, parentMenu){
20104 this.parentMenu = parentMenu;
20105 Roo.menu.BaseItem.superclass.render.call(this, container);
20106 this.container.menuItemId = this.id;
20110 onRender : function(container, position){
20111 this.el = Roo.get(this.el);
20112 container.dom.appendChild(this.el.dom);
20116 onClick : function(e){
20117 if(!this.disabled && this.fireEvent("click", this, e) !== false
20118 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20119 this.handleClick(e);
20126 activate : function(){
20130 var li = this.container;
20131 li.addClass(this.activeClass);
20132 this.region = li.getRegion().adjust(2, 2, -2, -2);
20133 this.fireEvent("activate", this);
20138 deactivate : function(){
20139 this.container.removeClass(this.activeClass);
20140 this.fireEvent("deactivate", this);
20144 shouldDeactivate : function(e){
20145 return !this.region || !this.region.contains(e.getPoint());
20149 handleClick : function(e){
20150 if(this.hideOnClick){
20151 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20156 expandMenu : function(autoActivate){
20161 hideMenu : function(){
20166 * Ext JS Library 1.1.1
20167 * Copyright(c) 2006-2007, Ext JS, LLC.
20169 * Originally Released Under LGPL - original licence link has changed is not relivant.
20172 * <script type="text/javascript">
20176 * @class Roo.menu.Adapter
20177 * @extends Roo.menu.BaseItem
20178 * 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.
20179 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20181 * Creates a new Adapter
20182 * @param {Object} config Configuration options
20184 Roo.menu.Adapter = function(component, config){
20185 Roo.menu.Adapter.superclass.constructor.call(this, config);
20186 this.component = component;
20188 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20190 canActivate : true,
20193 onRender : function(container, position){
20194 this.component.render(container);
20195 this.el = this.component.getEl();
20199 activate : function(){
20203 this.component.focus();
20204 this.fireEvent("activate", this);
20209 deactivate : function(){
20210 this.fireEvent("deactivate", this);
20214 disable : function(){
20215 this.component.disable();
20216 Roo.menu.Adapter.superclass.disable.call(this);
20220 enable : function(){
20221 this.component.enable();
20222 Roo.menu.Adapter.superclass.enable.call(this);
20226 * Ext JS Library 1.1.1
20227 * Copyright(c) 2006-2007, Ext JS, LLC.
20229 * Originally Released Under LGPL - original licence link has changed is not relivant.
20232 * <script type="text/javascript">
20236 * @class Roo.menu.TextItem
20237 * @extends Roo.menu.BaseItem
20238 * Adds a static text string to a menu, usually used as either a heading or group separator.
20239 * Note: old style constructor with text is still supported.
20242 * Creates a new TextItem
20243 * @param {Object} cfg Configuration
20245 Roo.menu.TextItem = function(cfg){
20246 if (typeof(cfg) == 'string') {
20249 Roo.apply(this,cfg);
20252 Roo.menu.TextItem.superclass.constructor.call(this);
20255 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20257 * @cfg {Boolean} text Text to show on item.
20262 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20264 hideOnClick : false,
20266 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20268 itemCls : "x-menu-text",
20271 onRender : function(){
20272 var s = document.createElement("span");
20273 s.className = this.itemCls;
20274 s.innerHTML = this.text;
20276 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20280 * Ext JS Library 1.1.1
20281 * Copyright(c) 2006-2007, Ext JS, LLC.
20283 * Originally Released Under LGPL - original licence link has changed is not relivant.
20286 * <script type="text/javascript">
20290 * @class Roo.menu.Separator
20291 * @extends Roo.menu.BaseItem
20292 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20293 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20295 * @param {Object} config Configuration options
20297 Roo.menu.Separator = function(config){
20298 Roo.menu.Separator.superclass.constructor.call(this, config);
20301 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20303 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20305 itemCls : "x-menu-sep",
20307 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20309 hideOnClick : false,
20312 onRender : function(li){
20313 var s = document.createElement("span");
20314 s.className = this.itemCls;
20315 s.innerHTML = " ";
20317 li.addClass("x-menu-sep-li");
20318 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20322 * Ext JS Library 1.1.1
20323 * Copyright(c) 2006-2007, Ext JS, LLC.
20325 * Originally Released Under LGPL - original licence link has changed is not relivant.
20328 * <script type="text/javascript">
20331 * @class Roo.menu.Item
20332 * @extends Roo.menu.BaseItem
20333 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20334 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20335 * activation and click handling.
20337 * Creates a new Item
20338 * @param {Object} config Configuration options
20340 Roo.menu.Item = function(config){
20341 Roo.menu.Item.superclass.constructor.call(this, config);
20343 this.menu = Roo.menu.MenuMgr.get(this.menu);
20346 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20349 * @cfg {String} text
20350 * The text to show on the menu item.
20354 * @cfg {String} HTML to render in menu
20355 * The text to show on the menu item (HTML version).
20359 * @cfg {String} icon
20360 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20364 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20366 itemCls : "x-menu-item",
20368 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20370 canActivate : true,
20372 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20375 // doc'd in BaseItem
20379 ctype: "Roo.menu.Item",
20382 onRender : function(container, position){
20383 var el = document.createElement("a");
20384 el.hideFocus = true;
20385 el.unselectable = "on";
20386 el.href = this.href || "#";
20387 if(this.hrefTarget){
20388 el.target = this.hrefTarget;
20390 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20392 var html = this.html.length ? this.html : String.format('{0}',this.text);
20394 el.innerHTML = String.format(
20395 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20396 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20398 Roo.menu.Item.superclass.onRender.call(this, container, position);
20402 * Sets the text to display in this menu item
20403 * @param {String} text The text to display
20404 * @param {Boolean} isHTML true to indicate text is pure html.
20406 setText : function(text, isHTML){
20414 var html = this.html.length ? this.html : String.format('{0}',this.text);
20416 this.el.update(String.format(
20417 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20418 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20419 this.parentMenu.autoWidth();
20424 handleClick : function(e){
20425 if(!this.href){ // if no link defined, stop the event automatically
20428 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20432 activate : function(autoExpand){
20433 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20443 shouldDeactivate : function(e){
20444 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20445 if(this.menu && this.menu.isVisible()){
20446 return !this.menu.getEl().getRegion().contains(e.getPoint());
20454 deactivate : function(){
20455 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20460 expandMenu : function(autoActivate){
20461 if(!this.disabled && this.menu){
20462 clearTimeout(this.hideTimer);
20463 delete this.hideTimer;
20464 if(!this.menu.isVisible() && !this.showTimer){
20465 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20466 }else if (this.menu.isVisible() && autoActivate){
20467 this.menu.tryActivate(0, 1);
20473 deferExpand : function(autoActivate){
20474 delete this.showTimer;
20475 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20477 this.menu.tryActivate(0, 1);
20482 hideMenu : function(){
20483 clearTimeout(this.showTimer);
20484 delete this.showTimer;
20485 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20486 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20491 deferHide : function(){
20492 delete this.hideTimer;
20497 * Ext JS Library 1.1.1
20498 * Copyright(c) 2006-2007, Ext JS, LLC.
20500 * Originally Released Under LGPL - original licence link has changed is not relivant.
20503 * <script type="text/javascript">
20507 * @class Roo.menu.CheckItem
20508 * @extends Roo.menu.Item
20509 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20511 * Creates a new CheckItem
20512 * @param {Object} config Configuration options
20514 Roo.menu.CheckItem = function(config){
20515 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20518 * @event beforecheckchange
20519 * Fires before the checked value is set, providing an opportunity to cancel if needed
20520 * @param {Roo.menu.CheckItem} this
20521 * @param {Boolean} checked The new checked value that will be set
20523 "beforecheckchange" : true,
20525 * @event checkchange
20526 * Fires after the checked value has been set
20527 * @param {Roo.menu.CheckItem} this
20528 * @param {Boolean} checked The checked value that was set
20530 "checkchange" : true
20532 if(this.checkHandler){
20533 this.on('checkchange', this.checkHandler, this.scope);
20536 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20538 * @cfg {String} group
20539 * All check items with the same group name will automatically be grouped into a single-select
20540 * radio button group (defaults to '')
20543 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20545 itemCls : "x-menu-item x-menu-check-item",
20547 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20549 groupClass : "x-menu-group-item",
20552 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20553 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20554 * initialized with checked = true will be rendered as checked.
20559 ctype: "Roo.menu.CheckItem",
20562 onRender : function(c){
20563 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20565 this.el.addClass(this.groupClass);
20567 Roo.menu.MenuMgr.registerCheckable(this);
20569 this.checked = false;
20570 this.setChecked(true, true);
20575 destroy : function(){
20577 Roo.menu.MenuMgr.unregisterCheckable(this);
20579 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20583 * Set the checked state of this item
20584 * @param {Boolean} checked The new checked value
20585 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20587 setChecked : function(state, suppressEvent){
20588 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20589 if(this.container){
20590 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20592 this.checked = state;
20593 if(suppressEvent !== true){
20594 this.fireEvent("checkchange", this, state);
20600 handleClick : function(e){
20601 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20602 this.setChecked(!this.checked);
20604 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20608 * Ext JS Library 1.1.1
20609 * Copyright(c) 2006-2007, Ext JS, LLC.
20611 * Originally Released Under LGPL - original licence link has changed is not relivant.
20614 * <script type="text/javascript">
20618 * @class Roo.menu.DateItem
20619 * @extends Roo.menu.Adapter
20620 * A menu item that wraps the {@link Roo.DatPicker} component.
20622 * Creates a new DateItem
20623 * @param {Object} config Configuration options
20625 Roo.menu.DateItem = function(config){
20626 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20627 /** The Roo.DatePicker object @type Roo.DatePicker */
20628 this.picker = this.component;
20629 this.addEvents({select: true});
20631 this.picker.on("render", function(picker){
20632 picker.getEl().swallowEvent("click");
20633 picker.container.addClass("x-menu-date-item");
20636 this.picker.on("select", this.onSelect, this);
20639 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20641 onSelect : function(picker, date){
20642 this.fireEvent("select", this, date, picker);
20643 Roo.menu.DateItem.superclass.handleClick.call(this);
20647 * Ext JS Library 1.1.1
20648 * Copyright(c) 2006-2007, Ext JS, LLC.
20650 * Originally Released Under LGPL - original licence link has changed is not relivant.
20653 * <script type="text/javascript">
20657 * @class Roo.menu.ColorItem
20658 * @extends Roo.menu.Adapter
20659 * A menu item that wraps the {@link Roo.ColorPalette} component.
20661 * Creates a new ColorItem
20662 * @param {Object} config Configuration options
20664 Roo.menu.ColorItem = function(config){
20665 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20666 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20667 this.palette = this.component;
20668 this.relayEvents(this.palette, ["select"]);
20669 if(this.selectHandler){
20670 this.on('select', this.selectHandler, this.scope);
20673 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20675 * Ext JS Library 1.1.1
20676 * Copyright(c) 2006-2007, Ext JS, LLC.
20678 * Originally Released Under LGPL - original licence link has changed is not relivant.
20681 * <script type="text/javascript">
20686 * @class Roo.menu.DateMenu
20687 * @extends Roo.menu.Menu
20688 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20690 * Creates a new DateMenu
20691 * @param {Object} config Configuration options
20693 Roo.menu.DateMenu = function(config){
20694 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20696 var di = new Roo.menu.DateItem(config);
20699 * The {@link Roo.DatePicker} instance for this DateMenu
20702 this.picker = di.picker;
20705 * @param {DatePicker} picker
20706 * @param {Date} date
20708 this.relayEvents(di, ["select"]);
20710 this.on('beforeshow', function(){
20712 this.picker.hideMonthPicker(true);
20716 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20720 * Ext JS Library 1.1.1
20721 * Copyright(c) 2006-2007, Ext JS, LLC.
20723 * Originally Released Under LGPL - original licence link has changed is not relivant.
20726 * <script type="text/javascript">
20731 * @class Roo.menu.ColorMenu
20732 * @extends Roo.menu.Menu
20733 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20735 * Creates a new ColorMenu
20736 * @param {Object} config Configuration options
20738 Roo.menu.ColorMenu = function(config){
20739 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20741 var ci = new Roo.menu.ColorItem(config);
20744 * The {@link Roo.ColorPalette} instance for this ColorMenu
20745 * @type ColorPalette
20747 this.palette = ci.palette;
20750 * @param {ColorPalette} palette
20751 * @param {String} color
20753 this.relayEvents(ci, ["select"]);
20755 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20757 * Ext JS Library 1.1.1
20758 * Copyright(c) 2006-2007, Ext JS, LLC.
20760 * Originally Released Under LGPL - original licence link has changed is not relivant.
20763 * <script type="text/javascript">
20767 * @class Roo.form.Field
20768 * @extends Roo.BoxComponent
20769 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20771 * Creates a new Field
20772 * @param {Object} config Configuration options
20774 Roo.form.Field = function(config){
20775 Roo.form.Field.superclass.constructor.call(this, config);
20778 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20780 * @cfg {String} fieldLabel Label to use when rendering a form.
20783 * @cfg {String} qtip Mouse over tip
20787 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20789 invalidClass : "x-form-invalid",
20791 * @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")
20793 invalidText : "The value in this field is invalid",
20795 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20797 focusClass : "x-form-focus",
20799 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20800 automatic validation (defaults to "keyup").
20802 validationEvent : "keyup",
20804 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20806 validateOnBlur : true,
20808 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20810 validationDelay : 250,
20812 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20813 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20815 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20817 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20819 fieldClass : "x-form-field",
20821 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20824 ----------- ----------------------------------------------------------------------
20825 qtip Display a quick tip when the user hovers over the field
20826 title Display a default browser title attribute popup
20827 under Add a block div beneath the field containing the error text
20828 side Add an error icon to the right of the field with a popup on hover
20829 [element id] Add the error text directly to the innerHTML of the specified element
20832 msgTarget : 'qtip',
20834 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20839 * @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.
20844 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20849 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20851 inputType : undefined,
20854 * @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).
20856 tabIndex : undefined,
20859 isFormField : true,
20864 * @property {Roo.Element} fieldEl
20865 * Element Containing the rendered Field (with label etc.)
20868 * @cfg {Mixed} value A value to initialize this field with.
20873 * @cfg {String} name The field's HTML name attribute.
20876 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20880 initComponent : function(){
20881 Roo.form.Field.superclass.initComponent.call(this);
20885 * Fires when this field receives input focus.
20886 * @param {Roo.form.Field} this
20891 * Fires when this field loses input focus.
20892 * @param {Roo.form.Field} this
20896 * @event specialkey
20897 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20898 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20899 * @param {Roo.form.Field} this
20900 * @param {Roo.EventObject} e The event object
20905 * Fires just before the field blurs if the field value has changed.
20906 * @param {Roo.form.Field} this
20907 * @param {Mixed} newValue The new value
20908 * @param {Mixed} oldValue The original value
20913 * Fires after the field has been marked as invalid.
20914 * @param {Roo.form.Field} this
20915 * @param {String} msg The validation message
20920 * Fires after the field has been validated with no errors.
20921 * @param {Roo.form.Field} this
20926 * Fires after the key up
20927 * @param {Roo.form.Field} this
20928 * @param {Roo.EventObject} e The event Object
20935 * Returns the name attribute of the field if available
20936 * @return {String} name The field name
20938 getName: function(){
20939 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20943 onRender : function(ct, position){
20944 Roo.form.Field.superclass.onRender.call(this, ct, position);
20946 var cfg = this.getAutoCreate();
20948 cfg.name = this.name || this.id;
20950 if(this.inputType){
20951 cfg.type = this.inputType;
20953 this.el = ct.createChild(cfg, position);
20955 var type = this.el.dom.type;
20957 if(type == 'password'){
20960 this.el.addClass('x-form-'+type);
20963 this.el.dom.readOnly = true;
20965 if(this.tabIndex !== undefined){
20966 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20969 this.el.addClass([this.fieldClass, this.cls]);
20974 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20975 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20976 * @return {Roo.form.Field} this
20978 applyTo : function(target){
20979 this.allowDomMove = false;
20980 this.el = Roo.get(target);
20981 this.render(this.el.dom.parentNode);
20986 initValue : function(){
20987 if(this.value !== undefined){
20988 this.setValue(this.value);
20989 }else if(this.el.dom.value.length > 0){
20990 this.setValue(this.el.dom.value);
20995 * Returns true if this field has been changed since it was originally loaded and is not disabled.
20997 isDirty : function() {
20998 if(this.disabled) {
21001 return String(this.getValue()) !== String(this.originalValue);
21005 afterRender : function(){
21006 Roo.form.Field.superclass.afterRender.call(this);
21011 fireKey : function(e){
21012 //Roo.log('field ' + e.getKey());
21013 if(e.isNavKeyPress()){
21014 this.fireEvent("specialkey", this, e);
21019 * Resets the current field value to the originally loaded value and clears any validation messages
21021 reset : function(){
21022 this.setValue(this.originalValue);
21023 this.clearInvalid();
21027 initEvents : function(){
21028 // safari killled keypress - so keydown is now used..
21029 this.el.on("keydown" , this.fireKey, this);
21030 this.el.on("focus", this.onFocus, this);
21031 this.el.on("blur", this.onBlur, this);
21032 this.el.relayEvent('keyup', this);
21034 // reference to original value for reset
21035 this.originalValue = this.getValue();
21039 onFocus : function(){
21040 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21041 this.el.addClass(this.focusClass);
21043 if(!this.hasFocus){
21044 this.hasFocus = true;
21045 this.startValue = this.getValue();
21046 this.fireEvent("focus", this);
21050 beforeBlur : Roo.emptyFn,
21053 onBlur : function(){
21055 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21056 this.el.removeClass(this.focusClass);
21058 this.hasFocus = false;
21059 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21062 var v = this.getValue();
21063 if(String(v) !== String(this.startValue)){
21064 this.fireEvent('change', this, v, this.startValue);
21066 this.fireEvent("blur", this);
21070 * Returns whether or not the field value is currently valid
21071 * @param {Boolean} preventMark True to disable marking the field invalid
21072 * @return {Boolean} True if the value is valid, else false
21074 isValid : function(preventMark){
21078 var restore = this.preventMark;
21079 this.preventMark = preventMark === true;
21080 var v = this.validateValue(this.processValue(this.getRawValue()));
21081 this.preventMark = restore;
21086 * Validates the field value
21087 * @return {Boolean} True if the value is valid, else false
21089 validate : function(){
21090 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21091 this.clearInvalid();
21097 processValue : function(value){
21102 // Subclasses should provide the validation implementation by overriding this
21103 validateValue : function(value){
21108 * Mark this field as invalid
21109 * @param {String} msg The validation message
21111 markInvalid : function(msg){
21112 if(!this.rendered || this.preventMark){ // not rendered
21115 this.el.addClass(this.invalidClass);
21116 msg = msg || this.invalidText;
21117 switch(this.msgTarget){
21119 this.el.dom.qtip = msg;
21120 this.el.dom.qclass = 'x-form-invalid-tip';
21121 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21122 Roo.QuickTips.enable();
21126 this.el.dom.title = msg;
21130 var elp = this.el.findParent('.x-form-element', 5, true);
21131 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21132 this.errorEl.setWidth(elp.getWidth(true)-20);
21134 this.errorEl.update(msg);
21135 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21138 if(!this.errorIcon){
21139 var elp = this.el.findParent('.x-form-element', 5, true);
21140 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21142 this.alignErrorIcon();
21143 this.errorIcon.dom.qtip = msg;
21144 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21145 this.errorIcon.show();
21146 this.on('resize', this.alignErrorIcon, this);
21149 var t = Roo.getDom(this.msgTarget);
21151 t.style.display = this.msgDisplay;
21154 this.fireEvent('invalid', this, msg);
21158 alignErrorIcon : function(){
21159 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21163 * Clear any invalid styles/messages for this field
21165 clearInvalid : function(){
21166 if(!this.rendered || this.preventMark){ // not rendered
21169 this.el.removeClass(this.invalidClass);
21170 switch(this.msgTarget){
21172 this.el.dom.qtip = '';
21175 this.el.dom.title = '';
21179 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21183 if(this.errorIcon){
21184 this.errorIcon.dom.qtip = '';
21185 this.errorIcon.hide();
21186 this.un('resize', this.alignErrorIcon, this);
21190 var t = Roo.getDom(this.msgTarget);
21192 t.style.display = 'none';
21195 this.fireEvent('valid', this);
21199 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21200 * @return {Mixed} value The field value
21202 getRawValue : function(){
21203 var v = this.el.getValue();
21204 if(v === this.emptyText){
21211 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21212 * @return {Mixed} value The field value
21214 getValue : function(){
21215 var v = this.el.getValue();
21216 if(v === this.emptyText || v === undefined){
21223 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21224 * @param {Mixed} value The value to set
21226 setRawValue : function(v){
21227 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21231 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21232 * @param {Mixed} value The value to set
21234 setValue : function(v){
21237 this.el.dom.value = (v === null || v === undefined ? '' : v);
21242 adjustSize : function(w, h){
21243 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21244 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21248 adjustWidth : function(tag, w){
21249 tag = tag.toLowerCase();
21250 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21251 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21252 if(tag == 'input'){
21255 if(tag = 'textarea'){
21258 }else if(Roo.isOpera){
21259 if(tag == 'input'){
21262 if(tag = 'textarea'){
21272 // anything other than normal should be considered experimental
21273 Roo.form.Field.msgFx = {
21275 show: function(msgEl, f){
21276 msgEl.setDisplayed('block');
21279 hide : function(msgEl, f){
21280 msgEl.setDisplayed(false).update('');
21285 show: function(msgEl, f){
21286 msgEl.slideIn('t', {stopFx:true});
21289 hide : function(msgEl, f){
21290 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21295 show: function(msgEl, f){
21296 msgEl.fixDisplay();
21297 msgEl.alignTo(f.el, 'tl-tr');
21298 msgEl.slideIn('l', {stopFx:true});
21301 hide : function(msgEl, f){
21302 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21307 * Ext JS Library 1.1.1
21308 * Copyright(c) 2006-2007, Ext JS, LLC.
21310 * Originally Released Under LGPL - original licence link has changed is not relivant.
21313 * <script type="text/javascript">
21318 * @class Roo.form.TextField
21319 * @extends Roo.form.Field
21320 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21321 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21323 * Creates a new TextField
21324 * @param {Object} config Configuration options
21326 Roo.form.TextField = function(config){
21327 Roo.form.TextField.superclass.constructor.call(this, config);
21331 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21332 * according to the default logic, but this event provides a hook for the developer to apply additional
21333 * logic at runtime to resize the field if needed.
21334 * @param {Roo.form.Field} this This text field
21335 * @param {Number} width The new field width
21341 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21343 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21347 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21351 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21355 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21359 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21363 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21365 disableKeyFilter : false,
21367 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21371 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21375 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21377 maxLength : Number.MAX_VALUE,
21379 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21381 minLengthText : "The minimum length for this field is {0}",
21383 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21385 maxLengthText : "The maximum length for this field is {0}",
21387 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21389 selectOnFocus : false,
21391 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21393 blankText : "This field is required",
21395 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21396 * If available, this function will be called only after the basic validators all return true, and will be passed the
21397 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21401 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21402 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21403 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21407 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21411 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21415 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21416 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21418 emptyClass : 'x-form-empty-field',
21421 initEvents : function(){
21422 Roo.form.TextField.superclass.initEvents.call(this);
21423 if(this.validationEvent == 'keyup'){
21424 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21425 this.el.on('keyup', this.filterValidation, this);
21427 else if(this.validationEvent !== false){
21428 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21430 if(this.selectOnFocus || this.emptyText){
21431 this.on("focus", this.preFocus, this);
21432 if(this.emptyText){
21433 this.on('blur', this.postBlur, this);
21434 this.applyEmptyText();
21437 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21438 this.el.on("keypress", this.filterKeys, this);
21441 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21442 this.el.on("click", this.autoSize, this);
21446 processValue : function(value){
21447 if(this.stripCharsRe){
21448 var newValue = value.replace(this.stripCharsRe, '');
21449 if(newValue !== value){
21450 this.setRawValue(newValue);
21457 filterValidation : function(e){
21458 if(!e.isNavKeyPress()){
21459 this.validationTask.delay(this.validationDelay);
21464 onKeyUp : function(e){
21465 if(!e.isNavKeyPress()){
21471 * Resets the current field value to the originally-loaded value and clears any validation messages.
21472 * Also adds emptyText and emptyClass if the original value was blank.
21474 reset : function(){
21475 Roo.form.TextField.superclass.reset.call(this);
21476 this.applyEmptyText();
21479 applyEmptyText : function(){
21480 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21481 this.setRawValue(this.emptyText);
21482 this.el.addClass(this.emptyClass);
21487 preFocus : function(){
21488 if(this.emptyText){
21489 if(this.el.dom.value == this.emptyText){
21490 this.setRawValue('');
21492 this.el.removeClass(this.emptyClass);
21494 if(this.selectOnFocus){
21495 this.el.dom.select();
21500 postBlur : function(){
21501 this.applyEmptyText();
21505 filterKeys : function(e){
21506 var k = e.getKey();
21507 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21510 var c = e.getCharCode(), cc = String.fromCharCode(c);
21511 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21514 if(!this.maskRe.test(cc)){
21519 setValue : function(v){
21520 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21521 this.el.removeClass(this.emptyClass);
21523 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21524 this.applyEmptyText();
21529 * Validates a value according to the field's validation rules and marks the field as invalid
21530 * if the validation fails
21531 * @param {Mixed} value The value to validate
21532 * @return {Boolean} True if the value is valid, else false
21534 validateValue : function(value){
21535 if(value.length < 1 || value === this.emptyText){ // if it's blank
21536 if(this.allowBlank){
21537 this.clearInvalid();
21540 this.markInvalid(this.blankText);
21544 if(value.length < this.minLength){
21545 this.markInvalid(String.format(this.minLengthText, this.minLength));
21548 if(value.length > this.maxLength){
21549 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21553 var vt = Roo.form.VTypes;
21554 if(!vt[this.vtype](value, this)){
21555 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21559 if(typeof this.validator == "function"){
21560 var msg = this.validator(value);
21562 this.markInvalid(msg);
21566 if(this.regex && !this.regex.test(value)){
21567 this.markInvalid(this.regexText);
21574 * Selects text in this field
21575 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21576 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21578 selectText : function(start, end){
21579 var v = this.getRawValue();
21581 start = start === undefined ? 0 : start;
21582 end = end === undefined ? v.length : end;
21583 var d = this.el.dom;
21584 if(d.setSelectionRange){
21585 d.setSelectionRange(start, end);
21586 }else if(d.createTextRange){
21587 var range = d.createTextRange();
21588 range.moveStart("character", start);
21589 range.moveEnd("character", v.length-end);
21596 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21597 * This only takes effect if grow = true, and fires the autosize event.
21599 autoSize : function(){
21600 if(!this.grow || !this.rendered){
21604 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21607 var v = el.dom.value;
21608 var d = document.createElement('div');
21609 d.appendChild(document.createTextNode(v));
21613 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21614 this.el.setWidth(w);
21615 this.fireEvent("autosize", this, w);
21619 * Ext JS Library 1.1.1
21620 * Copyright(c) 2006-2007, Ext JS, LLC.
21622 * Originally Released Under LGPL - original licence link has changed is not relivant.
21625 * <script type="text/javascript">
21629 * @class Roo.form.Hidden
21630 * @extends Roo.form.TextField
21631 * Simple Hidden element used on forms
21633 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21636 * Creates a new Hidden form element.
21637 * @param {Object} config Configuration options
21642 // easy hidden field...
21643 Roo.form.Hidden = function(config){
21644 Roo.form.Hidden.superclass.constructor.call(this, config);
21647 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21649 inputType: 'hidden',
21652 labelSeparator: '',
21654 itemCls : 'x-form-item-display-none'
21662 * Ext JS Library 1.1.1
21663 * Copyright(c) 2006-2007, Ext JS, LLC.
21665 * Originally Released Under LGPL - original licence link has changed is not relivant.
21668 * <script type="text/javascript">
21672 * @class Roo.form.TriggerField
21673 * @extends Roo.form.TextField
21674 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21675 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21676 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21677 * for which you can provide a custom implementation. For example:
21679 var trigger = new Roo.form.TriggerField();
21680 trigger.onTriggerClick = myTriggerFn;
21681 trigger.applyTo('my-field');
21684 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21685 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21686 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21687 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21689 * Create a new TriggerField.
21690 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21691 * to the base TextField)
21693 Roo.form.TriggerField = function(config){
21694 this.mimicing = false;
21695 Roo.form.TriggerField.superclass.constructor.call(this, config);
21698 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21700 * @cfg {String} triggerClass A CSS class to apply to the trigger
21703 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21704 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21706 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21708 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21712 /** @cfg {Boolean} grow @hide */
21713 /** @cfg {Number} growMin @hide */
21714 /** @cfg {Number} growMax @hide */
21720 autoSize: Roo.emptyFn,
21724 deferHeight : true,
21727 actionMode : 'wrap',
21729 onResize : function(w, h){
21730 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21731 if(typeof w == 'number'){
21732 var x = w - this.trigger.getWidth();
21733 this.el.setWidth(this.adjustWidth('input', x));
21734 this.trigger.setStyle('left', x+'px');
21739 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21742 getResizeEl : function(){
21747 getPositionEl : function(){
21752 alignErrorIcon : function(){
21753 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21757 onRender : function(ct, position){
21758 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21759 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21760 this.trigger = this.wrap.createChild(this.triggerConfig ||
21761 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21762 if(this.hideTrigger){
21763 this.trigger.setDisplayed(false);
21765 this.initTrigger();
21767 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21772 initTrigger : function(){
21773 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21774 this.trigger.addClassOnOver('x-form-trigger-over');
21775 this.trigger.addClassOnClick('x-form-trigger-click');
21779 onDestroy : function(){
21781 this.trigger.removeAllListeners();
21782 this.trigger.remove();
21785 this.wrap.remove();
21787 Roo.form.TriggerField.superclass.onDestroy.call(this);
21791 onFocus : function(){
21792 Roo.form.TriggerField.superclass.onFocus.call(this);
21793 if(!this.mimicing){
21794 this.wrap.addClass('x-trigger-wrap-focus');
21795 this.mimicing = true;
21796 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21797 if(this.monitorTab){
21798 this.el.on("keydown", this.checkTab, this);
21804 checkTab : function(e){
21805 if(e.getKey() == e.TAB){
21806 this.triggerBlur();
21811 onBlur : function(){
21816 mimicBlur : function(e, t){
21817 if(!this.wrap.contains(t) && this.validateBlur()){
21818 this.triggerBlur();
21823 triggerBlur : function(){
21824 this.mimicing = false;
21825 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21826 if(this.monitorTab){
21827 this.el.un("keydown", this.checkTab, this);
21829 this.wrap.removeClass('x-trigger-wrap-focus');
21830 Roo.form.TriggerField.superclass.onBlur.call(this);
21834 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21835 validateBlur : function(e, t){
21840 onDisable : function(){
21841 Roo.form.TriggerField.superclass.onDisable.call(this);
21843 this.wrap.addClass('x-item-disabled');
21848 onEnable : function(){
21849 Roo.form.TriggerField.superclass.onEnable.call(this);
21851 this.wrap.removeClass('x-item-disabled');
21856 onShow : function(){
21857 var ae = this.getActionEl();
21860 ae.dom.style.display = '';
21861 ae.dom.style.visibility = 'visible';
21867 onHide : function(){
21868 var ae = this.getActionEl();
21869 ae.dom.style.display = 'none';
21873 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21874 * by an implementing function.
21876 * @param {EventObject} e
21878 onTriggerClick : Roo.emptyFn
21881 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21882 // to be extended by an implementing class. For an example of implementing this class, see the custom
21883 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21884 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21885 initComponent : function(){
21886 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21888 this.triggerConfig = {
21889 tag:'span', cls:'x-form-twin-triggers', cn:[
21890 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21891 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21895 getTrigger : function(index){
21896 return this.triggers[index];
21899 initTrigger : function(){
21900 var ts = this.trigger.select('.x-form-trigger', true);
21901 this.wrap.setStyle('overflow', 'hidden');
21902 var triggerField = this;
21903 ts.each(function(t, all, index){
21904 t.hide = function(){
21905 var w = triggerField.wrap.getWidth();
21906 this.dom.style.display = 'none';
21907 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21909 t.show = function(){
21910 var w = triggerField.wrap.getWidth();
21911 this.dom.style.display = '';
21912 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21914 var triggerIndex = 'Trigger'+(index+1);
21916 if(this['hide'+triggerIndex]){
21917 t.dom.style.display = 'none';
21919 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21920 t.addClassOnOver('x-form-trigger-over');
21921 t.addClassOnClick('x-form-trigger-click');
21923 this.triggers = ts.elements;
21926 onTrigger1Click : Roo.emptyFn,
21927 onTrigger2Click : Roo.emptyFn
21930 * Ext JS Library 1.1.1
21931 * Copyright(c) 2006-2007, Ext JS, LLC.
21933 * Originally Released Under LGPL - original licence link has changed is not relivant.
21936 * <script type="text/javascript">
21940 * @class Roo.form.TextArea
21941 * @extends Roo.form.TextField
21942 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21943 * support for auto-sizing.
21945 * Creates a new TextArea
21946 * @param {Object} config Configuration options
21948 Roo.form.TextArea = function(config){
21949 Roo.form.TextArea.superclass.constructor.call(this, config);
21950 // these are provided exchanges for backwards compat
21951 // minHeight/maxHeight were replaced by growMin/growMax to be
21952 // compatible with TextField growing config values
21953 if(this.minHeight !== undefined){
21954 this.growMin = this.minHeight;
21956 if(this.maxHeight !== undefined){
21957 this.growMax = this.maxHeight;
21961 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
21963 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
21967 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
21971 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
21972 * in the field (equivalent to setting overflow: hidden, defaults to false)
21974 preventScrollbars: false,
21976 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21977 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
21981 onRender : function(ct, position){
21983 this.defaultAutoCreate = {
21985 style:"width:300px;height:60px;",
21986 autocomplete: "off"
21989 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
21991 this.textSizeEl = Roo.DomHelper.append(document.body, {
21992 tag: "pre", cls: "x-form-grow-sizer"
21994 if(this.preventScrollbars){
21995 this.el.setStyle("overflow", "hidden");
21997 this.el.setHeight(this.growMin);
22001 onDestroy : function(){
22002 if(this.textSizeEl){
22003 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22005 Roo.form.TextArea.superclass.onDestroy.call(this);
22009 onKeyUp : function(e){
22010 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22016 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22017 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22019 autoSize : function(){
22020 if(!this.grow || !this.textSizeEl){
22024 var v = el.dom.value;
22025 var ts = this.textSizeEl;
22028 ts.appendChild(document.createTextNode(v));
22031 Roo.fly(ts).setWidth(this.el.getWidth());
22033 v = "  ";
22036 v = v.replace(/\n/g, '<p> </p>');
22038 v += " \n ";
22041 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22042 if(h != this.lastHeight){
22043 this.lastHeight = h;
22044 this.el.setHeight(h);
22045 this.fireEvent("autosize", this, h);
22050 * Ext JS Library 1.1.1
22051 * Copyright(c) 2006-2007, Ext JS, LLC.
22053 * Originally Released Under LGPL - original licence link has changed is not relivant.
22056 * <script type="text/javascript">
22061 * @class Roo.form.NumberField
22062 * @extends Roo.form.TextField
22063 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22065 * Creates a new NumberField
22066 * @param {Object} config Configuration options
22068 Roo.form.NumberField = function(config){
22069 Roo.form.NumberField.superclass.constructor.call(this, config);
22072 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22074 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22076 fieldClass: "x-form-field x-form-num-field",
22078 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22080 allowDecimals : true,
22082 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22084 decimalSeparator : ".",
22086 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22088 decimalPrecision : 2,
22090 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22092 allowNegative : true,
22094 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22096 minValue : Number.NEGATIVE_INFINITY,
22098 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22100 maxValue : Number.MAX_VALUE,
22102 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22104 minText : "The minimum value for this field is {0}",
22106 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22108 maxText : "The maximum value for this field is {0}",
22110 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22111 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22113 nanText : "{0} is not a valid number",
22116 initEvents : function(){
22117 Roo.form.NumberField.superclass.initEvents.call(this);
22118 var allowed = "0123456789";
22119 if(this.allowDecimals){
22120 allowed += this.decimalSeparator;
22122 if(this.allowNegative){
22125 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22126 var keyPress = function(e){
22127 var k = e.getKey();
22128 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22131 var c = e.getCharCode();
22132 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22136 this.el.on("keypress", keyPress, this);
22140 validateValue : function(value){
22141 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22144 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22147 var num = this.parseValue(value);
22149 this.markInvalid(String.format(this.nanText, value));
22152 if(num < this.minValue){
22153 this.markInvalid(String.format(this.minText, this.minValue));
22156 if(num > this.maxValue){
22157 this.markInvalid(String.format(this.maxText, this.maxValue));
22163 getValue : function(){
22164 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22168 parseValue : function(value){
22169 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22170 return isNaN(value) ? '' : value;
22174 fixPrecision : function(value){
22175 var nan = isNaN(value);
22176 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22177 return nan ? '' : value;
22179 return parseFloat(value).toFixed(this.decimalPrecision);
22182 setValue : function(v){
22183 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22187 decimalPrecisionFcn : function(v){
22188 return Math.floor(v);
22191 beforeBlur : function(){
22192 var v = this.parseValue(this.getRawValue());
22194 this.setValue(this.fixPrecision(v));
22199 * Ext JS Library 1.1.1
22200 * Copyright(c) 2006-2007, Ext JS, LLC.
22202 * Originally Released Under LGPL - original licence link has changed is not relivant.
22205 * <script type="text/javascript">
22209 * @class Roo.form.DateField
22210 * @extends Roo.form.TriggerField
22211 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22213 * Create a new DateField
22214 * @param {Object} config
22216 Roo.form.DateField = function(config){
22217 Roo.form.DateField.superclass.constructor.call(this, config);
22223 * Fires when a date is selected
22224 * @param {Roo.form.DateField} combo This combo box
22225 * @param {Date} date The date selected
22232 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22233 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22234 this.ddMatch = null;
22235 if(this.disabledDates){
22236 var dd = this.disabledDates;
22238 for(var i = 0; i < dd.length; i++){
22240 if(i != dd.length-1) re += "|";
22242 this.ddMatch = new RegExp(re + ")");
22246 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22248 * @cfg {String} format
22249 * The default date format string which can be overriden for localization support. The format must be
22250 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22254 * @cfg {String} altFormats
22255 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22256 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22258 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22260 * @cfg {Array} disabledDays
22261 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22263 disabledDays : null,
22265 * @cfg {String} disabledDaysText
22266 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22268 disabledDaysText : "Disabled",
22270 * @cfg {Array} disabledDates
22271 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22272 * expression so they are very powerful. Some examples:
22274 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22275 * <li>["03/08", "09/16"] would disable those days for every year</li>
22276 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22277 * <li>["03/../2006"] would disable every day in March 2006</li>
22278 * <li>["^03"] would disable every day in every March</li>
22280 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22281 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22283 disabledDates : null,
22285 * @cfg {String} disabledDatesText
22286 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22288 disabledDatesText : "Disabled",
22290 * @cfg {Date/String} minValue
22291 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22292 * valid format (defaults to null).
22296 * @cfg {Date/String} maxValue
22297 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22298 * valid format (defaults to null).
22302 * @cfg {String} minText
22303 * The error text to display when the date in the cell is before minValue (defaults to
22304 * 'The date in this field must be after {minValue}').
22306 minText : "The date in this field must be equal to or after {0}",
22308 * @cfg {String} maxText
22309 * The error text to display when the date in the cell is after maxValue (defaults to
22310 * 'The date in this field must be before {maxValue}').
22312 maxText : "The date in this field must be equal to or before {0}",
22314 * @cfg {String} invalidText
22315 * The error text to display when the date in the field is invalid (defaults to
22316 * '{value} is not a valid date - it must be in the format {format}').
22318 invalidText : "{0} is not a valid date - it must be in the format {1}",
22320 * @cfg {String} triggerClass
22321 * An additional CSS class used to style the trigger button. The trigger will always get the
22322 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22323 * which displays a calendar icon).
22325 triggerClass : 'x-form-date-trigger',
22329 * @cfg {bool} useIso
22330 * if enabled, then the date field will use a hidden field to store the
22331 * real value as iso formated date. default (false)
22335 * @cfg {String/Object} autoCreate
22336 * A DomHelper element spec, or true for a default element spec (defaults to
22337 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22340 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22343 hiddenField: false,
22345 onRender : function(ct, position)
22347 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22349 this.el.dom.removeAttribute('name');
22350 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22352 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22353 // prevent input submission
22354 this.hiddenName = this.name;
22361 validateValue : function(value)
22363 value = this.formatDate(value);
22364 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22367 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22370 var svalue = value;
22371 value = this.parseDate(value);
22373 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22376 var time = value.getTime();
22377 if(this.minValue && time < this.minValue.getTime()){
22378 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22381 if(this.maxValue && time > this.maxValue.getTime()){
22382 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22385 if(this.disabledDays){
22386 var day = value.getDay();
22387 for(var i = 0; i < this.disabledDays.length; i++) {
22388 if(day === this.disabledDays[i]){
22389 this.markInvalid(this.disabledDaysText);
22394 var fvalue = this.formatDate(value);
22395 if(this.ddMatch && this.ddMatch.test(fvalue)){
22396 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22403 // Provides logic to override the default TriggerField.validateBlur which just returns true
22404 validateBlur : function(){
22405 return !this.menu || !this.menu.isVisible();
22409 * Returns the current date value of the date field.
22410 * @return {Date} The date value
22412 getValue : function(){
22414 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22418 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22419 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22420 * (the default format used is "m/d/y").
22423 //All of these calls set the same date value (May 4, 2006)
22425 //Pass a date object:
22426 var dt = new Date('5/4/06');
22427 dateField.setValue(dt);
22429 //Pass a date string (default format):
22430 dateField.setValue('5/4/06');
22432 //Pass a date string (custom format):
22433 dateField.format = 'Y-m-d';
22434 dateField.setValue('2006-5-4');
22436 * @param {String/Date} date The date or valid date string
22438 setValue : function(date){
22439 if (this.hiddenField) {
22440 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22442 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22446 parseDate : function(value){
22447 if(!value || value instanceof Date){
22450 var v = Date.parseDate(value, this.format);
22451 if(!v && this.altFormats){
22452 if(!this.altFormatsArray){
22453 this.altFormatsArray = this.altFormats.split("|");
22455 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22456 v = Date.parseDate(value, this.altFormatsArray[i]);
22463 formatDate : function(date, fmt){
22464 return (!date || !(date instanceof Date)) ?
22465 date : date.dateFormat(fmt || this.format);
22470 select: function(m, d){
22472 this.fireEvent('select', this, d);
22474 show : function(){ // retain focus styling
22478 this.focus.defer(10, this);
22479 var ml = this.menuListeners;
22480 this.menu.un("select", ml.select, this);
22481 this.menu.un("show", ml.show, this);
22482 this.menu.un("hide", ml.hide, this);
22487 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22488 onTriggerClick : function(){
22492 if(this.menu == null){
22493 this.menu = new Roo.menu.DateMenu();
22495 Roo.apply(this.menu.picker, {
22496 showClear: this.allowBlank,
22497 minDate : this.minValue,
22498 maxDate : this.maxValue,
22499 disabledDatesRE : this.ddMatch,
22500 disabledDatesText : this.disabledDatesText,
22501 disabledDays : this.disabledDays,
22502 disabledDaysText : this.disabledDaysText,
22503 format : this.format,
22504 minText : String.format(this.minText, this.formatDate(this.minValue)),
22505 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22507 this.menu.on(Roo.apply({}, this.menuListeners, {
22510 this.menu.picker.setValue(this.getValue() || new Date());
22511 this.menu.show(this.el, "tl-bl?");
22514 beforeBlur : function(){
22515 var v = this.parseDate(this.getRawValue());
22521 /** @cfg {Boolean} grow @hide */
22522 /** @cfg {Number} growMin @hide */
22523 /** @cfg {Number} growMax @hide */
22530 * Ext JS Library 1.1.1
22531 * Copyright(c) 2006-2007, Ext JS, LLC.
22533 * Originally Released Under LGPL - original licence link has changed is not relivant.
22536 * <script type="text/javascript">
22541 * @class Roo.form.ComboBox
22542 * @extends Roo.form.TriggerField
22543 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22545 * Create a new ComboBox.
22546 * @param {Object} config Configuration options
22548 Roo.form.ComboBox = function(config){
22549 Roo.form.ComboBox.superclass.constructor.call(this, config);
22553 * Fires when the dropdown list is expanded
22554 * @param {Roo.form.ComboBox} combo This combo box
22559 * Fires when the dropdown list is collapsed
22560 * @param {Roo.form.ComboBox} combo This combo box
22564 * @event beforeselect
22565 * Fires before a list item is selected. Return false to cancel the selection.
22566 * @param {Roo.form.ComboBox} combo This combo box
22567 * @param {Roo.data.Record} record The data record returned from the underlying store
22568 * @param {Number} index The index of the selected item in the dropdown list
22570 'beforeselect' : true,
22573 * Fires when a list item is selected
22574 * @param {Roo.form.ComboBox} combo This combo box
22575 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22576 * @param {Number} index The index of the selected item in the dropdown list
22580 * @event beforequery
22581 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22582 * The event object passed has these properties:
22583 * @param {Roo.form.ComboBox} combo This combo box
22584 * @param {String} query The query
22585 * @param {Boolean} forceAll true to force "all" query
22586 * @param {Boolean} cancel true to cancel the query
22587 * @param {Object} e The query event object
22589 'beforequery': true,
22592 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22593 * @param {Roo.form.ComboBox} combo This combo box
22598 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22599 * @param {Roo.form.ComboBox} combo This combo box
22600 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22606 if(this.transform){
22607 this.allowDomMove = false;
22608 var s = Roo.getDom(this.transform);
22609 if(!this.hiddenName){
22610 this.hiddenName = s.name;
22613 this.mode = 'local';
22614 var d = [], opts = s.options;
22615 for(var i = 0, len = opts.length;i < len; i++){
22617 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22619 this.value = value;
22621 d.push([value, o.text]);
22623 this.store = new Roo.data.SimpleStore({
22625 fields: ['value', 'text'],
22628 this.valueField = 'value';
22629 this.displayField = 'text';
22631 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22632 if(!this.lazyRender){
22633 this.target = true;
22634 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22635 s.parentNode.removeChild(s); // remove it
22636 this.render(this.el.parentNode);
22638 s.parentNode.removeChild(s); // remove it
22643 this.store = Roo.factory(this.store, Roo.data);
22646 this.selectedIndex = -1;
22647 if(this.mode == 'local'){
22648 if(config.queryDelay === undefined){
22649 this.queryDelay = 10;
22651 if(config.minChars === undefined){
22657 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22659 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22662 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22663 * rendering into an Roo.Editor, defaults to false)
22666 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22667 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22670 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22673 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22674 * the dropdown list (defaults to undefined, with no header element)
22678 * @cfg {String/Roo.Template} tpl The template to use to render the output
22682 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22684 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22686 listWidth: undefined,
22688 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22689 * mode = 'remote' or 'text' if mode = 'local')
22691 displayField: undefined,
22693 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22694 * mode = 'remote' or 'value' if mode = 'local').
22695 * Note: use of a valueField requires the user make a selection
22696 * in order for a value to be mapped.
22698 valueField: undefined,
22700 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22701 * field's data value (defaults to the underlying DOM element's name)
22703 hiddenName: undefined,
22705 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22709 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22711 selectedClass: 'x-combo-selected',
22713 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22714 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22715 * which displays a downward arrow icon).
22717 triggerClass : 'x-form-arrow-trigger',
22719 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22723 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22724 * anchor positions (defaults to 'tl-bl')
22726 listAlign: 'tl-bl?',
22728 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22732 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22733 * query specified by the allQuery config option (defaults to 'query')
22735 triggerAction: 'query',
22737 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22738 * (defaults to 4, does not apply if editable = false)
22742 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22743 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22747 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22748 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22752 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22753 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22757 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22758 * when editable = true (defaults to false)
22760 selectOnFocus:false,
22762 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22764 queryParam: 'query',
22766 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22767 * when mode = 'remote' (defaults to 'Loading...')
22769 loadingText: 'Loading...',
22771 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22775 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22779 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22780 * traditional select (defaults to true)
22784 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22788 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22792 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22793 * listWidth has a higher value)
22797 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22798 * allow the user to set arbitrary text into the field (defaults to false)
22800 forceSelection:false,
22802 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22803 * if typeAhead = true (defaults to 250)
22805 typeAheadDelay : 250,
22807 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22808 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22810 valueNotFoundText : undefined,
22812 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22814 blockFocus : false,
22817 * @cfg {Boolean} disableClear Disable showing of clear button.
22819 disableClear : false,
22821 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22823 alwaysQuery : false,
22831 onRender : function(ct, position){
22832 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22833 if(this.hiddenName){
22834 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22836 this.hiddenField.value =
22837 this.hiddenValue !== undefined ? this.hiddenValue :
22838 this.value !== undefined ? this.value : '';
22840 // prevent input submission
22841 this.el.dom.removeAttribute('name');
22844 this.el.dom.setAttribute('autocomplete', 'off');
22847 var cls = 'x-combo-list';
22849 this.list = new Roo.Layer({
22850 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22853 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22854 this.list.setWidth(lw);
22855 this.list.swallowEvent('mousewheel');
22856 this.assetHeight = 0;
22859 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22860 this.assetHeight += this.header.getHeight();
22863 this.innerList = this.list.createChild({cls:cls+'-inner'});
22864 this.innerList.on('mouseover', this.onViewOver, this);
22865 this.innerList.on('mousemove', this.onViewMove, this);
22866 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22868 if(this.allowBlank && !this.pageSize && !this.disableClear){
22869 this.footer = this.list.createChild({cls:cls+'-ft'});
22870 this.pageTb = new Roo.Toolbar(this.footer);
22874 this.footer = this.list.createChild({cls:cls+'-ft'});
22875 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22876 {pageSize: this.pageSize});
22880 if (this.pageTb && this.allowBlank && !this.disableClear) {
22882 this.pageTb.add(new Roo.Toolbar.Fill(), {
22883 cls: 'x-btn-icon x-btn-clear',
22885 handler: function()
22888 _this.clearValue();
22889 _this.onSelect(false, -1);
22894 this.assetHeight += this.footer.getHeight();
22899 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22902 this.view = new Roo.View(this.innerList, this.tpl, {
22903 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22906 this.view.on('click', this.onViewClick, this);
22908 this.store.on('beforeload', this.onBeforeLoad, this);
22909 this.store.on('load', this.onLoad, this);
22910 this.store.on('loadexception', this.collapse, this);
22912 if(this.resizable){
22913 this.resizer = new Roo.Resizable(this.list, {
22914 pinned:true, handles:'se'
22916 this.resizer.on('resize', function(r, w, h){
22917 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22918 this.listWidth = w;
22919 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22920 this.restrictHeight();
22922 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22924 if(!this.editable){
22925 this.editable = true;
22926 this.setEditable(false);
22930 if (typeof(this.events.add.listeners) != 'undefined') {
22932 this.addicon = this.wrap.createChild(
22933 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22935 this.addicon.on('click', function(e) {
22936 this.fireEvent('add', this);
22939 if (typeof(this.events.edit.listeners) != 'undefined') {
22941 this.editicon = this.wrap.createChild(
22942 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22943 if (this.addicon) {
22944 this.editicon.setStyle('margin-left', '40px');
22946 this.editicon.on('click', function(e) {
22948 // we fire even if inothing is selected..
22949 this.fireEvent('edit', this, this.lastData );
22959 initEvents : function(){
22960 Roo.form.ComboBox.superclass.initEvents.call(this);
22962 this.keyNav = new Roo.KeyNav(this.el, {
22963 "up" : function(e){
22964 this.inKeyMode = true;
22968 "down" : function(e){
22969 if(!this.isExpanded()){
22970 this.onTriggerClick();
22972 this.inKeyMode = true;
22977 "enter" : function(e){
22978 this.onViewClick();
22982 "esc" : function(e){
22986 "tab" : function(e){
22987 this.onViewClick(false);
22993 doRelay : function(foo, bar, hname){
22994 if(hname == 'down' || this.scope.isExpanded()){
22995 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23002 this.queryDelay = Math.max(this.queryDelay || 10,
23003 this.mode == 'local' ? 10 : 250);
23004 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23005 if(this.typeAhead){
23006 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23008 if(this.editable !== false){
23009 this.el.on("keyup", this.onKeyUp, this);
23011 if(this.forceSelection){
23012 this.on('blur', this.doForce, this);
23016 onDestroy : function(){
23018 this.view.setStore(null);
23019 this.view.el.removeAllListeners();
23020 this.view.el.remove();
23021 this.view.purgeListeners();
23024 this.list.destroy();
23027 this.store.un('beforeload', this.onBeforeLoad, this);
23028 this.store.un('load', this.onLoad, this);
23029 this.store.un('loadexception', this.collapse, this);
23031 Roo.form.ComboBox.superclass.onDestroy.call(this);
23035 fireKey : function(e){
23036 if(e.isNavKeyPress() && !this.list.isVisible()){
23037 this.fireEvent("specialkey", this, e);
23042 onResize: function(w, h){
23043 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23045 if(typeof w != 'number'){
23046 // we do not handle it!?!?
23049 var tw = this.trigger.getWidth();
23050 tw += this.addicon ? this.addicon.getWidth() : 0;
23051 tw += this.editicon ? this.editicon.getWidth() : 0;
23053 this.el.setWidth( this.adjustWidth('input', x));
23055 this.trigger.setStyle('left', x+'px');
23057 if(this.list && this.listWidth === undefined){
23058 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23059 this.list.setWidth(lw);
23060 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23068 * Allow or prevent the user from directly editing the field text. If false is passed,
23069 * the user will only be able to select from the items defined in the dropdown list. This method
23070 * is the runtime equivalent of setting the 'editable' config option at config time.
23071 * @param {Boolean} value True to allow the user to directly edit the field text
23073 setEditable : function(value){
23074 if(value == this.editable){
23077 this.editable = value;
23079 this.el.dom.setAttribute('readOnly', true);
23080 this.el.on('mousedown', this.onTriggerClick, this);
23081 this.el.addClass('x-combo-noedit');
23083 this.el.dom.setAttribute('readOnly', false);
23084 this.el.un('mousedown', this.onTriggerClick, this);
23085 this.el.removeClass('x-combo-noedit');
23090 onBeforeLoad : function(){
23091 if(!this.hasFocus){
23094 this.innerList.update(this.loadingText ?
23095 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23096 this.restrictHeight();
23097 this.selectedIndex = -1;
23101 onLoad : function(){
23102 if(!this.hasFocus){
23105 if(this.store.getCount() > 0){
23107 this.restrictHeight();
23108 if(this.lastQuery == this.allQuery){
23110 this.el.dom.select();
23112 if(!this.selectByValue(this.value, true)){
23113 this.select(0, true);
23117 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23118 this.taTask.delay(this.typeAheadDelay);
23122 this.onEmptyResults();
23128 onTypeAhead : function(){
23129 if(this.store.getCount() > 0){
23130 var r = this.store.getAt(0);
23131 var newValue = r.data[this.displayField];
23132 var len = newValue.length;
23133 var selStart = this.getRawValue().length;
23134 if(selStart != len){
23135 this.setRawValue(newValue);
23136 this.selectText(selStart, newValue.length);
23142 onSelect : function(record, index){
23143 if(this.fireEvent('beforeselect', this, record, index) !== false){
23144 this.setFromData(index > -1 ? record.data : false);
23146 this.fireEvent('select', this, record, index);
23151 * Returns the currently selected field value or empty string if no value is set.
23152 * @return {String} value The selected value
23154 getValue : function(){
23155 if(this.valueField){
23156 return typeof this.value != 'undefined' ? this.value : '';
23158 return Roo.form.ComboBox.superclass.getValue.call(this);
23163 * Clears any text/value currently set in the field
23165 clearValue : function(){
23166 if(this.hiddenField){
23167 this.hiddenField.value = '';
23170 this.setRawValue('');
23171 this.lastSelectionText = '';
23172 this.applyEmptyText();
23176 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23177 * will be displayed in the field. If the value does not match the data value of an existing item,
23178 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23179 * Otherwise the field will be blank (although the value will still be set).
23180 * @param {String} value The value to match
23182 setValue : function(v){
23184 if(this.valueField){
23185 var r = this.findRecord(this.valueField, v);
23187 text = r.data[this.displayField];
23188 }else if(this.valueNotFoundText !== undefined){
23189 text = this.valueNotFoundText;
23192 this.lastSelectionText = text;
23193 if(this.hiddenField){
23194 this.hiddenField.value = v;
23196 Roo.form.ComboBox.superclass.setValue.call(this, text);
23200 * @property {Object} the last set data for the element
23205 * Sets the value of the field based on a object which is related to the record format for the store.
23206 * @param {Object} value the value to set as. or false on reset?
23208 setFromData : function(o){
23209 var dv = ''; // display value
23210 var vv = ''; // value value..
23212 if (this.displayField) {
23213 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23215 // this is an error condition!!!
23216 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23219 if(this.valueField){
23220 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23222 if(this.hiddenField){
23223 this.hiddenField.value = vv;
23225 this.lastSelectionText = dv;
23226 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23230 // no hidden field.. - we store the value in 'value', but still display
23231 // display field!!!!
23232 this.lastSelectionText = dv;
23233 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23239 reset : function(){
23240 // overridden so that last data is reset..
23241 this.setValue(this.originalValue);
23242 this.clearInvalid();
23243 this.lastData = false;
23246 findRecord : function(prop, value){
23248 if(this.store.getCount() > 0){
23249 this.store.each(function(r){
23250 if(r.data[prop] == value){
23260 onViewMove : function(e, t){
23261 this.inKeyMode = false;
23265 onViewOver : function(e, t){
23266 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23269 var item = this.view.findItemFromChild(t);
23271 var index = this.view.indexOf(item);
23272 this.select(index, false);
23277 onViewClick : function(doFocus){
23278 var index = this.view.getSelectedIndexes()[0];
23279 var r = this.store.getAt(index);
23281 this.onSelect(r, index);
23283 if(doFocus !== false && !this.blockFocus){
23289 restrictHeight : function(){
23290 this.innerList.dom.style.height = '';
23291 var inner = this.innerList.dom;
23292 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23293 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23294 this.list.beginUpdate();
23295 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23296 this.list.alignTo(this.el, this.listAlign);
23297 this.list.endUpdate();
23301 onEmptyResults : function(){
23306 * Returns true if the dropdown list is expanded, else false.
23308 isExpanded : function(){
23309 return this.list.isVisible();
23313 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23314 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23315 * @param {String} value The data value of the item to select
23316 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23317 * selected item if it is not currently in view (defaults to true)
23318 * @return {Boolean} True if the value matched an item in the list, else false
23320 selectByValue : function(v, scrollIntoView){
23321 if(v !== undefined && v !== null){
23322 var r = this.findRecord(this.valueField || this.displayField, v);
23324 this.select(this.store.indexOf(r), scrollIntoView);
23332 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23333 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23334 * @param {Number} index The zero-based index of the list item to select
23335 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23336 * selected item if it is not currently in view (defaults to true)
23338 select : function(index, scrollIntoView){
23339 this.selectedIndex = index;
23340 this.view.select(index);
23341 if(scrollIntoView !== false){
23342 var el = this.view.getNode(index);
23344 this.innerList.scrollChildIntoView(el, false);
23350 selectNext : function(){
23351 var ct = this.store.getCount();
23353 if(this.selectedIndex == -1){
23355 }else if(this.selectedIndex < ct-1){
23356 this.select(this.selectedIndex+1);
23362 selectPrev : function(){
23363 var ct = this.store.getCount();
23365 if(this.selectedIndex == -1){
23367 }else if(this.selectedIndex != 0){
23368 this.select(this.selectedIndex-1);
23374 onKeyUp : function(e){
23375 if(this.editable !== false && !e.isSpecialKey()){
23376 this.lastKey = e.getKey();
23377 this.dqTask.delay(this.queryDelay);
23382 validateBlur : function(){
23383 return !this.list || !this.list.isVisible();
23387 initQuery : function(){
23388 this.doQuery(this.getRawValue());
23392 doForce : function(){
23393 if(this.el.dom.value.length > 0){
23394 this.el.dom.value =
23395 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23396 this.applyEmptyText();
23401 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23402 * query allowing the query action to be canceled if needed.
23403 * @param {String} query The SQL query to execute
23404 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23405 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23406 * saved in the current store (defaults to false)
23408 doQuery : function(q, forceAll){
23409 if(q === undefined || q === null){
23414 forceAll: forceAll,
23418 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23422 forceAll = qe.forceAll;
23423 if(forceAll === true || (q.length >= this.minChars)){
23424 if(this.lastQuery != q || this.alwaysQuery){
23425 this.lastQuery = q;
23426 if(this.mode == 'local'){
23427 this.selectedIndex = -1;
23429 this.store.clearFilter();
23431 this.store.filter(this.displayField, q);
23435 this.store.baseParams[this.queryParam] = q;
23437 params: this.getParams(q)
23442 this.selectedIndex = -1;
23449 getParams : function(q){
23451 //p[this.queryParam] = q;
23454 p.limit = this.pageSize;
23460 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23462 collapse : function(){
23463 if(!this.isExpanded()){
23467 Roo.get(document).un('mousedown', this.collapseIf, this);
23468 Roo.get(document).un('mousewheel', this.collapseIf, this);
23469 if (!this.editable) {
23470 Roo.get(document).un('keydown', this.listKeyPress, this);
23472 this.fireEvent('collapse', this);
23476 collapseIf : function(e){
23477 if(!e.within(this.wrap) && !e.within(this.list)){
23483 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23485 expand : function(){
23486 if(this.isExpanded() || !this.hasFocus){
23489 this.list.alignTo(this.el, this.listAlign);
23491 Roo.get(document).on('mousedown', this.collapseIf, this);
23492 Roo.get(document).on('mousewheel', this.collapseIf, this);
23493 if (!this.editable) {
23494 Roo.get(document).on('keydown', this.listKeyPress, this);
23497 this.fireEvent('expand', this);
23501 // Implements the default empty TriggerField.onTriggerClick function
23502 onTriggerClick : function(){
23506 if(this.isExpanded()){
23508 if (!this.blockFocus) {
23513 this.hasFocus = true;
23514 if(this.triggerAction == 'all') {
23515 this.doQuery(this.allQuery, true);
23517 this.doQuery(this.getRawValue());
23519 if (!this.blockFocus) {
23524 listKeyPress : function(e)
23526 //Roo.log('listkeypress');
23527 // scroll to first matching element based on key pres..
23528 if (e.isSpecialKey()) {
23531 var k = String.fromCharCode(e.getKey()).toUpperCase();
23534 var csel = this.view.getSelectedNodes();
23535 var cselitem = false;
23537 var ix = this.view.indexOf(csel[0]);
23538 cselitem = this.store.getAt(ix);
23539 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23545 this.store.each(function(v) {
23547 // start at existing selection.
23548 if (cselitem.id == v.id) {
23554 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23555 match = this.store.indexOf(v);
23560 if (match === false) {
23561 return true; // no more action?
23564 this.view.select(match);
23565 var sn = Roo.get(this.view.getSelectedNodes()[0])
23566 sn.scrollIntoView(sn.dom.parentNode, false);
23570 * @cfg {Boolean} grow
23574 * @cfg {Number} growMin
23578 * @cfg {Number} growMax
23587 * Ext JS Library 1.1.1
23588 * Copyright(c) 2006-2007, Ext JS, LLC.
23590 * Originally Released Under LGPL - original licence link has changed is not relivant.
23593 * <script type="text/javascript">
23596 * @class Roo.form.Checkbox
23597 * @extends Roo.form.Field
23598 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23600 * Creates a new Checkbox
23601 * @param {Object} config Configuration options
23603 Roo.form.Checkbox = function(config){
23604 Roo.form.Checkbox.superclass.constructor.call(this, config);
23608 * Fires when the checkbox is checked or unchecked.
23609 * @param {Roo.form.Checkbox} this This checkbox
23610 * @param {Boolean} checked The new checked value
23616 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23618 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23620 focusClass : undefined,
23622 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23624 fieldClass: "x-form-field",
23626 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23630 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23631 * {tag: "input", type: "checkbox", autocomplete: "off"})
23633 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23635 * @cfg {String} boxLabel The text that appears beside the checkbox
23639 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23643 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23645 valueOff: '0', // value when not checked..
23647 actionMode : 'viewEl',
23650 itemCls : 'x-menu-check-item x-form-item',
23651 groupClass : 'x-menu-group-item',
23652 inputType : 'hidden',
23655 inSetChecked: false, // check that we are not calling self...
23657 inputElement: false, // real input element?
23658 basedOn: false, // ????
23660 isFormField: true, // not sure where this is needed!!!!
23662 onResize : function(){
23663 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23664 if(!this.boxLabel){
23665 this.el.alignTo(this.wrap, 'c-c');
23669 initEvents : function(){
23670 Roo.form.Checkbox.superclass.initEvents.call(this);
23671 this.el.on("click", this.onClick, this);
23672 this.el.on("change", this.onClick, this);
23676 getResizeEl : function(){
23680 getPositionEl : function(){
23685 onRender : function(ct, position){
23686 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23688 if(this.inputValue !== undefined){
23689 this.el.dom.value = this.inputValue;
23692 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23693 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23694 var viewEl = this.wrap.createChild({
23695 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23696 this.viewEl = viewEl;
23697 this.wrap.on('click', this.onClick, this);
23699 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23700 this.el.on('propertychange', this.setFromHidden, this); //ie
23705 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23706 // viewEl.on('click', this.onClick, this);
23708 //if(this.checked){
23709 this.setChecked(this.checked);
23711 //this.checked = this.el.dom;
23717 initValue : Roo.emptyFn,
23720 * Returns the checked state of the checkbox.
23721 * @return {Boolean} True if checked, else false
23723 getValue : function(){
23725 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23727 return this.valueOff;
23732 onClick : function(){
23733 this.setChecked(!this.checked);
23735 //if(this.el.dom.checked != this.checked){
23736 // this.setValue(this.el.dom.checked);
23741 * Sets the checked state of the checkbox.
23742 * On is always based on a string comparison between inputValue and the param.
23743 * @param {Boolean/String} value - the value to set
23744 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23746 setValue : function(v,suppressEvent){
23749 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23750 //if(this.el && this.el.dom){
23751 // this.el.dom.checked = this.checked;
23752 // this.el.dom.defaultChecked = this.checked;
23754 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23755 //this.fireEvent("check", this, this.checked);
23758 setChecked : function(state,suppressEvent)
23760 if (this.inSetChecked) {
23761 this.checked = state;
23767 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23769 this.checked = state;
23770 if(suppressEvent !== true){
23771 this.fireEvent('check', this, state);
23773 this.inSetChecked = true;
23774 this.el.dom.value = state ? this.inputValue : this.valueOff;
23775 this.inSetChecked = false;
23778 // handle setting of hidden value by some other method!!?!?
23779 setFromHidden: function()
23784 //console.log("SET FROM HIDDEN");
23785 //alert('setFrom hidden');
23786 this.setValue(this.el.dom.value);
23789 onDestroy : function()
23792 Roo.get(this.viewEl).remove();
23795 Roo.form.Checkbox.superclass.onDestroy.call(this);
23800 * Ext JS Library 1.1.1
23801 * Copyright(c) 2006-2007, Ext JS, LLC.
23803 * Originally Released Under LGPL - original licence link has changed is not relivant.
23806 * <script type="text/javascript">
23810 * @class Roo.form.Radio
23811 * @extends Roo.form.Checkbox
23812 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23813 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23815 * Creates a new Radio
23816 * @param {Object} config Configuration options
23818 Roo.form.Radio = function(){
23819 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23821 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23822 inputType: 'radio',
23825 * If this radio is part of a group, it will return the selected value
23828 getGroupValue : function(){
23829 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23831 });//<script type="text/javascript">
23834 * Ext JS Library 1.1.1
23835 * Copyright(c) 2006-2007, Ext JS, LLC.
23836 * licensing@extjs.com
23838 * http://www.extjs.com/license
23844 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23845 * - IE ? - no idea how much works there.
23853 * @class Ext.form.HtmlEditor
23854 * @extends Ext.form.Field
23855 * Provides a lightweight HTML Editor component.
23856 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23858 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23859 * supported by this editor.</b><br/><br/>
23860 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23861 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23863 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23865 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23869 * @cfg {String} createLinkText The default text for the create link prompt
23871 createLinkText : 'Please enter the URL for the link:',
23873 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23875 defaultLinkValue : 'http:/'+'/',
23881 // private properties
23882 validationEvent : false,
23884 initialized : false,
23886 sourceEditMode : false,
23887 onFocus : Roo.emptyFn,
23889 hideMode:'offsets',
23890 defaultAutoCreate : {
23892 style:"width:500px;height:300px;",
23893 autocomplete: "off"
23897 initComponent : function(){
23900 * @event initialize
23901 * Fires when the editor is fully initialized (including the iframe)
23902 * @param {HtmlEditor} this
23907 * Fires when the editor is first receives the focus. Any insertion must wait
23908 * until after this event.
23909 * @param {HtmlEditor} this
23913 * @event beforesync
23914 * Fires before the textarea is updated with content from the editor iframe. Return false
23915 * to cancel the sync.
23916 * @param {HtmlEditor} this
23917 * @param {String} html
23921 * @event beforepush
23922 * Fires before the iframe editor is updated with content from the textarea. Return false
23923 * to cancel the push.
23924 * @param {HtmlEditor} this
23925 * @param {String} html
23930 * Fires when the textarea is updated with content from the editor iframe.
23931 * @param {HtmlEditor} this
23932 * @param {String} html
23937 * Fires when the iframe editor is updated with content from the textarea.
23938 * @param {HtmlEditor} this
23939 * @param {String} html
23943 * @event editmodechange
23944 * Fires when the editor switches edit modes
23945 * @param {HtmlEditor} this
23946 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23948 editmodechange: true,
23950 * @event editorevent
23951 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23952 * @param {HtmlEditor} this
23959 * Protected method that will not generally be called directly. It
23960 * is called when the editor creates its toolbar. Override this method if you need to
23961 * add custom toolbar buttons.
23962 * @param {HtmlEditor} editor
23964 createToolbar : function(editor){
23965 if (!editor.toolbars || !editor.toolbars.length) {
23966 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
23969 for (var i =0 ; i < editor.toolbars.length;i++) {
23970 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
23971 editor.toolbars[i].init(editor);
23978 * Protected method that will not generally be called directly. It
23979 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23980 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23982 getDocMarkup : function(){
23983 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
23987 onRender : function(ct, position){
23988 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
23989 this.el.dom.style.border = '0 none';
23990 this.el.dom.setAttribute('tabIndex', -1);
23991 this.el.addClass('x-hidden');
23992 if(Roo.isIE){ // fix IE 1px bogus margin
23993 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
23995 this.wrap = this.el.wrap({
23996 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
23999 this.frameId = Roo.id();
24000 this.createToolbar(this);
24007 var iframe = this.wrap.createChild({
24010 name: this.frameId,
24011 frameBorder : 'no',
24012 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24015 // console.log(iframe);
24016 //this.wrap.dom.appendChild(iframe);
24018 this.iframe = iframe.dom;
24020 this.assignDocWin();
24022 this.doc.designMode = 'on';
24025 this.doc.write(this.getDocMarkup());
24029 var task = { // must defer to wait for browser to be ready
24031 //console.log("run task?" + this.doc.readyState);
24032 this.assignDocWin();
24033 if(this.doc.body || this.doc.readyState == 'complete'){
24035 this.doc.designMode="on";
24039 Roo.TaskMgr.stop(task);
24040 this.initEditor.defer(10, this);
24047 Roo.TaskMgr.start(task);
24050 this.setSize(this.el.getSize());
24055 onResize : function(w, h){
24056 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24057 if(this.el && this.iframe){
24058 if(typeof w == 'number'){
24059 var aw = w - this.wrap.getFrameWidth('lr');
24060 this.el.setWidth(this.adjustWidth('textarea', aw));
24061 this.iframe.style.width = aw + 'px';
24063 if(typeof h == 'number'){
24065 for (var i =0; i < this.toolbars.length;i++) {
24066 // fixme - ask toolbars for heights?
24067 tbh += this.toolbars[i].tb.el.getHeight();
24073 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24074 this.el.setHeight(this.adjustWidth('textarea', ah));
24075 this.iframe.style.height = ah + 'px';
24077 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24084 * Toggles the editor between standard and source edit mode.
24085 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24087 toggleSourceEdit : function(sourceEditMode){
24089 this.sourceEditMode = sourceEditMode === true;
24091 if(this.sourceEditMode){
24094 this.iframe.className = 'x-hidden';
24095 this.el.removeClass('x-hidden');
24096 this.el.dom.removeAttribute('tabIndex');
24101 this.iframe.className = '';
24102 this.el.addClass('x-hidden');
24103 this.el.dom.setAttribute('tabIndex', -1);
24106 this.setSize(this.wrap.getSize());
24107 this.fireEvent('editmodechange', this, this.sourceEditMode);
24110 // private used internally
24111 createLink : function(){
24112 var url = prompt(this.createLinkText, this.defaultLinkValue);
24113 if(url && url != 'http:/'+'/'){
24114 this.relayCmd('createlink', url);
24118 // private (for BoxComponent)
24119 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24121 // private (for BoxComponent)
24122 getResizeEl : function(){
24126 // private (for BoxComponent)
24127 getPositionEl : function(){
24132 initEvents : function(){
24133 this.originalValue = this.getValue();
24137 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24140 markInvalid : Roo.emptyFn,
24142 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24145 clearInvalid : Roo.emptyFn,
24147 setValue : function(v){
24148 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24153 * Protected method that will not generally be called directly. If you need/want
24154 * custom HTML cleanup, this is the method you should override.
24155 * @param {String} html The HTML to be cleaned
24156 * return {String} The cleaned HTML
24158 cleanHtml : function(html){
24159 html = String(html);
24160 if(html.length > 5){
24161 if(Roo.isSafari){ // strip safari nonsense
24162 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24165 if(html == ' '){
24172 * Protected method that will not generally be called directly. Syncs the contents
24173 * of the editor iframe with the textarea.
24175 syncValue : function(){
24176 if(this.initialized){
24177 var bd = (this.doc.body || this.doc.documentElement);
24178 var html = bd.innerHTML;
24180 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24181 var m = bs.match(/text-align:(.*?);/i);
24183 html = '<div style="'+m[0]+'">' + html + '</div>';
24186 html = this.cleanHtml(html);
24187 if(this.fireEvent('beforesync', this, html) !== false){
24188 this.el.dom.value = html;
24189 this.fireEvent('sync', this, html);
24195 * Protected method that will not generally be called directly. Pushes the value of the textarea
24196 * into the iframe editor.
24198 pushValue : function(){
24199 if(this.initialized){
24200 var v = this.el.dom.value;
24204 if(this.fireEvent('beforepush', this, v) !== false){
24205 (this.doc.body || this.doc.documentElement).innerHTML = v;
24206 this.fireEvent('push', this, v);
24212 deferFocus : function(){
24213 this.focus.defer(10, this);
24217 focus : function(){
24218 if(this.win && !this.sourceEditMode){
24225 assignDocWin: function()
24227 var iframe = this.iframe;
24230 this.doc = iframe.contentWindow.document;
24231 this.win = iframe.contentWindow;
24233 if (!Roo.get(this.frameId)) {
24236 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24237 this.win = Roo.get(this.frameId).dom.contentWindow;
24242 initEditor : function(){
24243 //console.log("INIT EDITOR");
24244 this.assignDocWin();
24248 this.doc.designMode="on";
24250 this.doc.write(this.getDocMarkup());
24253 var dbody = (this.doc.body || this.doc.documentElement);
24254 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24255 // this copies styles from the containing element into thsi one..
24256 // not sure why we need all of this..
24257 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24258 ss['background-attachment'] = 'fixed'; // w3c
24259 dbody.bgProperties = 'fixed'; // ie
24260 Roo.DomHelper.applyStyles(dbody, ss);
24261 Roo.EventManager.on(this.doc, {
24262 'mousedown': this.onEditorEvent,
24263 'dblclick': this.onEditorEvent,
24264 'click': this.onEditorEvent,
24265 'keyup': this.onEditorEvent,
24270 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24272 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24273 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24275 this.initialized = true;
24277 this.fireEvent('initialize', this);
24282 onDestroy : function(){
24288 for (var i =0; i < this.toolbars.length;i++) {
24289 // fixme - ask toolbars for heights?
24290 this.toolbars[i].onDestroy();
24293 this.wrap.dom.innerHTML = '';
24294 this.wrap.remove();
24299 onFirstFocus : function(){
24301 this.assignDocWin();
24304 this.activated = true;
24305 for (var i =0; i < this.toolbars.length;i++) {
24306 this.toolbars[i].onFirstFocus();
24309 if(Roo.isGecko){ // prevent silly gecko errors
24311 var s = this.win.getSelection();
24312 if(!s.focusNode || s.focusNode.nodeType != 3){
24313 var r = s.getRangeAt(0);
24314 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24319 this.execCmd('useCSS', true);
24320 this.execCmd('styleWithCSS', false);
24323 this.fireEvent('activate', this);
24327 adjustFont: function(btn){
24328 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24329 //if(Roo.isSafari){ // safari
24332 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24333 if(Roo.isSafari){ // safari
24334 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24335 v = (v < 10) ? 10 : v;
24336 v = (v > 48) ? 48 : v;
24337 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24342 v = Math.max(1, v+adjust);
24344 this.execCmd('FontSize', v );
24347 onEditorEvent : function(e){
24348 this.fireEvent('editorevent', this, e);
24349 // this.updateToolbar();
24353 insertTag : function(tg)
24355 // could be a bit smarter... -> wrap the current selected tRoo..
24357 this.execCmd("formatblock", tg);
24361 insertText : function(txt)
24365 range = this.createRange();
24366 range.deleteContents();
24367 //alert(Sender.getAttribute('label'));
24369 range.insertNode(this.doc.createTextNode(txt));
24373 relayBtnCmd : function(btn){
24374 this.relayCmd(btn.cmd);
24378 * Executes a Midas editor command on the editor document and performs necessary focus and
24379 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24380 * @param {String} cmd The Midas command
24381 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24383 relayCmd : function(cmd, value){
24385 this.execCmd(cmd, value);
24386 this.fireEvent('editorevent', this);
24387 //this.updateToolbar();
24392 * Executes a Midas editor command directly on the editor document.
24393 * For visual commands, you should use {@link #relayCmd} instead.
24394 * <b>This should only be called after the editor is initialized.</b>
24395 * @param {String} cmd The Midas command
24396 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24398 execCmd : function(cmd, value){
24399 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24405 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24407 * @param {String} text
24409 insertAtCursor : function(text){
24410 if(!this.activated){
24415 var r = this.doc.selection.createRange();
24422 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24424 this.execCmd('InsertHTML', text);
24429 mozKeyPress : function(e){
24431 var c = e.getCharCode(), cmd;
24434 c = String.fromCharCode(c).toLowerCase();
24445 this.cleanUpPaste.defer(100, this);
24453 e.preventDefault();
24461 fixKeys : function(){ // load time branching for fastest keydown performance
24463 return function(e){
24464 var k = e.getKey(), r;
24467 r = this.doc.selection.createRange();
24470 r.pasteHTML('    ');
24477 r = this.doc.selection.createRange();
24479 var target = r.parentElement();
24480 if(!target || target.tagName.toLowerCase() != 'li'){
24482 r.pasteHTML('<br />');
24488 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24489 this.cleanUpPaste.defer(100, this);
24495 }else if(Roo.isOpera){
24496 return function(e){
24497 var k = e.getKey();
24501 this.execCmd('InsertHTML','    ');
24504 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24505 this.cleanUpPaste.defer(100, this);
24510 }else if(Roo.isSafari){
24511 return function(e){
24512 var k = e.getKey();
24516 this.execCmd('InsertText','\t');
24520 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24521 this.cleanUpPaste.defer(100, this);
24529 getAllAncestors: function()
24531 var p = this.getSelectedNode();
24534 a.push(p); // push blank onto stack..
24535 p = this.getParentElement();
24539 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24543 a.push(this.doc.body);
24547 lastSelNode : false,
24550 getSelection : function()
24552 this.assignDocWin();
24553 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24556 getSelectedNode: function()
24558 // this may only work on Gecko!!!
24560 // should we cache this!!!!
24565 var range = this.createRange(this.getSelection());
24568 var parent = range.parentElement();
24570 var testRange = range.duplicate();
24571 testRange.moveToElementText(parent);
24572 if (testRange.inRange(range)) {
24575 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24578 parent = parent.parentElement;
24584 var ar = range.endContainer.childNodes;
24586 ar = range.commonAncestorContainer.childNodes;
24587 //alert(ar.length);
24590 var other_nodes = [];
24591 var has_other_nodes = false;
24592 for (var i=0;i<ar.length;i++) {
24593 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24596 // fullly contained node.
24598 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24603 // probably selected..
24604 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24605 other_nodes.push(ar[i]);
24608 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24613 has_other_nodes = true;
24615 if (!nodes.length && other_nodes.length) {
24616 nodes= other_nodes;
24618 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24624 createRange: function(sel)
24626 // this has strange effects when using with
24627 // top toolbar - not sure if it's a great idea.
24628 //this.editor.contentWindow.focus();
24629 if (typeof sel != "undefined") {
24631 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24633 return this.doc.createRange();
24636 return this.doc.createRange();
24639 getParentElement: function()
24642 this.assignDocWin();
24643 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24645 var range = this.createRange(sel);
24648 var p = range.commonAncestorContainer;
24649 while (p.nodeType == 3) { // text node
24661 // BC Hacks - cause I cant work out what i was trying to do..
24662 rangeIntersectsNode : function(range, node)
24664 var nodeRange = node.ownerDocument.createRange();
24666 nodeRange.selectNode(node);
24669 nodeRange.selectNodeContents(node);
24672 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24673 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24675 rangeCompareNode : function(range, node) {
24676 var nodeRange = node.ownerDocument.createRange();
24678 nodeRange.selectNode(node);
24680 nodeRange.selectNodeContents(node);
24682 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24683 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24685 if (nodeIsBefore && !nodeIsAfter)
24687 if (!nodeIsBefore && nodeIsAfter)
24689 if (nodeIsBefore && nodeIsAfter)
24695 // private? - in a new class?
24696 cleanUpPaste : function()
24698 // cleans up the whole document..
24699 // console.log('cleanuppaste');
24700 this.cleanUpChildren(this.doc.body)
24704 cleanUpChildren : function (n)
24706 if (!n.childNodes.length) {
24709 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24710 this.cleanUpChild(n.childNodes[i]);
24717 cleanUpChild : function (node)
24719 //console.log(node);
24720 if (node.nodeName == "#text") {
24721 // clean up silly Windows -- stuff?
24724 if (node.nodeName == "#comment") {
24725 node.parentNode.removeChild(node);
24726 // clean up silly Windows -- stuff?
24730 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24732 node.parentNode.removeChild(node);
24736 if (!node.attributes || !node.attributes.length) {
24737 this.cleanUpChildren(node);
24741 function cleanAttr(n,v)
24744 if (v.match(/^\./) || v.match(/^\//)) {
24747 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24750 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24751 node.removeAttribute(n);
24755 function cleanStyle(n,v)
24757 if (v.match(/expression/)) { //XSS?? should we even bother..
24758 node.removeAttribute(n);
24763 var parts = v.split(/;/);
24764 Roo.each(parts, function(p) {
24765 p = p.replace(/\s+/g,'');
24769 var l = p.split(':').shift().replace(/\s+/g,'');
24771 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24772 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24773 node.removeAttribute(n);
24782 for (var i = node.attributes.length-1; i > -1 ; i--) {
24783 var a = node.attributes[i];
24785 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24786 node.removeAttribute(a.name);
24789 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24790 cleanAttr(a.name,a.value); // fixme..
24793 if (a.name == 'style') {
24794 cleanStyle(a.name,a.value);
24796 /// clean up MS crap..
24797 if (a.name == 'class') {
24798 if (a.value.match(/^Mso/)) {
24799 node.className = '';
24809 this.cleanUpChildren(node);
24815 // hide stuff that is not compatible
24829 * @event specialkey
24833 * @cfg {String} fieldClass @hide
24836 * @cfg {String} focusClass @hide
24839 * @cfg {String} autoCreate @hide
24842 * @cfg {String} inputType @hide
24845 * @cfg {String} invalidClass @hide
24848 * @cfg {String} invalidText @hide
24851 * @cfg {String} msgFx @hide
24854 * @cfg {String} validateOnBlur @hide
24858 Roo.form.HtmlEditor.white = [
24859 'area', 'br', 'img', 'input', 'hr', 'wbr',
24861 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24862 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24863 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24864 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24865 'table', 'ul', 'xmp',
24867 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24870 'dir', 'menu', 'ol', 'ul', 'dl',
24876 Roo.form.HtmlEditor.black = [
24877 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24879 'base', 'basefont', 'bgsound', 'blink', 'body',
24880 'frame', 'frameset', 'head', 'html', 'ilayer',
24881 'iframe', 'layer', 'link', 'meta', 'object',
24882 'script', 'style' ,'title', 'xml' // clean later..
24884 Roo.form.HtmlEditor.clean = [
24885 'script', 'style', 'title', 'xml'
24890 Roo.form.HtmlEditor.ablack = [
24894 Roo.form.HtmlEditor.aclean = [
24895 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24899 Roo.form.HtmlEditor.pwhite= [
24900 'http', 'https', 'mailto'
24903 Roo.form.HtmlEditor.cwhite= [
24908 // <script type="text/javascript">
24911 * Ext JS Library 1.1.1
24912 * Copyright(c) 2006-2007, Ext JS, LLC.
24918 * @class Roo.form.HtmlEditorToolbar1
24923 new Roo.form.HtmlEditor({
24926 new Roo.form.HtmlEditorToolbar1({
24927 disable : { fonts: 1 , format: 1, ..., ... , ...],
24933 * @cfg {Object} disable List of elements to disable..
24934 * @cfg {Array} btns List of additional buttons.
24938 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24941 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24944 Roo.apply(this, config);
24945 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24946 // dont call parent... till later.
24949 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
24957 * @cfg {Object} disable List of toolbar elements to disable
24962 * @cfg {Array} fontFamilies An array of available font families
24980 // "á" , ?? a acute?
24985 "°" // , // degrees
24987 // "é" , // e ecute
24988 // "ú" , // u ecute?
24991 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
24992 "input:submit", "input:button", "select", "textarea", "label" ],
24995 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
24997 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25000 * @cfg {String} defaultFont default font to use.
25002 defaultFont: 'tahoma',
25004 fontSelect : false,
25007 formatCombo : false,
25009 init : function(editor)
25011 this.editor = editor;
25014 var fid = editor.frameId;
25016 function btn(id, toggle, handler){
25017 var xid = fid + '-'+ id ;
25021 cls : 'x-btn-icon x-edit-'+id,
25022 enableToggle:toggle !== false,
25023 scope: editor, // was editor...
25024 handler:handler||editor.relayBtnCmd,
25025 clickEvent:'mousedown',
25026 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25033 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25035 // stop form submits
25036 tb.el.on('click', function(e){
25037 e.preventDefault(); // what does this do?
25040 if(!this.disable.font && !Roo.isSafari){
25041 /* why no safari for fonts
25042 editor.fontSelect = tb.el.createChild({
25045 cls:'x-font-select',
25046 html: editor.createFontOptions()
25048 editor.fontSelect.on('change', function(){
25049 var font = editor.fontSelect.dom.value;
25050 editor.relayCmd('fontname', font);
25051 editor.deferFocus();
25054 editor.fontSelect.dom,
25059 if(!this.disable.formats){
25060 this.formatCombo = new Roo.form.ComboBox({
25061 store: new Roo.data.SimpleStore({
25064 data : this.formats // from states.js
25067 //autoCreate : {tag: "div", size: "20"},
25068 displayField:'tag',
25072 triggerAction: 'all',
25073 emptyText:'Add tag',
25074 selectOnFocus:true,
25077 'select': function(c, r, i) {
25078 editor.insertTag(r.get('tag'));
25084 tb.addField(this.formatCombo);
25088 if(!this.disable.format){
25095 if(!this.disable.fontSize){
25100 btn('increasefontsize', false, editor.adjustFont),
25101 btn('decreasefontsize', false, editor.adjustFont)
25106 if(this.disable.colors){
25109 id:editor.frameId +'-forecolor',
25110 cls:'x-btn-icon x-edit-forecolor',
25111 clickEvent:'mousedown',
25112 tooltip: this.buttonTips['forecolor'] || undefined,
25114 menu : new Roo.menu.ColorMenu({
25115 allowReselect: true,
25116 focus: Roo.emptyFn,
25119 selectHandler: function(cp, color){
25120 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25121 editor.deferFocus();
25124 clickEvent:'mousedown'
25127 id:editor.frameId +'backcolor',
25128 cls:'x-btn-icon x-edit-backcolor',
25129 clickEvent:'mousedown',
25130 tooltip: this.buttonTips['backcolor'] || undefined,
25132 menu : new Roo.menu.ColorMenu({
25133 focus: Roo.emptyFn,
25136 allowReselect: true,
25137 selectHandler: function(cp, color){
25139 editor.execCmd('useCSS', false);
25140 editor.execCmd('hilitecolor', color);
25141 editor.execCmd('useCSS', true);
25142 editor.deferFocus();
25144 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25145 Roo.isSafari || Roo.isIE ? '#'+color : color);
25146 editor.deferFocus();
25150 clickEvent:'mousedown'
25155 // now add all the items...
25158 if(!this.disable.alignments){
25161 btn('justifyleft'),
25162 btn('justifycenter'),
25163 btn('justifyright')
25167 //if(!Roo.isSafari){
25168 if(!this.disable.links){
25171 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25175 if(!this.disable.lists){
25178 btn('insertorderedlist'),
25179 btn('insertunorderedlist')
25182 if(!this.disable.sourceEdit){
25185 btn('sourceedit', true, function(btn){
25186 this.toggleSourceEdit(btn.pressed);
25193 // special menu.. - needs to be tidied up..
25194 if (!this.disable.special) {
25197 cls: 'x-edit-none',
25202 for (var i =0; i < this.specialChars.length; i++) {
25203 smenu.menu.items.push({
25205 html: this.specialChars[i],
25206 handler: function(a,b) {
25207 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25220 for(var i =0; i< this.btns.length;i++) {
25221 var b = this.btns[i];
25222 b.cls = 'x-edit-none';
25231 // disable everything...
25233 this.tb.items.each(function(item){
25234 if(item.id != editor.frameId+ '-sourceedit'){
25238 this.rendered = true;
25240 // the all the btns;
25241 editor.on('editorevent', this.updateToolbar, this);
25242 // other toolbars need to implement this..
25243 //editor.on('editmodechange', this.updateToolbar, this);
25249 * Protected method that will not generally be called directly. It triggers
25250 * a toolbar update by reading the markup state of the current selection in the editor.
25252 updateToolbar: function(){
25254 if(!this.editor.activated){
25255 this.editor.onFirstFocus();
25259 var btns = this.tb.items.map,
25260 doc = this.editor.doc,
25261 frameId = this.editor.frameId;
25263 if(!this.disable.font && !Roo.isSafari){
25265 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25266 if(name != this.fontSelect.dom.value){
25267 this.fontSelect.dom.value = name;
25271 if(!this.disable.format){
25272 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25273 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25274 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25276 if(!this.disable.alignments){
25277 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25278 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25279 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25281 if(!Roo.isSafari && !this.disable.lists){
25282 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25283 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25286 var ans = this.editor.getAllAncestors();
25287 if (this.formatCombo) {
25290 var store = this.formatCombo.store;
25291 this.formatCombo.setValue("");
25292 for (var i =0; i < ans.length;i++) {
25293 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25295 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25303 // hides menus... - so this cant be on a menu...
25304 Roo.menu.MenuMgr.hideAll();
25306 //this.editorsyncValue();
25310 createFontOptions : function(){
25311 var buf = [], fs = this.fontFamilies, ff, lc;
25312 for(var i = 0, len = fs.length; i< len; i++){
25314 lc = ff.toLowerCase();
25316 '<option value="',lc,'" style="font-family:',ff,';"',
25317 (this.defaultFont == lc ? ' selected="true">' : '>'),
25322 return buf.join('');
25325 toggleSourceEdit : function(sourceEditMode){
25326 if(sourceEditMode === undefined){
25327 sourceEditMode = !this.sourceEditMode;
25329 this.sourceEditMode = sourceEditMode === true;
25330 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25331 // just toggle the button?
25332 if(btn.pressed !== this.editor.sourceEditMode){
25333 btn.toggle(this.editor.sourceEditMode);
25337 if(this.sourceEditMode){
25338 this.tb.items.each(function(item){
25339 if(item.cmd != 'sourceedit'){
25345 if(this.initialized){
25346 this.tb.items.each(function(item){
25352 // tell the editor that it's been pressed..
25353 this.editor.toggleSourceEdit(sourceEditMode);
25357 * Object collection of toolbar tooltips for the buttons in the editor. The key
25358 * is the command id associated with that button and the value is a valid QuickTips object.
25363 title: 'Bold (Ctrl+B)',
25364 text: 'Make the selected text bold.',
25365 cls: 'x-html-editor-tip'
25368 title: 'Italic (Ctrl+I)',
25369 text: 'Make the selected text italic.',
25370 cls: 'x-html-editor-tip'
25378 title: 'Bold (Ctrl+B)',
25379 text: 'Make the selected text bold.',
25380 cls: 'x-html-editor-tip'
25383 title: 'Italic (Ctrl+I)',
25384 text: 'Make the selected text italic.',
25385 cls: 'x-html-editor-tip'
25388 title: 'Underline (Ctrl+U)',
25389 text: 'Underline the selected text.',
25390 cls: 'x-html-editor-tip'
25392 increasefontsize : {
25393 title: 'Grow Text',
25394 text: 'Increase the font size.',
25395 cls: 'x-html-editor-tip'
25397 decreasefontsize : {
25398 title: 'Shrink Text',
25399 text: 'Decrease the font size.',
25400 cls: 'x-html-editor-tip'
25403 title: 'Text Highlight Color',
25404 text: 'Change the background color of the selected text.',
25405 cls: 'x-html-editor-tip'
25408 title: 'Font Color',
25409 text: 'Change the color of the selected text.',
25410 cls: 'x-html-editor-tip'
25413 title: 'Align Text Left',
25414 text: 'Align text to the left.',
25415 cls: 'x-html-editor-tip'
25418 title: 'Center Text',
25419 text: 'Center text in the editor.',
25420 cls: 'x-html-editor-tip'
25423 title: 'Align Text Right',
25424 text: 'Align text to the right.',
25425 cls: 'x-html-editor-tip'
25427 insertunorderedlist : {
25428 title: 'Bullet List',
25429 text: 'Start a bulleted list.',
25430 cls: 'x-html-editor-tip'
25432 insertorderedlist : {
25433 title: 'Numbered List',
25434 text: 'Start a numbered list.',
25435 cls: 'x-html-editor-tip'
25438 title: 'Hyperlink',
25439 text: 'Make the selected text a hyperlink.',
25440 cls: 'x-html-editor-tip'
25443 title: 'Source Edit',
25444 text: 'Switch to source editing mode.',
25445 cls: 'x-html-editor-tip'
25449 onDestroy : function(){
25452 this.tb.items.each(function(item){
25454 item.menu.removeAll();
25456 item.menu.el.destroy();
25464 onFirstFocus: function() {
25465 this.tb.items.each(function(item){
25474 // <script type="text/javascript">
25477 * Ext JS Library 1.1.1
25478 * Copyright(c) 2006-2007, Ext JS, LLC.
25485 * @class Roo.form.HtmlEditor.ToolbarContext
25490 new Roo.form.HtmlEditor({
25493 new Roo.form.HtmlEditor.ToolbarStandard(),
25494 new Roo.form.HtmlEditor.ToolbarContext()
25499 * @config : {Object} disable List of elements to disable.. (not done yet.)
25504 Roo.form.HtmlEditor.ToolbarContext = function(config)
25507 Roo.apply(this, config);
25508 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25509 // dont call parent... till later.
25511 Roo.form.HtmlEditor.ToolbarContext.types = {
25523 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25585 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25590 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25654 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25662 * @cfg {Object} disable List of toolbar elements to disable
25671 init : function(editor)
25673 this.editor = editor;
25676 var fid = editor.frameId;
25678 function btn(id, toggle, handler){
25679 var xid = fid + '-'+ id ;
25683 cls : 'x-btn-icon x-edit-'+id,
25684 enableToggle:toggle !== false,
25685 scope: editor, // was editor...
25686 handler:handler||editor.relayBtnCmd,
25687 clickEvent:'mousedown',
25688 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25692 // create a new element.
25693 var wdiv = editor.wrap.createChild({
25695 }, editor.wrap.dom.firstChild.nextSibling, true);
25697 // can we do this more than once??
25699 // stop form submits
25702 // disable everything...
25703 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25704 this.toolbars = {};
25706 for (var i in ty) {
25708 this.toolbars[i] = this.buildToolbar(ty[i],i);
25710 this.tb = this.toolbars.BODY;
25714 this.rendered = true;
25716 // the all the btns;
25717 editor.on('editorevent', this.updateToolbar, this);
25718 // other toolbars need to implement this..
25719 //editor.on('editmodechange', this.updateToolbar, this);
25725 * Protected method that will not generally be called directly. It triggers
25726 * a toolbar update by reading the markup state of the current selection in the editor.
25728 updateToolbar: function(){
25730 if(!this.editor.activated){
25731 this.editor.onFirstFocus();
25736 var ans = this.editor.getAllAncestors();
25739 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25740 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25741 sel = sel ? sel : this.editor.doc.body;
25742 sel = sel.tagName.length ? sel : this.editor.doc.body;
25743 var tn = sel.tagName.toUpperCase();
25744 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25745 tn = sel.tagName.toUpperCase();
25746 if (this.tb.name == tn) {
25747 return; // no change
25750 ///console.log("show: " + tn);
25751 this.tb = this.toolbars[tn];
25753 this.tb.fields.each(function(e) {
25754 e.setValue(sel.getAttribute(e.name));
25756 this.tb.selectedNode = sel;
25759 Roo.menu.MenuMgr.hideAll();
25761 //this.editorsyncValue();
25766 onDestroy : function(){
25769 this.tb.items.each(function(item){
25771 item.menu.removeAll();
25773 item.menu.el.destroy();
25781 onFirstFocus: function() {
25782 // need to do this for all the toolbars..
25783 this.tb.items.each(function(item){
25787 buildToolbar: function(tlist, nm)
25789 var editor = this.editor;
25790 // create a new element.
25791 var wdiv = editor.wrap.createChild({
25793 }, editor.wrap.dom.firstChild.nextSibling, true);
25796 var tb = new Roo.Toolbar(wdiv);
25797 tb.add(nm+ ": ");
25798 for (var i in tlist) {
25799 var item = tlist[i];
25800 tb.add(item.title + ": ");
25805 tb.addField( new Roo.form.ComboBox({
25806 store: new Roo.data.SimpleStore({
25809 data : item.opts // from states.js
25812 displayField:'val',
25816 triggerAction: 'all',
25817 emptyText:'Select',
25818 selectOnFocus:true,
25819 width: item.width ? item.width : 130,
25821 'select': function(c, r, i) {
25822 tb.selectedNode.setAttribute(c.name, r.get('val'));
25833 tb.addField( new Roo.form.TextField({
25836 //allowBlank:false,
25841 tb.addField( new Roo.form.TextField({
25847 'change' : function(f, nv, ov) {
25848 tb.selectedNode.setAttribute(f.name, nv);
25854 tb.el.on('click', function(e){
25855 e.preventDefault(); // what does this do?
25857 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25860 // dont need to disable them... as they will get hidden
25877 * Ext JS Library 1.1.1
25878 * Copyright(c) 2006-2007, Ext JS, LLC.
25880 * Originally Released Under LGPL - original licence link has changed is not relivant.
25883 * <script type="text/javascript">
25887 * @class Roo.form.BasicForm
25888 * @extends Roo.util.Observable
25889 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25891 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25892 * @param {Object} config Configuration options
25894 Roo.form.BasicForm = function(el, config){
25895 this.allItems = [];
25896 this.childForms = [];
25897 Roo.apply(this, config);
25899 * The Roo.form.Field items in this form.
25900 * @type MixedCollection
25904 this.items = new Roo.util.MixedCollection(false, function(o){
25905 return o.id || (o.id = Roo.id());
25909 * @event beforeaction
25910 * Fires before any action is performed. Return false to cancel the action.
25911 * @param {Form} this
25912 * @param {Action} action The action to be performed
25914 beforeaction: true,
25916 * @event actionfailed
25917 * Fires when an action fails.
25918 * @param {Form} this
25919 * @param {Action} action The action that failed
25921 actionfailed : true,
25923 * @event actioncomplete
25924 * Fires when an action is completed.
25925 * @param {Form} this
25926 * @param {Action} action The action that completed
25928 actioncomplete : true
25933 Roo.form.BasicForm.superclass.constructor.call(this);
25936 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25938 * @cfg {String} method
25939 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25942 * @cfg {DataReader} reader
25943 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25944 * This is optional as there is built-in support for processing JSON.
25947 * @cfg {DataReader} errorReader
25948 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
25949 * This is completely optional as there is built-in support for processing JSON.
25952 * @cfg {String} url
25953 * The URL to use for form actions if one isn't supplied in the action options.
25956 * @cfg {Boolean} fileUpload
25957 * Set to true if this form is a file upload.
25960 * @cfg {Object} baseParams
25961 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
25964 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
25969 activeAction : null,
25972 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
25973 * or setValues() data instead of when the form was first created.
25975 trackResetOnLoad : false,
25979 * childForms - used for multi-tab forms
25982 childForms : false,
25985 * allItems - full list of fields.
25991 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
25992 * element by passing it or its id or mask the form itself by passing in true.
25995 waitMsgTarget : undefined,
25998 initEl : function(el){
25999 this.el = Roo.get(el);
26000 this.id = this.el.id || Roo.id();
26001 this.el.on('submit', this.onSubmit, this);
26002 this.el.addClass('x-form');
26006 onSubmit : function(e){
26011 * Returns true if client-side validation on the form is successful.
26014 isValid : function(){
26016 this.items.each(function(f){
26025 * Returns true if any fields in this form have changed since their original load.
26028 isDirty : function(){
26030 this.items.each(function(f){
26040 * Performs a predefined action (submit or load) or custom actions you define on this form.
26041 * @param {String} actionName The name of the action type
26042 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26043 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26044 * accept other config options):
26046 Property Type Description
26047 ---------------- --------------- ----------------------------------------------------------------------------------
26048 url String The url for the action (defaults to the form's url)
26049 method String The form method to use (defaults to the form's method, or POST if not defined)
26050 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26051 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26052 validate the form on the client (defaults to false)
26054 * @return {BasicForm} this
26056 doAction : function(action, options){
26057 if(typeof action == 'string'){
26058 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26060 if(this.fireEvent('beforeaction', this, action) !== false){
26061 this.beforeAction(action);
26062 action.run.defer(100, action);
26068 * Shortcut to do a submit action.
26069 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26070 * @return {BasicForm} this
26072 submit : function(options){
26073 this.doAction('submit', options);
26078 * Shortcut to do a load action.
26079 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26080 * @return {BasicForm} this
26082 load : function(options){
26083 this.doAction('load', options);
26088 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26089 * @param {Record} record The record to edit
26090 * @return {BasicForm} this
26092 updateRecord : function(record){
26093 record.beginEdit();
26094 var fs = record.fields;
26095 fs.each(function(f){
26096 var field = this.findField(f.name);
26098 record.set(f.name, field.getValue());
26106 * Loads an Roo.data.Record into this form.
26107 * @param {Record} record The record to load
26108 * @return {BasicForm} this
26110 loadRecord : function(record){
26111 this.setValues(record.data);
26116 beforeAction : function(action){
26117 var o = action.options;
26119 if(this.waitMsgTarget === true){
26120 this.el.mask(o.waitMsg, 'x-mask-loading');
26121 }else if(this.waitMsgTarget){
26122 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26123 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
26125 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
26131 afterAction : function(action, success){
26132 this.activeAction = null;
26133 var o = action.options;
26135 if(this.waitMsgTarget === true){
26137 }else if(this.waitMsgTarget){
26138 this.waitMsgTarget.unmask();
26140 Roo.MessageBox.updateProgress(1);
26141 Roo.MessageBox.hide();
26148 Roo.callback(o.success, o.scope, [this, action]);
26149 this.fireEvent('actioncomplete', this, action);
26151 Roo.callback(o.failure, o.scope, [this, action]);
26152 this.fireEvent('actionfailed', this, action);
26157 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26158 * @param {String} id The value to search for
26161 findField : function(id){
26162 var field = this.items.get(id);
26164 this.items.each(function(f){
26165 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26171 return field || null;
26175 * Add a secondary form to this one,
26176 * Used to provide tabbed forms. One form is primary, with hidden values
26177 * which mirror the elements from the other forms.
26179 * @param {Roo.form.Form} form to add.
26182 addForm : function(form)
26185 if (this.childForms.indexOf(form) > -1) {
26189 this.childForms.push(form);
26191 Roo.each(form.allItems, function (fe) {
26193 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26194 if (this.findField(n)) { // already added..
26197 var add = new Roo.form.Hidden({
26200 add.render(this.el);
26207 * Mark fields in this form invalid in bulk.
26208 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26209 * @return {BasicForm} this
26211 markInvalid : function(errors){
26212 if(errors instanceof Array){
26213 for(var i = 0, len = errors.length; i < len; i++){
26214 var fieldError = errors[i];
26215 var f = this.findField(fieldError.id);
26217 f.markInvalid(fieldError.msg);
26223 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26224 field.markInvalid(errors[id]);
26228 Roo.each(this.childForms || [], function (f) {
26229 f.markInvalid(errors);
26236 * Set values for fields in this form in bulk.
26237 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26238 * @return {BasicForm} this
26240 setValues : function(values){
26241 if(values instanceof Array){ // array of objects
26242 for(var i = 0, len = values.length; i < len; i++){
26244 var f = this.findField(v.id);
26246 f.setValue(v.value);
26247 if(this.trackResetOnLoad){
26248 f.originalValue = f.getValue();
26252 }else{ // object hash
26255 if(typeof values[id] != 'function' && (field = this.findField(id))){
26257 if (field.setFromData &&
26258 field.valueField &&
26259 field.displayField &&
26260 // combos' with local stores can
26261 // be queried via setValue()
26262 // to set their value..
26263 (field.store && !field.store.isLocal)
26267 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26268 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26269 field.setFromData(sd);
26272 field.setValue(values[id]);
26276 if(this.trackResetOnLoad){
26277 field.originalValue = field.getValue();
26283 Roo.each(this.childForms || [], function (f) {
26284 f.setValues(values);
26291 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26292 * they are returned as an array.
26293 * @param {Boolean} asString
26296 getValues : function(asString){
26297 if (this.childForms) {
26298 // copy values from the child forms
26299 Roo.each(this.childForms, function (f) {
26300 this.setValues(f.getValues());
26306 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26307 if(asString === true){
26310 return Roo.urlDecode(fs);
26314 * Returns the fields in this form as an object with key/value pairs.
26315 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26318 getFieldValues : function()
26320 if (this.childForms) {
26321 // copy values from the child forms
26322 Roo.each(this.childForms, function (f) {
26323 this.setValues(f.getValues());
26328 this.items.each(function(f){
26329 if (!f.getName()) {
26332 var v = f.getValue();
26333 if ((typeof(v) == 'object') && f.getRawValue) {
26334 v = f.getRawValue() ; // dates..
26336 ret[f.getName()] = v;
26343 * Clears all invalid messages in this form.
26344 * @return {BasicForm} this
26346 clearInvalid : function(){
26347 this.items.each(function(f){
26351 Roo.each(this.childForms || [], function (f) {
26360 * Resets this form.
26361 * @return {BasicForm} this
26363 reset : function(){
26364 this.items.each(function(f){
26368 Roo.each(this.childForms || [], function (f) {
26377 * Add Roo.form components to this form.
26378 * @param {Field} field1
26379 * @param {Field} field2 (optional)
26380 * @param {Field} etc (optional)
26381 * @return {BasicForm} this
26384 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26390 * Removes a field from the items collection (does NOT remove its markup).
26391 * @param {Field} field
26392 * @return {BasicForm} this
26394 remove : function(field){
26395 this.items.remove(field);
26400 * Looks at the fields in this form, checks them for an id attribute,
26401 * and calls applyTo on the existing dom element with that id.
26402 * @return {BasicForm} this
26404 render : function(){
26405 this.items.each(function(f){
26406 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26414 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26415 * @param {Object} values
26416 * @return {BasicForm} this
26418 applyToFields : function(o){
26419 this.items.each(function(f){
26426 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26427 * @param {Object} values
26428 * @return {BasicForm} this
26430 applyIfToFields : function(o){
26431 this.items.each(function(f){
26439 Roo.BasicForm = Roo.form.BasicForm;/*
26441 * Ext JS Library 1.1.1
26442 * Copyright(c) 2006-2007, Ext JS, LLC.
26444 * Originally Released Under LGPL - original licence link has changed is not relivant.
26447 * <script type="text/javascript">
26451 * @class Roo.form.Form
26452 * @extends Roo.form.BasicForm
26453 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26455 * @param {Object} config Configuration options
26457 Roo.form.Form = function(config){
26459 if (config.items) {
26460 xitems = config.items;
26461 delete config.items;
26465 Roo.form.Form.superclass.constructor.call(this, null, config);
26466 this.url = this.url || this.action;
26468 this.root = new Roo.form.Layout(Roo.applyIf({
26472 this.active = this.root;
26474 * Array of all the buttons that have been added to this form via {@link addButton}
26478 this.allItems = [];
26481 * @event clientvalidation
26482 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26483 * @param {Form} this
26484 * @param {Boolean} valid true if the form has passed client-side validation
26486 clientvalidation: true,
26489 * Fires when the form is rendered
26490 * @param {Roo.form.Form} form
26495 if (this.progressUrl) {
26496 // push a hidden field onto the list of fields..
26500 name : 'UPLOAD_IDENTIFIER'
26505 Roo.each(xitems, this.addxtype, this);
26511 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26513 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26516 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26519 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26521 buttonAlign:'center',
26524 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26529 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26530 * This property cascades to child containers if not set.
26535 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26536 * fires a looping event with that state. This is required to bind buttons to the valid
26537 * state using the config value formBind:true on the button.
26539 monitorValid : false,
26542 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26547 * @cfg {String} progressUrl - Url to return progress data
26550 progressUrl : false,
26553 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26554 * fields are added and the column is closed. If no fields are passed the column remains open
26555 * until end() is called.
26556 * @param {Object} config The config to pass to the column
26557 * @param {Field} field1 (optional)
26558 * @param {Field} field2 (optional)
26559 * @param {Field} etc (optional)
26560 * @return Column The column container object
26562 column : function(c){
26563 var col = new Roo.form.Column(c);
26565 if(arguments.length > 1){ // duplicate code required because of Opera
26566 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26573 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26574 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26575 * until end() is called.
26576 * @param {Object} config The config to pass to the fieldset
26577 * @param {Field} field1 (optional)
26578 * @param {Field} field2 (optional)
26579 * @param {Field} etc (optional)
26580 * @return FieldSet The fieldset container object
26582 fieldset : function(c){
26583 var fs = new Roo.form.FieldSet(c);
26585 if(arguments.length > 1){ // duplicate code required because of Opera
26586 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26593 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26594 * fields are added and the container is closed. If no fields are passed the container remains open
26595 * until end() is called.
26596 * @param {Object} config The config to pass to the Layout
26597 * @param {Field} field1 (optional)
26598 * @param {Field} field2 (optional)
26599 * @param {Field} etc (optional)
26600 * @return Layout The container object
26602 container : function(c){
26603 var l = new Roo.form.Layout(c);
26605 if(arguments.length > 1){ // duplicate code required because of Opera
26606 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26613 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26614 * @param {Object} container A Roo.form.Layout or subclass of Layout
26615 * @return {Form} this
26617 start : function(c){
26618 // cascade label info
26619 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26620 this.active.stack.push(c);
26621 c.ownerCt = this.active;
26627 * Closes the current open container
26628 * @return {Form} this
26631 if(this.active == this.root){
26634 this.active = this.active.ownerCt;
26639 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26640 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26641 * as the label of the field.
26642 * @param {Field} field1
26643 * @param {Field} field2 (optional)
26644 * @param {Field} etc. (optional)
26645 * @return {Form} this
26648 this.active.stack.push.apply(this.active.stack, arguments);
26649 this.allItems.push.apply(this.allItems,arguments);
26651 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26652 if(a[i].isFormField){
26657 Roo.form.Form.superclass.add.apply(this, r);
26667 * Find any element that has been added to a form, using it's ID or name
26668 * This can include framesets, columns etc. along with regular fields..
26669 * @param {String} id - id or name to find.
26671 * @return {Element} e - or false if nothing found.
26673 findbyId : function(id)
26679 Ext.each(this.allItems, function(f){
26680 if (f.id == id || f.name == id ){
26691 * Render this form into the passed container. This should only be called once!
26692 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26693 * @return {Form} this
26695 render : function(ct)
26701 var o = this.autoCreate || {
26703 method : this.method || 'POST',
26704 id : this.id || Roo.id()
26706 this.initEl(ct.createChild(o));
26708 this.root.render(this.el);
26712 this.items.each(function(f){
26713 f.render('x-form-el-'+f.id);
26716 if(this.buttons.length > 0){
26717 // tables are required to maintain order and for correct IE layout
26718 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26719 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26720 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26722 var tr = tb.getElementsByTagName('tr')[0];
26723 for(var i = 0, len = this.buttons.length; i < len; i++) {
26724 var b = this.buttons[i];
26725 var td = document.createElement('td');
26726 td.className = 'x-form-btn-td';
26727 b.render(tr.appendChild(td));
26730 if(this.monitorValid){ // initialize after render
26731 this.startMonitoring();
26733 this.fireEvent('rendered', this);
26738 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26739 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26740 * object or a valid Roo.DomHelper element config
26741 * @param {Function} handler The function called when the button is clicked
26742 * @param {Object} scope (optional) The scope of the handler function
26743 * @return {Roo.Button}
26745 addButton : function(config, handler, scope){
26749 minWidth: this.minButtonWidth,
26752 if(typeof config == "string"){
26755 Roo.apply(bc, config);
26757 var btn = new Roo.Button(null, bc);
26758 this.buttons.push(btn);
26763 * Adds a series of form elements (using the xtype property as the factory method.
26764 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26765 * @param {Object} config
26768 addxtype : function()
26770 var ar = Array.prototype.slice.call(arguments, 0);
26772 for(var i = 0; i < ar.length; i++) {
26774 continue; // skip -- if this happends something invalid got sent, we
26775 // should ignore it, as basically that interface element will not show up
26776 // and that should be pretty obvious!!
26779 if (Roo.form[ar[i].xtype]) {
26781 var fe = Roo.factory(ar[i], Roo.form);
26787 fe.store.form = this;
26792 this.allItems.push(fe);
26793 if (fe.items && fe.addxtype) {
26794 fe.addxtype.apply(fe, fe.items);
26804 // console.log('adding ' + ar[i].xtype);
26806 if (ar[i].xtype == 'Button') {
26807 //console.log('adding button');
26808 //console.log(ar[i]);
26809 this.addButton(ar[i]);
26810 this.allItems.push(fe);
26814 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26815 alert('end is not supported on xtype any more, use items');
26817 // //console.log('adding end');
26825 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26826 * option "monitorValid"
26828 startMonitoring : function(){
26831 Roo.TaskMgr.start({
26832 run : this.bindHandler,
26833 interval : this.monitorPoll || 200,
26840 * Stops monitoring of the valid state of this form
26842 stopMonitoring : function(){
26843 this.bound = false;
26847 bindHandler : function(){
26849 return false; // stops binding
26852 this.items.each(function(f){
26853 if(!f.isValid(true)){
26858 for(var i = 0, len = this.buttons.length; i < len; i++){
26859 var btn = this.buttons[i];
26860 if(btn.formBind === true && btn.disabled === valid){
26861 btn.setDisabled(!valid);
26864 this.fireEvent('clientvalidation', this, valid);
26878 Roo.Form = Roo.form.Form;
26881 * Ext JS Library 1.1.1
26882 * Copyright(c) 2006-2007, Ext JS, LLC.
26884 * Originally Released Under LGPL - original licence link has changed is not relivant.
26887 * <script type="text/javascript">
26891 * @class Roo.form.Action
26892 * Internal Class used to handle form actions
26894 * @param {Roo.form.BasicForm} el The form element or its id
26895 * @param {Object} config Configuration options
26899 // define the action interface
26900 Roo.form.Action = function(form, options){
26902 this.options = options || {};
26905 * Client Validation Failed
26908 Roo.form.Action.CLIENT_INVALID = 'client';
26910 * Server Validation Failed
26913 Roo.form.Action.SERVER_INVALID = 'server';
26915 * Connect to Server Failed
26918 Roo.form.Action.CONNECT_FAILURE = 'connect';
26920 * Reading Data from Server Failed
26923 Roo.form.Action.LOAD_FAILURE = 'load';
26925 Roo.form.Action.prototype = {
26927 failureType : undefined,
26928 response : undefined,
26929 result : undefined,
26931 // interface method
26932 run : function(options){
26936 // interface method
26937 success : function(response){
26941 // interface method
26942 handleResponse : function(response){
26946 // default connection failure
26947 failure : function(response){
26948 this.response = response;
26949 this.failureType = Roo.form.Action.CONNECT_FAILURE;
26950 this.form.afterAction(this, false);
26953 processResponse : function(response){
26954 this.response = response;
26955 if(!response.responseText){
26958 this.result = this.handleResponse(response);
26959 return this.result;
26962 // utility functions used internally
26963 getUrl : function(appendParams){
26964 var url = this.options.url || this.form.url || this.form.el.dom.action;
26966 var p = this.getParams();
26968 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
26974 getMethod : function(){
26975 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
26978 getParams : function(){
26979 var bp = this.form.baseParams;
26980 var p = this.options.params;
26982 if(typeof p == "object"){
26983 p = Roo.urlEncode(Roo.applyIf(p, bp));
26984 }else if(typeof p == 'string' && bp){
26985 p += '&' + Roo.urlEncode(bp);
26988 p = Roo.urlEncode(bp);
26993 createCallback : function(){
26995 success: this.success,
26996 failure: this.failure,
26998 timeout: (this.form.timeout*1000),
26999 upload: this.form.fileUpload ? this.success : undefined
27004 Roo.form.Action.Submit = function(form, options){
27005 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27008 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27011 haveProgress : false,
27012 uploadComplete : false,
27014 // uploadProgress indicator.
27015 uploadProgress : function()
27017 if (!this.form.progressUrl) {
27021 if (!this.haveProgress) {
27022 Roo.MessageBox.progress("Uploading", "Uploading");
27024 if (this.uploadComplete) {
27025 Roo.MessageBox.hide();
27029 this.haveProgress = true;
27031 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27033 var c = new Roo.data.Connection();
27035 url : this.form.progressUrl,
27040 success : function(req){
27041 //console.log(data);
27045 rdata = Roo.decode(req.responseText)
27047 Roo.log("Invalid data from server..");
27051 if (!rdata || !rdata.success) {
27055 var data = rdata.data;
27057 if (this.uploadComplete) {
27058 Roo.MessageBox.hide();
27063 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27064 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27067 this.uploadProgress.defer(2000,this);
27070 failure: function(data) {
27071 Roo.log('progress url failed ');
27082 // run get Values on the form, so it syncs any secondary forms.
27083 this.form.getValues();
27085 var o = this.options;
27086 var method = this.getMethod();
27087 var isPost = method == 'POST';
27088 if(o.clientValidation === false || this.form.isValid()){
27090 if (this.form.progressUrl) {
27091 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27092 (new Date() * 1) + '' + Math.random());
27096 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27097 form:this.form.el.dom,
27098 url:this.getUrl(!isPost),
27100 params:isPost ? this.getParams() : null,
27101 isUpload: this.form.fileUpload
27104 this.uploadProgress();
27106 }else if (o.clientValidation !== false){ // client validation failed
27107 this.failureType = Roo.form.Action.CLIENT_INVALID;
27108 this.form.afterAction(this, false);
27112 success : function(response)
27114 this.uploadComplete= true;
27115 if (this.haveProgress) {
27116 Roo.MessageBox.hide();
27119 var result = this.processResponse(response);
27120 if(result === true || result.success){
27121 this.form.afterAction(this, true);
27125 this.form.markInvalid(result.errors);
27126 this.failureType = Roo.form.Action.SERVER_INVALID;
27128 this.form.afterAction(this, false);
27130 failure : function(response)
27132 this.uploadComplete= true;
27133 if (this.haveProgress) {
27134 Roo.MessageBox.hide();
27137 this.response = response;
27138 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27139 this.form.afterAction(this, false);
27142 handleResponse : function(response){
27143 if(this.form.errorReader){
27144 var rs = this.form.errorReader.read(response);
27147 for(var i = 0, len = rs.records.length; i < len; i++) {
27148 var r = rs.records[i];
27149 errors[i] = r.data;
27152 if(errors.length < 1){
27156 success : rs.success,
27162 ret = Roo.decode(response.responseText);
27166 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27176 Roo.form.Action.Load = function(form, options){
27177 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27178 this.reader = this.form.reader;
27181 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27185 Roo.Ajax.request(Roo.apply(
27186 this.createCallback(), {
27187 method:this.getMethod(),
27188 url:this.getUrl(false),
27189 params:this.getParams()
27193 success : function(response){
27194 var result = this.processResponse(response);
27195 if(result === true || !result.success || !result.data){
27196 this.failureType = Roo.form.Action.LOAD_FAILURE;
27197 this.form.afterAction(this, false);
27200 this.form.clearInvalid();
27201 this.form.setValues(result.data);
27202 this.form.afterAction(this, true);
27205 handleResponse : function(response){
27206 if(this.form.reader){
27207 var rs = this.form.reader.read(response);
27208 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27210 success : rs.success,
27214 return Roo.decode(response.responseText);
27218 Roo.form.Action.ACTION_TYPES = {
27219 'load' : Roo.form.Action.Load,
27220 'submit' : Roo.form.Action.Submit
27223 * Ext JS Library 1.1.1
27224 * Copyright(c) 2006-2007, Ext JS, LLC.
27226 * Originally Released Under LGPL - original licence link has changed is not relivant.
27229 * <script type="text/javascript">
27233 * @class Roo.form.Layout
27234 * @extends Roo.Component
27235 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27237 * @param {Object} config Configuration options
27239 Roo.form.Layout = function(config){
27241 if (config.items) {
27242 xitems = config.items;
27243 delete config.items;
27245 Roo.form.Layout.superclass.constructor.call(this, config);
27247 Roo.each(xitems, this.addxtype, this);
27251 Roo.extend(Roo.form.Layout, Roo.Component, {
27253 * @cfg {String/Object} autoCreate
27254 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27257 * @cfg {String/Object/Function} style
27258 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27259 * a function which returns such a specification.
27262 * @cfg {String} labelAlign
27263 * Valid values are "left," "top" and "right" (defaults to "left")
27266 * @cfg {Number} labelWidth
27267 * Fixed width in pixels of all field labels (defaults to undefined)
27270 * @cfg {Boolean} clear
27271 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27275 * @cfg {String} labelSeparator
27276 * The separator to use after field labels (defaults to ':')
27278 labelSeparator : ':',
27280 * @cfg {Boolean} hideLabels
27281 * True to suppress the display of field labels in this layout (defaults to false)
27283 hideLabels : false,
27286 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27291 onRender : function(ct, position){
27292 if(this.el){ // from markup
27293 this.el = Roo.get(this.el);
27294 }else { // generate
27295 var cfg = this.getAutoCreate();
27296 this.el = ct.createChild(cfg, position);
27299 this.el.applyStyles(this.style);
27301 if(this.labelAlign){
27302 this.el.addClass('x-form-label-'+this.labelAlign);
27304 if(this.hideLabels){
27305 this.labelStyle = "display:none";
27306 this.elementStyle = "padding-left:0;";
27308 if(typeof this.labelWidth == 'number'){
27309 this.labelStyle = "width:"+this.labelWidth+"px;";
27310 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27312 if(this.labelAlign == 'top'){
27313 this.labelStyle = "width:auto;";
27314 this.elementStyle = "padding-left:0;";
27317 var stack = this.stack;
27318 var slen = stack.length;
27320 if(!this.fieldTpl){
27321 var t = new Roo.Template(
27322 '<div class="x-form-item {5}">',
27323 '<label for="{0}" style="{2}">{1}{4}</label>',
27324 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27326 '</div><div class="x-form-clear-left"></div>'
27328 t.disableFormats = true;
27330 Roo.form.Layout.prototype.fieldTpl = t;
27332 for(var i = 0; i < slen; i++) {
27333 if(stack[i].isFormField){
27334 this.renderField(stack[i]);
27336 this.renderComponent(stack[i]);
27341 this.el.createChild({cls:'x-form-clear'});
27346 renderField : function(f){
27347 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27350 f.labelStyle||this.labelStyle||'', //2
27351 this.elementStyle||'', //3
27352 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27353 f.itemCls||this.itemCls||'' //5
27354 ], true).getPrevSibling());
27358 renderComponent : function(c){
27359 c.render(c.isLayout ? this.el : this.el.createChild());
27362 * Adds a object form elements (using the xtype property as the factory method.)
27363 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27364 * @param {Object} config
27366 addxtype : function(o)
27368 // create the lement.
27369 o.form = this.form;
27370 var fe = Roo.factory(o, Roo.form);
27371 this.form.allItems.push(fe);
27372 this.stack.push(fe);
27374 if (fe.isFormField) {
27375 this.form.items.add(fe);
27383 * @class Roo.form.Column
27384 * @extends Roo.form.Layout
27385 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27387 * @param {Object} config Configuration options
27389 Roo.form.Column = function(config){
27390 Roo.form.Column.superclass.constructor.call(this, config);
27393 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27395 * @cfg {Number/String} width
27396 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27399 * @cfg {String/Object} autoCreate
27400 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27404 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27407 onRender : function(ct, position){
27408 Roo.form.Column.superclass.onRender.call(this, ct, position);
27410 this.el.setWidth(this.width);
27417 * @class Roo.form.Row
27418 * @extends Roo.form.Layout
27419 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27421 * @param {Object} config Configuration options
27425 Roo.form.Row = function(config){
27426 Roo.form.Row.superclass.constructor.call(this, config);
27429 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27431 * @cfg {Number/String} width
27432 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27435 * @cfg {Number/String} height
27436 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27438 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27442 onRender : function(ct, position){
27443 //console.log('row render');
27445 var t = new Roo.Template(
27446 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27447 '<label for="{0}" style="{2}">{1}{4}</label>',
27448 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27452 t.disableFormats = true;
27454 Roo.form.Layout.prototype.rowTpl = t;
27456 this.fieldTpl = this.rowTpl;
27458 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27459 var labelWidth = 100;
27461 if ((this.labelAlign != 'top')) {
27462 if (typeof this.labelWidth == 'number') {
27463 labelWidth = this.labelWidth
27465 this.padWidth = 20 + labelWidth;
27469 Roo.form.Column.superclass.onRender.call(this, ct, position);
27471 this.el.setWidth(this.width);
27474 this.el.setHeight(this.height);
27479 renderField : function(f){
27480 f.fieldEl = this.fieldTpl.append(this.el, [
27481 f.id, f.fieldLabel,
27482 f.labelStyle||this.labelStyle||'',
27483 this.elementStyle||'',
27484 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27485 f.itemCls||this.itemCls||'',
27486 f.width ? f.width + this.padWidth : 160 + this.padWidth
27493 * @class Roo.form.FieldSet
27494 * @extends Roo.form.Layout
27495 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27497 * @param {Object} config Configuration options
27499 Roo.form.FieldSet = function(config){
27500 Roo.form.FieldSet.superclass.constructor.call(this, config);
27503 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27505 * @cfg {String} legend
27506 * The text to display as the legend for the FieldSet (defaults to '')
27509 * @cfg {String/Object} autoCreate
27510 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27514 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27517 onRender : function(ct, position){
27518 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27520 this.setLegend(this.legend);
27525 setLegend : function(text){
27527 this.el.child('legend').update(text);
27532 * Ext JS Library 1.1.1
27533 * Copyright(c) 2006-2007, Ext JS, LLC.
27535 * Originally Released Under LGPL - original licence link has changed is not relivant.
27538 * <script type="text/javascript">
27541 * @class Roo.form.VTypes
27542 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27545 Roo.form.VTypes = function(){
27546 // closure these in so they are only created once.
27547 var alpha = /^[a-zA-Z_]+$/;
27548 var alphanum = /^[a-zA-Z0-9_]+$/;
27549 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27550 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27552 // All these messages and functions are configurable
27555 * The function used to validate email addresses
27556 * @param {String} value The email address
27558 'email' : function(v){
27559 return email.test(v);
27562 * The error text to display when the email validation function returns false
27565 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27567 * The keystroke filter mask to be applied on email input
27570 'emailMask' : /[a-z0-9_\.\-@]/i,
27573 * The function used to validate URLs
27574 * @param {String} value The URL
27576 'url' : function(v){
27577 return url.test(v);
27580 * The error text to display when the url validation function returns false
27583 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27586 * The function used to validate alpha values
27587 * @param {String} value The value
27589 'alpha' : function(v){
27590 return alpha.test(v);
27593 * The error text to display when the alpha validation function returns false
27596 'alphaText' : 'This field should only contain letters and _',
27598 * The keystroke filter mask to be applied on alpha input
27601 'alphaMask' : /[a-z_]/i,
27604 * The function used to validate alphanumeric values
27605 * @param {String} value The value
27607 'alphanum' : function(v){
27608 return alphanum.test(v);
27611 * The error text to display when the alphanumeric validation function returns false
27614 'alphanumText' : 'This field should only contain letters, numbers and _',
27616 * The keystroke filter mask to be applied on alphanumeric input
27619 'alphanumMask' : /[a-z0-9_]/i
27621 }();//<script type="text/javascript">
27624 * @class Roo.form.FCKeditor
27625 * @extends Roo.form.TextArea
27626 * Wrapper around the FCKEditor http://www.fckeditor.net
27628 * Creates a new FCKeditor
27629 * @param {Object} config Configuration options
27631 Roo.form.FCKeditor = function(config){
27632 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27635 * @event editorinit
27636 * Fired when the editor is initialized - you can add extra handlers here..
27637 * @param {FCKeditor} this
27638 * @param {Object} the FCK object.
27645 Roo.form.FCKeditor.editors = { };
27646 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27648 //defaultAutoCreate : {
27649 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27653 * @cfg {Object} fck options - see fck manual for details.
27658 * @cfg {Object} fck toolbar set (Basic or Default)
27660 toolbarSet : 'Basic',
27662 * @cfg {Object} fck BasePath
27664 basePath : '/fckeditor/',
27672 onRender : function(ct, position)
27675 this.defaultAutoCreate = {
27677 style:"width:300px;height:60px;",
27678 autocomplete: "off"
27681 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27684 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27685 if(this.preventScrollbars){
27686 this.el.setStyle("overflow", "hidden");
27688 this.el.setHeight(this.growMin);
27691 //console.log('onrender' + this.getId() );
27692 Roo.form.FCKeditor.editors[this.getId()] = this;
27695 this.replaceTextarea() ;
27699 getEditor : function() {
27700 return this.fckEditor;
27703 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27704 * @param {Mixed} value The value to set
27708 setValue : function(value)
27710 //console.log('setValue: ' + value);
27712 if(typeof(value) == 'undefined') { // not sure why this is happending...
27715 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27717 //if(!this.el || !this.getEditor()) {
27718 // this.value = value;
27719 //this.setValue.defer(100,this,[value]);
27723 if(!this.getEditor()) {
27727 this.getEditor().SetData(value);
27734 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27735 * @return {Mixed} value The field value
27737 getValue : function()
27740 if (this.frame && this.frame.dom.style.display == 'none') {
27741 return Roo.form.FCKeditor.superclass.getValue.call(this);
27744 if(!this.el || !this.getEditor()) {
27746 // this.getValue.defer(100,this);
27751 var value=this.getEditor().GetData();
27752 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27753 return Roo.form.FCKeditor.superclass.getValue.call(this);
27759 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27760 * @return {Mixed} value The field value
27762 getRawValue : function()
27764 if (this.frame && this.frame.dom.style.display == 'none') {
27765 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27768 if(!this.el || !this.getEditor()) {
27769 //this.getRawValue.defer(100,this);
27776 var value=this.getEditor().GetData();
27777 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27778 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27782 setSize : function(w,h) {
27786 //if (this.frame && this.frame.dom.style.display == 'none') {
27787 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27790 //if(!this.el || !this.getEditor()) {
27791 // this.setSize.defer(100,this, [w,h]);
27797 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27799 this.frame.dom.setAttribute('width', w);
27800 this.frame.dom.setAttribute('height', h);
27801 this.frame.setSize(w,h);
27805 toggleSourceEdit : function(value) {
27809 this.el.dom.style.display = value ? '' : 'none';
27810 this.frame.dom.style.display = value ? 'none' : '';
27815 focus: function(tag)
27817 if (this.frame.dom.style.display == 'none') {
27818 return Roo.form.FCKeditor.superclass.focus.call(this);
27820 if(!this.el || !this.getEditor()) {
27821 this.focus.defer(100,this, [tag]);
27828 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27829 this.getEditor().Focus();
27831 if (!this.getEditor().Selection.GetSelection()) {
27832 this.focus.defer(100,this, [tag]);
27837 var r = this.getEditor().EditorDocument.createRange();
27838 r.setStart(tgs[0],0);
27839 r.setEnd(tgs[0],0);
27840 this.getEditor().Selection.GetSelection().removeAllRanges();
27841 this.getEditor().Selection.GetSelection().addRange(r);
27842 this.getEditor().Focus();
27849 replaceTextarea : function()
27851 if ( document.getElementById( this.getId() + '___Frame' ) )
27853 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27855 // We must check the elements firstly using the Id and then the name.
27856 var oTextarea = document.getElementById( this.getId() );
27858 var colElementsByName = document.getElementsByName( this.getId() ) ;
27860 oTextarea.style.display = 'none' ;
27862 if ( oTextarea.tabIndex ) {
27863 this.TabIndex = oTextarea.tabIndex ;
27866 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27867 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27868 this.frame = Roo.get(this.getId() + '___Frame')
27871 _getConfigHtml : function()
27875 for ( var o in this.fckconfig ) {
27876 sConfig += sConfig.length > 0 ? '&' : '';
27877 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27880 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27884 _getIFrameHtml : function()
27886 var sFile = 'fckeditor.html' ;
27887 /* no idea what this is about..
27890 if ( (/fcksource=true/i).test( window.top.location.search ) )
27891 sFile = 'fckeditor.original.html' ;
27896 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27897 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27900 var html = '<iframe id="' + this.getId() +
27901 '___Frame" src="' + sLink +
27902 '" width="' + this.width +
27903 '" height="' + this.height + '"' +
27904 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27905 ' frameborder="0" scrolling="no"></iframe>' ;
27910 _insertHtmlBefore : function( html, element )
27912 if ( element.insertAdjacentHTML ) {
27914 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27916 var oRange = document.createRange() ;
27917 oRange.setStartBefore( element ) ;
27918 var oFragment = oRange.createContextualFragment( html );
27919 element.parentNode.insertBefore( oFragment, element ) ;
27932 //Roo.reg('fckeditor', Roo.form.FCKeditor);
27934 function FCKeditor_OnComplete(editorInstance){
27935 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
27936 f.fckEditor = editorInstance;
27937 //console.log("loaded");
27938 f.fireEvent('editorinit', f, editorInstance);
27958 //<script type="text/javascript">
27960 * @class Roo.form.GridField
27961 * @extends Roo.form.Field
27962 * Embed a grid (or editable grid into a form)
27965 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
27967 * xgrid.store = Roo.data.Store
27968 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
27969 * xgrid.store.reader = Roo.data.JsonReader
27973 * Creates a new GridField
27974 * @param {Object} config Configuration options
27976 Roo.form.GridField = function(config){
27977 Roo.form.GridField.superclass.constructor.call(this, config);
27981 Roo.extend(Roo.form.GridField, Roo.form.Field, {
27983 * @cfg {Number} width - used to restrict width of grid..
27987 * @cfg {Number} height - used to restrict height of grid..
27991 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
27997 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
27998 * {tag: "input", type: "checkbox", autocomplete: "off"})
28000 // defaultAutoCreate : { tag: 'div' },
28001 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28003 * @cfg {String} addTitle Text to include for adding a title.
28007 onResize : function(){
28008 Roo.form.Field.superclass.onResize.apply(this, arguments);
28011 initEvents : function(){
28012 // Roo.form.Checkbox.superclass.initEvents.call(this);
28013 // has no events...
28018 getResizeEl : function(){
28022 getPositionEl : function(){
28027 onRender : function(ct, position){
28029 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28030 var style = this.style;
28033 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28034 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28035 this.viewEl = this.wrap.createChild({ tag: 'div' });
28037 this.viewEl.applyStyles(style);
28040 this.viewEl.setWidth(this.width);
28043 this.viewEl.setHeight(this.height);
28045 //if(this.inputValue !== undefined){
28046 //this.setValue(this.value);
28049 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28052 this.grid.render();
28053 this.grid.getDataSource().on('remove', this.refreshValue, this);
28054 this.grid.getDataSource().on('update', this.refreshValue, this);
28055 this.grid.on('afteredit', this.refreshValue, this);
28061 * Sets the value of the item.
28062 * @param {String} either an object or a string..
28064 setValue : function(v){
28066 v = v || []; // empty set..
28067 // this does not seem smart - it really only affects memoryproxy grids..
28068 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28069 var ds = this.grid.getDataSource();
28070 // assumes a json reader..
28072 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28073 ds.loadData( data);
28075 Roo.form.GridField.superclass.setValue.call(this, v);
28076 this.refreshValue();
28077 // should load data in the grid really....
28081 refreshValue: function() {
28083 this.grid.getDataSource().each(function(r) {
28086 this.el.dom.value = Roo.encode(val);
28094 * Ext JS Library 1.1.1
28095 * Copyright(c) 2006-2007, Ext JS, LLC.
28097 * Originally Released Under LGPL - original licence link has changed is not relivant.
28100 * <script type="text/javascript">
28103 * @class Roo.form.DisplayField
28104 * @extends Roo.form.Field
28105 * A generic Field to display non-editable data.
28107 * Creates a new Display Field item.
28108 * @param {Object} config Configuration options
28110 Roo.form.DisplayField = function(config){
28111 Roo.form.DisplayField.superclass.constructor.call(this, config);
28115 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28116 inputType: 'hidden',
28122 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28124 focusClass : undefined,
28126 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28128 fieldClass: 'x-form-field',
28131 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28133 valueRenderer: undefined,
28137 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28138 * {tag: "input", type: "checkbox", autocomplete: "off"})
28141 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28143 onResize : function(){
28144 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28148 initEvents : function(){
28149 // Roo.form.Checkbox.superclass.initEvents.call(this);
28150 // has no events...
28155 getResizeEl : function(){
28159 getPositionEl : function(){
28164 onRender : function(ct, position){
28166 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28167 //if(this.inputValue !== undefined){
28168 this.wrap = this.el.wrap();
28170 this.viewEl = this.wrap.createChild({ tag: 'div'});
28172 if (this.bodyStyle) {
28173 this.viewEl.applyStyles(this.bodyStyle);
28175 //this.viewEl.setStyle('padding', '2px');
28177 this.setValue(this.value);
28182 initValue : Roo.emptyFn,
28187 onClick : function(){
28192 * Sets the checked state of the checkbox.
28193 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28195 setValue : function(v){
28197 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28198 // this might be called before we have a dom element..
28199 if (!this.viewEl) {
28202 this.viewEl.dom.innerHTML = html;
28203 Roo.form.DisplayField.superclass.setValue.call(this, v);
28206 });//<script type="text/javasscript">
28210 * @class Roo.DDView
28211 * A DnD enabled version of Roo.View.
28212 * @param {Element/String} container The Element in which to create the View.
28213 * @param {String} tpl The template string used to create the markup for each element of the View
28214 * @param {Object} config The configuration properties. These include all the config options of
28215 * {@link Roo.View} plus some specific to this class.<br>
28217 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28218 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28220 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28221 .x-view-drag-insert-above {
28222 border-top:1px dotted #3366cc;
28224 .x-view-drag-insert-below {
28225 border-bottom:1px dotted #3366cc;
28231 Roo.DDView = function(container, tpl, config) {
28232 Roo.DDView.superclass.constructor.apply(this, arguments);
28233 this.getEl().setStyle("outline", "0px none");
28234 this.getEl().unselectable();
28235 if (this.dragGroup) {
28236 this.setDraggable(this.dragGroup.split(","));
28238 if (this.dropGroup) {
28239 this.setDroppable(this.dropGroup.split(","));
28241 if (this.deletable) {
28242 this.setDeletable();
28244 this.isDirtyFlag = false;
28250 Roo.extend(Roo.DDView, Roo.View, {
28251 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28252 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28253 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28254 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28258 reset: Roo.emptyFn,
28260 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28262 validate: function() {
28266 destroy: function() {
28267 this.purgeListeners();
28268 this.getEl.removeAllListeners();
28269 this.getEl().remove();
28270 if (this.dragZone) {
28271 if (this.dragZone.destroy) {
28272 this.dragZone.destroy();
28275 if (this.dropZone) {
28276 if (this.dropZone.destroy) {
28277 this.dropZone.destroy();
28282 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28283 getName: function() {
28287 /** Loads the View from a JSON string representing the Records to put into the Store. */
28288 setValue: function(v) {
28290 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28293 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28294 this.store.proxy = new Roo.data.MemoryProxy(data);
28298 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28299 getValue: function() {
28301 this.store.each(function(rec) {
28302 result += rec.id + ',';
28304 return result.substr(0, result.length - 1) + ')';
28307 getIds: function() {
28308 var i = 0, result = new Array(this.store.getCount());
28309 this.store.each(function(rec) {
28310 result[i++] = rec.id;
28315 isDirty: function() {
28316 return this.isDirtyFlag;
28320 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28321 * whole Element becomes the target, and this causes the drop gesture to append.
28323 getTargetFromEvent : function(e) {
28324 var target = e.getTarget();
28325 while ((target !== null) && (target.parentNode != this.el.dom)) {
28326 target = target.parentNode;
28329 target = this.el.dom.lastChild || this.el.dom;
28335 * Create the drag data which consists of an object which has the property "ddel" as
28336 * the drag proxy element.
28338 getDragData : function(e) {
28339 var target = this.findItemFromChild(e.getTarget());
28341 this.handleSelection(e);
28342 var selNodes = this.getSelectedNodes();
28345 copy: this.copy || (this.allowCopy && e.ctrlKey),
28349 var selectedIndices = this.getSelectedIndexes();
28350 for (var i = 0; i < selectedIndices.length; i++) {
28351 dragData.records.push(this.store.getAt(selectedIndices[i]));
28353 if (selNodes.length == 1) {
28354 dragData.ddel = target.cloneNode(true); // the div element
28356 var div = document.createElement('div'); // create the multi element drag "ghost"
28357 div.className = 'multi-proxy';
28358 for (var i = 0, len = selNodes.length; i < len; i++) {
28359 div.appendChild(selNodes[i].cloneNode(true));
28361 dragData.ddel = div;
28363 //console.log(dragData)
28364 //console.log(dragData.ddel.innerHTML)
28367 //console.log('nodragData')
28371 /** Specify to which ddGroup items in this DDView may be dragged. */
28372 setDraggable: function(ddGroup) {
28373 if (ddGroup instanceof Array) {
28374 Roo.each(ddGroup, this.setDraggable, this);
28377 if (this.dragZone) {
28378 this.dragZone.addToGroup(ddGroup);
28380 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28381 containerScroll: true,
28385 // Draggability implies selection. DragZone's mousedown selects the element.
28386 if (!this.multiSelect) { this.singleSelect = true; }
28388 // Wire the DragZone's handlers up to methods in *this*
28389 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28393 /** Specify from which ddGroup this DDView accepts drops. */
28394 setDroppable: function(ddGroup) {
28395 if (ddGroup instanceof Array) {
28396 Roo.each(ddGroup, this.setDroppable, this);
28399 if (this.dropZone) {
28400 this.dropZone.addToGroup(ddGroup);
28402 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28403 containerScroll: true,
28407 // Wire the DropZone's handlers up to methods in *this*
28408 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28409 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28410 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28411 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28412 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28416 /** Decide whether to drop above or below a View node. */
28417 getDropPoint : function(e, n, dd){
28418 if (n == this.el.dom) { return "above"; }
28419 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28420 var c = t + (b - t) / 2;
28421 var y = Roo.lib.Event.getPageY(e);
28429 onNodeEnter : function(n, dd, e, data){
28433 onNodeOver : function(n, dd, e, data){
28434 var pt = this.getDropPoint(e, n, dd);
28435 // set the insert point style on the target node
28436 var dragElClass = this.dropNotAllowed;
28439 if (pt == "above"){
28440 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28441 targetElClass = "x-view-drag-insert-above";
28443 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28444 targetElClass = "x-view-drag-insert-below";
28446 if (this.lastInsertClass != targetElClass){
28447 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28448 this.lastInsertClass = targetElClass;
28451 return dragElClass;
28454 onNodeOut : function(n, dd, e, data){
28455 this.removeDropIndicators(n);
28458 onNodeDrop : function(n, dd, e, data){
28459 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28462 var pt = this.getDropPoint(e, n, dd);
28463 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28464 if (pt == "below") { insertAt++; }
28465 for (var i = 0; i < data.records.length; i++) {
28466 var r = data.records[i];
28467 var dup = this.store.getById(r.id);
28468 if (dup && (dd != this.dragZone)) {
28469 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28472 this.store.insert(insertAt++, r.copy());
28474 data.source.isDirtyFlag = true;
28476 this.store.insert(insertAt++, r);
28478 this.isDirtyFlag = true;
28481 this.dragZone.cachedTarget = null;
28485 removeDropIndicators : function(n){
28487 Roo.fly(n).removeClass([
28488 "x-view-drag-insert-above",
28489 "x-view-drag-insert-below"]);
28490 this.lastInsertClass = "_noclass";
28495 * Utility method. Add a delete option to the DDView's context menu.
28496 * @param {String} imageUrl The URL of the "delete" icon image.
28498 setDeletable: function(imageUrl) {
28499 if (!this.singleSelect && !this.multiSelect) {
28500 this.singleSelect = true;
28502 var c = this.getContextMenu();
28503 this.contextMenu.on("itemclick", function(item) {
28506 this.remove(this.getSelectedIndexes());
28510 this.contextMenu.add({
28517 /** Return the context menu for this DDView. */
28518 getContextMenu: function() {
28519 if (!this.contextMenu) {
28520 // Create the View's context menu
28521 this.contextMenu = new Roo.menu.Menu({
28522 id: this.id + "-contextmenu"
28524 this.el.on("contextmenu", this.showContextMenu, this);
28526 return this.contextMenu;
28529 disableContextMenu: function() {
28530 if (this.contextMenu) {
28531 this.el.un("contextmenu", this.showContextMenu, this);
28535 showContextMenu: function(e, item) {
28536 item = this.findItemFromChild(e.getTarget());
28539 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28540 this.contextMenu.showAt(e.getXY());
28545 * Remove {@link Roo.data.Record}s at the specified indices.
28546 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28548 remove: function(selectedIndices) {
28549 selectedIndices = [].concat(selectedIndices);
28550 for (var i = 0; i < selectedIndices.length; i++) {
28551 var rec = this.store.getAt(selectedIndices[i]);
28552 this.store.remove(rec);
28557 * Double click fires the event, but also, if this is draggable, and there is only one other
28558 * related DropZone, it transfers the selected node.
28560 onDblClick : function(e){
28561 var item = this.findItemFromChild(e.getTarget());
28563 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28566 if (this.dragGroup) {
28567 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28568 while (targets.indexOf(this.dropZone) > -1) {
28569 targets.remove(this.dropZone);
28571 if (targets.length == 1) {
28572 this.dragZone.cachedTarget = null;
28573 var el = Roo.get(targets[0].getEl());
28574 var box = el.getBox(true);
28575 targets[0].onNodeDrop(el.dom, {
28577 xy: [box.x, box.y + box.height - 1]
28578 }, null, this.getDragData(e));
28584 handleSelection: function(e) {
28585 this.dragZone.cachedTarget = null;
28586 var item = this.findItemFromChild(e.getTarget());
28588 this.clearSelections(true);
28591 if (item && (this.multiSelect || this.singleSelect)){
28592 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28593 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28594 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28595 this.unselect(item);
28597 this.select(item, this.multiSelect && e.ctrlKey);
28598 this.lastSelection = item;
28603 onItemClick : function(item, index, e){
28604 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28610 unselect : function(nodeInfo, suppressEvent){
28611 var node = this.getNode(nodeInfo);
28612 if(node && this.isSelected(node)){
28613 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28614 Roo.fly(node).removeClass(this.selectedClass);
28615 this.selections.remove(node);
28616 if(!suppressEvent){
28617 this.fireEvent("selectionchange", this, this.selections);
28625 * Ext JS Library 1.1.1
28626 * Copyright(c) 2006-2007, Ext JS, LLC.
28628 * Originally Released Under LGPL - original licence link has changed is not relivant.
28631 * <script type="text/javascript">
28635 * @class Roo.LayoutManager
28636 * @extends Roo.util.Observable
28637 * Base class for layout managers.
28639 Roo.LayoutManager = function(container, config){
28640 Roo.LayoutManager.superclass.constructor.call(this);
28641 this.el = Roo.get(container);
28642 // ie scrollbar fix
28643 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28644 document.body.scroll = "no";
28645 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28646 this.el.position('relative');
28648 this.id = this.el.id;
28649 this.el.addClass("x-layout-container");
28650 /** false to disable window resize monitoring @type Boolean */
28651 this.monitorWindowResize = true;
28656 * Fires when a layout is performed.
28657 * @param {Roo.LayoutManager} this
28661 * @event regionresized
28662 * Fires when the user resizes a region.
28663 * @param {Roo.LayoutRegion} region The resized region
28664 * @param {Number} newSize The new size (width for east/west, height for north/south)
28666 "regionresized" : true,
28668 * @event regioncollapsed
28669 * Fires when a region is collapsed.
28670 * @param {Roo.LayoutRegion} region The collapsed region
28672 "regioncollapsed" : true,
28674 * @event regionexpanded
28675 * Fires when a region is expanded.
28676 * @param {Roo.LayoutRegion} region The expanded region
28678 "regionexpanded" : true
28680 this.updating = false;
28681 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28684 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28686 * Returns true if this layout is currently being updated
28687 * @return {Boolean}
28689 isUpdating : function(){
28690 return this.updating;
28694 * Suspend the LayoutManager from doing auto-layouts while
28695 * making multiple add or remove calls
28697 beginUpdate : function(){
28698 this.updating = true;
28702 * Restore auto-layouts and optionally disable the manager from performing a layout
28703 * @param {Boolean} noLayout true to disable a layout update
28705 endUpdate : function(noLayout){
28706 this.updating = false;
28712 layout: function(){
28716 onRegionResized : function(region, newSize){
28717 this.fireEvent("regionresized", region, newSize);
28721 onRegionCollapsed : function(region){
28722 this.fireEvent("regioncollapsed", region);
28725 onRegionExpanded : function(region){
28726 this.fireEvent("regionexpanded", region);
28730 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28731 * performs box-model adjustments.
28732 * @return {Object} The size as an object {width: (the width), height: (the height)}
28734 getViewSize : function(){
28736 if(this.el.dom != document.body){
28737 size = this.el.getSize();
28739 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28741 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28742 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28747 * Returns the Element this layout is bound to.
28748 * @return {Roo.Element}
28750 getEl : function(){
28755 * Returns the specified region.
28756 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
28757 * @return {Roo.LayoutRegion}
28759 getRegion : function(target){
28760 return this.regions[target.toLowerCase()];
28763 onWindowResize : function(){
28764 if(this.monitorWindowResize){
28770 * Ext JS Library 1.1.1
28771 * Copyright(c) 2006-2007, Ext JS, LLC.
28773 * Originally Released Under LGPL - original licence link has changed is not relivant.
28776 * <script type="text/javascript">
28779 * @class Roo.BorderLayout
28780 * @extends Roo.LayoutManager
28781 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
28782 * please see: <br><br>
28783 * <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>
28784 * <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>
28787 var layout = new Roo.BorderLayout(document.body, {
28821 preferredTabWidth: 150
28826 var CP = Roo.ContentPanel;
28828 layout.beginUpdate();
28829 layout.add("north", new CP("north", "North"));
28830 layout.add("south", new CP("south", {title: "South", closable: true}));
28831 layout.add("west", new CP("west", {title: "West"}));
28832 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
28833 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
28834 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
28835 layout.getRegion("center").showPanel("center1");
28836 layout.endUpdate();
28839 <b>The container the layout is rendered into can be either the body element or any other element.
28840 If it is not the body element, the container needs to either be an absolute positioned element,
28841 or you will need to add "position:relative" to the css of the container. You will also need to specify
28842 the container size if it is not the body element.</b>
28845 * Create a new BorderLayout
28846 * @param {String/HTMLElement/Element} container The container this layout is bound to
28847 * @param {Object} config Configuration options
28849 Roo.BorderLayout = function(container, config){
28850 config = config || {};
28851 Roo.BorderLayout.superclass.constructor.call(this, container, config);
28852 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
28853 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
28854 var target = this.factory.validRegions[i];
28855 if(config[target]){
28856 this.addRegion(target, config[target]);
28861 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
28863 * Creates and adds a new region if it doesn't already exist.
28864 * @param {String} target The target region key (north, south, east, west or center).
28865 * @param {Object} config The regions config object
28866 * @return {BorderLayoutRegion} The new region
28868 addRegion : function(target, config){
28869 if(!this.regions[target]){
28870 var r = this.factory.create(target, this, config);
28871 this.bindRegion(target, r);
28873 return this.regions[target];
28877 bindRegion : function(name, r){
28878 this.regions[name] = r;
28879 r.on("visibilitychange", this.layout, this);
28880 r.on("paneladded", this.layout, this);
28881 r.on("panelremoved", this.layout, this);
28882 r.on("invalidated", this.layout, this);
28883 r.on("resized", this.onRegionResized, this);
28884 r.on("collapsed", this.onRegionCollapsed, this);
28885 r.on("expanded", this.onRegionExpanded, this);
28889 * Performs a layout update.
28891 layout : function(){
28892 if(this.updating) return;
28893 var size = this.getViewSize();
28894 var w = size.width;
28895 var h = size.height;
28900 //var x = 0, y = 0;
28902 var rs = this.regions;
28903 var north = rs["north"];
28904 var south = rs["south"];
28905 var west = rs["west"];
28906 var east = rs["east"];
28907 var center = rs["center"];
28908 //if(this.hideOnLayout){ // not supported anymore
28909 //c.el.setStyle("display", "none");
28911 if(north && north.isVisible()){
28912 var b = north.getBox();
28913 var m = north.getMargins();
28914 b.width = w - (m.left+m.right);
28917 centerY = b.height + b.y + m.bottom;
28918 centerH -= centerY;
28919 north.updateBox(this.safeBox(b));
28921 if(south && south.isVisible()){
28922 var b = south.getBox();
28923 var m = south.getMargins();
28924 b.width = w - (m.left+m.right);
28926 var totalHeight = (b.height + m.top + m.bottom);
28927 b.y = h - totalHeight + m.top;
28928 centerH -= totalHeight;
28929 south.updateBox(this.safeBox(b));
28931 if(west && west.isVisible()){
28932 var b = west.getBox();
28933 var m = west.getMargins();
28934 b.height = centerH - (m.top+m.bottom);
28936 b.y = centerY + m.top;
28937 var totalWidth = (b.width + m.left + m.right);
28938 centerX += totalWidth;
28939 centerW -= totalWidth;
28940 west.updateBox(this.safeBox(b));
28942 if(east && east.isVisible()){
28943 var b = east.getBox();
28944 var m = east.getMargins();
28945 b.height = centerH - (m.top+m.bottom);
28946 var totalWidth = (b.width + m.left + m.right);
28947 b.x = w - totalWidth + m.left;
28948 b.y = centerY + m.top;
28949 centerW -= totalWidth;
28950 east.updateBox(this.safeBox(b));
28953 var m = center.getMargins();
28955 x: centerX + m.left,
28956 y: centerY + m.top,
28957 width: centerW - (m.left+m.right),
28958 height: centerH - (m.top+m.bottom)
28960 //if(this.hideOnLayout){
28961 //center.el.setStyle("display", "block");
28963 center.updateBox(this.safeBox(centerBox));
28966 this.fireEvent("layout", this);
28970 safeBox : function(box){
28971 box.width = Math.max(0, box.width);
28972 box.height = Math.max(0, box.height);
28977 * Adds a ContentPanel (or subclass) to this layout.
28978 * @param {String} target The target region key (north, south, east, west or center).
28979 * @param {Roo.ContentPanel} panel The panel to add
28980 * @return {Roo.ContentPanel} The added panel
28982 add : function(target, panel){
28984 target = target.toLowerCase();
28985 return this.regions[target].add(panel);
28989 * Remove a ContentPanel (or subclass) to this layout.
28990 * @param {String} target The target region key (north, south, east, west or center).
28991 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
28992 * @return {Roo.ContentPanel} The removed panel
28994 remove : function(target, panel){
28995 target = target.toLowerCase();
28996 return this.regions[target].remove(panel);
29000 * Searches all regions for a panel with the specified id
29001 * @param {String} panelId
29002 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29004 findPanel : function(panelId){
29005 var rs = this.regions;
29006 for(var target in rs){
29007 if(typeof rs[target] != "function"){
29008 var p = rs[target].getPanel(panelId);
29018 * Searches all regions for a panel with the specified id and activates (shows) it.
29019 * @param {String/ContentPanel} panelId The panels id or the panel itself
29020 * @return {Roo.ContentPanel} The shown panel or null
29022 showPanel : function(panelId) {
29023 var rs = this.regions;
29024 for(var target in rs){
29025 var r = rs[target];
29026 if(typeof r != "function"){
29027 if(r.hasPanel(panelId)){
29028 return r.showPanel(panelId);
29036 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29037 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29039 restoreState : function(provider){
29041 provider = Roo.state.Manager;
29043 var sm = new Roo.LayoutStateManager();
29044 sm.init(this, provider);
29048 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29049 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29050 * a valid ContentPanel config object. Example:
29052 // Create the main layout
29053 var layout = new Roo.BorderLayout('main-ct', {
29064 // Create and add multiple ContentPanels at once via configs
29067 id: 'source-files',
29069 title:'Ext Source Files',
29082 * @param {Object} regions An object containing ContentPanel configs by region name
29084 batchAdd : function(regions){
29085 this.beginUpdate();
29086 for(var rname in regions){
29087 var lr = this.regions[rname];
29089 this.addTypedPanels(lr, regions[rname]);
29096 addTypedPanels : function(lr, ps){
29097 if(typeof ps == 'string'){
29098 lr.add(new Roo.ContentPanel(ps));
29100 else if(ps instanceof Array){
29101 for(var i =0, len = ps.length; i < len; i++){
29102 this.addTypedPanels(lr, ps[i]);
29105 else if(!ps.events){ // raw config?
29107 delete ps.el; // prevent conflict
29108 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29110 else { // panel object assumed!
29115 * Adds a xtype elements to the layout.
29119 xtype : 'ContentPanel',
29126 xtype : 'NestedLayoutPanel',
29132 items : [ ... list of content panels or nested layout panels.. ]
29136 * @param {Object} cfg Xtype definition of item to add.
29138 addxtype : function(cfg)
29140 // basically accepts a pannel...
29141 // can accept a layout region..!?!?
29142 // console.log('BorderLayout add ' + cfg.xtype)
29144 if (!cfg.xtype.match(/Panel$/)) {
29148 var region = cfg.region;
29154 xitems = cfg.items;
29161 case 'ContentPanel': // ContentPanel (el, cfg)
29162 case 'ScrollPanel': // ContentPanel (el, cfg)
29163 if(cfg.autoCreate) {
29164 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29166 var el = this.el.createChild();
29167 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29170 this.add(region, ret);
29174 case 'TreePanel': // our new panel!
29175 cfg.el = this.el.createChild();
29176 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29177 this.add(region, ret);
29180 case 'NestedLayoutPanel':
29181 // create a new Layout (which is a Border Layout...
29182 var el = this.el.createChild();
29183 var clayout = cfg.layout;
29185 clayout.items = clayout.items || [];
29186 // replace this exitems with the clayout ones..
29187 xitems = clayout.items;
29190 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29191 cfg.background = false;
29193 var layout = new Roo.BorderLayout(el, clayout);
29195 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29196 //console.log('adding nested layout panel ' + cfg.toSource());
29197 this.add(region, ret);
29203 // needs grid and region
29205 //var el = this.getRegion(region).el.createChild();
29206 var el = this.el.createChild();
29207 // create the grid first...
29209 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29211 if (region == 'center' && this.active ) {
29212 cfg.background = false;
29214 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29216 this.add(region, ret);
29217 if (cfg.background) {
29218 ret.on('activate', function(gp) {
29219 if (!gp.grid.rendered) {
29232 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29234 // GridPanel (grid, cfg)
29237 this.beginUpdate();
29239 Roo.each(xitems, function(i) {
29249 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29250 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29251 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29252 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29255 var CP = Roo.ContentPanel;
29257 var layout = Roo.BorderLayout.create({
29261 panels: [new CP("north", "North")]
29270 panels: [new CP("west", {title: "West"})]
29279 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29288 panels: [new CP("south", {title: "South", closable: true})]
29295 preferredTabWidth: 150,
29297 new CP("center1", {title: "Close Me", closable: true}),
29298 new CP("center2", {title: "Center Panel", closable: false})
29303 layout.getRegion("center").showPanel("center1");
29308 Roo.BorderLayout.create = function(config, targetEl){
29309 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29310 layout.beginUpdate();
29311 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29312 for(var j = 0, jlen = regions.length; j < jlen; j++){
29313 var lr = regions[j];
29314 if(layout.regions[lr] && config[lr].panels){
29315 var r = layout.regions[lr];
29316 var ps = config[lr].panels;
29317 layout.addTypedPanels(r, ps);
29320 layout.endUpdate();
29325 Roo.BorderLayout.RegionFactory = {
29327 validRegions : ["north","south","east","west","center"],
29330 create : function(target, mgr, config){
29331 target = target.toLowerCase();
29332 if(config.lightweight || config.basic){
29333 return new Roo.BasicLayoutRegion(mgr, config, target);
29337 return new Roo.NorthLayoutRegion(mgr, config);
29339 return new Roo.SouthLayoutRegion(mgr, config);
29341 return new Roo.EastLayoutRegion(mgr, config);
29343 return new Roo.WestLayoutRegion(mgr, config);
29345 return new Roo.CenterLayoutRegion(mgr, config);
29347 throw 'Layout region "'+target+'" not supported.';
29351 * Ext JS Library 1.1.1
29352 * Copyright(c) 2006-2007, Ext JS, LLC.
29354 * Originally Released Under LGPL - original licence link has changed is not relivant.
29357 * <script type="text/javascript">
29361 * @class Roo.BasicLayoutRegion
29362 * @extends Roo.util.Observable
29363 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29364 * and does not have a titlebar, tabs or any other features. All it does is size and position
29365 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29367 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29369 this.position = pos;
29372 * @scope Roo.BasicLayoutRegion
29376 * @event beforeremove
29377 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29378 * @param {Roo.LayoutRegion} this
29379 * @param {Roo.ContentPanel} panel The panel
29380 * @param {Object} e The cancel event object
29382 "beforeremove" : true,
29384 * @event invalidated
29385 * Fires when the layout for this region is changed.
29386 * @param {Roo.LayoutRegion} this
29388 "invalidated" : true,
29390 * @event visibilitychange
29391 * Fires when this region is shown or hidden
29392 * @param {Roo.LayoutRegion} this
29393 * @param {Boolean} visibility true or false
29395 "visibilitychange" : true,
29397 * @event paneladded
29398 * Fires when a panel is added.
29399 * @param {Roo.LayoutRegion} this
29400 * @param {Roo.ContentPanel} panel The panel
29402 "paneladded" : true,
29404 * @event panelremoved
29405 * Fires when a panel is removed.
29406 * @param {Roo.LayoutRegion} this
29407 * @param {Roo.ContentPanel} panel The panel
29409 "panelremoved" : true,
29412 * Fires when this region is collapsed.
29413 * @param {Roo.LayoutRegion} this
29415 "collapsed" : true,
29418 * Fires when this region is expanded.
29419 * @param {Roo.LayoutRegion} this
29424 * Fires when this region is slid into view.
29425 * @param {Roo.LayoutRegion} this
29427 "slideshow" : true,
29430 * Fires when this region slides out of view.
29431 * @param {Roo.LayoutRegion} this
29433 "slidehide" : true,
29435 * @event panelactivated
29436 * Fires when a panel is activated.
29437 * @param {Roo.LayoutRegion} this
29438 * @param {Roo.ContentPanel} panel The activated panel
29440 "panelactivated" : true,
29443 * Fires when the user resizes this region.
29444 * @param {Roo.LayoutRegion} this
29445 * @param {Number} newSize The new size (width for east/west, height for north/south)
29449 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29450 this.panels = new Roo.util.MixedCollection();
29451 this.panels.getKey = this.getPanelId.createDelegate(this);
29453 this.activePanel = null;
29454 // ensure listeners are added...
29456 if (config.listeners || config.events) {
29457 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29458 listeners : config.listeners || {},
29459 events : config.events || {}
29463 if(skipConfig !== true){
29464 this.applyConfig(config);
29468 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29469 getPanelId : function(p){
29473 applyConfig : function(config){
29474 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29475 this.config = config;
29480 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29481 * the width, for horizontal (north, south) the height.
29482 * @param {Number} newSize The new width or height
29484 resizeTo : function(newSize){
29485 var el = this.el ? this.el :
29486 (this.activePanel ? this.activePanel.getEl() : null);
29488 switch(this.position){
29491 el.setWidth(newSize);
29492 this.fireEvent("resized", this, newSize);
29496 el.setHeight(newSize);
29497 this.fireEvent("resized", this, newSize);
29503 getBox : function(){
29504 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29507 getMargins : function(){
29508 return this.margins;
29511 updateBox : function(box){
29513 var el = this.activePanel.getEl();
29514 el.dom.style.left = box.x + "px";
29515 el.dom.style.top = box.y + "px";
29516 this.activePanel.setSize(box.width, box.height);
29520 * Returns the container element for this region.
29521 * @return {Roo.Element}
29523 getEl : function(){
29524 return this.activePanel;
29528 * Returns true if this region is currently visible.
29529 * @return {Boolean}
29531 isVisible : function(){
29532 return this.activePanel ? true : false;
29535 setActivePanel : function(panel){
29536 panel = this.getPanel(panel);
29537 if(this.activePanel && this.activePanel != panel){
29538 this.activePanel.setActiveState(false);
29539 this.activePanel.getEl().setLeftTop(-10000,-10000);
29541 this.activePanel = panel;
29542 panel.setActiveState(true);
29544 panel.setSize(this.box.width, this.box.height);
29546 this.fireEvent("panelactivated", this, panel);
29547 this.fireEvent("invalidated");
29551 * Show the specified panel.
29552 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29553 * @return {Roo.ContentPanel} The shown panel or null
29555 showPanel : function(panel){
29556 if(panel = this.getPanel(panel)){
29557 this.setActivePanel(panel);
29563 * Get the active panel for this region.
29564 * @return {Roo.ContentPanel} The active panel or null
29566 getActivePanel : function(){
29567 return this.activePanel;
29571 * Add the passed ContentPanel(s)
29572 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29573 * @return {Roo.ContentPanel} The panel added (if only one was added)
29575 add : function(panel){
29576 if(arguments.length > 1){
29577 for(var i = 0, len = arguments.length; i < len; i++) {
29578 this.add(arguments[i]);
29582 if(this.hasPanel(panel)){
29583 this.showPanel(panel);
29586 var el = panel.getEl();
29587 if(el.dom.parentNode != this.mgr.el.dom){
29588 this.mgr.el.dom.appendChild(el.dom);
29590 if(panel.setRegion){
29591 panel.setRegion(this);
29593 this.panels.add(panel);
29594 el.setStyle("position", "absolute");
29595 if(!panel.background){
29596 this.setActivePanel(panel);
29597 if(this.config.initialSize && this.panels.getCount()==1){
29598 this.resizeTo(this.config.initialSize);
29601 this.fireEvent("paneladded", this, panel);
29606 * Returns true if the panel is in this region.
29607 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29608 * @return {Boolean}
29610 hasPanel : function(panel){
29611 if(typeof panel == "object"){ // must be panel obj
29612 panel = panel.getId();
29614 return this.getPanel(panel) ? true : false;
29618 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29619 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29620 * @param {Boolean} preservePanel Overrides the config preservePanel option
29621 * @return {Roo.ContentPanel} The panel that was removed
29623 remove : function(panel, preservePanel){
29624 panel = this.getPanel(panel);
29629 this.fireEvent("beforeremove", this, panel, e);
29630 if(e.cancel === true){
29633 var panelId = panel.getId();
29634 this.panels.removeKey(panelId);
29639 * Returns the panel specified or null if it's not in this region.
29640 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29641 * @return {Roo.ContentPanel}
29643 getPanel : function(id){
29644 if(typeof id == "object"){ // must be panel obj
29647 return this.panels.get(id);
29651 * Returns this regions position (north/south/east/west/center).
29654 getPosition: function(){
29655 return this.position;
29659 * Ext JS Library 1.1.1
29660 * Copyright(c) 2006-2007, Ext JS, LLC.
29662 * Originally Released Under LGPL - original licence link has changed is not relivant.
29665 * <script type="text/javascript">
29669 * @class Roo.LayoutRegion
29670 * @extends Roo.BasicLayoutRegion
29671 * This class represents a region in a layout manager.
29672 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29673 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29674 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29675 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29676 * @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})
29677 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29678 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29679 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29680 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29681 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29682 * @cfg {String} title The title for the region (overrides panel titles)
29683 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29684 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29685 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29686 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29687 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29688 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29689 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29690 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29691 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29692 * @cfg {Boolean} showPin True to show a pin button
29693 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29694 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29695 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29696 * @cfg {Number} width For East/West panels
29697 * @cfg {Number} height For North/South panels
29698 * @cfg {Boolean} split To show the splitter
29700 Roo.LayoutRegion = function(mgr, config, pos){
29701 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29702 var dh = Roo.DomHelper;
29703 /** This region's container element
29704 * @type Roo.Element */
29705 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29706 /** This region's title element
29707 * @type Roo.Element */
29709 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29710 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29711 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29713 this.titleEl.enableDisplayMode();
29714 /** This region's title text element
29715 * @type HTMLElement */
29716 this.titleTextEl = this.titleEl.dom.firstChild;
29717 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29718 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29719 this.closeBtn.enableDisplayMode();
29720 this.closeBtn.on("click", this.closeClicked, this);
29721 this.closeBtn.hide();
29723 this.createBody(config);
29724 this.visible = true;
29725 this.collapsed = false;
29727 if(config.hideWhenEmpty){
29729 this.on("paneladded", this.validateVisibility, this);
29730 this.on("panelremoved", this.validateVisibility, this);
29732 this.applyConfig(config);
29735 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29737 createBody : function(){
29738 /** This region's body element
29739 * @type Roo.Element */
29740 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29743 applyConfig : function(c){
29744 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29745 var dh = Roo.DomHelper;
29746 if(c.titlebar !== false){
29747 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
29748 this.collapseBtn.on("click", this.collapse, this);
29749 this.collapseBtn.enableDisplayMode();
29751 if(c.showPin === true || this.showPin){
29752 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
29753 this.stickBtn.enableDisplayMode();
29754 this.stickBtn.on("click", this.expand, this);
29755 this.stickBtn.hide();
29758 /** This region's collapsed element
29759 * @type Roo.Element */
29760 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
29761 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
29763 if(c.floatable !== false){
29764 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
29765 this.collapsedEl.on("click", this.collapseClick, this);
29768 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
29769 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
29770 id: "message", unselectable: "on", style:{"float":"left"}});
29771 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
29773 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
29774 this.expandBtn.on("click", this.expand, this);
29776 if(this.collapseBtn){
29777 this.collapseBtn.setVisible(c.collapsible == true);
29779 this.cmargins = c.cmargins || this.cmargins ||
29780 (this.position == "west" || this.position == "east" ?
29781 {top: 0, left: 2, right:2, bottom: 0} :
29782 {top: 2, left: 0, right:0, bottom: 2});
29783 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29784 this.bottomTabs = c.tabPosition != "top";
29785 this.autoScroll = c.autoScroll || false;
29786 if(this.autoScroll){
29787 this.bodyEl.setStyle("overflow", "auto");
29789 this.bodyEl.setStyle("overflow", "hidden");
29791 //if(c.titlebar !== false){
29792 if((!c.titlebar && !c.title) || c.titlebar === false){
29793 this.titleEl.hide();
29795 this.titleEl.show();
29797 this.titleTextEl.innerHTML = c.title;
29801 this.duration = c.duration || .30;
29802 this.slideDuration = c.slideDuration || .45;
29805 this.collapse(true);
29812 * Returns true if this region is currently visible.
29813 * @return {Boolean}
29815 isVisible : function(){
29816 return this.visible;
29820 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
29821 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
29823 setCollapsedTitle : function(title){
29824 title = title || " ";
29825 if(this.collapsedTitleTextEl){
29826 this.collapsedTitleTextEl.innerHTML = title;
29830 getBox : function(){
29832 if(!this.collapsed){
29833 b = this.el.getBox(false, true);
29835 b = this.collapsedEl.getBox(false, true);
29840 getMargins : function(){
29841 return this.collapsed ? this.cmargins : this.margins;
29844 highlight : function(){
29845 this.el.addClass("x-layout-panel-dragover");
29848 unhighlight : function(){
29849 this.el.removeClass("x-layout-panel-dragover");
29852 updateBox : function(box){
29854 if(!this.collapsed){
29855 this.el.dom.style.left = box.x + "px";
29856 this.el.dom.style.top = box.y + "px";
29857 this.updateBody(box.width, box.height);
29859 this.collapsedEl.dom.style.left = box.x + "px";
29860 this.collapsedEl.dom.style.top = box.y + "px";
29861 this.collapsedEl.setSize(box.width, box.height);
29864 this.tabs.autoSizeTabs();
29868 updateBody : function(w, h){
29870 this.el.setWidth(w);
29871 w -= this.el.getBorderWidth("rl");
29872 if(this.config.adjustments){
29873 w += this.config.adjustments[0];
29877 this.el.setHeight(h);
29878 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
29879 h -= this.el.getBorderWidth("tb");
29880 if(this.config.adjustments){
29881 h += this.config.adjustments[1];
29883 this.bodyEl.setHeight(h);
29885 h = this.tabs.syncHeight(h);
29888 if(this.panelSize){
29889 w = w !== null ? w : this.panelSize.width;
29890 h = h !== null ? h : this.panelSize.height;
29892 if(this.activePanel){
29893 var el = this.activePanel.getEl();
29894 w = w !== null ? w : el.getWidth();
29895 h = h !== null ? h : el.getHeight();
29896 this.panelSize = {width: w, height: h};
29897 this.activePanel.setSize(w, h);
29899 if(Roo.isIE && this.tabs){
29900 this.tabs.el.repaint();
29905 * Returns the container element for this region.
29906 * @return {Roo.Element}
29908 getEl : function(){
29913 * Hides this region.
29916 if(!this.collapsed){
29917 this.el.dom.style.left = "-2000px";
29920 this.collapsedEl.dom.style.left = "-2000px";
29921 this.collapsedEl.hide();
29923 this.visible = false;
29924 this.fireEvent("visibilitychange", this, false);
29928 * Shows this region if it was previously hidden.
29931 if(!this.collapsed){
29934 this.collapsedEl.show();
29936 this.visible = true;
29937 this.fireEvent("visibilitychange", this, true);
29940 closeClicked : function(){
29941 if(this.activePanel){
29942 this.remove(this.activePanel);
29946 collapseClick : function(e){
29948 e.stopPropagation();
29951 e.stopPropagation();
29957 * Collapses this region.
29958 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
29960 collapse : function(skipAnim){
29961 if(this.collapsed) return;
29962 this.collapsed = true;
29964 this.split.el.hide();
29966 if(this.config.animate && skipAnim !== true){
29967 this.fireEvent("invalidated", this);
29968 this.animateCollapse();
29970 this.el.setLocation(-20000,-20000);
29972 this.collapsedEl.show();
29973 this.fireEvent("collapsed", this);
29974 this.fireEvent("invalidated", this);
29978 animateCollapse : function(){
29983 * Expands this region if it was previously collapsed.
29984 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
29985 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
29987 expand : function(e, skipAnim){
29988 if(e) e.stopPropagation();
29989 if(!this.collapsed || this.el.hasActiveFx()) return;
29991 this.afterSlideIn();
29994 this.collapsed = false;
29995 if(this.config.animate && skipAnim !== true){
29996 this.animateExpand();
30000 this.split.el.show();
30002 this.collapsedEl.setLocation(-2000,-2000);
30003 this.collapsedEl.hide();
30004 this.fireEvent("invalidated", this);
30005 this.fireEvent("expanded", this);
30009 animateExpand : function(){
30013 initTabs : function(){
30014 this.bodyEl.setStyle("overflow", "hidden");
30015 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30016 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30017 disableTooltips: this.config.disableTabTips
30019 if(this.config.hideTabs){
30020 ts.stripWrap.setDisplayed(false);
30023 ts.resizeTabs = this.config.resizeTabs === true;
30024 ts.minTabWidth = this.config.minTabWidth || 40;
30025 ts.maxTabWidth = this.config.maxTabWidth || 250;
30026 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30027 ts.monitorResize = false;
30028 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30029 ts.bodyEl.addClass('x-layout-tabs-body');
30030 this.panels.each(this.initPanelAsTab, this);
30033 initPanelAsTab : function(panel){
30034 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30035 this.config.closeOnTab && panel.isClosable());
30036 if(panel.tabTip !== undefined){
30037 ti.setTooltip(panel.tabTip);
30039 ti.on("activate", function(){
30040 this.setActivePanel(panel);
30042 if(this.config.closeOnTab){
30043 ti.on("beforeclose", function(t, e){
30045 this.remove(panel);
30051 updatePanelTitle : function(panel, title){
30052 if(this.activePanel == panel){
30053 this.updateTitle(title);
30056 var ti = this.tabs.getTab(panel.getEl().id);
30058 if(panel.tabTip !== undefined){
30059 ti.setTooltip(panel.tabTip);
30064 updateTitle : function(title){
30065 if(this.titleTextEl && !this.config.title){
30066 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30070 setActivePanel : function(panel){
30071 panel = this.getPanel(panel);
30072 if(this.activePanel && this.activePanel != panel){
30073 this.activePanel.setActiveState(false);
30075 this.activePanel = panel;
30076 panel.setActiveState(true);
30077 if(this.panelSize){
30078 panel.setSize(this.panelSize.width, this.panelSize.height);
30081 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30083 this.updateTitle(panel.getTitle());
30085 this.fireEvent("invalidated", this);
30087 this.fireEvent("panelactivated", this, panel);
30091 * Shows the specified panel.
30092 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30093 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30095 showPanel : function(panel){
30096 if(panel = this.getPanel(panel)){
30098 var tab = this.tabs.getTab(panel.getEl().id);
30099 if(tab.isHidden()){
30100 this.tabs.unhideTab(tab.id);
30104 this.setActivePanel(panel);
30111 * Get the active panel for this region.
30112 * @return {Roo.ContentPanel} The active panel or null
30114 getActivePanel : function(){
30115 return this.activePanel;
30118 validateVisibility : function(){
30119 if(this.panels.getCount() < 1){
30120 this.updateTitle(" ");
30121 this.closeBtn.hide();
30124 if(!this.isVisible()){
30131 * Adds the passed ContentPanel(s) to this region.
30132 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30133 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30135 add : function(panel){
30136 if(arguments.length > 1){
30137 for(var i = 0, len = arguments.length; i < len; i++) {
30138 this.add(arguments[i]);
30142 if(this.hasPanel(panel)){
30143 this.showPanel(panel);
30146 panel.setRegion(this);
30147 this.panels.add(panel);
30148 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30149 this.bodyEl.dom.appendChild(panel.getEl().dom);
30150 if(panel.background !== true){
30151 this.setActivePanel(panel);
30153 this.fireEvent("paneladded", this, panel);
30159 this.initPanelAsTab(panel);
30161 if(panel.background !== true){
30162 this.tabs.activate(panel.getEl().id);
30164 this.fireEvent("paneladded", this, panel);
30169 * Hides the tab for the specified panel.
30170 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30172 hidePanel : function(panel){
30173 if(this.tabs && (panel = this.getPanel(panel))){
30174 this.tabs.hideTab(panel.getEl().id);
30179 * Unhides the tab for a previously hidden panel.
30180 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30182 unhidePanel : function(panel){
30183 if(this.tabs && (panel = this.getPanel(panel))){
30184 this.tabs.unhideTab(panel.getEl().id);
30188 clearPanels : function(){
30189 while(this.panels.getCount() > 0){
30190 this.remove(this.panels.first());
30195 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30196 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30197 * @param {Boolean} preservePanel Overrides the config preservePanel option
30198 * @return {Roo.ContentPanel} The panel that was removed
30200 remove : function(panel, preservePanel){
30201 panel = this.getPanel(panel);
30206 this.fireEvent("beforeremove", this, panel, e);
30207 if(e.cancel === true){
30210 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30211 var panelId = panel.getId();
30212 this.panels.removeKey(panelId);
30214 document.body.appendChild(panel.getEl().dom);
30217 this.tabs.removeTab(panel.getEl().id);
30218 }else if (!preservePanel){
30219 this.bodyEl.dom.removeChild(panel.getEl().dom);
30221 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30222 var p = this.panels.first();
30223 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30224 tempEl.appendChild(p.getEl().dom);
30225 this.bodyEl.update("");
30226 this.bodyEl.dom.appendChild(p.getEl().dom);
30228 this.updateTitle(p.getTitle());
30230 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30231 this.setActivePanel(p);
30233 panel.setRegion(null);
30234 if(this.activePanel == panel){
30235 this.activePanel = null;
30237 if(this.config.autoDestroy !== false && preservePanel !== true){
30238 try{panel.destroy();}catch(e){}
30240 this.fireEvent("panelremoved", this, panel);
30245 * Returns the TabPanel component used by this region
30246 * @return {Roo.TabPanel}
30248 getTabs : function(){
30252 createTool : function(parentEl, className){
30253 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30254 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30255 btn.addClassOnOver("x-layout-tools-button-over");
30260 * Ext JS Library 1.1.1
30261 * Copyright(c) 2006-2007, Ext JS, LLC.
30263 * Originally Released Under LGPL - original licence link has changed is not relivant.
30266 * <script type="text/javascript">
30272 * @class Roo.SplitLayoutRegion
30273 * @extends Roo.LayoutRegion
30274 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30276 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30277 this.cursor = cursor;
30278 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30281 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30282 splitTip : "Drag to resize.",
30283 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30284 useSplitTips : false,
30286 applyConfig : function(config){
30287 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30290 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30291 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30292 /** The SplitBar for this region
30293 * @type Roo.SplitBar */
30294 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30295 this.split.on("moved", this.onSplitMove, this);
30296 this.split.useShim = config.useShim === true;
30297 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30298 if(this.useSplitTips){
30299 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30301 if(config.collapsible){
30302 this.split.el.on("dblclick", this.collapse, this);
30305 if(typeof config.minSize != "undefined"){
30306 this.split.minSize = config.minSize;
30308 if(typeof config.maxSize != "undefined"){
30309 this.split.maxSize = config.maxSize;
30311 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30312 this.hideSplitter();
30317 getHMaxSize : function(){
30318 var cmax = this.config.maxSize || 10000;
30319 var center = this.mgr.getRegion("center");
30320 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30323 getVMaxSize : function(){
30324 var cmax = this.config.maxSize || 10000;
30325 var center = this.mgr.getRegion("center");
30326 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30329 onSplitMove : function(split, newSize){
30330 this.fireEvent("resized", this, newSize);
30334 * Returns the {@link Roo.SplitBar} for this region.
30335 * @return {Roo.SplitBar}
30337 getSplitBar : function(){
30342 this.hideSplitter();
30343 Roo.SplitLayoutRegion.superclass.hide.call(this);
30346 hideSplitter : function(){
30348 this.split.el.setLocation(-2000,-2000);
30349 this.split.el.hide();
30355 this.split.el.show();
30357 Roo.SplitLayoutRegion.superclass.show.call(this);
30360 beforeSlide: function(){
30361 if(Roo.isGecko){// firefox overflow auto bug workaround
30362 this.bodyEl.clip();
30363 if(this.tabs) this.tabs.bodyEl.clip();
30364 if(this.activePanel){
30365 this.activePanel.getEl().clip();
30367 if(this.activePanel.beforeSlide){
30368 this.activePanel.beforeSlide();
30374 afterSlide : function(){
30375 if(Roo.isGecko){// firefox overflow auto bug workaround
30376 this.bodyEl.unclip();
30377 if(this.tabs) this.tabs.bodyEl.unclip();
30378 if(this.activePanel){
30379 this.activePanel.getEl().unclip();
30380 if(this.activePanel.afterSlide){
30381 this.activePanel.afterSlide();
30387 initAutoHide : function(){
30388 if(this.autoHide !== false){
30389 if(!this.autoHideHd){
30390 var st = new Roo.util.DelayedTask(this.slideIn, this);
30391 this.autoHideHd = {
30392 "mouseout": function(e){
30393 if(!e.within(this.el, true)){
30397 "mouseover" : function(e){
30403 this.el.on(this.autoHideHd);
30407 clearAutoHide : function(){
30408 if(this.autoHide !== false){
30409 this.el.un("mouseout", this.autoHideHd.mouseout);
30410 this.el.un("mouseover", this.autoHideHd.mouseover);
30414 clearMonitor : function(){
30415 Roo.get(document).un("click", this.slideInIf, this);
30418 // these names are backwards but not changed for compat
30419 slideOut : function(){
30420 if(this.isSlid || this.el.hasActiveFx()){
30423 this.isSlid = true;
30424 if(this.collapseBtn){
30425 this.collapseBtn.hide();
30427 this.closeBtnState = this.closeBtn.getStyle('display');
30428 this.closeBtn.hide();
30430 this.stickBtn.show();
30433 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30434 this.beforeSlide();
30435 this.el.setStyle("z-index", 10001);
30436 this.el.slideIn(this.getSlideAnchor(), {
30437 callback: function(){
30439 this.initAutoHide();
30440 Roo.get(document).on("click", this.slideInIf, this);
30441 this.fireEvent("slideshow", this);
30448 afterSlideIn : function(){
30449 this.clearAutoHide();
30450 this.isSlid = false;
30451 this.clearMonitor();
30452 this.el.setStyle("z-index", "");
30453 if(this.collapseBtn){
30454 this.collapseBtn.show();
30456 this.closeBtn.setStyle('display', this.closeBtnState);
30458 this.stickBtn.hide();
30460 this.fireEvent("slidehide", this);
30463 slideIn : function(cb){
30464 if(!this.isSlid || this.el.hasActiveFx()){
30468 this.isSlid = false;
30469 this.beforeSlide();
30470 this.el.slideOut(this.getSlideAnchor(), {
30471 callback: function(){
30472 this.el.setLeftTop(-10000, -10000);
30474 this.afterSlideIn();
30482 slideInIf : function(e){
30483 if(!e.within(this.el)){
30488 animateCollapse : function(){
30489 this.beforeSlide();
30490 this.el.setStyle("z-index", 20000);
30491 var anchor = this.getSlideAnchor();
30492 this.el.slideOut(anchor, {
30493 callback : function(){
30494 this.el.setStyle("z-index", "");
30495 this.collapsedEl.slideIn(anchor, {duration:.3});
30497 this.el.setLocation(-10000,-10000);
30499 this.fireEvent("collapsed", this);
30506 animateExpand : function(){
30507 this.beforeSlide();
30508 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30509 this.el.setStyle("z-index", 20000);
30510 this.collapsedEl.hide({
30513 this.el.slideIn(this.getSlideAnchor(), {
30514 callback : function(){
30515 this.el.setStyle("z-index", "");
30518 this.split.el.show();
30520 this.fireEvent("invalidated", this);
30521 this.fireEvent("expanded", this);
30549 getAnchor : function(){
30550 return this.anchors[this.position];
30553 getCollapseAnchor : function(){
30554 return this.canchors[this.position];
30557 getSlideAnchor : function(){
30558 return this.sanchors[this.position];
30561 getAlignAdj : function(){
30562 var cm = this.cmargins;
30563 switch(this.position){
30579 getExpandAdj : function(){
30580 var c = this.collapsedEl, cm = this.cmargins;
30581 switch(this.position){
30583 return [-(cm.right+c.getWidth()+cm.left), 0];
30586 return [cm.right+c.getWidth()+cm.left, 0];
30589 return [0, -(cm.top+cm.bottom+c.getHeight())];
30592 return [0, cm.top+cm.bottom+c.getHeight()];
30598 * Ext JS Library 1.1.1
30599 * Copyright(c) 2006-2007, Ext JS, LLC.
30601 * Originally Released Under LGPL - original licence link has changed is not relivant.
30604 * <script type="text/javascript">
30607 * These classes are private internal classes
30609 Roo.CenterLayoutRegion = function(mgr, config){
30610 Roo.LayoutRegion.call(this, mgr, config, "center");
30611 this.visible = true;
30612 this.minWidth = config.minWidth || 20;
30613 this.minHeight = config.minHeight || 20;
30616 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30618 // center panel can't be hidden
30622 // center panel can't be hidden
30625 getMinWidth: function(){
30626 return this.minWidth;
30629 getMinHeight: function(){
30630 return this.minHeight;
30635 Roo.NorthLayoutRegion = function(mgr, config){
30636 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30638 this.split.placement = Roo.SplitBar.TOP;
30639 this.split.orientation = Roo.SplitBar.VERTICAL;
30640 this.split.el.addClass("x-layout-split-v");
30642 var size = config.initialSize || config.height;
30643 if(typeof size != "undefined"){
30644 this.el.setHeight(size);
30647 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30648 orientation: Roo.SplitBar.VERTICAL,
30649 getBox : function(){
30650 if(this.collapsed){
30651 return this.collapsedEl.getBox();
30653 var box = this.el.getBox();
30655 box.height += this.split.el.getHeight();
30660 updateBox : function(box){
30661 if(this.split && !this.collapsed){
30662 box.height -= this.split.el.getHeight();
30663 this.split.el.setLeft(box.x);
30664 this.split.el.setTop(box.y+box.height);
30665 this.split.el.setWidth(box.width);
30667 if(this.collapsed){
30668 this.updateBody(box.width, null);
30670 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30674 Roo.SouthLayoutRegion = function(mgr, config){
30675 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30677 this.split.placement = Roo.SplitBar.BOTTOM;
30678 this.split.orientation = Roo.SplitBar.VERTICAL;
30679 this.split.el.addClass("x-layout-split-v");
30681 var size = config.initialSize || config.height;
30682 if(typeof size != "undefined"){
30683 this.el.setHeight(size);
30686 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30687 orientation: Roo.SplitBar.VERTICAL,
30688 getBox : function(){
30689 if(this.collapsed){
30690 return this.collapsedEl.getBox();
30692 var box = this.el.getBox();
30694 var sh = this.split.el.getHeight();
30701 updateBox : function(box){
30702 if(this.split && !this.collapsed){
30703 var sh = this.split.el.getHeight();
30706 this.split.el.setLeft(box.x);
30707 this.split.el.setTop(box.y-sh);
30708 this.split.el.setWidth(box.width);
30710 if(this.collapsed){
30711 this.updateBody(box.width, null);
30713 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30717 Roo.EastLayoutRegion = function(mgr, config){
30718 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
30720 this.split.placement = Roo.SplitBar.RIGHT;
30721 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30722 this.split.el.addClass("x-layout-split-h");
30724 var size = config.initialSize || config.width;
30725 if(typeof size != "undefined"){
30726 this.el.setWidth(size);
30729 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
30730 orientation: Roo.SplitBar.HORIZONTAL,
30731 getBox : function(){
30732 if(this.collapsed){
30733 return this.collapsedEl.getBox();
30735 var box = this.el.getBox();
30737 var sw = this.split.el.getWidth();
30744 updateBox : function(box){
30745 if(this.split && !this.collapsed){
30746 var sw = this.split.el.getWidth();
30748 this.split.el.setLeft(box.x);
30749 this.split.el.setTop(box.y);
30750 this.split.el.setHeight(box.height);
30753 if(this.collapsed){
30754 this.updateBody(null, box.height);
30756 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30760 Roo.WestLayoutRegion = function(mgr, config){
30761 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
30763 this.split.placement = Roo.SplitBar.LEFT;
30764 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30765 this.split.el.addClass("x-layout-split-h");
30767 var size = config.initialSize || config.width;
30768 if(typeof size != "undefined"){
30769 this.el.setWidth(size);
30772 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
30773 orientation: Roo.SplitBar.HORIZONTAL,
30774 getBox : function(){
30775 if(this.collapsed){
30776 return this.collapsedEl.getBox();
30778 var box = this.el.getBox();
30780 box.width += this.split.el.getWidth();
30785 updateBox : function(box){
30786 if(this.split && !this.collapsed){
30787 var sw = this.split.el.getWidth();
30789 this.split.el.setLeft(box.x+box.width);
30790 this.split.el.setTop(box.y);
30791 this.split.el.setHeight(box.height);
30793 if(this.collapsed){
30794 this.updateBody(null, box.height);
30796 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30801 * Ext JS Library 1.1.1
30802 * Copyright(c) 2006-2007, Ext JS, LLC.
30804 * Originally Released Under LGPL - original licence link has changed is not relivant.
30807 * <script type="text/javascript">
30812 * Private internal class for reading and applying state
30814 Roo.LayoutStateManager = function(layout){
30815 // default empty state
30824 Roo.LayoutStateManager.prototype = {
30825 init : function(layout, provider){
30826 this.provider = provider;
30827 var state = provider.get(layout.id+"-layout-state");
30829 var wasUpdating = layout.isUpdating();
30831 layout.beginUpdate();
30833 for(var key in state){
30834 if(typeof state[key] != "function"){
30835 var rstate = state[key];
30836 var r = layout.getRegion(key);
30839 r.resizeTo(rstate.size);
30841 if(rstate.collapsed == true){
30844 r.expand(null, true);
30850 layout.endUpdate();
30852 this.state = state;
30854 this.layout = layout;
30855 layout.on("regionresized", this.onRegionResized, this);
30856 layout.on("regioncollapsed", this.onRegionCollapsed, this);
30857 layout.on("regionexpanded", this.onRegionExpanded, this);
30860 storeState : function(){
30861 this.provider.set(this.layout.id+"-layout-state", this.state);
30864 onRegionResized : function(region, newSize){
30865 this.state[region.getPosition()].size = newSize;
30869 onRegionCollapsed : function(region){
30870 this.state[region.getPosition()].collapsed = true;
30874 onRegionExpanded : function(region){
30875 this.state[region.getPosition()].collapsed = false;
30880 * Ext JS Library 1.1.1
30881 * Copyright(c) 2006-2007, Ext JS, LLC.
30883 * Originally Released Under LGPL - original licence link has changed is not relivant.
30886 * <script type="text/javascript">
30889 * @class Roo.ContentPanel
30890 * @extends Roo.util.Observable
30891 * A basic ContentPanel element.
30892 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
30893 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
30894 * @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
30895 * @cfg {Boolean} closable True if the panel can be closed/removed
30896 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
30897 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
30898 * @cfg {Toolbar} toolbar A toolbar for this panel
30899 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
30900 * @cfg {String} title The title for this panel
30901 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
30902 * @cfg {String} url Calls {@link #setUrl} with this value
30903 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
30904 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
30905 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
30907 * Create a new ContentPanel.
30908 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
30909 * @param {String/Object} config A string to set only the title or a config object
30910 * @param {String} content (optional) Set the HTML content for this panel
30911 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
30913 Roo.ContentPanel = function(el, config, content){
30917 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
30921 if (config && config.parentLayout) {
30922 el = config.parentLayout.el.createChild();
30925 if(el.autoCreate){ // xtype is available if this is called from factory
30929 this.el = Roo.get(el);
30930 if(!this.el && config && config.autoCreate){
30931 if(typeof config.autoCreate == "object"){
30932 if(!config.autoCreate.id){
30933 config.autoCreate.id = config.id||el;
30935 this.el = Roo.DomHelper.append(document.body,
30936 config.autoCreate, true);
30938 this.el = Roo.DomHelper.append(document.body,
30939 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
30942 this.closable = false;
30943 this.loaded = false;
30944 this.active = false;
30945 if(typeof config == "string"){
30946 this.title = config;
30948 Roo.apply(this, config);
30951 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
30952 this.wrapEl = this.el.wrap();
30953 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
30960 this.resizeEl = Roo.get(this.resizeEl, true);
30962 this.resizeEl = this.el;
30967 * Fires when this panel is activated.
30968 * @param {Roo.ContentPanel} this
30972 * @event deactivate
30973 * Fires when this panel is activated.
30974 * @param {Roo.ContentPanel} this
30976 "deactivate" : true,
30980 * Fires when this panel is resized if fitToFrame is true.
30981 * @param {Roo.ContentPanel} this
30982 * @param {Number} width The width after any component adjustments
30983 * @param {Number} height The height after any component adjustments
30987 if(this.autoScroll){
30988 this.resizeEl.setStyle("overflow", "auto");
30990 // fix randome scrolling
30991 this.el.on('scroll', function() {
30992 this.scrollTo('top',0);
30995 content = content || this.content;
30997 this.setContent(content);
30999 if(config && config.url){
31000 this.setUrl(this.url, this.params, this.loadOnce);
31005 Roo.ContentPanel.superclass.constructor.call(this);
31008 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31010 setRegion : function(region){
31011 this.region = region;
31013 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31015 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31020 * Returns the toolbar for this Panel if one was configured.
31021 * @return {Roo.Toolbar}
31023 getToolbar : function(){
31024 return this.toolbar;
31027 setActiveState : function(active){
31028 this.active = active;
31030 this.fireEvent("deactivate", this);
31032 this.fireEvent("activate", this);
31036 * Updates this panel's element
31037 * @param {String} content The new content
31038 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31040 setContent : function(content, loadScripts){
31041 this.el.update(content, loadScripts);
31044 ignoreResize : function(w, h){
31045 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31048 this.lastSize = {width: w, height: h};
31053 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31054 * @return {Roo.UpdateManager} The UpdateManager
31056 getUpdateManager : function(){
31057 return this.el.getUpdateManager();
31060 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31061 * @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:
31064 url: "your-url.php",
31065 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31066 callback: yourFunction,
31067 scope: yourObject, //(optional scope)
31070 text: "Loading...",
31075 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31076 * 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.
31077 * @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}
31078 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31079 * @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.
31080 * @return {Roo.ContentPanel} this
31083 var um = this.el.getUpdateManager();
31084 um.update.apply(um, arguments);
31090 * 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.
31091 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31092 * @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)
31093 * @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)
31094 * @return {Roo.UpdateManager} The UpdateManager
31096 setUrl : function(url, params, loadOnce){
31097 if(this.refreshDelegate){
31098 this.removeListener("activate", this.refreshDelegate);
31100 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31101 this.on("activate", this.refreshDelegate);
31102 return this.el.getUpdateManager();
31105 _handleRefresh : function(url, params, loadOnce){
31106 if(!loadOnce || !this.loaded){
31107 var updater = this.el.getUpdateManager();
31108 updater.update(url, params, this._setLoaded.createDelegate(this));
31112 _setLoaded : function(){
31113 this.loaded = true;
31117 * Returns this panel's id
31120 getId : function(){
31125 * Returns this panel's element - used by regiosn to add.
31126 * @return {Roo.Element}
31128 getEl : function(){
31129 return this.wrapEl || this.el;
31132 adjustForComponents : function(width, height){
31133 if(this.resizeEl != this.el){
31134 width -= this.el.getFrameWidth('lr');
31135 height -= this.el.getFrameWidth('tb');
31138 var te = this.toolbar.getEl();
31139 height -= te.getHeight();
31140 te.setWidth(width);
31142 if(this.adjustments){
31143 width += this.adjustments[0];
31144 height += this.adjustments[1];
31146 return {"width": width, "height": height};
31149 setSize : function(width, height){
31150 if(this.fitToFrame && !this.ignoreResize(width, height)){
31151 if(this.fitContainer && this.resizeEl != this.el){
31152 this.el.setSize(width, height);
31154 var size = this.adjustForComponents(width, height);
31155 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31156 this.fireEvent('resize', this, size.width, size.height);
31161 * Returns this panel's title
31164 getTitle : function(){
31169 * Set this panel's title
31170 * @param {String} title
31172 setTitle : function(title){
31173 this.title = title;
31175 this.region.updatePanelTitle(this, title);
31180 * Returns true is this panel was configured to be closable
31181 * @return {Boolean}
31183 isClosable : function(){
31184 return this.closable;
31187 beforeSlide : function(){
31189 this.resizeEl.clip();
31192 afterSlide : function(){
31194 this.resizeEl.unclip();
31198 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31199 * Will fail silently if the {@link #setUrl} method has not been called.
31200 * This does not activate the panel, just updates its content.
31202 refresh : function(){
31203 if(this.refreshDelegate){
31204 this.loaded = false;
31205 this.refreshDelegate();
31210 * Destroys this panel
31212 destroy : function(){
31213 this.el.removeAllListeners();
31214 var tempEl = document.createElement("span");
31215 tempEl.appendChild(this.el.dom);
31216 tempEl.innerHTML = "";
31222 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31232 * @param {Object} cfg Xtype definition of item to add.
31235 addxtype : function(cfg) {
31237 if (cfg.xtype.match(/^Form$/)) {
31238 var el = this.el.createChild();
31240 this.form = new Roo.form.Form(cfg);
31243 if ( this.form.allItems.length) this.form.render(el.dom);
31246 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
31248 cfg.el = this.el.appendChild(document.createElement("div"));
31250 var ret = new Roo[cfg.xtype](cfg);
31251 ret.render(false, ''); // render blank..
31261 * @class Roo.GridPanel
31262 * @extends Roo.ContentPanel
31264 * Create a new GridPanel.
31265 * @param {Roo.grid.Grid} grid The grid for this panel
31266 * @param {String/Object} config A string to set only the panel's title, or a config object
31268 Roo.GridPanel = function(grid, config){
31271 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31272 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31274 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31276 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31279 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31281 // xtype created footer. - not sure if will work as we normally have to render first..
31282 if (this.footer && !this.footer.el && this.footer.xtype) {
31284 this.footer.container = this.grid.getView().getFooterPanel(true);
31285 this.footer.dataSource = this.grid.dataSource;
31286 this.footer = Roo.factory(this.footer, Roo);
31290 grid.monitorWindowResize = false; // turn off autosizing
31291 grid.autoHeight = false;
31292 grid.autoWidth = false;
31294 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31297 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31298 getId : function(){
31299 return this.grid.id;
31303 * Returns the grid for this panel
31304 * @return {Roo.grid.Grid}
31306 getGrid : function(){
31310 setSize : function(width, height){
31311 if(!this.ignoreResize(width, height)){
31312 var grid = this.grid;
31313 var size = this.adjustForComponents(width, height);
31314 grid.getGridEl().setSize(size.width, size.height);
31319 beforeSlide : function(){
31320 this.grid.getView().scroller.clip();
31323 afterSlide : function(){
31324 this.grid.getView().scroller.unclip();
31327 destroy : function(){
31328 this.grid.destroy();
31330 Roo.GridPanel.superclass.destroy.call(this);
31336 * @class Roo.NestedLayoutPanel
31337 * @extends Roo.ContentPanel
31339 * Create a new NestedLayoutPanel.
31342 * @param {Roo.BorderLayout} layout The layout for this panel
31343 * @param {String/Object} config A string to set only the title or a config object
31345 Roo.NestedLayoutPanel = function(layout, config)
31347 // construct with only one argument..
31348 /* FIXME - implement nicer consturctors
31349 if (layout.layout) {
31351 layout = config.layout;
31352 delete config.layout;
31354 if (layout.xtype && !layout.getEl) {
31355 // then layout needs constructing..
31356 layout = Roo.factory(layout, Roo);
31361 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31363 layout.monitorWindowResize = false; // turn off autosizing
31364 this.layout = layout;
31365 this.layout.getEl().addClass("x-layout-nested-layout");
31372 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31374 setSize : function(width, height){
31375 if(!this.ignoreResize(width, height)){
31376 var size = this.adjustForComponents(width, height);
31377 var el = this.layout.getEl();
31378 el.setSize(size.width, size.height);
31379 var touch = el.dom.offsetWidth;
31380 this.layout.layout();
31381 // ie requires a double layout on the first pass
31382 if(Roo.isIE && !this.initialized){
31383 this.initialized = true;
31384 this.layout.layout();
31389 // activate all subpanels if not currently active..
31391 setActiveState : function(active){
31392 this.active = active;
31394 this.fireEvent("deactivate", this);
31398 this.fireEvent("activate", this);
31399 // not sure if this should happen before or after..
31400 if (!this.layout) {
31401 return; // should not happen..
31404 for (var r in this.layout.regions) {
31405 reg = this.layout.getRegion(r);
31406 if (reg.getActivePanel()) {
31407 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31408 reg.setActivePanel(reg.getActivePanel());
31411 if (!reg.panels.length) {
31414 reg.showPanel(reg.getPanel(0));
31423 * Returns the nested BorderLayout for this panel
31424 * @return {Roo.BorderLayout}
31426 getLayout : function(){
31427 return this.layout;
31431 * Adds a xtype elements to the layout of the nested panel
31435 xtype : 'ContentPanel',
31442 xtype : 'NestedLayoutPanel',
31448 items : [ ... list of content panels or nested layout panels.. ]
31452 * @param {Object} cfg Xtype definition of item to add.
31454 addxtype : function(cfg) {
31455 return this.layout.addxtype(cfg);
31460 Roo.ScrollPanel = function(el, config, content){
31461 config = config || {};
31462 config.fitToFrame = true;
31463 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31465 this.el.dom.style.overflow = "hidden";
31466 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31467 this.el.removeClass("x-layout-inactive-content");
31468 this.el.on("mousewheel", this.onWheel, this);
31470 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31471 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31472 up.unselectable(); down.unselectable();
31473 up.on("click", this.scrollUp, this);
31474 down.on("click", this.scrollDown, this);
31475 up.addClassOnOver("x-scroller-btn-over");
31476 down.addClassOnOver("x-scroller-btn-over");
31477 up.addClassOnClick("x-scroller-btn-click");
31478 down.addClassOnClick("x-scroller-btn-click");
31479 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31481 this.resizeEl = this.el;
31482 this.el = wrap; this.up = up; this.down = down;
31485 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31487 wheelIncrement : 5,
31488 scrollUp : function(){
31489 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31492 scrollDown : function(){
31493 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31496 afterScroll : function(){
31497 var el = this.resizeEl;
31498 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31499 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31500 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31503 setSize : function(){
31504 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31505 this.afterScroll();
31508 onWheel : function(e){
31509 var d = e.getWheelDelta();
31510 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31511 this.afterScroll();
31515 setContent : function(content, loadScripts){
31516 this.resizeEl.update(content, loadScripts);
31530 * @class Roo.TreePanel
31531 * @extends Roo.ContentPanel
31533 * Create a new TreePanel. - defaults to fit/scoll contents.
31534 * @param {String/Object} config A string to set only the panel's title, or a config object
31535 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31537 Roo.TreePanel = function(config){
31538 var el = config.el;
31539 var tree = config.tree;
31540 delete config.tree;
31541 delete config.el; // hopefull!
31543 // wrapper for IE7 strict & safari scroll issue
31545 var treeEl = el.createChild();
31546 config.resizeEl = treeEl;
31550 Roo.TreePanel.superclass.constructor.call(this, el, config);
31553 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31554 //console.log(tree);
31555 this.on('activate', function()
31557 if (this.tree.rendered) {
31560 //console.log('render tree');
31561 this.tree.render();
31564 this.on('resize', function (cp, w, h) {
31565 this.tree.innerCt.setWidth(w);
31566 this.tree.innerCt.setHeight(h);
31567 this.tree.innerCt.setStyle('overflow-y', 'auto');
31574 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31591 * Ext JS Library 1.1.1
31592 * Copyright(c) 2006-2007, Ext JS, LLC.
31594 * Originally Released Under LGPL - original licence link has changed is not relivant.
31597 * <script type="text/javascript">
31602 * @class Roo.ReaderLayout
31603 * @extends Roo.BorderLayout
31604 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31605 * center region containing two nested regions (a top one for a list view and one for item preview below),
31606 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31607 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31608 * expedites the setup of the overall layout and regions for this common application style.
31611 var reader = new Roo.ReaderLayout();
31612 var CP = Roo.ContentPanel; // shortcut for adding
31614 reader.beginUpdate();
31615 reader.add("north", new CP("north", "North"));
31616 reader.add("west", new CP("west", {title: "West"}));
31617 reader.add("east", new CP("east", {title: "East"}));
31619 reader.regions.listView.add(new CP("listView", "List"));
31620 reader.regions.preview.add(new CP("preview", "Preview"));
31621 reader.endUpdate();
31624 * Create a new ReaderLayout
31625 * @param {Object} config Configuration options
31626 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31627 * document.body if omitted)
31629 Roo.ReaderLayout = function(config, renderTo){
31630 var c = config || {size:{}};
31631 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31632 north: c.north !== false ? Roo.apply({
31636 }, c.north) : false,
31637 west: c.west !== false ? Roo.apply({
31645 margins:{left:5,right:0,bottom:5,top:5},
31646 cmargins:{left:5,right:5,bottom:5,top:5}
31647 }, c.west) : false,
31648 east: c.east !== false ? Roo.apply({
31656 margins:{left:0,right:5,bottom:5,top:5},
31657 cmargins:{left:5,right:5,bottom:5,top:5}
31658 }, c.east) : false,
31659 center: Roo.apply({
31660 tabPosition: 'top',
31664 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31668 this.el.addClass('x-reader');
31670 this.beginUpdate();
31672 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31673 south: c.preview !== false ? Roo.apply({
31680 cmargins:{top:5,left:0, right:0, bottom:0}
31681 }, c.preview) : false,
31682 center: Roo.apply({
31688 this.add('center', new Roo.NestedLayoutPanel(inner,
31689 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31693 this.regions.preview = inner.getRegion('south');
31694 this.regions.listView = inner.getRegion('center');
31697 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31699 * Ext JS Library 1.1.1
31700 * Copyright(c) 2006-2007, Ext JS, LLC.
31702 * Originally Released Under LGPL - original licence link has changed is not relivant.
31705 * <script type="text/javascript">
31709 * @class Roo.grid.Grid
31710 * @extends Roo.util.Observable
31711 * This class represents the primary interface of a component based grid control.
31712 * <br><br>Usage:<pre><code>
31713 var grid = new Roo.grid.Grid("my-container-id", {
31716 selModel: mySelectionModel,
31717 autoSizeColumns: true,
31718 monitorWindowResize: false,
31719 trackMouseOver: true
31724 * <b>Common Problems:</b><br/>
31725 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
31726 * element will correct this<br/>
31727 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
31728 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
31729 * are unpredictable.<br/>
31730 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
31731 * grid to calculate dimensions/offsets.<br/>
31733 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
31734 * The container MUST have some type of size defined for the grid to fill. The container will be
31735 * automatically set to position relative if it isn't already.
31736 * @param {Object} config A config object that sets properties on this grid.
31738 Roo.grid.Grid = function(container, config){
31739 // initialize the container
31740 this.container = Roo.get(container);
31741 this.container.update("");
31742 this.container.setStyle("overflow", "hidden");
31743 this.container.addClass('x-grid-container');
31745 this.id = this.container.id;
31747 Roo.apply(this, config);
31748 // check and correct shorthanded configs
31750 this.dataSource = this.ds;
31754 this.colModel = this.cm;
31758 this.selModel = this.sm;
31762 if (this.selModel) {
31763 this.selModel = Roo.factory(this.selModel, Roo.grid);
31764 this.sm = this.selModel;
31765 this.sm.xmodule = this.xmodule || false;
31767 if (typeof(this.colModel.config) == 'undefined') {
31768 this.colModel = new Roo.grid.ColumnModel(this.colModel);
31769 this.cm = this.colModel;
31770 this.cm.xmodule = this.xmodule || false;
31772 if (this.dataSource) {
31773 this.dataSource= Roo.factory(this.dataSource, Roo.data);
31774 this.ds = this.dataSource;
31775 this.ds.xmodule = this.xmodule || false;
31782 this.container.setWidth(this.width);
31786 this.container.setHeight(this.height);
31793 * The raw click event for the entire grid.
31794 * @param {Roo.EventObject} e
31799 * The raw dblclick event for the entire grid.
31800 * @param {Roo.EventObject} e
31804 * @event contextmenu
31805 * The raw contextmenu event for the entire grid.
31806 * @param {Roo.EventObject} e
31808 "contextmenu" : true,
31811 * The raw mousedown event for the entire grid.
31812 * @param {Roo.EventObject} e
31814 "mousedown" : true,
31817 * The raw mouseup event for the entire grid.
31818 * @param {Roo.EventObject} e
31823 * The raw mouseover event for the entire grid.
31824 * @param {Roo.EventObject} e
31826 "mouseover" : true,
31829 * The raw mouseout event for the entire grid.
31830 * @param {Roo.EventObject} e
31835 * The raw keypress event for the entire grid.
31836 * @param {Roo.EventObject} e
31841 * The raw keydown event for the entire grid.
31842 * @param {Roo.EventObject} e
31850 * Fires when a cell is clicked
31851 * @param {Grid} this
31852 * @param {Number} rowIndex
31853 * @param {Number} columnIndex
31854 * @param {Roo.EventObject} e
31856 "cellclick" : true,
31858 * @event celldblclick
31859 * Fires when a cell is double clicked
31860 * @param {Grid} this
31861 * @param {Number} rowIndex
31862 * @param {Number} columnIndex
31863 * @param {Roo.EventObject} e
31865 "celldblclick" : true,
31868 * Fires when a row is clicked
31869 * @param {Grid} this
31870 * @param {Number} rowIndex
31871 * @param {Roo.EventObject} e
31875 * @event rowdblclick
31876 * Fires when a row is double clicked
31877 * @param {Grid} this
31878 * @param {Number} rowIndex
31879 * @param {Roo.EventObject} e
31881 "rowdblclick" : true,
31883 * @event headerclick
31884 * Fires when a header is clicked
31885 * @param {Grid} this
31886 * @param {Number} columnIndex
31887 * @param {Roo.EventObject} e
31889 "headerclick" : true,
31891 * @event headerdblclick
31892 * Fires when a header cell is double clicked
31893 * @param {Grid} this
31894 * @param {Number} columnIndex
31895 * @param {Roo.EventObject} e
31897 "headerdblclick" : true,
31899 * @event rowcontextmenu
31900 * Fires when a row is right clicked
31901 * @param {Grid} this
31902 * @param {Number} rowIndex
31903 * @param {Roo.EventObject} e
31905 "rowcontextmenu" : true,
31907 * @event cellcontextmenu
31908 * Fires when a cell is right clicked
31909 * @param {Grid} this
31910 * @param {Number} rowIndex
31911 * @param {Number} cellIndex
31912 * @param {Roo.EventObject} e
31914 "cellcontextmenu" : true,
31916 * @event headercontextmenu
31917 * Fires when a header is right clicked
31918 * @param {Grid} this
31919 * @param {Number} columnIndex
31920 * @param {Roo.EventObject} e
31922 "headercontextmenu" : true,
31924 * @event bodyscroll
31925 * Fires when the body element is scrolled
31926 * @param {Number} scrollLeft
31927 * @param {Number} scrollTop
31929 "bodyscroll" : true,
31931 * @event columnresize
31932 * Fires when the user resizes a column
31933 * @param {Number} columnIndex
31934 * @param {Number} newSize
31936 "columnresize" : true,
31938 * @event columnmove
31939 * Fires when the user moves a column
31940 * @param {Number} oldIndex
31941 * @param {Number} newIndex
31943 "columnmove" : true,
31946 * Fires when row(s) start being dragged
31947 * @param {Grid} this
31948 * @param {Roo.GridDD} dd The drag drop object
31949 * @param {event} e The raw browser event
31951 "startdrag" : true,
31954 * Fires when a drag operation is complete
31955 * @param {Grid} this
31956 * @param {Roo.GridDD} dd The drag drop object
31957 * @param {event} e The raw browser event
31962 * Fires when dragged row(s) are dropped on a valid DD target
31963 * @param {Grid} this
31964 * @param {Roo.GridDD} dd The drag drop object
31965 * @param {String} targetId The target drag drop object
31966 * @param {event} e The raw browser event
31971 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
31972 * @param {Grid} this
31973 * @param {Roo.GridDD} dd The drag drop object
31974 * @param {String} targetId The target drag drop object
31975 * @param {event} e The raw browser event
31980 * Fires when the dragged row(s) first cross another DD target while being dragged
31981 * @param {Grid} this
31982 * @param {Roo.GridDD} dd The drag drop object
31983 * @param {String} targetId The target drag drop object
31984 * @param {event} e The raw browser event
31986 "dragenter" : true,
31989 * Fires when the dragged row(s) leave another DD target while being dragged
31990 * @param {Grid} this
31991 * @param {Roo.GridDD} dd The drag drop object
31992 * @param {String} targetId The target drag drop object
31993 * @param {event} e The raw browser event
31998 * Fires when the grid is rendered
31999 * @param {Grid} grid
32004 Roo.grid.Grid.superclass.constructor.call(this);
32006 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32009 * @cfg {String} ddGroup - drag drop group.
32013 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32015 minColumnWidth : 25,
32018 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32019 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32020 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32022 autoSizeColumns : false,
32025 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32027 autoSizeHeaders : true,
32030 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32032 monitorWindowResize : true,
32035 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32036 * rows measured to get a columns size. Default is 0 (all rows).
32038 maxRowsToMeasure : 0,
32041 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32043 trackMouseOver : true,
32046 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32050 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32052 enableDragDrop : false,
32055 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32057 enableColumnMove : true,
32060 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32062 enableColumnHide : true,
32065 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32067 enableRowHeightSync : false,
32070 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32075 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32077 autoHeight : false,
32080 * @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.
32082 autoExpandColumn : false,
32085 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32088 autoExpandMin : 50,
32091 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32093 autoExpandMax : 1000,
32096 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32101 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32109 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32110 * of a fixed width. Default is false.
32113 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32116 * Called once after all setup has been completed and the grid is ready to be rendered.
32117 * @return {Roo.grid.Grid} this
32119 render : function(){
32120 var c = this.container;
32121 // try to detect autoHeight/width mode
32122 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32123 this.autoHeight = true;
32125 var view = this.getView();
32128 c.on("click", this.onClick, this);
32129 c.on("dblclick", this.onDblClick, this);
32130 c.on("contextmenu", this.onContextMenu, this);
32131 c.on("keydown", this.onKeyDown, this);
32133 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32135 this.getSelectionModel().init(this);
32140 this.loadMask = new Roo.LoadMask(this.container,
32141 Roo.apply({store:this.dataSource}, this.loadMask));
32145 if (this.toolbar && this.toolbar.xtype) {
32146 this.toolbar.container = this.getView().getHeaderPanel(true);
32147 this.toolbar = new Ext.Toolbar(this.toolbar);
32149 if (this.footer && this.footer.xtype) {
32150 this.footer.dataSource = this.getDataSource();
32151 this.footer.container = this.getView().getFooterPanel(true);
32152 this.footer = Roo.factory(this.footer, Roo);
32154 if (this.dragTarget && this.dragTarget) {
32155 delete this.dragTarget.xtype;
32156 this.dragTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dragTarget);
32160 this.rendered = true;
32161 this.fireEvent('render', this);
32166 * Reconfigures the grid to use a different Store and Column Model.
32167 * The View will be bound to the new objects and refreshed.
32168 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32169 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32171 reconfigure : function(dataSource, colModel){
32173 this.loadMask.destroy();
32174 this.loadMask = new Roo.LoadMask(this.container,
32175 Roo.apply({store:dataSource}, this.loadMask));
32177 this.view.bind(dataSource, colModel);
32178 this.dataSource = dataSource;
32179 this.colModel = colModel;
32180 this.view.refresh(true);
32184 onKeyDown : function(e){
32185 this.fireEvent("keydown", e);
32189 * Destroy this grid.
32190 * @param {Boolean} removeEl True to remove the element
32192 destroy : function(removeEl, keepListeners){
32194 this.loadMask.destroy();
32196 var c = this.container;
32197 c.removeAllListeners();
32198 this.view.destroy();
32199 this.colModel.purgeListeners();
32200 if(!keepListeners){
32201 this.purgeListeners();
32204 if(removeEl === true){
32210 processEvent : function(name, e){
32211 this.fireEvent(name, e);
32212 var t = e.getTarget();
32214 var header = v.findHeaderIndex(t);
32215 if(header !== false){
32216 this.fireEvent("header" + name, this, header, e);
32218 var row = v.findRowIndex(t);
32219 var cell = v.findCellIndex(t);
32221 this.fireEvent("row" + name, this, row, e);
32222 if(cell !== false){
32223 this.fireEvent("cell" + name, this, row, cell, e);
32230 onClick : function(e){
32231 this.processEvent("click", e);
32235 onContextMenu : function(e, t){
32236 this.processEvent("contextmenu", e);
32240 onDblClick : function(e){
32241 this.processEvent("dblclick", e);
32245 walkCells : function(row, col, step, fn, scope){
32246 var cm = this.colModel, clen = cm.getColumnCount();
32247 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32259 if(fn.call(scope || this, row, col, cm) === true){
32277 if(fn.call(scope || this, row, col, cm) === true){
32289 getSelections : function(){
32290 return this.selModel.getSelections();
32294 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32295 * but if manual update is required this method will initiate it.
32297 autoSize : function(){
32299 this.view.layout();
32300 if(this.view.adjustForScroll){
32301 this.view.adjustForScroll();
32307 * Returns the grid's underlying element.
32308 * @return {Element} The element
32310 getGridEl : function(){
32311 return this.container;
32314 // private for compatibility, overridden by editor grid
32315 stopEditing : function(){},
32318 * Returns the grid's SelectionModel.
32319 * @return {SelectionModel}
32321 getSelectionModel : function(){
32322 if(!this.selModel){
32323 this.selModel = new Roo.grid.RowSelectionModel();
32325 return this.selModel;
32329 * Returns the grid's DataSource.
32330 * @return {DataSource}
32332 getDataSource : function(){
32333 return this.dataSource;
32337 * Returns the grid's ColumnModel.
32338 * @return {ColumnModel}
32340 getColumnModel : function(){
32341 return this.colModel;
32345 * Returns the grid's GridView object.
32346 * @return {GridView}
32348 getView : function(){
32350 this.view = new Roo.grid.GridView(this.viewConfig);
32355 * Called to get grid's drag proxy text, by default returns this.ddText.
32358 getDragDropText : function(){
32359 var count = this.selModel.getCount();
32360 return String.format(this.ddText, count, count == 1 ? '' : 's');
32364 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32365 * %0 is replaced with the number of selected rows.
32368 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32370 * Ext JS Library 1.1.1
32371 * Copyright(c) 2006-2007, Ext JS, LLC.
32373 * Originally Released Under LGPL - original licence link has changed is not relivant.
32376 * <script type="text/javascript">
32379 Roo.grid.AbstractGridView = function(){
32383 "beforerowremoved" : true,
32384 "beforerowsinserted" : true,
32385 "beforerefresh" : true,
32386 "rowremoved" : true,
32387 "rowsinserted" : true,
32388 "rowupdated" : true,
32391 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32394 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32395 rowClass : "x-grid-row",
32396 cellClass : "x-grid-cell",
32397 tdClass : "x-grid-td",
32398 hdClass : "x-grid-hd",
32399 splitClass : "x-grid-hd-split",
32401 init: function(grid){
32403 var cid = this.grid.getGridEl().id;
32404 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32405 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32406 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32407 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32410 getColumnRenderers : function(){
32411 var renderers = [];
32412 var cm = this.grid.colModel;
32413 var colCount = cm.getColumnCount();
32414 for(var i = 0; i < colCount; i++){
32415 renderers[i] = cm.getRenderer(i);
32420 getColumnIds : function(){
32422 var cm = this.grid.colModel;
32423 var colCount = cm.getColumnCount();
32424 for(var i = 0; i < colCount; i++){
32425 ids[i] = cm.getColumnId(i);
32430 getDataIndexes : function(){
32431 if(!this.indexMap){
32432 this.indexMap = this.buildIndexMap();
32434 return this.indexMap.colToData;
32437 getColumnIndexByDataIndex : function(dataIndex){
32438 if(!this.indexMap){
32439 this.indexMap = this.buildIndexMap();
32441 return this.indexMap.dataToCol[dataIndex];
32445 * Set a css style for a column dynamically.
32446 * @param {Number} colIndex The index of the column
32447 * @param {String} name The css property name
32448 * @param {String} value The css value
32450 setCSSStyle : function(colIndex, name, value){
32451 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32452 Roo.util.CSS.updateRule(selector, name, value);
32455 generateRules : function(cm){
32456 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32457 Roo.util.CSS.removeStyleSheet(rulesId);
32458 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32459 var cid = cm.getColumnId(i);
32460 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32461 this.tdSelector, cid, " {\n}\n",
32462 this.hdSelector, cid, " {\n}\n",
32463 this.splitSelector, cid, " {\n}\n");
32465 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32469 * Ext JS Library 1.1.1
32470 * Copyright(c) 2006-2007, Ext JS, LLC.
32472 * Originally Released Under LGPL - original licence link has changed is not relivant.
32475 * <script type="text/javascript">
32479 // This is a support class used internally by the Grid components
32480 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32482 this.view = grid.getView();
32483 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32484 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32486 this.setHandleElId(Roo.id(hd));
32487 this.setOuterHandleElId(Roo.id(hd2));
32489 this.scroll = false;
32491 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32493 getDragData : function(e){
32494 var t = Roo.lib.Event.getTarget(e);
32495 var h = this.view.findHeaderCell(t);
32497 return {ddel: h.firstChild, header:h};
32502 onInitDrag : function(e){
32503 this.view.headersDisabled = true;
32504 var clone = this.dragData.ddel.cloneNode(true);
32505 clone.id = Roo.id();
32506 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32507 this.proxy.update(clone);
32511 afterValidDrop : function(){
32513 setTimeout(function(){
32514 v.headersDisabled = false;
32518 afterInvalidDrop : function(){
32520 setTimeout(function(){
32521 v.headersDisabled = false;
32527 * Ext JS Library 1.1.1
32528 * Copyright(c) 2006-2007, Ext JS, LLC.
32530 * Originally Released Under LGPL - original licence link has changed is not relivant.
32533 * <script type="text/javascript">
32536 // This is a support class used internally by the Grid components
32537 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32539 this.view = grid.getView();
32540 // split the proxies so they don't interfere with mouse events
32541 this.proxyTop = Roo.DomHelper.append(document.body, {
32542 cls:"col-move-top", html:" "
32544 this.proxyBottom = Roo.DomHelper.append(document.body, {
32545 cls:"col-move-bottom", html:" "
32547 this.proxyTop.hide = this.proxyBottom.hide = function(){
32548 this.setLeftTop(-100,-100);
32549 this.setStyle("visibility", "hidden");
32551 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32552 // temporarily disabled
32553 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32554 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32556 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32557 proxyOffsets : [-4, -9],
32558 fly: Roo.Element.fly,
32560 getTargetFromEvent : function(e){
32561 var t = Roo.lib.Event.getTarget(e);
32562 var cindex = this.view.findCellIndex(t);
32563 if(cindex !== false){
32564 return this.view.getHeaderCell(cindex);
32568 nextVisible : function(h){
32569 var v = this.view, cm = this.grid.colModel;
32572 if(!cm.isHidden(v.getCellIndex(h))){
32580 prevVisible : function(h){
32581 var v = this.view, cm = this.grid.colModel;
32584 if(!cm.isHidden(v.getCellIndex(h))){
32592 positionIndicator : function(h, n, e){
32593 var x = Roo.lib.Event.getPageX(e);
32594 var r = Roo.lib.Dom.getRegion(n.firstChild);
32595 var px, pt, py = r.top + this.proxyOffsets[1];
32596 if((r.right - x) <= (r.right-r.left)/2){
32597 px = r.right+this.view.borderWidth;
32603 var oldIndex = this.view.getCellIndex(h);
32604 var newIndex = this.view.getCellIndex(n);
32606 if(this.grid.colModel.isFixed(newIndex)){
32610 var locked = this.grid.colModel.isLocked(newIndex);
32615 if(oldIndex < newIndex){
32618 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32621 px += this.proxyOffsets[0];
32622 this.proxyTop.setLeftTop(px, py);
32623 this.proxyTop.show();
32624 if(!this.bottomOffset){
32625 this.bottomOffset = this.view.mainHd.getHeight();
32627 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32628 this.proxyBottom.show();
32632 onNodeEnter : function(n, dd, e, data){
32633 if(data.header != n){
32634 this.positionIndicator(data.header, n, e);
32638 onNodeOver : function(n, dd, e, data){
32639 var result = false;
32640 if(data.header != n){
32641 result = this.positionIndicator(data.header, n, e);
32644 this.proxyTop.hide();
32645 this.proxyBottom.hide();
32647 return result ? this.dropAllowed : this.dropNotAllowed;
32650 onNodeOut : function(n, dd, e, data){
32651 this.proxyTop.hide();
32652 this.proxyBottom.hide();
32655 onNodeDrop : function(n, dd, e, data){
32656 var h = data.header;
32658 var cm = this.grid.colModel;
32659 var x = Roo.lib.Event.getPageX(e);
32660 var r = Roo.lib.Dom.getRegion(n.firstChild);
32661 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32662 var oldIndex = this.view.getCellIndex(h);
32663 var newIndex = this.view.getCellIndex(n);
32664 var locked = cm.isLocked(newIndex);
32668 if(oldIndex < newIndex){
32671 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32674 cm.setLocked(oldIndex, locked, true);
32675 cm.moveColumn(oldIndex, newIndex);
32676 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32684 * Ext JS Library 1.1.1
32685 * Copyright(c) 2006-2007, Ext JS, LLC.
32687 * Originally Released Under LGPL - original licence link has changed is not relivant.
32690 * <script type="text/javascript">
32694 * @class Roo.grid.GridView
32695 * @extends Roo.util.Observable
32698 * @param {Object} config
32700 Roo.grid.GridView = function(config){
32701 Roo.grid.GridView.superclass.constructor.call(this);
32704 Roo.apply(this, config);
32707 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
32710 * Override this function to apply custom css classes to rows during rendering
32711 * @param {Record} record The record
32712 * @param {Number} index
32713 * @method getRowClass
32715 rowClass : "x-grid-row",
32717 cellClass : "x-grid-col",
32719 tdClass : "x-grid-td",
32721 hdClass : "x-grid-hd",
32723 splitClass : "x-grid-split",
32725 sortClasses : ["sort-asc", "sort-desc"],
32727 enableMoveAnim : false,
32731 dh : Roo.DomHelper,
32733 fly : Roo.Element.fly,
32735 css : Roo.util.CSS,
32741 scrollIncrement : 22,
32743 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
32745 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
32747 bind : function(ds, cm){
32749 this.ds.un("load", this.onLoad, this);
32750 this.ds.un("datachanged", this.onDataChange, this);
32751 this.ds.un("add", this.onAdd, this);
32752 this.ds.un("remove", this.onRemove, this);
32753 this.ds.un("update", this.onUpdate, this);
32754 this.ds.un("clear", this.onClear, this);
32757 ds.on("load", this.onLoad, this);
32758 ds.on("datachanged", this.onDataChange, this);
32759 ds.on("add", this.onAdd, this);
32760 ds.on("remove", this.onRemove, this);
32761 ds.on("update", this.onUpdate, this);
32762 ds.on("clear", this.onClear, this);
32767 this.cm.un("widthchange", this.onColWidthChange, this);
32768 this.cm.un("headerchange", this.onHeaderChange, this);
32769 this.cm.un("hiddenchange", this.onHiddenChange, this);
32770 this.cm.un("columnmoved", this.onColumnMove, this);
32771 this.cm.un("columnlockchange", this.onColumnLock, this);
32774 this.generateRules(cm);
32775 cm.on("widthchange", this.onColWidthChange, this);
32776 cm.on("headerchange", this.onHeaderChange, this);
32777 cm.on("hiddenchange", this.onHiddenChange, this);
32778 cm.on("columnmoved", this.onColumnMove, this);
32779 cm.on("columnlockchange", this.onColumnLock, this);
32784 init: function(grid){
32785 Roo.grid.GridView.superclass.init.call(this, grid);
32787 this.bind(grid.dataSource, grid.colModel);
32789 grid.on("headerclick", this.handleHeaderClick, this);
32791 if(grid.trackMouseOver){
32792 grid.on("mouseover", this.onRowOver, this);
32793 grid.on("mouseout", this.onRowOut, this);
32795 grid.cancelTextSelection = function(){};
32796 this.gridId = grid.id;
32798 var tpls = this.templates || {};
32801 tpls.master = new Roo.Template(
32802 '<div class="x-grid" hidefocus="true">',
32803 '<div class="x-grid-topbar"></div>',
32804 '<div class="x-grid-scroller"><div></div></div>',
32805 '<div class="x-grid-locked">',
32806 '<div class="x-grid-header">{lockedHeader}</div>',
32807 '<div class="x-grid-body">{lockedBody}</div>',
32809 '<div class="x-grid-viewport">',
32810 '<div class="x-grid-header">{header}</div>',
32811 '<div class="x-grid-body">{body}</div>',
32813 '<div class="x-grid-bottombar"></div>',
32814 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
32815 '<div class="x-grid-resize-proxy"> </div>',
32818 tpls.master.disableformats = true;
32822 tpls.header = new Roo.Template(
32823 '<table border="0" cellspacing="0" cellpadding="0">',
32824 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
32827 tpls.header.disableformats = true;
32829 tpls.header.compile();
32832 tpls.hcell = new Roo.Template(
32833 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
32834 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
32837 tpls.hcell.disableFormats = true;
32839 tpls.hcell.compile();
32842 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
32843 tpls.hsplit.disableFormats = true;
32845 tpls.hsplit.compile();
32848 tpls.body = new Roo.Template(
32849 '<table border="0" cellspacing="0" cellpadding="0">',
32850 "<tbody>{rows}</tbody>",
32853 tpls.body.disableFormats = true;
32855 tpls.body.compile();
32858 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
32859 tpls.row.disableFormats = true;
32861 tpls.row.compile();
32864 tpls.cell = new Roo.Template(
32865 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
32866 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
32869 tpls.cell.disableFormats = true;
32871 tpls.cell.compile();
32873 this.templates = tpls;
32876 // remap these for backwards compat
32877 onColWidthChange : function(){
32878 this.updateColumns.apply(this, arguments);
32880 onHeaderChange : function(){
32881 this.updateHeaders.apply(this, arguments);
32883 onHiddenChange : function(){
32884 this.handleHiddenChange.apply(this, arguments);
32886 onColumnMove : function(){
32887 this.handleColumnMove.apply(this, arguments);
32889 onColumnLock : function(){
32890 this.handleLockChange.apply(this, arguments);
32893 onDataChange : function(){
32895 this.updateHeaderSortState();
32898 onClear : function(){
32902 onUpdate : function(ds, record){
32903 this.refreshRow(record);
32906 refreshRow : function(record){
32907 var ds = this.ds, index;
32908 if(typeof record == 'number'){
32910 record = ds.getAt(index);
32912 index = ds.indexOf(record);
32914 this.insertRows(ds, index, index, true);
32915 this.onRemove(ds, record, index+1, true);
32916 this.syncRowHeights(index, index);
32918 this.fireEvent("rowupdated", this, index, record);
32921 onAdd : function(ds, records, index){
32922 this.insertRows(ds, index, index + (records.length-1));
32925 onRemove : function(ds, record, index, isUpdate){
32926 if(isUpdate !== true){
32927 this.fireEvent("beforerowremoved", this, index, record);
32929 var bt = this.getBodyTable(), lt = this.getLockedTable();
32930 if(bt.rows[index]){
32931 bt.firstChild.removeChild(bt.rows[index]);
32933 if(lt.rows[index]){
32934 lt.firstChild.removeChild(lt.rows[index]);
32936 if(isUpdate !== true){
32937 this.stripeRows(index);
32938 this.syncRowHeights(index, index);
32940 this.fireEvent("rowremoved", this, index, record);
32944 onLoad : function(){
32945 this.scrollToTop();
32949 * Scrolls the grid to the top
32951 scrollToTop : function(){
32953 this.scroller.dom.scrollTop = 0;
32959 * Gets a panel in the header of the grid that can be used for toolbars etc.
32960 * After modifying the contents of this panel a call to grid.autoSize() may be
32961 * required to register any changes in size.
32962 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
32963 * @return Roo.Element
32965 getHeaderPanel : function(doShow){
32967 this.headerPanel.show();
32969 return this.headerPanel;
32973 * Gets a panel in the footer of the grid that can be used for toolbars etc.
32974 * After modifying the contents of this panel a call to grid.autoSize() may be
32975 * required to register any changes in size.
32976 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
32977 * @return Roo.Element
32979 getFooterPanel : function(doShow){
32981 this.footerPanel.show();
32983 return this.footerPanel;
32986 initElements : function(){
32987 var E = Roo.Element;
32988 var el = this.grid.getGridEl().dom.firstChild;
32989 var cs = el.childNodes;
32991 this.el = new E(el);
32992 this.headerPanel = new E(el.firstChild);
32993 this.headerPanel.enableDisplayMode("block");
32995 this.scroller = new E(cs[1]);
32996 this.scrollSizer = new E(this.scroller.dom.firstChild);
32998 this.lockedWrap = new E(cs[2]);
32999 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33000 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33002 this.mainWrap = new E(cs[3]);
33003 this.mainHd = new E(this.mainWrap.dom.firstChild);
33004 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33006 this.footerPanel = new E(cs[4]);
33007 this.footerPanel.enableDisplayMode("block");
33009 this.focusEl = new E(cs[5]);
33010 this.focusEl.swallowEvent("click", true);
33011 this.resizeProxy = new E(cs[6]);
33013 this.headerSelector = String.format(
33014 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33015 this.lockedHd.id, this.mainHd.id
33018 this.splitterSelector = String.format(
33019 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33020 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33023 idToCssName : function(s)
33025 return s.replace(/[^a-z0-9]+/ig, '-');
33028 getHeaderCell : function(index){
33029 return Roo.DomQuery.select(this.headerSelector)[index];
33032 getHeaderCellMeasure : function(index){
33033 return this.getHeaderCell(index).firstChild;
33036 getHeaderCellText : function(index){
33037 return this.getHeaderCell(index).firstChild.firstChild;
33040 getLockedTable : function(){
33041 return this.lockedBody.dom.firstChild;
33044 getBodyTable : function(){
33045 return this.mainBody.dom.firstChild;
33048 getLockedRow : function(index){
33049 return this.getLockedTable().rows[index];
33052 getRow : function(index){
33053 return this.getBodyTable().rows[index];
33056 getRowComposite : function(index){
33058 this.rowEl = new Roo.CompositeElementLite();
33060 var els = [], lrow, mrow;
33061 if(lrow = this.getLockedRow(index)){
33064 if(mrow = this.getRow(index)){
33067 this.rowEl.elements = els;
33071 getCell : function(rowIndex, colIndex){
33072 var locked = this.cm.getLockedCount();
33074 if(colIndex < locked){
33075 source = this.lockedBody.dom.firstChild;
33077 source = this.mainBody.dom.firstChild;
33078 colIndex -= locked;
33080 return source.rows[rowIndex].childNodes[colIndex];
33083 getCellText : function(rowIndex, colIndex){
33084 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33087 getCellBox : function(cell){
33088 var b = this.fly(cell).getBox();
33089 if(Roo.isOpera){ // opera fails to report the Y
33090 b.y = cell.offsetTop + this.mainBody.getY();
33095 getCellIndex : function(cell){
33096 var id = String(cell.className).match(this.cellRE);
33098 return parseInt(id[1], 10);
33103 findHeaderIndex : function(n){
33104 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33105 return r ? this.getCellIndex(r) : false;
33108 findHeaderCell : function(n){
33109 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33110 return r ? r : false;
33113 findRowIndex : function(n){
33117 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33118 return r ? r.rowIndex : false;
33121 findCellIndex : function(node){
33122 var stop = this.el.dom;
33123 while(node && node != stop){
33124 if(this.findRE.test(node.className)){
33125 return this.getCellIndex(node);
33127 node = node.parentNode;
33132 getColumnId : function(index){
33133 return this.cm.getColumnId(index);
33136 getSplitters : function(){
33137 if(this.splitterSelector){
33138 return Roo.DomQuery.select(this.splitterSelector);
33144 getSplitter : function(index){
33145 return this.getSplitters()[index];
33148 onRowOver : function(e, t){
33150 if((row = this.findRowIndex(t)) !== false){
33151 this.getRowComposite(row).addClass("x-grid-row-over");
33155 onRowOut : function(e, t){
33157 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33158 this.getRowComposite(row).removeClass("x-grid-row-over");
33162 renderHeaders : function(){
33164 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33165 var cb = [], lb = [], sb = [], lsb = [], p = {};
33166 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33167 p.cellId = "x-grid-hd-0-" + i;
33168 p.splitId = "x-grid-csplit-0-" + i;
33169 p.id = cm.getColumnId(i);
33170 p.title = cm.getColumnTooltip(i) || "";
33171 p.value = cm.getColumnHeader(i) || "";
33172 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33173 if(!cm.isLocked(i)){
33174 cb[cb.length] = ct.apply(p);
33175 sb[sb.length] = st.apply(p);
33177 lb[lb.length] = ct.apply(p);
33178 lsb[lsb.length] = st.apply(p);
33181 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33182 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33185 updateHeaders : function(){
33186 var html = this.renderHeaders();
33187 this.lockedHd.update(html[0]);
33188 this.mainHd.update(html[1]);
33192 * Focuses the specified row.
33193 * @param {Number} row The row index
33195 focusRow : function(row){
33196 var x = this.scroller.dom.scrollLeft;
33197 this.focusCell(row, 0, false);
33198 this.scroller.dom.scrollLeft = x;
33202 * Focuses the specified cell.
33203 * @param {Number} row The row index
33204 * @param {Number} col The column index
33205 * @param {Boolean} hscroll false to disable horizontal scrolling
33207 focusCell : function(row, col, hscroll){
33208 var el = this.ensureVisible(row, col, hscroll);
33209 this.focusEl.alignTo(el, "tl-tl");
33211 this.focusEl.focus();
33213 this.focusEl.focus.defer(1, this.focusEl);
33218 * Scrolls the specified cell into view
33219 * @param {Number} row The row index
33220 * @param {Number} col The column index
33221 * @param {Boolean} hscroll false to disable horizontal scrolling
33223 ensureVisible : function(row, col, hscroll){
33224 if(typeof row != "number"){
33225 row = row.rowIndex;
33227 if(row < 0 && row >= this.ds.getCount()){
33230 col = (col !== undefined ? col : 0);
33231 var cm = this.grid.colModel;
33232 while(cm.isHidden(col)){
33236 var el = this.getCell(row, col);
33240 var c = this.scroller.dom;
33242 var ctop = parseInt(el.offsetTop, 10);
33243 var cleft = parseInt(el.offsetLeft, 10);
33244 var cbot = ctop + el.offsetHeight;
33245 var cright = cleft + el.offsetWidth;
33247 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33248 var stop = parseInt(c.scrollTop, 10);
33249 var sleft = parseInt(c.scrollLeft, 10);
33250 var sbot = stop + ch;
33251 var sright = sleft + c.clientWidth;
33254 c.scrollTop = ctop;
33255 }else if(cbot > sbot){
33256 c.scrollTop = cbot-ch;
33259 if(hscroll !== false){
33261 c.scrollLeft = cleft;
33262 }else if(cright > sright){
33263 c.scrollLeft = cright-c.clientWidth;
33269 updateColumns : function(){
33270 this.grid.stopEditing();
33271 var cm = this.grid.colModel, colIds = this.getColumnIds();
33272 //var totalWidth = cm.getTotalWidth();
33274 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33275 //if(cm.isHidden(i)) continue;
33276 var w = cm.getColumnWidth(i);
33277 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33278 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33280 this.updateSplitters();
33283 generateRules : function(cm){
33284 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33285 Roo.util.CSS.removeStyleSheet(rulesId);
33286 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33287 var cid = cm.getColumnId(i);
33289 if(cm.config[i].align){
33290 align = 'text-align:'+cm.config[i].align+';';
33293 if(cm.isHidden(i)){
33294 hidden = 'display:none;';
33296 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33298 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33299 this.hdSelector, cid, " {\n", align, width, "}\n",
33300 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33301 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33303 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33306 updateSplitters : function(){
33307 var cm = this.cm, s = this.getSplitters();
33308 if(s){ // splitters not created yet
33309 var pos = 0, locked = true;
33310 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33311 if(cm.isHidden(i)) continue;
33312 var w = cm.getColumnWidth(i);
33313 if(!cm.isLocked(i) && locked){
33318 s[i].style.left = (pos-this.splitOffset) + "px";
33323 handleHiddenChange : function(colModel, colIndex, hidden){
33325 this.hideColumn(colIndex);
33327 this.unhideColumn(colIndex);
33331 hideColumn : function(colIndex){
33332 var cid = this.getColumnId(colIndex);
33333 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33334 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33336 this.updateHeaders();
33338 this.updateSplitters();
33342 unhideColumn : function(colIndex){
33343 var cid = this.getColumnId(colIndex);
33344 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33345 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33348 this.updateHeaders();
33350 this.updateSplitters();
33354 insertRows : function(dm, firstRow, lastRow, isUpdate){
33355 if(firstRow == 0 && lastRow == dm.getCount()-1){
33359 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33361 var s = this.getScrollState();
33362 var markup = this.renderRows(firstRow, lastRow);
33363 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33364 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33365 this.restoreScroll(s);
33367 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33368 this.syncRowHeights(firstRow, lastRow);
33369 this.stripeRows(firstRow);
33375 bufferRows : function(markup, target, index){
33376 var before = null, trows = target.rows, tbody = target.tBodies[0];
33377 if(index < trows.length){
33378 before = trows[index];
33380 var b = document.createElement("div");
33381 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33382 var rows = b.firstChild.rows;
33383 for(var i = 0, len = rows.length; i < len; i++){
33385 tbody.insertBefore(rows[0], before);
33387 tbody.appendChild(rows[0]);
33394 deleteRows : function(dm, firstRow, lastRow){
33395 if(dm.getRowCount()<1){
33396 this.fireEvent("beforerefresh", this);
33397 this.mainBody.update("");
33398 this.lockedBody.update("");
33399 this.fireEvent("refresh", this);
33401 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33402 var bt = this.getBodyTable();
33403 var tbody = bt.firstChild;
33404 var rows = bt.rows;
33405 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33406 tbody.removeChild(rows[firstRow]);
33408 this.stripeRows(firstRow);
33409 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33413 updateRows : function(dataSource, firstRow, lastRow){
33414 var s = this.getScrollState();
33416 this.restoreScroll(s);
33419 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33423 this.updateHeaderSortState();
33426 getScrollState : function(){
33427 var sb = this.scroller.dom;
33428 return {left: sb.scrollLeft, top: sb.scrollTop};
33431 stripeRows : function(startRow){
33432 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33435 startRow = startRow || 0;
33436 var rows = this.getBodyTable().rows;
33437 var lrows = this.getLockedTable().rows;
33438 var cls = ' x-grid-row-alt ';
33439 for(var i = startRow, len = rows.length; i < len; i++){
33440 var row = rows[i], lrow = lrows[i];
33441 var isAlt = ((i+1) % 2 == 0);
33442 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33443 if(isAlt == hasAlt){
33447 row.className += " x-grid-row-alt";
33449 row.className = row.className.replace("x-grid-row-alt", "");
33452 lrow.className = row.className;
33457 restoreScroll : function(state){
33458 var sb = this.scroller.dom;
33459 sb.scrollLeft = state.left;
33460 sb.scrollTop = state.top;
33464 syncScroll : function(){
33465 var sb = this.scroller.dom;
33466 var sh = this.mainHd.dom;
33467 var bs = this.mainBody.dom;
33468 var lv = this.lockedBody.dom;
33469 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33470 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33473 handleScroll : function(e){
33475 var sb = this.scroller.dom;
33476 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33480 handleWheel : function(e){
33481 var d = e.getWheelDelta();
33482 this.scroller.dom.scrollTop -= d*22;
33483 // set this here to prevent jumpy scrolling on large tables
33484 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33488 renderRows : function(startRow, endRow){
33489 // pull in all the crap needed to render rows
33490 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33491 var colCount = cm.getColumnCount();
33493 if(ds.getCount() < 1){
33497 // build a map for all the columns
33499 for(var i = 0; i < colCount; i++){
33500 var name = cm.getDataIndex(i);
33502 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33503 renderer : cm.getRenderer(i),
33504 id : cm.getColumnId(i),
33505 locked : cm.isLocked(i)
33509 startRow = startRow || 0;
33510 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33512 // records to render
33513 var rs = ds.getRange(startRow, endRow);
33515 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33518 // As much as I hate to duplicate code, this was branched because FireFox really hates
33519 // [].join("") on strings. The performance difference was substantial enough to
33520 // branch this function
33521 doRender : Roo.isGecko ?
33522 function(cs, rs, ds, startRow, colCount, stripe){
33523 var ts = this.templates, ct = ts.cell, rt = ts.row;
33525 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33526 for(var j = 0, len = rs.length; j < len; j++){
33527 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33528 for(var i = 0; i < colCount; i++){
33530 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33532 p.css = p.attr = "";
33533 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33534 if(p.value == undefined || p.value === "") p.value = " ";
33535 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33536 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33538 var markup = ct.apply(p);
33546 if(stripe && ((rowIndex+1) % 2 == 0)){
33547 alt[0] = "x-grid-row-alt";
33550 alt[1] = " x-grid-dirty-row";
33553 if(this.getRowClass){
33554 alt[2] = this.getRowClass(r, rowIndex);
33556 rp.alt = alt.join(" ");
33557 lbuf+= rt.apply(rp);
33559 buf+= rt.apply(rp);
33561 return [lbuf, buf];
33563 function(cs, rs, ds, startRow, colCount, stripe){
33564 var ts = this.templates, ct = ts.cell, rt = ts.row;
33566 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33567 for(var j = 0, len = rs.length; j < len; j++){
33568 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33569 for(var i = 0; i < colCount; i++){
33571 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33573 p.css = p.attr = "";
33574 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33575 if(p.value == undefined || p.value === "") p.value = " ";
33576 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33577 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33579 var markup = ct.apply(p);
33581 cb[cb.length] = markup;
33583 lcb[lcb.length] = markup;
33587 if(stripe && ((rowIndex+1) % 2 == 0)){
33588 alt[0] = "x-grid-row-alt";
33591 alt[1] = " x-grid-dirty-row";
33594 if(this.getRowClass){
33595 alt[2] = this.getRowClass(r, rowIndex);
33597 rp.alt = alt.join(" ");
33598 rp.cells = lcb.join("");
33599 lbuf[lbuf.length] = rt.apply(rp);
33600 rp.cells = cb.join("");
33601 buf[buf.length] = rt.apply(rp);
33603 return [lbuf.join(""), buf.join("")];
33606 renderBody : function(){
33607 var markup = this.renderRows();
33608 var bt = this.templates.body;
33609 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33613 * Refreshes the grid
33614 * @param {Boolean} headersToo
33616 refresh : function(headersToo){
33617 this.fireEvent("beforerefresh", this);
33618 this.grid.stopEditing();
33619 var result = this.renderBody();
33620 this.lockedBody.update(result[0]);
33621 this.mainBody.update(result[1]);
33622 if(headersToo === true){
33623 this.updateHeaders();
33624 this.updateColumns();
33625 this.updateSplitters();
33626 this.updateHeaderSortState();
33628 this.syncRowHeights();
33630 this.fireEvent("refresh", this);
33633 handleColumnMove : function(cm, oldIndex, newIndex){
33634 this.indexMap = null;
33635 var s = this.getScrollState();
33636 this.refresh(true);
33637 this.restoreScroll(s);
33638 this.afterMove(newIndex);
33641 afterMove : function(colIndex){
33642 if(this.enableMoveAnim && Roo.enableFx){
33643 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
33647 updateCell : function(dm, rowIndex, dataIndex){
33648 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
33649 if(typeof colIndex == "undefined"){ // not present in grid
33652 var cm = this.grid.colModel;
33653 var cell = this.getCell(rowIndex, colIndex);
33654 var cellText = this.getCellText(rowIndex, colIndex);
33657 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
33658 id : cm.getColumnId(colIndex),
33659 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
33661 var renderer = cm.getRenderer(colIndex);
33662 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
33663 if(typeof val == "undefined" || val === "") val = " ";
33664 cellText.innerHTML = val;
33665 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
33666 this.syncRowHeights(rowIndex, rowIndex);
33669 calcColumnWidth : function(colIndex, maxRowsToMeasure){
33671 if(this.grid.autoSizeHeaders){
33672 var h = this.getHeaderCellMeasure(colIndex);
33673 maxWidth = Math.max(maxWidth, h.scrollWidth);
33676 if(this.cm.isLocked(colIndex)){
33677 tb = this.getLockedTable();
33680 tb = this.getBodyTable();
33681 index = colIndex - this.cm.getLockedCount();
33684 var rows = tb.rows;
33685 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
33686 for(var i = 0; i < stopIndex; i++){
33687 var cell = rows[i].childNodes[index].firstChild;
33688 maxWidth = Math.max(maxWidth, cell.scrollWidth);
33691 return maxWidth + /*margin for error in IE*/ 5;
33694 * Autofit a column to its content.
33695 * @param {Number} colIndex
33696 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
33698 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
33699 if(this.cm.isHidden(colIndex)){
33700 return; // can't calc a hidden column
33703 var cid = this.cm.getColumnId(colIndex);
33704 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
33705 if(this.grid.autoSizeHeaders){
33706 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
33709 var newWidth = this.calcColumnWidth(colIndex);
33710 this.cm.setColumnWidth(colIndex,
33711 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
33712 if(!suppressEvent){
33713 this.grid.fireEvent("columnresize", colIndex, newWidth);
33718 * Autofits all columns to their content and then expands to fit any extra space in the grid
33720 autoSizeColumns : function(){
33721 var cm = this.grid.colModel;
33722 var colCount = cm.getColumnCount();
33723 for(var i = 0; i < colCount; i++){
33724 this.autoSizeColumn(i, true, true);
33726 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
33729 this.updateColumns();
33735 * Autofits all columns to the grid's width proportionate with their current size
33736 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
33738 fitColumns : function(reserveScrollSpace){
33739 var cm = this.grid.colModel;
33740 var colCount = cm.getColumnCount();
33744 for (i = 0; i < colCount; i++){
33745 if(!cm.isHidden(i) && !cm.isFixed(i)){
33746 w = cm.getColumnWidth(i);
33752 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
33753 if(reserveScrollSpace){
33756 var frac = (avail - cm.getTotalWidth())/width;
33757 while (cols.length){
33760 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
33762 this.updateColumns();
33766 onRowSelect : function(rowIndex){
33767 var row = this.getRowComposite(rowIndex);
33768 row.addClass("x-grid-row-selected");
33771 onRowDeselect : function(rowIndex){
33772 var row = this.getRowComposite(rowIndex);
33773 row.removeClass("x-grid-row-selected");
33776 onCellSelect : function(row, col){
33777 var cell = this.getCell(row, col);
33779 Roo.fly(cell).addClass("x-grid-cell-selected");
33783 onCellDeselect : function(row, col){
33784 var cell = this.getCell(row, col);
33786 Roo.fly(cell).removeClass("x-grid-cell-selected");
33790 updateHeaderSortState : function(){
33791 var state = this.ds.getSortState();
33795 this.sortState = state;
33796 var sortColumn = this.cm.findColumnIndex(state.field);
33797 if(sortColumn != -1){
33798 var sortDir = state.direction;
33799 var sc = this.sortClasses;
33800 var hds = this.el.select(this.headerSelector).removeClass(sc);
33801 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
33805 handleHeaderClick : function(g, index){
33806 if(this.headersDisabled){
33809 var dm = g.dataSource, cm = g.colModel;
33810 if(!cm.isSortable(index)){
33814 dm.sort(cm.getDataIndex(index));
33818 destroy : function(){
33820 this.colMenu.removeAll();
33821 Roo.menu.MenuMgr.unregister(this.colMenu);
33822 this.colMenu.getEl().remove();
33823 delete this.colMenu;
33826 this.hmenu.removeAll();
33827 Roo.menu.MenuMgr.unregister(this.hmenu);
33828 this.hmenu.getEl().remove();
33831 if(this.grid.enableColumnMove){
33832 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33834 for(var dd in dds){
33835 if(!dds[dd].config.isTarget && dds[dd].dragElId){
33836 var elid = dds[dd].dragElId;
33838 Roo.get(elid).remove();
33839 } else if(dds[dd].config.isTarget){
33840 dds[dd].proxyTop.remove();
33841 dds[dd].proxyBottom.remove();
33844 if(Roo.dd.DDM.locationCache[dd]){
33845 delete Roo.dd.DDM.locationCache[dd];
33848 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33851 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
33852 this.bind(null, null);
33853 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
33856 handleLockChange : function(){
33857 this.refresh(true);
33860 onDenyColumnLock : function(){
33864 onDenyColumnHide : function(){
33868 handleHdMenuClick : function(item){
33869 var index = this.hdCtxIndex;
33870 var cm = this.cm, ds = this.ds;
33873 ds.sort(cm.getDataIndex(index), "ASC");
33876 ds.sort(cm.getDataIndex(index), "DESC");
33879 var lc = cm.getLockedCount();
33880 if(cm.getColumnCount(true) <= lc+1){
33881 this.onDenyColumnLock();
33885 cm.setLocked(index, true, true);
33886 cm.moveColumn(index, lc);
33887 this.grid.fireEvent("columnmove", index, lc);
33889 cm.setLocked(index, true);
33893 var lc = cm.getLockedCount();
33894 if((lc-1) != index){
33895 cm.setLocked(index, false, true);
33896 cm.moveColumn(index, lc-1);
33897 this.grid.fireEvent("columnmove", index, lc-1);
33899 cm.setLocked(index, false);
33903 index = cm.getIndexById(item.id.substr(4));
33905 if(item.checked && cm.getColumnCount(true) <= 1){
33906 this.onDenyColumnHide();
33909 cm.setHidden(index, item.checked);
33915 beforeColMenuShow : function(){
33916 var cm = this.cm, colCount = cm.getColumnCount();
33917 this.colMenu.removeAll();
33918 for(var i = 0; i < colCount; i++){
33919 this.colMenu.add(new Roo.menu.CheckItem({
33920 id: "col-"+cm.getColumnId(i),
33921 text: cm.getColumnHeader(i),
33922 checked: !cm.isHidden(i),
33928 handleHdCtx : function(g, index, e){
33930 var hd = this.getHeaderCell(index);
33931 this.hdCtxIndex = index;
33932 var ms = this.hmenu.items, cm = this.cm;
33933 ms.get("asc").setDisabled(!cm.isSortable(index));
33934 ms.get("desc").setDisabled(!cm.isSortable(index));
33935 if(this.grid.enableColLock !== false){
33936 ms.get("lock").setDisabled(cm.isLocked(index));
33937 ms.get("unlock").setDisabled(!cm.isLocked(index));
33939 this.hmenu.show(hd, "tl-bl");
33942 handleHdOver : function(e){
33943 var hd = this.findHeaderCell(e.getTarget());
33944 if(hd && !this.headersDisabled){
33945 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
33946 this.fly(hd).addClass("x-grid-hd-over");
33951 handleHdOut : function(e){
33952 var hd = this.findHeaderCell(e.getTarget());
33954 this.fly(hd).removeClass("x-grid-hd-over");
33958 handleSplitDblClick : function(e, t){
33959 var i = this.getCellIndex(t);
33960 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
33961 this.autoSizeColumn(i, true);
33966 render : function(){
33969 var colCount = cm.getColumnCount();
33971 if(this.grid.monitorWindowResize === true){
33972 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33974 var header = this.renderHeaders();
33975 var body = this.templates.body.apply({rows:""});
33976 var html = this.templates.master.apply({
33979 lockedHeader: header[0],
33983 //this.updateColumns();
33985 this.grid.getGridEl().dom.innerHTML = html;
33987 this.initElements();
33989 // a kludge to fix the random scolling effect in webkit
33990 this.el.on("scroll", function() {
33991 this.el.dom.scrollTop=0; // hopefully not recursive..
33994 this.scroller.on("scroll", this.handleScroll, this);
33995 this.lockedBody.on("mousewheel", this.handleWheel, this);
33996 this.mainBody.on("mousewheel", this.handleWheel, this);
33998 this.mainHd.on("mouseover", this.handleHdOver, this);
33999 this.mainHd.on("mouseout", this.handleHdOut, this);
34000 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34001 {delegate: "."+this.splitClass});
34003 this.lockedHd.on("mouseover", this.handleHdOver, this);
34004 this.lockedHd.on("mouseout", this.handleHdOut, this);
34005 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34006 {delegate: "."+this.splitClass});
34008 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34009 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34012 this.updateSplitters();
34014 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34015 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34016 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34019 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34020 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34022 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34023 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34025 if(this.grid.enableColLock !== false){
34026 this.hmenu.add('-',
34027 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34028 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34031 if(this.grid.enableColumnHide !== false){
34033 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34034 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34035 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34037 this.hmenu.add('-',
34038 {id:"columns", text: this.columnsText, menu: this.colMenu}
34041 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34043 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34046 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34047 this.dd = new Roo.grid.GridDragZone(this.grid, {
34048 ddGroup : this.grid.ddGroup || 'GridDD'
34053 for(var i = 0; i < colCount; i++){
34054 if(cm.isHidden(i)){
34055 this.hideColumn(i);
34057 if(cm.config[i].align){
34058 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34059 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34063 this.updateHeaderSortState();
34065 this.beforeInitialResize();
34068 // two part rendering gives faster view to the user
34069 this.renderPhase2.defer(1, this);
34072 renderPhase2 : function(){
34073 // render the rows now
34075 if(this.grid.autoSizeColumns){
34076 this.autoSizeColumns();
34080 beforeInitialResize : function(){
34084 onColumnSplitterMoved : function(i, w){
34085 this.userResized = true;
34086 var cm = this.grid.colModel;
34087 cm.setColumnWidth(i, w, true);
34088 var cid = cm.getColumnId(i);
34089 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34090 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34091 this.updateSplitters();
34093 this.grid.fireEvent("columnresize", i, w);
34096 syncRowHeights : function(startIndex, endIndex){
34097 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34098 startIndex = startIndex || 0;
34099 var mrows = this.getBodyTable().rows;
34100 var lrows = this.getLockedTable().rows;
34101 var len = mrows.length-1;
34102 endIndex = Math.min(endIndex || len, len);
34103 for(var i = startIndex; i <= endIndex; i++){
34104 var m = mrows[i], l = lrows[i];
34105 var h = Math.max(m.offsetHeight, l.offsetHeight);
34106 m.style.height = l.style.height = h + "px";
34111 layout : function(initialRender, is2ndPass){
34113 var auto = g.autoHeight;
34114 var scrollOffset = 16;
34115 var c = g.getGridEl(), cm = this.cm,
34116 expandCol = g.autoExpandColumn,
34118 //c.beginMeasure();
34120 if(!c.dom.offsetWidth){ // display:none?
34122 this.lockedWrap.show();
34123 this.mainWrap.show();
34128 var hasLock = this.cm.isLocked(0);
34130 var tbh = this.headerPanel.getHeight();
34131 var bbh = this.footerPanel.getHeight();
34134 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34135 var newHeight = ch + c.getBorderWidth("tb");
34137 newHeight = Math.min(g.maxHeight, newHeight);
34139 c.setHeight(newHeight);
34143 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34146 var s = this.scroller;
34148 var csize = c.getSize(true);
34150 this.el.setSize(csize.width, csize.height);
34152 this.headerPanel.setWidth(csize.width);
34153 this.footerPanel.setWidth(csize.width);
34155 var hdHeight = this.mainHd.getHeight();
34156 var vw = csize.width;
34157 var vh = csize.height - (tbh + bbh);
34161 var bt = this.getBodyTable();
34162 var ltWidth = hasLock ?
34163 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34165 var scrollHeight = bt.offsetHeight;
34166 var scrollWidth = ltWidth + bt.offsetWidth;
34167 var vscroll = false, hscroll = false;
34169 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34171 var lw = this.lockedWrap, mw = this.mainWrap;
34172 var lb = this.lockedBody, mb = this.mainBody;
34174 setTimeout(function(){
34175 var t = s.dom.offsetTop;
34176 var w = s.dom.clientWidth,
34177 h = s.dom.clientHeight;
34180 lw.setSize(ltWidth, h);
34182 mw.setLeftTop(ltWidth, t);
34183 mw.setSize(w-ltWidth, h);
34185 lb.setHeight(h-hdHeight);
34186 mb.setHeight(h-hdHeight);
34188 if(is2ndPass !== true && !gv.userResized && expandCol){
34189 // high speed resize without full column calculation
34191 var ci = cm.getIndexById(expandCol);
34193 ci = cm.findColumnIndex(expandCol);
34195 ci = Math.max(0, ci); // make sure it's got at least the first col.
34196 var expandId = cm.getColumnId(ci);
34197 var tw = cm.getTotalWidth(false);
34198 var currentWidth = cm.getColumnWidth(ci);
34199 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34200 if(currentWidth != cw){
34201 cm.setColumnWidth(ci, cw, true);
34202 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34203 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34204 gv.updateSplitters();
34205 gv.layout(false, true);
34217 onWindowResize : function(){
34218 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34224 appendFooter : function(parentEl){
34228 sortAscText : "Sort Ascending",
34229 sortDescText : "Sort Descending",
34230 lockText : "Lock Column",
34231 unlockText : "Unlock Column",
34232 columnsText : "Columns"
34236 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34237 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34238 this.proxy.el.addClass('x-grid3-col-dd');
34241 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34242 handleMouseDown : function(e){
34246 callHandleMouseDown : function(e){
34247 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34252 * Ext JS Library 1.1.1
34253 * Copyright(c) 2006-2007, Ext JS, LLC.
34255 * Originally Released Under LGPL - original licence link has changed is not relivant.
34258 * <script type="text/javascript">
34262 // This is a support class used internally by the Grid components
34263 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34265 this.view = grid.getView();
34266 this.proxy = this.view.resizeProxy;
34267 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34268 "gridSplitters" + this.grid.getGridEl().id, {
34269 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34271 this.setHandleElId(Roo.id(hd));
34272 this.setOuterHandleElId(Roo.id(hd2));
34273 this.scroll = false;
34275 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34276 fly: Roo.Element.fly,
34278 b4StartDrag : function(x, y){
34279 this.view.headersDisabled = true;
34280 this.proxy.setHeight(this.view.mainWrap.getHeight());
34281 var w = this.cm.getColumnWidth(this.cellIndex);
34282 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34283 this.resetConstraints();
34284 this.setXConstraint(minw, 1000);
34285 this.setYConstraint(0, 0);
34286 this.minX = x - minw;
34287 this.maxX = x + 1000;
34289 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34293 handleMouseDown : function(e){
34294 ev = Roo.EventObject.setEvent(e);
34295 var t = this.fly(ev.getTarget());
34296 if(t.hasClass("x-grid-split")){
34297 this.cellIndex = this.view.getCellIndex(t.dom);
34298 this.split = t.dom;
34299 this.cm = this.grid.colModel;
34300 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34301 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34306 endDrag : function(e){
34307 this.view.headersDisabled = false;
34308 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34309 var diff = endX - this.startPos;
34310 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34313 autoOffset : function(){
34314 this.setDelta(0,0);
34318 * Ext JS Library 1.1.1
34319 * Copyright(c) 2006-2007, Ext JS, LLC.
34321 * Originally Released Under LGPL - original licence link has changed is not relivant.
34324 * <script type="text/javascript">
34328 // This is a support class used internally by the Grid components
34329 Roo.grid.GridDragZone = function(grid, config){
34330 this.view = grid.getView();
34331 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34332 if(this.view.lockedBody){
34333 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34334 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34336 this.scroll = false;
34338 this.ddel = document.createElement('div');
34339 this.ddel.className = 'x-grid-dd-wrap';
34342 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34343 ddGroup : "GridDD",
34345 getDragData : function(e){
34346 var t = Roo.lib.Event.getTarget(e);
34347 var rowIndex = this.view.findRowIndex(t);
34348 if(rowIndex !== false){
34349 var sm = this.grid.selModel;
34350 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34351 // sm.mouseDown(e, t);
34353 if (e.hasModifier()){
34354 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34356 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34361 onInitDrag : function(e){
34362 var data = this.dragData;
34363 this.ddel.innerHTML = this.grid.getDragDropText();
34364 this.proxy.update(this.ddel);
34365 // fire start drag?
34368 afterRepair : function(){
34369 this.dragging = false;
34372 getRepairXY : function(e, data){
34376 onEndDrag : function(data, e){
34380 onValidDrop : function(dd, e, id){
34385 beforeInvalidDrop : function(e, id){
34390 * Ext JS Library 1.1.1
34391 * Copyright(c) 2006-2007, Ext JS, LLC.
34393 * Originally Released Under LGPL - original licence link has changed is not relivant.
34396 * <script type="text/javascript">
34401 * @class Roo.grid.ColumnModel
34402 * @extends Roo.util.Observable
34403 * This is the default implementation of a ColumnModel used by the Grid. It defines
34404 * the columns in the grid.
34407 var colModel = new Roo.grid.ColumnModel([
34408 {header: "Ticker", width: 60, sortable: true, locked: true},
34409 {header: "Company Name", width: 150, sortable: true},
34410 {header: "Market Cap.", width: 100, sortable: true},
34411 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34412 {header: "Employees", width: 100, sortable: true, resizable: false}
34417 * The config options listed for this class are options which may appear in each
34418 * individual column definition.
34419 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34421 * @param {Object} config An Array of column config objects. See this class's
34422 * config objects for details.
34424 Roo.grid.ColumnModel = function(config){
34426 * The config passed into the constructor
34428 this.config = config;
34431 // if no id, create one
34432 // if the column does not have a dataIndex mapping,
34433 // map it to the order it is in the config
34434 for(var i = 0, len = config.length; i < len; i++){
34436 if(typeof c.dataIndex == "undefined"){
34439 if(typeof c.renderer == "string"){
34440 c.renderer = Roo.util.Format[c.renderer];
34442 if(typeof c.id == "undefined"){
34445 if(c.editor && c.editor.xtype){
34446 c.editor = Roo.factory(c.editor, Roo.grid);
34448 if(c.editor && c.editor.isFormField){
34449 c.editor = new Roo.grid.GridEditor(c.editor);
34451 this.lookup[c.id] = c;
34455 * The width of columns which have no width specified (defaults to 100)
34458 this.defaultWidth = 100;
34461 * Default sortable of columns which have no sortable specified (defaults to false)
34464 this.defaultSortable = false;
34468 * @event widthchange
34469 * Fires when the width of a column changes.
34470 * @param {ColumnModel} this
34471 * @param {Number} columnIndex The column index
34472 * @param {Number} newWidth The new width
34474 "widthchange": true,
34476 * @event headerchange
34477 * Fires when the text of a header changes.
34478 * @param {ColumnModel} this
34479 * @param {Number} columnIndex The column index
34480 * @param {Number} newText The new header text
34482 "headerchange": true,
34484 * @event hiddenchange
34485 * Fires when a column is hidden or "unhidden".
34486 * @param {ColumnModel} this
34487 * @param {Number} columnIndex The column index
34488 * @param {Boolean} hidden true if hidden, false otherwise
34490 "hiddenchange": true,
34492 * @event columnmoved
34493 * Fires when a column is moved.
34494 * @param {ColumnModel} this
34495 * @param {Number} oldIndex
34496 * @param {Number} newIndex
34498 "columnmoved" : true,
34500 * @event columlockchange
34501 * Fires when a column's locked state is changed
34502 * @param {ColumnModel} this
34503 * @param {Number} colIndex
34504 * @param {Boolean} locked true if locked
34506 "columnlockchange" : true
34508 Roo.grid.ColumnModel.superclass.constructor.call(this);
34510 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34512 * @cfg {String} header The header text to display in the Grid view.
34515 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34516 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34517 * specified, the column's index is used as an index into the Record's data Array.
34520 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34521 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34524 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34525 * Defaults to the value of the {@link #defaultSortable} property.
34526 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34529 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34532 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34535 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34538 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34541 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34542 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34543 * default renderer uses the raw data value.
34546 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34549 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34553 * Returns the id of the column at the specified index.
34554 * @param {Number} index The column index
34555 * @return {String} the id
34557 getColumnId : function(index){
34558 return this.config[index].id;
34562 * Returns the column for a specified id.
34563 * @param {String} id The column id
34564 * @return {Object} the column
34566 getColumnById : function(id){
34567 return this.lookup[id];
34572 * Returns the column for a specified dataIndex.
34573 * @param {String} dataIndex The column dataIndex
34574 * @return {Object|Boolean} the column or false if not found
34576 getColumnByDataIndex: function(dataIndex){
34577 var index = this.findColumnIndex(dataIndex);
34578 return index > -1 ? this.config[index] : false;
34582 * Returns the index for a specified column id.
34583 * @param {String} id The column id
34584 * @return {Number} the index, or -1 if not found
34586 getIndexById : function(id){
34587 for(var i = 0, len = this.config.length; i < len; i++){
34588 if(this.config[i].id == id){
34596 * Returns the index for a specified column dataIndex.
34597 * @param {String} dataIndex The column dataIndex
34598 * @return {Number} the index, or -1 if not found
34601 findColumnIndex : function(dataIndex){
34602 for(var i = 0, len = this.config.length; i < len; i++){
34603 if(this.config[i].dataIndex == dataIndex){
34611 moveColumn : function(oldIndex, newIndex){
34612 var c = this.config[oldIndex];
34613 this.config.splice(oldIndex, 1);
34614 this.config.splice(newIndex, 0, c);
34615 this.dataMap = null;
34616 this.fireEvent("columnmoved", this, oldIndex, newIndex);
34619 isLocked : function(colIndex){
34620 return this.config[colIndex].locked === true;
34623 setLocked : function(colIndex, value, suppressEvent){
34624 if(this.isLocked(colIndex) == value){
34627 this.config[colIndex].locked = value;
34628 if(!suppressEvent){
34629 this.fireEvent("columnlockchange", this, colIndex, value);
34633 getTotalLockedWidth : function(){
34634 var totalWidth = 0;
34635 for(var i = 0; i < this.config.length; i++){
34636 if(this.isLocked(i) && !this.isHidden(i)){
34637 this.totalWidth += this.getColumnWidth(i);
34643 getLockedCount : function(){
34644 for(var i = 0, len = this.config.length; i < len; i++){
34645 if(!this.isLocked(i)){
34652 * Returns the number of columns.
34655 getColumnCount : function(visibleOnly){
34656 if(visibleOnly === true){
34658 for(var i = 0, len = this.config.length; i < len; i++){
34659 if(!this.isHidden(i)){
34665 return this.config.length;
34669 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
34670 * @param {Function} fn
34671 * @param {Object} scope (optional)
34672 * @return {Array} result
34674 getColumnsBy : function(fn, scope){
34676 for(var i = 0, len = this.config.length; i < len; i++){
34677 var c = this.config[i];
34678 if(fn.call(scope||this, c, i) === true){
34686 * Returns true if the specified column is sortable.
34687 * @param {Number} col The column index
34688 * @return {Boolean}
34690 isSortable : function(col){
34691 if(typeof this.config[col].sortable == "undefined"){
34692 return this.defaultSortable;
34694 return this.config[col].sortable;
34698 * Returns the rendering (formatting) function defined for the column.
34699 * @param {Number} col The column index.
34700 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
34702 getRenderer : function(col){
34703 if(!this.config[col].renderer){
34704 return Roo.grid.ColumnModel.defaultRenderer;
34706 return this.config[col].renderer;
34710 * Sets the rendering (formatting) function for a column.
34711 * @param {Number} col The column index
34712 * @param {Function} fn The function to use to process the cell's raw data
34713 * to return HTML markup for the grid view. The render function is called with
34714 * the following parameters:<ul>
34715 * <li>Data value.</li>
34716 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
34717 * <li>css A CSS style string to apply to the table cell.</li>
34718 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
34719 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
34720 * <li>Row index</li>
34721 * <li>Column index</li>
34722 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
34724 setRenderer : function(col, fn){
34725 this.config[col].renderer = fn;
34729 * Returns the width for the specified column.
34730 * @param {Number} col The column index
34733 getColumnWidth : function(col){
34734 return this.config[col].width || this.defaultWidth;
34738 * Sets the width for a column.
34739 * @param {Number} col The column index
34740 * @param {Number} width The new width
34742 setColumnWidth : function(col, width, suppressEvent){
34743 this.config[col].width = width;
34744 this.totalWidth = null;
34745 if(!suppressEvent){
34746 this.fireEvent("widthchange", this, col, width);
34751 * Returns the total width of all columns.
34752 * @param {Boolean} includeHidden True to include hidden column widths
34755 getTotalWidth : function(includeHidden){
34756 if(!this.totalWidth){
34757 this.totalWidth = 0;
34758 for(var i = 0, len = this.config.length; i < len; i++){
34759 if(includeHidden || !this.isHidden(i)){
34760 this.totalWidth += this.getColumnWidth(i);
34764 return this.totalWidth;
34768 * Returns the header for the specified column.
34769 * @param {Number} col The column index
34772 getColumnHeader : function(col){
34773 return this.config[col].header;
34777 * Sets the header for a column.
34778 * @param {Number} col The column index
34779 * @param {String} header The new header
34781 setColumnHeader : function(col, header){
34782 this.config[col].header = header;
34783 this.fireEvent("headerchange", this, col, header);
34787 * Returns the tooltip for the specified column.
34788 * @param {Number} col The column index
34791 getColumnTooltip : function(col){
34792 return this.config[col].tooltip;
34795 * Sets the tooltip for a column.
34796 * @param {Number} col The column index
34797 * @param {String} tooltip The new tooltip
34799 setColumnTooltip : function(col, tooltip){
34800 this.config[col].tooltip = tooltip;
34804 * Returns the dataIndex for the specified column.
34805 * @param {Number} col The column index
34808 getDataIndex : function(col){
34809 return this.config[col].dataIndex;
34813 * Sets the dataIndex for a column.
34814 * @param {Number} col The column index
34815 * @param {Number} dataIndex The new dataIndex
34817 setDataIndex : function(col, dataIndex){
34818 this.config[col].dataIndex = dataIndex;
34824 * Returns true if the cell is editable.
34825 * @param {Number} colIndex The column index
34826 * @param {Number} rowIndex The row index
34827 * @return {Boolean}
34829 isCellEditable : function(colIndex, rowIndex){
34830 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
34834 * Returns the editor defined for the cell/column.
34835 * return false or null to disable editing.
34836 * @param {Number} colIndex The column index
34837 * @param {Number} rowIndex The row index
34840 getCellEditor : function(colIndex, rowIndex){
34841 return this.config[colIndex].editor;
34845 * Sets if a column is editable.
34846 * @param {Number} col The column index
34847 * @param {Boolean} editable True if the column is editable
34849 setEditable : function(col, editable){
34850 this.config[col].editable = editable;
34855 * Returns true if the column is hidden.
34856 * @param {Number} colIndex The column index
34857 * @return {Boolean}
34859 isHidden : function(colIndex){
34860 return this.config[colIndex].hidden;
34865 * Returns true if the column width cannot be changed
34867 isFixed : function(colIndex){
34868 return this.config[colIndex].fixed;
34872 * Returns true if the column can be resized
34873 * @return {Boolean}
34875 isResizable : function(colIndex){
34876 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
34879 * Sets if a column is hidden.
34880 * @param {Number} colIndex The column index
34881 * @param {Boolean} hidden True if the column is hidden
34883 setHidden : function(colIndex, hidden){
34884 this.config[colIndex].hidden = hidden;
34885 this.totalWidth = null;
34886 this.fireEvent("hiddenchange", this, colIndex, hidden);
34890 * Sets the editor for a column.
34891 * @param {Number} col The column index
34892 * @param {Object} editor The editor object
34894 setEditor : function(col, editor){
34895 this.config[col].editor = editor;
34899 Roo.grid.ColumnModel.defaultRenderer = function(value){
34900 if(typeof value == "string" && value.length < 1){
34906 // Alias for backwards compatibility
34907 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
34910 * Ext JS Library 1.1.1
34911 * Copyright(c) 2006-2007, Ext JS, LLC.
34913 * Originally Released Under LGPL - original licence link has changed is not relivant.
34916 * <script type="text/javascript">
34920 * @class Roo.grid.AbstractSelectionModel
34921 * @extends Roo.util.Observable
34922 * Abstract base class for grid SelectionModels. It provides the interface that should be
34923 * implemented by descendant classes. This class should not be directly instantiated.
34926 Roo.grid.AbstractSelectionModel = function(){
34927 this.locked = false;
34928 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
34931 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
34932 /** @ignore Called by the grid automatically. Do not call directly. */
34933 init : function(grid){
34939 * Locks the selections.
34942 this.locked = true;
34946 * Unlocks the selections.
34948 unlock : function(){
34949 this.locked = false;
34953 * Returns true if the selections are locked.
34954 * @return {Boolean}
34956 isLocked : function(){
34957 return this.locked;
34961 * Ext JS Library 1.1.1
34962 * Copyright(c) 2006-2007, Ext JS, LLC.
34964 * Originally Released Under LGPL - original licence link has changed is not relivant.
34967 * <script type="text/javascript">
34970 * @extends Roo.grid.AbstractSelectionModel
34971 * @class Roo.grid.RowSelectionModel
34972 * The default SelectionModel used by {@link Roo.grid.Grid}.
34973 * It supports multiple selections and keyboard selection/navigation.
34975 * @param {Object} config
34977 Roo.grid.RowSelectionModel = function(config){
34978 Roo.apply(this, config);
34979 this.selections = new Roo.util.MixedCollection(false, function(o){
34984 this.lastActive = false;
34988 * @event selectionchange
34989 * Fires when the selection changes
34990 * @param {SelectionModel} this
34992 "selectionchange" : true,
34994 * @event afterselectionchange
34995 * Fires after the selection changes (eg. by key press or clicking)
34996 * @param {SelectionModel} this
34998 "afterselectionchange" : true,
35000 * @event beforerowselect
35001 * Fires when a row is selected being selected, return false to cancel.
35002 * @param {SelectionModel} this
35003 * @param {Number} rowIndex The selected index
35004 * @param {Boolean} keepExisting False if other selections will be cleared
35006 "beforerowselect" : true,
35009 * Fires when a row is selected.
35010 * @param {SelectionModel} this
35011 * @param {Number} rowIndex The selected index
35012 * @param {Roo.data.Record} r The record
35014 "rowselect" : true,
35016 * @event rowdeselect
35017 * Fires when a row is deselected.
35018 * @param {SelectionModel} this
35019 * @param {Number} rowIndex The selected index
35021 "rowdeselect" : true
35023 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35024 this.locked = false;
35027 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35029 * @cfg {Boolean} singleSelect
35030 * True to allow selection of only one row at a time (defaults to false)
35032 singleSelect : false,
35035 initEvents : function(){
35037 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35038 this.grid.on("mousedown", this.handleMouseDown, this);
35039 }else{ // allow click to work like normal
35040 this.grid.on("rowclick", this.handleDragableRowClick, this);
35043 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35044 "up" : function(e){
35046 this.selectPrevious(e.shiftKey);
35047 }else if(this.last !== false && this.lastActive !== false){
35048 var last = this.last;
35049 this.selectRange(this.last, this.lastActive-1);
35050 this.grid.getView().focusRow(this.lastActive);
35051 if(last !== false){
35055 this.selectFirstRow();
35057 this.fireEvent("afterselectionchange", this);
35059 "down" : function(e){
35061 this.selectNext(e.shiftKey);
35062 }else if(this.last !== false && this.lastActive !== false){
35063 var last = this.last;
35064 this.selectRange(this.last, this.lastActive+1);
35065 this.grid.getView().focusRow(this.lastActive);
35066 if(last !== false){
35070 this.selectFirstRow();
35072 this.fireEvent("afterselectionchange", this);
35077 var view = this.grid.view;
35078 view.on("refresh", this.onRefresh, this);
35079 view.on("rowupdated", this.onRowUpdated, this);
35080 view.on("rowremoved", this.onRemove, this);
35084 onRefresh : function(){
35085 var ds = this.grid.dataSource, i, v = this.grid.view;
35086 var s = this.selections;
35087 s.each(function(r){
35088 if((i = ds.indexOfId(r.id)) != -1){
35097 onRemove : function(v, index, r){
35098 this.selections.remove(r);
35102 onRowUpdated : function(v, index, r){
35103 if(this.isSelected(r)){
35104 v.onRowSelect(index);
35110 * @param {Array} records The records to select
35111 * @param {Boolean} keepExisting (optional) True to keep existing selections
35113 selectRecords : function(records, keepExisting){
35115 this.clearSelections();
35117 var ds = this.grid.dataSource;
35118 for(var i = 0, len = records.length; i < len; i++){
35119 this.selectRow(ds.indexOf(records[i]), true);
35124 * Gets the number of selected rows.
35127 getCount : function(){
35128 return this.selections.length;
35132 * Selects the first row in the grid.
35134 selectFirstRow : function(){
35139 * Select the last row.
35140 * @param {Boolean} keepExisting (optional) True to keep existing selections
35142 selectLastRow : function(keepExisting){
35143 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35147 * Selects the row immediately following the last selected row.
35148 * @param {Boolean} keepExisting (optional) True to keep existing selections
35150 selectNext : function(keepExisting){
35151 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35152 this.selectRow(this.last+1, keepExisting);
35153 this.grid.getView().focusRow(this.last);
35158 * Selects the row that precedes the last selected row.
35159 * @param {Boolean} keepExisting (optional) True to keep existing selections
35161 selectPrevious : function(keepExisting){
35163 this.selectRow(this.last-1, keepExisting);
35164 this.grid.getView().focusRow(this.last);
35169 * Returns the selected records
35170 * @return {Array} Array of selected records
35172 getSelections : function(){
35173 return [].concat(this.selections.items);
35177 * Returns the first selected record.
35180 getSelected : function(){
35181 return this.selections.itemAt(0);
35186 * Clears all selections.
35188 clearSelections : function(fast){
35189 if(this.locked) return;
35191 var ds = this.grid.dataSource;
35192 var s = this.selections;
35193 s.each(function(r){
35194 this.deselectRow(ds.indexOfId(r.id));
35198 this.selections.clear();
35205 * Selects all rows.
35207 selectAll : function(){
35208 if(this.locked) return;
35209 this.selections.clear();
35210 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35211 this.selectRow(i, true);
35216 * Returns True if there is a selection.
35217 * @return {Boolean}
35219 hasSelection : function(){
35220 return this.selections.length > 0;
35224 * Returns True if the specified row is selected.
35225 * @param {Number/Record} record The record or index of the record to check
35226 * @return {Boolean}
35228 isSelected : function(index){
35229 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35230 return (r && this.selections.key(r.id) ? true : false);
35234 * Returns True if the specified record id is selected.
35235 * @param {String} id The id of record to check
35236 * @return {Boolean}
35238 isIdSelected : function(id){
35239 return (this.selections.key(id) ? true : false);
35243 handleMouseDown : function(e, t){
35244 var view = this.grid.getView(), rowIndex;
35245 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35248 if(e.shiftKey && this.last !== false){
35249 var last = this.last;
35250 this.selectRange(last, rowIndex, e.ctrlKey);
35251 this.last = last; // reset the last
35252 view.focusRow(rowIndex);
35254 var isSelected = this.isSelected(rowIndex);
35255 if(e.button !== 0 && isSelected){
35256 view.focusRow(rowIndex);
35257 }else if(e.ctrlKey && isSelected){
35258 this.deselectRow(rowIndex);
35259 }else if(!isSelected){
35260 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35261 view.focusRow(rowIndex);
35264 this.fireEvent("afterselectionchange", this);
35267 handleDragableRowClick : function(grid, rowIndex, e)
35269 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35270 this.selectRow(rowIndex, false);
35271 grid.view.focusRow(rowIndex);
35272 this.fireEvent("afterselectionchange", this);
35277 * Selects multiple rows.
35278 * @param {Array} rows Array of the indexes of the row to select
35279 * @param {Boolean} keepExisting (optional) True to keep existing selections
35281 selectRows : function(rows, keepExisting){
35283 this.clearSelections();
35285 for(var i = 0, len = rows.length; i < len; i++){
35286 this.selectRow(rows[i], true);
35291 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35292 * @param {Number} startRow The index of the first row in the range
35293 * @param {Number} endRow The index of the last row in the range
35294 * @param {Boolean} keepExisting (optional) True to retain existing selections
35296 selectRange : function(startRow, endRow, keepExisting){
35297 if(this.locked) return;
35299 this.clearSelections();
35301 if(startRow <= endRow){
35302 for(var i = startRow; i <= endRow; i++){
35303 this.selectRow(i, true);
35306 for(var i = startRow; i >= endRow; i--){
35307 this.selectRow(i, true);
35313 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35314 * @param {Number} startRow The index of the first row in the range
35315 * @param {Number} endRow The index of the last row in the range
35317 deselectRange : function(startRow, endRow, preventViewNotify){
35318 if(this.locked) return;
35319 for(var i = startRow; i <= endRow; i++){
35320 this.deselectRow(i, preventViewNotify);
35326 * @param {Number} row The index of the row to select
35327 * @param {Boolean} keepExisting (optional) True to keep existing selections
35329 selectRow : function(index, keepExisting, preventViewNotify){
35330 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35331 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35332 if(!keepExisting || this.singleSelect){
35333 this.clearSelections();
35335 var r = this.grid.dataSource.getAt(index);
35336 this.selections.add(r);
35337 this.last = this.lastActive = index;
35338 if(!preventViewNotify){
35339 this.grid.getView().onRowSelect(index);
35341 this.fireEvent("rowselect", this, index, r);
35342 this.fireEvent("selectionchange", this);
35348 * @param {Number} row The index of the row to deselect
35350 deselectRow : function(index, preventViewNotify){
35351 if(this.locked) return;
35352 if(this.last == index){
35355 if(this.lastActive == index){
35356 this.lastActive = false;
35358 var r = this.grid.dataSource.getAt(index);
35359 this.selections.remove(r);
35360 if(!preventViewNotify){
35361 this.grid.getView().onRowDeselect(index);
35363 this.fireEvent("rowdeselect", this, index);
35364 this.fireEvent("selectionchange", this);
35368 restoreLast : function(){
35370 this.last = this._last;
35375 acceptsNav : function(row, col, cm){
35376 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35380 onEditorKey : function(field, e){
35381 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35386 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35388 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35390 }else if(k == e.ENTER && !e.ctrlKey){
35394 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35396 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35398 }else if(k == e.ESC){
35402 g.startEditing(newCell[0], newCell[1]);
35407 * Ext JS Library 1.1.1
35408 * Copyright(c) 2006-2007, Ext JS, LLC.
35410 * Originally Released Under LGPL - original licence link has changed is not relivant.
35413 * <script type="text/javascript">
35416 * @class Roo.grid.CellSelectionModel
35417 * @extends Roo.grid.AbstractSelectionModel
35418 * This class provides the basic implementation for cell selection in a grid.
35420 * @param {Object} config The object containing the configuration of this model.
35422 Roo.grid.CellSelectionModel = function(config){
35423 Roo.apply(this, config);
35425 this.selection = null;
35429 * @event beforerowselect
35430 * Fires before a cell is selected.
35431 * @param {SelectionModel} this
35432 * @param {Number} rowIndex The selected row index
35433 * @param {Number} colIndex The selected cell index
35435 "beforecellselect" : true,
35437 * @event cellselect
35438 * Fires when a cell is selected.
35439 * @param {SelectionModel} this
35440 * @param {Number} rowIndex The selected row index
35441 * @param {Number} colIndex The selected cell index
35443 "cellselect" : true,
35445 * @event selectionchange
35446 * Fires when the active selection changes.
35447 * @param {SelectionModel} this
35448 * @param {Object} selection null for no selection or an object (o) with two properties
35450 <li>o.record: the record object for the row the selection is in</li>
35451 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35454 "selectionchange" : true
35456 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35459 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35462 initEvents : function(){
35463 this.grid.on("mousedown", this.handleMouseDown, this);
35464 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35465 var view = this.grid.view;
35466 view.on("refresh", this.onViewChange, this);
35467 view.on("rowupdated", this.onRowUpdated, this);
35468 view.on("beforerowremoved", this.clearSelections, this);
35469 view.on("beforerowsinserted", this.clearSelections, this);
35470 if(this.grid.isEditor){
35471 this.grid.on("beforeedit", this.beforeEdit, this);
35476 beforeEdit : function(e){
35477 this.select(e.row, e.column, false, true, e.record);
35481 onRowUpdated : function(v, index, r){
35482 if(this.selection && this.selection.record == r){
35483 v.onCellSelect(index, this.selection.cell[1]);
35488 onViewChange : function(){
35489 this.clearSelections(true);
35493 * Returns the currently selected cell,.
35494 * @return {Array} The selected cell (row, column) or null if none selected.
35496 getSelectedCell : function(){
35497 return this.selection ? this.selection.cell : null;
35501 * Clears all selections.
35502 * @param {Boolean} true to prevent the gridview from being notified about the change.
35504 clearSelections : function(preventNotify){
35505 var s = this.selection;
35507 if(preventNotify !== true){
35508 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35510 this.selection = null;
35511 this.fireEvent("selectionchange", this, null);
35516 * Returns true if there is a selection.
35517 * @return {Boolean}
35519 hasSelection : function(){
35520 return this.selection ? true : false;
35524 handleMouseDown : function(e, t){
35525 var v = this.grid.getView();
35526 if(this.isLocked()){
35529 var row = v.findRowIndex(t);
35530 var cell = v.findCellIndex(t);
35531 if(row !== false && cell !== false){
35532 this.select(row, cell);
35538 * @param {Number} rowIndex
35539 * @param {Number} collIndex
35541 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35542 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35543 this.clearSelections();
35544 r = r || this.grid.dataSource.getAt(rowIndex);
35547 cell : [rowIndex, colIndex]
35549 if(!preventViewNotify){
35550 var v = this.grid.getView();
35551 v.onCellSelect(rowIndex, colIndex);
35552 if(preventFocus !== true){
35553 v.focusCell(rowIndex, colIndex);
35556 this.fireEvent("cellselect", this, rowIndex, colIndex);
35557 this.fireEvent("selectionchange", this, this.selection);
35562 isSelectable : function(rowIndex, colIndex, cm){
35563 return !cm.isHidden(colIndex);
35567 handleKeyDown : function(e){
35568 Roo.log('Cell Sel Model handleKeyDown');
35569 if(!e.isNavKeyPress()){
35572 var g = this.grid, s = this.selection;
35575 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35577 this.select(cell[0], cell[1]);
35582 var walk = function(row, col, step){
35583 return g.walkCells(row, col, step, sm.isSelectable, sm);
35585 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
35590 // handled by onEditorKey
35591 if (g.isEditor && g.editing) {
35595 newCell = walk(r, c-1, -1);
35597 newCell = walk(r, c+1, 1);
35601 newCell = walk(r+1, c, 1);
35604 newCell = walk(r-1, c, -1);
35607 newCell = walk(r, c+1, 1);
35610 newCell = walk(r, c-1, -1);
35613 if(g.isEditor && !g.editing){
35614 g.startEditing(r, c);
35621 this.select(newCell[0], newCell[1]);
35626 acceptsNav : function(row, col, cm){
35627 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35630 onEditorKey : function(field, e){
35632 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35633 ///Roo.log('onEditorKey' + k);
35637 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35639 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35642 }else if(k == e.ENTER && !e.ctrlKey){
35645 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35646 }else if(k == e.ESC){
35652 //Roo.log('next cell after edit');
35653 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
35658 * Ext JS Library 1.1.1
35659 * Copyright(c) 2006-2007, Ext JS, LLC.
35661 * Originally Released Under LGPL - original licence link has changed is not relivant.
35664 * <script type="text/javascript">
35668 * @class Roo.grid.EditorGrid
35669 * @extends Roo.grid.Grid
35670 * Class for creating and editable grid.
35671 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35672 * The container MUST have some type of size defined for the grid to fill. The container will be
35673 * automatically set to position relative if it isn't already.
35674 * @param {Object} dataSource The data model to bind to
35675 * @param {Object} colModel The column model with info about this grid's columns
35677 Roo.grid.EditorGrid = function(container, config){
35678 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
35679 this.getGridEl().addClass("xedit-grid");
35681 if(!this.selModel){
35682 this.selModel = new Roo.grid.CellSelectionModel();
35685 this.activeEditor = null;
35689 * @event beforeedit
35690 * Fires before cell editing is triggered. The edit event object has the following properties <br />
35691 * <ul style="padding:5px;padding-left:16px;">
35692 * <li>grid - This grid</li>
35693 * <li>record - The record being edited</li>
35694 * <li>field - The field name being edited</li>
35695 * <li>value - The value for the field being edited.</li>
35696 * <li>row - The grid row index</li>
35697 * <li>column - The grid column index</li>
35698 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35700 * @param {Object} e An edit event (see above for description)
35702 "beforeedit" : true,
35705 * Fires after a cell is edited. <br />
35706 * <ul style="padding:5px;padding-left:16px;">
35707 * <li>grid - This grid</li>
35708 * <li>record - The record being edited</li>
35709 * <li>field - The field name being edited</li>
35710 * <li>value - The value being set</li>
35711 * <li>originalValue - The original value for the field, before the edit.</li>
35712 * <li>row - The grid row index</li>
35713 * <li>column - The grid column index</li>
35715 * @param {Object} e An edit event (see above for description)
35717 "afteredit" : true,
35719 * @event validateedit
35720 * Fires after a cell is edited, but before the value is set in the record.
35721 * You can use this to modify the value being set in the field, Return false
35722 * to cancel the change. The edit event object has the following properties <br />
35723 * <ul style="padding:5px;padding-left:16px;">
35724 * <li>editor - This editor</li>
35725 * <li>grid - This grid</li>
35726 * <li>record - The record being edited</li>
35727 * <li>field - The field name being edited</li>
35728 * <li>value - The value being set</li>
35729 * <li>originalValue - The original value for the field, before the edit.</li>
35730 * <li>row - The grid row index</li>
35731 * <li>column - The grid column index</li>
35732 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35734 * @param {Object} e An edit event (see above for description)
35736 "validateedit" : true
35738 this.on("bodyscroll", this.stopEditing, this);
35739 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
35742 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
35744 * @cfg {Number} clicksToEdit
35745 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
35752 trackMouseOver: false, // causes very odd FF errors
35754 onCellDblClick : function(g, row, col){
35755 this.startEditing(row, col);
35758 onEditComplete : function(ed, value, startValue){
35759 this.editing = false;
35760 this.activeEditor = null;
35761 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
35763 var field = this.colModel.getDataIndex(ed.col);
35768 originalValue: startValue,
35775 if(String(value) !== String(startValue)){
35777 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
35778 r.set(field, e.value);
35779 // if we are dealing with a combo box..
35780 // then we also set the 'name' colum to be the displayField
35781 if (ed.field.displayField && ed.field.name) {
35782 r.set(ed.field.name, ed.field.el.dom.value);
35785 delete e.cancel; //?? why!!!
35786 this.fireEvent("afteredit", e);
35789 this.fireEvent("afteredit", e); // always fire it!
35791 this.view.focusCell(ed.row, ed.col);
35795 * Starts editing the specified for the specified row/column
35796 * @param {Number} rowIndex
35797 * @param {Number} colIndex
35799 startEditing : function(row, col){
35800 this.stopEditing();
35801 if(this.colModel.isCellEditable(col, row)){
35802 this.view.ensureVisible(row, col, true);
35803 var r = this.dataSource.getAt(row);
35804 var field = this.colModel.getDataIndex(col);
35809 value: r.data[field],
35814 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
35815 this.editing = true;
35816 var ed = this.colModel.getCellEditor(col, row);
35822 ed.render(ed.parentEl || document.body);
35825 (function(){ // complex but required for focus issues in safari, ie and opera
35829 ed.on("complete", this.onEditComplete, this, {single: true});
35830 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
35831 this.activeEditor = ed;
35832 var v = r.data[field];
35833 ed.startEdit(this.view.getCell(row, col), v);
35834 // combo's with 'displayField and name set
35835 if (ed.field.displayField && ed.field.name) {
35836 ed.field.el.dom.value = r.data[ed.field.name];
35840 }).defer(50, this);
35846 * Stops any active editing
35848 stopEditing : function(){
35849 if(this.activeEditor){
35850 this.activeEditor.completeEdit();
35852 this.activeEditor = null;
35856 * Ext JS Library 1.1.1
35857 * Copyright(c) 2006-2007, Ext JS, LLC.
35859 * Originally Released Under LGPL - original licence link has changed is not relivant.
35862 * <script type="text/javascript">
35865 // private - not really -- you end up using it !
35866 // This is a support class used internally by the Grid components
35869 * @class Roo.grid.GridEditor
35870 * @extends Roo.Editor
35871 * Class for creating and editable grid elements.
35872 * @param {Object} config any settings (must include field)
35874 Roo.grid.GridEditor = function(field, config){
35875 if (!config && field.field) {
35877 field = Roo.factory(config.field, Roo.form);
35879 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
35880 field.monitorTab = false;
35883 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
35886 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
35889 alignment: "tl-tl",
35892 cls: "x-small-editor x-grid-editor",
35897 * Ext JS Library 1.1.1
35898 * Copyright(c) 2006-2007, Ext JS, LLC.
35900 * Originally Released Under LGPL - original licence link has changed is not relivant.
35903 * <script type="text/javascript">
35908 Roo.grid.PropertyRecord = Roo.data.Record.create([
35909 {name:'name',type:'string'}, 'value'
35913 Roo.grid.PropertyStore = function(grid, source){
35915 this.store = new Roo.data.Store({
35916 recordType : Roo.grid.PropertyRecord
35918 this.store.on('update', this.onUpdate, this);
35920 this.setSource(source);
35922 Roo.grid.PropertyStore.superclass.constructor.call(this);
35927 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
35928 setSource : function(o){
35930 this.store.removeAll();
35933 if(this.isEditableValue(o[k])){
35934 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
35937 this.store.loadRecords({records: data}, {}, true);
35940 onUpdate : function(ds, record, type){
35941 if(type == Roo.data.Record.EDIT){
35942 var v = record.data['value'];
35943 var oldValue = record.modified['value'];
35944 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
35945 this.source[record.id] = v;
35947 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
35954 getProperty : function(row){
35955 return this.store.getAt(row);
35958 isEditableValue: function(val){
35959 if(val && val instanceof Date){
35961 }else if(typeof val == 'object' || typeof val == 'function'){
35967 setValue : function(prop, value){
35968 this.source[prop] = value;
35969 this.store.getById(prop).set('value', value);
35972 getSource : function(){
35973 return this.source;
35977 Roo.grid.PropertyColumnModel = function(grid, store){
35980 g.PropertyColumnModel.superclass.constructor.call(this, [
35981 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
35982 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
35984 this.store = store;
35985 this.bselect = Roo.DomHelper.append(document.body, {
35986 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
35987 {tag: 'option', value: 'true', html: 'true'},
35988 {tag: 'option', value: 'false', html: 'false'}
35991 Roo.id(this.bselect);
35994 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
35995 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
35996 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
35997 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
35998 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36000 this.renderCellDelegate = this.renderCell.createDelegate(this);
36001 this.renderPropDelegate = this.renderProp.createDelegate(this);
36004 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36008 valueText : 'Value',
36010 dateFormat : 'm/j/Y',
36013 renderDate : function(dateVal){
36014 return dateVal.dateFormat(this.dateFormat);
36017 renderBool : function(bVal){
36018 return bVal ? 'true' : 'false';
36021 isCellEditable : function(colIndex, rowIndex){
36022 return colIndex == 1;
36025 getRenderer : function(col){
36027 this.renderCellDelegate : this.renderPropDelegate;
36030 renderProp : function(v){
36031 return this.getPropertyName(v);
36034 renderCell : function(val){
36036 if(val instanceof Date){
36037 rv = this.renderDate(val);
36038 }else if(typeof val == 'boolean'){
36039 rv = this.renderBool(val);
36041 return Roo.util.Format.htmlEncode(rv);
36044 getPropertyName : function(name){
36045 var pn = this.grid.propertyNames;
36046 return pn && pn[name] ? pn[name] : name;
36049 getCellEditor : function(colIndex, rowIndex){
36050 var p = this.store.getProperty(rowIndex);
36051 var n = p.data['name'], val = p.data['value'];
36053 if(typeof(this.grid.customEditors[n]) == 'string'){
36054 return this.editors[this.grid.customEditors[n]];
36056 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36057 return this.grid.customEditors[n];
36059 if(val instanceof Date){
36060 return this.editors['date'];
36061 }else if(typeof val == 'number'){
36062 return this.editors['number'];
36063 }else if(typeof val == 'boolean'){
36064 return this.editors['boolean'];
36066 return this.editors['string'];
36072 * @class Roo.grid.PropertyGrid
36073 * @extends Roo.grid.EditorGrid
36074 * This class represents the interface of a component based property grid control.
36075 * <br><br>Usage:<pre><code>
36076 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36084 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36085 * The container MUST have some type of size defined for the grid to fill. The container will be
36086 * automatically set to position relative if it isn't already.
36087 * @param {Object} config A config object that sets properties on this grid.
36089 Roo.grid.PropertyGrid = function(container, config){
36090 config = config || {};
36091 var store = new Roo.grid.PropertyStore(this);
36092 this.store = store;
36093 var cm = new Roo.grid.PropertyColumnModel(this, store);
36094 store.store.sort('name', 'ASC');
36095 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36098 enableColLock:false,
36099 enableColumnMove:false,
36101 trackMouseOver: false,
36104 this.getGridEl().addClass('x-props-grid');
36105 this.lastEditRow = null;
36106 this.on('columnresize', this.onColumnResize, this);
36109 * @event beforepropertychange
36110 * Fires before a property changes (return false to stop?)
36111 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36112 * @param {String} id Record Id
36113 * @param {String} newval New Value
36114 * @param {String} oldval Old Value
36116 "beforepropertychange": true,
36118 * @event propertychange
36119 * Fires after a property changes
36120 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36121 * @param {String} id Record Id
36122 * @param {String} newval New Value
36123 * @param {String} oldval Old Value
36125 "propertychange": true
36127 this.customEditors = this.customEditors || {};
36129 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36132 * @cfg {Object} customEditors map of colnames=> custom editors.
36133 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36134 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36135 * false disables editing of the field.
36139 * @cfg {Object} propertyNames map of property Names to their displayed value
36142 render : function(){
36143 Roo.grid.PropertyGrid.superclass.render.call(this);
36144 this.autoSize.defer(100, this);
36147 autoSize : function(){
36148 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36150 this.view.fitColumns();
36154 onColumnResize : function(){
36155 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36159 * Sets the data for the Grid
36160 * accepts a Key => Value object of all the elements avaiable.
36161 * @param {Object} data to appear in grid.
36163 setSource : function(source){
36164 this.store.setSource(source);
36168 * Gets all the data from the grid.
36169 * @return {Object} data data stored in grid
36171 getSource : function(){
36172 return this.store.getSource();
36176 * Ext JS Library 1.1.1
36177 * Copyright(c) 2006-2007, Ext JS, LLC.
36179 * Originally Released Under LGPL - original licence link has changed is not relivant.
36182 * <script type="text/javascript">
36186 * @class Roo.LoadMask
36187 * A simple utility class for generically masking elements while loading data. If the element being masked has
36188 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36189 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36190 * element's UpdateManager load indicator and will be destroyed after the initial load.
36192 * Create a new LoadMask
36193 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36194 * @param {Object} config The config object
36196 Roo.LoadMask = function(el, config){
36197 this.el = Roo.get(el);
36198 Roo.apply(this, config);
36200 this.store.on('beforeload', this.onBeforeLoad, this);
36201 this.store.on('load', this.onLoad, this);
36202 this.store.on('loadexception', this.onLoad, this);
36203 this.removeMask = false;
36205 var um = this.el.getUpdateManager();
36206 um.showLoadIndicator = false; // disable the default indicator
36207 um.on('beforeupdate', this.onBeforeLoad, this);
36208 um.on('update', this.onLoad, this);
36209 um.on('failure', this.onLoad, this);
36210 this.removeMask = true;
36214 Roo.LoadMask.prototype = {
36216 * @cfg {Boolean} removeMask
36217 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36218 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36221 * @cfg {String} msg
36222 * The text to display in a centered loading message box (defaults to 'Loading...')
36224 msg : 'Loading...',
36226 * @cfg {String} msgCls
36227 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36229 msgCls : 'x-mask-loading',
36232 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36238 * Disables the mask to prevent it from being displayed
36240 disable : function(){
36241 this.disabled = true;
36245 * Enables the mask so that it can be displayed
36247 enable : function(){
36248 this.disabled = false;
36252 onLoad : function(){
36253 this.el.unmask(this.removeMask);
36257 onBeforeLoad : function(){
36258 if(!this.disabled){
36259 this.el.mask(this.msg, this.msgCls);
36264 destroy : function(){
36266 this.store.un('beforeload', this.onBeforeLoad, this);
36267 this.store.un('load', this.onLoad, this);
36268 this.store.un('loadexception', this.onLoad, this);
36270 var um = this.el.getUpdateManager();
36271 um.un('beforeupdate', this.onBeforeLoad, this);
36272 um.un('update', this.onLoad, this);
36273 um.un('failure', this.onLoad, this);
36278 * Ext JS Library 1.1.1
36279 * Copyright(c) 2006-2007, Ext JS, LLC.
36281 * Originally Released Under LGPL - original licence link has changed is not relivant.
36284 * <script type="text/javascript">
36286 Roo.XTemplate = function(){
36287 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36290 s = ['<tpl>', s, '</tpl>'].join('');
36292 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36294 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36295 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36296 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36300 while(m = s.match(re)){
36301 var m2 = m[0].match(nameRe);
36302 var m3 = m[0].match(ifRe);
36303 var m4 = m[0].match(execRe);
36304 var exp = null, fn = null, exec = null;
36305 var name = m2 && m2[1] ? m2[1] : '';
36307 exp = m3 && m3[1] ? m3[1] : null;
36309 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36313 exp = m4 && m4[1] ? m4[1] : null;
36315 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36320 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36321 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36322 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36332 s = s.replace(m[0], '{xtpl'+ id + '}');
36335 for(var i = tpls.length-1; i >= 0; --i){
36336 this.compileTpl(tpls[i]);
36338 this.master = tpls[tpls.length-1];
36341 Roo.extend(Roo.XTemplate, Roo.Template, {
36343 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36345 applySubTemplate : function(id, values, parent){
36346 var t = this.tpls[id];
36347 if(t.test && !t.test.call(this, values, parent)){
36350 if(t.exec && t.exec.call(this, values, parent)){
36353 var vs = t.target ? t.target.call(this, values, parent) : values;
36354 parent = t.target ? values : parent;
36355 if(t.target && vs instanceof Array){
36357 for(var i = 0, len = vs.length; i < len; i++){
36358 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36360 return buf.join('');
36362 return t.compiled.call(this, vs, parent);
36365 compileTpl : function(tpl){
36366 var fm = Roo.util.Format;
36367 var useF = this.disableFormats !== true;
36368 var sep = Roo.isGecko ? "+" : ",";
36369 var fn = function(m, name, format, args){
36370 if(name.substr(0, 4) == 'xtpl'){
36371 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36374 if(name.indexOf('.') != -1){
36377 v = "values['" + name + "']";
36379 if(format && useF){
36380 args = args ? ',' + args : "";
36381 if(format.substr(0, 5) != "this."){
36382 format = "fm." + format + '(';
36384 format = 'this.call("'+ format.substr(5) + '", ';
36388 args= ''; format = "("+v+" === undefined ? '' : ";
36390 return "'"+ sep + format + v + args + ")"+sep+"'";
36393 // branched to use + in gecko and [].join() in others
36395 body = "tpl.compiled = function(values, parent){ return '" +
36396 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36399 body = ["tpl.compiled = function(values, parent){ return ['"];
36400 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36401 body.push("'].join('');};");
36402 body = body.join('');
36404 /** eval:var:zzzzzzz */
36409 applyTemplate : function(values){
36410 return this.master.compiled.call(this, values, {});
36414 apply : function(){
36415 return this.applyTemplate.apply(this, arguments);
36418 compile : function(){return this;}
36421 Roo.XTemplate.from = function(el){
36422 el = Roo.getDom(el);
36423 return new Roo.XTemplate(el.value || el.innerHTML);
36425 * Original code for Roojs - LGPL
36426 * <script type="text/javascript">
36430 * @class Roo.XComponent
36431 * A delayed Element creator...
36433 * Mypart.xyx = new Roo.XComponent({
36435 parent : 'Mypart.xyz', // empty == document.element.!!
36439 disabled : function() {}
36441 tree : function() { // return an tree of xtype declared components
36445 xtype : 'NestedLayoutPanel',
36450 * @extends Roo.util.Observable
36452 * @param cfg {Object} configuration of component
36455 Roo.XComponent = function(cfg) {
36456 Roo.apply(this, cfg);
36460 * Fires when this the componnt is built
36461 * @param {Roo.XComponent} c the component
36465 * @event buildcomplete
36466 * Fires on the top level element when all elements have been built
36467 * @param {Roo.XComponent} c the top level component.
36469 'buildcomplete' : true
36473 Roo.XComponent.register(this);
36474 this.modules = false;
36475 this.el = false; // where the layout goes..
36479 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36482 * The created element (with Roo.factory())
36483 * @type {Roo.Layout}
36489 * for BC - use el in new code
36490 * @type {Roo.Layout}
36496 * for BC - use el in new code
36497 * @type {Roo.Layout}
36502 * @cfg {Function|boolean} disabled
36503 * If this module is disabled by some rule, return true from the funtion
36508 * @cfg {String} parent
36509 * Name of parent element which it get xtype added to..
36514 * @cfg {String} order
36515 * Used to set the order in which elements are created (usefull for multiple tabs)
36520 * @cfg {String} name
36521 * String to display while loading.
36525 * @cfg {Array} items
36526 * A single item array - the first element is the root of the tree..
36527 * It's done this way to stay compatible with the Xtype system...
36535 Roo.apply(Roo.XComponent, {
36538 * @property buildCompleted
36539 * True when the builder has completed building the interface.
36542 buildCompleted : false,
36545 * @property topModule
36546 * the upper most module - uses document.element as it's constructor.
36553 * @property modules
36554 * array of modules to be created by registration system.
36555 * @type Roo.XComponent
36562 * Register components to be built later.
36564 * This solves the following issues
36565 * - Building is not done on page load, but after an authentication process has occured.
36566 * - Interface elements are registered on page load
36567 * - Parent Interface elements may not be loaded before child, so this handles that..
36574 module : 'Pman.Tab.projectMgr',
36576 parent : 'Pman.layout',
36577 disabled : false, // or use a function..
36580 * * @param {Object} details about module
36582 register : function(obj) {
36583 this.modules.push(obj);
36587 * convert a string to an object..
36591 toObject : function(str)
36593 if (!str || typeof(str) == 'object') {
36596 var ar = str.split('.');
36600 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
36602 throw "Module not found : " + str;
36604 Roo.each(ar, function(e) {
36605 if (typeof(o[e]) == 'undefined') {
36606 throw "Module not found : " + str;
36616 * move modules into their correct place in the tree..
36619 preBuild : function ()
36622 Roo.each(this.modules , function (obj)
36624 obj.parent = this.toObject(obj.parent);
36627 this.topModule = obj;
36631 if (!obj.parent.modules) {
36632 obj.parent.modules = new Roo.util.MixedCollection(false,
36633 function(o) { return o.order + '' }
36637 obj.parent.modules.add(obj);
36642 * make a list of modules to build.
36643 * @return {Array} list of modules.
36646 buildOrder : function()
36649 var cmp = function(a,b) {
36650 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
36653 if (!this.topModule || !this.topModule.modules) {
36654 throw "No top level modules to build";
36657 // make a flat list in order of modules to build.
36658 var mods = [ this.topModule ];
36661 // add modules to their parents..
36662 var addMod = function(m) {
36663 // Roo.debug && Roo.log(m.modKey);
36667 m.modules.keySort('ASC', cmp );
36668 m.modules.each(addMod);
36670 // not sure if this is used any more..
36672 m.finalize.name = m.name + " (clean up) ";
36673 mods.push(m.finalize);
36677 this.topModule.modules.keySort('ASC', cmp );
36678 this.topModule.modules.each(addMod);
36683 * Build the registered modules.
36684 * @param {Object} parent element.
36685 * @param {Function} optional method to call after module has been added.
36693 var mods = this.buildOrder();
36695 //this.allmods = mods;
36696 //Roo.debug && Roo.log(mods);
36698 if (!mods.length) { // should not happen
36699 throw "NO modules!!!";
36704 // flash it up as modal - so we store the mask!?
36705 Roo.MessageBox.show({ title: 'loading' });
36706 Roo.MessageBox.show({
36707 title: "Please wait...",
36708 msg: "Building Interface...",
36715 var total = mods.length;
36718 var progressRun = function() {
36719 if (!mods.length) {
36720 Roo.debug && Roo.log('hide?');
36721 Roo.MessageBox.hide();
36722 _this.topModule.fireEvent('buildcomplete', _this.topModule);
36726 var m = mods.shift();
36727 Roo.debug && Roo.log(m);
36728 if (typeof(m) == 'function') { // not sure if this is supported any more..
36730 return progressRun.defer(10, _this);
36733 Roo.MessageBox.updateProgress(
36734 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
36736 (m.name ? (' - ' + m.name) : '')
36741 var disabled = (typeof(m.disabled) == 'function') ?
36742 m.disabled.call(m.module.disabled) : m.disabled;
36746 return progressRun(); // we do not update the display!
36750 // it's a top level one..
36751 var layoutbase = new Ext.BorderLayout(document.body, {
36757 tabPosition: 'top',
36758 //resizeTabs: true,
36759 alwaysShowTabs: true,
36763 var tree = m.tree();
36764 tree.region = 'center';
36765 m.el = layoutbase.addxtype(tree);
36767 m.layout = m.panel.layout;
36768 return progressRun.defer(10, _this);
36771 var tree = m.tree();
36772 tree.region = tree.region || m.region;
36773 m.el = m.parent.el.addxtype(tree);
36774 m.fireEvent('built', m);
36776 m.layout = m.panel.layout;
36777 progressRun.defer(10, _this);
36780 progressRun.defer(1, _this);
36790 //<script type="text/javascript">
36795 * @extends Roo.LayoutDialog
36796 * A generic Login Dialog..... - only one needed in theory!?!?
36798 * Fires XComponent builder on success...
36801 * username,password, lang = for login actions.
36802 * check = 1 for periodic checking that sesion is valid.
36803 * passwordRequest = email request password
36804 * logout = 1 = to logout
36806 * Affects: (this id="????" elements)
36807 * loading (removed) (used to indicate application is loading)
36808 * loading-mask (hides) (used to hide application when it's building loading)
36814 * Myapp.login = Roo.Login({
36830 Roo.Login = function(cfg)
36836 Roo.apply(this,cfg);
36838 Roo.onReady(function() {
36844 Roo.Login.superclass.constructor.call(this, this);
36845 //this.addxtype(this.items[0]);
36851 Roo.extend(Roo.Login, Roo.LayoutDialog, {
36854 * @cfg {String} method
36855 * Method used to query for login details.
36860 * @cfg {String} url
36861 * URL to query login data. - eg. baseURL + '/Login.php'
36867 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
36872 * @property checkFails
36873 * Number of times we have attempted to get authentication check, and failed.
36878 * @property intervalID
36879 * The window interval that does the constant login checking.
36885 onLoad : function() // called on page load...
36889 if (Roo.get('loading')) { // clear any loading indicator..
36890 Roo.get('loading').remove();
36893 //this.switchLang('en'); // set the language to english..
36896 success: function(response, opts) { // check successfull...
36898 var res = this.processResponse(response);
36899 this.checkFails =0;
36900 if (!res.success) { // error!
36901 this.checkFails = 5;
36902 //console.log('call failure');
36903 return this.failure(response,opts);
36906 if (!res.data.id) { // id=0 == login failure.
36907 return this.show();
36911 //console.log(success);
36912 this.fillAuth(res.data);
36913 this.checkFails =0;
36914 Roo.XComponent.build();
36916 failure : this.show
36922 check: function(cfg) // called every so often to refresh cookie etc..
36924 if (cfg.again) { // could be undefined..
36927 this.checkFails = 0;
36930 if (this.sending) {
36931 if ( this.checkFails > 4) {
36932 Roo.MessageBox.alert("Error",
36933 "Error getting authentication status. - try reloading, or wait a while", function() {
36934 _this.sending = false;
36939 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
36942 this.sending = true;
36949 method: this.method,
36950 success: cfg.success || this.success,
36951 failure : cfg.failure || this.failure,
36961 window.onbeforeunload = function() { }; // false does not work for IE..
36971 failure : function() {
36972 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
36973 document.location = document.location.toString() + '?ts=' + Math.random();
36977 success : function() {
36978 _this.user = false;
36979 this.checkFails =0;
36981 document.location = document.location.toString() + '?ts=' + Math.random();
36988 processResponse : function (response)
36992 res = Roo.decode(response.responseText);
36994 if (typeof(res) != 'object') {
36995 res = { success : false, errorMsg : res, errors : true };
36997 if (typeof(res.success) == 'undefined') {
36998 res.success = false;
37002 res = { success : false, errorMsg : response.responseText, errors : true };
37007 success : function(response, opts) // check successfull...
37009 this.sending = false;
37010 var res = this.processResponse(response);
37011 if (!res.success) {
37012 return this.failure(response, opts);
37014 if (!res.data || !res.data.id) {
37015 return this.failure(response,opts);
37017 //console.log(res);
37018 this.fillAuth(res.data);
37020 this.checkFails =0;
37025 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37027 this.authUser = -1;
37028 this.sending = false;
37029 var res = this.processResponse(response);
37030 //console.log(res);
37031 if ( this.checkFails > 2) {
37033 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37034 "Error getting authentication status. - try reloading");
37037 opts.callCfg.again = true;
37038 this.check.defer(1000, this, [ opts.callCfg ]);
37044 fillAuth: function(au) {
37045 this.startAuthCheck();
37046 this.authUserId = au.id;
37047 this.authUser = au;
37048 this.lastChecked = new Date();
37049 this.fireEvent('refreshed', au);
37050 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37051 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37052 au.lang = au.lang || 'en';
37053 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37054 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37055 this.switchLang(au.lang );
37058 // open system... - -on setyp..
37059 if (this.authUserId < 0) {
37060 Roo.MessageBox.alert("Warning",
37061 "This is an open system - please set up a admin user with a password.");
37064 //Pman.onload(); // which should do nothing if it's a re-auth result...
37069 startAuthCheck : function() // starter for timeout checking..
37071 if (this.intervalID) { // timer already in place...
37075 this.intervalID = window.setInterval(function() {
37076 _this.check(false);
37077 }, 120000); // every 120 secs = 2mins..
37083 switchLang : function (lang)
37085 _T = typeof(_T) == 'undefined' ? false : _T;
37086 if (!_T || !lang.length) {
37090 if (!_T && lang != 'en') {
37091 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37095 if (typeof(_T.en) == 'undefined') {
37097 Roo.apply(_T.en, _T);
37100 if (typeof(_T[lang]) == 'undefined') {
37101 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37106 Roo.apply(_T, _T[lang]);
37107 // just need to set the text values for everything...
37109 /* this will not work ...
37113 function formLabel(name, val) {
37114 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37117 formLabel('password', "Password"+':');
37118 formLabel('username', "Email Address"+':');
37119 formLabel('lang', "Language"+':');
37120 this.dialog.setTitle("Login");
37121 this.dialog.buttons[0].setText("Forgot Password");
37122 this.dialog.buttons[1].setText("Login");
37141 collapsible: false,
37143 center: { // needed??
37146 // tabPosition: 'top',
37149 alwaysShowTabs: false
37153 show : function(dlg)
37155 //console.log(this);
37156 this.form = this.layout.getRegion('center').activePanel.form;
37157 this.form.dialog = dlg;
37158 this.buttons[0].form = this.form;
37159 this.buttons[0].dialog = dlg;
37160 this.buttons[1].form = this.form;
37161 this.buttons[1].dialog = dlg;
37163 //this.resizeToLogo.defer(1000,this);
37164 // this is all related to resizing for logos..
37165 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37167 // this.resizeToLogo.defer(1000,this);
37170 //var w = Ext.lib.Dom.getViewWidth() - 100;
37171 //var h = Ext.lib.Dom.getViewHeight() - 100;
37172 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37174 if (this.disabled) {
37179 if (this.user.id < 0) { // used for inital setup situations.
37183 if (this.intervalID) {
37184 // remove the timer
37185 window.clearInterval(this.intervalID);
37186 this.intervalID = false;
37190 if (Roo.get('loading')) {
37191 Roo.get('loading').remove();
37193 if (Roo.get('loading-mask')) {
37194 Roo.get('loading-mask').hide();
37197 //incomming._node = tnode;
37199 //this.dialog.modal = !modal;
37200 //this.dialog.show();
37204 this.form.setValues({
37205 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37206 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37209 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37210 if (this.form.findField('username').getValue().length > 0 ){
37211 this.form.findField('password').focus();
37213 this.form.findField('username').focus();
37221 xtype : 'ContentPanel',
37233 style : 'margin: 10px;',
37236 actionfailed : function(f, act) {
37237 // form can return { errors: .... }
37239 //act.result.errors // invalid form element list...
37240 //act.result.errorMsg// invalid form element list...
37242 this.dialog.el.unmask();
37243 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37244 "Login failed - communication error - try again.");
37247 actioncomplete: function(re, act) {
37249 Roo.state.Manager.set(
37250 this.dialog.realm + '.username',
37251 this.findField('username').getValue()
37253 Roo.state.Manager.set(
37254 this.dialog.realm + '.lang',
37255 this.findField('lang').getValue()
37258 this.dialog.fillAuth(act.result.data);
37260 this.dialog.hide();
37262 if (Roo.get('loading-mask')) {
37263 Roo.get('loading-mask').show();
37265 Roo.XComponent.build();
37273 xtype : 'TextField',
37275 fieldLabel: "Email Address",
37278 autoCreate : {tag: "input", type: "text", size: "20"}
37281 xtype : 'TextField',
37283 fieldLabel: "Password",
37284 inputType: 'password',
37287 autoCreate : {tag: "input", type: "text", size: "20"},
37289 specialkey : function(e,ev) {
37290 if (ev.keyCode == 13) {
37291 this.form.dialog.el.mask("Logging in");
37292 this.form.doAction('submit', {
37293 url: this.form.dialog.url,
37294 method: this.form.dialog.method
37301 xtype : 'ComboBox',
37303 fieldLabel: "Language",
37306 xtype : 'SimpleStore',
37307 fields: ['lang', 'ldisp'],
37309 [ 'en', 'English' ],
37310 [ 'zh_HK' , '\u7E41\u4E2D' ],
37311 [ 'zh_CN', '\u7C21\u4E2D' ]
37315 valueField : 'lang',
37316 hiddenName: 'lang',
37318 displayField:'ldisp',
37322 triggerAction: 'all',
37323 emptyText:'Select a Language...',
37324 selectOnFocus:true,
37326 select : function(cb, rec, ix) {
37327 this.form.switchLang(rec.data.lang);
37343 text : "Forgot Password",
37345 click : function() {
37346 //console.log(this);
37347 var n = this.form.findField('username').getValue();
37349 Roo.MessageBox.alert("Error", "Fill in your email address");
37353 url: this.dialog.url,
37357 method: this.dialog.method,
37358 success: function(response, opts) { // check successfull...
37360 var res = this.dialog.processResponse(response);
37361 if (!res.success) { // error!
37362 Roo.MessageBox.alert("Error" ,
37363 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37366 Roo.MessageBox.alert("Notice" ,
37367 "Please check you email for the Password Reset message");
37369 failure : function() {
37370 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37383 click : function () {
37385 this.dialog.el.mask("Logging in");
37386 this.form.doAction('submit', {
37387 url: this.dialog.url,
37388 method: this.dialog.method