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} ddGroup
3978 * The drag drop group to handle drop events for
3982 * @cfg {String} dropAllowed
3983 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3985 dropAllowed : "x-dd-drop-ok",
3987 * @cfg {String} dropNotAllowed
3988 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3990 dropNotAllowed : "x-dd-drop-nodrop",
3992 * @cfg {boolean} success
3993 * set this after drop listener..
3997 * @cfg {boolean} valid
3998 * if the drop point is valid for over/enter..
4005 isNotifyTarget : true,
4010 notifyEnter : function(dd, e, data){
4012 this.fireEvent('enter', this, dd, e, data);
4014 this.el.addClass(this.overClass);
4016 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOver : function(dd, e, data){
4024 this.fireEvent('over', this, dd, e, data);
4025 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4031 notifyOut : function(dd, e, data){
4032 this.fireEvent('out', this, dd, e, data);
4034 this.el.removeClass(this.overClass);
4041 notifyDrop : function(dd, e, data){
4042 this.success = false;
4043 this.fireEvent('drop', this, dd, e, data);
4044 return this.success;
4048 * Ext JS Library 1.1.1
4049 * Copyright(c) 2006-2007, Ext JS, LLC.
4051 * Originally Released Under LGPL - original licence link has changed is not relivant.
4054 * <script type="text/javascript">
4059 * @class Roo.dd.DragZone
4060 * @extends Roo.dd.DragSource
4061 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4062 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4064 * @param {String/HTMLElement/Element} el The container element
4065 * @param {Object} config
4067 Roo.dd.DragZone = function(el, config){
4068 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4069 if(this.containerScroll){
4070 Roo.dd.ScrollManager.register(this.el);
4074 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4076 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4077 * for auto scrolling during drag operations.
4080 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4081 * method after a failed drop (defaults to "c3daf9" - light blue)
4085 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4086 * for a valid target to drag based on the mouse down. Override this method
4087 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4088 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4089 * @param {EventObject} e The mouse down event
4090 * @return {Object} The dragData
4092 getDragData : function(e){
4093 return Roo.dd.Registry.getHandleFromEvent(e);
4097 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4098 * this.dragData.ddel
4099 * @param {Number} x The x position of the click on the dragged object
4100 * @param {Number} y The y position of the click on the dragged object
4101 * @return {Boolean} true to continue the drag, false to cancel
4103 onInitDrag : function(x, y){
4104 this.proxy.update(this.dragData.ddel.cloneNode(true));
4105 this.onStartDrag(x, y);
4110 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4112 afterRepair : function(){
4114 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4116 this.dragging = false;
4120 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4121 * the XY of this.dragData.ddel
4122 * @param {EventObject} e The mouse up event
4123 * @return {Array} The xy location (e.g. [100, 200])
4125 getRepairXY : function(e){
4126 return Roo.Element.fly(this.dragData.ddel).getXY();
4130 * Ext JS Library 1.1.1
4131 * Copyright(c) 2006-2007, Ext JS, LLC.
4133 * Originally Released Under LGPL - original licence link has changed is not relivant.
4136 * <script type="text/javascript">
4139 * @class Roo.dd.DropZone
4140 * @extends Roo.dd.DropTarget
4141 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4142 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4144 * @param {String/HTMLElement/Element} el The container element
4145 * @param {Object} config
4147 Roo.dd.DropZone = function(el, config){
4148 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4151 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4153 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4154 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4155 * provide your own custom lookup.
4156 * @param {Event} e The event
4157 * @return {Object} data The custom data
4159 getTargetFromEvent : function(e){
4160 return Roo.dd.Registry.getTargetFromEvent(e);
4164 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4165 * that it has registered. This method has no default implementation and should be overridden to provide
4166 * node-specific processing if necessary.
4167 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4168 * {@link #getTargetFromEvent} for this node)
4169 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4170 * @param {Event} e The event
4171 * @param {Object} data An object containing arbitrary data supplied by the drag source
4173 onNodeEnter : function(n, dd, e, data){
4178 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4179 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4180 * overridden to provide the proper feedback.
4181 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4182 * {@link #getTargetFromEvent} for this node)
4183 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4184 * @param {Event} e The event
4185 * @param {Object} data An object containing arbitrary data supplied by the drag source
4186 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4187 * underlying {@link Roo.dd.StatusProxy} can be updated
4189 onNodeOver : function(n, dd, e, data){
4190 return this.dropAllowed;
4194 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4195 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4196 * node-specific processing if necessary.
4197 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4198 * {@link #getTargetFromEvent} for this node)
4199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4200 * @param {Event} e The event
4201 * @param {Object} data An object containing arbitrary data supplied by the drag source
4203 onNodeOut : function(n, dd, e, data){
4208 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4209 * the drop node. The default implementation returns false, so it should be overridden to provide the
4210 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4211 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4212 * {@link #getTargetFromEvent} for this node)
4213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4214 * @param {Event} e The event
4215 * @param {Object} data An object containing arbitrary data supplied by the drag source
4216 * @return {Boolean} True if the drop was valid, else false
4218 onNodeDrop : function(n, dd, e, data){
4223 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4224 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4225 * it should be overridden to provide the proper feedback if necessary.
4226 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4227 * @param {Event} e The event
4228 * @param {Object} data An object containing arbitrary data supplied by the drag source
4229 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4230 * underlying {@link Roo.dd.StatusProxy} can be updated
4232 onContainerOver : function(dd, e, data){
4233 return this.dropNotAllowed;
4237 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4238 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4239 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4240 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4241 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4242 * @param {Event} e The event
4243 * @param {Object} data An object containing arbitrary data supplied by the drag source
4244 * @return {Boolean} True if the drop was valid, else false
4246 onContainerDrop : function(dd, e, data){
4251 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4252 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4253 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4254 * you should override this method and provide a custom implementation.
4255 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4256 * @param {Event} e The event
4257 * @param {Object} data An object containing arbitrary data supplied by the drag source
4258 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4259 * underlying {@link Roo.dd.StatusProxy} can be updated
4261 notifyEnter : function(dd, e, data){
4262 return this.dropNotAllowed;
4266 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4267 * This method will be called on every mouse movement while the drag source is over the drop zone.
4268 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4269 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4270 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4271 * registered node, it will call {@link #onContainerOver}.
4272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4273 * @param {Event} e The event
4274 * @param {Object} data An object containing arbitrary data supplied by the drag source
4275 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4276 * underlying {@link Roo.dd.StatusProxy} can be updated
4278 notifyOver : function(dd, e, data){
4279 var n = this.getTargetFromEvent(e);
4280 if(!n){ // not over valid drop target
4281 if(this.lastOverNode){
4282 this.onNodeOut(this.lastOverNode, dd, e, data);
4283 this.lastOverNode = null;
4285 return this.onContainerOver(dd, e, data);
4287 if(this.lastOverNode != n){
4288 if(this.lastOverNode){
4289 this.onNodeOut(this.lastOverNode, dd, e, data);
4291 this.onNodeEnter(n, dd, e, data);
4292 this.lastOverNode = n;
4294 return this.onNodeOver(n, dd, e, data);
4298 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4299 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4300 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4301 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4302 * @param {Event} e The event
4303 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4305 notifyOut : function(dd, e, data){
4306 if(this.lastOverNode){
4307 this.onNodeOut(this.lastOverNode, dd, e, data);
4308 this.lastOverNode = null;
4313 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4314 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4315 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4316 * otherwise it will call {@link #onContainerDrop}.
4317 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4318 * @param {Event} e The event
4319 * @param {Object} data An object containing arbitrary data supplied by the drag source
4320 * @return {Boolean} True if the drop was valid, else false
4322 notifyDrop : function(dd, e, data){
4323 if(this.lastOverNode){
4324 this.onNodeOut(this.lastOverNode, dd, e, data);
4325 this.lastOverNode = null;
4327 var n = this.getTargetFromEvent(e);
4329 this.onNodeDrop(n, dd, e, data) :
4330 this.onContainerDrop(dd, e, data);
4334 triggerCacheRefresh : function(){
4335 Roo.dd.DDM.refreshCache(this.groups);
4339 * Ext JS Library 1.1.1
4340 * Copyright(c) 2006-2007, Ext JS, LLC.
4342 * Originally Released Under LGPL - original licence link has changed is not relivant.
4345 * <script type="text/javascript">
4350 * @class Roo.data.SortTypes
4352 * Defines the default sorting (casting?) comparison functions used when sorting data.
4354 Roo.data.SortTypes = {
4356 * Default sort that does nothing
4357 * @param {Mixed} s The value being converted
4358 * @return {Mixed} The comparison value
4365 * The regular expression used to strip tags
4369 stripTagsRE : /<\/?[^>]+>/gi,
4372 * Strips all HTML tags to sort on text only
4373 * @param {Mixed} s The value being converted
4374 * @return {String} The comparison value
4376 asText : function(s){
4377 return String(s).replace(this.stripTagsRE, "");
4381 * Strips all HTML tags to sort on text only - Case insensitive
4382 * @param {Mixed} s The value being converted
4383 * @return {String} The comparison value
4385 asUCText : function(s){
4386 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4390 * Case insensitive string
4391 * @param {Mixed} s The value being converted
4392 * @return {String} The comparison value
4394 asUCString : function(s) {
4395 return String(s).toUpperCase();
4400 * @param {Mixed} s The value being converted
4401 * @return {Number} The comparison value
4403 asDate : function(s) {
4407 if(s instanceof Date){
4410 return Date.parse(String(s));
4415 * @param {Mixed} s The value being converted
4416 * @return {Float} The comparison value
4418 asFloat : function(s) {
4419 var val = parseFloat(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4426 * @param {Mixed} s The value being converted
4427 * @return {Number} The comparison value
4429 asInt : function(s) {
4430 var val = parseInt(String(s).replace(/,/g, ""));
4431 if(isNaN(val)) val = 0;
4436 * Ext JS Library 1.1.1
4437 * Copyright(c) 2006-2007, Ext JS, LLC.
4439 * Originally Released Under LGPL - original licence link has changed is not relivant.
4442 * <script type="text/javascript">
4446 * @class Roo.data.Record
4447 * Instances of this class encapsulate both record <em>definition</em> information, and record
4448 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4449 * to access Records cached in an {@link Roo.data.Store} object.<br>
4451 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4452 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4455 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4457 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4458 * {@link #create}. The parameters are the same.
4459 * @param {Array} data An associative Array of data values keyed by the field name.
4460 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4461 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4462 * not specified an integer id is generated.
4464 Roo.data.Record = function(data, id){
4465 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4470 * Generate a constructor for a specific record layout.
4471 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4472 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4473 * Each field definition object may contain the following properties: <ul>
4474 * <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,
4475 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4476 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4477 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4478 * is being used, then this is a string containing the javascript expression to reference the data relative to
4479 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4480 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4481 * this may be omitted.</p></li>
4482 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4483 * <ul><li>auto (Default, implies no conversion)</li>
4488 * <li>date</li></ul></p></li>
4489 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4490 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4491 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4492 * by the Reader into an object that will be stored in the Record. It is passed the
4493 * following parameters:<ul>
4494 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4496 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4498 * <br>usage:<br><pre><code>
4499 var TopicRecord = Roo.data.Record.create(
4500 {name: 'title', mapping: 'topic_title'},
4501 {name: 'author', mapping: 'username'},
4502 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4503 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4504 {name: 'lastPoster', mapping: 'user2'},
4505 {name: 'excerpt', mapping: 'post_text'}
4508 var myNewRecord = new TopicRecord({
4509 title: 'Do my job please',
4512 lastPost: new Date(),
4513 lastPoster: 'Animal',
4514 excerpt: 'No way dude!'
4516 myStore.add(myNewRecord);
4521 Roo.data.Record.create = function(o){
4523 f.superclass.constructor.apply(this, arguments);
4525 Roo.extend(f, Roo.data.Record);
4526 var p = f.prototype;
4527 p.fields = new Roo.util.MixedCollection(false, function(field){
4530 for(var i = 0, len = o.length; i < len; i++){
4531 p.fields.add(new Roo.data.Field(o[i]));
4533 f.getField = function(name){
4534 return p.fields.get(name);
4539 Roo.data.Record.AUTO_ID = 1000;
4540 Roo.data.Record.EDIT = 'edit';
4541 Roo.data.Record.REJECT = 'reject';
4542 Roo.data.Record.COMMIT = 'commit';
4544 Roo.data.Record.prototype = {
4546 * Readonly flag - true if this record has been modified.
4555 join : function(store){
4560 * Set the named field to the specified value.
4561 * @param {String} name The name of the field to set.
4562 * @param {Object} value The value to set the field to.
4564 set : function(name, value){
4565 if(this.data[name] == value){
4572 if(typeof this.modified[name] == 'undefined'){
4573 this.modified[name] = this.data[name];
4575 this.data[name] = value;
4577 this.store.afterEdit(this);
4582 * Get the value of the named field.
4583 * @param {String} name The name of the field to get the value of.
4584 * @return {Object} The value of the field.
4586 get : function(name){
4587 return this.data[name];
4591 beginEdit : function(){
4592 this.editing = true;
4597 cancelEdit : function(){
4598 this.editing = false;
4599 delete this.modified;
4603 endEdit : function(){
4604 this.editing = false;
4605 if(this.dirty && this.store){
4606 this.store.afterEdit(this);
4611 * Usually called by the {@link Roo.data.Store} which owns the Record.
4612 * Rejects all changes made to the Record since either creation, or the last commit operation.
4613 * Modified fields are reverted to their original values.
4615 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4616 * of reject operations.
4618 reject : function(){
4619 var m = this.modified;
4621 if(typeof m[n] != "function"){
4622 this.data[n] = m[n];
4626 delete this.modified;
4627 this.editing = false;
4629 this.store.afterReject(this);
4634 * Usually called by the {@link Roo.data.Store} which owns the Record.
4635 * Commits all changes made to the Record since either creation, or the last commit operation.
4637 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4638 * of commit operations.
4640 commit : function(){
4642 delete this.modified;
4643 this.editing = false;
4645 this.store.afterCommit(this);
4650 hasError : function(){
4651 return this.error != null;
4655 clearError : function(){
4660 * Creates a copy of this record.
4661 * @param {String} id (optional) A new record id if you don't want to use this record's id
4664 copy : function(newId) {
4665 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4669 * Ext JS Library 1.1.1
4670 * Copyright(c) 2006-2007, Ext JS, LLC.
4672 * Originally Released Under LGPL - original licence link has changed is not relivant.
4675 * <script type="text/javascript">
4681 * @class Roo.data.Store
4682 * @extends Roo.util.Observable
4683 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4684 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4686 * 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
4687 * has no knowledge of the format of the data returned by the Proxy.<br>
4689 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4690 * instances from the data object. These records are cached and made available through accessor functions.
4692 * Creates a new Store.
4693 * @param {Object} config A config object containing the objects needed for the Store to access data,
4694 * and read the data into Records.
4696 Roo.data.Store = function(config){
4697 this.data = new Roo.util.MixedCollection(false);
4698 this.data.getKey = function(o){
4701 this.baseParams = {};
4710 if(config && config.data){
4711 this.inlineData = config.data;
4715 Roo.apply(this, config);
4717 if(this.reader){ // reader passed
4718 this.reader = Roo.factory(this.reader, Roo.data);
4719 this.reader.xmodule = this.xmodule || false;
4720 if(!this.recordType){
4721 this.recordType = this.reader.recordType;
4723 if(this.reader.onMetaChange){
4724 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4728 if(this.recordType){
4729 this.fields = this.recordType.prototype.fields;
4735 * @event datachanged
4736 * Fires when the data cache has changed, and a widget which is using this Store
4737 * as a Record cache should refresh its view.
4738 * @param {Store} this
4743 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4744 * @param {Store} this
4745 * @param {Object} meta The JSON metadata
4750 * Fires when Records have been added to the Store
4751 * @param {Store} this
4752 * @param {Roo.data.Record[]} records The array of Records added
4753 * @param {Number} index The index at which the record(s) were added
4758 * Fires when a Record has been removed from the Store
4759 * @param {Store} this
4760 * @param {Roo.data.Record} record The Record that was removed
4761 * @param {Number} index The index at which the record was removed
4766 * Fires when a Record has been updated
4767 * @param {Store} this
4768 * @param {Roo.data.Record} record The Record that was updated
4769 * @param {String} operation The update operation being performed. Value may be one of:
4771 Roo.data.Record.EDIT
4772 Roo.data.Record.REJECT
4773 Roo.data.Record.COMMIT
4779 * Fires when the data cache has been cleared.
4780 * @param {Store} this
4785 * Fires before a request is made for a new data object. If the beforeload handler returns false
4786 * the load action will be canceled.
4787 * @param {Store} this
4788 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4793 * Fires after a new set of Records has been loaded.
4794 * @param {Store} this
4795 * @param {Roo.data.Record[]} records The Records that were loaded
4796 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4800 * @event loadexception
4801 * Fires if an exception occurs in the Proxy during loading.
4802 * Called with the signature of the Proxy's "loadexception" event.
4803 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4806 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4807 * @param {Object} load options
4808 * @param {Object} jsonData from your request (normally this contains the Exception)
4810 loadexception : true
4814 this.proxy = Roo.factory(this.proxy, Roo.data);
4815 this.proxy.xmodule = this.xmodule || false;
4816 this.relayEvents(this.proxy, ["loadexception"]);
4818 this.sortToggle = {};
4820 Roo.data.Store.superclass.constructor.call(this);
4822 if(this.inlineData){
4823 this.loadData(this.inlineData);
4824 delete this.inlineData;
4827 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4829 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4830 * without a remote query - used by combo/forms at present.
4834 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4837 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4840 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4841 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4844 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4845 * on any HTTP request
4848 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4851 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4852 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4857 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4858 * loaded or when a record is removed. (defaults to false).
4860 pruneModifiedRecords : false,
4866 * Add Records to the Store and fires the add event.
4867 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4869 add : function(records){
4870 records = [].concat(records);
4871 for(var i = 0, len = records.length; i < len; i++){
4872 records[i].join(this);
4874 var index = this.data.length;
4875 this.data.addAll(records);
4876 this.fireEvent("add", this, records, index);
4880 * Remove a Record from the Store and fires the remove event.
4881 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4883 remove : function(record){
4884 var index = this.data.indexOf(record);
4885 this.data.removeAt(index);
4886 if(this.pruneModifiedRecords){
4887 this.modified.remove(record);
4889 this.fireEvent("remove", this, record, index);
4893 * Remove all Records from the Store and fires the clear event.
4895 removeAll : function(){
4897 if(this.pruneModifiedRecords){
4900 this.fireEvent("clear", this);
4904 * Inserts Records to the Store at the given index and fires the add event.
4905 * @param {Number} index The start index at which to insert the passed Records.
4906 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4908 insert : function(index, records){
4909 records = [].concat(records);
4910 for(var i = 0, len = records.length; i < len; i++){
4911 this.data.insert(index, records[i]);
4912 records[i].join(this);
4914 this.fireEvent("add", this, records, index);
4918 * Get the index within the cache of the passed Record.
4919 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4920 * @return {Number} The index of the passed Record. Returns -1 if not found.
4922 indexOf : function(record){
4923 return this.data.indexOf(record);
4927 * Get the index within the cache of the Record with the passed id.
4928 * @param {String} id The id of the Record to find.
4929 * @return {Number} The index of the Record. Returns -1 if not found.
4931 indexOfId : function(id){
4932 return this.data.indexOfKey(id);
4936 * Get the Record with the specified id.
4937 * @param {String} id The id of the Record to find.
4938 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4940 getById : function(id){
4941 return this.data.key(id);
4945 * Get the Record at the specified index.
4946 * @param {Number} index The index of the Record to find.
4947 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4949 getAt : function(index){
4950 return this.data.itemAt(index);
4954 * Returns a range of Records between specified indices.
4955 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4956 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4957 * @return {Roo.data.Record[]} An array of Records
4959 getRange : function(start, end){
4960 return this.data.getRange(start, end);
4964 storeOptions : function(o){
4965 o = Roo.apply({}, o);
4968 this.lastOptions = o;
4972 * Loads the Record cache from the configured Proxy using the configured Reader.
4974 * If using remote paging, then the first load call must specify the <em>start</em>
4975 * and <em>limit</em> properties in the options.params property to establish the initial
4976 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4978 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4979 * and this call will return before the new data has been loaded. Perform any post-processing
4980 * in a callback function, or in a "load" event handler.</strong>
4982 * @param {Object} options An object containing properties which control loading options:<ul>
4983 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4984 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4985 * passed the following arguments:<ul>
4986 * <li>r : Roo.data.Record[]</li>
4987 * <li>options: Options object from the load call</li>
4988 * <li>success: Boolean success indicator</li></ul></li>
4989 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4990 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4993 load : function(options){
4994 options = options || {};
4995 if(this.fireEvent("beforeload", this, options) !== false){
4996 this.storeOptions(options);
4997 var p = Roo.apply(options.params || {}, this.baseParams);
4998 // if meta was not loaded from remote source.. try requesting it.
4999 if (!this.reader.metaFromRemote) {
5002 if(this.sortInfo && this.remoteSort){
5003 var pn = this.paramNames;
5004 p[pn["sort"]] = this.sortInfo.field;
5005 p[pn["dir"]] = this.sortInfo.direction;
5007 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5012 * Reloads the Record cache from the configured Proxy using the configured Reader and
5013 * the options from the last load operation performed.
5014 * @param {Object} options (optional) An object containing properties which may override the options
5015 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5016 * the most recently used options are reused).
5018 reload : function(options){
5019 this.load(Roo.applyIf(options||{}, this.lastOptions));
5023 // Called as a callback by the Reader during a load operation.
5024 loadRecords : function(o, options, success){
5025 if(!o || success === false){
5026 if(success !== false){
5027 this.fireEvent("load", this, [], options);
5029 if(options.callback){
5030 options.callback.call(options.scope || this, [], options, false);
5034 // if data returned failure - throw an exception.
5035 if (o.success === false) {
5036 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5039 var r = o.records, t = o.totalRecords || r.length;
5040 if(!options || options.add !== true){
5041 if(this.pruneModifiedRecords){
5044 for(var i = 0, len = r.length; i < len; i++){
5048 this.data = this.snapshot;
5049 delete this.snapshot;
5052 this.data.addAll(r);
5053 this.totalLength = t;
5055 this.fireEvent("datachanged", this);
5057 this.totalLength = Math.max(t, this.data.length+r.length);
5060 this.fireEvent("load", this, r, options);
5061 if(options.callback){
5062 options.callback.call(options.scope || this, r, options, true);
5067 * Loads data from a passed data block. A Reader which understands the format of the data
5068 * must have been configured in the constructor.
5069 * @param {Object} data The data block from which to read the Records. The format of the data expected
5070 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5071 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5073 loadData : function(o, append){
5074 var r = this.reader.readRecords(o);
5075 this.loadRecords(r, {add: append}, true);
5079 * Gets the number of cached records.
5081 * <em>If using paging, this may not be the total size of the dataset. If the data object
5082 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5083 * the data set size</em>
5085 getCount : function(){
5086 return this.data.length || 0;
5090 * Gets the total number of records in the dataset as returned by the server.
5092 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5093 * the dataset size</em>
5095 getTotalCount : function(){
5096 return this.totalLength || 0;
5100 * Returns the sort state of the Store as an object with two properties:
5102 field {String} The name of the field by which the Records are sorted
5103 direction {String} The sort order, "ASC" or "DESC"
5106 getSortState : function(){
5107 return this.sortInfo;
5111 applySort : function(){
5112 if(this.sortInfo && !this.remoteSort){
5113 var s = this.sortInfo, f = s.field;
5114 var st = this.fields.get(f).sortType;
5115 var fn = function(r1, r2){
5116 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5117 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5119 this.data.sort(s.direction, fn);
5120 if(this.snapshot && this.snapshot != this.data){
5121 this.snapshot.sort(s.direction, fn);
5127 * Sets the default sort column and order to be used by the next load operation.
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 setDefaultSort : function(field, dir){
5132 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5137 * If remote sorting is used, the sort is performed on the server, and the cache is
5138 * reloaded. If local sorting is used, the cache is sorted internally.
5139 * @param {String} fieldName The name of the field to sort by.
5140 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5142 sort : function(fieldName, dir){
5143 var f = this.fields.get(fieldName);
5145 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5146 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5151 this.sortToggle[f.name] = dir;
5152 this.sortInfo = {field: f.name, direction: dir};
5153 if(!this.remoteSort){
5155 this.fireEvent("datachanged", this);
5157 this.load(this.lastOptions);
5162 * Calls the specified function for each of the Records in the cache.
5163 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5164 * Returning <em>false</em> aborts and exits the iteration.
5165 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5167 each : function(fn, scope){
5168 this.data.each(fn, scope);
5172 * Gets all records modified since the last commit. Modified records are persisted across load operations
5173 * (e.g., during paging).
5174 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5176 getModifiedRecords : function(){
5177 return this.modified;
5181 createFilterFn : function(property, value, anyMatch){
5182 if(!value.exec){ // not a regex
5183 value = String(value);
5184 if(value.length == 0){
5187 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5190 return value.test(r.data[property]);
5195 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5196 * @param {String} property A field on your records
5197 * @param {Number} start The record index to start at (defaults to 0)
5198 * @param {Number} end The last record index to include (defaults to length - 1)
5199 * @return {Number} The sum
5201 sum : function(property, start, end){
5202 var rs = this.data.items, v = 0;
5204 end = (end || end === 0) ? end : rs.length-1;
5206 for(var i = start; i <= end; i++){
5207 v += (rs[i].data[property] || 0);
5213 * Filter the records by a specified property.
5214 * @param {String} field A field on your records
5215 * @param {String/RegExp} value Either a string that the field
5216 * should start with or a RegExp to test against the field
5217 * @param {Boolean} anyMatch True to match any part not just the beginning
5219 filter : function(property, value, anyMatch){
5220 var fn = this.createFilterFn(property, value, anyMatch);
5221 return fn ? this.filterBy(fn) : this.clearFilter();
5225 * Filter by a function. The specified function will be called with each
5226 * record in this data source. If the function returns true the record is included,
5227 * otherwise it is filtered.
5228 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5229 * @param {Object} scope (optional) The scope of the function (defaults to this)
5231 filterBy : function(fn, scope){
5232 this.snapshot = this.snapshot || this.data;
5233 this.data = this.queryBy(fn, scope||this);
5234 this.fireEvent("datachanged", this);
5238 * Query the records by a specified property.
5239 * @param {String} field A field on your records
5240 * @param {String/RegExp} value Either a string that the field
5241 * should start with or a RegExp to test against the field
5242 * @param {Boolean} anyMatch True to match any part not just the beginning
5243 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5245 query : function(property, value, anyMatch){
5246 var fn = this.createFilterFn(property, value, anyMatch);
5247 return fn ? this.queryBy(fn) : this.data.clone();
5251 * Query by a function. The specified function will be called with each
5252 * record in this data source. If the function returns true the record is included
5254 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5255 * @param {Object} scope (optional) The scope of the function (defaults to this)
5256 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5258 queryBy : function(fn, scope){
5259 var data = this.snapshot || this.data;
5260 return data.filterBy(fn, scope||this);
5264 * Collects unique values for a particular dataIndex from this store.
5265 * @param {String} dataIndex The property to collect
5266 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5267 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5268 * @return {Array} An array of the unique values
5270 collect : function(dataIndex, allowNull, bypassFilter){
5271 var d = (bypassFilter === true && this.snapshot) ?
5272 this.snapshot.items : this.data.items;
5273 var v, sv, r = [], l = {};
5274 for(var i = 0, len = d.length; i < len; i++){
5275 v = d[i].data[dataIndex];
5277 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5286 * Revert to a view of the Record cache with no filtering applied.
5287 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5289 clearFilter : function(suppressEvent){
5290 if(this.snapshot && this.snapshot != this.data){
5291 this.data = this.snapshot;
5292 delete this.snapshot;
5293 if(suppressEvent !== true){
5294 this.fireEvent("datachanged", this);
5300 afterEdit : function(record){
5301 if(this.modified.indexOf(record) == -1){
5302 this.modified.push(record);
5304 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5308 afterReject : function(record){
5309 this.modified.remove(record);
5310 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5314 afterCommit : function(record){
5315 this.modified.remove(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5320 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5321 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5323 commitChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5332 * Cancel outstanding changes on all changed records.
5334 rejectChanges : function(){
5335 var m = this.modified.slice(0);
5337 for(var i = 0, len = m.length; i < len; i++){
5342 onMetaChange : function(meta, rtype, o){
5343 this.recordType = rtype;
5344 this.fields = rtype.prototype.fields;
5345 delete this.snapshot;
5346 this.sortInfo = meta.sortInfo || this.sortInfo;
5348 this.fireEvent('metachange', this, this.reader.meta);
5352 * Ext JS Library 1.1.1
5353 * Copyright(c) 2006-2007, Ext JS, LLC.
5355 * Originally Released Under LGPL - original licence link has changed is not relivant.
5358 * <script type="text/javascript">
5362 * @class Roo.data.SimpleStore
5363 * @extends Roo.data.Store
5364 * Small helper class to make creating Stores from Array data easier.
5365 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5366 * @cfg {Array} fields An array of field definition objects, or field name strings.
5367 * @cfg {Array} data The multi-dimensional array of data
5369 * @param {Object} config
5371 Roo.data.SimpleStore = function(config){
5372 Roo.data.SimpleStore.superclass.constructor.call(this, {
5374 reader: new Roo.data.ArrayReader({
5377 Roo.data.Record.create(config.fields)
5379 proxy : new Roo.data.MemoryProxy(config.data)
5383 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5385 * Ext JS Library 1.1.1
5386 * Copyright(c) 2006-2007, Ext JS, LLC.
5388 * Originally Released Under LGPL - original licence link has changed is not relivant.
5391 * <script type="text/javascript">
5396 * @extends Roo.data.Store
5397 * @class Roo.data.JsonStore
5398 * Small helper class to make creating Stores for JSON data easier. <br/>
5400 var store = new Roo.data.JsonStore({
5401 url: 'get-images.php',
5403 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5406 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5407 * JsonReader and HttpProxy (unless inline data is provided).</b>
5408 * @cfg {Array} fields An array of field definition objects, or field name strings.
5410 * @param {Object} config
5412 Roo.data.JsonStore = function(c){
5413 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5414 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5415 reader: new Roo.data.JsonReader(c, c.fields)
5418 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5420 * Ext JS Library 1.1.1
5421 * Copyright(c) 2006-2007, Ext JS, LLC.
5423 * Originally Released Under LGPL - original licence link has changed is not relivant.
5426 * <script type="text/javascript">
5430 Roo.data.Field = function(config){
5431 if(typeof config == "string"){
5432 config = {name: config};
5434 Roo.apply(this, config);
5440 var st = Roo.data.SortTypes;
5441 // named sortTypes are supported, here we look them up
5442 if(typeof this.sortType == "string"){
5443 this.sortType = st[this.sortType];
5446 // set default sortType for strings and dates
5450 this.sortType = st.asUCString;
5453 this.sortType = st.asDate;
5456 this.sortType = st.none;
5461 var stripRe = /[\$,%]/g;
5463 // prebuilt conversion function for this field, instead of
5464 // switching every time we're reading a value
5466 var cv, dateFormat = this.dateFormat;
5471 cv = function(v){ return v; };
5474 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5478 return v !== undefined && v !== null && v !== '' ?
5479 parseInt(String(v).replace(stripRe, ""), 10) : '';
5484 return v !== undefined && v !== null && v !== '' ?
5485 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5490 cv = function(v){ return v === true || v === "true" || v == 1; };
5497 if(v instanceof Date){
5501 if(dateFormat == "timestamp"){
5502 return new Date(v*1000);
5504 return Date.parseDate(v, dateFormat);
5506 var parsed = Date.parse(v);
5507 return parsed ? new Date(parsed) : null;
5516 Roo.data.Field.prototype = {
5524 * Ext JS Library 1.1.1
5525 * Copyright(c) 2006-2007, Ext JS, LLC.
5527 * Originally Released Under LGPL - original licence link has changed is not relivant.
5530 * <script type="text/javascript">
5533 // Base class for reading structured data from a data source. This class is intended to be
5534 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5537 * @class Roo.data.DataReader
5538 * Base class for reading structured data from a data source. This class is intended to be
5539 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5542 Roo.data.DataReader = function(meta, recordType){
5546 this.recordType = recordType instanceof Array ?
5547 Roo.data.Record.create(recordType) : recordType;
5550 Roo.data.DataReader.prototype = {
5552 * Create an empty record
5553 * @param {Object} data (optional) - overlay some values
5554 * @return {Roo.data.Record} record created.
5556 newRow : function(d) {
5558 this.recordType.prototype.fields.each(function(c) {
5560 case 'int' : da[c.name] = 0; break;
5561 case 'date' : da[c.name] = new Date(); break;
5562 case 'float' : da[c.name] = 0.0; break;
5563 case 'boolean' : da[c.name] = false; break;
5564 default : da[c.name] = ""; break;
5568 return new this.recordType(Roo.apply(da, d));
5573 * Ext JS Library 1.1.1
5574 * Copyright(c) 2006-2007, Ext JS, LLC.
5576 * Originally Released Under LGPL - original licence link has changed is not relivant.
5579 * <script type="text/javascript">
5583 * @class Roo.data.DataProxy
5584 * @extends Roo.data.Observable
5585 * This class is an abstract base class for implementations which provide retrieval of
5586 * unformatted data objects.<br>
5588 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5589 * (of the appropriate type which knows how to parse the data object) to provide a block of
5590 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5592 * Custom implementations must implement the load method as described in
5593 * {@link Roo.data.HttpProxy#load}.
5595 Roo.data.DataProxy = function(){
5599 * Fires before a network request is made to retrieve a data object.
5600 * @param {Object} This DataProxy object.
5601 * @param {Object} params The params parameter to the load function.
5606 * Fires before the load method's callback is called.
5607 * @param {Object} This DataProxy object.
5608 * @param {Object} o The data object.
5609 * @param {Object} arg The callback argument object passed to the load function.
5613 * @event loadexception
5614 * Fires if an Exception occurs during data retrieval.
5615 * @param {Object} This DataProxy object.
5616 * @param {Object} o The data object.
5617 * @param {Object} arg The callback argument object passed to the load function.
5618 * @param {Object} e The Exception.
5620 loadexception : true
5622 Roo.data.DataProxy.superclass.constructor.call(this);
5625 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5628 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5632 * Ext JS Library 1.1.1
5633 * Copyright(c) 2006-2007, Ext JS, LLC.
5635 * Originally Released Under LGPL - original licence link has changed is not relivant.
5638 * <script type="text/javascript">
5641 * @class Roo.data.MemoryProxy
5642 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5643 * to the Reader when its load method is called.
5645 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5647 Roo.data.MemoryProxy = function(data){
5651 Roo.data.MemoryProxy.superclass.constructor.call(this);
5655 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5657 * Load data from the requested source (in this case an in-memory
5658 * data object passed to the constructor), read the data object into
5659 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5660 * process that block using the passed callback.
5661 * @param {Object} params This parameter is not used by the MemoryProxy class.
5662 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5663 * object into a block of Roo.data.Records.
5664 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5665 * The function must be passed <ul>
5666 * <li>The Record block object</li>
5667 * <li>The "arg" argument from the load function</li>
5668 * <li>A boolean success indicator</li>
5670 * @param {Object} scope The scope in which to call the callback
5671 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5673 load : function(params, reader, callback, scope, arg){
5674 params = params || {};
5677 result = reader.readRecords(this.data);
5679 this.fireEvent("loadexception", this, arg, null, e);
5680 callback.call(scope, null, arg, false);
5683 callback.call(scope, result, arg, true);
5687 update : function(params, records){
5692 * Ext JS Library 1.1.1
5693 * Copyright(c) 2006-2007, Ext JS, LLC.
5695 * Originally Released Under LGPL - original licence link has changed is not relivant.
5698 * <script type="text/javascript">
5701 * @class Roo.data.HttpProxy
5702 * @extends Roo.data.DataProxy
5703 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5704 * configured to reference a certain URL.<br><br>
5706 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5707 * from which the running page was served.<br><br>
5709 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5711 * Be aware that to enable the browser to parse an XML document, the server must set
5712 * the Content-Type header in the HTTP response to "text/xml".
5714 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5715 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5716 * will be used to make the request.
5718 Roo.data.HttpProxy = function(conn){
5719 Roo.data.HttpProxy.superclass.constructor.call(this);
5720 // is conn a conn config or a real conn?
5722 this.useAjax = !conn || !conn.events;
5726 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5727 // thse are take from connection...
5730 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5733 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5734 * extra parameters to each request made by this object. (defaults to undefined)
5737 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5738 * to each request made by this object. (defaults to undefined)
5741 * @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)
5744 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5747 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5753 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5757 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5758 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5759 * a finer-grained basis than the DataProxy events.
5761 getConnection : function(){
5762 return this.useAjax ? Roo.Ajax : this.conn;
5766 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5767 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5768 * process that block using the passed callback.
5769 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5770 * for the request to the remote server.
5771 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5772 * object into a block of Roo.data.Records.
5773 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5774 * The function must be passed <ul>
5775 * <li>The Record block object</li>
5776 * <li>The "arg" argument from the load function</li>
5777 * <li>A boolean success indicator</li>
5779 * @param {Object} scope The scope in which to call the callback
5780 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5782 load : function(params, reader, callback, scope, arg){
5783 if(this.fireEvent("beforeload", this, params) !== false){
5785 params : params || {},
5787 callback : callback,
5792 callback : this.loadResponse,
5796 Roo.applyIf(o, this.conn);
5797 if(this.activeRequest){
5798 Roo.Ajax.abort(this.activeRequest);
5800 this.activeRequest = Roo.Ajax.request(o);
5802 this.conn.request(o);
5805 callback.call(scope||this, null, arg, false);
5810 loadResponse : function(o, success, response){
5811 delete this.activeRequest;
5813 this.fireEvent("loadexception", this, o, response);
5814 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5819 result = o.reader.read(response);
5821 this.fireEvent("loadexception", this, o, response, e);
5822 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5826 this.fireEvent("load", this, o, o.request.arg);
5827 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5831 update : function(dataSet){
5836 updateResponse : function(dataSet){
5841 * Ext JS Library 1.1.1
5842 * Copyright(c) 2006-2007, Ext JS, LLC.
5844 * Originally Released Under LGPL - original licence link has changed is not relivant.
5847 * <script type="text/javascript">
5851 * @class Roo.data.ScriptTagProxy
5852 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5853 * other than the originating domain of the running page.<br><br>
5855 * <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
5856 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5858 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5859 * source code that is used as the source inside a <script> tag.<br><br>
5861 * In order for the browser to process the returned data, the server must wrap the data object
5862 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5863 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5864 * depending on whether the callback name was passed:
5867 boolean scriptTag = false;
5868 String cb = request.getParameter("callback");
5871 response.setContentType("text/javascript");
5873 response.setContentType("application/x-json");
5875 Writer out = response.getWriter();
5877 out.write(cb + "(");
5879 out.print(dataBlock.toJsonString());
5886 * @param {Object} config A configuration object.
5888 Roo.data.ScriptTagProxy = function(config){
5889 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5890 Roo.apply(this, config);
5891 this.head = document.getElementsByTagName("head")[0];
5894 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5896 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5898 * @cfg {String} url The URL from which to request the data object.
5901 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5905 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5906 * the server the name of the callback function set up by the load call to process the returned data object.
5907 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5908 * javascript output which calls this named function passing the data object as its only parameter.
5910 callbackParam : "callback",
5912 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5913 * name to the request.
5918 * Load data from the configured URL, read the data object into
5919 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5920 * process that block using the passed callback.
5921 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5922 * for the request to the remote server.
5923 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5924 * object into a block of Roo.data.Records.
5925 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5926 * The function must be passed <ul>
5927 * <li>The Record block object</li>
5928 * <li>The "arg" argument from the load function</li>
5929 * <li>A boolean success indicator</li>
5931 * @param {Object} scope The scope in which to call the callback
5932 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5934 load : function(params, reader, callback, scope, arg){
5935 if(this.fireEvent("beforeload", this, params) !== false){
5937 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5940 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5942 url += "&_dc=" + (new Date().getTime());
5944 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5947 cb : "stcCallback"+transId,
5948 scriptId : "stcScript"+transId,
5952 callback : callback,
5958 window[trans.cb] = function(o){
5959 conn.handleResponse(o, trans);
5962 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5964 if(this.autoAbort !== false){
5968 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5970 var script = document.createElement("script");
5971 script.setAttribute("src", url);
5972 script.setAttribute("type", "text/javascript");
5973 script.setAttribute("id", trans.scriptId);
5974 this.head.appendChild(script);
5978 callback.call(scope||this, null, arg, false);
5983 isLoading : function(){
5984 return this.trans ? true : false;
5988 * Abort the current server request.
5991 if(this.isLoading()){
5992 this.destroyTrans(this.trans);
5997 destroyTrans : function(trans, isLoaded){
5998 this.head.removeChild(document.getElementById(trans.scriptId));
5999 clearTimeout(trans.timeoutId);
6001 window[trans.cb] = undefined;
6003 delete window[trans.cb];
6006 // if hasn't been loaded, wait for load to remove it to prevent script error
6007 window[trans.cb] = function(){
6008 window[trans.cb] = undefined;
6010 delete window[trans.cb];
6017 handleResponse : function(o, trans){
6019 this.destroyTrans(trans, true);
6022 result = trans.reader.readRecords(o);
6024 this.fireEvent("loadexception", this, o, trans.arg, e);
6025 trans.callback.call(trans.scope||window, null, trans.arg, false);
6028 this.fireEvent("load", this, o, trans.arg);
6029 trans.callback.call(trans.scope||window, result, trans.arg, true);
6033 handleFailure : function(trans){
6035 this.destroyTrans(trans, false);
6036 this.fireEvent("loadexception", this, null, trans.arg);
6037 trans.callback.call(trans.scope||window, null, trans.arg, false);
6041 * Ext JS Library 1.1.1
6042 * Copyright(c) 2006-2007, Ext JS, LLC.
6044 * Originally Released Under LGPL - original licence link has changed is not relivant.
6047 * <script type="text/javascript">
6051 * @class Roo.data.JsonReader
6052 * @extends Roo.data.DataReader
6053 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6054 * based on mappings in a provided Roo.data.Record constructor.
6056 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6057 * in the reply previously.
6062 var RecordDef = Roo.data.Record.create([
6063 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6064 {name: 'occupation'} // This field will use "occupation" as the mapping.
6066 var myReader = new Roo.data.JsonReader({
6067 totalProperty: "results", // The property which contains the total dataset size (optional)
6068 root: "rows", // The property which contains an Array of row objects
6069 id: "id" // The property within each row object that provides an ID for the record (optional)
6073 * This would consume a JSON file like this:
6075 { 'results': 2, 'rows': [
6076 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6077 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6080 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6081 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6082 * paged from the remote server.
6083 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6084 * @cfg {String} root name of the property which contains the Array of row objects.
6085 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6087 * Create a new JsonReader
6088 * @param {Object} meta Metadata configuration options
6089 * @param {Object} recordType Either an Array of field definition objects,
6090 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6092 Roo.data.JsonReader = function(meta, recordType){
6095 // set some defaults:
6097 totalProperty: 'total',
6098 successProperty : 'success',
6103 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6105 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6108 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6109 * Used by Store query builder to append _requestMeta to params.
6112 metaFromRemote : false,
6114 * This method is only used by a DataProxy which has retrieved data from a remote server.
6115 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6116 * @return {Object} data A data block which is used by an Roo.data.Store object as
6117 * a cache of Roo.data.Records.
6119 read : function(response){
6120 var json = response.responseText;
6122 var o = /* eval:var:o */ eval("("+json+")");
6124 throw {message: "JsonReader.read: Json object not found"};
6130 this.metaFromRemote = true;
6131 this.meta = o.metaData;
6132 this.recordType = Roo.data.Record.create(o.metaData.fields);
6133 this.onMetaChange(this.meta, this.recordType, o);
6135 return this.readRecords(o);
6138 // private function a store will implement
6139 onMetaChange : function(meta, recordType, o){
6146 simpleAccess: function(obj, subsc) {
6153 getJsonAccessor: function(){
6155 return function(expr) {
6157 return(re.test(expr))
6158 ? new Function("obj", "return obj." + expr)
6168 * Create a data block containing Roo.data.Records from an XML document.
6169 * @param {Object} o An object which contains an Array of row objects in the property specified
6170 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6171 * which contains the total size of the dataset.
6172 * @return {Object} data A data block which is used by an Roo.data.Store object as
6173 * a cache of Roo.data.Records.
6175 readRecords : function(o){
6177 * After any data loads, the raw JSON data is available for further custom processing.
6181 var s = this.meta, Record = this.recordType,
6182 f = Record.prototype.fields, fi = f.items, fl = f.length;
6184 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6186 if(s.totalProperty) {
6187 this.getTotal = this.getJsonAccessor(s.totalProperty);
6189 if(s.successProperty) {
6190 this.getSuccess = this.getJsonAccessor(s.successProperty);
6192 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6194 var g = this.getJsonAccessor(s.id);
6195 this.getId = function(rec) {
6197 return (r === undefined || r === "") ? null : r;
6200 this.getId = function(){return null;};
6203 for(var jj = 0; jj < fl; jj++){
6205 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6206 this.ef[jj] = this.getJsonAccessor(map);
6210 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6211 if(s.totalProperty){
6212 var vt = parseInt(this.getTotal(o), 10);
6217 if(s.successProperty){
6218 var vs = this.getSuccess(o);
6219 if(vs === false || vs === 'false'){
6224 for(var i = 0; i < c; i++){
6227 var id = this.getId(n);
6228 for(var j = 0; j < fl; j++){
6230 var v = this.ef[j](n);
6232 Roo.log('missing convert for ' + f.name);
6236 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6238 var record = new Record(values, id);
6240 records[i] = record;
6245 totalRecords : totalRecords
6250 * Ext JS Library 1.1.1
6251 * Copyright(c) 2006-2007, Ext JS, LLC.
6253 * Originally Released Under LGPL - original licence link has changed is not relivant.
6256 * <script type="text/javascript">
6260 * @class Roo.data.XmlReader
6261 * @extends Roo.data.DataReader
6262 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6263 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6265 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6266 * header in the HTTP response must be set to "text/xml".</em>
6270 var RecordDef = Roo.data.Record.create([
6271 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6272 {name: 'occupation'} // This field will use "occupation" as the mapping.
6274 var myReader = new Roo.data.XmlReader({
6275 totalRecords: "results", // The element which contains the total dataset size (optional)
6276 record: "row", // The repeated element which contains row information
6277 id: "id" // The element within the row that provides an ID for the record (optional)
6281 * This would consume an XML file like this:
6285 <results>2</results>
6288 <name>Bill</name>
6289 <occupation>Gardener</occupation>
6293 <name>Ben</name>
6294 <occupation>Horticulturalist</occupation>
6298 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6299 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6300 * paged from the remote server.
6301 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6302 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6303 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6304 * a record identifier value.
6306 * Create a new XmlReader
6307 * @param {Object} meta Metadata configuration options
6308 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6309 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6310 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6312 Roo.data.XmlReader = function(meta, recordType){
6314 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6316 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6318 * This method is only used by a DataProxy which has retrieved data from a remote server.
6319 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6320 * to contain a method called 'responseXML' that returns an XML document object.
6321 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6322 * a cache of Roo.data.Records.
6324 read : function(response){
6325 var doc = response.responseXML;
6327 throw {message: "XmlReader.read: XML Document not available"};
6329 return this.readRecords(doc);
6333 * Create a data block containing Roo.data.Records from an XML document.
6334 * @param {Object} doc A parsed XML document.
6335 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6336 * a cache of Roo.data.Records.
6338 readRecords : function(doc){
6340 * After any data loads/reads, the raw XML Document is available for further custom processing.
6344 var root = doc.documentElement || doc;
6345 var q = Roo.DomQuery;
6346 var recordType = this.recordType, fields = recordType.prototype.fields;
6347 var sid = this.meta.id;
6348 var totalRecords = 0, success = true;
6349 if(this.meta.totalRecords){
6350 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6353 if(this.meta.success){
6354 var sv = q.selectValue(this.meta.success, root, true);
6355 success = sv !== false && sv !== 'false';
6358 var ns = q.select(this.meta.record, root);
6359 for(var i = 0, len = ns.length; i < len; i++) {
6362 var id = sid ? q.selectValue(sid, n) : undefined;
6363 for(var j = 0, jlen = fields.length; j < jlen; j++){
6364 var f = fields.items[j];
6365 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6369 var record = new recordType(values, id);
6371 records[records.length] = record;
6377 totalRecords : totalRecords || records.length
6382 * Ext JS Library 1.1.1
6383 * Copyright(c) 2006-2007, Ext JS, LLC.
6385 * Originally Released Under LGPL - original licence link has changed is not relivant.
6388 * <script type="text/javascript">
6392 * @class Roo.data.ArrayReader
6393 * @extends Roo.data.DataReader
6394 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6395 * Each element of that Array represents a row of data fields. The
6396 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6397 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6401 var RecordDef = Roo.data.Record.create([
6402 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6403 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6405 var myReader = new Roo.data.ArrayReader({
6406 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6410 * This would consume an Array like this:
6412 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6414 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6416 * Create a new JsonReader
6417 * @param {Object} meta Metadata configuration options.
6418 * @param {Object} recordType Either an Array of field definition objects
6419 * as specified to {@link Roo.data.Record#create},
6420 * or an {@link Roo.data.Record} object
6421 * created using {@link Roo.data.Record#create}.
6423 Roo.data.ArrayReader = function(meta, recordType){
6424 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6427 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6429 * Create a data block containing Roo.data.Records from an XML document.
6430 * @param {Object} o An Array of row objects which represents the dataset.
6431 * @return {Object} data A data block which is used by an Roo.data.Store object as
6432 * a cache of Roo.data.Records.
6434 readRecords : function(o){
6435 var sid = this.meta ? this.meta.id : null;
6436 var recordType = this.recordType, fields = recordType.prototype.fields;
6439 for(var i = 0; i < root.length; i++){
6442 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6443 for(var j = 0, jlen = fields.length; j < jlen; j++){
6444 var f = fields.items[j];
6445 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6446 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6450 var record = new recordType(values, id);
6452 records[records.length] = record;
6456 totalRecords : records.length
6461 * Ext JS Library 1.1.1
6462 * Copyright(c) 2006-2007, Ext JS, LLC.
6464 * Originally Released Under LGPL - original licence link has changed is not relivant.
6467 * <script type="text/javascript">
6472 * @class Roo.data.Tree
6473 * @extends Roo.util.Observable
6474 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6475 * in the tree have most standard DOM functionality.
6477 * @param {Node} root (optional) The root node
6479 Roo.data.Tree = function(root){
6482 * The root node for this tree
6487 this.setRootNode(root);
6492 * Fires when a new child node is appended to a node in this tree.
6493 * @param {Tree} tree The owner tree
6494 * @param {Node} parent The parent node
6495 * @param {Node} node The newly appended node
6496 * @param {Number} index The index of the newly appended node
6501 * Fires when a child node is removed from a node in this tree.
6502 * @param {Tree} tree The owner tree
6503 * @param {Node} parent The parent node
6504 * @param {Node} node The child node removed
6509 * Fires when a node is moved to a new location in the tree
6510 * @param {Tree} tree The owner tree
6511 * @param {Node} node The node moved
6512 * @param {Node} oldParent The old parent of this node
6513 * @param {Node} newParent The new parent of this node
6514 * @param {Number} index The index it was moved to
6519 * Fires when a new child node is inserted in a node in this tree.
6520 * @param {Tree} tree The owner tree
6521 * @param {Node} parent The parent node
6522 * @param {Node} node The child node inserted
6523 * @param {Node} refNode The child node the node was inserted before
6527 * @event beforeappend
6528 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6529 * @param {Tree} tree The owner tree
6530 * @param {Node} parent The parent node
6531 * @param {Node} node The child node to be appended
6533 "beforeappend" : true,
6535 * @event beforeremove
6536 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6537 * @param {Tree} tree The owner tree
6538 * @param {Node} parent The parent node
6539 * @param {Node} node The child node to be removed
6541 "beforeremove" : true,
6544 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6545 * @param {Tree} tree The owner tree
6546 * @param {Node} node The node being moved
6547 * @param {Node} oldParent The parent of the node
6548 * @param {Node} newParent The new parent the node is moving to
6549 * @param {Number} index The index it is being moved to
6551 "beforemove" : true,
6553 * @event beforeinsert
6554 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6555 * @param {Tree} tree The owner tree
6556 * @param {Node} parent The parent node
6557 * @param {Node} node The child node to be inserted
6558 * @param {Node} refNode The child node the node is being inserted before
6560 "beforeinsert" : true
6563 Roo.data.Tree.superclass.constructor.call(this);
6566 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6569 proxyNodeEvent : function(){
6570 return this.fireEvent.apply(this, arguments);
6574 * Returns the root node for this tree.
6577 getRootNode : function(){
6582 * Sets the root node for this tree.
6583 * @param {Node} node
6586 setRootNode : function(node){
6588 node.ownerTree = this;
6590 this.registerNode(node);
6595 * Gets a node in this tree by its id.
6596 * @param {String} id
6599 getNodeById : function(id){
6600 return this.nodeHash[id];
6603 registerNode : function(node){
6604 this.nodeHash[node.id] = node;
6607 unregisterNode : function(node){
6608 delete this.nodeHash[node.id];
6611 toString : function(){
6612 return "[Tree"+(this.id?" "+this.id:"")+"]";
6617 * @class Roo.data.Node
6618 * @extends Roo.util.Observable
6619 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6620 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6622 * @param {Object} attributes The attributes/config for the node
6624 Roo.data.Node = function(attributes){
6626 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6629 this.attributes = attributes || {};
6630 this.leaf = this.attributes.leaf;
6632 * The node id. @type String
6634 this.id = this.attributes.id;
6636 this.id = Roo.id(null, "ynode-");
6637 this.attributes.id = this.id;
6640 * All child nodes of this node. @type Array
6642 this.childNodes = [];
6643 if(!this.childNodes.indexOf){ // indexOf is a must
6644 this.childNodes.indexOf = function(o){
6645 for(var i = 0, len = this.length; i < len; i++){
6654 * The parent node for this node. @type Node
6656 this.parentNode = null;
6658 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6660 this.firstChild = null;
6662 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6664 this.lastChild = null;
6666 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6668 this.previousSibling = null;
6670 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6672 this.nextSibling = null;
6677 * Fires when a new child node is appended
6678 * @param {Tree} tree The owner tree
6679 * @param {Node} this This node
6680 * @param {Node} node The newly appended node
6681 * @param {Number} index The index of the newly appended node
6686 * Fires when a child node is removed
6687 * @param {Tree} tree The owner tree
6688 * @param {Node} this This node
6689 * @param {Node} node The removed node
6694 * Fires when this node is moved to a new location in the tree
6695 * @param {Tree} tree The owner tree
6696 * @param {Node} this This node
6697 * @param {Node} oldParent The old parent of this node
6698 * @param {Node} newParent The new parent of this node
6699 * @param {Number} index The index it was moved to
6704 * Fires when a new child node is inserted.
6705 * @param {Tree} tree The owner tree
6706 * @param {Node} this This node
6707 * @param {Node} node The child node inserted
6708 * @param {Node} refNode The child node the node was inserted before
6712 * @event beforeappend
6713 * Fires before a new child is appended, return false to cancel the append.
6714 * @param {Tree} tree The owner tree
6715 * @param {Node} this This node
6716 * @param {Node} node The child node to be appended
6718 "beforeappend" : true,
6720 * @event beforeremove
6721 * Fires before a child is removed, return false to cancel the remove.
6722 * @param {Tree} tree The owner tree
6723 * @param {Node} this This node
6724 * @param {Node} node The child node to be removed
6726 "beforeremove" : true,
6729 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6730 * @param {Tree} tree The owner tree
6731 * @param {Node} this This node
6732 * @param {Node} oldParent The parent of this node
6733 * @param {Node} newParent The new parent this node is moving to
6734 * @param {Number} index The index it is being moved to
6736 "beforemove" : true,
6738 * @event beforeinsert
6739 * Fires before a new child is inserted, return false to cancel the insert.
6740 * @param {Tree} tree The owner tree
6741 * @param {Node} this This node
6742 * @param {Node} node The child node to be inserted
6743 * @param {Node} refNode The child node the node is being inserted before
6745 "beforeinsert" : true
6747 this.listeners = this.attributes.listeners;
6748 Roo.data.Node.superclass.constructor.call(this);
6751 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6752 fireEvent : function(evtName){
6753 // first do standard event for this node
6754 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6757 // then bubble it up to the tree if the event wasn't cancelled
6758 var ot = this.getOwnerTree();
6760 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6768 * Returns true if this node is a leaf
6771 isLeaf : function(){
6772 return this.leaf === true;
6776 setFirstChild : function(node){
6777 this.firstChild = node;
6781 setLastChild : function(node){
6782 this.lastChild = node;
6787 * Returns true if this node is the last child of its parent
6790 isLast : function(){
6791 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6795 * Returns true if this node is the first child of its parent
6798 isFirst : function(){
6799 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6802 hasChildNodes : function(){
6803 return !this.isLeaf() && this.childNodes.length > 0;
6807 * Insert node(s) as the last child node of this node.
6808 * @param {Node/Array} node The node or Array of nodes to append
6809 * @return {Node} The appended node if single append, or null if an array was passed
6811 appendChild : function(node){
6813 if(node instanceof Array){
6815 }else if(arguments.length > 1){
6818 // if passed an array or multiple args do them one by one
6820 for(var i = 0, len = multi.length; i < len; i++) {
6821 this.appendChild(multi[i]);
6824 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6827 var index = this.childNodes.length;
6828 var oldParent = node.parentNode;
6829 // it's a move, make sure we move it cleanly
6831 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6834 oldParent.removeChild(node);
6836 index = this.childNodes.length;
6838 this.setFirstChild(node);
6840 this.childNodes.push(node);
6841 node.parentNode = this;
6842 var ps = this.childNodes[index-1];
6844 node.previousSibling = ps;
6845 ps.nextSibling = node;
6847 node.previousSibling = null;
6849 node.nextSibling = null;
6850 this.setLastChild(node);
6851 node.setOwnerTree(this.getOwnerTree());
6852 this.fireEvent("append", this.ownerTree, this, node, index);
6854 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6861 * Removes a child node from this node.
6862 * @param {Node} node The node to remove
6863 * @return {Node} The removed node
6865 removeChild : function(node){
6866 var index = this.childNodes.indexOf(node);
6870 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6874 // remove it from childNodes collection
6875 this.childNodes.splice(index, 1);
6878 if(node.previousSibling){
6879 node.previousSibling.nextSibling = node.nextSibling;
6881 if(node.nextSibling){
6882 node.nextSibling.previousSibling = node.previousSibling;
6885 // update child refs
6886 if(this.firstChild == node){
6887 this.setFirstChild(node.nextSibling);
6889 if(this.lastChild == node){
6890 this.setLastChild(node.previousSibling);
6893 node.setOwnerTree(null);
6894 // clear any references from the node
6895 node.parentNode = null;
6896 node.previousSibling = null;
6897 node.nextSibling = null;
6898 this.fireEvent("remove", this.ownerTree, this, node);
6903 * Inserts the first node before the second node in this nodes childNodes collection.
6904 * @param {Node} node The node to insert
6905 * @param {Node} refNode The node to insert before (if null the node is appended)
6906 * @return {Node} The inserted node
6908 insertBefore : function(node, refNode){
6909 if(!refNode){ // like standard Dom, refNode can be null for append
6910 return this.appendChild(node);
6913 if(node == refNode){
6917 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6920 var index = this.childNodes.indexOf(refNode);
6921 var oldParent = node.parentNode;
6922 var refIndex = index;
6924 // when moving internally, indexes will change after remove
6925 if(oldParent == this && this.childNodes.indexOf(node) < index){
6929 // it's a move, make sure we move it cleanly
6931 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6934 oldParent.removeChild(node);
6937 this.setFirstChild(node);
6939 this.childNodes.splice(refIndex, 0, node);
6940 node.parentNode = this;
6941 var ps = this.childNodes[refIndex-1];
6943 node.previousSibling = ps;
6944 ps.nextSibling = node;
6946 node.previousSibling = null;
6948 node.nextSibling = refNode;
6949 refNode.previousSibling = node;
6950 node.setOwnerTree(this.getOwnerTree());
6951 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6953 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6959 * Returns the child node at the specified index.
6960 * @param {Number} index
6963 item : function(index){
6964 return this.childNodes[index];
6968 * Replaces one child node in this node with another.
6969 * @param {Node} newChild The replacement node
6970 * @param {Node} oldChild The node to replace
6971 * @return {Node} The replaced node
6973 replaceChild : function(newChild, oldChild){
6974 this.insertBefore(newChild, oldChild);
6975 this.removeChild(oldChild);
6980 * Returns the index of a child node
6981 * @param {Node} node
6982 * @return {Number} The index of the node or -1 if it was not found
6984 indexOf : function(child){
6985 return this.childNodes.indexOf(child);
6989 * Returns the tree this node is in.
6992 getOwnerTree : function(){
6993 // if it doesn't have one, look for one
6994 if(!this.ownerTree){
6998 this.ownerTree = p.ownerTree;
7004 return this.ownerTree;
7008 * Returns depth of this node (the root node has a depth of 0)
7011 getDepth : function(){
7014 while(p.parentNode){
7022 setOwnerTree : function(tree){
7023 // if it's move, we need to update everyone
7024 if(tree != this.ownerTree){
7026 this.ownerTree.unregisterNode(this);
7028 this.ownerTree = tree;
7029 var cs = this.childNodes;
7030 for(var i = 0, len = cs.length; i < len; i++) {
7031 cs[i].setOwnerTree(tree);
7034 tree.registerNode(this);
7040 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7041 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7042 * @return {String} The path
7044 getPath : function(attr){
7045 attr = attr || "id";
7046 var p = this.parentNode;
7047 var b = [this.attributes[attr]];
7049 b.unshift(p.attributes[attr]);
7052 var sep = this.getOwnerTree().pathSeparator;
7053 return sep + b.join(sep);
7057 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7058 * function call will be the scope provided or the current node. The arguments to the function
7059 * will be the args provided or the current node. If the function returns false at any point,
7060 * the bubble is stopped.
7061 * @param {Function} fn The function to call
7062 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7063 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7065 bubble : function(fn, scope, args){
7068 if(fn.call(scope || p, args || p) === false){
7076 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7077 * function call will be the scope provided or the current node. The arguments to the function
7078 * will be the args provided or the current node. If the function returns false at any point,
7079 * the cascade is stopped on that branch.
7080 * @param {Function} fn The function to call
7081 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7082 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7084 cascade : function(fn, scope, args){
7085 if(fn.call(scope || this, args || this) !== false){
7086 var cs = this.childNodes;
7087 for(var i = 0, len = cs.length; i < len; i++) {
7088 cs[i].cascade(fn, scope, args);
7094 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7095 * function call will be the scope provided or the current node. The arguments to the function
7096 * will be the args provided or the current node. If the function returns false at any point,
7097 * the iteration stops.
7098 * @param {Function} fn The function to call
7099 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7100 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7102 eachChild : function(fn, scope, args){
7103 var cs = this.childNodes;
7104 for(var i = 0, len = cs.length; i < len; i++) {
7105 if(fn.call(scope || this, args || cs[i]) === false){
7112 * Finds the first child that has the attribute with the specified value.
7113 * @param {String} attribute The attribute name
7114 * @param {Mixed} value The value to search for
7115 * @return {Node} The found child or null if none was found
7117 findChild : function(attribute, value){
7118 var cs = this.childNodes;
7119 for(var i = 0, len = cs.length; i < len; i++) {
7120 if(cs[i].attributes[attribute] == value){
7128 * Finds the first child by a custom function. The child matches if the function passed
7130 * @param {Function} fn
7131 * @param {Object} scope (optional)
7132 * @return {Node} The found child or null if none was found
7134 findChildBy : function(fn, scope){
7135 var cs = this.childNodes;
7136 for(var i = 0, len = cs.length; i < len; i++) {
7137 if(fn.call(scope||cs[i], cs[i]) === true){
7145 * Sorts this nodes children using the supplied sort function
7146 * @param {Function} fn
7147 * @param {Object} scope (optional)
7149 sort : function(fn, scope){
7150 var cs = this.childNodes;
7151 var len = cs.length;
7153 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7155 for(var i = 0; i < len; i++){
7157 n.previousSibling = cs[i-1];
7158 n.nextSibling = cs[i+1];
7160 this.setFirstChild(n);
7163 this.setLastChild(n);
7170 * Returns true if this node is an ancestor (at any point) of the passed node.
7171 * @param {Node} node
7174 contains : function(node){
7175 return node.isAncestor(this);
7179 * Returns true if the passed node is an ancestor (at any point) of this node.
7180 * @param {Node} node
7183 isAncestor : function(node){
7184 var p = this.parentNode;
7194 toString : function(){
7195 return "[Node"+(this.id?" "+this.id:"")+"]";
7199 * Ext JS Library 1.1.1
7200 * Copyright(c) 2006-2007, Ext JS, LLC.
7202 * Originally Released Under LGPL - original licence link has changed is not relivant.
7205 * <script type="text/javascript">
7210 * @class Roo.ComponentMgr
7211 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7214 Roo.ComponentMgr = function(){
7215 var all = new Roo.util.MixedCollection();
7219 * Registers a component.
7220 * @param {Roo.Component} c The component
7222 register : function(c){
7227 * Unregisters a component.
7228 * @param {Roo.Component} c The component
7230 unregister : function(c){
7235 * Returns a component by id
7236 * @param {String} id The component id
7243 * Registers a function that will be called when a specified component is added to ComponentMgr
7244 * @param {String} id The component id
7245 * @param {Funtction} fn The callback function
7246 * @param {Object} scope The scope of the callback
7248 onAvailable : function(id, fn, scope){
7249 all.on("add", function(index, o){
7251 fn.call(scope || o, o);
7252 all.un("add", fn, scope);
7259 * Ext JS Library 1.1.1
7260 * Copyright(c) 2006-2007, Ext JS, LLC.
7262 * Originally Released Under LGPL - original licence link has changed is not relivant.
7265 * <script type="text/javascript">
7269 * @class Roo.Component
7270 * @extends Roo.util.Observable
7271 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7272 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7273 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7274 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7275 * All visual components (widgets) that require rendering into a layout should subclass Component.
7277 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7278 * 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
7279 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7281 Roo.Component = function(config){
7282 config = config || {};
7283 if(config.tagName || config.dom || typeof config == "string"){ // element object
7284 config = {el: config, id: config.id || config};
7286 this.initialConfig = config;
7288 Roo.apply(this, config);
7292 * Fires after the component is disabled.
7293 * @param {Roo.Component} this
7298 * Fires after the component is enabled.
7299 * @param {Roo.Component} this
7304 * Fires before the component is shown. Return false to stop the show.
7305 * @param {Roo.Component} this
7310 * Fires after the component is shown.
7311 * @param {Roo.Component} this
7316 * Fires before the component is hidden. Return false to stop the hide.
7317 * @param {Roo.Component} this
7322 * Fires after the component is hidden.
7323 * @param {Roo.Component} this
7327 * @event beforerender
7328 * Fires before the component is rendered. Return false to stop the render.
7329 * @param {Roo.Component} this
7331 beforerender : true,
7334 * Fires after the component is rendered.
7335 * @param {Roo.Component} this
7339 * @event beforedestroy
7340 * Fires before the component is destroyed. Return false to stop the destroy.
7341 * @param {Roo.Component} this
7343 beforedestroy : true,
7346 * Fires after the component is destroyed.
7347 * @param {Roo.Component} this
7352 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7354 Roo.ComponentMgr.register(this);
7355 Roo.Component.superclass.constructor.call(this);
7356 this.initComponent();
7357 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7358 this.render(this.renderTo);
7359 delete this.renderTo;
7364 Roo.Component.AUTO_ID = 1000;
7366 Roo.extend(Roo.Component, Roo.util.Observable, {
7368 * @property {Boolean} hidden
7369 * true if this component is hidden. Read-only.
7373 * true if this component is disabled. Read-only.
7377 * true if this component has been rendered. Read-only.
7381 /** @cfg {String} disableClass
7382 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7384 disabledClass : "x-item-disabled",
7385 /** @cfg {Boolean} allowDomMove
7386 * Whether the component can move the Dom node when rendering (defaults to true).
7388 allowDomMove : true,
7389 /** @cfg {String} hideMode
7390 * How this component should hidden. Supported values are
7391 * "visibility" (css visibility), "offsets" (negative offset position) and
7392 * "display" (css display) - defaults to "display".
7394 hideMode: 'display',
7397 ctype : "Roo.Component",
7399 /** @cfg {String} actionMode
7400 * which property holds the element that used for hide() / show() / disable() / enable()
7406 getActionEl : function(){
7407 return this[this.actionMode];
7410 initComponent : Roo.emptyFn,
7412 * If this is a lazy rendering component, render it to its container element.
7413 * @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.
7415 render : function(container, position){
7416 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7417 if(!container && this.el){
7418 this.el = Roo.get(this.el);
7419 container = this.el.dom.parentNode;
7420 this.allowDomMove = false;
7422 this.container = Roo.get(container);
7423 this.rendered = true;
7424 if(position !== undefined){
7425 if(typeof position == 'number'){
7426 position = this.container.dom.childNodes[position];
7428 position = Roo.getDom(position);
7431 this.onRender(this.container, position || null);
7433 this.el.addClass(this.cls);
7437 this.el.applyStyles(this.style);
7440 this.fireEvent("render", this);
7441 this.afterRender(this.container);
7453 // default function is not really useful
7454 onRender : function(ct, position){
7456 this.el = Roo.get(this.el);
7457 if(this.allowDomMove !== false){
7458 ct.dom.insertBefore(this.el.dom, position);
7464 getAutoCreate : function(){
7465 var cfg = typeof this.autoCreate == "object" ?
7466 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7467 if(this.id && !cfg.id){
7474 afterRender : Roo.emptyFn,
7477 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7478 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7480 destroy : function(){
7481 if(this.fireEvent("beforedestroy", this) !== false){
7482 this.purgeListeners();
7483 this.beforeDestroy();
7485 this.el.removeAllListeners();
7487 if(this.actionMode == "container"){
7488 this.container.remove();
7492 Roo.ComponentMgr.unregister(this);
7493 this.fireEvent("destroy", this);
7498 beforeDestroy : function(){
7503 onDestroy : function(){
7508 * Returns the underlying {@link Roo.Element}.
7509 * @return {Roo.Element} The element
7516 * Returns the id of this component.
7524 * Try to focus this component.
7525 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7526 * @return {Roo.Component} this
7528 focus : function(selectText){
7531 if(selectText === true){
7532 this.el.dom.select();
7547 * Disable this component.
7548 * @return {Roo.Component} this
7550 disable : function(){
7554 this.disabled = true;
7555 this.fireEvent("disable", this);
7560 onDisable : function(){
7561 this.getActionEl().addClass(this.disabledClass);
7562 this.el.dom.disabled = true;
7566 * Enable this component.
7567 * @return {Roo.Component} this
7569 enable : function(){
7573 this.disabled = false;
7574 this.fireEvent("enable", this);
7579 onEnable : function(){
7580 this.getActionEl().removeClass(this.disabledClass);
7581 this.el.dom.disabled = false;
7585 * Convenience function for setting disabled/enabled by boolean.
7586 * @param {Boolean} disabled
7588 setDisabled : function(disabled){
7589 this[disabled ? "disable" : "enable"]();
7593 * Show this component.
7594 * @return {Roo.Component} this
7597 if(this.fireEvent("beforeshow", this) !== false){
7598 this.hidden = false;
7602 this.fireEvent("show", this);
7608 onShow : function(){
7609 var ae = this.getActionEl();
7610 if(this.hideMode == 'visibility'){
7611 ae.dom.style.visibility = "visible";
7612 }else if(this.hideMode == 'offsets'){
7613 ae.removeClass('x-hidden');
7615 ae.dom.style.display = "";
7620 * Hide this component.
7621 * @return {Roo.Component} this
7624 if(this.fireEvent("beforehide", this) !== false){
7629 this.fireEvent("hide", this);
7635 onHide : function(){
7636 var ae = this.getActionEl();
7637 if(this.hideMode == 'visibility'){
7638 ae.dom.style.visibility = "hidden";
7639 }else if(this.hideMode == 'offsets'){
7640 ae.addClass('x-hidden');
7642 ae.dom.style.display = "none";
7647 * Convenience function to hide or show this component by boolean.
7648 * @param {Boolean} visible True to show, false to hide
7649 * @return {Roo.Component} this
7651 setVisible: function(visible){
7661 * Returns true if this component is visible.
7663 isVisible : function(){
7664 return this.getActionEl().isVisible();
7667 cloneConfig : function(overrides){
7668 overrides = overrides || {};
7669 var id = overrides.id || Roo.id();
7670 var cfg = Roo.applyIf(overrides, this.initialConfig);
7671 cfg.id = id; // prevent dup id
7672 return new this.constructor(cfg);
7676 * Ext JS Library 1.1.1
7677 * Copyright(c) 2006-2007, Ext JS, LLC.
7679 * Originally Released Under LGPL - original licence link has changed is not relivant.
7682 * <script type="text/javascript">
7687 * @extends Roo.Element
7688 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7689 * automatic maintaining of shadow/shim positions.
7690 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7691 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7692 * you can pass a string with a CSS class name. False turns off the shadow.
7693 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7694 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7695 * @cfg {String} cls CSS class to add to the element
7696 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7697 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7699 * @param {Object} config An object with config options.
7700 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7703 Roo.Layer = function(config, existingEl){
7704 config = config || {};
7705 var dh = Roo.DomHelper;
7706 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7708 this.dom = Roo.getDom(existingEl);
7711 var o = config.dh || {tag: "div", cls: "x-layer"};
7712 this.dom = dh.append(pel, o);
7715 this.addClass(config.cls);
7717 this.constrain = config.constrain !== false;
7718 this.visibilityMode = Roo.Element.VISIBILITY;
7720 this.id = this.dom.id = config.id;
7722 this.id = Roo.id(this.dom);
7724 this.zindex = config.zindex || this.getZIndex();
7725 this.position("absolute", this.zindex);
7727 this.shadowOffset = config.shadowOffset || 4;
7728 this.shadow = new Roo.Shadow({
7729 offset : this.shadowOffset,
7730 mode : config.shadow
7733 this.shadowOffset = 0;
7735 this.useShim = config.shim !== false && Roo.useShims;
7736 this.useDisplay = config.useDisplay;
7740 var supr = Roo.Element.prototype;
7742 // shims are shared among layer to keep from having 100 iframes
7745 Roo.extend(Roo.Layer, Roo.Element, {
7747 getZIndex : function(){
7748 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7751 getShim : function(){
7758 var shim = shims.shift();
7760 shim = this.createShim();
7761 shim.enableDisplayMode('block');
7762 shim.dom.style.display = 'none';
7763 shim.dom.style.visibility = 'visible';
7765 var pn = this.dom.parentNode;
7766 if(shim.dom.parentNode != pn){
7767 pn.insertBefore(shim.dom, this.dom);
7769 shim.setStyle('z-index', this.getZIndex()-2);
7774 hideShim : function(){
7776 this.shim.setDisplayed(false);
7777 shims.push(this.shim);
7782 disableShadow : function(){
7784 this.shadowDisabled = true;
7786 this.lastShadowOffset = this.shadowOffset;
7787 this.shadowOffset = 0;
7791 enableShadow : function(show){
7793 this.shadowDisabled = false;
7794 this.shadowOffset = this.lastShadowOffset;
7795 delete this.lastShadowOffset;
7803 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7804 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7805 sync : function(doShow){
7806 var sw = this.shadow;
7807 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7808 var sh = this.getShim();
7810 var w = this.getWidth(),
7811 h = this.getHeight();
7813 var l = this.getLeft(true),
7814 t = this.getTop(true);
7816 if(sw && !this.shadowDisabled){
7817 if(doShow && !sw.isVisible()){
7820 sw.realign(l, t, w, h);
7826 // fit the shim behind the shadow, so it is shimmed too
7827 var a = sw.adjusts, s = sh.dom.style;
7828 s.left = (Math.min(l, l+a.l))+"px";
7829 s.top = (Math.min(t, t+a.t))+"px";
7830 s.width = (w+a.w)+"px";
7831 s.height = (h+a.h)+"px";
7838 sh.setLeftTop(l, t);
7845 destroy : function(){
7850 this.removeAllListeners();
7851 var pn = this.dom.parentNode;
7853 pn.removeChild(this.dom);
7855 Roo.Element.uncache(this.id);
7858 remove : function(){
7863 beginUpdate : function(){
7864 this.updating = true;
7868 endUpdate : function(){
7869 this.updating = false;
7874 hideUnders : function(negOffset){
7882 constrainXY : function(){
7884 var vw = Roo.lib.Dom.getViewWidth(),
7885 vh = Roo.lib.Dom.getViewHeight();
7886 var s = Roo.get(document).getScroll();
7888 var xy = this.getXY();
7889 var x = xy[0], y = xy[1];
7890 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7891 // only move it if it needs it
7893 // first validate right/bottom
7894 if((x + w) > vw+s.left){
7895 x = vw - w - this.shadowOffset;
7898 if((y + h) > vh+s.top){
7899 y = vh - h - this.shadowOffset;
7902 // then make sure top/left isn't negative
7913 var ay = this.avoidY;
7914 if(y <= ay && (y+h) >= ay){
7920 supr.setXY.call(this, xy);
7926 isVisible : function(){
7927 return this.visible;
7931 showAction : function(){
7932 this.visible = true; // track visibility to prevent getStyle calls
7933 if(this.useDisplay === true){
7934 this.setDisplayed("");
7935 }else if(this.lastXY){
7936 supr.setXY.call(this, this.lastXY);
7937 }else if(this.lastLT){
7938 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7943 hideAction : function(){
7944 this.visible = false;
7945 if(this.useDisplay === true){
7946 this.setDisplayed(false);
7948 this.setLeftTop(-10000,-10000);
7952 // overridden Element method
7953 setVisible : function(v, a, d, c, e){
7958 var cb = function(){
7963 }.createDelegate(this);
7964 supr.setVisible.call(this, true, true, d, cb, e);
7967 this.hideUnders(true);
7976 }.createDelegate(this);
7978 supr.setVisible.call(this, v, a, d, cb, e);
7987 storeXY : function(xy){
7992 storeLeftTop : function(left, top){
7994 this.lastLT = [left, top];
7998 beforeFx : function(){
7999 this.beforeAction();
8000 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8004 afterFx : function(){
8005 Roo.Layer.superclass.afterFx.apply(this, arguments);
8006 this.sync(this.isVisible());
8010 beforeAction : function(){
8011 if(!this.updating && this.shadow){
8016 // overridden Element method
8017 setLeft : function(left){
8018 this.storeLeftTop(left, this.getTop(true));
8019 supr.setLeft.apply(this, arguments);
8023 setTop : function(top){
8024 this.storeLeftTop(this.getLeft(true), top);
8025 supr.setTop.apply(this, arguments);
8029 setLeftTop : function(left, top){
8030 this.storeLeftTop(left, top);
8031 supr.setLeftTop.apply(this, arguments);
8035 setXY : function(xy, a, d, c, e){
8037 this.beforeAction();
8039 var cb = this.createCB(c);
8040 supr.setXY.call(this, xy, a, d, cb, e);
8047 createCB : function(c){
8058 // overridden Element method
8059 setX : function(x, a, d, c, e){
8060 this.setXY([x, this.getY()], a, d, c, e);
8063 // overridden Element method
8064 setY : function(y, a, d, c, e){
8065 this.setXY([this.getX(), y], a, d, c, e);
8068 // overridden Element method
8069 setSize : function(w, h, a, d, c, e){
8070 this.beforeAction();
8071 var cb = this.createCB(c);
8072 supr.setSize.call(this, w, h, a, d, cb, e);
8078 // overridden Element method
8079 setWidth : function(w, a, d, c, e){
8080 this.beforeAction();
8081 var cb = this.createCB(c);
8082 supr.setWidth.call(this, w, a, d, cb, e);
8088 // overridden Element method
8089 setHeight : function(h, a, d, c, e){
8090 this.beforeAction();
8091 var cb = this.createCB(c);
8092 supr.setHeight.call(this, h, a, d, cb, e);
8098 // overridden Element method
8099 setBounds : function(x, y, w, h, a, d, c, e){
8100 this.beforeAction();
8101 var cb = this.createCB(c);
8103 this.storeXY([x, y]);
8104 supr.setXY.call(this, [x, y]);
8105 supr.setSize.call(this, w, h, a, d, cb, e);
8108 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8114 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8115 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8116 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8117 * @param {Number} zindex The new z-index to set
8118 * @return {this} The Layer
8120 setZIndex : function(zindex){
8121 this.zindex = zindex;
8122 this.setStyle("z-index", zindex + 2);
8124 this.shadow.setZIndex(zindex + 1);
8127 this.shim.setStyle("z-index", zindex);
8133 * Ext JS Library 1.1.1
8134 * Copyright(c) 2006-2007, Ext JS, LLC.
8136 * Originally Released Under LGPL - original licence link has changed is not relivant.
8139 * <script type="text/javascript">
8145 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8146 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8147 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8149 * Create a new Shadow
8150 * @param {Object} config The config object
8152 Roo.Shadow = function(config){
8153 Roo.apply(this, config);
8154 if(typeof this.mode != "string"){
8155 this.mode = this.defaultMode;
8157 var o = this.offset, a = {h: 0};
8158 var rad = Math.floor(this.offset/2);
8159 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8165 a.l -= this.offset + rad;
8166 a.t -= this.offset + rad;
8177 a.l -= (this.offset - rad);
8178 a.t -= this.offset + rad;
8180 a.w -= (this.offset - rad)*2;
8191 a.l -= (this.offset - rad);
8192 a.t -= (this.offset - rad);
8194 a.w -= (this.offset + rad + 1);
8195 a.h -= (this.offset + rad);
8204 Roo.Shadow.prototype = {
8206 * @cfg {String} mode
8207 * The shadow display mode. Supports the following options:<br />
8208 * sides: Shadow displays on both sides and bottom only<br />
8209 * frame: Shadow displays equally on all four sides<br />
8210 * drop: Traditional bottom-right drop shadow (default)
8213 * @cfg {String} offset
8214 * The number of pixels to offset the shadow from the element (defaults to 4)
8219 defaultMode: "drop",
8222 * Displays the shadow under the target element
8223 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8225 show : function(target){
8226 target = Roo.get(target);
8228 this.el = Roo.Shadow.Pool.pull();
8229 if(this.el.dom.nextSibling != target.dom){
8230 this.el.insertBefore(target);
8233 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8235 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8238 target.getLeft(true),
8239 target.getTop(true),
8243 this.el.dom.style.display = "block";
8247 * Returns true if the shadow is visible, else false
8249 isVisible : function(){
8250 return this.el ? true : false;
8254 * Direct alignment when values are already available. Show must be called at least once before
8255 * calling this method to ensure it is initialized.
8256 * @param {Number} left The target element left position
8257 * @param {Number} top The target element top position
8258 * @param {Number} width The target element width
8259 * @param {Number} height The target element height
8261 realign : function(l, t, w, h){
8265 var a = this.adjusts, d = this.el.dom, s = d.style;
8267 s.left = (l+a.l)+"px";
8268 s.top = (t+a.t)+"px";
8269 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8271 if(s.width != sws || s.height != shs){
8275 var cn = d.childNodes;
8276 var sww = Math.max(0, (sw-12))+"px";
8277 cn[0].childNodes[1].style.width = sww;
8278 cn[1].childNodes[1].style.width = sww;
8279 cn[2].childNodes[1].style.width = sww;
8280 cn[1].style.height = Math.max(0, (sh-12))+"px";
8290 this.el.dom.style.display = "none";
8291 Roo.Shadow.Pool.push(this.el);
8297 * Adjust the z-index of this shadow
8298 * @param {Number} zindex The new z-index
8300 setZIndex : function(z){
8303 this.el.setStyle("z-index", z);
8308 // Private utility class that manages the internal Shadow cache
8309 Roo.Shadow.Pool = function(){
8311 var markup = Roo.isIE ?
8312 '<div class="x-ie-shadow"></div>' :
8313 '<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>';
8318 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8319 sh.autoBoxAdjust = false;
8324 push : function(sh){
8330 * Ext JS Library 1.1.1
8331 * Copyright(c) 2006-2007, Ext JS, LLC.
8333 * Originally Released Under LGPL - original licence link has changed is not relivant.
8336 * <script type="text/javascript">
8340 * @class Roo.BoxComponent
8341 * @extends Roo.Component
8342 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8343 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8344 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8345 * layout containers.
8347 * @param {Roo.Element/String/Object} config The configuration options.
8349 Roo.BoxComponent = function(config){
8350 Roo.Component.call(this, config);
8354 * Fires after the component is resized.
8355 * @param {Roo.Component} this
8356 * @param {Number} adjWidth The box-adjusted width that was set
8357 * @param {Number} adjHeight The box-adjusted height that was set
8358 * @param {Number} rawWidth The width that was originally specified
8359 * @param {Number} rawHeight The height that was originally specified
8364 * Fires after the component is moved.
8365 * @param {Roo.Component} this
8366 * @param {Number} x The new x position
8367 * @param {Number} y The new y position
8373 Roo.extend(Roo.BoxComponent, Roo.Component, {
8374 // private, set in afterRender to signify that the component has been rendered
8376 // private, used to defer height settings to subclasses
8378 /** @cfg {Number} width
8379 * width (optional) size of component
8381 /** @cfg {Number} height
8382 * height (optional) size of component
8386 * Sets the width and height of the component. This method fires the resize event. This method can accept
8387 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8388 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8389 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8390 * @return {Roo.BoxComponent} this
8392 setSize : function(w, h){
8393 // support for standard size objects
8394 if(typeof w == 'object'){
8405 // prevent recalcs when not needed
8406 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8409 this.lastSize = {width: w, height: h};
8411 var adj = this.adjustSize(w, h);
8412 var aw = adj.width, ah = adj.height;
8413 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8414 var rz = this.getResizeEl();
8415 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8417 }else if(!this.deferHeight && ah !== undefined){
8419 }else if(aw !== undefined){
8422 this.onResize(aw, ah, w, h);
8423 this.fireEvent('resize', this, aw, ah, w, h);
8429 * Gets the current size of the component's underlying element.
8430 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8432 getSize : function(){
8433 return this.el.getSize();
8437 * Gets the current XY position of the component's underlying element.
8438 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8439 * @return {Array} The XY position of the element (e.g., [100, 200])
8441 getPosition : function(local){
8443 return [this.el.getLeft(true), this.el.getTop(true)];
8445 return this.xy || this.el.getXY();
8449 * Gets the current box measurements of the component's underlying element.
8450 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8451 * @returns {Object} box An object in the format {x, y, width, height}
8453 getBox : function(local){
8454 var s = this.el.getSize();
8456 s.x = this.el.getLeft(true);
8457 s.y = this.el.getTop(true);
8459 var xy = this.xy || this.el.getXY();
8467 * Sets the current box measurements of the component's underlying element.
8468 * @param {Object} box An object in the format {x, y, width, height}
8469 * @returns {Roo.BoxComponent} this
8471 updateBox : function(box){
8472 this.setSize(box.width, box.height);
8473 this.setPagePosition(box.x, box.y);
8478 getResizeEl : function(){
8479 return this.resizeEl || this.el;
8483 getPositionEl : function(){
8484 return this.positionEl || this.el;
8488 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8489 * This method fires the move event.
8490 * @param {Number} left The new left
8491 * @param {Number} top The new top
8492 * @returns {Roo.BoxComponent} this
8494 setPosition : function(x, y){
8500 var adj = this.adjustPosition(x, y);
8501 var ax = adj.x, ay = adj.y;
8503 var el = this.getPositionEl();
8504 if(ax !== undefined || ay !== undefined){
8505 if(ax !== undefined && ay !== undefined){
8506 el.setLeftTop(ax, ay);
8507 }else if(ax !== undefined){
8509 }else if(ay !== undefined){
8512 this.onPosition(ax, ay);
8513 this.fireEvent('move', this, ax, ay);
8519 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8520 * This method fires the move event.
8521 * @param {Number} x The new x position
8522 * @param {Number} y The new y position
8523 * @returns {Roo.BoxComponent} this
8525 setPagePosition : function(x, y){
8531 if(x === undefined || y === undefined){ // cannot translate undefined points
8534 var p = this.el.translatePoints(x, y);
8535 this.setPosition(p.left, p.top);
8540 onRender : function(ct, position){
8541 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8543 this.resizeEl = Roo.get(this.resizeEl);
8545 if(this.positionEl){
8546 this.positionEl = Roo.get(this.positionEl);
8551 afterRender : function(){
8552 Roo.BoxComponent.superclass.afterRender.call(this);
8553 this.boxReady = true;
8554 this.setSize(this.width, this.height);
8555 if(this.x || this.y){
8556 this.setPosition(this.x, this.y);
8558 if(this.pageX || this.pageY){
8559 this.setPagePosition(this.pageX, this.pageY);
8564 * Force the component's size to recalculate based on the underlying element's current height and width.
8565 * @returns {Roo.BoxComponent} this
8567 syncSize : function(){
8568 delete this.lastSize;
8569 this.setSize(this.el.getWidth(), this.el.getHeight());
8574 * Called after the component is resized, this method is empty by default but can be implemented by any
8575 * subclass that needs to perform custom logic after a resize occurs.
8576 * @param {Number} adjWidth The box-adjusted width that was set
8577 * @param {Number} adjHeight The box-adjusted height that was set
8578 * @param {Number} rawWidth The width that was originally specified
8579 * @param {Number} rawHeight The height that was originally specified
8581 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8586 * Called after the component is moved, this method is empty by default but can be implemented by any
8587 * subclass that needs to perform custom logic after a move occurs.
8588 * @param {Number} x The new x position
8589 * @param {Number} y The new y position
8591 onPosition : function(x, y){
8596 adjustSize : function(w, h){
8600 if(this.autoHeight){
8603 return {width : w, height: h};
8607 adjustPosition : function(x, y){
8608 return {x : x, y: y};
8612 * Ext JS Library 1.1.1
8613 * Copyright(c) 2006-2007, Ext JS, LLC.
8615 * Originally Released Under LGPL - original licence link has changed is not relivant.
8618 * <script type="text/javascript">
8623 * @class Roo.SplitBar
8624 * @extends Roo.util.Observable
8625 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8629 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8630 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8631 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8632 split.minSize = 100;
8633 split.maxSize = 600;
8634 split.animate = true;
8635 split.on('moved', splitterMoved);
8638 * Create a new SplitBar
8639 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8640 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8641 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8642 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8643 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8644 position of the SplitBar).
8646 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8649 this.el = Roo.get(dragElement, true);
8650 this.el.dom.unselectable = "on";
8652 this.resizingEl = Roo.get(resizingElement, true);
8656 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8657 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8660 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8663 * The minimum size of the resizing element. (Defaults to 0)
8669 * The maximum size of the resizing element. (Defaults to 2000)
8672 this.maxSize = 2000;
8675 * Whether to animate the transition to the new size
8678 this.animate = false;
8681 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8684 this.useShim = false;
8691 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8693 this.proxy = Roo.get(existingProxy).dom;
8696 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8699 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8702 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8705 this.dragSpecs = {};
8708 * @private The adapter to use to positon and resize elements
8710 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8711 this.adapter.init(this);
8713 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8715 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8716 this.el.addClass("x-splitbar-h");
8719 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8720 this.el.addClass("x-splitbar-v");
8726 * Fires when the splitter is moved (alias for {@link #event-moved})
8727 * @param {Roo.SplitBar} this
8728 * @param {Number} newSize the new width or height
8733 * Fires when the splitter is moved
8734 * @param {Roo.SplitBar} this
8735 * @param {Number} newSize the new width or height
8739 * @event beforeresize
8740 * Fires before the splitter is dragged
8741 * @param {Roo.SplitBar} this
8743 "beforeresize" : true,
8745 "beforeapply" : true
8748 Roo.util.Observable.call(this);
8751 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8752 onStartProxyDrag : function(x, y){
8753 this.fireEvent("beforeresize", this);
8755 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8757 o.enableDisplayMode("block");
8758 // all splitbars share the same overlay
8759 Roo.SplitBar.prototype.overlay = o;
8761 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8762 this.overlay.show();
8763 Roo.get(this.proxy).setDisplayed("block");
8764 var size = this.adapter.getElementSize(this);
8765 this.activeMinSize = this.getMinimumSize();;
8766 this.activeMaxSize = this.getMaximumSize();;
8767 var c1 = size - this.activeMinSize;
8768 var c2 = Math.max(this.activeMaxSize - size, 0);
8769 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8770 this.dd.resetConstraints();
8771 this.dd.setXConstraint(
8772 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8773 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8775 this.dd.setYConstraint(0, 0);
8777 this.dd.resetConstraints();
8778 this.dd.setXConstraint(0, 0);
8779 this.dd.setYConstraint(
8780 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8781 this.placement == Roo.SplitBar.TOP ? c2 : c1
8784 this.dragSpecs.startSize = size;
8785 this.dragSpecs.startPoint = [x, y];
8786 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8790 * @private Called after the drag operation by the DDProxy
8792 onEndProxyDrag : function(e){
8793 Roo.get(this.proxy).setDisplayed(false);
8794 var endPoint = Roo.lib.Event.getXY(e);
8796 this.overlay.hide();
8799 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8800 newSize = this.dragSpecs.startSize +
8801 (this.placement == Roo.SplitBar.LEFT ?
8802 endPoint[0] - this.dragSpecs.startPoint[0] :
8803 this.dragSpecs.startPoint[0] - endPoint[0]
8806 newSize = this.dragSpecs.startSize +
8807 (this.placement == Roo.SplitBar.TOP ?
8808 endPoint[1] - this.dragSpecs.startPoint[1] :
8809 this.dragSpecs.startPoint[1] - endPoint[1]
8812 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8813 if(newSize != this.dragSpecs.startSize){
8814 if(this.fireEvent('beforeapply', this, newSize) !== false){
8815 this.adapter.setElementSize(this, newSize);
8816 this.fireEvent("moved", this, newSize);
8817 this.fireEvent("resize", this, newSize);
8823 * Get the adapter this SplitBar uses
8824 * @return The adapter object
8826 getAdapter : function(){
8827 return this.adapter;
8831 * Set the adapter this SplitBar uses
8832 * @param {Object} adapter A SplitBar adapter object
8834 setAdapter : function(adapter){
8835 this.adapter = adapter;
8836 this.adapter.init(this);
8840 * Gets the minimum size for the resizing element
8841 * @return {Number} The minimum size
8843 getMinimumSize : function(){
8844 return this.minSize;
8848 * Sets the minimum size for the resizing element
8849 * @param {Number} minSize The minimum size
8851 setMinimumSize : function(minSize){
8852 this.minSize = minSize;
8856 * Gets the maximum size for the resizing element
8857 * @return {Number} The maximum size
8859 getMaximumSize : function(){
8860 return this.maxSize;
8864 * Sets the maximum size for the resizing element
8865 * @param {Number} maxSize The maximum size
8867 setMaximumSize : function(maxSize){
8868 this.maxSize = maxSize;
8872 * Sets the initialize size for the resizing element
8873 * @param {Number} size The initial size
8875 setCurrentSize : function(size){
8876 var oldAnimate = this.animate;
8877 this.animate = false;
8878 this.adapter.setElementSize(this, size);
8879 this.animate = oldAnimate;
8883 * Destroy this splitbar.
8884 * @param {Boolean} removeEl True to remove the element
8886 destroy : function(removeEl){
8891 this.proxy.parentNode.removeChild(this.proxy);
8899 * @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.
8901 Roo.SplitBar.createProxy = function(dir){
8902 var proxy = new Roo.Element(document.createElement("div"));
8903 proxy.unselectable();
8904 var cls = 'x-splitbar-proxy';
8905 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8906 document.body.appendChild(proxy.dom);
8911 * @class Roo.SplitBar.BasicLayoutAdapter
8912 * Default Adapter. It assumes the splitter and resizing element are not positioned
8913 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8915 Roo.SplitBar.BasicLayoutAdapter = function(){
8918 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8919 // do nothing for now
8924 * Called before drag operations to get the current size of the resizing element.
8925 * @param {Roo.SplitBar} s The SplitBar using this adapter
8927 getElementSize : function(s){
8928 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8929 return s.resizingEl.getWidth();
8931 return s.resizingEl.getHeight();
8936 * Called after drag operations to set the size of the resizing element.
8937 * @param {Roo.SplitBar} s The SplitBar using this adapter
8938 * @param {Number} newSize The new size to set
8939 * @param {Function} onComplete A function to be invoked when resizing is complete
8941 setElementSize : function(s, newSize, onComplete){
8942 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8944 s.resizingEl.setWidth(newSize);
8946 onComplete(s, newSize);
8949 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8954 s.resizingEl.setHeight(newSize);
8956 onComplete(s, newSize);
8959 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8966 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8967 * @extends Roo.SplitBar.BasicLayoutAdapter
8968 * Adapter that moves the splitter element to align with the resized sizing element.
8969 * Used with an absolute positioned SplitBar.
8970 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8971 * document.body, make sure you assign an id to the body element.
8973 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8974 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8975 this.container = Roo.get(container);
8978 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8983 getElementSize : function(s){
8984 return this.basic.getElementSize(s);
8987 setElementSize : function(s, newSize, onComplete){
8988 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8991 moveSplitter : function(s){
8992 var yes = Roo.SplitBar;
8993 switch(s.placement){
8995 s.el.setX(s.resizingEl.getRight());
8998 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9001 s.el.setY(s.resizingEl.getBottom());
9004 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9011 * Orientation constant - Create a vertical SplitBar
9015 Roo.SplitBar.VERTICAL = 1;
9018 * Orientation constant - Create a horizontal SplitBar
9022 Roo.SplitBar.HORIZONTAL = 2;
9025 * Placement constant - The resizing element is to the left of the splitter element
9029 Roo.SplitBar.LEFT = 1;
9032 * Placement constant - The resizing element is to the right of the splitter element
9036 Roo.SplitBar.RIGHT = 2;
9039 * Placement constant - The resizing element is positioned above the splitter element
9043 Roo.SplitBar.TOP = 3;
9046 * Placement constant - The resizing element is positioned under splitter element
9050 Roo.SplitBar.BOTTOM = 4;
9053 * Ext JS Library 1.1.1
9054 * Copyright(c) 2006-2007, Ext JS, LLC.
9056 * Originally Released Under LGPL - original licence link has changed is not relivant.
9059 * <script type="text/javascript">
9064 * @extends Roo.util.Observable
9065 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9066 * This class also supports single and multi selection modes. <br>
9067 * Create a data model bound view:
9069 var store = new Roo.data.Store(...);
9071 var view = new Roo.View({
9073 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9076 selectedClass: "ydataview-selected",
9080 // listen for node click?
9081 view.on("click", function(vw, index, node, e){
9082 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9086 dataModel.load("foobar.xml");
9088 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9090 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9091 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9093 * Note: old style constructor is still suported (container, template, config)
9097 * @param {Object} config The config object
9100 Roo.View = function(config, depreciated_tpl, depreciated_config){
9102 if (typeof(depreciated_tpl) == 'undefined') {
9103 // new way.. - universal constructor.
9104 Roo.apply(this, config);
9105 this.el = Roo.get(this.el);
9108 this.el = Roo.get(config);
9109 this.tpl = depreciated_tpl;
9110 Roo.apply(this, depreciated_config);
9114 if(typeof(this.tpl) == "string"){
9115 this.tpl = new Roo.Template(this.tpl);
9117 // support xtype ctors..
9118 this.tpl = new Roo.factory(this.tpl, Roo);
9129 * @event beforeclick
9130 * Fires before a click is processed. Returns false to cancel the default action.
9131 * @param {Roo.View} this
9132 * @param {Number} index The index of the target node
9133 * @param {HTMLElement} node The target node
9134 * @param {Roo.EventObject} e The raw event object
9136 "beforeclick" : true,
9139 * Fires when a template node is clicked.
9140 * @param {Roo.View} this
9141 * @param {Number} index The index of the target node
9142 * @param {HTMLElement} node The target node
9143 * @param {Roo.EventObject} e The raw event object
9148 * Fires when a template node is double clicked.
9149 * @param {Roo.View} this
9150 * @param {Number} index The index of the target node
9151 * @param {HTMLElement} node The target node
9152 * @param {Roo.EventObject} e The raw event object
9156 * @event contextmenu
9157 * Fires when a template node is right clicked.
9158 * @param {Roo.View} this
9159 * @param {Number} index The index of the target node
9160 * @param {HTMLElement} node The target node
9161 * @param {Roo.EventObject} e The raw event object
9163 "contextmenu" : true,
9165 * @event selectionchange
9166 * Fires when the selected nodes change.
9167 * @param {Roo.View} this
9168 * @param {Array} selections Array of the selected nodes
9170 "selectionchange" : true,
9173 * @event beforeselect
9174 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9175 * @param {Roo.View} this
9176 * @param {HTMLElement} node The node to be selected
9177 * @param {Array} selections Array of currently selected nodes
9179 "beforeselect" : true
9183 "click": this.onClick,
9184 "dblclick": this.onDblClick,
9185 "contextmenu": this.onContextMenu,
9189 this.selections = [];
9191 this.cmp = new Roo.CompositeElementLite([]);
9193 this.store = Roo.factory(this.store, Roo.data);
9194 this.setStore(this.store, true);
9196 Roo.View.superclass.constructor.call(this);
9199 Roo.extend(Roo.View, Roo.util.Observable, {
9202 * @cfg {Roo.data.Store} store Data store to load data from.
9207 * @cfg {String|Roo.Element} el The container element.
9212 * @cfg {String|Roo.Template} tpl The template used by this View
9217 * @cfg {String} selectedClass The css class to add to selected nodes
9219 selectedClass : "x-view-selected",
9221 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9225 * @cfg {Boolean} multiSelect Allow multiple selection
9228 multiSelect : false,
9230 * @cfg {Boolean} singleSelect Allow single selection
9232 singleSelect: false,
9235 * Returns the element this view is bound to.
9236 * @return {Roo.Element}
9243 * Refreshes the view.
9245 refresh : function(){
9247 this.clearSelections();
9250 var records = this.store.getRange();
9251 if(records.length < 1){
9252 this.el.update(this.emptyText);
9255 for(var i = 0, len = records.length; i < len; i++){
9256 var data = this.prepareData(records[i].data, i, records[i]);
9257 html[html.length] = t.apply(data);
9259 this.el.update(html.join(""));
9260 this.nodes = this.el.dom.childNodes;
9261 this.updateIndexes(0);
9265 * Function to override to reformat the data that is sent to
9266 * the template for each node.
9267 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9268 * a JSON object for an UpdateManager bound view).
9270 prepareData : function(data){
9274 onUpdate : function(ds, record){
9275 this.clearSelections();
9276 var index = this.store.indexOf(record);
9277 var n = this.nodes[index];
9278 this.tpl.insertBefore(n, this.prepareData(record.data));
9279 n.parentNode.removeChild(n);
9280 this.updateIndexes(index, index);
9283 onAdd : function(ds, records, index){
9284 this.clearSelections();
9285 if(this.nodes.length == 0){
9289 var n = this.nodes[index];
9290 for(var i = 0, len = records.length; i < len; i++){
9291 var d = this.prepareData(records[i].data);
9293 this.tpl.insertBefore(n, d);
9295 this.tpl.append(this.el, d);
9298 this.updateIndexes(index);
9301 onRemove : function(ds, record, index){
9302 this.clearSelections();
9303 this.el.dom.removeChild(this.nodes[index]);
9304 this.updateIndexes(index);
9308 * Refresh an individual node.
9309 * @param {Number} index
9311 refreshNode : function(index){
9312 this.onUpdate(this.store, this.store.getAt(index));
9315 updateIndexes : function(startIndex, endIndex){
9316 var ns = this.nodes;
9317 startIndex = startIndex || 0;
9318 endIndex = endIndex || ns.length - 1;
9319 for(var i = startIndex; i <= endIndex; i++){
9320 ns[i].nodeIndex = i;
9325 * Changes the data store this view uses and refresh the view.
9326 * @param {Store} store
9328 setStore : function(store, initial){
9329 if(!initial && this.store){
9330 this.store.un("datachanged", this.refresh);
9331 this.store.un("add", this.onAdd);
9332 this.store.un("remove", this.onRemove);
9333 this.store.un("update", this.onUpdate);
9334 this.store.un("clear", this.refresh);
9338 store.on("datachanged", this.refresh, this);
9339 store.on("add", this.onAdd, this);
9340 store.on("remove", this.onRemove, this);
9341 store.on("update", this.onUpdate, this);
9342 store.on("clear", this.refresh, this);
9351 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9352 * @param {HTMLElement} node
9353 * @return {HTMLElement} The template node
9355 findItemFromChild : function(node){
9356 var el = this.el.dom;
9357 if(!node || node.parentNode == el){
9360 var p = node.parentNode;
9361 while(p && p != el){
9362 if(p.parentNode == el){
9371 onClick : function(e){
9372 var item = this.findItemFromChild(e.getTarget());
9374 var index = this.indexOf(item);
9375 if(this.onItemClick(item, index, e) !== false){
9376 this.fireEvent("click", this, index, item, e);
9379 this.clearSelections();
9384 onContextMenu : function(e){
9385 var item = this.findItemFromChild(e.getTarget());
9387 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9392 onDblClick : function(e){
9393 var item = this.findItemFromChild(e.getTarget());
9395 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9399 onItemClick : function(item, index, e){
9400 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9403 if(this.multiSelect || this.singleSelect){
9404 if(this.multiSelect && e.shiftKey && this.lastSelection){
9405 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9407 this.select(item, this.multiSelect && e.ctrlKey);
9408 this.lastSelection = item;
9416 * Get the number of selected nodes.
9419 getSelectionCount : function(){
9420 return this.selections.length;
9424 * Get the currently selected nodes.
9425 * @return {Array} An array of HTMLElements
9427 getSelectedNodes : function(){
9428 return this.selections;
9432 * Get the indexes of the selected nodes.
9435 getSelectedIndexes : function(){
9436 var indexes = [], s = this.selections;
9437 for(var i = 0, len = s.length; i < len; i++){
9438 indexes.push(s[i].nodeIndex);
9444 * Clear all selections
9445 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9447 clearSelections : function(suppressEvent){
9448 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9449 this.cmp.elements = this.selections;
9450 this.cmp.removeClass(this.selectedClass);
9451 this.selections = [];
9453 this.fireEvent("selectionchange", this, this.selections);
9459 * Returns true if the passed node is selected
9460 * @param {HTMLElement/Number} node The node or node index
9463 isSelected : function(node){
9464 var s = this.selections;
9468 node = this.getNode(node);
9469 return s.indexOf(node) !== -1;
9474 * @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
9475 * @param {Boolean} keepExisting (optional) true to keep existing selections
9476 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9478 select : function(nodeInfo, keepExisting, suppressEvent){
9479 if(nodeInfo instanceof Array){
9481 this.clearSelections(true);
9483 for(var i = 0, len = nodeInfo.length; i < len; i++){
9484 this.select(nodeInfo[i], true, true);
9487 var node = this.getNode(nodeInfo);
9488 if(node && !this.isSelected(node)){
9490 this.clearSelections(true);
9492 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9493 Roo.fly(node).addClass(this.selectedClass);
9494 this.selections.push(node);
9496 this.fireEvent("selectionchange", this, this.selections);
9504 * Gets a template node.
9505 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9506 * @return {HTMLElement} The node or null if it wasn't found
9508 getNode : function(nodeInfo){
9509 if(typeof nodeInfo == "string"){
9510 return document.getElementById(nodeInfo);
9511 }else if(typeof nodeInfo == "number"){
9512 return this.nodes[nodeInfo];
9518 * Gets a range template nodes.
9519 * @param {Number} startIndex
9520 * @param {Number} endIndex
9521 * @return {Array} An array of nodes
9523 getNodes : function(start, end){
9524 var ns = this.nodes;
9526 end = typeof end == "undefined" ? ns.length - 1 : end;
9529 for(var i = start; i <= end; i++){
9533 for(var i = start; i >= end; i--){
9541 * Finds the index of the passed node
9542 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9543 * @return {Number} The index of the node or -1
9545 indexOf : function(node){
9546 node = this.getNode(node);
9547 if(typeof node.nodeIndex == "number"){
9548 return node.nodeIndex;
9550 var ns = this.nodes;
9551 for(var i = 0, len = ns.length; i < len; i++){
9561 * Ext JS Library 1.1.1
9562 * Copyright(c) 2006-2007, Ext JS, LLC.
9564 * Originally Released Under LGPL - original licence link has changed is not relivant.
9567 * <script type="text/javascript">
9571 * @class Roo.JsonView
9573 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9575 var view = new Roo.JsonView({
9576 container: "my-element",
9577 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9582 // listen for node click?
9583 view.on("click", function(vw, index, node, e){
9584 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9587 // direct load of JSON data
9588 view.load("foobar.php");
9590 // Example from my blog list
9591 var tpl = new Roo.Template(
9592 '<div class="entry">' +
9593 '<a class="entry-title" href="{link}">{title}</a>' +
9594 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9595 "</div><hr />"
9598 var moreView = new Roo.JsonView({
9599 container : "entry-list",
9603 moreView.on("beforerender", this.sortEntries, this);
9605 url: "/blog/get-posts.php",
9606 params: "allposts=true",
9607 text: "Loading Blog Entries..."
9611 * Note: old code is supported with arguments : (container, template, config)
9615 * Create a new JsonView
9617 * @param {Object} config The config object
9620 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9623 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9625 var um = this.el.getUpdateManager();
9626 um.setRenderer(this);
9627 um.on("update", this.onLoad, this);
9628 um.on("failure", this.onLoadException, this);
9631 * @event beforerender
9632 * Fires before rendering of the downloaded JSON data.
9633 * @param {Roo.JsonView} this
9634 * @param {Object} data The JSON data loaded
9638 * Fires when data is loaded.
9639 * @param {Roo.JsonView} this
9640 * @param {Object} data The JSON data loaded
9641 * @param {Object} response The raw Connect response object
9644 * @event loadexception
9645 * Fires when loading fails.
9646 * @param {Roo.JsonView} this
9647 * @param {Object} response The raw Connect response object
9650 'beforerender' : true,
9652 'loadexception' : true
9655 Roo.extend(Roo.JsonView, Roo.View, {
9657 * @type {String} The root property in the loaded JSON object that contains the data
9662 * Refreshes the view.
9664 refresh : function(){
9665 this.clearSelections();
9668 var o = this.jsonData;
9669 if(o && o.length > 0){
9670 for(var i = 0, len = o.length; i < len; i++){
9671 var data = this.prepareData(o[i], i, o);
9672 html[html.length] = this.tpl.apply(data);
9675 html.push(this.emptyText);
9677 this.el.update(html.join(""));
9678 this.nodes = this.el.dom.childNodes;
9679 this.updateIndexes(0);
9683 * 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.
9684 * @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:
9687 url: "your-url.php",
9688 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9689 callback: yourFunction,
9690 scope: yourObject, //(optional scope)
9698 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9699 * 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.
9700 * @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}
9701 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9702 * @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.
9705 var um = this.el.getUpdateManager();
9706 um.update.apply(um, arguments);
9709 render : function(el, response){
9710 this.clearSelections();
9714 o = Roo.util.JSON.decode(response.responseText);
9717 o = o[this.jsonRoot];
9722 * The current JSON data or null
9725 this.beforeRender();
9730 * Get the number of records in the current JSON dataset
9733 getCount : function(){
9734 return this.jsonData ? this.jsonData.length : 0;
9738 * Returns the JSON object for the specified node(s)
9739 * @param {HTMLElement/Array} node The node or an array of nodes
9740 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9741 * you get the JSON object for the node
9743 getNodeData : function(node){
9744 if(node instanceof Array){
9746 for(var i = 0, len = node.length; i < len; i++){
9747 data.push(this.getNodeData(node[i]));
9751 return this.jsonData[this.indexOf(node)] || null;
9754 beforeRender : function(){
9755 this.snapshot = this.jsonData;
9757 this.sort.apply(this, this.sortInfo);
9759 this.fireEvent("beforerender", this, this.jsonData);
9762 onLoad : function(el, o){
9763 this.fireEvent("load", this, this.jsonData, o);
9766 onLoadException : function(el, o){
9767 this.fireEvent("loadexception", this, o);
9771 * Filter the data by a specific property.
9772 * @param {String} property A property on your JSON objects
9773 * @param {String/RegExp} value Either string that the property values
9774 * should start with, or a RegExp to test against the property
9776 filter : function(property, value){
9779 var ss = this.snapshot;
9780 if(typeof value == "string"){
9781 var vlen = value.length;
9786 value = value.toLowerCase();
9787 for(var i = 0, len = ss.length; i < len; i++){
9789 if(o[property].substr(0, vlen).toLowerCase() == value){
9793 } else if(value.exec){ // regex?
9794 for(var i = 0, len = ss.length; i < len; i++){
9796 if(value.test(o[property])){
9803 this.jsonData = data;
9809 * Filter by a function. The passed function will be called with each
9810 * object in the current dataset. If the function returns true the value is kept,
9811 * otherwise it is filtered.
9812 * @param {Function} fn
9813 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9815 filterBy : function(fn, scope){
9818 var ss = this.snapshot;
9819 for(var i = 0, len = ss.length; i < len; i++){
9821 if(fn.call(scope || this, o)){
9825 this.jsonData = data;
9831 * Clears the current filter.
9833 clearFilter : function(){
9834 if(this.snapshot && this.jsonData != this.snapshot){
9835 this.jsonData = this.snapshot;
9842 * Sorts the data for this view and refreshes it.
9843 * @param {String} property A property on your JSON objects to sort on
9844 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9845 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9847 sort : function(property, dir, sortType){
9848 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9851 var dsc = dir && dir.toLowerCase() == "desc";
9852 var f = function(o1, o2){
9853 var v1 = sortType ? sortType(o1[p]) : o1[p];
9854 var v2 = sortType ? sortType(o2[p]) : o2[p];
9857 return dsc ? +1 : -1;
9859 return dsc ? -1 : +1;
9864 this.jsonData.sort(f);
9866 if(this.jsonData != this.snapshot){
9867 this.snapshot.sort(f);
9873 * Ext JS Library 1.1.1
9874 * Copyright(c) 2006-2007, Ext JS, LLC.
9876 * Originally Released Under LGPL - original licence link has changed is not relivant.
9879 * <script type="text/javascript">
9884 * @class Roo.ColorPalette
9885 * @extends Roo.Component
9886 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9887 * Here's an example of typical usage:
9889 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9890 cp.render('my-div');
9892 cp.on('select', function(palette, selColor){
9893 // do something with selColor
9897 * Create a new ColorPalette
9898 * @param {Object} config The config object
9900 Roo.ColorPalette = function(config){
9901 Roo.ColorPalette.superclass.constructor.call(this, config);
9905 * Fires when a color is selected
9906 * @param {ColorPalette} this
9907 * @param {String} color The 6-digit color hex code (without the # symbol)
9913 this.on("select", this.handler, this.scope, true);
9916 Roo.extend(Roo.ColorPalette, Roo.Component, {
9918 * @cfg {String} itemCls
9919 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9921 itemCls : "x-color-palette",
9923 * @cfg {String} value
9924 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9925 * the hex codes are case-sensitive.
9930 ctype: "Roo.ColorPalette",
9933 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9935 allowReselect : false,
9938 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9939 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9940 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9941 * of colors with the width setting until the box is symmetrical.</p>
9942 * <p>You can override individual colors if needed:</p>
9944 var cp = new Roo.ColorPalette();
9945 cp.colors[0] = "FF0000"; // change the first box to red
9948 Or you can provide a custom array of your own for complete control:
9950 var cp = new Roo.ColorPalette();
9951 cp.colors = ["000000", "993300", "333300"];
9956 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9957 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9958 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9959 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9960 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9964 onRender : function(container, position){
9965 var t = new Roo.MasterTemplate(
9966 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9968 var c = this.colors;
9969 for(var i = 0, len = c.length; i < len; i++){
9972 var el = document.createElement("div");
9973 el.className = this.itemCls;
9975 container.dom.insertBefore(el, position);
9976 this.el = Roo.get(el);
9977 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9978 if(this.clickEvent != 'click'){
9979 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9984 afterRender : function(){
9985 Roo.ColorPalette.superclass.afterRender.call(this);
9994 handleClick : function(e, t){
9997 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9998 this.select(c.toUpperCase());
10003 * Selects the specified color in the palette (fires the select event)
10004 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10006 select : function(color){
10007 color = color.replace("#", "");
10008 if(color != this.value || this.allowReselect){
10011 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10013 el.child("a.color-"+color).addClass("x-color-palette-sel");
10014 this.value = color;
10015 this.fireEvent("select", this, color);
10020 * Ext JS Library 1.1.1
10021 * Copyright(c) 2006-2007, Ext JS, LLC.
10023 * Originally Released Under LGPL - original licence link has changed is not relivant.
10026 * <script type="text/javascript">
10030 * @class Roo.DatePicker
10031 * @extends Roo.Component
10032 * Simple date picker class.
10034 * Create a new DatePicker
10035 * @param {Object} config The config object
10037 Roo.DatePicker = function(config){
10038 Roo.DatePicker.superclass.constructor.call(this, config);
10040 this.value = config && config.value ?
10041 config.value.clearTime() : new Date().clearTime();
10046 * Fires when a date is selected
10047 * @param {DatePicker} this
10048 * @param {Date} date The selected date
10054 this.on("select", this.handler, this.scope || this);
10056 // build the disabledDatesRE
10057 if(!this.disabledDatesRE && this.disabledDates){
10058 var dd = this.disabledDates;
10060 for(var i = 0; i < dd.length; i++){
10062 if(i != dd.length-1) re += "|";
10064 this.disabledDatesRE = new RegExp(re + ")");
10068 Roo.extend(Roo.DatePicker, Roo.Component, {
10070 * @cfg {String} todayText
10071 * The text to display on the button that selects the current date (defaults to "Today")
10073 todayText : "Today",
10075 * @cfg {String} okText
10076 * The text to display on the ok button
10078 okText : " OK ", //   to give the user extra clicking room
10080 * @cfg {String} cancelText
10081 * The text to display on the cancel button
10083 cancelText : "Cancel",
10085 * @cfg {String} todayTip
10086 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10088 todayTip : "{0} (Spacebar)",
10090 * @cfg {Date} minDate
10091 * Minimum allowable date (JavaScript date object, defaults to null)
10095 * @cfg {Date} maxDate
10096 * Maximum allowable date (JavaScript date object, defaults to null)
10100 * @cfg {String} minText
10101 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10103 minText : "This date is before the minimum date",
10105 * @cfg {String} maxText
10106 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10108 maxText : "This date is after the maximum date",
10110 * @cfg {String} format
10111 * The default date format string which can be overriden for localization support. The format must be
10112 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10116 * @cfg {Array} disabledDays
10117 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10119 disabledDays : null,
10121 * @cfg {String} disabledDaysText
10122 * The tooltip to display when the date falls on a disabled day (defaults to "")
10124 disabledDaysText : "",
10126 * @cfg {RegExp} disabledDatesRE
10127 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10129 disabledDatesRE : null,
10131 * @cfg {String} disabledDatesText
10132 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10134 disabledDatesText : "",
10136 * @cfg {Boolean} constrainToViewport
10137 * True to constrain the date picker to the viewport (defaults to true)
10139 constrainToViewport : true,
10141 * @cfg {Array} monthNames
10142 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10144 monthNames : Date.monthNames,
10146 * @cfg {Array} dayNames
10147 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10149 dayNames : Date.dayNames,
10151 * @cfg {String} nextText
10152 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10154 nextText: 'Next Month (Control+Right)',
10156 * @cfg {String} prevText
10157 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10159 prevText: 'Previous Month (Control+Left)',
10161 * @cfg {String} monthYearText
10162 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10164 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10166 * @cfg {Number} startDay
10167 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10171 * @cfg {Bool} showClear
10172 * Show a clear button (usefull for date form elements that can be blank.)
10178 * Sets the value of the date field
10179 * @param {Date} value The date to set
10181 setValue : function(value){
10182 var old = this.value;
10183 this.value = value.clearTime(true);
10185 this.update(this.value);
10190 * Gets the current selected value of the date field
10191 * @return {Date} The selected date
10193 getValue : function(){
10198 focus : function(){
10200 this.update(this.activeDate);
10205 onRender : function(container, position){
10207 '<table cellspacing="0">',
10208 '<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>',
10209 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10210 var dn = this.dayNames;
10211 for(var i = 0; i < 7; i++){
10212 var d = this.startDay+i;
10216 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10218 m[m.length] = "</tr></thead><tbody><tr>";
10219 for(var i = 0; i < 42; i++) {
10220 if(i % 7 == 0 && i != 0){
10221 m[m.length] = "</tr><tr>";
10223 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10225 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10226 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10228 var el = document.createElement("div");
10229 el.className = "x-date-picker";
10230 el.innerHTML = m.join("");
10232 container.dom.insertBefore(el, position);
10234 this.el = Roo.get(el);
10235 this.eventEl = Roo.get(el.firstChild);
10237 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10238 handler: this.showPrevMonth,
10240 preventDefault:true,
10244 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10245 handler: this.showNextMonth,
10247 preventDefault:true,
10251 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10253 this.monthPicker = this.el.down('div.x-date-mp');
10254 this.monthPicker.enableDisplayMode('block');
10256 var kn = new Roo.KeyNav(this.eventEl, {
10257 "left" : function(e){
10259 this.showPrevMonth() :
10260 this.update(this.activeDate.add("d", -1));
10263 "right" : function(e){
10265 this.showNextMonth() :
10266 this.update(this.activeDate.add("d", 1));
10269 "up" : function(e){
10271 this.showNextYear() :
10272 this.update(this.activeDate.add("d", -7));
10275 "down" : function(e){
10277 this.showPrevYear() :
10278 this.update(this.activeDate.add("d", 7));
10281 "pageUp" : function(e){
10282 this.showNextMonth();
10285 "pageDown" : function(e){
10286 this.showPrevMonth();
10289 "enter" : function(e){
10290 e.stopPropagation();
10297 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10299 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10301 this.el.unselectable();
10303 this.cells = this.el.select("table.x-date-inner tbody td");
10304 this.textNodes = this.el.query("table.x-date-inner tbody span");
10306 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10308 tooltip: this.monthYearText
10311 this.mbtn.on('click', this.showMonthPicker, this);
10312 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10315 var today = (new Date()).dateFormat(this.format);
10317 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10318 if (this.showClear) {
10319 baseTb.add( new Roo.Toolbar.Fill());
10322 text: String.format(this.todayText, today),
10323 tooltip: String.format(this.todayTip, today),
10324 handler: this.selectToday,
10328 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10331 if (this.showClear) {
10333 baseTb.add( new Roo.Toolbar.Fill());
10336 cls: 'x-btn-icon x-btn-clear',
10337 handler: function() {
10339 this.fireEvent("select", this, '');
10349 this.update(this.value);
10352 createMonthPicker : function(){
10353 if(!this.monthPicker.dom.firstChild){
10354 var buf = ['<table border="0" cellspacing="0">'];
10355 for(var i = 0; i < 6; i++){
10357 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10358 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10360 '<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>' :
10361 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10365 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10367 '</button><button type="button" class="x-date-mp-cancel">',
10369 '</button></td></tr>',
10372 this.monthPicker.update(buf.join(''));
10373 this.monthPicker.on('click', this.onMonthClick, this);
10374 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10376 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10377 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10379 this.mpMonths.each(function(m, a, i){
10382 m.dom.xmonth = 5 + Math.round(i * .5);
10384 m.dom.xmonth = Math.round((i-1) * .5);
10390 showMonthPicker : function(){
10391 this.createMonthPicker();
10392 var size = this.el.getSize();
10393 this.monthPicker.setSize(size);
10394 this.monthPicker.child('table').setSize(size);
10396 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10397 this.updateMPMonth(this.mpSelMonth);
10398 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10399 this.updateMPYear(this.mpSelYear);
10401 this.monthPicker.slideIn('t', {duration:.2});
10404 updateMPYear : function(y){
10406 var ys = this.mpYears.elements;
10407 for(var i = 1; i <= 10; i++){
10408 var td = ys[i-1], y2;
10410 y2 = y + Math.round(i * .5);
10411 td.firstChild.innerHTML = y2;
10414 y2 = y - (5-Math.round(i * .5));
10415 td.firstChild.innerHTML = y2;
10418 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10422 updateMPMonth : function(sm){
10423 this.mpMonths.each(function(m, a, i){
10424 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10428 selectMPMonth: function(m){
10432 onMonthClick : function(e, t){
10434 var el = new Roo.Element(t), pn;
10435 if(el.is('button.x-date-mp-cancel')){
10436 this.hideMonthPicker();
10438 else if(el.is('button.x-date-mp-ok')){
10439 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10440 this.hideMonthPicker();
10442 else if(pn = el.up('td.x-date-mp-month', 2)){
10443 this.mpMonths.removeClass('x-date-mp-sel');
10444 pn.addClass('x-date-mp-sel');
10445 this.mpSelMonth = pn.dom.xmonth;
10447 else if(pn = el.up('td.x-date-mp-year', 2)){
10448 this.mpYears.removeClass('x-date-mp-sel');
10449 pn.addClass('x-date-mp-sel');
10450 this.mpSelYear = pn.dom.xyear;
10452 else if(el.is('a.x-date-mp-prev')){
10453 this.updateMPYear(this.mpyear-10);
10455 else if(el.is('a.x-date-mp-next')){
10456 this.updateMPYear(this.mpyear+10);
10460 onMonthDblClick : function(e, t){
10462 var el = new Roo.Element(t), pn;
10463 if(pn = el.up('td.x-date-mp-month', 2)){
10464 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10465 this.hideMonthPicker();
10467 else if(pn = el.up('td.x-date-mp-year', 2)){
10468 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10469 this.hideMonthPicker();
10473 hideMonthPicker : function(disableAnim){
10474 if(this.monthPicker){
10475 if(disableAnim === true){
10476 this.monthPicker.hide();
10478 this.monthPicker.slideOut('t', {duration:.2});
10484 showPrevMonth : function(e){
10485 this.update(this.activeDate.add("mo", -1));
10489 showNextMonth : function(e){
10490 this.update(this.activeDate.add("mo", 1));
10494 showPrevYear : function(){
10495 this.update(this.activeDate.add("y", -1));
10499 showNextYear : function(){
10500 this.update(this.activeDate.add("y", 1));
10504 handleMouseWheel : function(e){
10505 var delta = e.getWheelDelta();
10507 this.showPrevMonth();
10509 } else if(delta < 0){
10510 this.showNextMonth();
10516 handleDateClick : function(e, t){
10518 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10519 this.setValue(new Date(t.dateValue));
10520 this.fireEvent("select", this, this.value);
10525 selectToday : function(){
10526 this.setValue(new Date().clearTime());
10527 this.fireEvent("select", this, this.value);
10531 update : function(date){
10532 var vd = this.activeDate;
10533 this.activeDate = date;
10535 var t = date.getTime();
10536 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10537 this.cells.removeClass("x-date-selected");
10538 this.cells.each(function(c){
10539 if(c.dom.firstChild.dateValue == t){
10540 c.addClass("x-date-selected");
10541 setTimeout(function(){
10542 try{c.dom.firstChild.focus();}catch(e){}
10550 var days = date.getDaysInMonth();
10551 var firstOfMonth = date.getFirstDateOfMonth();
10552 var startingPos = firstOfMonth.getDay()-this.startDay;
10554 if(startingPos <= this.startDay){
10558 var pm = date.add("mo", -1);
10559 var prevStart = pm.getDaysInMonth()-startingPos;
10561 var cells = this.cells.elements;
10562 var textEls = this.textNodes;
10563 days += startingPos;
10565 // convert everything to numbers so it's fast
10566 var day = 86400000;
10567 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10568 var today = new Date().clearTime().getTime();
10569 var sel = date.clearTime().getTime();
10570 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10571 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10572 var ddMatch = this.disabledDatesRE;
10573 var ddText = this.disabledDatesText;
10574 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10575 var ddaysText = this.disabledDaysText;
10576 var format = this.format;
10578 var setCellClass = function(cal, cell){
10580 var t = d.getTime();
10581 cell.firstChild.dateValue = t;
10583 cell.className += " x-date-today";
10584 cell.title = cal.todayText;
10587 cell.className += " x-date-selected";
10588 setTimeout(function(){
10589 try{cell.firstChild.focus();}catch(e){}
10594 cell.className = " x-date-disabled";
10595 cell.title = cal.minText;
10599 cell.className = " x-date-disabled";
10600 cell.title = cal.maxText;
10604 if(ddays.indexOf(d.getDay()) != -1){
10605 cell.title = ddaysText;
10606 cell.className = " x-date-disabled";
10609 if(ddMatch && format){
10610 var fvalue = d.dateFormat(format);
10611 if(ddMatch.test(fvalue)){
10612 cell.title = ddText.replace("%0", fvalue);
10613 cell.className = " x-date-disabled";
10619 for(; i < startingPos; i++) {
10620 textEls[i].innerHTML = (++prevStart);
10621 d.setDate(d.getDate()+1);
10622 cells[i].className = "x-date-prevday";
10623 setCellClass(this, cells[i]);
10625 for(; i < days; i++){
10626 intDay = i - startingPos + 1;
10627 textEls[i].innerHTML = (intDay);
10628 d.setDate(d.getDate()+1);
10629 cells[i].className = "x-date-active";
10630 setCellClass(this, cells[i]);
10633 for(; i < 42; i++) {
10634 textEls[i].innerHTML = (++extraDays);
10635 d.setDate(d.getDate()+1);
10636 cells[i].className = "x-date-nextday";
10637 setCellClass(this, cells[i]);
10640 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10642 if(!this.internalRender){
10643 var main = this.el.dom.firstChild;
10644 var w = main.offsetWidth;
10645 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10646 Roo.fly(main).setWidth(w);
10647 this.internalRender = true;
10648 // opera does not respect the auto grow header center column
10649 // then, after it gets a width opera refuses to recalculate
10650 // without a second pass
10651 if(Roo.isOpera && !this.secondPass){
10652 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10653 this.secondPass = true;
10654 this.update.defer(10, this, [date]);
10660 * Ext JS Library 1.1.1
10661 * Copyright(c) 2006-2007, Ext JS, LLC.
10663 * Originally Released Under LGPL - original licence link has changed is not relivant.
10666 * <script type="text/javascript">
10669 * @class Roo.TabPanel
10670 * @extends Roo.util.Observable
10671 * A lightweight tab container.
10675 // basic tabs 1, built from existing content
10676 var tabs = new Roo.TabPanel("tabs1");
10677 tabs.addTab("script", "View Script");
10678 tabs.addTab("markup", "View Markup");
10679 tabs.activate("script");
10681 // more advanced tabs, built from javascript
10682 var jtabs = new Roo.TabPanel("jtabs");
10683 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10685 // set up the UpdateManager
10686 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10687 var updater = tab2.getUpdateManager();
10688 updater.setDefaultUrl("ajax1.htm");
10689 tab2.on('activate', updater.refresh, updater, true);
10691 // Use setUrl for Ajax loading
10692 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10693 tab3.setUrl("ajax2.htm", null, true);
10696 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10699 jtabs.activate("jtabs-1");
10702 * Create a new TabPanel.
10703 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10704 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10706 Roo.TabPanel = function(container, config){
10708 * The container element for this TabPanel.
10709 * @type Roo.Element
10711 this.el = Roo.get(container, true);
10713 if(typeof config == "boolean"){
10714 this.tabPosition = config ? "bottom" : "top";
10716 Roo.apply(this, config);
10719 if(this.tabPosition == "bottom"){
10720 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10721 this.el.addClass("x-tabs-bottom");
10723 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10724 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10725 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10727 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10729 if(this.tabPosition != "bottom"){
10730 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10731 * @type Roo.Element
10733 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10734 this.el.addClass("x-tabs-top");
10738 this.bodyEl.setStyle("position", "relative");
10740 this.active = null;
10741 this.activateDelegate = this.activate.createDelegate(this);
10746 * Fires when the active tab changes
10747 * @param {Roo.TabPanel} this
10748 * @param {Roo.TabPanelItem} activePanel The new active tab
10752 * @event beforetabchange
10753 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10754 * @param {Roo.TabPanel} this
10755 * @param {Object} e Set cancel to true on this object to cancel the tab change
10756 * @param {Roo.TabPanelItem} tab The tab being changed to
10758 "beforetabchange" : true
10761 Roo.EventManager.onWindowResize(this.onResize, this);
10762 this.cpad = this.el.getPadding("lr");
10763 this.hiddenCount = 0;
10765 Roo.TabPanel.superclass.constructor.call(this);
10768 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10770 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10772 tabPosition : "top",
10774 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10776 currentTabWidth : 0,
10778 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10782 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10786 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10788 preferredTabWidth : 175,
10790 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10792 resizeTabs : false,
10794 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10796 monitorResize : true,
10799 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10800 * @param {String} id The id of the div to use <b>or create</b>
10801 * @param {String} text The text for the tab
10802 * @param {String} content (optional) Content to put in the TabPanelItem body
10803 * @param {Boolean} closable (optional) True to create a close icon on the tab
10804 * @return {Roo.TabPanelItem} The created TabPanelItem
10806 addTab : function(id, text, content, closable){
10807 var item = new Roo.TabPanelItem(this, id, text, closable);
10808 this.addTabItem(item);
10810 item.setContent(content);
10816 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10817 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10818 * @return {Roo.TabPanelItem}
10820 getTab : function(id){
10821 return this.items[id];
10825 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10826 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10828 hideTab : function(id){
10829 var t = this.items[id];
10832 this.hiddenCount++;
10833 this.autoSizeTabs();
10838 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10839 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10841 unhideTab : function(id){
10842 var t = this.items[id];
10844 t.setHidden(false);
10845 this.hiddenCount--;
10846 this.autoSizeTabs();
10851 * Adds an existing {@link Roo.TabPanelItem}.
10852 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10854 addTabItem : function(item){
10855 this.items[item.id] = item;
10856 this.items.push(item);
10857 if(this.resizeTabs){
10858 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10859 this.autoSizeTabs();
10866 * Removes a {@link Roo.TabPanelItem}.
10867 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10869 removeTab : function(id){
10870 var items = this.items;
10871 var tab = items[id];
10872 if(!tab) { return; }
10873 var index = items.indexOf(tab);
10874 if(this.active == tab && items.length > 1){
10875 var newTab = this.getNextAvailable(index);
10880 this.stripEl.dom.removeChild(tab.pnode.dom);
10881 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10882 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10884 items.splice(index, 1);
10885 delete this.items[tab.id];
10886 tab.fireEvent("close", tab);
10887 tab.purgeListeners();
10888 this.autoSizeTabs();
10891 getNextAvailable : function(start){
10892 var items = this.items;
10894 // look for a next tab that will slide over to
10895 // replace the one being removed
10896 while(index < items.length){
10897 var item = items[++index];
10898 if(item && !item.isHidden()){
10902 // if one isn't found select the previous tab (on the left)
10905 var item = items[--index];
10906 if(item && !item.isHidden()){
10914 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10915 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10917 disableTab : function(id){
10918 var tab = this.items[id];
10919 if(tab && this.active != tab){
10925 * Enables a {@link Roo.TabPanelItem} that is disabled.
10926 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10928 enableTab : function(id){
10929 var tab = this.items[id];
10934 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10935 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10936 * @return {Roo.TabPanelItem} The TabPanelItem.
10938 activate : function(id){
10939 var tab = this.items[id];
10943 if(tab == this.active || tab.disabled){
10947 this.fireEvent("beforetabchange", this, e, tab);
10948 if(e.cancel !== true && !tab.disabled){
10950 this.active.hide();
10952 this.active = this.items[id];
10953 this.active.show();
10954 this.fireEvent("tabchange", this, this.active);
10960 * Gets the active {@link Roo.TabPanelItem}.
10961 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10963 getActiveTab : function(){
10964 return this.active;
10968 * Updates the tab body element to fit the height of the container element
10969 * for overflow scrolling
10970 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10972 syncHeight : function(targetHeight){
10973 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10974 var bm = this.bodyEl.getMargins();
10975 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10976 this.bodyEl.setHeight(newHeight);
10980 onResize : function(){
10981 if(this.monitorResize){
10982 this.autoSizeTabs();
10987 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10989 beginUpdate : function(){
10990 this.updating = true;
10994 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10996 endUpdate : function(){
10997 this.updating = false;
10998 this.autoSizeTabs();
11002 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11004 autoSizeTabs : function(){
11005 var count = this.items.length;
11006 var vcount = count - this.hiddenCount;
11007 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11008 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11009 var availWidth = Math.floor(w / vcount);
11010 var b = this.stripBody;
11011 if(b.getWidth() > w){
11012 var tabs = this.items;
11013 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11014 if(availWidth < this.minTabWidth){
11015 /*if(!this.sleft){ // incomplete scrolling code
11016 this.createScrollButtons();
11019 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11022 if(this.currentTabWidth < this.preferredTabWidth){
11023 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11029 * Returns the number of tabs in this TabPanel.
11032 getCount : function(){
11033 return this.items.length;
11037 * Resizes all the tabs to the passed width
11038 * @param {Number} The new width
11040 setTabWidth : function(width){
11041 this.currentTabWidth = width;
11042 for(var i = 0, len = this.items.length; i < len; i++) {
11043 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11048 * Destroys this TabPanel
11049 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11051 destroy : function(removeEl){
11052 Roo.EventManager.removeResizeListener(this.onResize, this);
11053 for(var i = 0, len = this.items.length; i < len; i++){
11054 this.items[i].purgeListeners();
11056 if(removeEl === true){
11057 this.el.update("");
11064 * @class Roo.TabPanelItem
11065 * @extends Roo.util.Observable
11066 * Represents an individual item (tab plus body) in a TabPanel.
11067 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11068 * @param {String} id The id of this TabPanelItem
11069 * @param {String} text The text for the tab of this TabPanelItem
11070 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11072 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11074 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11075 * @type Roo.TabPanel
11077 this.tabPanel = tabPanel;
11079 * The id for this TabPanelItem
11084 this.disabled = false;
11088 this.loaded = false;
11089 this.closable = closable;
11092 * The body element for this TabPanelItem.
11093 * @type Roo.Element
11095 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11096 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11097 this.bodyEl.setStyle("display", "block");
11098 this.bodyEl.setStyle("zoom", "1");
11101 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11103 this.el = Roo.get(els.el, true);
11104 this.inner = Roo.get(els.inner, true);
11105 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11106 this.pnode = Roo.get(els.el.parentNode, true);
11107 this.el.on("mousedown", this.onTabMouseDown, this);
11108 this.el.on("click", this.onTabClick, this);
11111 var c = Roo.get(els.close, true);
11112 c.dom.title = this.closeText;
11113 c.addClassOnOver("close-over");
11114 c.on("click", this.closeClick, this);
11120 * Fires when this tab becomes the active tab.
11121 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11122 * @param {Roo.TabPanelItem} this
11126 * @event beforeclose
11127 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11128 * @param {Roo.TabPanelItem} this
11129 * @param {Object} e Set cancel to true on this object to cancel the close.
11131 "beforeclose": true,
11134 * Fires when this tab is closed.
11135 * @param {Roo.TabPanelItem} this
11139 * @event deactivate
11140 * Fires when this tab is no longer the active tab.
11141 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11142 * @param {Roo.TabPanelItem} this
11144 "deactivate" : true
11146 this.hidden = false;
11148 Roo.TabPanelItem.superclass.constructor.call(this);
11151 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11152 purgeListeners : function(){
11153 Roo.util.Observable.prototype.purgeListeners.call(this);
11154 this.el.removeAllListeners();
11157 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11160 this.pnode.addClass("on");
11163 this.tabPanel.stripWrap.repaint();
11165 this.fireEvent("activate", this.tabPanel, this);
11169 * Returns true if this tab is the active tab.
11170 * @return {Boolean}
11172 isActive : function(){
11173 return this.tabPanel.getActiveTab() == this;
11177 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11180 this.pnode.removeClass("on");
11182 this.fireEvent("deactivate", this.tabPanel, this);
11185 hideAction : function(){
11186 this.bodyEl.hide();
11187 this.bodyEl.setStyle("position", "absolute");
11188 this.bodyEl.setLeft("-20000px");
11189 this.bodyEl.setTop("-20000px");
11192 showAction : function(){
11193 this.bodyEl.setStyle("position", "relative");
11194 this.bodyEl.setTop("");
11195 this.bodyEl.setLeft("");
11196 this.bodyEl.show();
11200 * Set the tooltip for the tab.
11201 * @param {String} tooltip The tab's tooltip
11203 setTooltip : function(text){
11204 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11205 this.textEl.dom.qtip = text;
11206 this.textEl.dom.removeAttribute('title');
11208 this.textEl.dom.title = text;
11212 onTabClick : function(e){
11213 e.preventDefault();
11214 this.tabPanel.activate(this.id);
11217 onTabMouseDown : function(e){
11218 e.preventDefault();
11219 this.tabPanel.activate(this.id);
11222 getWidth : function(){
11223 return this.inner.getWidth();
11226 setWidth : function(width){
11227 var iwidth = width - this.pnode.getPadding("lr");
11228 this.inner.setWidth(iwidth);
11229 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11230 this.pnode.setWidth(width);
11234 * Show or hide the tab
11235 * @param {Boolean} hidden True to hide or false to show.
11237 setHidden : function(hidden){
11238 this.hidden = hidden;
11239 this.pnode.setStyle("display", hidden ? "none" : "");
11243 * Returns true if this tab is "hidden"
11244 * @return {Boolean}
11246 isHidden : function(){
11247 return this.hidden;
11251 * Returns the text for this tab
11254 getText : function(){
11258 autoSize : function(){
11259 //this.el.beginMeasure();
11260 this.textEl.setWidth(1);
11261 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11262 //this.el.endMeasure();
11266 * Sets the text for the tab (Note: this also sets the tooltip text)
11267 * @param {String} text The tab's text and tooltip
11269 setText : function(text){
11271 this.textEl.update(text);
11272 this.setTooltip(text);
11273 if(!this.tabPanel.resizeTabs){
11278 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11280 activate : function(){
11281 this.tabPanel.activate(this.id);
11285 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11287 disable : function(){
11288 if(this.tabPanel.active != this){
11289 this.disabled = true;
11290 this.pnode.addClass("disabled");
11295 * Enables this TabPanelItem if it was previously disabled.
11297 enable : function(){
11298 this.disabled = false;
11299 this.pnode.removeClass("disabled");
11303 * Sets the content for this TabPanelItem.
11304 * @param {String} content The content
11305 * @param {Boolean} loadScripts true to look for and load scripts
11307 setContent : function(content, loadScripts){
11308 this.bodyEl.update(content, loadScripts);
11312 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11313 * @return {Roo.UpdateManager} The UpdateManager
11315 getUpdateManager : function(){
11316 return this.bodyEl.getUpdateManager();
11320 * Set a URL to be used to load the content for this TabPanelItem.
11321 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11322 * @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)
11323 * @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)
11324 * @return {Roo.UpdateManager} The UpdateManager
11326 setUrl : function(url, params, loadOnce){
11327 if(this.refreshDelegate){
11328 this.un('activate', this.refreshDelegate);
11330 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11331 this.on("activate", this.refreshDelegate);
11332 return this.bodyEl.getUpdateManager();
11336 _handleRefresh : function(url, params, loadOnce){
11337 if(!loadOnce || !this.loaded){
11338 var updater = this.bodyEl.getUpdateManager();
11339 updater.update(url, params, this._setLoaded.createDelegate(this));
11344 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11345 * Will fail silently if the setUrl method has not been called.
11346 * This does not activate the panel, just updates its content.
11348 refresh : function(){
11349 if(this.refreshDelegate){
11350 this.loaded = false;
11351 this.refreshDelegate();
11356 _setLoaded : function(){
11357 this.loaded = true;
11361 closeClick : function(e){
11364 this.fireEvent("beforeclose", this, o);
11365 if(o.cancel !== true){
11366 this.tabPanel.removeTab(this.id);
11370 * The text displayed in the tooltip for the close icon.
11373 closeText : "Close this tab"
11377 Roo.TabPanel.prototype.createStrip = function(container){
11378 var strip = document.createElement("div");
11379 strip.className = "x-tabs-wrap";
11380 container.appendChild(strip);
11384 Roo.TabPanel.prototype.createStripList = function(strip){
11385 // div wrapper for retard IE
11386 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>';
11387 return strip.firstChild.firstChild.firstChild.firstChild;
11390 Roo.TabPanel.prototype.createBody = function(container){
11391 var body = document.createElement("div");
11392 Roo.id(body, "tab-body");
11393 Roo.fly(body).addClass("x-tabs-body");
11394 container.appendChild(body);
11398 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11399 var body = Roo.getDom(id);
11401 body = document.createElement("div");
11404 Roo.fly(body).addClass("x-tabs-item-body");
11405 bodyEl.insertBefore(body, bodyEl.firstChild);
11409 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11410 var td = document.createElement("td");
11411 stripEl.appendChild(td);
11413 td.className = "x-tabs-closable";
11414 if(!this.closeTpl){
11415 this.closeTpl = new Roo.Template(
11416 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11417 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11418 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11421 var el = this.closeTpl.overwrite(td, {"text": text});
11422 var close = el.getElementsByTagName("div")[0];
11423 var inner = el.getElementsByTagName("em")[0];
11424 return {"el": el, "close": close, "inner": inner};
11427 this.tabTpl = new Roo.Template(
11428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11432 var el = this.tabTpl.overwrite(td, {"text": text});
11433 var inner = el.getElementsByTagName("em")[0];
11434 return {"el": el, "inner": inner};
11438 * Ext JS Library 1.1.1
11439 * Copyright(c) 2006-2007, Ext JS, LLC.
11441 * Originally Released Under LGPL - original licence link has changed is not relivant.
11444 * <script type="text/javascript">
11448 * @class Roo.Button
11449 * @extends Roo.util.Observable
11450 * Simple Button class
11451 * @cfg {String} text The button text
11452 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11453 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11454 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11455 * @cfg {Object} scope The scope of the handler
11456 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11457 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11458 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11459 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11460 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11461 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11462 applies if enableToggle = true)
11463 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11464 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11465 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11467 * Create a new button
11468 * @param {Object} config The config object
11470 Roo.Button = function(renderTo, config)
11474 renderTo = config.renderTo || false;
11477 Roo.apply(this, config);
11481 * Fires when this button is clicked
11482 * @param {Button} this
11483 * @param {EventObject} e The click event
11488 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11489 * @param {Button} this
11490 * @param {Boolean} pressed
11495 * Fires when the mouse hovers over the button
11496 * @param {Button} this
11497 * @param {Event} e The event object
11499 'mouseover' : true,
11502 * Fires when the mouse exits the button
11503 * @param {Button} this
11504 * @param {Event} e The event object
11509 * Fires when the button is rendered
11510 * @param {Button} this
11515 this.menu = Roo.menu.MenuMgr.get(this.menu);
11517 // register listeners first!! - so render can be captured..
11518 Roo.util.Observable.call(this);
11520 this.render(renderTo);
11526 Roo.extend(Roo.Button, Roo.util.Observable, {
11532 * Read-only. True if this button is hidden
11537 * Read-only. True if this button is disabled
11542 * Read-only. True if this button is pressed (only if enableToggle = true)
11548 * @cfg {Number} tabIndex
11549 * The DOM tabIndex for this button (defaults to undefined)
11551 tabIndex : undefined,
11554 * @cfg {Boolean} enableToggle
11555 * True to enable pressed/not pressed toggling (defaults to false)
11557 enableToggle: false,
11559 * @cfg {Mixed} menu
11560 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11564 * @cfg {String} menuAlign
11565 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11567 menuAlign : "tl-bl?",
11570 * @cfg {String} iconCls
11571 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11573 iconCls : undefined,
11575 * @cfg {String} type
11576 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11581 menuClassTarget: 'tr',
11584 * @cfg {String} clickEvent
11585 * The type of event to map to the button's event handler (defaults to 'click')
11587 clickEvent : 'click',
11590 * @cfg {Boolean} handleMouseEvents
11591 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11593 handleMouseEvents : true,
11596 * @cfg {String} tooltipType
11597 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11599 tooltipType : 'qtip',
11602 * @cfg {String} cls
11603 * A CSS class to apply to the button's main element.
11607 * @cfg {Roo.Template} template (Optional)
11608 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11609 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11610 * require code modifications if required elements (e.g. a button) aren't present.
11614 render : function(renderTo){
11616 if(this.hideParent){
11617 this.parentEl = Roo.get(renderTo);
11619 if(!this.dhconfig){
11620 if(!this.template){
11621 if(!Roo.Button.buttonTemplate){
11622 // hideous table template
11623 Roo.Button.buttonTemplate = new Roo.Template(
11624 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11625 '<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>',
11626 "</tr></tbody></table>");
11628 this.template = Roo.Button.buttonTemplate;
11630 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11631 var btnEl = btn.child("button:first");
11632 btnEl.on('focus', this.onFocus, this);
11633 btnEl.on('blur', this.onBlur, this);
11635 btn.addClass(this.cls);
11638 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11641 btnEl.addClass(this.iconCls);
11643 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11646 if(this.tabIndex !== undefined){
11647 btnEl.dom.tabIndex = this.tabIndex;
11650 if(typeof this.tooltip == 'object'){
11651 Roo.QuickTips.tips(Roo.apply({
11655 btnEl.dom[this.tooltipType] = this.tooltip;
11659 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11663 this.el.dom.id = this.el.id = this.id;
11666 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11667 this.menu.on("show", this.onMenuShow, this);
11668 this.menu.on("hide", this.onMenuHide, this);
11670 btn.addClass("x-btn");
11671 if(Roo.isIE && !Roo.isIE7){
11672 this.autoWidth.defer(1, this);
11676 if(this.handleMouseEvents){
11677 btn.on("mouseover", this.onMouseOver, this);
11678 btn.on("mouseout", this.onMouseOut, this);
11679 btn.on("mousedown", this.onMouseDown, this);
11681 btn.on(this.clickEvent, this.onClick, this);
11682 //btn.on("mouseup", this.onMouseUp, this);
11689 Roo.ButtonToggleMgr.register(this);
11691 this.el.addClass("x-btn-pressed");
11694 var repeater = new Roo.util.ClickRepeater(btn,
11695 typeof this.repeat == "object" ? this.repeat : {}
11697 repeater.on("click", this.onClick, this);
11700 this.fireEvent('render', this);
11704 * Returns the button's underlying element
11705 * @return {Roo.Element} The element
11707 getEl : function(){
11712 * Destroys this Button and removes any listeners.
11714 destroy : function(){
11715 Roo.ButtonToggleMgr.unregister(this);
11716 this.el.removeAllListeners();
11717 this.purgeListeners();
11722 autoWidth : function(){
11724 this.el.setWidth("auto");
11725 if(Roo.isIE7 && Roo.isStrict){
11726 var ib = this.el.child('button');
11727 if(ib && ib.getWidth() > 20){
11729 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11734 this.el.beginMeasure();
11736 if(this.el.getWidth() < this.minWidth){
11737 this.el.setWidth(this.minWidth);
11740 this.el.endMeasure();
11747 * Assigns this button's click handler
11748 * @param {Function} handler The function to call when the button is clicked
11749 * @param {Object} scope (optional) Scope for the function passed in
11751 setHandler : function(handler, scope){
11752 this.handler = handler;
11753 this.scope = scope;
11757 * Sets this button's text
11758 * @param {String} text The button text
11760 setText : function(text){
11763 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11769 * Gets the text for this button
11770 * @return {String} The button text
11772 getText : function(){
11780 this.hidden = false;
11782 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11790 this.hidden = true;
11792 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11797 * Convenience function for boolean show/hide
11798 * @param {Boolean} visible True to show, false to hide
11800 setVisible: function(visible){
11809 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11810 * @param {Boolean} state (optional) Force a particular state
11812 toggle : function(state){
11813 state = state === undefined ? !this.pressed : state;
11814 if(state != this.pressed){
11816 this.el.addClass("x-btn-pressed");
11817 this.pressed = true;
11818 this.fireEvent("toggle", this, true);
11820 this.el.removeClass("x-btn-pressed");
11821 this.pressed = false;
11822 this.fireEvent("toggle", this, false);
11824 if(this.toggleHandler){
11825 this.toggleHandler.call(this.scope || this, this, state);
11833 focus : function(){
11834 this.el.child('button:first').focus();
11838 * Disable this button
11840 disable : function(){
11842 this.el.addClass("x-btn-disabled");
11844 this.disabled = true;
11848 * Enable this button
11850 enable : function(){
11852 this.el.removeClass("x-btn-disabled");
11854 this.disabled = false;
11858 * Convenience function for boolean enable/disable
11859 * @param {Boolean} enabled True to enable, false to disable
11861 setDisabled : function(v){
11862 this[v !== true ? "enable" : "disable"]();
11866 onClick : function(e){
11868 e.preventDefault();
11873 if(!this.disabled){
11874 if(this.enableToggle){
11877 if(this.menu && !this.menu.isVisible()){
11878 this.menu.show(this.el, this.menuAlign);
11880 this.fireEvent("click", this, e);
11882 this.el.removeClass("x-btn-over");
11883 this.handler.call(this.scope || this, this, e);
11888 onMouseOver : function(e){
11889 if(!this.disabled){
11890 this.el.addClass("x-btn-over");
11891 this.fireEvent('mouseover', this, e);
11895 onMouseOut : function(e){
11896 if(!e.within(this.el, true)){
11897 this.el.removeClass("x-btn-over");
11898 this.fireEvent('mouseout', this, e);
11902 onFocus : function(e){
11903 if(!this.disabled){
11904 this.el.addClass("x-btn-focus");
11908 onBlur : function(e){
11909 this.el.removeClass("x-btn-focus");
11912 onMouseDown : function(e){
11913 if(!this.disabled && e.button == 0){
11914 this.el.addClass("x-btn-click");
11915 Roo.get(document).on('mouseup', this.onMouseUp, this);
11919 onMouseUp : function(e){
11921 this.el.removeClass("x-btn-click");
11922 Roo.get(document).un('mouseup', this.onMouseUp, this);
11926 onMenuShow : function(e){
11927 this.el.addClass("x-btn-menu-active");
11930 onMenuHide : function(e){
11931 this.el.removeClass("x-btn-menu-active");
11935 // Private utility class used by Button
11936 Roo.ButtonToggleMgr = function(){
11939 function toggleGroup(btn, state){
11941 var g = groups[btn.toggleGroup];
11942 for(var i = 0, l = g.length; i < l; i++){
11944 g[i].toggle(false);
11951 register : function(btn){
11952 if(!btn.toggleGroup){
11955 var g = groups[btn.toggleGroup];
11957 g = groups[btn.toggleGroup] = [];
11960 btn.on("toggle", toggleGroup);
11963 unregister : function(btn){
11964 if(!btn.toggleGroup){
11967 var g = groups[btn.toggleGroup];
11970 btn.un("toggle", toggleGroup);
11976 * Ext JS Library 1.1.1
11977 * Copyright(c) 2006-2007, Ext JS, LLC.
11979 * Originally Released Under LGPL - original licence link has changed is not relivant.
11982 * <script type="text/javascript">
11986 * @class Roo.SplitButton
11987 * @extends Roo.Button
11988 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11989 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11990 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11991 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11992 * @cfg {String} arrowTooltip The title attribute of the arrow
11994 * Create a new menu button
11995 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11996 * @param {Object} config The config object
11998 Roo.SplitButton = function(renderTo, config){
11999 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12001 * @event arrowclick
12002 * Fires when this button's arrow is clicked
12003 * @param {SplitButton} this
12004 * @param {EventObject} e The click event
12006 this.addEvents({"arrowclick":true});
12009 Roo.extend(Roo.SplitButton, Roo.Button, {
12010 render : function(renderTo){
12011 // this is one sweet looking template!
12012 var tpl = new Roo.Template(
12013 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12014 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12015 '<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>',
12016 "</tbody></table></td><td>",
12017 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12018 '<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>',
12019 "</tbody></table></td></tr></table>"
12021 var btn = tpl.append(renderTo, [this.text, this.type], true);
12022 var btnEl = btn.child("button");
12024 btn.addClass(this.cls);
12027 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12030 btnEl.addClass(this.iconCls);
12032 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12036 if(this.handleMouseEvents){
12037 btn.on("mouseover", this.onMouseOver, this);
12038 btn.on("mouseout", this.onMouseOut, this);
12039 btn.on("mousedown", this.onMouseDown, this);
12040 btn.on("mouseup", this.onMouseUp, this);
12042 btn.on(this.clickEvent, this.onClick, this);
12044 if(typeof this.tooltip == 'object'){
12045 Roo.QuickTips.tips(Roo.apply({
12049 btnEl.dom[this.tooltipType] = this.tooltip;
12052 if(this.arrowTooltip){
12053 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12062 this.el.addClass("x-btn-pressed");
12064 if(Roo.isIE && !Roo.isIE7){
12065 this.autoWidth.defer(1, this);
12070 this.menu.on("show", this.onMenuShow, this);
12071 this.menu.on("hide", this.onMenuHide, this);
12073 this.fireEvent('render', this);
12077 autoWidth : function(){
12079 var tbl = this.el.child("table:first");
12080 var tbl2 = this.el.child("table:last");
12081 this.el.setWidth("auto");
12082 tbl.setWidth("auto");
12083 if(Roo.isIE7 && Roo.isStrict){
12084 var ib = this.el.child('button:first');
12085 if(ib && ib.getWidth() > 20){
12087 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12092 this.el.beginMeasure();
12094 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12095 tbl.setWidth(this.minWidth-tbl2.getWidth());
12098 this.el.endMeasure();
12101 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12105 * Sets this button's click handler
12106 * @param {Function} handler The function to call when the button is clicked
12107 * @param {Object} scope (optional) Scope for the function passed above
12109 setHandler : function(handler, scope){
12110 this.handler = handler;
12111 this.scope = scope;
12115 * Sets this button's arrow click handler
12116 * @param {Function} handler The function to call when the arrow is clicked
12117 * @param {Object} scope (optional) Scope for the function passed above
12119 setArrowHandler : function(handler, scope){
12120 this.arrowHandler = handler;
12121 this.scope = scope;
12127 focus : function(){
12129 this.el.child("button:first").focus();
12134 onClick : function(e){
12135 e.preventDefault();
12136 if(!this.disabled){
12137 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12138 if(this.menu && !this.menu.isVisible()){
12139 this.menu.show(this.el, this.menuAlign);
12141 this.fireEvent("arrowclick", this, e);
12142 if(this.arrowHandler){
12143 this.arrowHandler.call(this.scope || this, this, e);
12146 this.fireEvent("click", this, e);
12148 this.handler.call(this.scope || this, this, e);
12154 onMouseDown : function(e){
12155 if(!this.disabled){
12156 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12160 onMouseUp : function(e){
12161 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12166 // backwards compat
12167 Roo.MenuButton = Roo.SplitButton;/*
12169 * Ext JS Library 1.1.1
12170 * Copyright(c) 2006-2007, Ext JS, LLC.
12172 * Originally Released Under LGPL - original licence link has changed is not relivant.
12175 * <script type="text/javascript">
12179 * @class Roo.Toolbar
12180 * Basic Toolbar class.
12182 * Creates a new Toolbar
12183 * @param {Object} config The config object
12185 Roo.Toolbar = function(container, buttons, config)
12187 /// old consturctor format still supported..
12188 if(container instanceof Array){ // omit the container for later rendering
12189 buttons = container;
12193 if (typeof(container) == 'object' && container.xtype) {
12194 config = container;
12195 container = config.container;
12196 buttons = config.buttons; // not really - use items!!
12199 if (config && config.items) {
12200 xitems = config.items;
12201 delete config.items;
12203 Roo.apply(this, config);
12204 this.buttons = buttons;
12207 this.render(container);
12209 Roo.each(xitems, function(b) {
12215 Roo.Toolbar.prototype = {
12217 * @cfg {Roo.data.Store} items
12218 * array of button configs or elements to add
12222 * @cfg {String/HTMLElement/Element} container
12223 * The id or element that will contain the toolbar
12226 render : function(ct){
12227 this.el = Roo.get(ct);
12229 this.el.addClass(this.cls);
12231 // using a table allows for vertical alignment
12232 // 100% width is needed by Safari...
12233 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12234 this.tr = this.el.child("tr", true);
12236 this.items = new Roo.util.MixedCollection(false, function(o){
12237 return o.id || ("item" + (++autoId));
12240 this.add.apply(this, this.buttons);
12241 delete this.buttons;
12246 * Adds element(s) to the toolbar -- this function takes a variable number of
12247 * arguments of mixed type and adds them to the toolbar.
12248 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12250 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12251 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12252 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12253 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12254 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12255 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12256 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12257 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12258 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12260 * @param {Mixed} arg2
12261 * @param {Mixed} etc.
12264 var a = arguments, l = a.length;
12265 for(var i = 0; i < l; i++){
12270 _add : function(el) {
12273 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12276 if (el.applyTo){ // some kind of form field
12277 return this.addField(el);
12279 if (el.render){ // some kind of Toolbar.Item
12280 return this.addItem(el);
12282 if (typeof el == "string"){ // string
12283 if(el == "separator" || el == "-"){
12284 return this.addSeparator();
12287 return this.addSpacer();
12290 return this.addFill();
12292 return this.addText(el);
12295 if(el.tagName){ // element
12296 return this.addElement(el);
12298 if(typeof el == "object"){ // must be button config?
12299 return this.addButton(el);
12301 // and now what?!?!
12307 * Add an Xtype element
12308 * @param {Object} xtype Xtype Object
12309 * @return {Object} created Object
12311 addxtype : function(e){
12312 return this.add(e);
12316 * Returns the Element for this toolbar.
12317 * @return {Roo.Element}
12319 getEl : function(){
12325 * @return {Roo.Toolbar.Item} The separator item
12327 addSeparator : function(){
12328 return this.addItem(new Roo.Toolbar.Separator());
12332 * Adds a spacer element
12333 * @return {Roo.Toolbar.Spacer} The spacer item
12335 addSpacer : function(){
12336 return this.addItem(new Roo.Toolbar.Spacer());
12340 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12341 * @return {Roo.Toolbar.Fill} The fill item
12343 addFill : function(){
12344 return this.addItem(new Roo.Toolbar.Fill());
12348 * Adds any standard HTML element to the toolbar
12349 * @param {String/HTMLElement/Element} el The element or id of the element to add
12350 * @return {Roo.Toolbar.Item} The element's item
12352 addElement : function(el){
12353 return this.addItem(new Roo.Toolbar.Item(el));
12356 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12357 * @type Roo.util.MixedCollection
12362 * Adds any Toolbar.Item or subclass
12363 * @param {Roo.Toolbar.Item} item
12364 * @return {Roo.Toolbar.Item} The item
12366 addItem : function(item){
12367 var td = this.nextBlock();
12369 this.items.add(item);
12374 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12375 * @param {Object/Array} config A button config or array of configs
12376 * @return {Roo.Toolbar.Button/Array}
12378 addButton : function(config){
12379 if(config instanceof Array){
12381 for(var i = 0, len = config.length; i < len; i++) {
12382 buttons.push(this.addButton(config[i]));
12387 if(!(config instanceof Roo.Toolbar.Button)){
12389 new Roo.Toolbar.SplitButton(config) :
12390 new Roo.Toolbar.Button(config);
12392 var td = this.nextBlock();
12399 * Adds text to the toolbar
12400 * @param {String} text The text to add
12401 * @return {Roo.Toolbar.Item} The element's item
12403 addText : function(text){
12404 return this.addItem(new Roo.Toolbar.TextItem(text));
12408 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12409 * @param {Number} index The index where the item is to be inserted
12410 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12411 * @return {Roo.Toolbar.Button/Item}
12413 insertButton : function(index, item){
12414 if(item instanceof Array){
12416 for(var i = 0, len = item.length; i < len; i++) {
12417 buttons.push(this.insertButton(index + i, item[i]));
12421 if (!(item instanceof Roo.Toolbar.Button)){
12422 item = new Roo.Toolbar.Button(item);
12424 var td = document.createElement("td");
12425 this.tr.insertBefore(td, this.tr.childNodes[index]);
12427 this.items.insert(index, item);
12432 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12433 * @param {Object} config
12434 * @return {Roo.Toolbar.Item} The element's item
12436 addDom : function(config, returnEl){
12437 var td = this.nextBlock();
12438 Roo.DomHelper.overwrite(td, config);
12439 var ti = new Roo.Toolbar.Item(td.firstChild);
12441 this.items.add(ti);
12446 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12447 * @type Roo.util.MixedCollection
12452 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12453 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12454 * @param {Roo.form.Field} field
12455 * @return {Roo.ToolbarItem}
12459 addField : function(field) {
12460 if (!this.fields) {
12462 this.fields = new Roo.util.MixedCollection(false, function(o){
12463 return o.id || ("item" + (++autoId));
12468 var td = this.nextBlock();
12470 var ti = new Roo.Toolbar.Item(td.firstChild);
12472 this.items.add(ti);
12473 this.fields.add(field);
12484 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12485 this.el.child('div').hide();
12493 this.el.child('div').show();
12497 nextBlock : function(){
12498 var td = document.createElement("td");
12499 this.tr.appendChild(td);
12504 destroy : function(){
12505 if(this.items){ // rendered?
12506 Roo.destroy.apply(Roo, this.items.items);
12508 if(this.fields){ // rendered?
12509 Roo.destroy.apply(Roo, this.fields.items);
12511 Roo.Element.uncache(this.el, this.tr);
12516 * @class Roo.Toolbar.Item
12517 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12519 * Creates a new Item
12520 * @param {HTMLElement} el
12522 Roo.Toolbar.Item = function(el){
12523 this.el = Roo.getDom(el);
12524 this.id = Roo.id(this.el);
12525 this.hidden = false;
12528 Roo.Toolbar.Item.prototype = {
12531 * Get this item's HTML Element
12532 * @return {HTMLElement}
12534 getEl : function(){
12539 render : function(td){
12541 td.appendChild(this.el);
12545 * Removes and destroys this item.
12547 destroy : function(){
12548 this.td.parentNode.removeChild(this.td);
12555 this.hidden = false;
12556 this.td.style.display = "";
12563 this.hidden = true;
12564 this.td.style.display = "none";
12568 * Convenience function for boolean show/hide.
12569 * @param {Boolean} visible true to show/false to hide
12571 setVisible: function(visible){
12580 * Try to focus this item.
12582 focus : function(){
12583 Roo.fly(this.el).focus();
12587 * Disables this item.
12589 disable : function(){
12590 Roo.fly(this.td).addClass("x-item-disabled");
12591 this.disabled = true;
12592 this.el.disabled = true;
12596 * Enables this item.
12598 enable : function(){
12599 Roo.fly(this.td).removeClass("x-item-disabled");
12600 this.disabled = false;
12601 this.el.disabled = false;
12607 * @class Roo.Toolbar.Separator
12608 * @extends Roo.Toolbar.Item
12609 * A simple toolbar separator class
12611 * Creates a new Separator
12613 Roo.Toolbar.Separator = function(){
12614 var s = document.createElement("span");
12615 s.className = "ytb-sep";
12616 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12618 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12619 enable:Roo.emptyFn,
12620 disable:Roo.emptyFn,
12625 * @class Roo.Toolbar.Spacer
12626 * @extends Roo.Toolbar.Item
12627 * A simple element that adds extra horizontal space to a toolbar.
12629 * Creates a new Spacer
12631 Roo.Toolbar.Spacer = function(){
12632 var s = document.createElement("div");
12633 s.className = "ytb-spacer";
12634 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12636 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12637 enable:Roo.emptyFn,
12638 disable:Roo.emptyFn,
12643 * @class Roo.Toolbar.Fill
12644 * @extends Roo.Toolbar.Spacer
12645 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12647 * Creates a new Spacer
12649 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12651 render : function(td){
12652 td.style.width = '100%';
12653 Roo.Toolbar.Fill.superclass.render.call(this, td);
12658 * @class Roo.Toolbar.TextItem
12659 * @extends Roo.Toolbar.Item
12660 * A simple class that renders text directly into a toolbar.
12662 * Creates a new TextItem
12663 * @param {String} text
12665 Roo.Toolbar.TextItem = function(text){
12666 if (typeof(text) == 'object') {
12669 var s = document.createElement("span");
12670 s.className = "ytb-text";
12671 s.innerHTML = text;
12672 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12674 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12675 enable:Roo.emptyFn,
12676 disable:Roo.emptyFn,
12681 * @class Roo.Toolbar.Button
12682 * @extends Roo.Button
12683 * A button that renders into a toolbar.
12685 * Creates a new Button
12686 * @param {Object} config A standard {@link Roo.Button} config object
12688 Roo.Toolbar.Button = function(config){
12689 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12691 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12692 render : function(td){
12694 Roo.Toolbar.Button.superclass.render.call(this, td);
12698 * Removes and destroys this button
12700 destroy : function(){
12701 Roo.Toolbar.Button.superclass.destroy.call(this);
12702 this.td.parentNode.removeChild(this.td);
12706 * Shows this button
12709 this.hidden = false;
12710 this.td.style.display = "";
12714 * Hides this button
12717 this.hidden = true;
12718 this.td.style.display = "none";
12722 * Disables this item
12724 disable : function(){
12725 Roo.fly(this.td).addClass("x-item-disabled");
12726 this.disabled = true;
12730 * Enables this item
12732 enable : function(){
12733 Roo.fly(this.td).removeClass("x-item-disabled");
12734 this.disabled = false;
12737 // backwards compat
12738 Roo.ToolbarButton = Roo.Toolbar.Button;
12741 * @class Roo.Toolbar.SplitButton
12742 * @extends Roo.SplitButton
12743 * A menu button that renders into a toolbar.
12745 * Creates a new SplitButton
12746 * @param {Object} config A standard {@link Roo.SplitButton} config object
12748 Roo.Toolbar.SplitButton = function(config){
12749 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12751 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12752 render : function(td){
12754 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12758 * Removes and destroys this button
12760 destroy : function(){
12761 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12762 this.td.parentNode.removeChild(this.td);
12766 * Shows this button
12769 this.hidden = false;
12770 this.td.style.display = "";
12774 * Hides this button
12777 this.hidden = true;
12778 this.td.style.display = "none";
12782 // backwards compat
12783 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12785 * Ext JS Library 1.1.1
12786 * Copyright(c) 2006-2007, Ext JS, LLC.
12788 * Originally Released Under LGPL - original licence link has changed is not relivant.
12791 * <script type="text/javascript">
12795 * @class Roo.PagingToolbar
12796 * @extends Roo.Toolbar
12797 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12799 * Create a new PagingToolbar
12800 * @param {Object} config The config object
12802 Roo.PagingToolbar = function(el, ds, config)
12804 // old args format still supported... - xtype is prefered..
12805 if (typeof(el) == 'object' && el.xtype) {
12806 // created from xtype...
12808 ds = el.dataSource;
12809 el = config.container;
12812 if (config.items) {
12813 items = config.items;
12817 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12820 this.renderButtons(this.el);
12823 // supprot items array.
12825 Roo.each(items, function(e) {
12826 this.add(Roo.factory(e));
12831 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12833 * @cfg {Roo.data.Store} dataSource
12834 * The underlying data store providing the paged data
12837 * @cfg {String/HTMLElement/Element} container
12838 * container The id or element that will contain the toolbar
12841 * @cfg {Boolean} displayInfo
12842 * True to display the displayMsg (defaults to false)
12845 * @cfg {Number} pageSize
12846 * The number of records to display per page (defaults to 20)
12850 * @cfg {String} displayMsg
12851 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12853 displayMsg : 'Displaying {0} - {1} of {2}',
12855 * @cfg {String} emptyMsg
12856 * The message to display when no records are found (defaults to "No data to display")
12858 emptyMsg : 'No data to display',
12860 * Customizable piece of the default paging text (defaults to "Page")
12863 beforePageText : "Page",
12865 * Customizable piece of the default paging text (defaults to "of %0")
12868 afterPageText : "of {0}",
12870 * Customizable piece of the default paging text (defaults to "First Page")
12873 firstText : "First Page",
12875 * Customizable piece of the default paging text (defaults to "Previous Page")
12878 prevText : "Previous Page",
12880 * Customizable piece of the default paging text (defaults to "Next Page")
12883 nextText : "Next Page",
12885 * Customizable piece of the default paging text (defaults to "Last Page")
12888 lastText : "Last Page",
12890 * Customizable piece of the default paging text (defaults to "Refresh")
12893 refreshText : "Refresh",
12896 renderButtons : function(el){
12897 Roo.PagingToolbar.superclass.render.call(this, el);
12898 this.first = this.addButton({
12899 tooltip: this.firstText,
12900 cls: "x-btn-icon x-grid-page-first",
12902 handler: this.onClick.createDelegate(this, ["first"])
12904 this.prev = this.addButton({
12905 tooltip: this.prevText,
12906 cls: "x-btn-icon x-grid-page-prev",
12908 handler: this.onClick.createDelegate(this, ["prev"])
12910 //this.addSeparator();
12911 this.add(this.beforePageText);
12912 this.field = Roo.get(this.addDom({
12917 cls: "x-grid-page-number"
12919 this.field.on("keydown", this.onPagingKeydown, this);
12920 this.field.on("focus", function(){this.dom.select();});
12921 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12922 this.field.setHeight(18);
12923 //this.addSeparator();
12924 this.next = this.addButton({
12925 tooltip: this.nextText,
12926 cls: "x-btn-icon x-grid-page-next",
12928 handler: this.onClick.createDelegate(this, ["next"])
12930 this.last = this.addButton({
12931 tooltip: this.lastText,
12932 cls: "x-btn-icon x-grid-page-last",
12934 handler: this.onClick.createDelegate(this, ["last"])
12936 //this.addSeparator();
12937 this.loading = this.addButton({
12938 tooltip: this.refreshText,
12939 cls: "x-btn-icon x-grid-loading",
12940 handler: this.onClick.createDelegate(this, ["refresh"])
12943 if(this.displayInfo){
12944 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12949 updateInfo : function(){
12950 if(this.displayEl){
12951 var count = this.ds.getCount();
12952 var msg = count == 0 ?
12956 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12958 this.displayEl.update(msg);
12963 onLoad : function(ds, r, o){
12964 this.cursor = o.params ? o.params.start : 0;
12965 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12967 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12968 this.field.dom.value = ap;
12969 this.first.setDisabled(ap == 1);
12970 this.prev.setDisabled(ap == 1);
12971 this.next.setDisabled(ap == ps);
12972 this.last.setDisabled(ap == ps);
12973 this.loading.enable();
12978 getPageData : function(){
12979 var total = this.ds.getTotalCount();
12982 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12983 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12988 onLoadError : function(){
12989 this.loading.enable();
12993 onPagingKeydown : function(e){
12994 var k = e.getKey();
12995 var d = this.getPageData();
12997 var v = this.field.dom.value, pageNum;
12998 if(!v || isNaN(pageNum = parseInt(v, 10))){
12999 this.field.dom.value = d.activePage;
13002 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13003 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13006 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))
13008 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13009 this.field.dom.value = pageNum;
13010 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13013 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13015 var v = this.field.dom.value, pageNum;
13016 var increment = (e.shiftKey) ? 10 : 1;
13017 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13019 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13020 this.field.dom.value = d.activePage;
13023 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13025 this.field.dom.value = parseInt(v, 10) + increment;
13026 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13027 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13034 beforeLoad : function(){
13036 this.loading.disable();
13041 onClick : function(which){
13045 ds.load({params:{start: 0, limit: this.pageSize}});
13048 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13051 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13054 var total = ds.getTotalCount();
13055 var extra = total % this.pageSize;
13056 var lastStart = extra ? (total - extra) : total-this.pageSize;
13057 ds.load({params:{start: lastStart, limit: this.pageSize}});
13060 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13066 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13067 * @param {Roo.data.Store} store The data store to unbind
13069 unbind : function(ds){
13070 ds.un("beforeload", this.beforeLoad, this);
13071 ds.un("load", this.onLoad, this);
13072 ds.un("loadexception", this.onLoadError, this);
13073 ds.un("remove", this.updateInfo, this);
13074 ds.un("add", this.updateInfo, this);
13075 this.ds = undefined;
13079 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13080 * @param {Roo.data.Store} store The data store to bind
13082 bind : function(ds){
13083 ds.on("beforeload", this.beforeLoad, this);
13084 ds.on("load", this.onLoad, this);
13085 ds.on("loadexception", this.onLoadError, this);
13086 ds.on("remove", this.updateInfo, this);
13087 ds.on("add", this.updateInfo, this);
13092 * Ext JS Library 1.1.1
13093 * Copyright(c) 2006-2007, Ext JS, LLC.
13095 * Originally Released Under LGPL - original licence link has changed is not relivant.
13098 * <script type="text/javascript">
13102 * @class Roo.Resizable
13103 * @extends Roo.util.Observable
13104 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13105 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13106 * 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
13107 * the element will be wrapped for you automatically.</p>
13108 * <p>Here is the list of valid resize handles:</p>
13111 ------ -------------------
13120 'hd' horizontal drag
13123 * <p>Here's an example showing the creation of a typical Resizable:</p>
13125 var resizer = new Roo.Resizable("element-id", {
13133 resizer.on("resize", myHandler);
13135 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13136 * resizer.east.setDisplayed(false);</p>
13137 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13138 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13139 * resize operation's new size (defaults to [0, 0])
13140 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13141 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13142 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13143 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13144 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13145 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13146 * @cfg {Number} width The width of the element in pixels (defaults to null)
13147 * @cfg {Number} height The height of the element in pixels (defaults to null)
13148 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13149 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13150 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13151 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13152 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13153 * in favor of the handles config option (defaults to false)
13154 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13155 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13156 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13157 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13158 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13159 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13160 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13161 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13162 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13163 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13164 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13166 * Create a new resizable component
13167 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13168 * @param {Object} config configuration options
13170 Roo.Resizable = function(el, config)
13172 this.el = Roo.get(el);
13174 if(config && config.wrap){
13175 config.resizeChild = this.el;
13176 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13177 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13178 this.el.setStyle("overflow", "hidden");
13179 this.el.setPositioning(config.resizeChild.getPositioning());
13180 config.resizeChild.clearPositioning();
13181 if(!config.width || !config.height){
13182 var csize = config.resizeChild.getSize();
13183 this.el.setSize(csize.width, csize.height);
13185 if(config.pinned && !config.adjustments){
13186 config.adjustments = "auto";
13190 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13191 this.proxy.unselectable();
13192 this.proxy.enableDisplayMode('block');
13194 Roo.apply(this, config);
13197 this.disableTrackOver = true;
13198 this.el.addClass("x-resizable-pinned");
13200 // if the element isn't positioned, make it relative
13201 var position = this.el.getStyle("position");
13202 if(position != "absolute" && position != "fixed"){
13203 this.el.setStyle("position", "relative");
13205 if(!this.handles){ // no handles passed, must be legacy style
13206 this.handles = 's,e,se';
13207 if(this.multiDirectional){
13208 this.handles += ',n,w';
13211 if(this.handles == "all"){
13212 this.handles = "n s e w ne nw se sw";
13214 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13215 var ps = Roo.Resizable.positions;
13216 for(var i = 0, len = hs.length; i < len; i++){
13217 if(hs[i] && ps[hs[i]]){
13218 var pos = ps[hs[i]];
13219 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13223 this.corner = this.southeast;
13225 // updateBox = the box can move..
13226 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13227 this.updateBox = true;
13230 this.activeHandle = null;
13232 if(this.resizeChild){
13233 if(typeof this.resizeChild == "boolean"){
13234 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13236 this.resizeChild = Roo.get(this.resizeChild, true);
13240 if(this.adjustments == "auto"){
13241 var rc = this.resizeChild;
13242 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13243 if(rc && (hw || hn)){
13244 rc.position("relative");
13245 rc.setLeft(hw ? hw.el.getWidth() : 0);
13246 rc.setTop(hn ? hn.el.getHeight() : 0);
13248 this.adjustments = [
13249 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13250 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13254 if(this.draggable){
13255 this.dd = this.dynamic ?
13256 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13257 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13263 * @event beforeresize
13264 * Fired before resize is allowed. Set enabled to false to cancel resize.
13265 * @param {Roo.Resizable} this
13266 * @param {Roo.EventObject} e The mousedown event
13268 "beforeresize" : true,
13271 * Fired after a resize.
13272 * @param {Roo.Resizable} this
13273 * @param {Number} width The new width
13274 * @param {Number} height The new height
13275 * @param {Roo.EventObject} e The mouseup event
13280 if(this.width !== null && this.height !== null){
13281 this.resizeTo(this.width, this.height);
13283 this.updateChildSize();
13286 this.el.dom.style.zoom = 1;
13288 Roo.Resizable.superclass.constructor.call(this);
13291 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13292 resizeChild : false,
13293 adjustments : [0, 0],
13303 multiDirectional : false,
13304 disableTrackOver : false,
13305 easing : 'easeOutStrong',
13306 widthIncrement : 0,
13307 heightIncrement : 0,
13311 preserveRatio : false,
13312 transparent: false,
13318 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13320 constrainTo: undefined,
13322 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13324 resizeRegion: undefined,
13328 * Perform a manual resize
13329 * @param {Number} width
13330 * @param {Number} height
13332 resizeTo : function(width, height){
13333 this.el.setSize(width, height);
13334 this.updateChildSize();
13335 this.fireEvent("resize", this, width, height, null);
13339 startSizing : function(e, handle){
13340 this.fireEvent("beforeresize", this, e);
13341 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13344 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13345 this.overlay.unselectable();
13346 this.overlay.enableDisplayMode("block");
13347 this.overlay.on("mousemove", this.onMouseMove, this);
13348 this.overlay.on("mouseup", this.onMouseUp, this);
13350 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13352 this.resizing = true;
13353 this.startBox = this.el.getBox();
13354 this.startPoint = e.getXY();
13355 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13356 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13358 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13359 this.overlay.show();
13361 if(this.constrainTo) {
13362 var ct = Roo.get(this.constrainTo);
13363 this.resizeRegion = ct.getRegion().adjust(
13364 ct.getFrameWidth('t'),
13365 ct.getFrameWidth('l'),
13366 -ct.getFrameWidth('b'),
13367 -ct.getFrameWidth('r')
13371 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13373 this.proxy.setBox(this.startBox);
13375 this.proxy.setStyle('visibility', 'visible');
13381 onMouseDown : function(handle, e){
13384 this.activeHandle = handle;
13385 this.startSizing(e, handle);
13390 onMouseUp : function(e){
13391 var size = this.resizeElement();
13392 this.resizing = false;
13394 this.overlay.hide();
13396 this.fireEvent("resize", this, size.width, size.height, e);
13400 updateChildSize : function(){
13401 if(this.resizeChild){
13403 var child = this.resizeChild;
13404 var adj = this.adjustments;
13405 if(el.dom.offsetWidth){
13406 var b = el.getSize(true);
13407 child.setSize(b.width+adj[0], b.height+adj[1]);
13409 // Second call here for IE
13410 // The first call enables instant resizing and
13411 // the second call corrects scroll bars if they
13414 setTimeout(function(){
13415 if(el.dom.offsetWidth){
13416 var b = el.getSize(true);
13417 child.setSize(b.width+adj[0], b.height+adj[1]);
13425 snap : function(value, inc, min){
13426 if(!inc || !value) return value;
13427 var newValue = value;
13428 var m = value % inc;
13431 newValue = value + (inc-m);
13433 newValue = value - m;
13436 return Math.max(min, newValue);
13440 resizeElement : function(){
13441 var box = this.proxy.getBox();
13442 if(this.updateBox){
13443 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13445 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13447 this.updateChildSize();
13455 constrain : function(v, diff, m, mx){
13458 }else if(v - diff > mx){
13465 onMouseMove : function(e){
13467 try{// try catch so if something goes wrong the user doesn't get hung
13469 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13473 //var curXY = this.startPoint;
13474 var curSize = this.curSize || this.startBox;
13475 var x = this.startBox.x, y = this.startBox.y;
13476 var ox = x, oy = y;
13477 var w = curSize.width, h = curSize.height;
13478 var ow = w, oh = h;
13479 var mw = this.minWidth, mh = this.minHeight;
13480 var mxw = this.maxWidth, mxh = this.maxHeight;
13481 var wi = this.widthIncrement;
13482 var hi = this.heightIncrement;
13484 var eventXY = e.getXY();
13485 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13486 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13488 var pos = this.activeHandle.position;
13493 w = Math.min(Math.max(mw, w), mxw);
13498 h = Math.min(Math.max(mh, h), mxh);
13503 w = Math.min(Math.max(mw, w), mxw);
13504 h = Math.min(Math.max(mh, h), mxh);
13507 diffY = this.constrain(h, diffY, mh, mxh);
13514 var adiffX = Math.abs(diffX);
13515 var sub = (adiffX % wi); // how much
13516 if (sub > (wi/2)) { // far enough to snap
13517 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13519 // remove difference..
13520 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13524 x = Math.max(this.minX, x);
13527 diffX = this.constrain(w, diffX, mw, mxw);
13533 w = Math.min(Math.max(mw, w), mxw);
13534 diffY = this.constrain(h, diffY, mh, mxh);
13539 diffX = this.constrain(w, diffX, mw, mxw);
13540 diffY = this.constrain(h, diffY, mh, mxh);
13547 diffX = this.constrain(w, diffX, mw, mxw);
13549 h = Math.min(Math.max(mh, h), mxh);
13555 var sw = this.snap(w, wi, mw);
13556 var sh = this.snap(h, hi, mh);
13557 if(sw != w || sh != h){
13580 if(this.preserveRatio){
13585 h = Math.min(Math.max(mh, h), mxh);
13590 w = Math.min(Math.max(mw, w), mxw);
13595 w = Math.min(Math.max(mw, w), mxw);
13601 w = Math.min(Math.max(mw, w), mxw);
13607 h = Math.min(Math.max(mh, h), mxh);
13615 h = Math.min(Math.max(mh, h), mxh);
13625 h = Math.min(Math.max(mh, h), mxh);
13633 if (pos == 'hdrag') {
13636 this.proxy.setBounds(x, y, w, h);
13638 this.resizeElement();
13645 handleOver : function(){
13647 this.el.addClass("x-resizable-over");
13652 handleOut : function(){
13653 if(!this.resizing){
13654 this.el.removeClass("x-resizable-over");
13659 * Returns the element this component is bound to.
13660 * @return {Roo.Element}
13662 getEl : function(){
13667 * Returns the resizeChild element (or null).
13668 * @return {Roo.Element}
13670 getResizeChild : function(){
13671 return this.resizeChild;
13675 * Destroys this resizable. If the element was wrapped and
13676 * removeEl is not true then the element remains.
13677 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13679 destroy : function(removeEl){
13680 this.proxy.remove();
13682 this.overlay.removeAllListeners();
13683 this.overlay.remove();
13685 var ps = Roo.Resizable.positions;
13687 if(typeof ps[k] != "function" && this[ps[k]]){
13688 var h = this[ps[k]];
13689 h.el.removeAllListeners();
13694 this.el.update("");
13701 // hash to map config positions to true positions
13702 Roo.Resizable.positions = {
13703 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13708 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13710 // only initialize the template if resizable is used
13711 var tpl = Roo.DomHelper.createTemplate(
13712 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13715 Roo.Resizable.Handle.prototype.tpl = tpl;
13717 this.position = pos;
13719 // show north drag fro topdra
13720 var handlepos = pos == 'hdrag' ? 'north' : pos;
13722 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13723 if (pos == 'hdrag') {
13724 this.el.setStyle('cursor', 'pointer');
13726 this.el.unselectable();
13728 this.el.setOpacity(0);
13730 this.el.on("mousedown", this.onMouseDown, this);
13731 if(!disableTrackOver){
13732 this.el.on("mouseover", this.onMouseOver, this);
13733 this.el.on("mouseout", this.onMouseOut, this);
13738 Roo.Resizable.Handle.prototype = {
13739 afterResize : function(rz){
13743 onMouseDown : function(e){
13744 this.rz.onMouseDown(this, e);
13747 onMouseOver : function(e){
13748 this.rz.handleOver(this, e);
13751 onMouseOut : function(e){
13752 this.rz.handleOut(this, e);
13756 * Ext JS Library 1.1.1
13757 * Copyright(c) 2006-2007, Ext JS, LLC.
13759 * Originally Released Under LGPL - original licence link has changed is not relivant.
13762 * <script type="text/javascript">
13766 * @class Roo.Editor
13767 * @extends Roo.Component
13768 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13770 * Create a new Editor
13771 * @param {Roo.form.Field} field The Field object (or descendant)
13772 * @param {Object} config The config object
13774 Roo.Editor = function(field, config){
13775 Roo.Editor.superclass.constructor.call(this, config);
13776 this.field = field;
13779 * @event beforestartedit
13780 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13781 * false from the handler of this event.
13782 * @param {Editor} this
13783 * @param {Roo.Element} boundEl The underlying element bound to this editor
13784 * @param {Mixed} value The field value being set
13786 "beforestartedit" : true,
13789 * Fires when this editor is displayed
13790 * @param {Roo.Element} boundEl The underlying element bound to this editor
13791 * @param {Mixed} value The starting field value
13793 "startedit" : true,
13795 * @event beforecomplete
13796 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13797 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13798 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13799 * event will not fire since no edit actually occurred.
13800 * @param {Editor} this
13801 * @param {Mixed} value The current field value
13802 * @param {Mixed} startValue The original field value
13804 "beforecomplete" : true,
13807 * Fires after editing is complete and any changed value has been written to the underlying field.
13808 * @param {Editor} this
13809 * @param {Mixed} value The current field value
13810 * @param {Mixed} startValue The original field value
13814 * @event specialkey
13815 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13816 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13817 * @param {Roo.form.Field} this
13818 * @param {Roo.EventObject} e The event object
13820 "specialkey" : true
13824 Roo.extend(Roo.Editor, Roo.Component, {
13826 * @cfg {Boolean/String} autosize
13827 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13828 * or "height" to adopt the height only (defaults to false)
13831 * @cfg {Boolean} revertInvalid
13832 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13833 * validation fails (defaults to true)
13836 * @cfg {Boolean} ignoreNoChange
13837 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13838 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13839 * will never be ignored.
13842 * @cfg {Boolean} hideEl
13843 * False to keep the bound element visible while the editor is displayed (defaults to true)
13846 * @cfg {Mixed} value
13847 * The data value of the underlying field (defaults to "")
13851 * @cfg {String} alignment
13852 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13856 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13857 * for bottom-right shadow (defaults to "frame")
13861 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13865 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13867 completeOnEnter : false,
13869 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13871 cancelOnEsc : false,
13873 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13878 onRender : function(ct, position){
13879 this.el = new Roo.Layer({
13880 shadow: this.shadow,
13886 constrain: this.constrain
13888 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13889 if(this.field.msgTarget != 'title'){
13890 this.field.msgTarget = 'qtip';
13892 this.field.render(this.el);
13894 this.field.el.dom.setAttribute('autocomplete', 'off');
13896 this.field.on("specialkey", this.onSpecialKey, this);
13897 if(this.swallowKeys){
13898 this.field.el.swallowEvent(['keydown','keypress']);
13901 this.field.on("blur", this.onBlur, this);
13902 if(this.field.grow){
13903 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13907 onSpecialKey : function(field, e){
13908 //Roo.log('editor onSpecialKey');
13909 if(this.completeOnEnter && e.getKey() == e.ENTER){
13911 this.completeEdit();
13912 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13915 this.fireEvent('specialkey', field, e);
13920 * Starts the editing process and shows the editor.
13921 * @param {String/HTMLElement/Element} el The element to edit
13922 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13923 * to the innerHTML of el.
13925 startEdit : function(el, value){
13927 this.completeEdit();
13929 this.boundEl = Roo.get(el);
13930 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13931 if(!this.rendered){
13932 this.render(this.parentEl || document.body);
13934 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13937 this.startValue = v;
13938 this.field.setValue(v);
13940 var sz = this.boundEl.getSize();
13941 switch(this.autoSize){
13943 this.setSize(sz.width, "");
13946 this.setSize("", sz.height);
13949 this.setSize(sz.width, sz.height);
13952 this.el.alignTo(this.boundEl, this.alignment);
13953 this.editing = true;
13955 Roo.QuickTips.disable();
13961 * Sets the height and width of this editor.
13962 * @param {Number} width The new width
13963 * @param {Number} height The new height
13965 setSize : function(w, h){
13966 this.field.setSize(w, h);
13973 * Realigns the editor to the bound field based on the current alignment config value.
13975 realign : function(){
13976 this.el.alignTo(this.boundEl, this.alignment);
13980 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13981 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13983 completeEdit : function(remainVisible){
13987 var v = this.getValue();
13988 if(this.revertInvalid !== false && !this.field.isValid()){
13989 v = this.startValue;
13990 this.cancelEdit(true);
13992 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13993 this.editing = false;
13997 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13998 this.editing = false;
13999 if(this.updateEl && this.boundEl){
14000 this.boundEl.update(v);
14002 if(remainVisible !== true){
14005 this.fireEvent("complete", this, v, this.startValue);
14010 onShow : function(){
14012 if(this.hideEl !== false){
14013 this.boundEl.hide();
14016 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14017 this.fixIEFocus = true;
14018 this.deferredFocus.defer(50, this);
14020 this.field.focus();
14022 this.fireEvent("startedit", this.boundEl, this.startValue);
14025 deferredFocus : function(){
14027 this.field.focus();
14032 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14033 * reverted to the original starting value.
14034 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14035 * cancel (defaults to false)
14037 cancelEdit : function(remainVisible){
14039 this.setValue(this.startValue);
14040 if(remainVisible !== true){
14047 onBlur : function(){
14048 if(this.allowBlur !== true && this.editing){
14049 this.completeEdit();
14054 onHide : function(){
14056 this.completeEdit();
14060 if(this.field.collapse){
14061 this.field.collapse();
14064 if(this.hideEl !== false){
14065 this.boundEl.show();
14068 Roo.QuickTips.enable();
14073 * Sets the data value of the editor
14074 * @param {Mixed} value Any valid value supported by the underlying field
14076 setValue : function(v){
14077 this.field.setValue(v);
14081 * Gets the data value of the editor
14082 * @return {Mixed} The data value
14084 getValue : function(){
14085 return this.field.getValue();
14089 * Ext JS Library 1.1.1
14090 * Copyright(c) 2006-2007, Ext JS, LLC.
14092 * Originally Released Under LGPL - original licence link has changed is not relivant.
14095 * <script type="text/javascript">
14099 * @class Roo.BasicDialog
14100 * @extends Roo.util.Observable
14101 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14103 var dlg = new Roo.BasicDialog("my-dlg", {
14112 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14113 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14114 dlg.addButton('Cancel', dlg.hide, dlg);
14117 <b>A Dialog should always be a direct child of the body element.</b>
14118 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14119 * @cfg {String} title Default text to display in the title bar (defaults to null)
14120 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14121 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14122 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14123 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14124 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14125 * (defaults to null with no animation)
14126 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14127 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14128 * property for valid values (defaults to 'all')
14129 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14130 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14131 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14132 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14133 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14134 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14135 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14136 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14137 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14138 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14139 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14140 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14141 * draggable = true (defaults to false)
14142 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14143 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14144 * shadow (defaults to false)
14145 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14146 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14147 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14148 * @cfg {Array} buttons Array of buttons
14149 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14151 * Create a new BasicDialog.
14152 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14153 * @param {Object} config Configuration options
14155 Roo.BasicDialog = function(el, config){
14156 this.el = Roo.get(el);
14157 var dh = Roo.DomHelper;
14158 if(!this.el && config && config.autoCreate){
14159 if(typeof config.autoCreate == "object"){
14160 if(!config.autoCreate.id){
14161 config.autoCreate.id = el;
14163 this.el = dh.append(document.body,
14164 config.autoCreate, true);
14166 this.el = dh.append(document.body,
14167 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14171 el.setDisplayed(true);
14172 el.hide = this.hideAction;
14174 el.addClass("x-dlg");
14176 Roo.apply(this, config);
14178 this.proxy = el.createProxy("x-dlg-proxy");
14179 this.proxy.hide = this.hideAction;
14180 this.proxy.setOpacity(.5);
14184 el.setWidth(config.width);
14187 el.setHeight(config.height);
14189 this.size = el.getSize();
14190 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14191 this.xy = [config.x,config.y];
14193 this.xy = el.getCenterXY(true);
14195 /** The header element @type Roo.Element */
14196 this.header = el.child("> .x-dlg-hd");
14197 /** The body element @type Roo.Element */
14198 this.body = el.child("> .x-dlg-bd");
14199 /** The footer element @type Roo.Element */
14200 this.footer = el.child("> .x-dlg-ft");
14203 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14206 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14209 this.header.unselectable();
14211 this.header.update(this.title);
14213 // this element allows the dialog to be focused for keyboard event
14214 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14215 this.focusEl.swallowEvent("click", true);
14217 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14219 // wrap the body and footer for special rendering
14220 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14222 this.bwrap.dom.appendChild(this.footer.dom);
14225 this.bg = this.el.createChild({
14226 tag: "div", cls:"x-dlg-bg",
14227 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14229 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14232 if(this.autoScroll !== false && !this.autoTabs){
14233 this.body.setStyle("overflow", "auto");
14236 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14238 if(this.closable !== false){
14239 this.el.addClass("x-dlg-closable");
14240 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14241 this.close.on("click", this.closeClick, this);
14242 this.close.addClassOnOver("x-dlg-close-over");
14244 if(this.collapsible !== false){
14245 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14246 this.collapseBtn.on("click", this.collapseClick, this);
14247 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14248 this.header.on("dblclick", this.collapseClick, this);
14250 if(this.resizable !== false){
14251 this.el.addClass("x-dlg-resizable");
14252 this.resizer = new Roo.Resizable(el, {
14253 minWidth: this.minWidth || 80,
14254 minHeight:this.minHeight || 80,
14255 handles: this.resizeHandles || "all",
14258 this.resizer.on("beforeresize", this.beforeResize, this);
14259 this.resizer.on("resize", this.onResize, this);
14261 if(this.draggable !== false){
14262 el.addClass("x-dlg-draggable");
14263 if (!this.proxyDrag) {
14264 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14267 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14269 dd.setHandleElId(this.header.id);
14270 dd.endDrag = this.endMove.createDelegate(this);
14271 dd.startDrag = this.startMove.createDelegate(this);
14272 dd.onDrag = this.onDrag.createDelegate(this);
14277 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14278 this.mask.enableDisplayMode("block");
14280 this.el.addClass("x-dlg-modal");
14283 this.shadow = new Roo.Shadow({
14284 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14285 offset : this.shadowOffset
14288 this.shadowOffset = 0;
14290 if(Roo.useShims && this.shim !== false){
14291 this.shim = this.el.createShim();
14292 this.shim.hide = this.hideAction;
14300 if (this.buttons) {
14301 var bts= this.buttons;
14303 Roo.each(bts, function(b) {
14312 * Fires when a key is pressed
14313 * @param {Roo.BasicDialog} this
14314 * @param {Roo.EventObject} e
14319 * Fires when this dialog is moved by the user.
14320 * @param {Roo.BasicDialog} this
14321 * @param {Number} x The new page X
14322 * @param {Number} y The new page Y
14327 * Fires when this dialog is resized by the user.
14328 * @param {Roo.BasicDialog} this
14329 * @param {Number} width The new width
14330 * @param {Number} height The new height
14334 * @event beforehide
14335 * Fires before this dialog is hidden.
14336 * @param {Roo.BasicDialog} this
14338 "beforehide" : true,
14341 * Fires when this dialog is hidden.
14342 * @param {Roo.BasicDialog} this
14346 * @event beforeshow
14347 * Fires before this dialog is shown.
14348 * @param {Roo.BasicDialog} this
14350 "beforeshow" : true,
14353 * Fires when this dialog is shown.
14354 * @param {Roo.BasicDialog} this
14358 el.on("keydown", this.onKeyDown, this);
14359 el.on("mousedown", this.toFront, this);
14360 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14362 Roo.DialogManager.register(this);
14363 Roo.BasicDialog.superclass.constructor.call(this);
14366 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14367 shadowOffset: Roo.isIE ? 6 : 5,
14370 minButtonWidth: 75,
14371 defaultButton: null,
14372 buttonAlign: "right",
14377 * Sets the dialog title text
14378 * @param {String} text The title text to display
14379 * @return {Roo.BasicDialog} this
14381 setTitle : function(text){
14382 this.header.update(text);
14387 closeClick : function(){
14392 collapseClick : function(){
14393 this[this.collapsed ? "expand" : "collapse"]();
14397 * Collapses the dialog to its minimized state (only the title bar is visible).
14398 * Equivalent to the user clicking the collapse dialog button.
14400 collapse : function(){
14401 if(!this.collapsed){
14402 this.collapsed = true;
14403 this.el.addClass("x-dlg-collapsed");
14404 this.restoreHeight = this.el.getHeight();
14405 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14410 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14411 * clicking the expand dialog button.
14413 expand : function(){
14414 if(this.collapsed){
14415 this.collapsed = false;
14416 this.el.removeClass("x-dlg-collapsed");
14417 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14422 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14423 * @return {Roo.TabPanel} The tabs component
14425 initTabs : function(){
14426 var tabs = this.getTabs();
14427 while(tabs.getTab(0)){
14430 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14432 tabs.addTab(Roo.id(dom), dom.title);
14440 beforeResize : function(){
14441 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14445 onResize : function(){
14446 this.refreshSize();
14447 this.syncBodyHeight();
14448 this.adjustAssets();
14450 this.fireEvent("resize", this, this.size.width, this.size.height);
14454 onKeyDown : function(e){
14455 if(this.isVisible()){
14456 this.fireEvent("keydown", this, e);
14461 * Resizes the dialog.
14462 * @param {Number} width
14463 * @param {Number} height
14464 * @return {Roo.BasicDialog} this
14466 resizeTo : function(width, height){
14467 this.el.setSize(width, height);
14468 this.size = {width: width, height: height};
14469 this.syncBodyHeight();
14470 if(this.fixedcenter){
14473 if(this.isVisible()){
14474 this.constrainXY();
14475 this.adjustAssets();
14477 this.fireEvent("resize", this, width, height);
14483 * Resizes the dialog to fit the specified content size.
14484 * @param {Number} width
14485 * @param {Number} height
14486 * @return {Roo.BasicDialog} this
14488 setContentSize : function(w, h){
14489 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14490 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14491 //if(!this.el.isBorderBox()){
14492 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14493 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14496 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14497 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14499 this.resizeTo(w, h);
14504 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14505 * executed in response to a particular key being pressed while the dialog is active.
14506 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14507 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14508 * @param {Function} fn The function to call
14509 * @param {Object} scope (optional) The scope of the function
14510 * @return {Roo.BasicDialog} this
14512 addKeyListener : function(key, fn, scope){
14513 var keyCode, shift, ctrl, alt;
14514 if(typeof key == "object" && !(key instanceof Array)){
14515 keyCode = key["key"];
14516 shift = key["shift"];
14517 ctrl = key["ctrl"];
14522 var handler = function(dlg, e){
14523 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14524 var k = e.getKey();
14525 if(keyCode instanceof Array){
14526 for(var i = 0, len = keyCode.length; i < len; i++){
14527 if(keyCode[i] == k){
14528 fn.call(scope || window, dlg, k, e);
14534 fn.call(scope || window, dlg, k, e);
14539 this.on("keydown", handler);
14544 * Returns the TabPanel component (creates it if it doesn't exist).
14545 * Note: If you wish to simply check for the existence of tabs without creating them,
14546 * check for a null 'tabs' property.
14547 * @return {Roo.TabPanel} The tabs component
14549 getTabs : function(){
14551 this.el.addClass("x-dlg-auto-tabs");
14552 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14553 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14559 * Adds a button to the footer section of the dialog.
14560 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14561 * object or a valid Roo.DomHelper element config
14562 * @param {Function} handler The function called when the button is clicked
14563 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14564 * @return {Roo.Button} The new button
14566 addButton : function(config, handler, scope){
14567 var dh = Roo.DomHelper;
14569 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14571 if(!this.btnContainer){
14572 var tb = this.footer.createChild({
14574 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14575 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14577 this.btnContainer = tb.firstChild.firstChild.firstChild;
14582 minWidth: this.minButtonWidth,
14585 if(typeof config == "string"){
14586 bconfig.text = config;
14589 bconfig.dhconfig = config;
14591 Roo.apply(bconfig, config);
14595 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14596 bconfig.position = Math.max(0, bconfig.position);
14597 fc = this.btnContainer.childNodes[bconfig.position];
14600 var btn = new Roo.Button(
14602 this.btnContainer.insertBefore(document.createElement("td"),fc)
14603 : this.btnContainer.appendChild(document.createElement("td")),
14604 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14607 this.syncBodyHeight();
14610 * Array of all the buttons that have been added to this dialog via addButton
14615 this.buttons.push(btn);
14620 * Sets the default button to be focused when the dialog is displayed.
14621 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14622 * @return {Roo.BasicDialog} this
14624 setDefaultButton : function(btn){
14625 this.defaultButton = btn;
14630 getHeaderFooterHeight : function(safe){
14633 height += this.header.getHeight();
14636 var fm = this.footer.getMargins();
14637 height += (this.footer.getHeight()+fm.top+fm.bottom);
14639 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14640 height += this.centerBg.getPadding("tb");
14645 syncBodyHeight : function(){
14646 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14647 var height = this.size.height - this.getHeaderFooterHeight(false);
14648 bd.setHeight(height-bd.getMargins("tb"));
14649 var hh = this.header.getHeight();
14650 var h = this.size.height-hh;
14652 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14653 bw.setHeight(h-cb.getPadding("tb"));
14654 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14655 bd.setWidth(bw.getWidth(true));
14657 this.tabs.syncHeight();
14659 this.tabs.el.repaint();
14665 * Restores the previous state of the dialog if Roo.state is configured.
14666 * @return {Roo.BasicDialog} this
14668 restoreState : function(){
14669 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14670 if(box && box.width){
14671 this.xy = [box.x, box.y];
14672 this.resizeTo(box.width, box.height);
14678 beforeShow : function(){
14680 if(this.fixedcenter){
14681 this.xy = this.el.getCenterXY(true);
14684 Roo.get(document.body).addClass("x-body-masked");
14685 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14688 this.constrainXY();
14692 animShow : function(){
14693 var b = Roo.get(this.animateTarget).getBox();
14694 this.proxy.setSize(b.width, b.height);
14695 this.proxy.setLocation(b.x, b.y);
14697 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14698 true, .35, this.showEl.createDelegate(this));
14702 * Shows the dialog.
14703 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14704 * @return {Roo.BasicDialog} this
14706 show : function(animateTarget){
14707 if (this.fireEvent("beforeshow", this) === false){
14710 if(this.syncHeightBeforeShow){
14711 this.syncBodyHeight();
14712 }else if(this.firstShow){
14713 this.firstShow = false;
14714 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14716 this.animateTarget = animateTarget || this.animateTarget;
14717 if(!this.el.isVisible()){
14719 if(this.animateTarget && Roo.get(this.animateTarget)){
14729 showEl : function(){
14731 this.el.setXY(this.xy);
14733 this.adjustAssets(true);
14736 // IE peekaboo bug - fix found by Dave Fenwick
14740 this.fireEvent("show", this);
14744 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14745 * dialog itself will receive focus.
14747 focus : function(){
14748 if(this.defaultButton){
14749 this.defaultButton.focus();
14751 this.focusEl.focus();
14756 constrainXY : function(){
14757 if(this.constraintoviewport !== false){
14758 if(!this.viewSize){
14759 if(this.container){
14760 var s = this.container.getSize();
14761 this.viewSize = [s.width, s.height];
14763 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14766 var s = Roo.get(this.container||document).getScroll();
14768 var x = this.xy[0], y = this.xy[1];
14769 var w = this.size.width, h = this.size.height;
14770 var vw = this.viewSize[0], vh = this.viewSize[1];
14771 // only move it if it needs it
14773 // first validate right/bottom
14774 if(x + w > vw+s.left){
14778 if(y + h > vh+s.top){
14782 // then make sure top/left isn't negative
14794 if(this.isVisible()){
14795 this.el.setLocation(x, y);
14796 this.adjustAssets();
14803 onDrag : function(){
14804 if(!this.proxyDrag){
14805 this.xy = this.el.getXY();
14806 this.adjustAssets();
14811 adjustAssets : function(doShow){
14812 var x = this.xy[0], y = this.xy[1];
14813 var w = this.size.width, h = this.size.height;
14814 if(doShow === true){
14816 this.shadow.show(this.el);
14822 if(this.shadow && this.shadow.isVisible()){
14823 this.shadow.show(this.el);
14825 if(this.shim && this.shim.isVisible()){
14826 this.shim.setBounds(x, y, w, h);
14831 adjustViewport : function(w, h){
14833 w = Roo.lib.Dom.getViewWidth();
14834 h = Roo.lib.Dom.getViewHeight();
14837 this.viewSize = [w, h];
14838 if(this.modal && this.mask.isVisible()){
14839 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14840 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14842 if(this.isVisible()){
14843 this.constrainXY();
14848 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14849 * shadow, proxy, mask, etc.) Also removes all event listeners.
14850 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14852 destroy : function(removeEl){
14853 if(this.isVisible()){
14854 this.animateTarget = null;
14857 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14859 this.tabs.destroy(removeEl);
14872 for(var i = 0, len = this.buttons.length; i < len; i++){
14873 this.buttons[i].destroy();
14876 this.el.removeAllListeners();
14877 if(removeEl === true){
14878 this.el.update("");
14881 Roo.DialogManager.unregister(this);
14885 startMove : function(){
14886 if(this.proxyDrag){
14889 if(this.constraintoviewport !== false){
14890 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14895 endMove : function(){
14896 if(!this.proxyDrag){
14897 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14899 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14902 this.refreshSize();
14903 this.adjustAssets();
14905 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14909 * Brings this dialog to the front of any other visible dialogs
14910 * @return {Roo.BasicDialog} this
14912 toFront : function(){
14913 Roo.DialogManager.bringToFront(this);
14918 * Sends this dialog to the back (under) of any other visible dialogs
14919 * @return {Roo.BasicDialog} this
14921 toBack : function(){
14922 Roo.DialogManager.sendToBack(this);
14927 * Centers this dialog in the viewport
14928 * @return {Roo.BasicDialog} this
14930 center : function(){
14931 var xy = this.el.getCenterXY(true);
14932 this.moveTo(xy[0], xy[1]);
14937 * Moves the dialog's top-left corner to the specified point
14938 * @param {Number} x
14939 * @param {Number} y
14940 * @return {Roo.BasicDialog} this
14942 moveTo : function(x, y){
14944 if(this.isVisible()){
14945 this.el.setXY(this.xy);
14946 this.adjustAssets();
14952 * Aligns the dialog to the specified element
14953 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14954 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14955 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14956 * @return {Roo.BasicDialog} this
14958 alignTo : function(element, position, offsets){
14959 this.xy = this.el.getAlignToXY(element, position, offsets);
14960 if(this.isVisible()){
14961 this.el.setXY(this.xy);
14962 this.adjustAssets();
14968 * Anchors an element to another element and realigns it when the window is resized.
14969 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14970 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14971 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14972 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14973 * is a number, it is used as the buffer delay (defaults to 50ms).
14974 * @return {Roo.BasicDialog} this
14976 anchorTo : function(el, alignment, offsets, monitorScroll){
14977 var action = function(){
14978 this.alignTo(el, alignment, offsets);
14980 Roo.EventManager.onWindowResize(action, this);
14981 var tm = typeof monitorScroll;
14982 if(tm != 'undefined'){
14983 Roo.EventManager.on(window, 'scroll', action, this,
14984 {buffer: tm == 'number' ? monitorScroll : 50});
14991 * Returns true if the dialog is visible
14992 * @return {Boolean}
14994 isVisible : function(){
14995 return this.el.isVisible();
14999 animHide : function(callback){
15000 var b = Roo.get(this.animateTarget).getBox();
15002 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15004 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15005 this.hideEl.createDelegate(this, [callback]));
15009 * Hides the dialog.
15010 * @param {Function} callback (optional) Function to call when the dialog is hidden
15011 * @return {Roo.BasicDialog} this
15013 hide : function(callback){
15014 if (this.fireEvent("beforehide", this) === false){
15018 this.shadow.hide();
15023 // sometimes animateTarget seems to get set.. causing problems...
15024 // this just double checks..
15025 if(this.animateTarget && Roo.get(this.animateTarget)) {
15026 this.animHide(callback);
15029 this.hideEl(callback);
15035 hideEl : function(callback){
15039 Roo.get(document.body).removeClass("x-body-masked");
15041 this.fireEvent("hide", this);
15042 if(typeof callback == "function"){
15048 hideAction : function(){
15049 this.setLeft("-10000px");
15050 this.setTop("-10000px");
15051 this.setStyle("visibility", "hidden");
15055 refreshSize : function(){
15056 this.size = this.el.getSize();
15057 this.xy = this.el.getXY();
15058 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15062 // z-index is managed by the DialogManager and may be overwritten at any time
15063 setZIndex : function(index){
15065 this.mask.setStyle("z-index", index);
15068 this.shim.setStyle("z-index", ++index);
15071 this.shadow.setZIndex(++index);
15073 this.el.setStyle("z-index", ++index);
15075 this.proxy.setStyle("z-index", ++index);
15078 this.resizer.proxy.setStyle("z-index", ++index);
15081 this.lastZIndex = index;
15085 * Returns the element for this dialog
15086 * @return {Roo.Element} The underlying dialog Element
15088 getEl : function(){
15094 * @class Roo.DialogManager
15095 * Provides global access to BasicDialogs that have been created and
15096 * support for z-indexing (layering) multiple open dialogs.
15098 Roo.DialogManager = function(){
15100 var accessList = [];
15104 var sortDialogs = function(d1, d2){
15105 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15109 var orderDialogs = function(){
15110 accessList.sort(sortDialogs);
15111 var seed = Roo.DialogManager.zseed;
15112 for(var i = 0, len = accessList.length; i < len; i++){
15113 var dlg = accessList[i];
15115 dlg.setZIndex(seed + (i*10));
15122 * The starting z-index for BasicDialogs (defaults to 9000)
15123 * @type Number The z-index value
15128 register : function(dlg){
15129 list[dlg.id] = dlg;
15130 accessList.push(dlg);
15134 unregister : function(dlg){
15135 delete list[dlg.id];
15138 if(!accessList.indexOf){
15139 for( i = 0, len = accessList.length; i < len; i++){
15140 if(accessList[i] == dlg){
15141 accessList.splice(i, 1);
15146 i = accessList.indexOf(dlg);
15148 accessList.splice(i, 1);
15154 * Gets a registered dialog by id
15155 * @param {String/Object} id The id of the dialog or a dialog
15156 * @return {Roo.BasicDialog} this
15158 get : function(id){
15159 return typeof id == "object" ? id : list[id];
15163 * Brings the specified dialog to the front
15164 * @param {String/Object} dlg The id of the dialog or a dialog
15165 * @return {Roo.BasicDialog} this
15167 bringToFront : function(dlg){
15168 dlg = this.get(dlg);
15171 dlg._lastAccess = new Date().getTime();
15178 * Sends the specified dialog to the back
15179 * @param {String/Object} dlg The id of the dialog or a dialog
15180 * @return {Roo.BasicDialog} this
15182 sendToBack : function(dlg){
15183 dlg = this.get(dlg);
15184 dlg._lastAccess = -(new Date().getTime());
15190 * Hides all dialogs
15192 hideAll : function(){
15193 for(var id in list){
15194 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15203 * @class Roo.LayoutDialog
15204 * @extends Roo.BasicDialog
15205 * Dialog which provides adjustments for working with a layout in a Dialog.
15206 * Add your necessary layout config options to the dialog's config.<br>
15207 * Example usage (including a nested layout):
15210 dialog = new Roo.LayoutDialog("download-dlg", {
15219 // layout config merges with the dialog config
15221 tabPosition: "top",
15222 alwaysShowTabs: true
15225 dialog.addKeyListener(27, dialog.hide, dialog);
15226 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15227 dialog.addButton("Build It!", this.getDownload, this);
15229 // we can even add nested layouts
15230 var innerLayout = new Roo.BorderLayout("dl-inner", {
15240 innerLayout.beginUpdate();
15241 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15242 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15243 innerLayout.endUpdate(true);
15245 var layout = dialog.getLayout();
15246 layout.beginUpdate();
15247 layout.add("center", new Roo.ContentPanel("standard-panel",
15248 {title: "Download the Source", fitToFrame:true}));
15249 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15250 {title: "Build your own roo.js"}));
15251 layout.getRegion("center").showPanel(sp);
15252 layout.endUpdate();
15256 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15257 * @param {Object} config configuration options
15259 Roo.LayoutDialog = function(el, cfg){
15262 if (typeof(cfg) == 'undefined') {
15263 config = Roo.apply({}, el);
15264 // not sure why we use documentElement here.. - it should always be body.
15265 // IE7 borks horribly if we use documentElement.
15266 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15267 //config.autoCreate = true;
15271 config.autoTabs = false;
15272 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15273 this.body.setStyle({overflow:"hidden", position:"relative"});
15274 this.layout = new Roo.BorderLayout(this.body.dom, config);
15275 this.layout.monitorWindowResize = false;
15276 this.el.addClass("x-dlg-auto-layout");
15277 // fix case when center region overwrites center function
15278 this.center = Roo.BasicDialog.prototype.center;
15279 this.on("show", this.layout.layout, this.layout, true);
15280 if (config.items) {
15281 var xitems = config.items;
15282 delete config.items;
15283 Roo.each(xitems, this.addxtype, this);
15288 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15290 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15293 endUpdate : function(){
15294 this.layout.endUpdate();
15298 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15301 beginUpdate : function(){
15302 this.layout.beginUpdate();
15306 * Get the BorderLayout for this dialog
15307 * @return {Roo.BorderLayout}
15309 getLayout : function(){
15310 return this.layout;
15313 showEl : function(){
15314 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15316 this.layout.layout();
15321 // Use the syncHeightBeforeShow config option to control this automatically
15322 syncBodyHeight : function(){
15323 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15324 if(this.layout){this.layout.layout();}
15328 * Add an xtype element (actually adds to the layout.)
15329 * @return {Object} xdata xtype object data.
15332 addxtype : function(c) {
15333 return this.layout.addxtype(c);
15337 * Ext JS Library 1.1.1
15338 * Copyright(c) 2006-2007, Ext JS, LLC.
15340 * Originally Released Under LGPL - original licence link has changed is not relivant.
15343 * <script type="text/javascript">
15347 * @class Roo.MessageBox
15348 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15352 Roo.Msg.alert('Status', 'Changes saved successfully.');
15354 // Prompt for user data:
15355 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15357 // process text value...
15361 // Show a dialog using config options:
15363 title:'Save Changes?',
15364 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15365 buttons: Roo.Msg.YESNOCANCEL,
15372 Roo.MessageBox = function(){
15373 var dlg, opt, mask, waitTimer;
15374 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15375 var buttons, activeTextEl, bwidth;
15378 var handleButton = function(button){
15380 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15384 var handleHide = function(){
15385 if(opt && opt.cls){
15386 dlg.el.removeClass(opt.cls);
15389 Roo.TaskMgr.stop(waitTimer);
15395 var updateButtons = function(b){
15398 buttons["ok"].hide();
15399 buttons["cancel"].hide();
15400 buttons["yes"].hide();
15401 buttons["no"].hide();
15402 dlg.footer.dom.style.display = 'none';
15405 dlg.footer.dom.style.display = '';
15406 for(var k in buttons){
15407 if(typeof buttons[k] != "function"){
15410 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15411 width += buttons[k].el.getWidth()+15;
15421 var handleEsc = function(d, k, e){
15422 if(opt && opt.closable !== false){
15432 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15433 * @return {Roo.BasicDialog} The BasicDialog element
15435 getDialog : function(){
15437 dlg = new Roo.BasicDialog("x-msg-box", {
15442 constraintoviewport:false,
15444 collapsible : false,
15447 width:400, height:100,
15448 buttonAlign:"center",
15449 closeClick : function(){
15450 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15451 handleButton("no");
15453 handleButton("cancel");
15457 dlg.on("hide", handleHide);
15459 dlg.addKeyListener(27, handleEsc);
15461 var bt = this.buttonText;
15462 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15463 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15464 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15465 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15466 bodyEl = dlg.body.createChild({
15468 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>'
15470 msgEl = bodyEl.dom.firstChild;
15471 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15472 textboxEl.enableDisplayMode();
15473 textboxEl.addKeyListener([10,13], function(){
15474 if(dlg.isVisible() && opt && opt.buttons){
15475 if(opt.buttons.ok){
15476 handleButton("ok");
15477 }else if(opt.buttons.yes){
15478 handleButton("yes");
15482 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15483 textareaEl.enableDisplayMode();
15484 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15485 progressEl.enableDisplayMode();
15486 var pf = progressEl.dom.firstChild;
15488 pp = Roo.get(pf.firstChild);
15489 pp.setHeight(pf.offsetHeight);
15497 * Updates the message box body text
15498 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15499 * the XHTML-compliant non-breaking space character '&#160;')
15500 * @return {Roo.MessageBox} This message box
15502 updateText : function(text){
15503 if(!dlg.isVisible() && !opt.width){
15504 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15506 msgEl.innerHTML = text || ' ';
15507 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15508 Math.max(opt.minWidth || this.minWidth, bwidth));
15510 activeTextEl.setWidth(w);
15512 if(dlg.isVisible()){
15513 dlg.fixedcenter = false;
15515 dlg.setContentSize(w, bodyEl.getHeight());
15516 if(dlg.isVisible()){
15517 dlg.fixedcenter = true;
15523 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15524 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15525 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15526 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15527 * @return {Roo.MessageBox} This message box
15529 updateProgress : function(value, text){
15531 this.updateText(text);
15533 if (pp) { // weird bug on my firefox - for some reason this is not defined
15534 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15540 * Returns true if the message box is currently displayed
15541 * @return {Boolean} True if the message box is visible, else false
15543 isVisible : function(){
15544 return dlg && dlg.isVisible();
15548 * Hides the message box if it is displayed
15551 if(this.isVisible()){
15557 * Displays a new message box, or reinitializes an existing message box, based on the config options
15558 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15559 * The following config object properties are supported:
15561 Property Type Description
15562 ---------- --------------- ------------------------------------------------------------------------------------
15563 animEl String/Element An id or Element from which the message box should animate as it opens and
15564 closes (defaults to undefined)
15565 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15566 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15567 closable Boolean False to hide the top-right close button (defaults to true). Note that
15568 progress and wait dialogs will ignore this property and always hide the
15569 close button as they can only be closed programmatically.
15570 cls String A custom CSS class to apply to the message box element
15571 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15572 displayed (defaults to 75)
15573 fn Function A callback function to execute after closing the dialog. The arguments to the
15574 function will be btn (the name of the button that was clicked, if applicable,
15575 e.g. "ok"), and text (the value of the active text field, if applicable).
15576 Progress and wait dialogs will ignore this option since they do not respond to
15577 user actions and can only be closed programmatically, so any required function
15578 should be called by the same code after it closes the dialog.
15579 icon String A CSS class that provides a background image to be used as an icon for
15580 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15581 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15582 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15583 modal Boolean False to allow user interaction with the page while the message box is
15584 displayed (defaults to true)
15585 msg String A string that will replace the existing message box body text (defaults
15586 to the XHTML-compliant non-breaking space character ' ')
15587 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15588 progress Boolean True to display a progress bar (defaults to false)
15589 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15590 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15591 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15592 title String The title text
15593 value String The string value to set into the active textbox element if displayed
15594 wait Boolean True to display a progress bar (defaults to false)
15595 width Number The width of the dialog in pixels
15602 msg: 'Please enter your address:',
15604 buttons: Roo.MessageBox.OKCANCEL,
15607 animEl: 'addAddressBtn'
15610 * @param {Object} config Configuration options
15611 * @return {Roo.MessageBox} This message box
15613 show : function(options){
15614 if(this.isVisible()){
15617 var d = this.getDialog();
15619 d.setTitle(opt.title || " ");
15620 d.close.setDisplayed(opt.closable !== false);
15621 activeTextEl = textboxEl;
15622 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15627 textareaEl.setHeight(typeof opt.multiline == "number" ?
15628 opt.multiline : this.defaultTextHeight);
15629 activeTextEl = textareaEl;
15638 progressEl.setDisplayed(opt.progress === true);
15639 this.updateProgress(0);
15640 activeTextEl.dom.value = opt.value || "";
15642 dlg.setDefaultButton(activeTextEl);
15644 var bs = opt.buttons;
15647 db = buttons["ok"];
15648 }else if(bs && bs.yes){
15649 db = buttons["yes"];
15651 dlg.setDefaultButton(db);
15653 bwidth = updateButtons(opt.buttons);
15654 this.updateText(opt.msg);
15656 d.el.addClass(opt.cls);
15658 d.proxyDrag = opt.proxyDrag === true;
15659 d.modal = opt.modal !== false;
15660 d.mask = opt.modal !== false ? mask : false;
15661 if(!d.isVisible()){
15662 // force it to the end of the z-index stack so it gets a cursor in FF
15663 document.body.appendChild(dlg.el.dom);
15664 d.animateTarget = null;
15665 d.show(options.animEl);
15671 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15672 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15673 * and closing the message box when the process is complete.
15674 * @param {String} title The title bar text
15675 * @param {String} msg The message box body text
15676 * @return {Roo.MessageBox} This message box
15678 progress : function(title, msg){
15685 minWidth: this.minProgressWidth,
15692 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15693 * If a callback function is passed it will be called after the user clicks the button, and the
15694 * id of the button that was clicked will be passed as the only parameter to the callback
15695 * (could also be the top-right close button).
15696 * @param {String} title The title bar text
15697 * @param {String} msg The message box body text
15698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15699 * @param {Object} scope (optional) The scope of the callback function
15700 * @return {Roo.MessageBox} This message box
15702 alert : function(title, msg, fn, scope){
15715 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15716 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15717 * You are responsible for closing the message box when the process is complete.
15718 * @param {String} msg The message box body text
15719 * @param {String} title (optional) The title bar text
15720 * @return {Roo.MessageBox} This message box
15722 wait : function(msg, title){
15733 waitTimer = Roo.TaskMgr.start({
15735 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15743 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15744 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15745 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15746 * @param {String} title The title bar text
15747 * @param {String} msg The message box body text
15748 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15749 * @param {Object} scope (optional) The scope of the callback function
15750 * @return {Roo.MessageBox} This message box
15752 confirm : function(title, msg, fn, scope){
15756 buttons: this.YESNO,
15765 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15766 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15767 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15768 * (could also be the top-right close button) and the text that was entered will be passed as the two
15769 * parameters to the callback.
15770 * @param {String} title The title bar text
15771 * @param {String} msg The message box body text
15772 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15773 * @param {Object} scope (optional) The scope of the callback function
15774 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15775 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15776 * @return {Roo.MessageBox} This message box
15778 prompt : function(title, msg, fn, scope, multiline){
15782 buttons: this.OKCANCEL,
15787 multiline: multiline,
15794 * Button config that displays a single OK button
15799 * Button config that displays Yes and No buttons
15802 YESNO : {yes:true, no:true},
15804 * Button config that displays OK and Cancel buttons
15807 OKCANCEL : {ok:true, cancel:true},
15809 * Button config that displays Yes, No and Cancel buttons
15812 YESNOCANCEL : {yes:true, no:true, cancel:true},
15815 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15818 defaultTextHeight : 75,
15820 * The maximum width in pixels of the message box (defaults to 600)
15825 * The minimum width in pixels of the message box (defaults to 100)
15830 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15831 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15834 minProgressWidth : 250,
15836 * An object containing the default button text strings that can be overriden for localized language support.
15837 * Supported properties are: ok, cancel, yes and no.
15838 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15851 * Shorthand for {@link Roo.MessageBox}
15853 Roo.Msg = Roo.MessageBox;/*
15855 * Ext JS Library 1.1.1
15856 * Copyright(c) 2006-2007, Ext JS, LLC.
15858 * Originally Released Under LGPL - original licence link has changed is not relivant.
15861 * <script type="text/javascript">
15864 * @class Roo.QuickTips
15865 * Provides attractive and customizable tooltips for any element.
15868 Roo.QuickTips = function(){
15869 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15870 var ce, bd, xy, dd;
15871 var visible = false, disabled = true, inited = false;
15872 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15874 var onOver = function(e){
15878 var t = e.getTarget();
15879 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15882 if(ce && t == ce.el){
15883 clearTimeout(hideProc);
15886 if(t && tagEls[t.id]){
15887 tagEls[t.id].el = t;
15888 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15891 var ttp, et = Roo.fly(t);
15892 var ns = cfg.namespace;
15893 if(tm.interceptTitles && t.title){
15896 t.removeAttribute("title");
15897 e.preventDefault();
15899 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15902 showProc = show.defer(tm.showDelay, tm, [{
15905 width: et.getAttributeNS(ns, cfg.width),
15906 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15907 title: et.getAttributeNS(ns, cfg.title),
15908 cls: et.getAttributeNS(ns, cfg.cls)
15913 var onOut = function(e){
15914 clearTimeout(showProc);
15915 var t = e.getTarget();
15916 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15917 hideProc = setTimeout(hide, tm.hideDelay);
15921 var onMove = function(e){
15927 if(tm.trackMouse && ce){
15932 var onDown = function(e){
15933 clearTimeout(showProc);
15934 clearTimeout(hideProc);
15936 if(tm.hideOnClick){
15939 tm.enable.defer(100, tm);
15944 var getPad = function(){
15945 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15948 var show = function(o){
15952 clearTimeout(dismissProc);
15954 if(removeCls){ // in case manually hidden
15955 el.removeClass(removeCls);
15959 el.addClass(ce.cls);
15960 removeCls = ce.cls;
15963 tipTitle.update(ce.title);
15966 tipTitle.update('');
15969 el.dom.style.width = tm.maxWidth+'px';
15970 //tipBody.dom.style.width = '';
15971 tipBodyText.update(o.text);
15972 var p = getPad(), w = ce.width;
15974 var td = tipBodyText.dom;
15975 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15976 if(aw > tm.maxWidth){
15978 }else if(aw < tm.minWidth){
15984 //tipBody.setWidth(w);
15985 el.setWidth(parseInt(w, 10) + p);
15986 if(ce.autoHide === false){
15987 close.setDisplayed(true);
15992 close.setDisplayed(false);
15998 el.avoidY = xy[1]-18;
16003 el.setStyle("visibility", "visible");
16004 el.fadeIn({callback: afterShow});
16010 var afterShow = function(){
16014 if(tm.autoDismiss && ce.autoHide !== false){
16015 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16020 var hide = function(noanim){
16021 clearTimeout(dismissProc);
16022 clearTimeout(hideProc);
16024 if(el.isVisible()){
16026 if(noanim !== true && tm.animate){
16027 el.fadeOut({callback: afterHide});
16034 var afterHide = function(){
16037 el.removeClass(removeCls);
16044 * @cfg {Number} minWidth
16045 * The minimum width of the quick tip (defaults to 40)
16049 * @cfg {Number} maxWidth
16050 * The maximum width of the quick tip (defaults to 300)
16054 * @cfg {Boolean} interceptTitles
16055 * True to automatically use the element's DOM title value if available (defaults to false)
16057 interceptTitles : false,
16059 * @cfg {Boolean} trackMouse
16060 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16062 trackMouse : false,
16064 * @cfg {Boolean} hideOnClick
16065 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16067 hideOnClick : true,
16069 * @cfg {Number} showDelay
16070 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16074 * @cfg {Number} hideDelay
16075 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16079 * @cfg {Boolean} autoHide
16080 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16081 * Used in conjunction with hideDelay.
16086 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16087 * (defaults to true). Used in conjunction with autoDismissDelay.
16089 autoDismiss : true,
16092 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16094 autoDismissDelay : 5000,
16096 * @cfg {Boolean} animate
16097 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16102 * @cfg {String} title
16103 * Title text to display (defaults to ''). This can be any valid HTML markup.
16107 * @cfg {String} text
16108 * Body text to display (defaults to ''). This can be any valid HTML markup.
16112 * @cfg {String} cls
16113 * A CSS class to apply to the base quick tip element (defaults to '').
16117 * @cfg {Number} width
16118 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16119 * minWidth or maxWidth.
16124 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16125 * or display QuickTips in a page.
16128 tm = Roo.QuickTips;
16129 cfg = tm.tagConfig;
16131 if(!Roo.isReady){ // allow calling of init() before onReady
16132 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16135 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16136 el.fxDefaults = {stopFx: true};
16137 // maximum custom styling
16138 //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>');
16139 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>');
16140 tipTitle = el.child('h3');
16141 tipTitle.enableDisplayMode("block");
16142 tipBody = el.child('div.x-tip-bd');
16143 tipBodyText = el.child('div.x-tip-bd-inner');
16144 //bdLeft = el.child('div.x-tip-bd-left');
16145 //bdRight = el.child('div.x-tip-bd-right');
16146 close = el.child('div.x-tip-close');
16147 close.enableDisplayMode("block");
16148 close.on("click", hide);
16149 var d = Roo.get(document);
16150 d.on("mousedown", onDown);
16151 d.on("mouseover", onOver);
16152 d.on("mouseout", onOut);
16153 d.on("mousemove", onMove);
16154 esc = d.addKeyListener(27, hide);
16157 dd = el.initDD("default", null, {
16158 onDrag : function(){
16162 dd.setHandleElId(tipTitle.id);
16171 * Configures a new quick tip instance and assigns it to a target element. The following config options
16174 Property Type Description
16175 ---------- --------------------- ------------------------------------------------------------------------
16176 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16178 * @param {Object} config The config object
16180 register : function(config){
16181 var cs = config instanceof Array ? config : arguments;
16182 for(var i = 0, len = cs.length; i < len; i++) {
16184 var target = c.target;
16186 if(target instanceof Array){
16187 for(var j = 0, jlen = target.length; j < jlen; j++){
16188 tagEls[target[j]] = c;
16191 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16198 * Removes this quick tip from its element and destroys it.
16199 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16201 unregister : function(el){
16202 delete tagEls[Roo.id(el)];
16206 * Enable this quick tip.
16208 enable : function(){
16209 if(inited && disabled){
16211 if(locks.length < 1){
16218 * Disable this quick tip.
16220 disable : function(){
16222 clearTimeout(showProc);
16223 clearTimeout(hideProc);
16224 clearTimeout(dismissProc);
16232 * Returns true if the quick tip is enabled, else false.
16234 isEnabled : function(){
16241 attribute : "qtip",
16251 // backwards compat
16252 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16254 * Ext JS Library 1.1.1
16255 * Copyright(c) 2006-2007, Ext JS, LLC.
16257 * Originally Released Under LGPL - original licence link has changed is not relivant.
16260 * <script type="text/javascript">
16265 * @class Roo.tree.TreePanel
16266 * @extends Roo.data.Tree
16268 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16269 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16270 * @cfg {Boolean} enableDD true to enable drag and drop
16271 * @cfg {Boolean} enableDrag true to enable just drag
16272 * @cfg {Boolean} enableDrop true to enable just drop
16273 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16274 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16275 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16276 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16277 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16278 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16279 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16280 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16281 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16282 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16283 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16284 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16285 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16286 * @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>
16287 * @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>
16290 * @param {String/HTMLElement/Element} el The container element
16291 * @param {Object} config
16293 Roo.tree.TreePanel = function(el, config){
16295 var loader = false;
16297 root = config.root;
16298 delete config.root;
16300 if (config.loader) {
16301 loader = config.loader;
16302 delete config.loader;
16305 Roo.apply(this, config);
16306 Roo.tree.TreePanel.superclass.constructor.call(this);
16307 this.el = Roo.get(el);
16308 this.el.addClass('x-tree');
16309 //console.log(root);
16311 this.setRootNode( Roo.factory(root, Roo.tree));
16314 this.loader = Roo.factory(loader, Roo.tree);
16317 * Read-only. The id of the container element becomes this TreePanel's id.
16319 this.id = this.el.id;
16322 * @event beforeload
16323 * Fires before a node is loaded, return false to cancel
16324 * @param {Node} node The node being loaded
16326 "beforeload" : true,
16329 * Fires when a node is loaded
16330 * @param {Node} node The node that was loaded
16334 * @event textchange
16335 * Fires when the text for a node is changed
16336 * @param {Node} node The node
16337 * @param {String} text The new text
16338 * @param {String} oldText The old text
16340 "textchange" : true,
16342 * @event beforeexpand
16343 * Fires before a node is expanded, return false to cancel.
16344 * @param {Node} node The node
16345 * @param {Boolean} deep
16346 * @param {Boolean} anim
16348 "beforeexpand" : true,
16350 * @event beforecollapse
16351 * Fires before a node is collapsed, return false to cancel.
16352 * @param {Node} node The node
16353 * @param {Boolean} deep
16354 * @param {Boolean} anim
16356 "beforecollapse" : true,
16359 * Fires when a node is expanded
16360 * @param {Node} node The node
16364 * @event disabledchange
16365 * Fires when the disabled status of a node changes
16366 * @param {Node} node The node
16367 * @param {Boolean} disabled
16369 "disabledchange" : true,
16372 * Fires when a node is collapsed
16373 * @param {Node} node The node
16377 * @event beforeclick
16378 * Fires before click processing on a node. Return false to cancel the default action.
16379 * @param {Node} node The node
16380 * @param {Roo.EventObject} e The event object
16382 "beforeclick":true,
16384 * @event checkchange
16385 * Fires when a node with a checkbox's checked property changes
16386 * @param {Node} this This node
16387 * @param {Boolean} checked
16389 "checkchange":true,
16392 * Fires when a node is clicked
16393 * @param {Node} node The node
16394 * @param {Roo.EventObject} e The event object
16399 * Fires when a node is double clicked
16400 * @param {Node} node The node
16401 * @param {Roo.EventObject} e The event object
16405 * @event contextmenu
16406 * Fires when a node is right clicked
16407 * @param {Node} node The node
16408 * @param {Roo.EventObject} e The event object
16410 "contextmenu":true,
16412 * @event beforechildrenrendered
16413 * Fires right before the child nodes for a node are rendered
16414 * @param {Node} node The node
16416 "beforechildrenrendered":true,
16419 * Fires when a node starts being dragged
16420 * @param {Roo.tree.TreePanel} this
16421 * @param {Roo.tree.TreeNode} node
16422 * @param {event} e The raw browser event
16424 "startdrag" : true,
16427 * Fires when a drag operation is complete
16428 * @param {Roo.tree.TreePanel} this
16429 * @param {Roo.tree.TreeNode} node
16430 * @param {event} e The raw browser event
16435 * Fires when a dragged node is dropped on a valid DD target
16436 * @param {Roo.tree.TreePanel} this
16437 * @param {Roo.tree.TreeNode} node
16438 * @param {DD} dd The dd it was dropped on
16439 * @param {event} e The raw browser event
16443 * @event beforenodedrop
16444 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16445 * passed to handlers has the following properties:<br />
16446 * <ul style="padding:5px;padding-left:16px;">
16447 * <li>tree - The TreePanel</li>
16448 * <li>target - The node being targeted for the drop</li>
16449 * <li>data - The drag data from the drag source</li>
16450 * <li>point - The point of the drop - append, above or below</li>
16451 * <li>source - The drag source</li>
16452 * <li>rawEvent - Raw mouse event</li>
16453 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16454 * to be inserted by setting them on this object.</li>
16455 * <li>cancel - Set this to true to cancel the drop.</li>
16457 * @param {Object} dropEvent
16459 "beforenodedrop" : true,
16462 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16463 * passed to handlers has the following properties:<br />
16464 * <ul style="padding:5px;padding-left:16px;">
16465 * <li>tree - The TreePanel</li>
16466 * <li>target - The node being targeted for the drop</li>
16467 * <li>data - The drag data from the drag source</li>
16468 * <li>point - The point of the drop - append, above or below</li>
16469 * <li>source - The drag source</li>
16470 * <li>rawEvent - Raw mouse event</li>
16471 * <li>dropNode - Dropped node(s).</li>
16473 * @param {Object} dropEvent
16477 * @event nodedragover
16478 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16479 * passed to handlers has the following properties:<br />
16480 * <ul style="padding:5px;padding-left:16px;">
16481 * <li>tree - The TreePanel</li>
16482 * <li>target - The node being targeted for the drop</li>
16483 * <li>data - The drag data from the drag source</li>
16484 * <li>point - The point of the drop - append, above or below</li>
16485 * <li>source - The drag source</li>
16486 * <li>rawEvent - Raw mouse event</li>
16487 * <li>dropNode - Drop node(s) provided by the source.</li>
16488 * <li>cancel - Set this to true to signal drop not allowed.</li>
16490 * @param {Object} dragOverEvent
16492 "nodedragover" : true
16495 if(this.singleExpand){
16496 this.on("beforeexpand", this.restrictExpand, this);
16499 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16500 rootVisible : true,
16501 animate: Roo.enableFx,
16504 hlDrop : Roo.enableFx,
16508 rendererTip: false,
16510 restrictExpand : function(node){
16511 var p = node.parentNode;
16513 if(p.expandedChild && p.expandedChild.parentNode == p){
16514 p.expandedChild.collapse();
16516 p.expandedChild = node;
16520 // private override
16521 setRootNode : function(node){
16522 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16523 if(!this.rootVisible){
16524 node.ui = new Roo.tree.RootTreeNodeUI(node);
16530 * Returns the container element for this TreePanel
16532 getEl : function(){
16537 * Returns the default TreeLoader for this TreePanel
16539 getLoader : function(){
16540 return this.loader;
16546 expandAll : function(){
16547 this.root.expand(true);
16551 * Collapse all nodes
16553 collapseAll : function(){
16554 this.root.collapse(true);
16558 * Returns the selection model used by this TreePanel
16560 getSelectionModel : function(){
16561 if(!this.selModel){
16562 this.selModel = new Roo.tree.DefaultSelectionModel();
16564 return this.selModel;
16568 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16569 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16570 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16573 getChecked : function(a, startNode){
16574 startNode = startNode || this.root;
16576 var f = function(){
16577 if(this.attributes.checked){
16578 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16581 startNode.cascade(f);
16586 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16587 * @param {String} path
16588 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16589 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16590 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16592 expandPath : function(path, attr, callback){
16593 attr = attr || "id";
16594 var keys = path.split(this.pathSeparator);
16595 var curNode = this.root;
16596 if(curNode.attributes[attr] != keys[1]){ // invalid root
16598 callback(false, null);
16603 var f = function(){
16604 if(++index == keys.length){
16606 callback(true, curNode);
16610 var c = curNode.findChild(attr, keys[index]);
16613 callback(false, curNode);
16618 c.expand(false, false, f);
16620 curNode.expand(false, false, f);
16624 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16625 * @param {String} path
16626 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16627 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16628 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16630 selectPath : function(path, attr, callback){
16631 attr = attr || "id";
16632 var keys = path.split(this.pathSeparator);
16633 var v = keys.pop();
16634 if(keys.length > 0){
16635 var f = function(success, node){
16636 if(success && node){
16637 var n = node.findChild(attr, v);
16643 }else if(callback){
16644 callback(false, n);
16648 callback(false, n);
16652 this.expandPath(keys.join(this.pathSeparator), attr, f);
16654 this.root.select();
16656 callback(true, this.root);
16661 getTreeEl : function(){
16666 * Trigger rendering of this TreePanel
16668 render : function(){
16669 if (this.innerCt) {
16670 return this; // stop it rendering more than once!!
16673 this.innerCt = this.el.createChild({tag:"ul",
16674 cls:"x-tree-root-ct " +
16675 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16677 if(this.containerScroll){
16678 Roo.dd.ScrollManager.register(this.el);
16680 if((this.enableDD || this.enableDrop) && !this.dropZone){
16682 * The dropZone used by this tree if drop is enabled
16683 * @type Roo.tree.TreeDropZone
16685 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16686 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16689 if((this.enableDD || this.enableDrag) && !this.dragZone){
16691 * The dragZone used by this tree if drag is enabled
16692 * @type Roo.tree.TreeDragZone
16694 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16695 ddGroup: this.ddGroup || "TreeDD",
16696 scroll: this.ddScroll
16699 this.getSelectionModel().init(this);
16701 console.log("ROOT not set in tree");
16704 this.root.render();
16705 if(!this.rootVisible){
16706 this.root.renderChildren();
16712 * Ext JS Library 1.1.1
16713 * Copyright(c) 2006-2007, Ext JS, LLC.
16715 * Originally Released Under LGPL - original licence link has changed is not relivant.
16718 * <script type="text/javascript">
16723 * @class Roo.tree.DefaultSelectionModel
16724 * @extends Roo.util.Observable
16725 * The default single selection for a TreePanel.
16727 Roo.tree.DefaultSelectionModel = function(){
16728 this.selNode = null;
16732 * @event selectionchange
16733 * Fires when the selected node changes
16734 * @param {DefaultSelectionModel} this
16735 * @param {TreeNode} node the new selection
16737 "selectionchange" : true,
16740 * @event beforeselect
16741 * Fires before the selected node changes, return false to cancel the change
16742 * @param {DefaultSelectionModel} this
16743 * @param {TreeNode} node the new selection
16744 * @param {TreeNode} node the old selection
16746 "beforeselect" : true
16750 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16751 init : function(tree){
16753 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16754 tree.on("click", this.onNodeClick, this);
16757 onNodeClick : function(node, e){
16758 if (e.ctrlKey && this.selNode == node) {
16759 this.unselect(node);
16767 * @param {TreeNode} node The node to select
16768 * @return {TreeNode} The selected node
16770 select : function(node){
16771 var last = this.selNode;
16772 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16774 last.ui.onSelectedChange(false);
16776 this.selNode = node;
16777 node.ui.onSelectedChange(true);
16778 this.fireEvent("selectionchange", this, node, last);
16785 * @param {TreeNode} node The node to unselect
16787 unselect : function(node){
16788 if(this.selNode == node){
16789 this.clearSelections();
16794 * Clear all selections
16796 clearSelections : function(){
16797 var n = this.selNode;
16799 n.ui.onSelectedChange(false);
16800 this.selNode = null;
16801 this.fireEvent("selectionchange", this, null);
16807 * Get the selected node
16808 * @return {TreeNode} The selected node
16810 getSelectedNode : function(){
16811 return this.selNode;
16815 * Returns true if the node is selected
16816 * @param {TreeNode} node The node to check
16817 * @return {Boolean}
16819 isSelected : function(node){
16820 return this.selNode == node;
16824 * Selects the node above the selected node in the tree, intelligently walking the nodes
16825 * @return TreeNode The new selection
16827 selectPrevious : function(){
16828 var s = this.selNode || this.lastSelNode;
16832 var ps = s.previousSibling;
16834 if(!ps.isExpanded() || ps.childNodes.length < 1){
16835 return this.select(ps);
16837 var lc = ps.lastChild;
16838 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16841 return this.select(lc);
16843 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16844 return this.select(s.parentNode);
16850 * Selects the node above the selected node in the tree, intelligently walking the nodes
16851 * @return TreeNode The new selection
16853 selectNext : function(){
16854 var s = this.selNode || this.lastSelNode;
16858 if(s.firstChild && s.isExpanded()){
16859 return this.select(s.firstChild);
16860 }else if(s.nextSibling){
16861 return this.select(s.nextSibling);
16862 }else if(s.parentNode){
16864 s.parentNode.bubble(function(){
16865 if(this.nextSibling){
16866 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16875 onKeyDown : function(e){
16876 var s = this.selNode || this.lastSelNode;
16877 // undesirable, but required
16882 var k = e.getKey();
16890 this.selectPrevious();
16893 e.preventDefault();
16894 if(s.hasChildNodes()){
16895 if(!s.isExpanded()){
16897 }else if(s.firstChild){
16898 this.select(s.firstChild, e);
16903 e.preventDefault();
16904 if(s.hasChildNodes() && s.isExpanded()){
16906 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16907 this.select(s.parentNode, e);
16915 * @class Roo.tree.MultiSelectionModel
16916 * @extends Roo.util.Observable
16917 * Multi selection for a TreePanel.
16919 Roo.tree.MultiSelectionModel = function(){
16920 this.selNodes = [];
16924 * @event selectionchange
16925 * Fires when the selected nodes change
16926 * @param {MultiSelectionModel} this
16927 * @param {Array} nodes Array of the selected nodes
16929 "selectionchange" : true
16933 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16934 init : function(tree){
16936 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16937 tree.on("click", this.onNodeClick, this);
16940 onNodeClick : function(node, e){
16941 this.select(node, e, e.ctrlKey);
16946 * @param {TreeNode} node The node to select
16947 * @param {EventObject} e (optional) An event associated with the selection
16948 * @param {Boolean} keepExisting True to retain existing selections
16949 * @return {TreeNode} The selected node
16951 select : function(node, e, keepExisting){
16952 if(keepExisting !== true){
16953 this.clearSelections(true);
16955 if(this.isSelected(node)){
16956 this.lastSelNode = node;
16959 this.selNodes.push(node);
16960 this.selMap[node.id] = node;
16961 this.lastSelNode = node;
16962 node.ui.onSelectedChange(true);
16963 this.fireEvent("selectionchange", this, this.selNodes);
16969 * @param {TreeNode} node The node to unselect
16971 unselect : function(node){
16972 if(this.selMap[node.id]){
16973 node.ui.onSelectedChange(false);
16974 var sn = this.selNodes;
16977 index = sn.indexOf(node);
16979 for(var i = 0, len = sn.length; i < len; i++){
16987 this.selNodes.splice(index, 1);
16989 delete this.selMap[node.id];
16990 this.fireEvent("selectionchange", this, this.selNodes);
16995 * Clear all selections
16997 clearSelections : function(suppressEvent){
16998 var sn = this.selNodes;
17000 for(var i = 0, len = sn.length; i < len; i++){
17001 sn[i].ui.onSelectedChange(false);
17003 this.selNodes = [];
17005 if(suppressEvent !== true){
17006 this.fireEvent("selectionchange", this, this.selNodes);
17012 * Returns true if the node is selected
17013 * @param {TreeNode} node The node to check
17014 * @return {Boolean}
17016 isSelected : function(node){
17017 return this.selMap[node.id] ? true : false;
17021 * Returns an array of the selected nodes
17024 getSelectedNodes : function(){
17025 return this.selNodes;
17028 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17030 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17032 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17035 * Ext JS Library 1.1.1
17036 * Copyright(c) 2006-2007, Ext JS, LLC.
17038 * Originally Released Under LGPL - original licence link has changed is not relivant.
17041 * <script type="text/javascript">
17045 * @class Roo.tree.TreeNode
17046 * @extends Roo.data.Node
17047 * @cfg {String} text The text for this node
17048 * @cfg {Boolean} expanded true to start the node expanded
17049 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17050 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17051 * @cfg {Boolean} disabled true to start the node disabled
17052 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17053 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17054 * @cfg {String} cls A css class to be added to the node
17055 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17056 * @cfg {String} href URL of the link used for the node (defaults to #)
17057 * @cfg {String} hrefTarget target frame for the link
17058 * @cfg {String} qtip An Ext QuickTip for the node
17059 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17060 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17061 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17062 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17063 * (defaults to undefined with no checkbox rendered)
17065 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17067 Roo.tree.TreeNode = function(attributes){
17068 attributes = attributes || {};
17069 if(typeof attributes == "string"){
17070 attributes = {text: attributes};
17072 this.childrenRendered = false;
17073 this.rendered = false;
17074 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17075 this.expanded = attributes.expanded === true;
17076 this.isTarget = attributes.isTarget !== false;
17077 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17078 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17081 * Read-only. The text for this node. To change it use setText().
17084 this.text = attributes.text;
17086 * True if this node is disabled.
17089 this.disabled = attributes.disabled === true;
17093 * @event textchange
17094 * Fires when the text for this node is changed
17095 * @param {Node} this This node
17096 * @param {String} text The new text
17097 * @param {String} oldText The old text
17099 "textchange" : true,
17101 * @event beforeexpand
17102 * Fires before this node is expanded, return false to cancel.
17103 * @param {Node} this This node
17104 * @param {Boolean} deep
17105 * @param {Boolean} anim
17107 "beforeexpand" : true,
17109 * @event beforecollapse
17110 * Fires before this node is collapsed, return false to cancel.
17111 * @param {Node} this This node
17112 * @param {Boolean} deep
17113 * @param {Boolean} anim
17115 "beforecollapse" : true,
17118 * Fires when this node is expanded
17119 * @param {Node} this This node
17123 * @event disabledchange
17124 * Fires when the disabled status of this node changes
17125 * @param {Node} this This node
17126 * @param {Boolean} disabled
17128 "disabledchange" : true,
17131 * Fires when this node is collapsed
17132 * @param {Node} this This node
17136 * @event beforeclick
17137 * Fires before click processing. Return false to cancel the default action.
17138 * @param {Node} this This node
17139 * @param {Roo.EventObject} e The event object
17141 "beforeclick":true,
17143 * @event checkchange
17144 * Fires when a node with a checkbox's checked property changes
17145 * @param {Node} this This node
17146 * @param {Boolean} checked
17148 "checkchange":true,
17151 * Fires when this node is clicked
17152 * @param {Node} this This node
17153 * @param {Roo.EventObject} e The event object
17158 * Fires when this node is double clicked
17159 * @param {Node} this This node
17160 * @param {Roo.EventObject} e The event object
17164 * @event contextmenu
17165 * Fires when this node is right clicked
17166 * @param {Node} this This node
17167 * @param {Roo.EventObject} e The event object
17169 "contextmenu":true,
17171 * @event beforechildrenrendered
17172 * Fires right before the child nodes for this node are rendered
17173 * @param {Node} this This node
17175 "beforechildrenrendered":true
17178 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17181 * Read-only. The UI for this node
17184 this.ui = new uiClass(this);
17186 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17187 preventHScroll: true,
17189 * Returns true if this node is expanded
17190 * @return {Boolean}
17192 isExpanded : function(){
17193 return this.expanded;
17197 * Returns the UI object for this node
17198 * @return {TreeNodeUI}
17200 getUI : function(){
17204 // private override
17205 setFirstChild : function(node){
17206 var of = this.firstChild;
17207 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17208 if(this.childrenRendered && of && node != of){
17209 of.renderIndent(true, true);
17212 this.renderIndent(true, true);
17216 // private override
17217 setLastChild : function(node){
17218 var ol = this.lastChild;
17219 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17220 if(this.childrenRendered && ol && node != ol){
17221 ol.renderIndent(true, true);
17224 this.renderIndent(true, true);
17228 // these methods are overridden to provide lazy rendering support
17229 // private override
17230 appendChild : function(){
17231 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17232 if(node && this.childrenRendered){
17235 this.ui.updateExpandIcon();
17239 // private override
17240 removeChild : function(node){
17241 this.ownerTree.getSelectionModel().unselect(node);
17242 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17243 // if it's been rendered remove dom node
17244 if(this.childrenRendered){
17247 if(this.childNodes.length < 1){
17248 this.collapse(false, false);
17250 this.ui.updateExpandIcon();
17252 if(!this.firstChild) {
17253 this.childrenRendered = false;
17258 // private override
17259 insertBefore : function(node, refNode){
17260 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17261 if(newNode && refNode && this.childrenRendered){
17264 this.ui.updateExpandIcon();
17269 * Sets the text for this node
17270 * @param {String} text
17272 setText : function(text){
17273 var oldText = this.text;
17275 this.attributes.text = text;
17276 if(this.rendered){ // event without subscribing
17277 this.ui.onTextChange(this, text, oldText);
17279 this.fireEvent("textchange", this, text, oldText);
17283 * Triggers selection of this node
17285 select : function(){
17286 this.getOwnerTree().getSelectionModel().select(this);
17290 * Triggers deselection of this node
17292 unselect : function(){
17293 this.getOwnerTree().getSelectionModel().unselect(this);
17297 * Returns true if this node is selected
17298 * @return {Boolean}
17300 isSelected : function(){
17301 return this.getOwnerTree().getSelectionModel().isSelected(this);
17305 * Expand this node.
17306 * @param {Boolean} deep (optional) True to expand all children as well
17307 * @param {Boolean} anim (optional) false to cancel the default animation
17308 * @param {Function} callback (optional) A callback to be called when
17309 * expanding this node completes (does not wait for deep expand to complete).
17310 * Called with 1 parameter, this node.
17312 expand : function(deep, anim, callback){
17313 if(!this.expanded){
17314 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17317 if(!this.childrenRendered){
17318 this.renderChildren();
17320 this.expanded = true;
17321 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17322 this.ui.animExpand(function(){
17323 this.fireEvent("expand", this);
17324 if(typeof callback == "function"){
17328 this.expandChildNodes(true);
17330 }.createDelegate(this));
17334 this.fireEvent("expand", this);
17335 if(typeof callback == "function"){
17340 if(typeof callback == "function"){
17345 this.expandChildNodes(true);
17349 isHiddenRoot : function(){
17350 return this.isRoot && !this.getOwnerTree().rootVisible;
17354 * Collapse this node.
17355 * @param {Boolean} deep (optional) True to collapse all children as well
17356 * @param {Boolean} anim (optional) false to cancel the default animation
17358 collapse : function(deep, anim){
17359 if(this.expanded && !this.isHiddenRoot()){
17360 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17363 this.expanded = false;
17364 if((this.getOwnerTree().animate && anim !== false) || anim){
17365 this.ui.animCollapse(function(){
17366 this.fireEvent("collapse", this);
17368 this.collapseChildNodes(true);
17370 }.createDelegate(this));
17373 this.ui.collapse();
17374 this.fireEvent("collapse", this);
17378 var cs = this.childNodes;
17379 for(var i = 0, len = cs.length; i < len; i++) {
17380 cs[i].collapse(true, false);
17386 delayedExpand : function(delay){
17387 if(!this.expandProcId){
17388 this.expandProcId = this.expand.defer(delay, this);
17393 cancelExpand : function(){
17394 if(this.expandProcId){
17395 clearTimeout(this.expandProcId);
17397 this.expandProcId = false;
17401 * Toggles expanded/collapsed state of the node
17403 toggle : function(){
17412 * Ensures all parent nodes are expanded
17414 ensureVisible : function(callback){
17415 var tree = this.getOwnerTree();
17416 tree.expandPath(this.parentNode.getPath(), false, function(){
17417 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17418 Roo.callback(callback);
17419 }.createDelegate(this));
17423 * Expand all child nodes
17424 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17426 expandChildNodes : function(deep){
17427 var cs = this.childNodes;
17428 for(var i = 0, len = cs.length; i < len; i++) {
17429 cs[i].expand(deep);
17434 * Collapse all child nodes
17435 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17437 collapseChildNodes : function(deep){
17438 var cs = this.childNodes;
17439 for(var i = 0, len = cs.length; i < len; i++) {
17440 cs[i].collapse(deep);
17445 * Disables this node
17447 disable : function(){
17448 this.disabled = true;
17450 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17451 this.ui.onDisableChange(this, true);
17453 this.fireEvent("disabledchange", this, true);
17457 * Enables this node
17459 enable : function(){
17460 this.disabled = false;
17461 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17462 this.ui.onDisableChange(this, false);
17464 this.fireEvent("disabledchange", this, false);
17468 renderChildren : function(suppressEvent){
17469 if(suppressEvent !== false){
17470 this.fireEvent("beforechildrenrendered", this);
17472 var cs = this.childNodes;
17473 for(var i = 0, len = cs.length; i < len; i++){
17474 cs[i].render(true);
17476 this.childrenRendered = true;
17480 sort : function(fn, scope){
17481 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17482 if(this.childrenRendered){
17483 var cs = this.childNodes;
17484 for(var i = 0, len = cs.length; i < len; i++){
17485 cs[i].render(true);
17491 render : function(bulkRender){
17492 this.ui.render(bulkRender);
17493 if(!this.rendered){
17494 this.rendered = true;
17496 this.expanded = false;
17497 this.expand(false, false);
17503 renderIndent : function(deep, refresh){
17505 this.ui.childIndent = null;
17507 this.ui.renderIndent();
17508 if(deep === true && this.childrenRendered){
17509 var cs = this.childNodes;
17510 for(var i = 0, len = cs.length; i < len; i++){
17511 cs[i].renderIndent(true, refresh);
17517 * Ext JS Library 1.1.1
17518 * Copyright(c) 2006-2007, Ext JS, LLC.
17520 * Originally Released Under LGPL - original licence link has changed is not relivant.
17523 * <script type="text/javascript">
17527 * @class Roo.tree.AsyncTreeNode
17528 * @extends Roo.tree.TreeNode
17529 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17531 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17533 Roo.tree.AsyncTreeNode = function(config){
17534 this.loaded = false;
17535 this.loading = false;
17536 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17538 * @event beforeload
17539 * Fires before this node is loaded, return false to cancel
17540 * @param {Node} this This node
17542 this.addEvents({'beforeload':true, 'load': true});
17545 * Fires when this node is loaded
17546 * @param {Node} this This node
17549 * The loader used by this node (defaults to using the tree's defined loader)
17554 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17555 expand : function(deep, anim, callback){
17556 if(this.loading){ // if an async load is already running, waiting til it's done
17558 var f = function(){
17559 if(!this.loading){ // done loading
17560 clearInterval(timer);
17561 this.expand(deep, anim, callback);
17563 }.createDelegate(this);
17564 timer = setInterval(f, 200);
17568 if(this.fireEvent("beforeload", this) === false){
17571 this.loading = true;
17572 this.ui.beforeLoad(this);
17573 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17575 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17579 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17583 * Returns true if this node is currently loading
17584 * @return {Boolean}
17586 isLoading : function(){
17587 return this.loading;
17590 loadComplete : function(deep, anim, callback){
17591 this.loading = false;
17592 this.loaded = true;
17593 this.ui.afterLoad(this);
17594 this.fireEvent("load", this);
17595 this.expand(deep, anim, callback);
17599 * Returns true if this node has been loaded
17600 * @return {Boolean}
17602 isLoaded : function(){
17603 return this.loaded;
17606 hasChildNodes : function(){
17607 if(!this.isLeaf() && !this.loaded){
17610 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17615 * Trigger a reload for this node
17616 * @param {Function} callback
17618 reload : function(callback){
17619 this.collapse(false, false);
17620 while(this.firstChild){
17621 this.removeChild(this.firstChild);
17623 this.childrenRendered = false;
17624 this.loaded = false;
17625 if(this.isHiddenRoot()){
17626 this.expanded = false;
17628 this.expand(false, false, callback);
17632 * Ext JS Library 1.1.1
17633 * Copyright(c) 2006-2007, Ext JS, LLC.
17635 * Originally Released Under LGPL - original licence link has changed is not relivant.
17638 * <script type="text/javascript">
17642 * @class Roo.tree.TreeNodeUI
17644 * @param {Object} node The node to render
17645 * The TreeNode UI implementation is separate from the
17646 * tree implementation. Unless you are customizing the tree UI,
17647 * you should never have to use this directly.
17649 Roo.tree.TreeNodeUI = function(node){
17651 this.rendered = false;
17652 this.animating = false;
17653 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17656 Roo.tree.TreeNodeUI.prototype = {
17657 removeChild : function(node){
17659 this.ctNode.removeChild(node.ui.getEl());
17663 beforeLoad : function(){
17664 this.addClass("x-tree-node-loading");
17667 afterLoad : function(){
17668 this.removeClass("x-tree-node-loading");
17671 onTextChange : function(node, text, oldText){
17673 this.textNode.innerHTML = text;
17677 onDisableChange : function(node, state){
17678 this.disabled = state;
17680 this.addClass("x-tree-node-disabled");
17682 this.removeClass("x-tree-node-disabled");
17686 onSelectedChange : function(state){
17689 this.addClass("x-tree-selected");
17692 this.removeClass("x-tree-selected");
17696 onMove : function(tree, node, oldParent, newParent, index, refNode){
17697 this.childIndent = null;
17699 var targetNode = newParent.ui.getContainer();
17700 if(!targetNode){//target not rendered
17701 this.holder = document.createElement("div");
17702 this.holder.appendChild(this.wrap);
17705 var insertBefore = refNode ? refNode.ui.getEl() : null;
17707 targetNode.insertBefore(this.wrap, insertBefore);
17709 targetNode.appendChild(this.wrap);
17711 this.node.renderIndent(true);
17715 addClass : function(cls){
17717 Roo.fly(this.elNode).addClass(cls);
17721 removeClass : function(cls){
17723 Roo.fly(this.elNode).removeClass(cls);
17727 remove : function(){
17729 this.holder = document.createElement("div");
17730 this.holder.appendChild(this.wrap);
17734 fireEvent : function(){
17735 return this.node.fireEvent.apply(this.node, arguments);
17738 initEvents : function(){
17739 this.node.on("move", this.onMove, this);
17740 var E = Roo.EventManager;
17741 var a = this.anchor;
17743 var el = Roo.fly(a, '_treeui');
17745 if(Roo.isOpera){ // opera render bug ignores the CSS
17746 el.setStyle("text-decoration", "none");
17749 el.on("click", this.onClick, this);
17750 el.on("dblclick", this.onDblClick, this);
17753 Roo.EventManager.on(this.checkbox,
17754 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17757 el.on("contextmenu", this.onContextMenu, this);
17759 var icon = Roo.fly(this.iconNode);
17760 icon.on("click", this.onClick, this);
17761 icon.on("dblclick", this.onDblClick, this);
17762 icon.on("contextmenu", this.onContextMenu, this);
17763 E.on(this.ecNode, "click", this.ecClick, this, true);
17765 if(this.node.disabled){
17766 this.addClass("x-tree-node-disabled");
17768 if(this.node.hidden){
17769 this.addClass("x-tree-node-disabled");
17771 var ot = this.node.getOwnerTree();
17772 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17773 if(dd && (!this.node.isRoot || ot.rootVisible)){
17774 Roo.dd.Registry.register(this.elNode, {
17776 handles: this.getDDHandles(),
17782 getDDHandles : function(){
17783 return [this.iconNode, this.textNode];
17788 this.wrap.style.display = "none";
17794 this.wrap.style.display = "";
17798 onContextMenu : function(e){
17799 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17800 e.preventDefault();
17802 this.fireEvent("contextmenu", this.node, e);
17806 onClick : function(e){
17811 if(this.fireEvent("beforeclick", this.node, e) !== false){
17812 if(!this.disabled && this.node.attributes.href){
17813 this.fireEvent("click", this.node, e);
17816 e.preventDefault();
17821 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17822 this.node.toggle();
17825 this.fireEvent("click", this.node, e);
17831 onDblClick : function(e){
17832 e.preventDefault();
17837 this.toggleCheck();
17839 if(!this.animating && this.node.hasChildNodes()){
17840 this.node.toggle();
17842 this.fireEvent("dblclick", this.node, e);
17845 onCheckChange : function(){
17846 var checked = this.checkbox.checked;
17847 this.node.attributes.checked = checked;
17848 this.fireEvent('checkchange', this.node, checked);
17851 ecClick : function(e){
17852 if(!this.animating && this.node.hasChildNodes()){
17853 this.node.toggle();
17857 startDrop : function(){
17858 this.dropping = true;
17861 // delayed drop so the click event doesn't get fired on a drop
17862 endDrop : function(){
17863 setTimeout(function(){
17864 this.dropping = false;
17865 }.createDelegate(this), 50);
17868 expand : function(){
17869 this.updateExpandIcon();
17870 this.ctNode.style.display = "";
17873 focus : function(){
17874 if(!this.node.preventHScroll){
17875 try{this.anchor.focus();
17877 }else if(!Roo.isIE){
17879 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17880 var l = noscroll.scrollLeft;
17881 this.anchor.focus();
17882 noscroll.scrollLeft = l;
17887 toggleCheck : function(value){
17888 var cb = this.checkbox;
17890 cb.checked = (value === undefined ? !cb.checked : value);
17896 this.anchor.blur();
17900 animExpand : function(callback){
17901 var ct = Roo.get(this.ctNode);
17903 if(!this.node.hasChildNodes()){
17904 this.updateExpandIcon();
17905 this.ctNode.style.display = "";
17906 Roo.callback(callback);
17909 this.animating = true;
17910 this.updateExpandIcon();
17913 callback : function(){
17914 this.animating = false;
17915 Roo.callback(callback);
17918 duration: this.node.ownerTree.duration || .25
17922 highlight : function(){
17923 var tree = this.node.getOwnerTree();
17924 Roo.fly(this.wrap).highlight(
17925 tree.hlColor || "C3DAF9",
17926 {endColor: tree.hlBaseColor}
17930 collapse : function(){
17931 this.updateExpandIcon();
17932 this.ctNode.style.display = "none";
17935 animCollapse : function(callback){
17936 var ct = Roo.get(this.ctNode);
17937 ct.enableDisplayMode('block');
17940 this.animating = true;
17941 this.updateExpandIcon();
17944 callback : function(){
17945 this.animating = false;
17946 Roo.callback(callback);
17949 duration: this.node.ownerTree.duration || .25
17953 getContainer : function(){
17954 return this.ctNode;
17957 getEl : function(){
17961 appendDDGhost : function(ghostNode){
17962 ghostNode.appendChild(this.elNode.cloneNode(true));
17965 getDDRepairXY : function(){
17966 return Roo.lib.Dom.getXY(this.iconNode);
17969 onRender : function(){
17973 render : function(bulkRender){
17974 var n = this.node, a = n.attributes;
17975 var targetNode = n.parentNode ?
17976 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17978 if(!this.rendered){
17979 this.rendered = true;
17981 this.renderElements(n, a, targetNode, bulkRender);
17984 if(this.textNode.setAttributeNS){
17985 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17987 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17990 this.textNode.setAttribute("ext:qtip", a.qtip);
17992 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17995 }else if(a.qtipCfg){
17996 a.qtipCfg.target = Roo.id(this.textNode);
17997 Roo.QuickTips.register(a.qtipCfg);
18000 if(!this.node.expanded){
18001 this.updateExpandIcon();
18004 if(bulkRender === true) {
18005 targetNode.appendChild(this.wrap);
18010 renderElements : function(n, a, targetNode, bulkRender){
18011 // add some indent caching, this helps performance when rendering a large tree
18012 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18013 var t = n.getOwnerTree();
18014 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18015 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18016 var cb = typeof a.checked == 'boolean';
18017 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18018 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18019 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18020 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18021 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18022 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18023 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18024 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18025 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18026 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18029 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18030 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18031 n.nextSibling.ui.getEl(), buf.join(""));
18033 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18036 this.elNode = this.wrap.childNodes[0];
18037 this.ctNode = this.wrap.childNodes[1];
18038 var cs = this.elNode.childNodes;
18039 this.indentNode = cs[0];
18040 this.ecNode = cs[1];
18041 this.iconNode = cs[2];
18044 this.checkbox = cs[3];
18047 this.anchor = cs[index];
18048 this.textNode = cs[index].firstChild;
18051 getAnchor : function(){
18052 return this.anchor;
18055 getTextEl : function(){
18056 return this.textNode;
18059 getIconEl : function(){
18060 return this.iconNode;
18063 isChecked : function(){
18064 return this.checkbox ? this.checkbox.checked : false;
18067 updateExpandIcon : function(){
18069 var n = this.node, c1, c2;
18070 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18071 var hasChild = n.hasChildNodes();
18075 c1 = "x-tree-node-collapsed";
18076 c2 = "x-tree-node-expanded";
18079 c1 = "x-tree-node-expanded";
18080 c2 = "x-tree-node-collapsed";
18083 this.removeClass("x-tree-node-leaf");
18084 this.wasLeaf = false;
18086 if(this.c1 != c1 || this.c2 != c2){
18087 Roo.fly(this.elNode).replaceClass(c1, c2);
18088 this.c1 = c1; this.c2 = c2;
18092 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18095 this.wasLeaf = true;
18098 var ecc = "x-tree-ec-icon "+cls;
18099 if(this.ecc != ecc){
18100 this.ecNode.className = ecc;
18106 getChildIndent : function(){
18107 if(!this.childIndent){
18111 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18113 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18115 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18120 this.childIndent = buf.join("");
18122 return this.childIndent;
18125 renderIndent : function(){
18128 var p = this.node.parentNode;
18130 indent = p.ui.getChildIndent();
18132 if(this.indentMarkup != indent){ // don't rerender if not required
18133 this.indentNode.innerHTML = indent;
18134 this.indentMarkup = indent;
18136 this.updateExpandIcon();
18141 Roo.tree.RootTreeNodeUI = function(){
18142 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18144 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18145 render : function(){
18146 if(!this.rendered){
18147 var targetNode = this.node.ownerTree.innerCt.dom;
18148 this.node.expanded = true;
18149 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18150 this.wrap = this.ctNode = targetNode.firstChild;
18153 collapse : function(){
18155 expand : function(){
18159 * Ext JS Library 1.1.1
18160 * Copyright(c) 2006-2007, Ext JS, LLC.
18162 * Originally Released Under LGPL - original licence link has changed is not relivant.
18165 * <script type="text/javascript">
18168 * @class Roo.tree.TreeLoader
18169 * @extends Roo.util.Observable
18170 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18171 * nodes from a specified URL. The response must be a javascript Array definition
18172 * who's elements are node definition objects. eg:
18174 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18175 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18178 * A server request is sent, and child nodes are loaded only when a node is expanded.
18179 * The loading node's id is passed to the server under the parameter name "node" to
18180 * enable the server to produce the correct child nodes.
18182 * To pass extra parameters, an event handler may be attached to the "beforeload"
18183 * event, and the parameters specified in the TreeLoader's baseParams property:
18185 myTreeLoader.on("beforeload", function(treeLoader, node) {
18186 this.baseParams.category = node.attributes.category;
18189 * This would pass an HTTP parameter called "category" to the server containing
18190 * the value of the Node's "category" attribute.
18192 * Creates a new Treeloader.
18193 * @param {Object} config A config object containing config properties.
18195 Roo.tree.TreeLoader = function(config){
18196 this.baseParams = {};
18197 this.requestMethod = "POST";
18198 Roo.apply(this, config);
18203 * @event beforeload
18204 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18205 * @param {Object} This TreeLoader object.
18206 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18207 * @param {Object} callback The callback function specified in the {@link #load} call.
18212 * Fires when the node has been successfuly loaded.
18213 * @param {Object} This TreeLoader object.
18214 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18215 * @param {Object} response The response object containing the data from the server.
18219 * @event loadexception
18220 * Fires if the network request failed.
18221 * @param {Object} This TreeLoader object.
18222 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18223 * @param {Object} response The response object containing the data from the server.
18225 loadexception : true,
18228 * Fires before a node is created, enabling you to return custom Node types
18229 * @param {Object} This TreeLoader object.
18230 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18235 Roo.tree.TreeLoader.superclass.constructor.call(this);
18238 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18240 * @cfg {String} dataUrl The URL from which to request a Json string which
18241 * specifies an array of node definition object representing the child nodes
18245 * @cfg {Object} baseParams (optional) An object containing properties which
18246 * specify HTTP parameters to be passed to each request for child nodes.
18249 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18250 * created by this loader. If the attributes sent by the server have an attribute in this object,
18251 * they take priority.
18254 * @cfg {Object} uiProviders (optional) An object containing properties which
18256 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18257 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18258 * <i>uiProvider</i> attribute of a returned child node is a string rather
18259 * than a reference to a TreeNodeUI implementation, this that string value
18260 * is used as a property name in the uiProviders object. You can define the provider named
18261 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18266 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18267 * child nodes before loading.
18269 clearOnLoad : true,
18272 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18273 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18274 * Grid query { data : [ .....] }
18279 * @cfg {String} queryParam (optional)
18280 * Name of the query as it will be passed on the querystring (defaults to 'node')
18281 * eg. the request will be ?node=[id]
18288 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18289 * This is called automatically when a node is expanded, but may be used to reload
18290 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18291 * @param {Roo.tree.TreeNode} node
18292 * @param {Function} callback
18294 load : function(node, callback){
18295 if(this.clearOnLoad){
18296 while(node.firstChild){
18297 node.removeChild(node.firstChild);
18300 if(node.attributes.children){ // preloaded json children
18301 var cs = node.attributes.children;
18302 for(var i = 0, len = cs.length; i < len; i++){
18303 node.appendChild(this.createNode(cs[i]));
18305 if(typeof callback == "function"){
18308 }else if(this.dataUrl){
18309 this.requestData(node, callback);
18313 getParams: function(node){
18314 var buf = [], bp = this.baseParams;
18315 for(var key in bp){
18316 if(typeof bp[key] != "function"){
18317 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18320 var n = this.queryParam === false ? 'node' : this.queryParam;
18321 buf.push(n + "=", encodeURIComponent(node.id));
18322 return buf.join("");
18325 requestData : function(node, callback){
18326 if(this.fireEvent("beforeload", this, node, callback) !== false){
18327 this.transId = Roo.Ajax.request({
18328 method:this.requestMethod,
18329 url: this.dataUrl||this.url,
18330 success: this.handleResponse,
18331 failure: this.handleFailure,
18333 argument: {callback: callback, node: node},
18334 params: this.getParams(node)
18337 // if the load is cancelled, make sure we notify
18338 // the node that we are done
18339 if(typeof callback == "function"){
18345 isLoading : function(){
18346 return this.transId ? true : false;
18349 abort : function(){
18350 if(this.isLoading()){
18351 Roo.Ajax.abort(this.transId);
18356 createNode : function(attr){
18357 // apply baseAttrs, nice idea Corey!
18358 if(this.baseAttrs){
18359 Roo.applyIf(attr, this.baseAttrs);
18361 if(this.applyLoader !== false){
18362 attr.loader = this;
18364 // uiProvider = depreciated..
18366 if(typeof(attr.uiProvider) == 'string'){
18367 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18368 /** eval:var:attr */ eval(attr.uiProvider);
18370 if(typeof(this.uiProviders['default']) != 'undefined') {
18371 attr.uiProvider = this.uiProviders['default'];
18374 this.fireEvent('create', this, attr);
18376 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18378 new Roo.tree.TreeNode(attr) :
18379 new Roo.tree.AsyncTreeNode(attr));
18382 processResponse : function(response, node, callback){
18383 var json = response.responseText;
18386 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18387 if (this.root !== false) {
18391 for(var i = 0, len = o.length; i < len; i++){
18392 var n = this.createNode(o[i]);
18394 node.appendChild(n);
18397 if(typeof callback == "function"){
18398 callback(this, node);
18401 this.handleFailure(response);
18405 handleResponse : function(response){
18406 this.transId = false;
18407 var a = response.argument;
18408 this.processResponse(response, a.node, a.callback);
18409 this.fireEvent("load", this, a.node, response);
18412 handleFailure : function(response){
18413 this.transId = false;
18414 var a = response.argument;
18415 this.fireEvent("loadexception", this, a.node, response);
18416 if(typeof a.callback == "function"){
18417 a.callback(this, a.node);
18422 * Ext JS Library 1.1.1
18423 * Copyright(c) 2006-2007, Ext JS, LLC.
18425 * Originally Released Under LGPL - original licence link has changed is not relivant.
18428 * <script type="text/javascript">
18432 * @class Roo.tree.TreeFilter
18433 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18434 * @param {TreePanel} tree
18435 * @param {Object} config (optional)
18437 Roo.tree.TreeFilter = function(tree, config){
18439 this.filtered = {};
18440 Roo.apply(this, config);
18443 Roo.tree.TreeFilter.prototype = {
18450 * Filter the data by a specific attribute.
18451 * @param {String/RegExp} value Either string that the attribute value
18452 * should start with or a RegExp to test against the attribute
18453 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18454 * @param {TreeNode} startNode (optional) The node to start the filter at.
18456 filter : function(value, attr, startNode){
18457 attr = attr || "text";
18459 if(typeof value == "string"){
18460 var vlen = value.length;
18461 // auto clear empty filter
18462 if(vlen == 0 && this.clearBlank){
18466 value = value.toLowerCase();
18468 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18470 }else if(value.exec){ // regex?
18472 return value.test(n.attributes[attr]);
18475 throw 'Illegal filter type, must be string or regex';
18477 this.filterBy(f, null, startNode);
18481 * Filter by a function. The passed function will be called with each
18482 * node in the tree (or from the startNode). If the function returns true, the node is kept
18483 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18484 * @param {Function} fn The filter function
18485 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18487 filterBy : function(fn, scope, startNode){
18488 startNode = startNode || this.tree.root;
18489 if(this.autoClear){
18492 var af = this.filtered, rv = this.reverse;
18493 var f = function(n){
18494 if(n == startNode){
18500 var m = fn.call(scope || n, n);
18508 startNode.cascade(f);
18511 if(typeof id != "function"){
18513 if(n && n.parentNode){
18514 n.parentNode.removeChild(n);
18522 * Clears the current filter. Note: with the "remove" option
18523 * set a filter cannot be cleared.
18525 clear : function(){
18527 var af = this.filtered;
18529 if(typeof id != "function"){
18536 this.filtered = {};
18541 * Ext JS Library 1.1.1
18542 * Copyright(c) 2006-2007, Ext JS, LLC.
18544 * Originally Released Under LGPL - original licence link has changed is not relivant.
18547 * <script type="text/javascript">
18552 * @class Roo.tree.TreeSorter
18553 * Provides sorting of nodes in a TreePanel
18555 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18556 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18557 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18558 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18559 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18560 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18562 * @param {TreePanel} tree
18563 * @param {Object} config
18565 Roo.tree.TreeSorter = function(tree, config){
18566 Roo.apply(this, config);
18567 tree.on("beforechildrenrendered", this.doSort, this);
18568 tree.on("append", this.updateSort, this);
18569 tree.on("insert", this.updateSort, this);
18571 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18572 var p = this.property || "text";
18573 var sortType = this.sortType;
18574 var fs = this.folderSort;
18575 var cs = this.caseSensitive === true;
18576 var leafAttr = this.leafAttr || 'leaf';
18578 this.sortFn = function(n1, n2){
18580 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18583 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18587 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18588 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18590 return dsc ? +1 : -1;
18592 return dsc ? -1 : +1;
18599 Roo.tree.TreeSorter.prototype = {
18600 doSort : function(node){
18601 node.sort(this.sortFn);
18604 compareNodes : function(n1, n2){
18605 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18608 updateSort : function(tree, node){
18609 if(node.childrenRendered){
18610 this.doSort.defer(1, this, [node]);
18615 * Ext JS Library 1.1.1
18616 * Copyright(c) 2006-2007, Ext JS, LLC.
18618 * Originally Released Under LGPL - original licence link has changed is not relivant.
18621 * <script type="text/javascript">
18624 if(Roo.dd.DropZone){
18626 Roo.tree.TreeDropZone = function(tree, config){
18627 this.allowParentInsert = false;
18628 this.allowContainerDrop = false;
18629 this.appendOnly = false;
18630 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18632 this.lastInsertClass = "x-tree-no-status";
18633 this.dragOverData = {};
18636 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18637 ddGroup : "TreeDD",
18639 expandDelay : 1000,
18641 expandNode : function(node){
18642 if(node.hasChildNodes() && !node.isExpanded()){
18643 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18647 queueExpand : function(node){
18648 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18651 cancelExpand : function(){
18652 if(this.expandProcId){
18653 clearTimeout(this.expandProcId);
18654 this.expandProcId = false;
18658 isValidDropPoint : function(n, pt, dd, e, data){
18659 if(!n || !data){ return false; }
18660 var targetNode = n.node;
18661 var dropNode = data.node;
18662 // default drop rules
18663 if(!(targetNode && targetNode.isTarget && pt)){
18666 if(pt == "append" && targetNode.allowChildren === false){
18669 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18672 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18675 // reuse the object
18676 var overEvent = this.dragOverData;
18677 overEvent.tree = this.tree;
18678 overEvent.target = targetNode;
18679 overEvent.data = data;
18680 overEvent.point = pt;
18681 overEvent.source = dd;
18682 overEvent.rawEvent = e;
18683 overEvent.dropNode = dropNode;
18684 overEvent.cancel = false;
18685 var result = this.tree.fireEvent("nodedragover", overEvent);
18686 return overEvent.cancel === false && result !== false;
18689 getDropPoint : function(e, n, dd){
18692 return tn.allowChildren !== false ? "append" : false; // always append for root
18694 var dragEl = n.ddel;
18695 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18696 var y = Roo.lib.Event.getPageY(e);
18697 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18699 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18700 var noAppend = tn.allowChildren === false;
18701 if(this.appendOnly || tn.parentNode.allowChildren === false){
18702 return noAppend ? false : "append";
18704 var noBelow = false;
18705 if(!this.allowParentInsert){
18706 noBelow = tn.hasChildNodes() && tn.isExpanded();
18708 var q = (b - t) / (noAppend ? 2 : 3);
18709 if(y >= t && y < (t + q)){
18711 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18718 onNodeEnter : function(n, dd, e, data){
18719 this.cancelExpand();
18722 onNodeOver : function(n, dd, e, data){
18723 var pt = this.getDropPoint(e, n, dd);
18726 // auto node expand check
18727 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18728 this.queueExpand(node);
18729 }else if(pt != "append"){
18730 this.cancelExpand();
18733 // set the insert point style on the target node
18734 var returnCls = this.dropNotAllowed;
18735 if(this.isValidDropPoint(n, pt, dd, e, data)){
18740 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18741 cls = "x-tree-drag-insert-above";
18742 }else if(pt == "below"){
18743 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18744 cls = "x-tree-drag-insert-below";
18746 returnCls = "x-tree-drop-ok-append";
18747 cls = "x-tree-drag-append";
18749 if(this.lastInsertClass != cls){
18750 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18751 this.lastInsertClass = cls;
18758 onNodeOut : function(n, dd, e, data){
18759 this.cancelExpand();
18760 this.removeDropIndicators(n);
18763 onNodeDrop : function(n, dd, e, data){
18764 var point = this.getDropPoint(e, n, dd);
18765 var targetNode = n.node;
18766 targetNode.ui.startDrop();
18767 if(!this.isValidDropPoint(n, point, dd, e, data)){
18768 targetNode.ui.endDrop();
18771 // first try to find the drop node
18772 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18775 target: targetNode,
18780 dropNode: dropNode,
18783 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18784 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18785 targetNode.ui.endDrop();
18788 // allow target changing
18789 targetNode = dropEvent.target;
18790 if(point == "append" && !targetNode.isExpanded()){
18791 targetNode.expand(false, null, function(){
18792 this.completeDrop(dropEvent);
18793 }.createDelegate(this));
18795 this.completeDrop(dropEvent);
18800 completeDrop : function(de){
18801 var ns = de.dropNode, p = de.point, t = de.target;
18802 if(!(ns instanceof Array)){
18806 for(var i = 0, len = ns.length; i < len; i++){
18809 t.parentNode.insertBefore(n, t);
18810 }else if(p == "below"){
18811 t.parentNode.insertBefore(n, t.nextSibling);
18817 if(this.tree.hlDrop){
18821 this.tree.fireEvent("nodedrop", de);
18824 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18825 if(this.tree.hlDrop){
18826 dropNode.ui.focus();
18827 dropNode.ui.highlight();
18829 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18832 getTree : function(){
18836 removeDropIndicators : function(n){
18839 Roo.fly(el).removeClass([
18840 "x-tree-drag-insert-above",
18841 "x-tree-drag-insert-below",
18842 "x-tree-drag-append"]);
18843 this.lastInsertClass = "_noclass";
18847 beforeDragDrop : function(target, e, id){
18848 this.cancelExpand();
18852 afterRepair : function(data){
18853 if(data && Roo.enableFx){
18854 data.node.ui.highlight();
18863 * Ext JS Library 1.1.1
18864 * Copyright(c) 2006-2007, Ext JS, LLC.
18866 * Originally Released Under LGPL - original licence link has changed is not relivant.
18869 * <script type="text/javascript">
18873 if(Roo.dd.DragZone){
18874 Roo.tree.TreeDragZone = function(tree, config){
18875 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18879 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18880 ddGroup : "TreeDD",
18882 onBeforeDrag : function(data, e){
18884 return n && n.draggable && !n.disabled;
18887 onInitDrag : function(e){
18888 var data = this.dragData;
18889 this.tree.getSelectionModel().select(data.node);
18890 this.proxy.update("");
18891 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18892 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18895 getRepairXY : function(e, data){
18896 return data.node.ui.getDDRepairXY();
18899 onEndDrag : function(data, e){
18900 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18903 onValidDrop : function(dd, e, id){
18904 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18908 beforeInvalidDrop : function(e, id){
18909 // this scrolls the original position back into view
18910 var sm = this.tree.getSelectionModel();
18911 sm.clearSelections();
18912 sm.select(this.dragData.node);
18917 * Ext JS Library 1.1.1
18918 * Copyright(c) 2006-2007, Ext JS, LLC.
18920 * Originally Released Under LGPL - original licence link has changed is not relivant.
18923 * <script type="text/javascript">
18926 * @class Roo.tree.TreeEditor
18927 * @extends Roo.Editor
18928 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18929 * as the editor field.
18931 * @param {TreePanel} tree
18932 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18934 Roo.tree.TreeEditor = function(tree, config){
18935 config = config || {};
18936 var field = config.events ? config : new Roo.form.TextField(config);
18937 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18941 tree.on('beforeclick', this.beforeNodeClick, this);
18942 tree.getTreeEl().on('mousedown', this.hide, this);
18943 this.on('complete', this.updateNode, this);
18944 this.on('beforestartedit', this.fitToTree, this);
18945 this.on('startedit', this.bindScroll, this, {delay:10});
18946 this.on('specialkey', this.onSpecialKey, this);
18949 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18951 * @cfg {String} alignment
18952 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18958 * @cfg {Boolean} hideEl
18959 * True to hide the bound element while the editor is displayed (defaults to false)
18963 * @cfg {String} cls
18964 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18966 cls: "x-small-editor x-tree-editor",
18968 * @cfg {Boolean} shim
18969 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18975 * @cfg {Number} maxWidth
18976 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18977 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18978 * scroll and client offsets into account prior to each edit.
18985 fitToTree : function(ed, el){
18986 var td = this.tree.getTreeEl().dom, nd = el.dom;
18987 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
18988 td.scrollLeft = nd.offsetLeft;
18992 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
18993 this.setSize(w, '');
18997 triggerEdit : function(node){
18998 this.completeEdit();
18999 this.editNode = node;
19000 this.startEdit(node.ui.textNode, node.text);
19004 bindScroll : function(){
19005 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19009 beforeNodeClick : function(node, e){
19010 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19011 this.lastClick = new Date();
19012 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19014 this.triggerEdit(node);
19020 updateNode : function(ed, value){
19021 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19022 this.editNode.setText(value);
19026 onHide : function(){
19027 Roo.tree.TreeEditor.superclass.onHide.call(this);
19029 this.editNode.ui.focus();
19034 onSpecialKey : function(field, e){
19035 var k = e.getKey();
19039 }else if(k == e.ENTER && !e.hasModifier()){
19041 this.completeEdit();
19044 });//<Script type="text/javascript">
19047 * Ext JS Library 1.1.1
19048 * Copyright(c) 2006-2007, Ext JS, LLC.
19050 * Originally Released Under LGPL - original licence link has changed is not relivant.
19053 * <script type="text/javascript">
19057 * Not documented??? - probably should be...
19060 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19061 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19063 renderElements : function(n, a, targetNode, bulkRender){
19064 //consel.log("renderElements?");
19065 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19067 var t = n.getOwnerTree();
19068 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19070 var cols = t.columns;
19071 var bw = t.borderWidth;
19073 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19074 var cb = typeof a.checked == "boolean";
19075 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19076 var colcls = 'x-t-' + tid + '-c0';
19078 '<li class="x-tree-node">',
19081 '<div class="x-tree-node-el ', a.cls,'">',
19083 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19086 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19087 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19088 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19089 (a.icon ? ' x-tree-node-inline-icon' : ''),
19090 (a.iconCls ? ' '+a.iconCls : ''),
19091 '" unselectable="on" />',
19092 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19093 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19095 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19096 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19097 '<span unselectable="on" qtip="' + tx + '">',
19101 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19102 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19104 for(var i = 1, len = cols.length; i < len; i++){
19106 colcls = 'x-t-' + tid + '-c' +i;
19107 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19108 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19109 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19115 '<div class="x-clear"></div></div>',
19116 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19119 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19120 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19121 n.nextSibling.ui.getEl(), buf.join(""));
19123 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19125 var el = this.wrap.firstChild;
19127 this.elNode = el.firstChild;
19128 this.ranchor = el.childNodes[1];
19129 this.ctNode = this.wrap.childNodes[1];
19130 var cs = el.firstChild.childNodes;
19131 this.indentNode = cs[0];
19132 this.ecNode = cs[1];
19133 this.iconNode = cs[2];
19136 this.checkbox = cs[3];
19139 this.anchor = cs[index];
19141 this.textNode = cs[index].firstChild;
19143 //el.on("click", this.onClick, this);
19144 //el.on("dblclick", this.onDblClick, this);
19147 // console.log(this);
19149 initEvents : function(){
19150 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19153 var a = this.ranchor;
19155 var el = Roo.get(a);
19157 if(Roo.isOpera){ // opera render bug ignores the CSS
19158 el.setStyle("text-decoration", "none");
19161 el.on("click", this.onClick, this);
19162 el.on("dblclick", this.onDblClick, this);
19163 el.on("contextmenu", this.onContextMenu, this);
19167 /*onSelectedChange : function(state){
19170 this.addClass("x-tree-selected");
19173 this.removeClass("x-tree-selected");
19176 addClass : function(cls){
19178 Roo.fly(this.elRow).addClass(cls);
19184 removeClass : function(cls){
19186 Roo.fly(this.elRow).removeClass(cls);
19192 });//<Script type="text/javascript">
19196 * Ext JS Library 1.1.1
19197 * Copyright(c) 2006-2007, Ext JS, LLC.
19199 * Originally Released Under LGPL - original licence link has changed is not relivant.
19202 * <script type="text/javascript">
19207 * @class Roo.tree.ColumnTree
19208 * @extends Roo.data.TreePanel
19209 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19210 * @cfg {int} borderWidth compined right/left border allowance
19212 * @param {String/HTMLElement/Element} el The container element
19213 * @param {Object} config
19215 Roo.tree.ColumnTree = function(el, config)
19217 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19221 * Fire this event on a container when it resizes
19222 * @param {int} w Width
19223 * @param {int} h Height
19227 this.on('resize', this.onResize, this);
19230 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19234 borderWidth: Roo.isBorderBox ? 0 : 2,
19237 render : function(){
19238 // add the header.....
19240 Roo.tree.ColumnTree.superclass.render.apply(this);
19242 this.el.addClass('x-column-tree');
19244 this.headers = this.el.createChild(
19245 {cls:'x-tree-headers'},this.innerCt.dom);
19247 var cols = this.columns, c;
19248 var totalWidth = 0;
19250 var len = cols.length;
19251 for(var i = 0; i < len; i++){
19253 totalWidth += c.width;
19254 this.headEls.push(this.headers.createChild({
19255 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19257 cls:'x-tree-hd-text',
19260 style:'width:'+(c.width-this.borderWidth)+'px;'
19263 this.headers.createChild({cls:'x-clear'});
19264 // prevent floats from wrapping when clipped
19265 this.headers.setWidth(totalWidth);
19266 //this.innerCt.setWidth(totalWidth);
19267 this.innerCt.setStyle({ overflow: 'auto' });
19268 this.onResize(this.width, this.height);
19272 onResize : function(w,h)
19277 this.innerCt.setWidth(this.width);
19278 this.innerCt.setHeight(this.height-20);
19281 var cols = this.columns, c;
19282 var totalWidth = 0;
19284 var len = cols.length;
19285 for(var i = 0; i < len; i++){
19287 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19288 // it's the expander..
19289 expEl = this.headEls[i];
19292 totalWidth += c.width;
19296 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19298 this.headers.setWidth(w-20);
19307 * Ext JS Library 1.1.1
19308 * Copyright(c) 2006-2007, Ext JS, LLC.
19310 * Originally Released Under LGPL - original licence link has changed is not relivant.
19313 * <script type="text/javascript">
19317 * @class Roo.menu.Menu
19318 * @extends Roo.util.Observable
19319 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19320 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19322 * Creates a new Menu
19323 * @param {Object} config Configuration options
19325 Roo.menu.Menu = function(config){
19326 Roo.apply(this, config);
19327 this.id = this.id || Roo.id();
19330 * @event beforeshow
19331 * Fires before this menu is displayed
19332 * @param {Roo.menu.Menu} this
19336 * @event beforehide
19337 * Fires before this menu is hidden
19338 * @param {Roo.menu.Menu} this
19343 * Fires after this menu is displayed
19344 * @param {Roo.menu.Menu} this
19349 * Fires after this menu is hidden
19350 * @param {Roo.menu.Menu} this
19355 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19356 * @param {Roo.menu.Menu} this
19357 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19358 * @param {Roo.EventObject} e
19363 * Fires when the mouse is hovering over this menu
19364 * @param {Roo.menu.Menu} this
19365 * @param {Roo.EventObject} e
19366 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19371 * Fires when the mouse exits this menu
19372 * @param {Roo.menu.Menu} this
19373 * @param {Roo.EventObject} e
19374 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19379 * Fires when a menu item contained in this menu is clicked
19380 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19381 * @param {Roo.EventObject} e
19385 if (this.registerMenu) {
19386 Roo.menu.MenuMgr.register(this);
19389 var mis = this.items;
19390 this.items = new Roo.util.MixedCollection();
19392 this.add.apply(this, mis);
19396 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19398 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19402 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19403 * for bottom-right shadow (defaults to "sides")
19407 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19408 * this menu (defaults to "tl-tr?")
19410 subMenuAlign : "tl-tr?",
19412 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19413 * relative to its element of origin (defaults to "tl-bl?")
19415 defaultAlign : "tl-bl?",
19417 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19419 allowOtherMenus : false,
19421 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19423 registerMenu : true,
19428 render : function(){
19432 var el = this.el = new Roo.Layer({
19434 shadow:this.shadow,
19436 parentEl: this.parentEl || document.body,
19440 this.keyNav = new Roo.menu.MenuNav(this);
19443 el.addClass("x-menu-plain");
19446 el.addClass(this.cls);
19448 // generic focus element
19449 this.focusEl = el.createChild({
19450 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19452 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19453 ul.on("click", this.onClick, this);
19454 ul.on("mouseover", this.onMouseOver, this);
19455 ul.on("mouseout", this.onMouseOut, this);
19456 this.items.each(function(item){
19457 var li = document.createElement("li");
19458 li.className = "x-menu-list-item";
19459 ul.dom.appendChild(li);
19460 item.render(li, this);
19467 autoWidth : function(){
19468 var el = this.el, ul = this.ul;
19472 var w = this.width;
19475 }else if(Roo.isIE){
19476 el.setWidth(this.minWidth);
19477 var t = el.dom.offsetWidth; // force recalc
19478 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19483 delayAutoWidth : function(){
19486 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19488 this.awTask.delay(20);
19493 findTargetItem : function(e){
19494 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19495 if(t && t.menuItemId){
19496 return this.items.get(t.menuItemId);
19501 onClick : function(e){
19503 if(t = this.findTargetItem(e)){
19505 this.fireEvent("click", this, t, e);
19510 setActiveItem : function(item, autoExpand){
19511 if(item != this.activeItem){
19512 if(this.activeItem){
19513 this.activeItem.deactivate();
19515 this.activeItem = item;
19516 item.activate(autoExpand);
19517 }else if(autoExpand){
19523 tryActivate : function(start, step){
19524 var items = this.items;
19525 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19526 var item = items.get(i);
19527 if(!item.disabled && item.canActivate){
19528 this.setActiveItem(item, false);
19536 onMouseOver : function(e){
19538 if(t = this.findTargetItem(e)){
19539 if(t.canActivate && !t.disabled){
19540 this.setActiveItem(t, true);
19543 this.fireEvent("mouseover", this, e, t);
19547 onMouseOut : function(e){
19549 if(t = this.findTargetItem(e)){
19550 if(t == this.activeItem && t.shouldDeactivate(e)){
19551 this.activeItem.deactivate();
19552 delete this.activeItem;
19555 this.fireEvent("mouseout", this, e, t);
19559 * Read-only. Returns true if the menu is currently displayed, else false.
19562 isVisible : function(){
19563 return this.el && !this.hidden;
19567 * Displays this menu relative to another element
19568 * @param {String/HTMLElement/Roo.Element} element The element to align to
19569 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19570 * the element (defaults to this.defaultAlign)
19571 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19573 show : function(el, pos, parentMenu){
19574 this.parentMenu = parentMenu;
19578 this.fireEvent("beforeshow", this);
19579 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19583 * Displays this menu at a specific xy position
19584 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19585 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19587 showAt : function(xy, parentMenu, /* private: */_e){
19588 this.parentMenu = parentMenu;
19593 this.fireEvent("beforeshow", this);
19594 xy = this.el.adjustForConstraints(xy);
19598 this.hidden = false;
19600 this.fireEvent("show", this);
19603 focus : function(){
19605 this.doFocus.defer(50, this);
19609 doFocus : function(){
19611 this.focusEl.focus();
19616 * Hides this menu and optionally all parent menus
19617 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19619 hide : function(deep){
19620 if(this.el && this.isVisible()){
19621 this.fireEvent("beforehide", this);
19622 if(this.activeItem){
19623 this.activeItem.deactivate();
19624 this.activeItem = null;
19627 this.hidden = true;
19628 this.fireEvent("hide", this);
19630 if(deep === true && this.parentMenu){
19631 this.parentMenu.hide(true);
19636 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19637 * Any of the following are valid:
19639 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19640 * <li>An HTMLElement object which will be converted to a menu item</li>
19641 * <li>A menu item config object that will be created as a new menu item</li>
19642 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19643 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19648 var menu = new Roo.menu.Menu();
19650 // Create a menu item to add by reference
19651 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19653 // Add a bunch of items at once using different methods.
19654 // Only the last item added will be returned.
19655 var item = menu.add(
19656 menuItem, // add existing item by ref
19657 'Dynamic Item', // new TextItem
19658 '-', // new separator
19659 { text: 'Config Item' } // new item by config
19662 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19663 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19666 var a = arguments, l = a.length, item;
19667 for(var i = 0; i < l; i++){
19669 if ((typeof(el) == "object") && el.xtype && el.xns) {
19670 el = Roo.factory(el, Roo.menu);
19673 if(el.render){ // some kind of Item
19674 item = this.addItem(el);
19675 }else if(typeof el == "string"){ // string
19676 if(el == "separator" || el == "-"){
19677 item = this.addSeparator();
19679 item = this.addText(el);
19681 }else if(el.tagName || el.el){ // element
19682 item = this.addElement(el);
19683 }else if(typeof el == "object"){ // must be menu item config?
19684 item = this.addMenuItem(el);
19691 * Returns this menu's underlying {@link Roo.Element} object
19692 * @return {Roo.Element} The element
19694 getEl : function(){
19702 * Adds a separator bar to the menu
19703 * @return {Roo.menu.Item} The menu item that was added
19705 addSeparator : function(){
19706 return this.addItem(new Roo.menu.Separator());
19710 * Adds an {@link Roo.Element} object to the menu
19711 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19712 * @return {Roo.menu.Item} The menu item that was added
19714 addElement : function(el){
19715 return this.addItem(new Roo.menu.BaseItem(el));
19719 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19720 * @param {Roo.menu.Item} item The menu item to add
19721 * @return {Roo.menu.Item} The menu item that was added
19723 addItem : function(item){
19724 this.items.add(item);
19726 var li = document.createElement("li");
19727 li.className = "x-menu-list-item";
19728 this.ul.dom.appendChild(li);
19729 item.render(li, this);
19730 this.delayAutoWidth();
19736 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19737 * @param {Object} config A MenuItem config object
19738 * @return {Roo.menu.Item} The menu item that was added
19740 addMenuItem : function(config){
19741 if(!(config instanceof Roo.menu.Item)){
19742 if(typeof config.checked == "boolean"){ // must be check menu item config?
19743 config = new Roo.menu.CheckItem(config);
19745 config = new Roo.menu.Item(config);
19748 return this.addItem(config);
19752 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19753 * @param {String} text The text to display in the menu item
19754 * @return {Roo.menu.Item} The menu item that was added
19756 addText : function(text){
19757 return this.addItem(new Roo.menu.TextItem({ text : text }));
19761 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19762 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19763 * @param {Roo.menu.Item} item The menu item to add
19764 * @return {Roo.menu.Item} The menu item that was added
19766 insert : function(index, item){
19767 this.items.insert(index, item);
19769 var li = document.createElement("li");
19770 li.className = "x-menu-list-item";
19771 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19772 item.render(li, this);
19773 this.delayAutoWidth();
19779 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19780 * @param {Roo.menu.Item} item The menu item to remove
19782 remove : function(item){
19783 this.items.removeKey(item.id);
19788 * Removes and destroys all items in the menu
19790 removeAll : function(){
19792 while(f = this.items.first()){
19798 // MenuNav is a private utility class used internally by the Menu
19799 Roo.menu.MenuNav = function(menu){
19800 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19801 this.scope = this.menu = menu;
19804 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19805 doRelay : function(e, h){
19806 var k = e.getKey();
19807 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19808 this.menu.tryActivate(0, 1);
19811 return h.call(this.scope || this, e, this.menu);
19814 up : function(e, m){
19815 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19816 m.tryActivate(m.items.length-1, -1);
19820 down : function(e, m){
19821 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19822 m.tryActivate(0, 1);
19826 right : function(e, m){
19828 m.activeItem.expandMenu(true);
19832 left : function(e, m){
19834 if(m.parentMenu && m.parentMenu.activeItem){
19835 m.parentMenu.activeItem.activate();
19839 enter : function(e, m){
19841 e.stopPropagation();
19842 m.activeItem.onClick(e);
19843 m.fireEvent("click", this, m.activeItem);
19849 * Ext JS Library 1.1.1
19850 * Copyright(c) 2006-2007, Ext JS, LLC.
19852 * Originally Released Under LGPL - original licence link has changed is not relivant.
19855 * <script type="text/javascript">
19859 * @class Roo.menu.MenuMgr
19860 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19863 Roo.menu.MenuMgr = function(){
19864 var menus, active, groups = {}, attached = false, lastShow = new Date();
19866 // private - called when first menu is created
19869 active = new Roo.util.MixedCollection();
19870 Roo.get(document).addKeyListener(27, function(){
19871 if(active.length > 0){
19878 function hideAll(){
19879 if(active && active.length > 0){
19880 var c = active.clone();
19881 c.each(function(m){
19888 function onHide(m){
19890 if(active.length < 1){
19891 Roo.get(document).un("mousedown", onMouseDown);
19897 function onShow(m){
19898 var last = active.last();
19899 lastShow = new Date();
19902 Roo.get(document).on("mousedown", onMouseDown);
19906 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19907 m.parentMenu.activeChild = m;
19908 }else if(last && last.isVisible()){
19909 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19914 function onBeforeHide(m){
19916 m.activeChild.hide();
19918 if(m.autoHideTimer){
19919 clearTimeout(m.autoHideTimer);
19920 delete m.autoHideTimer;
19925 function onBeforeShow(m){
19926 var pm = m.parentMenu;
19927 if(!pm && !m.allowOtherMenus){
19929 }else if(pm && pm.activeChild && active != m){
19930 pm.activeChild.hide();
19935 function onMouseDown(e){
19936 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19942 function onBeforeCheck(mi, state){
19944 var g = groups[mi.group];
19945 for(var i = 0, l = g.length; i < l; i++){
19947 g[i].setChecked(false);
19956 * Hides all menus that are currently visible
19958 hideAll : function(){
19963 register : function(menu){
19967 menus[menu.id] = menu;
19968 menu.on("beforehide", onBeforeHide);
19969 menu.on("hide", onHide);
19970 menu.on("beforeshow", onBeforeShow);
19971 menu.on("show", onShow);
19972 var g = menu.group;
19973 if(g && menu.events["checkchange"]){
19977 groups[g].push(menu);
19978 menu.on("checkchange", onCheck);
19983 * Returns a {@link Roo.menu.Menu} object
19984 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19985 * be used to generate and return a new Menu instance.
19987 get : function(menu){
19988 if(typeof menu == "string"){ // menu id
19989 return menus[menu];
19990 }else if(menu.events){ // menu instance
19992 }else if(typeof menu.length == 'number'){ // array of menu items?
19993 return new Roo.menu.Menu({items:menu});
19994 }else{ // otherwise, must be a config
19995 return new Roo.menu.Menu(menu);
20000 unregister : function(menu){
20001 delete menus[menu.id];
20002 menu.un("beforehide", onBeforeHide);
20003 menu.un("hide", onHide);
20004 menu.un("beforeshow", onBeforeShow);
20005 menu.un("show", onShow);
20006 var g = menu.group;
20007 if(g && menu.events["checkchange"]){
20008 groups[g].remove(menu);
20009 menu.un("checkchange", onCheck);
20014 registerCheckable : function(menuItem){
20015 var g = menuItem.group;
20020 groups[g].push(menuItem);
20021 menuItem.on("beforecheckchange", onBeforeCheck);
20026 unregisterCheckable : function(menuItem){
20027 var g = menuItem.group;
20029 groups[g].remove(menuItem);
20030 menuItem.un("beforecheckchange", onBeforeCheck);
20036 * Ext JS Library 1.1.1
20037 * Copyright(c) 2006-2007, Ext JS, LLC.
20039 * Originally Released Under LGPL - original licence link has changed is not relivant.
20042 * <script type="text/javascript">
20047 * @class Roo.menu.BaseItem
20048 * @extends Roo.Component
20049 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20050 * management and base configuration options shared by all menu components.
20052 * Creates a new BaseItem
20053 * @param {Object} config Configuration options
20055 Roo.menu.BaseItem = function(config){
20056 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20061 * Fires when this item is clicked
20062 * @param {Roo.menu.BaseItem} this
20063 * @param {Roo.EventObject} e
20068 * Fires when this item is activated
20069 * @param {Roo.menu.BaseItem} this
20073 * @event deactivate
20074 * Fires when this item is deactivated
20075 * @param {Roo.menu.BaseItem} this
20081 this.on("click", this.handler, this.scope, true);
20085 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20087 * @cfg {Function} handler
20088 * A function that will handle the click event of this menu item (defaults to undefined)
20091 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20093 canActivate : false,
20095 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20097 activeClass : "x-menu-item-active",
20099 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20101 hideOnClick : true,
20103 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20108 ctype: "Roo.menu.BaseItem",
20111 actionMode : "container",
20114 render : function(container, parentMenu){
20115 this.parentMenu = parentMenu;
20116 Roo.menu.BaseItem.superclass.render.call(this, container);
20117 this.container.menuItemId = this.id;
20121 onRender : function(container, position){
20122 this.el = Roo.get(this.el);
20123 container.dom.appendChild(this.el.dom);
20127 onClick : function(e){
20128 if(!this.disabled && this.fireEvent("click", this, e) !== false
20129 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20130 this.handleClick(e);
20137 activate : function(){
20141 var li = this.container;
20142 li.addClass(this.activeClass);
20143 this.region = li.getRegion().adjust(2, 2, -2, -2);
20144 this.fireEvent("activate", this);
20149 deactivate : function(){
20150 this.container.removeClass(this.activeClass);
20151 this.fireEvent("deactivate", this);
20155 shouldDeactivate : function(e){
20156 return !this.region || !this.region.contains(e.getPoint());
20160 handleClick : function(e){
20161 if(this.hideOnClick){
20162 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20167 expandMenu : function(autoActivate){
20172 hideMenu : function(){
20177 * Ext JS Library 1.1.1
20178 * Copyright(c) 2006-2007, Ext JS, LLC.
20180 * Originally Released Under LGPL - original licence link has changed is not relivant.
20183 * <script type="text/javascript">
20187 * @class Roo.menu.Adapter
20188 * @extends Roo.menu.BaseItem
20189 * 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.
20190 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20192 * Creates a new Adapter
20193 * @param {Object} config Configuration options
20195 Roo.menu.Adapter = function(component, config){
20196 Roo.menu.Adapter.superclass.constructor.call(this, config);
20197 this.component = component;
20199 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20201 canActivate : true,
20204 onRender : function(container, position){
20205 this.component.render(container);
20206 this.el = this.component.getEl();
20210 activate : function(){
20214 this.component.focus();
20215 this.fireEvent("activate", this);
20220 deactivate : function(){
20221 this.fireEvent("deactivate", this);
20225 disable : function(){
20226 this.component.disable();
20227 Roo.menu.Adapter.superclass.disable.call(this);
20231 enable : function(){
20232 this.component.enable();
20233 Roo.menu.Adapter.superclass.enable.call(this);
20237 * Ext JS Library 1.1.1
20238 * Copyright(c) 2006-2007, Ext JS, LLC.
20240 * Originally Released Under LGPL - original licence link has changed is not relivant.
20243 * <script type="text/javascript">
20247 * @class Roo.menu.TextItem
20248 * @extends Roo.menu.BaseItem
20249 * Adds a static text string to a menu, usually used as either a heading or group separator.
20250 * Note: old style constructor with text is still supported.
20253 * Creates a new TextItem
20254 * @param {Object} cfg Configuration
20256 Roo.menu.TextItem = function(cfg){
20257 if (typeof(cfg) == 'string') {
20260 Roo.apply(this,cfg);
20263 Roo.menu.TextItem.superclass.constructor.call(this);
20266 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20268 * @cfg {Boolean} text Text to show on item.
20273 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20275 hideOnClick : false,
20277 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20279 itemCls : "x-menu-text",
20282 onRender : function(){
20283 var s = document.createElement("span");
20284 s.className = this.itemCls;
20285 s.innerHTML = this.text;
20287 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20291 * Ext JS Library 1.1.1
20292 * Copyright(c) 2006-2007, Ext JS, LLC.
20294 * Originally Released Under LGPL - original licence link has changed is not relivant.
20297 * <script type="text/javascript">
20301 * @class Roo.menu.Separator
20302 * @extends Roo.menu.BaseItem
20303 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20304 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20306 * @param {Object} config Configuration options
20308 Roo.menu.Separator = function(config){
20309 Roo.menu.Separator.superclass.constructor.call(this, config);
20312 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20314 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20316 itemCls : "x-menu-sep",
20318 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20320 hideOnClick : false,
20323 onRender : function(li){
20324 var s = document.createElement("span");
20325 s.className = this.itemCls;
20326 s.innerHTML = " ";
20328 li.addClass("x-menu-sep-li");
20329 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20333 * Ext JS Library 1.1.1
20334 * Copyright(c) 2006-2007, Ext JS, LLC.
20336 * Originally Released Under LGPL - original licence link has changed is not relivant.
20339 * <script type="text/javascript">
20342 * @class Roo.menu.Item
20343 * @extends Roo.menu.BaseItem
20344 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20345 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20346 * activation and click handling.
20348 * Creates a new Item
20349 * @param {Object} config Configuration options
20351 Roo.menu.Item = function(config){
20352 Roo.menu.Item.superclass.constructor.call(this, config);
20354 this.menu = Roo.menu.MenuMgr.get(this.menu);
20357 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20360 * @cfg {String} text
20361 * The text to show on the menu item.
20365 * @cfg {String} HTML to render in menu
20366 * The text to show on the menu item (HTML version).
20370 * @cfg {String} icon
20371 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20375 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20377 itemCls : "x-menu-item",
20379 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20381 canActivate : true,
20383 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20386 // doc'd in BaseItem
20390 ctype: "Roo.menu.Item",
20393 onRender : function(container, position){
20394 var el = document.createElement("a");
20395 el.hideFocus = true;
20396 el.unselectable = "on";
20397 el.href = this.href || "#";
20398 if(this.hrefTarget){
20399 el.target = this.hrefTarget;
20401 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20403 var html = this.html.length ? this.html : String.format('{0}',this.text);
20405 el.innerHTML = String.format(
20406 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20407 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20409 Roo.menu.Item.superclass.onRender.call(this, container, position);
20413 * Sets the text to display in this menu item
20414 * @param {String} text The text to display
20415 * @param {Boolean} isHTML true to indicate text is pure html.
20417 setText : function(text, isHTML){
20425 var html = this.html.length ? this.html : String.format('{0}',this.text);
20427 this.el.update(String.format(
20428 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20429 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20430 this.parentMenu.autoWidth();
20435 handleClick : function(e){
20436 if(!this.href){ // if no link defined, stop the event automatically
20439 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20443 activate : function(autoExpand){
20444 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20454 shouldDeactivate : function(e){
20455 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20456 if(this.menu && this.menu.isVisible()){
20457 return !this.menu.getEl().getRegion().contains(e.getPoint());
20465 deactivate : function(){
20466 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20471 expandMenu : function(autoActivate){
20472 if(!this.disabled && this.menu){
20473 clearTimeout(this.hideTimer);
20474 delete this.hideTimer;
20475 if(!this.menu.isVisible() && !this.showTimer){
20476 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20477 }else if (this.menu.isVisible() && autoActivate){
20478 this.menu.tryActivate(0, 1);
20484 deferExpand : function(autoActivate){
20485 delete this.showTimer;
20486 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20488 this.menu.tryActivate(0, 1);
20493 hideMenu : function(){
20494 clearTimeout(this.showTimer);
20495 delete this.showTimer;
20496 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20497 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20502 deferHide : function(){
20503 delete this.hideTimer;
20508 * Ext JS Library 1.1.1
20509 * Copyright(c) 2006-2007, Ext JS, LLC.
20511 * Originally Released Under LGPL - original licence link has changed is not relivant.
20514 * <script type="text/javascript">
20518 * @class Roo.menu.CheckItem
20519 * @extends Roo.menu.Item
20520 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20522 * Creates a new CheckItem
20523 * @param {Object} config Configuration options
20525 Roo.menu.CheckItem = function(config){
20526 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20529 * @event beforecheckchange
20530 * Fires before the checked value is set, providing an opportunity to cancel if needed
20531 * @param {Roo.menu.CheckItem} this
20532 * @param {Boolean} checked The new checked value that will be set
20534 "beforecheckchange" : true,
20536 * @event checkchange
20537 * Fires after the checked value has been set
20538 * @param {Roo.menu.CheckItem} this
20539 * @param {Boolean} checked The checked value that was set
20541 "checkchange" : true
20543 if(this.checkHandler){
20544 this.on('checkchange', this.checkHandler, this.scope);
20547 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20549 * @cfg {String} group
20550 * All check items with the same group name will automatically be grouped into a single-select
20551 * radio button group (defaults to '')
20554 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20556 itemCls : "x-menu-item x-menu-check-item",
20558 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20560 groupClass : "x-menu-group-item",
20563 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20564 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20565 * initialized with checked = true will be rendered as checked.
20570 ctype: "Roo.menu.CheckItem",
20573 onRender : function(c){
20574 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20576 this.el.addClass(this.groupClass);
20578 Roo.menu.MenuMgr.registerCheckable(this);
20580 this.checked = false;
20581 this.setChecked(true, true);
20586 destroy : function(){
20588 Roo.menu.MenuMgr.unregisterCheckable(this);
20590 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20594 * Set the checked state of this item
20595 * @param {Boolean} checked The new checked value
20596 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20598 setChecked : function(state, suppressEvent){
20599 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20600 if(this.container){
20601 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20603 this.checked = state;
20604 if(suppressEvent !== true){
20605 this.fireEvent("checkchange", this, state);
20611 handleClick : function(e){
20612 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20613 this.setChecked(!this.checked);
20615 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20619 * Ext JS Library 1.1.1
20620 * Copyright(c) 2006-2007, Ext JS, LLC.
20622 * Originally Released Under LGPL - original licence link has changed is not relivant.
20625 * <script type="text/javascript">
20629 * @class Roo.menu.DateItem
20630 * @extends Roo.menu.Adapter
20631 * A menu item that wraps the {@link Roo.DatPicker} component.
20633 * Creates a new DateItem
20634 * @param {Object} config Configuration options
20636 Roo.menu.DateItem = function(config){
20637 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20638 /** The Roo.DatePicker object @type Roo.DatePicker */
20639 this.picker = this.component;
20640 this.addEvents({select: true});
20642 this.picker.on("render", function(picker){
20643 picker.getEl().swallowEvent("click");
20644 picker.container.addClass("x-menu-date-item");
20647 this.picker.on("select", this.onSelect, this);
20650 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20652 onSelect : function(picker, date){
20653 this.fireEvent("select", this, date, picker);
20654 Roo.menu.DateItem.superclass.handleClick.call(this);
20658 * Ext JS Library 1.1.1
20659 * Copyright(c) 2006-2007, Ext JS, LLC.
20661 * Originally Released Under LGPL - original licence link has changed is not relivant.
20664 * <script type="text/javascript">
20668 * @class Roo.menu.ColorItem
20669 * @extends Roo.menu.Adapter
20670 * A menu item that wraps the {@link Roo.ColorPalette} component.
20672 * Creates a new ColorItem
20673 * @param {Object} config Configuration options
20675 Roo.menu.ColorItem = function(config){
20676 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20677 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20678 this.palette = this.component;
20679 this.relayEvents(this.palette, ["select"]);
20680 if(this.selectHandler){
20681 this.on('select', this.selectHandler, this.scope);
20684 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20686 * Ext JS Library 1.1.1
20687 * Copyright(c) 2006-2007, Ext JS, LLC.
20689 * Originally Released Under LGPL - original licence link has changed is not relivant.
20692 * <script type="text/javascript">
20697 * @class Roo.menu.DateMenu
20698 * @extends Roo.menu.Menu
20699 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20701 * Creates a new DateMenu
20702 * @param {Object} config Configuration options
20704 Roo.menu.DateMenu = function(config){
20705 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20707 var di = new Roo.menu.DateItem(config);
20710 * The {@link Roo.DatePicker} instance for this DateMenu
20713 this.picker = di.picker;
20716 * @param {DatePicker} picker
20717 * @param {Date} date
20719 this.relayEvents(di, ["select"]);
20721 this.on('beforeshow', function(){
20723 this.picker.hideMonthPicker(true);
20727 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20731 * Ext JS Library 1.1.1
20732 * Copyright(c) 2006-2007, Ext JS, LLC.
20734 * Originally Released Under LGPL - original licence link has changed is not relivant.
20737 * <script type="text/javascript">
20742 * @class Roo.menu.ColorMenu
20743 * @extends Roo.menu.Menu
20744 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20746 * Creates a new ColorMenu
20747 * @param {Object} config Configuration options
20749 Roo.menu.ColorMenu = function(config){
20750 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20752 var ci = new Roo.menu.ColorItem(config);
20755 * The {@link Roo.ColorPalette} instance for this ColorMenu
20756 * @type ColorPalette
20758 this.palette = ci.palette;
20761 * @param {ColorPalette} palette
20762 * @param {String} color
20764 this.relayEvents(ci, ["select"]);
20766 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20768 * Ext JS Library 1.1.1
20769 * Copyright(c) 2006-2007, Ext JS, LLC.
20771 * Originally Released Under LGPL - original licence link has changed is not relivant.
20774 * <script type="text/javascript">
20778 * @class Roo.form.Field
20779 * @extends Roo.BoxComponent
20780 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20782 * Creates a new Field
20783 * @param {Object} config Configuration options
20785 Roo.form.Field = function(config){
20786 Roo.form.Field.superclass.constructor.call(this, config);
20789 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20791 * @cfg {String} fieldLabel Label to use when rendering a form.
20794 * @cfg {String} qtip Mouse over tip
20798 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20800 invalidClass : "x-form-invalid",
20802 * @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")
20804 invalidText : "The value in this field is invalid",
20806 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20808 focusClass : "x-form-focus",
20810 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20811 automatic validation (defaults to "keyup").
20813 validationEvent : "keyup",
20815 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20817 validateOnBlur : true,
20819 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20821 validationDelay : 250,
20823 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20824 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20826 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20828 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20830 fieldClass : "x-form-field",
20832 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20835 ----------- ----------------------------------------------------------------------
20836 qtip Display a quick tip when the user hovers over the field
20837 title Display a default browser title attribute popup
20838 under Add a block div beneath the field containing the error text
20839 side Add an error icon to the right of the field with a popup on hover
20840 [element id] Add the error text directly to the innerHTML of the specified element
20843 msgTarget : 'qtip',
20845 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20850 * @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.
20855 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20860 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20862 inputType : undefined,
20865 * @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).
20867 tabIndex : undefined,
20870 isFormField : true,
20875 * @property {Roo.Element} fieldEl
20876 * Element Containing the rendered Field (with label etc.)
20879 * @cfg {Mixed} value A value to initialize this field with.
20884 * @cfg {String} name The field's HTML name attribute.
20887 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20891 initComponent : function(){
20892 Roo.form.Field.superclass.initComponent.call(this);
20896 * Fires when this field receives input focus.
20897 * @param {Roo.form.Field} this
20902 * Fires when this field loses input focus.
20903 * @param {Roo.form.Field} this
20907 * @event specialkey
20908 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20909 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20910 * @param {Roo.form.Field} this
20911 * @param {Roo.EventObject} e The event object
20916 * Fires just before the field blurs if the field value has changed.
20917 * @param {Roo.form.Field} this
20918 * @param {Mixed} newValue The new value
20919 * @param {Mixed} oldValue The original value
20924 * Fires after the field has been marked as invalid.
20925 * @param {Roo.form.Field} this
20926 * @param {String} msg The validation message
20931 * Fires after the field has been validated with no errors.
20932 * @param {Roo.form.Field} this
20937 * Fires after the key up
20938 * @param {Roo.form.Field} this
20939 * @param {Roo.EventObject} e The event Object
20946 * Returns the name attribute of the field if available
20947 * @return {String} name The field name
20949 getName: function(){
20950 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20954 onRender : function(ct, position){
20955 Roo.form.Field.superclass.onRender.call(this, ct, position);
20957 var cfg = this.getAutoCreate();
20959 cfg.name = this.name || this.id;
20961 if(this.inputType){
20962 cfg.type = this.inputType;
20964 this.el = ct.createChild(cfg, position);
20966 var type = this.el.dom.type;
20968 if(type == 'password'){
20971 this.el.addClass('x-form-'+type);
20974 this.el.dom.readOnly = true;
20976 if(this.tabIndex !== undefined){
20977 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20980 this.el.addClass([this.fieldClass, this.cls]);
20985 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20986 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20987 * @return {Roo.form.Field} this
20989 applyTo : function(target){
20990 this.allowDomMove = false;
20991 this.el = Roo.get(target);
20992 this.render(this.el.dom.parentNode);
20997 initValue : function(){
20998 if(this.value !== undefined){
20999 this.setValue(this.value);
21000 }else if(this.el.dom.value.length > 0){
21001 this.setValue(this.el.dom.value);
21006 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21008 isDirty : function() {
21009 if(this.disabled) {
21012 return String(this.getValue()) !== String(this.originalValue);
21016 afterRender : function(){
21017 Roo.form.Field.superclass.afterRender.call(this);
21022 fireKey : function(e){
21023 //Roo.log('field ' + e.getKey());
21024 if(e.isNavKeyPress()){
21025 this.fireEvent("specialkey", this, e);
21030 * Resets the current field value to the originally loaded value and clears any validation messages
21032 reset : function(){
21033 this.setValue(this.originalValue);
21034 this.clearInvalid();
21038 initEvents : function(){
21039 // safari killled keypress - so keydown is now used..
21040 this.el.on("keydown" , this.fireKey, this);
21041 this.el.on("focus", this.onFocus, this);
21042 this.el.on("blur", this.onBlur, this);
21043 this.el.relayEvent('keyup', this);
21045 // reference to original value for reset
21046 this.originalValue = this.getValue();
21050 onFocus : function(){
21051 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21052 this.el.addClass(this.focusClass);
21054 if(!this.hasFocus){
21055 this.hasFocus = true;
21056 this.startValue = this.getValue();
21057 this.fireEvent("focus", this);
21061 beforeBlur : Roo.emptyFn,
21064 onBlur : function(){
21066 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21067 this.el.removeClass(this.focusClass);
21069 this.hasFocus = false;
21070 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21073 var v = this.getValue();
21074 if(String(v) !== String(this.startValue)){
21075 this.fireEvent('change', this, v, this.startValue);
21077 this.fireEvent("blur", this);
21081 * Returns whether or not the field value is currently valid
21082 * @param {Boolean} preventMark True to disable marking the field invalid
21083 * @return {Boolean} True if the value is valid, else false
21085 isValid : function(preventMark){
21089 var restore = this.preventMark;
21090 this.preventMark = preventMark === true;
21091 var v = this.validateValue(this.processValue(this.getRawValue()));
21092 this.preventMark = restore;
21097 * Validates the field value
21098 * @return {Boolean} True if the value is valid, else false
21100 validate : function(){
21101 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21102 this.clearInvalid();
21108 processValue : function(value){
21113 // Subclasses should provide the validation implementation by overriding this
21114 validateValue : function(value){
21119 * Mark this field as invalid
21120 * @param {String} msg The validation message
21122 markInvalid : function(msg){
21123 if(!this.rendered || this.preventMark){ // not rendered
21126 this.el.addClass(this.invalidClass);
21127 msg = msg || this.invalidText;
21128 switch(this.msgTarget){
21130 this.el.dom.qtip = msg;
21131 this.el.dom.qclass = 'x-form-invalid-tip';
21132 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21133 Roo.QuickTips.enable();
21137 this.el.dom.title = msg;
21141 var elp = this.el.findParent('.x-form-element', 5, true);
21142 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21143 this.errorEl.setWidth(elp.getWidth(true)-20);
21145 this.errorEl.update(msg);
21146 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21149 if(!this.errorIcon){
21150 var elp = this.el.findParent('.x-form-element', 5, true);
21151 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21153 this.alignErrorIcon();
21154 this.errorIcon.dom.qtip = msg;
21155 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21156 this.errorIcon.show();
21157 this.on('resize', this.alignErrorIcon, this);
21160 var t = Roo.getDom(this.msgTarget);
21162 t.style.display = this.msgDisplay;
21165 this.fireEvent('invalid', this, msg);
21169 alignErrorIcon : function(){
21170 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21174 * Clear any invalid styles/messages for this field
21176 clearInvalid : function(){
21177 if(!this.rendered || this.preventMark){ // not rendered
21180 this.el.removeClass(this.invalidClass);
21181 switch(this.msgTarget){
21183 this.el.dom.qtip = '';
21186 this.el.dom.title = '';
21190 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21194 if(this.errorIcon){
21195 this.errorIcon.dom.qtip = '';
21196 this.errorIcon.hide();
21197 this.un('resize', this.alignErrorIcon, this);
21201 var t = Roo.getDom(this.msgTarget);
21203 t.style.display = 'none';
21206 this.fireEvent('valid', this);
21210 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21211 * @return {Mixed} value The field value
21213 getRawValue : function(){
21214 var v = this.el.getValue();
21215 if(v === this.emptyText){
21222 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21223 * @return {Mixed} value The field value
21225 getValue : function(){
21226 var v = this.el.getValue();
21227 if(v === this.emptyText || v === undefined){
21234 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21235 * @param {Mixed} value The value to set
21237 setRawValue : function(v){
21238 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21242 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21243 * @param {Mixed} value The value to set
21245 setValue : function(v){
21248 this.el.dom.value = (v === null || v === undefined ? '' : v);
21253 adjustSize : function(w, h){
21254 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21255 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21259 adjustWidth : function(tag, w){
21260 tag = tag.toLowerCase();
21261 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21262 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21263 if(tag == 'input'){
21266 if(tag = 'textarea'){
21269 }else if(Roo.isOpera){
21270 if(tag == 'input'){
21273 if(tag = 'textarea'){
21283 // anything other than normal should be considered experimental
21284 Roo.form.Field.msgFx = {
21286 show: function(msgEl, f){
21287 msgEl.setDisplayed('block');
21290 hide : function(msgEl, f){
21291 msgEl.setDisplayed(false).update('');
21296 show: function(msgEl, f){
21297 msgEl.slideIn('t', {stopFx:true});
21300 hide : function(msgEl, f){
21301 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21306 show: function(msgEl, f){
21307 msgEl.fixDisplay();
21308 msgEl.alignTo(f.el, 'tl-tr');
21309 msgEl.slideIn('l', {stopFx:true});
21312 hide : function(msgEl, f){
21313 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21318 * Ext JS Library 1.1.1
21319 * Copyright(c) 2006-2007, Ext JS, LLC.
21321 * Originally Released Under LGPL - original licence link has changed is not relivant.
21324 * <script type="text/javascript">
21329 * @class Roo.form.TextField
21330 * @extends Roo.form.Field
21331 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21332 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21334 * Creates a new TextField
21335 * @param {Object} config Configuration options
21337 Roo.form.TextField = function(config){
21338 Roo.form.TextField.superclass.constructor.call(this, config);
21342 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21343 * according to the default logic, but this event provides a hook for the developer to apply additional
21344 * logic at runtime to resize the field if needed.
21345 * @param {Roo.form.Field} this This text field
21346 * @param {Number} width The new field width
21352 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21354 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21358 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21362 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21366 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21370 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21374 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21376 disableKeyFilter : false,
21378 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21382 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21386 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21388 maxLength : Number.MAX_VALUE,
21390 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21392 minLengthText : "The minimum length for this field is {0}",
21394 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21396 maxLengthText : "The maximum length for this field is {0}",
21398 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21400 selectOnFocus : false,
21402 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21404 blankText : "This field is required",
21406 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21407 * If available, this function will be called only after the basic validators all return true, and will be passed the
21408 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21412 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21413 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21414 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21418 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21422 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21426 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21427 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21429 emptyClass : 'x-form-empty-field',
21432 initEvents : function(){
21433 Roo.form.TextField.superclass.initEvents.call(this);
21434 if(this.validationEvent == 'keyup'){
21435 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21436 this.el.on('keyup', this.filterValidation, this);
21438 else if(this.validationEvent !== false){
21439 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21441 if(this.selectOnFocus || this.emptyText){
21442 this.on("focus", this.preFocus, this);
21443 if(this.emptyText){
21444 this.on('blur', this.postBlur, this);
21445 this.applyEmptyText();
21448 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21449 this.el.on("keypress", this.filterKeys, this);
21452 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21453 this.el.on("click", this.autoSize, this);
21457 processValue : function(value){
21458 if(this.stripCharsRe){
21459 var newValue = value.replace(this.stripCharsRe, '');
21460 if(newValue !== value){
21461 this.setRawValue(newValue);
21468 filterValidation : function(e){
21469 if(!e.isNavKeyPress()){
21470 this.validationTask.delay(this.validationDelay);
21475 onKeyUp : function(e){
21476 if(!e.isNavKeyPress()){
21482 * Resets the current field value to the originally-loaded value and clears any validation messages.
21483 * Also adds emptyText and emptyClass if the original value was blank.
21485 reset : function(){
21486 Roo.form.TextField.superclass.reset.call(this);
21487 this.applyEmptyText();
21490 applyEmptyText : function(){
21491 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21492 this.setRawValue(this.emptyText);
21493 this.el.addClass(this.emptyClass);
21498 preFocus : function(){
21499 if(this.emptyText){
21500 if(this.el.dom.value == this.emptyText){
21501 this.setRawValue('');
21503 this.el.removeClass(this.emptyClass);
21505 if(this.selectOnFocus){
21506 this.el.dom.select();
21511 postBlur : function(){
21512 this.applyEmptyText();
21516 filterKeys : function(e){
21517 var k = e.getKey();
21518 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21521 var c = e.getCharCode(), cc = String.fromCharCode(c);
21522 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21525 if(!this.maskRe.test(cc)){
21530 setValue : function(v){
21531 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21532 this.el.removeClass(this.emptyClass);
21534 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21535 this.applyEmptyText();
21540 * Validates a value according to the field's validation rules and marks the field as invalid
21541 * if the validation fails
21542 * @param {Mixed} value The value to validate
21543 * @return {Boolean} True if the value is valid, else false
21545 validateValue : function(value){
21546 if(value.length < 1 || value === this.emptyText){ // if it's blank
21547 if(this.allowBlank){
21548 this.clearInvalid();
21551 this.markInvalid(this.blankText);
21555 if(value.length < this.minLength){
21556 this.markInvalid(String.format(this.minLengthText, this.minLength));
21559 if(value.length > this.maxLength){
21560 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21564 var vt = Roo.form.VTypes;
21565 if(!vt[this.vtype](value, this)){
21566 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21570 if(typeof this.validator == "function"){
21571 var msg = this.validator(value);
21573 this.markInvalid(msg);
21577 if(this.regex && !this.regex.test(value)){
21578 this.markInvalid(this.regexText);
21585 * Selects text in this field
21586 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21587 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21589 selectText : function(start, end){
21590 var v = this.getRawValue();
21592 start = start === undefined ? 0 : start;
21593 end = end === undefined ? v.length : end;
21594 var d = this.el.dom;
21595 if(d.setSelectionRange){
21596 d.setSelectionRange(start, end);
21597 }else if(d.createTextRange){
21598 var range = d.createTextRange();
21599 range.moveStart("character", start);
21600 range.moveEnd("character", v.length-end);
21607 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21608 * This only takes effect if grow = true, and fires the autosize event.
21610 autoSize : function(){
21611 if(!this.grow || !this.rendered){
21615 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21618 var v = el.dom.value;
21619 var d = document.createElement('div');
21620 d.appendChild(document.createTextNode(v));
21624 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21625 this.el.setWidth(w);
21626 this.fireEvent("autosize", this, w);
21630 * Ext JS Library 1.1.1
21631 * Copyright(c) 2006-2007, Ext JS, LLC.
21633 * Originally Released Under LGPL - original licence link has changed is not relivant.
21636 * <script type="text/javascript">
21640 * @class Roo.form.Hidden
21641 * @extends Roo.form.TextField
21642 * Simple Hidden element used on forms
21644 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21647 * Creates a new Hidden form element.
21648 * @param {Object} config Configuration options
21653 // easy hidden field...
21654 Roo.form.Hidden = function(config){
21655 Roo.form.Hidden.superclass.constructor.call(this, config);
21658 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21660 inputType: 'hidden',
21663 labelSeparator: '',
21665 itemCls : 'x-form-item-display-none'
21673 * Ext JS Library 1.1.1
21674 * Copyright(c) 2006-2007, Ext JS, LLC.
21676 * Originally Released Under LGPL - original licence link has changed is not relivant.
21679 * <script type="text/javascript">
21683 * @class Roo.form.TriggerField
21684 * @extends Roo.form.TextField
21685 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21686 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21687 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21688 * for which you can provide a custom implementation. For example:
21690 var trigger = new Roo.form.TriggerField();
21691 trigger.onTriggerClick = myTriggerFn;
21692 trigger.applyTo('my-field');
21695 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21696 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21697 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21698 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21700 * Create a new TriggerField.
21701 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21702 * to the base TextField)
21704 Roo.form.TriggerField = function(config){
21705 this.mimicing = false;
21706 Roo.form.TriggerField.superclass.constructor.call(this, config);
21709 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21711 * @cfg {String} triggerClass A CSS class to apply to the trigger
21714 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21715 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21717 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21719 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21723 /** @cfg {Boolean} grow @hide */
21724 /** @cfg {Number} growMin @hide */
21725 /** @cfg {Number} growMax @hide */
21731 autoSize: Roo.emptyFn,
21735 deferHeight : true,
21738 actionMode : 'wrap',
21740 onResize : function(w, h){
21741 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21742 if(typeof w == 'number'){
21743 var x = w - this.trigger.getWidth();
21744 this.el.setWidth(this.adjustWidth('input', x));
21745 this.trigger.setStyle('left', x+'px');
21750 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21753 getResizeEl : function(){
21758 getPositionEl : function(){
21763 alignErrorIcon : function(){
21764 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21768 onRender : function(ct, position){
21769 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21770 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21771 this.trigger = this.wrap.createChild(this.triggerConfig ||
21772 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21773 if(this.hideTrigger){
21774 this.trigger.setDisplayed(false);
21776 this.initTrigger();
21778 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21783 initTrigger : function(){
21784 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21785 this.trigger.addClassOnOver('x-form-trigger-over');
21786 this.trigger.addClassOnClick('x-form-trigger-click');
21790 onDestroy : function(){
21792 this.trigger.removeAllListeners();
21793 this.trigger.remove();
21796 this.wrap.remove();
21798 Roo.form.TriggerField.superclass.onDestroy.call(this);
21802 onFocus : function(){
21803 Roo.form.TriggerField.superclass.onFocus.call(this);
21804 if(!this.mimicing){
21805 this.wrap.addClass('x-trigger-wrap-focus');
21806 this.mimicing = true;
21807 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21808 if(this.monitorTab){
21809 this.el.on("keydown", this.checkTab, this);
21815 checkTab : function(e){
21816 if(e.getKey() == e.TAB){
21817 this.triggerBlur();
21822 onBlur : function(){
21827 mimicBlur : function(e, t){
21828 if(!this.wrap.contains(t) && this.validateBlur()){
21829 this.triggerBlur();
21834 triggerBlur : function(){
21835 this.mimicing = false;
21836 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21837 if(this.monitorTab){
21838 this.el.un("keydown", this.checkTab, this);
21840 this.wrap.removeClass('x-trigger-wrap-focus');
21841 Roo.form.TriggerField.superclass.onBlur.call(this);
21845 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21846 validateBlur : function(e, t){
21851 onDisable : function(){
21852 Roo.form.TriggerField.superclass.onDisable.call(this);
21854 this.wrap.addClass('x-item-disabled');
21859 onEnable : function(){
21860 Roo.form.TriggerField.superclass.onEnable.call(this);
21862 this.wrap.removeClass('x-item-disabled');
21867 onShow : function(){
21868 var ae = this.getActionEl();
21871 ae.dom.style.display = '';
21872 ae.dom.style.visibility = 'visible';
21878 onHide : function(){
21879 var ae = this.getActionEl();
21880 ae.dom.style.display = 'none';
21884 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21885 * by an implementing function.
21887 * @param {EventObject} e
21889 onTriggerClick : Roo.emptyFn
21892 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21893 // to be extended by an implementing class. For an example of implementing this class, see the custom
21894 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21895 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21896 initComponent : function(){
21897 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21899 this.triggerConfig = {
21900 tag:'span', cls:'x-form-twin-triggers', cn:[
21901 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21902 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21906 getTrigger : function(index){
21907 return this.triggers[index];
21910 initTrigger : function(){
21911 var ts = this.trigger.select('.x-form-trigger', true);
21912 this.wrap.setStyle('overflow', 'hidden');
21913 var triggerField = this;
21914 ts.each(function(t, all, index){
21915 t.hide = function(){
21916 var w = triggerField.wrap.getWidth();
21917 this.dom.style.display = 'none';
21918 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21920 t.show = function(){
21921 var w = triggerField.wrap.getWidth();
21922 this.dom.style.display = '';
21923 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21925 var triggerIndex = 'Trigger'+(index+1);
21927 if(this['hide'+triggerIndex]){
21928 t.dom.style.display = 'none';
21930 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21931 t.addClassOnOver('x-form-trigger-over');
21932 t.addClassOnClick('x-form-trigger-click');
21934 this.triggers = ts.elements;
21937 onTrigger1Click : Roo.emptyFn,
21938 onTrigger2Click : Roo.emptyFn
21941 * Ext JS Library 1.1.1
21942 * Copyright(c) 2006-2007, Ext JS, LLC.
21944 * Originally Released Under LGPL - original licence link has changed is not relivant.
21947 * <script type="text/javascript">
21951 * @class Roo.form.TextArea
21952 * @extends Roo.form.TextField
21953 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21954 * support for auto-sizing.
21956 * Creates a new TextArea
21957 * @param {Object} config Configuration options
21959 Roo.form.TextArea = function(config){
21960 Roo.form.TextArea.superclass.constructor.call(this, config);
21961 // these are provided exchanges for backwards compat
21962 // minHeight/maxHeight were replaced by growMin/growMax to be
21963 // compatible with TextField growing config values
21964 if(this.minHeight !== undefined){
21965 this.growMin = this.minHeight;
21967 if(this.maxHeight !== undefined){
21968 this.growMax = this.maxHeight;
21972 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
21974 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
21978 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
21982 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
21983 * in the field (equivalent to setting overflow: hidden, defaults to false)
21985 preventScrollbars: false,
21987 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21988 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
21992 onRender : function(ct, position){
21994 this.defaultAutoCreate = {
21996 style:"width:300px;height:60px;",
21997 autocomplete: "off"
22000 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22002 this.textSizeEl = Roo.DomHelper.append(document.body, {
22003 tag: "pre", cls: "x-form-grow-sizer"
22005 if(this.preventScrollbars){
22006 this.el.setStyle("overflow", "hidden");
22008 this.el.setHeight(this.growMin);
22012 onDestroy : function(){
22013 if(this.textSizeEl){
22014 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22016 Roo.form.TextArea.superclass.onDestroy.call(this);
22020 onKeyUp : function(e){
22021 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22027 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22028 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22030 autoSize : function(){
22031 if(!this.grow || !this.textSizeEl){
22035 var v = el.dom.value;
22036 var ts = this.textSizeEl;
22039 ts.appendChild(document.createTextNode(v));
22042 Roo.fly(ts).setWidth(this.el.getWidth());
22044 v = "  ";
22047 v = v.replace(/\n/g, '<p> </p>');
22049 v += " \n ";
22052 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22053 if(h != this.lastHeight){
22054 this.lastHeight = h;
22055 this.el.setHeight(h);
22056 this.fireEvent("autosize", this, h);
22061 * Ext JS Library 1.1.1
22062 * Copyright(c) 2006-2007, Ext JS, LLC.
22064 * Originally Released Under LGPL - original licence link has changed is not relivant.
22067 * <script type="text/javascript">
22072 * @class Roo.form.NumberField
22073 * @extends Roo.form.TextField
22074 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22076 * Creates a new NumberField
22077 * @param {Object} config Configuration options
22079 Roo.form.NumberField = function(config){
22080 Roo.form.NumberField.superclass.constructor.call(this, config);
22083 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22085 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22087 fieldClass: "x-form-field x-form-num-field",
22089 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22091 allowDecimals : true,
22093 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22095 decimalSeparator : ".",
22097 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22099 decimalPrecision : 2,
22101 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22103 allowNegative : true,
22105 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22107 minValue : Number.NEGATIVE_INFINITY,
22109 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22111 maxValue : Number.MAX_VALUE,
22113 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22115 minText : "The minimum value for this field is {0}",
22117 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22119 maxText : "The maximum value for this field is {0}",
22121 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22122 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22124 nanText : "{0} is not a valid number",
22127 initEvents : function(){
22128 Roo.form.NumberField.superclass.initEvents.call(this);
22129 var allowed = "0123456789";
22130 if(this.allowDecimals){
22131 allowed += this.decimalSeparator;
22133 if(this.allowNegative){
22136 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22137 var keyPress = function(e){
22138 var k = e.getKey();
22139 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22142 var c = e.getCharCode();
22143 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22147 this.el.on("keypress", keyPress, this);
22151 validateValue : function(value){
22152 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22155 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22158 var num = this.parseValue(value);
22160 this.markInvalid(String.format(this.nanText, value));
22163 if(num < this.minValue){
22164 this.markInvalid(String.format(this.minText, this.minValue));
22167 if(num > this.maxValue){
22168 this.markInvalid(String.format(this.maxText, this.maxValue));
22174 getValue : function(){
22175 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22179 parseValue : function(value){
22180 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22181 return isNaN(value) ? '' : value;
22185 fixPrecision : function(value){
22186 var nan = isNaN(value);
22187 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22188 return nan ? '' : value;
22190 return parseFloat(value).toFixed(this.decimalPrecision);
22193 setValue : function(v){
22194 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22198 decimalPrecisionFcn : function(v){
22199 return Math.floor(v);
22202 beforeBlur : function(){
22203 var v = this.parseValue(this.getRawValue());
22205 this.setValue(this.fixPrecision(v));
22210 * Ext JS Library 1.1.1
22211 * Copyright(c) 2006-2007, Ext JS, LLC.
22213 * Originally Released Under LGPL - original licence link has changed is not relivant.
22216 * <script type="text/javascript">
22220 * @class Roo.form.DateField
22221 * @extends Roo.form.TriggerField
22222 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22224 * Create a new DateField
22225 * @param {Object} config
22227 Roo.form.DateField = function(config){
22228 Roo.form.DateField.superclass.constructor.call(this, config);
22234 * Fires when a date is selected
22235 * @param {Roo.form.DateField} combo This combo box
22236 * @param {Date} date The date selected
22243 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22244 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22245 this.ddMatch = null;
22246 if(this.disabledDates){
22247 var dd = this.disabledDates;
22249 for(var i = 0; i < dd.length; i++){
22251 if(i != dd.length-1) re += "|";
22253 this.ddMatch = new RegExp(re + ")");
22257 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22259 * @cfg {String} format
22260 * The default date format string which can be overriden for localization support. The format must be
22261 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22265 * @cfg {String} altFormats
22266 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22267 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22269 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22271 * @cfg {Array} disabledDays
22272 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22274 disabledDays : null,
22276 * @cfg {String} disabledDaysText
22277 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22279 disabledDaysText : "Disabled",
22281 * @cfg {Array} disabledDates
22282 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22283 * expression so they are very powerful. Some examples:
22285 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22286 * <li>["03/08", "09/16"] would disable those days for every year</li>
22287 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22288 * <li>["03/../2006"] would disable every day in March 2006</li>
22289 * <li>["^03"] would disable every day in every March</li>
22291 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22292 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22294 disabledDates : null,
22296 * @cfg {String} disabledDatesText
22297 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22299 disabledDatesText : "Disabled",
22301 * @cfg {Date/String} minValue
22302 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22303 * valid format (defaults to null).
22307 * @cfg {Date/String} maxValue
22308 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22309 * valid format (defaults to null).
22313 * @cfg {String} minText
22314 * The error text to display when the date in the cell is before minValue (defaults to
22315 * 'The date in this field must be after {minValue}').
22317 minText : "The date in this field must be equal to or after {0}",
22319 * @cfg {String} maxText
22320 * The error text to display when the date in the cell is after maxValue (defaults to
22321 * 'The date in this field must be before {maxValue}').
22323 maxText : "The date in this field must be equal to or before {0}",
22325 * @cfg {String} invalidText
22326 * The error text to display when the date in the field is invalid (defaults to
22327 * '{value} is not a valid date - it must be in the format {format}').
22329 invalidText : "{0} is not a valid date - it must be in the format {1}",
22331 * @cfg {String} triggerClass
22332 * An additional CSS class used to style the trigger button. The trigger will always get the
22333 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22334 * which displays a calendar icon).
22336 triggerClass : 'x-form-date-trigger',
22340 * @cfg {bool} useIso
22341 * if enabled, then the date field will use a hidden field to store the
22342 * real value as iso formated date. default (false)
22346 * @cfg {String/Object} autoCreate
22347 * A DomHelper element spec, or true for a default element spec (defaults to
22348 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22351 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22354 hiddenField: false,
22356 onRender : function(ct, position)
22358 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22360 this.el.dom.removeAttribute('name');
22361 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22363 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22364 // prevent input submission
22365 this.hiddenName = this.name;
22372 validateValue : function(value)
22374 value = this.formatDate(value);
22375 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22378 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22381 var svalue = value;
22382 value = this.parseDate(value);
22384 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22387 var time = value.getTime();
22388 if(this.minValue && time < this.minValue.getTime()){
22389 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22392 if(this.maxValue && time > this.maxValue.getTime()){
22393 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22396 if(this.disabledDays){
22397 var day = value.getDay();
22398 for(var i = 0; i < this.disabledDays.length; i++) {
22399 if(day === this.disabledDays[i]){
22400 this.markInvalid(this.disabledDaysText);
22405 var fvalue = this.formatDate(value);
22406 if(this.ddMatch && this.ddMatch.test(fvalue)){
22407 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22414 // Provides logic to override the default TriggerField.validateBlur which just returns true
22415 validateBlur : function(){
22416 return !this.menu || !this.menu.isVisible();
22420 * Returns the current date value of the date field.
22421 * @return {Date} The date value
22423 getValue : function(){
22425 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22429 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22430 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22431 * (the default format used is "m/d/y").
22434 //All of these calls set the same date value (May 4, 2006)
22436 //Pass a date object:
22437 var dt = new Date('5/4/06');
22438 dateField.setValue(dt);
22440 //Pass a date string (default format):
22441 dateField.setValue('5/4/06');
22443 //Pass a date string (custom format):
22444 dateField.format = 'Y-m-d';
22445 dateField.setValue('2006-5-4');
22447 * @param {String/Date} date The date or valid date string
22449 setValue : function(date){
22450 if (this.hiddenField) {
22451 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22453 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22457 parseDate : function(value){
22458 if(!value || value instanceof Date){
22461 var v = Date.parseDate(value, this.format);
22462 if(!v && this.altFormats){
22463 if(!this.altFormatsArray){
22464 this.altFormatsArray = this.altFormats.split("|");
22466 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22467 v = Date.parseDate(value, this.altFormatsArray[i]);
22474 formatDate : function(date, fmt){
22475 return (!date || !(date instanceof Date)) ?
22476 date : date.dateFormat(fmt || this.format);
22481 select: function(m, d){
22483 this.fireEvent('select', this, d);
22485 show : function(){ // retain focus styling
22489 this.focus.defer(10, this);
22490 var ml = this.menuListeners;
22491 this.menu.un("select", ml.select, this);
22492 this.menu.un("show", ml.show, this);
22493 this.menu.un("hide", ml.hide, this);
22498 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22499 onTriggerClick : function(){
22503 if(this.menu == null){
22504 this.menu = new Roo.menu.DateMenu();
22506 Roo.apply(this.menu.picker, {
22507 showClear: this.allowBlank,
22508 minDate : this.minValue,
22509 maxDate : this.maxValue,
22510 disabledDatesRE : this.ddMatch,
22511 disabledDatesText : this.disabledDatesText,
22512 disabledDays : this.disabledDays,
22513 disabledDaysText : this.disabledDaysText,
22514 format : this.format,
22515 minText : String.format(this.minText, this.formatDate(this.minValue)),
22516 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22518 this.menu.on(Roo.apply({}, this.menuListeners, {
22521 this.menu.picker.setValue(this.getValue() || new Date());
22522 this.menu.show(this.el, "tl-bl?");
22525 beforeBlur : function(){
22526 var v = this.parseDate(this.getRawValue());
22532 /** @cfg {Boolean} grow @hide */
22533 /** @cfg {Number} growMin @hide */
22534 /** @cfg {Number} growMax @hide */
22541 * Ext JS Library 1.1.1
22542 * Copyright(c) 2006-2007, Ext JS, LLC.
22544 * Originally Released Under LGPL - original licence link has changed is not relivant.
22547 * <script type="text/javascript">
22552 * @class Roo.form.ComboBox
22553 * @extends Roo.form.TriggerField
22554 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22556 * Create a new ComboBox.
22557 * @param {Object} config Configuration options
22559 Roo.form.ComboBox = function(config){
22560 Roo.form.ComboBox.superclass.constructor.call(this, config);
22564 * Fires when the dropdown list is expanded
22565 * @param {Roo.form.ComboBox} combo This combo box
22570 * Fires when the dropdown list is collapsed
22571 * @param {Roo.form.ComboBox} combo This combo box
22575 * @event beforeselect
22576 * Fires before a list item is selected. Return false to cancel the selection.
22577 * @param {Roo.form.ComboBox} combo This combo box
22578 * @param {Roo.data.Record} record The data record returned from the underlying store
22579 * @param {Number} index The index of the selected item in the dropdown list
22581 'beforeselect' : true,
22584 * Fires when a list item is selected
22585 * @param {Roo.form.ComboBox} combo This combo box
22586 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22587 * @param {Number} index The index of the selected item in the dropdown list
22591 * @event beforequery
22592 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22593 * The event object passed has these properties:
22594 * @param {Roo.form.ComboBox} combo This combo box
22595 * @param {String} query The query
22596 * @param {Boolean} forceAll true to force "all" query
22597 * @param {Boolean} cancel true to cancel the query
22598 * @param {Object} e The query event object
22600 'beforequery': true,
22603 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22604 * @param {Roo.form.ComboBox} combo This combo box
22609 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22610 * @param {Roo.form.ComboBox} combo This combo box
22611 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22617 if(this.transform){
22618 this.allowDomMove = false;
22619 var s = Roo.getDom(this.transform);
22620 if(!this.hiddenName){
22621 this.hiddenName = s.name;
22624 this.mode = 'local';
22625 var d = [], opts = s.options;
22626 for(var i = 0, len = opts.length;i < len; i++){
22628 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22630 this.value = value;
22632 d.push([value, o.text]);
22634 this.store = new Roo.data.SimpleStore({
22636 fields: ['value', 'text'],
22639 this.valueField = 'value';
22640 this.displayField = 'text';
22642 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22643 if(!this.lazyRender){
22644 this.target = true;
22645 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22646 s.parentNode.removeChild(s); // remove it
22647 this.render(this.el.parentNode);
22649 s.parentNode.removeChild(s); // remove it
22654 this.store = Roo.factory(this.store, Roo.data);
22657 this.selectedIndex = -1;
22658 if(this.mode == 'local'){
22659 if(config.queryDelay === undefined){
22660 this.queryDelay = 10;
22662 if(config.minChars === undefined){
22668 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22670 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22673 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22674 * rendering into an Roo.Editor, defaults to false)
22677 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22678 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22681 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22684 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22685 * the dropdown list (defaults to undefined, with no header element)
22689 * @cfg {String/Roo.Template} tpl The template to use to render the output
22693 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22695 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22697 listWidth: undefined,
22699 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22700 * mode = 'remote' or 'text' if mode = 'local')
22702 displayField: undefined,
22704 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22705 * mode = 'remote' or 'value' if mode = 'local').
22706 * Note: use of a valueField requires the user make a selection
22707 * in order for a value to be mapped.
22709 valueField: undefined,
22711 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22712 * field's data value (defaults to the underlying DOM element's name)
22714 hiddenName: undefined,
22716 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22720 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22722 selectedClass: 'x-combo-selected',
22724 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22725 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22726 * which displays a downward arrow icon).
22728 triggerClass : 'x-form-arrow-trigger',
22730 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22734 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22735 * anchor positions (defaults to 'tl-bl')
22737 listAlign: 'tl-bl?',
22739 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22743 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22744 * query specified by the allQuery config option (defaults to 'query')
22746 triggerAction: 'query',
22748 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22749 * (defaults to 4, does not apply if editable = false)
22753 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22754 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22758 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22759 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22763 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22764 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22768 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22769 * when editable = true (defaults to false)
22771 selectOnFocus:false,
22773 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22775 queryParam: 'query',
22777 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22778 * when mode = 'remote' (defaults to 'Loading...')
22780 loadingText: 'Loading...',
22782 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22786 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22790 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22791 * traditional select (defaults to true)
22795 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22799 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22803 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22804 * listWidth has a higher value)
22808 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22809 * allow the user to set arbitrary text into the field (defaults to false)
22811 forceSelection:false,
22813 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22814 * if typeAhead = true (defaults to 250)
22816 typeAheadDelay : 250,
22818 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22819 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22821 valueNotFoundText : undefined,
22823 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22825 blockFocus : false,
22828 * @cfg {Boolean} disableClear Disable showing of clear button.
22830 disableClear : false,
22832 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22834 alwaysQuery : false,
22842 onRender : function(ct, position){
22843 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22844 if(this.hiddenName){
22845 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22847 this.hiddenField.value =
22848 this.hiddenValue !== undefined ? this.hiddenValue :
22849 this.value !== undefined ? this.value : '';
22851 // prevent input submission
22852 this.el.dom.removeAttribute('name');
22855 this.el.dom.setAttribute('autocomplete', 'off');
22858 var cls = 'x-combo-list';
22860 this.list = new Roo.Layer({
22861 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22864 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22865 this.list.setWidth(lw);
22866 this.list.swallowEvent('mousewheel');
22867 this.assetHeight = 0;
22870 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22871 this.assetHeight += this.header.getHeight();
22874 this.innerList = this.list.createChild({cls:cls+'-inner'});
22875 this.innerList.on('mouseover', this.onViewOver, this);
22876 this.innerList.on('mousemove', this.onViewMove, this);
22877 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22879 if(this.allowBlank && !this.pageSize && !this.disableClear){
22880 this.footer = this.list.createChild({cls:cls+'-ft'});
22881 this.pageTb = new Roo.Toolbar(this.footer);
22885 this.footer = this.list.createChild({cls:cls+'-ft'});
22886 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22887 {pageSize: this.pageSize});
22891 if (this.pageTb && this.allowBlank && !this.disableClear) {
22893 this.pageTb.add(new Roo.Toolbar.Fill(), {
22894 cls: 'x-btn-icon x-btn-clear',
22896 handler: function()
22899 _this.clearValue();
22900 _this.onSelect(false, -1);
22905 this.assetHeight += this.footer.getHeight();
22910 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22913 this.view = new Roo.View(this.innerList, this.tpl, {
22914 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22917 this.view.on('click', this.onViewClick, this);
22919 this.store.on('beforeload', this.onBeforeLoad, this);
22920 this.store.on('load', this.onLoad, this);
22921 this.store.on('loadexception', this.collapse, this);
22923 if(this.resizable){
22924 this.resizer = new Roo.Resizable(this.list, {
22925 pinned:true, handles:'se'
22927 this.resizer.on('resize', function(r, w, h){
22928 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22929 this.listWidth = w;
22930 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22931 this.restrictHeight();
22933 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22935 if(!this.editable){
22936 this.editable = true;
22937 this.setEditable(false);
22941 if (typeof(this.events.add.listeners) != 'undefined') {
22943 this.addicon = this.wrap.createChild(
22944 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22946 this.addicon.on('click', function(e) {
22947 this.fireEvent('add', this);
22950 if (typeof(this.events.edit.listeners) != 'undefined') {
22952 this.editicon = this.wrap.createChild(
22953 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22954 if (this.addicon) {
22955 this.editicon.setStyle('margin-left', '40px');
22957 this.editicon.on('click', function(e) {
22959 // we fire even if inothing is selected..
22960 this.fireEvent('edit', this, this.lastData );
22970 initEvents : function(){
22971 Roo.form.ComboBox.superclass.initEvents.call(this);
22973 this.keyNav = new Roo.KeyNav(this.el, {
22974 "up" : function(e){
22975 this.inKeyMode = true;
22979 "down" : function(e){
22980 if(!this.isExpanded()){
22981 this.onTriggerClick();
22983 this.inKeyMode = true;
22988 "enter" : function(e){
22989 this.onViewClick();
22993 "esc" : function(e){
22997 "tab" : function(e){
22998 this.onViewClick(false);
23004 doRelay : function(foo, bar, hname){
23005 if(hname == 'down' || this.scope.isExpanded()){
23006 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23013 this.queryDelay = Math.max(this.queryDelay || 10,
23014 this.mode == 'local' ? 10 : 250);
23015 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23016 if(this.typeAhead){
23017 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23019 if(this.editable !== false){
23020 this.el.on("keyup", this.onKeyUp, this);
23022 if(this.forceSelection){
23023 this.on('blur', this.doForce, this);
23027 onDestroy : function(){
23029 this.view.setStore(null);
23030 this.view.el.removeAllListeners();
23031 this.view.el.remove();
23032 this.view.purgeListeners();
23035 this.list.destroy();
23038 this.store.un('beforeload', this.onBeforeLoad, this);
23039 this.store.un('load', this.onLoad, this);
23040 this.store.un('loadexception', this.collapse, this);
23042 Roo.form.ComboBox.superclass.onDestroy.call(this);
23046 fireKey : function(e){
23047 if(e.isNavKeyPress() && !this.list.isVisible()){
23048 this.fireEvent("specialkey", this, e);
23053 onResize: function(w, h){
23054 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23056 if(typeof w != 'number'){
23057 // we do not handle it!?!?
23060 var tw = this.trigger.getWidth();
23061 tw += this.addicon ? this.addicon.getWidth() : 0;
23062 tw += this.editicon ? this.editicon.getWidth() : 0;
23064 this.el.setWidth( this.adjustWidth('input', x));
23066 this.trigger.setStyle('left', x+'px');
23068 if(this.list && this.listWidth === undefined){
23069 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23070 this.list.setWidth(lw);
23071 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23079 * Allow or prevent the user from directly editing the field text. If false is passed,
23080 * the user will only be able to select from the items defined in the dropdown list. This method
23081 * is the runtime equivalent of setting the 'editable' config option at config time.
23082 * @param {Boolean} value True to allow the user to directly edit the field text
23084 setEditable : function(value){
23085 if(value == this.editable){
23088 this.editable = value;
23090 this.el.dom.setAttribute('readOnly', true);
23091 this.el.on('mousedown', this.onTriggerClick, this);
23092 this.el.addClass('x-combo-noedit');
23094 this.el.dom.setAttribute('readOnly', false);
23095 this.el.un('mousedown', this.onTriggerClick, this);
23096 this.el.removeClass('x-combo-noedit');
23101 onBeforeLoad : function(){
23102 if(!this.hasFocus){
23105 this.innerList.update(this.loadingText ?
23106 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23107 this.restrictHeight();
23108 this.selectedIndex = -1;
23112 onLoad : function(){
23113 if(!this.hasFocus){
23116 if(this.store.getCount() > 0){
23118 this.restrictHeight();
23119 if(this.lastQuery == this.allQuery){
23121 this.el.dom.select();
23123 if(!this.selectByValue(this.value, true)){
23124 this.select(0, true);
23128 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23129 this.taTask.delay(this.typeAheadDelay);
23133 this.onEmptyResults();
23139 onTypeAhead : function(){
23140 if(this.store.getCount() > 0){
23141 var r = this.store.getAt(0);
23142 var newValue = r.data[this.displayField];
23143 var len = newValue.length;
23144 var selStart = this.getRawValue().length;
23145 if(selStart != len){
23146 this.setRawValue(newValue);
23147 this.selectText(selStart, newValue.length);
23153 onSelect : function(record, index){
23154 if(this.fireEvent('beforeselect', this, record, index) !== false){
23155 this.setFromData(index > -1 ? record.data : false);
23157 this.fireEvent('select', this, record, index);
23162 * Returns the currently selected field value or empty string if no value is set.
23163 * @return {String} value The selected value
23165 getValue : function(){
23166 if(this.valueField){
23167 return typeof this.value != 'undefined' ? this.value : '';
23169 return Roo.form.ComboBox.superclass.getValue.call(this);
23174 * Clears any text/value currently set in the field
23176 clearValue : function(){
23177 if(this.hiddenField){
23178 this.hiddenField.value = '';
23181 this.setRawValue('');
23182 this.lastSelectionText = '';
23183 this.applyEmptyText();
23187 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23188 * will be displayed in the field. If the value does not match the data value of an existing item,
23189 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23190 * Otherwise the field will be blank (although the value will still be set).
23191 * @param {String} value The value to match
23193 setValue : function(v){
23195 if(this.valueField){
23196 var r = this.findRecord(this.valueField, v);
23198 text = r.data[this.displayField];
23199 }else if(this.valueNotFoundText !== undefined){
23200 text = this.valueNotFoundText;
23203 this.lastSelectionText = text;
23204 if(this.hiddenField){
23205 this.hiddenField.value = v;
23207 Roo.form.ComboBox.superclass.setValue.call(this, text);
23211 * @property {Object} the last set data for the element
23216 * Sets the value of the field based on a object which is related to the record format for the store.
23217 * @param {Object} value the value to set as. or false on reset?
23219 setFromData : function(o){
23220 var dv = ''; // display value
23221 var vv = ''; // value value..
23223 if (this.displayField) {
23224 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23226 // this is an error condition!!!
23227 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23230 if(this.valueField){
23231 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23233 if(this.hiddenField){
23234 this.hiddenField.value = vv;
23236 this.lastSelectionText = dv;
23237 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23241 // no hidden field.. - we store the value in 'value', but still display
23242 // display field!!!!
23243 this.lastSelectionText = dv;
23244 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23250 reset : function(){
23251 // overridden so that last data is reset..
23252 this.setValue(this.originalValue);
23253 this.clearInvalid();
23254 this.lastData = false;
23257 findRecord : function(prop, value){
23259 if(this.store.getCount() > 0){
23260 this.store.each(function(r){
23261 if(r.data[prop] == value){
23271 onViewMove : function(e, t){
23272 this.inKeyMode = false;
23276 onViewOver : function(e, t){
23277 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23280 var item = this.view.findItemFromChild(t);
23282 var index = this.view.indexOf(item);
23283 this.select(index, false);
23288 onViewClick : function(doFocus){
23289 var index = this.view.getSelectedIndexes()[0];
23290 var r = this.store.getAt(index);
23292 this.onSelect(r, index);
23294 if(doFocus !== false && !this.blockFocus){
23300 restrictHeight : function(){
23301 this.innerList.dom.style.height = '';
23302 var inner = this.innerList.dom;
23303 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23304 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23305 this.list.beginUpdate();
23306 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23307 this.list.alignTo(this.el, this.listAlign);
23308 this.list.endUpdate();
23312 onEmptyResults : function(){
23317 * Returns true if the dropdown list is expanded, else false.
23319 isExpanded : function(){
23320 return this.list.isVisible();
23324 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23325 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23326 * @param {String} value The data value of the item to select
23327 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23328 * selected item if it is not currently in view (defaults to true)
23329 * @return {Boolean} True if the value matched an item in the list, else false
23331 selectByValue : function(v, scrollIntoView){
23332 if(v !== undefined && v !== null){
23333 var r = this.findRecord(this.valueField || this.displayField, v);
23335 this.select(this.store.indexOf(r), scrollIntoView);
23343 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23344 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23345 * @param {Number} index The zero-based index of the list item to select
23346 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23347 * selected item if it is not currently in view (defaults to true)
23349 select : function(index, scrollIntoView){
23350 this.selectedIndex = index;
23351 this.view.select(index);
23352 if(scrollIntoView !== false){
23353 var el = this.view.getNode(index);
23355 this.innerList.scrollChildIntoView(el, false);
23361 selectNext : function(){
23362 var ct = this.store.getCount();
23364 if(this.selectedIndex == -1){
23366 }else if(this.selectedIndex < ct-1){
23367 this.select(this.selectedIndex+1);
23373 selectPrev : function(){
23374 var ct = this.store.getCount();
23376 if(this.selectedIndex == -1){
23378 }else if(this.selectedIndex != 0){
23379 this.select(this.selectedIndex-1);
23385 onKeyUp : function(e){
23386 if(this.editable !== false && !e.isSpecialKey()){
23387 this.lastKey = e.getKey();
23388 this.dqTask.delay(this.queryDelay);
23393 validateBlur : function(){
23394 return !this.list || !this.list.isVisible();
23398 initQuery : function(){
23399 this.doQuery(this.getRawValue());
23403 doForce : function(){
23404 if(this.el.dom.value.length > 0){
23405 this.el.dom.value =
23406 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23407 this.applyEmptyText();
23412 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23413 * query allowing the query action to be canceled if needed.
23414 * @param {String} query The SQL query to execute
23415 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23416 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23417 * saved in the current store (defaults to false)
23419 doQuery : function(q, forceAll){
23420 if(q === undefined || q === null){
23425 forceAll: forceAll,
23429 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23433 forceAll = qe.forceAll;
23434 if(forceAll === true || (q.length >= this.minChars)){
23435 if(this.lastQuery != q || this.alwaysQuery){
23436 this.lastQuery = q;
23437 if(this.mode == 'local'){
23438 this.selectedIndex = -1;
23440 this.store.clearFilter();
23442 this.store.filter(this.displayField, q);
23446 this.store.baseParams[this.queryParam] = q;
23448 params: this.getParams(q)
23453 this.selectedIndex = -1;
23460 getParams : function(q){
23462 //p[this.queryParam] = q;
23465 p.limit = this.pageSize;
23471 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23473 collapse : function(){
23474 if(!this.isExpanded()){
23478 Roo.get(document).un('mousedown', this.collapseIf, this);
23479 Roo.get(document).un('mousewheel', this.collapseIf, this);
23480 if (!this.editable) {
23481 Roo.get(document).un('keydown', this.listKeyPress, this);
23483 this.fireEvent('collapse', this);
23487 collapseIf : function(e){
23488 if(!e.within(this.wrap) && !e.within(this.list)){
23494 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23496 expand : function(){
23497 if(this.isExpanded() || !this.hasFocus){
23500 this.list.alignTo(this.el, this.listAlign);
23502 Roo.get(document).on('mousedown', this.collapseIf, this);
23503 Roo.get(document).on('mousewheel', this.collapseIf, this);
23504 if (!this.editable) {
23505 Roo.get(document).on('keydown', this.listKeyPress, this);
23508 this.fireEvent('expand', this);
23512 // Implements the default empty TriggerField.onTriggerClick function
23513 onTriggerClick : function(){
23517 if(this.isExpanded()){
23519 if (!this.blockFocus) {
23524 this.hasFocus = true;
23525 if(this.triggerAction == 'all') {
23526 this.doQuery(this.allQuery, true);
23528 this.doQuery(this.getRawValue());
23530 if (!this.blockFocus) {
23535 listKeyPress : function(e)
23537 //Roo.log('listkeypress');
23538 // scroll to first matching element based on key pres..
23539 if (e.isSpecialKey()) {
23542 var k = String.fromCharCode(e.getKey()).toUpperCase();
23545 var csel = this.view.getSelectedNodes();
23546 var cselitem = false;
23548 var ix = this.view.indexOf(csel[0]);
23549 cselitem = this.store.getAt(ix);
23550 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23556 this.store.each(function(v) {
23558 // start at existing selection.
23559 if (cselitem.id == v.id) {
23565 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23566 match = this.store.indexOf(v);
23571 if (match === false) {
23572 return true; // no more action?
23575 this.view.select(match);
23576 var sn = Roo.get(this.view.getSelectedNodes()[0])
23577 sn.scrollIntoView(sn.dom.parentNode, false);
23581 * @cfg {Boolean} grow
23585 * @cfg {Number} growMin
23589 * @cfg {Number} growMax
23598 * Ext JS Library 1.1.1
23599 * Copyright(c) 2006-2007, Ext JS, LLC.
23601 * Originally Released Under LGPL - original licence link has changed is not relivant.
23604 * <script type="text/javascript">
23607 * @class Roo.form.Checkbox
23608 * @extends Roo.form.Field
23609 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23611 * Creates a new Checkbox
23612 * @param {Object} config Configuration options
23614 Roo.form.Checkbox = function(config){
23615 Roo.form.Checkbox.superclass.constructor.call(this, config);
23619 * Fires when the checkbox is checked or unchecked.
23620 * @param {Roo.form.Checkbox} this This checkbox
23621 * @param {Boolean} checked The new checked value
23627 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23629 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23631 focusClass : undefined,
23633 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23635 fieldClass: "x-form-field",
23637 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23641 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23642 * {tag: "input", type: "checkbox", autocomplete: "off"})
23644 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23646 * @cfg {String} boxLabel The text that appears beside the checkbox
23650 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23654 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23656 valueOff: '0', // value when not checked..
23658 actionMode : 'viewEl',
23661 itemCls : 'x-menu-check-item x-form-item',
23662 groupClass : 'x-menu-group-item',
23663 inputType : 'hidden',
23666 inSetChecked: false, // check that we are not calling self...
23668 inputElement: false, // real input element?
23669 basedOn: false, // ????
23671 isFormField: true, // not sure where this is needed!!!!
23673 onResize : function(){
23674 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23675 if(!this.boxLabel){
23676 this.el.alignTo(this.wrap, 'c-c');
23680 initEvents : function(){
23681 Roo.form.Checkbox.superclass.initEvents.call(this);
23682 this.el.on("click", this.onClick, this);
23683 this.el.on("change", this.onClick, this);
23687 getResizeEl : function(){
23691 getPositionEl : function(){
23696 onRender : function(ct, position){
23697 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23699 if(this.inputValue !== undefined){
23700 this.el.dom.value = this.inputValue;
23703 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23704 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23705 var viewEl = this.wrap.createChild({
23706 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23707 this.viewEl = viewEl;
23708 this.wrap.on('click', this.onClick, this);
23710 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23711 this.el.on('propertychange', this.setFromHidden, this); //ie
23716 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23717 // viewEl.on('click', this.onClick, this);
23719 //if(this.checked){
23720 this.setChecked(this.checked);
23722 //this.checked = this.el.dom;
23728 initValue : Roo.emptyFn,
23731 * Returns the checked state of the checkbox.
23732 * @return {Boolean} True if checked, else false
23734 getValue : function(){
23736 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23738 return this.valueOff;
23743 onClick : function(){
23744 this.setChecked(!this.checked);
23746 //if(this.el.dom.checked != this.checked){
23747 // this.setValue(this.el.dom.checked);
23752 * Sets the checked state of the checkbox.
23753 * On is always based on a string comparison between inputValue and the param.
23754 * @param {Boolean/String} value - the value to set
23755 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23757 setValue : function(v,suppressEvent){
23760 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23761 //if(this.el && this.el.dom){
23762 // this.el.dom.checked = this.checked;
23763 // this.el.dom.defaultChecked = this.checked;
23765 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23766 //this.fireEvent("check", this, this.checked);
23769 setChecked : function(state,suppressEvent)
23771 if (this.inSetChecked) {
23772 this.checked = state;
23778 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23780 this.checked = state;
23781 if(suppressEvent !== true){
23782 this.fireEvent('check', this, state);
23784 this.inSetChecked = true;
23785 this.el.dom.value = state ? this.inputValue : this.valueOff;
23786 this.inSetChecked = false;
23789 // handle setting of hidden value by some other method!!?!?
23790 setFromHidden: function()
23795 //console.log("SET FROM HIDDEN");
23796 //alert('setFrom hidden');
23797 this.setValue(this.el.dom.value);
23800 onDestroy : function()
23803 Roo.get(this.viewEl).remove();
23806 Roo.form.Checkbox.superclass.onDestroy.call(this);
23811 * Ext JS Library 1.1.1
23812 * Copyright(c) 2006-2007, Ext JS, LLC.
23814 * Originally Released Under LGPL - original licence link has changed is not relivant.
23817 * <script type="text/javascript">
23821 * @class Roo.form.Radio
23822 * @extends Roo.form.Checkbox
23823 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23824 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23826 * Creates a new Radio
23827 * @param {Object} config Configuration options
23829 Roo.form.Radio = function(){
23830 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23832 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23833 inputType: 'radio',
23836 * If this radio is part of a group, it will return the selected value
23839 getGroupValue : function(){
23840 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23842 });//<script type="text/javascript">
23845 * Ext JS Library 1.1.1
23846 * Copyright(c) 2006-2007, Ext JS, LLC.
23847 * licensing@extjs.com
23849 * http://www.extjs.com/license
23855 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23856 * - IE ? - no idea how much works there.
23864 * @class Ext.form.HtmlEditor
23865 * @extends Ext.form.Field
23866 * Provides a lightweight HTML Editor component.
23867 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23869 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23870 * supported by this editor.</b><br/><br/>
23871 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23872 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23874 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23876 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23880 * @cfg {String} createLinkText The default text for the create link prompt
23882 createLinkText : 'Please enter the URL for the link:',
23884 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23886 defaultLinkValue : 'http:/'+'/',
23892 // private properties
23893 validationEvent : false,
23895 initialized : false,
23897 sourceEditMode : false,
23898 onFocus : Roo.emptyFn,
23900 hideMode:'offsets',
23901 defaultAutoCreate : {
23903 style:"width:500px;height:300px;",
23904 autocomplete: "off"
23908 initComponent : function(){
23911 * @event initialize
23912 * Fires when the editor is fully initialized (including the iframe)
23913 * @param {HtmlEditor} this
23918 * Fires when the editor is first receives the focus. Any insertion must wait
23919 * until after this event.
23920 * @param {HtmlEditor} this
23924 * @event beforesync
23925 * Fires before the textarea is updated with content from the editor iframe. Return false
23926 * to cancel the sync.
23927 * @param {HtmlEditor} this
23928 * @param {String} html
23932 * @event beforepush
23933 * Fires before the iframe editor is updated with content from the textarea. Return false
23934 * to cancel the push.
23935 * @param {HtmlEditor} this
23936 * @param {String} html
23941 * Fires when the textarea is updated with content from the editor iframe.
23942 * @param {HtmlEditor} this
23943 * @param {String} html
23948 * Fires when the iframe editor is updated with content from the textarea.
23949 * @param {HtmlEditor} this
23950 * @param {String} html
23954 * @event editmodechange
23955 * Fires when the editor switches edit modes
23956 * @param {HtmlEditor} this
23957 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23959 editmodechange: true,
23961 * @event editorevent
23962 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23963 * @param {HtmlEditor} this
23970 * Protected method that will not generally be called directly. It
23971 * is called when the editor creates its toolbar. Override this method if you need to
23972 * add custom toolbar buttons.
23973 * @param {HtmlEditor} editor
23975 createToolbar : function(editor){
23976 if (!editor.toolbars || !editor.toolbars.length) {
23977 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
23980 for (var i =0 ; i < editor.toolbars.length;i++) {
23981 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
23982 editor.toolbars[i].init(editor);
23989 * Protected method that will not generally be called directly. It
23990 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23991 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23993 getDocMarkup : function(){
23994 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
23998 onRender : function(ct, position){
23999 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24000 this.el.dom.style.border = '0 none';
24001 this.el.dom.setAttribute('tabIndex', -1);
24002 this.el.addClass('x-hidden');
24003 if(Roo.isIE){ // fix IE 1px bogus margin
24004 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24006 this.wrap = this.el.wrap({
24007 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24010 this.frameId = Roo.id();
24011 this.createToolbar(this);
24018 var iframe = this.wrap.createChild({
24021 name: this.frameId,
24022 frameBorder : 'no',
24023 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24026 // console.log(iframe);
24027 //this.wrap.dom.appendChild(iframe);
24029 this.iframe = iframe.dom;
24031 this.assignDocWin();
24033 this.doc.designMode = 'on';
24036 this.doc.write(this.getDocMarkup());
24040 var task = { // must defer to wait for browser to be ready
24042 //console.log("run task?" + this.doc.readyState);
24043 this.assignDocWin();
24044 if(this.doc.body || this.doc.readyState == 'complete'){
24046 this.doc.designMode="on";
24050 Roo.TaskMgr.stop(task);
24051 this.initEditor.defer(10, this);
24058 Roo.TaskMgr.start(task);
24061 this.setSize(this.el.getSize());
24066 onResize : function(w, h){
24067 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24068 if(this.el && this.iframe){
24069 if(typeof w == 'number'){
24070 var aw = w - this.wrap.getFrameWidth('lr');
24071 this.el.setWidth(this.adjustWidth('textarea', aw));
24072 this.iframe.style.width = aw + 'px';
24074 if(typeof h == 'number'){
24076 for (var i =0; i < this.toolbars.length;i++) {
24077 // fixme - ask toolbars for heights?
24078 tbh += this.toolbars[i].tb.el.getHeight();
24084 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24085 this.el.setHeight(this.adjustWidth('textarea', ah));
24086 this.iframe.style.height = ah + 'px';
24088 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24095 * Toggles the editor between standard and source edit mode.
24096 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24098 toggleSourceEdit : function(sourceEditMode){
24100 this.sourceEditMode = sourceEditMode === true;
24102 if(this.sourceEditMode){
24105 this.iframe.className = 'x-hidden';
24106 this.el.removeClass('x-hidden');
24107 this.el.dom.removeAttribute('tabIndex');
24112 this.iframe.className = '';
24113 this.el.addClass('x-hidden');
24114 this.el.dom.setAttribute('tabIndex', -1);
24117 this.setSize(this.wrap.getSize());
24118 this.fireEvent('editmodechange', this, this.sourceEditMode);
24121 // private used internally
24122 createLink : function(){
24123 var url = prompt(this.createLinkText, this.defaultLinkValue);
24124 if(url && url != 'http:/'+'/'){
24125 this.relayCmd('createlink', url);
24129 // private (for BoxComponent)
24130 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24132 // private (for BoxComponent)
24133 getResizeEl : function(){
24137 // private (for BoxComponent)
24138 getPositionEl : function(){
24143 initEvents : function(){
24144 this.originalValue = this.getValue();
24148 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24151 markInvalid : Roo.emptyFn,
24153 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24156 clearInvalid : Roo.emptyFn,
24158 setValue : function(v){
24159 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24164 * Protected method that will not generally be called directly. If you need/want
24165 * custom HTML cleanup, this is the method you should override.
24166 * @param {String} html The HTML to be cleaned
24167 * return {String} The cleaned HTML
24169 cleanHtml : function(html){
24170 html = String(html);
24171 if(html.length > 5){
24172 if(Roo.isSafari){ // strip safari nonsense
24173 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24176 if(html == ' '){
24183 * Protected method that will not generally be called directly. Syncs the contents
24184 * of the editor iframe with the textarea.
24186 syncValue : function(){
24187 if(this.initialized){
24188 var bd = (this.doc.body || this.doc.documentElement);
24189 var html = bd.innerHTML;
24191 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24192 var m = bs.match(/text-align:(.*?);/i);
24194 html = '<div style="'+m[0]+'">' + html + '</div>';
24197 html = this.cleanHtml(html);
24198 if(this.fireEvent('beforesync', this, html) !== false){
24199 this.el.dom.value = html;
24200 this.fireEvent('sync', this, html);
24206 * Protected method that will not generally be called directly. Pushes the value of the textarea
24207 * into the iframe editor.
24209 pushValue : function(){
24210 if(this.initialized){
24211 var v = this.el.dom.value;
24215 if(this.fireEvent('beforepush', this, v) !== false){
24216 (this.doc.body || this.doc.documentElement).innerHTML = v;
24217 this.fireEvent('push', this, v);
24223 deferFocus : function(){
24224 this.focus.defer(10, this);
24228 focus : function(){
24229 if(this.win && !this.sourceEditMode){
24236 assignDocWin: function()
24238 var iframe = this.iframe;
24241 this.doc = iframe.contentWindow.document;
24242 this.win = iframe.contentWindow;
24244 if (!Roo.get(this.frameId)) {
24247 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24248 this.win = Roo.get(this.frameId).dom.contentWindow;
24253 initEditor : function(){
24254 //console.log("INIT EDITOR");
24255 this.assignDocWin();
24259 this.doc.designMode="on";
24261 this.doc.write(this.getDocMarkup());
24264 var dbody = (this.doc.body || this.doc.documentElement);
24265 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24266 // this copies styles from the containing element into thsi one..
24267 // not sure why we need all of this..
24268 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24269 ss['background-attachment'] = 'fixed'; // w3c
24270 dbody.bgProperties = 'fixed'; // ie
24271 Roo.DomHelper.applyStyles(dbody, ss);
24272 Roo.EventManager.on(this.doc, {
24273 'mousedown': this.onEditorEvent,
24274 'dblclick': this.onEditorEvent,
24275 'click': this.onEditorEvent,
24276 'keyup': this.onEditorEvent,
24281 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24283 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24284 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24286 this.initialized = true;
24288 this.fireEvent('initialize', this);
24293 onDestroy : function(){
24299 for (var i =0; i < this.toolbars.length;i++) {
24300 // fixme - ask toolbars for heights?
24301 this.toolbars[i].onDestroy();
24304 this.wrap.dom.innerHTML = '';
24305 this.wrap.remove();
24310 onFirstFocus : function(){
24312 this.assignDocWin();
24315 this.activated = true;
24316 for (var i =0; i < this.toolbars.length;i++) {
24317 this.toolbars[i].onFirstFocus();
24320 if(Roo.isGecko){ // prevent silly gecko errors
24322 var s = this.win.getSelection();
24323 if(!s.focusNode || s.focusNode.nodeType != 3){
24324 var r = s.getRangeAt(0);
24325 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24330 this.execCmd('useCSS', true);
24331 this.execCmd('styleWithCSS', false);
24334 this.fireEvent('activate', this);
24338 adjustFont: function(btn){
24339 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24340 //if(Roo.isSafari){ // safari
24343 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24344 if(Roo.isSafari){ // safari
24345 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24346 v = (v < 10) ? 10 : v;
24347 v = (v > 48) ? 48 : v;
24348 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24353 v = Math.max(1, v+adjust);
24355 this.execCmd('FontSize', v );
24358 onEditorEvent : function(e){
24359 this.fireEvent('editorevent', this, e);
24360 // this.updateToolbar();
24364 insertTag : function(tg)
24366 // could be a bit smarter... -> wrap the current selected tRoo..
24368 this.execCmd("formatblock", tg);
24372 insertText : function(txt)
24376 range = this.createRange();
24377 range.deleteContents();
24378 //alert(Sender.getAttribute('label'));
24380 range.insertNode(this.doc.createTextNode(txt));
24384 relayBtnCmd : function(btn){
24385 this.relayCmd(btn.cmd);
24389 * Executes a Midas editor command on the editor document and performs necessary focus and
24390 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24391 * @param {String} cmd The Midas command
24392 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24394 relayCmd : function(cmd, value){
24396 this.execCmd(cmd, value);
24397 this.fireEvent('editorevent', this);
24398 //this.updateToolbar();
24403 * Executes a Midas editor command directly on the editor document.
24404 * For visual commands, you should use {@link #relayCmd} instead.
24405 * <b>This should only be called after the editor is initialized.</b>
24406 * @param {String} cmd The Midas command
24407 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24409 execCmd : function(cmd, value){
24410 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24416 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24418 * @param {String} text
24420 insertAtCursor : function(text){
24421 if(!this.activated){
24426 var r = this.doc.selection.createRange();
24433 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24435 this.execCmd('InsertHTML', text);
24440 mozKeyPress : function(e){
24442 var c = e.getCharCode(), cmd;
24445 c = String.fromCharCode(c).toLowerCase();
24456 this.cleanUpPaste.defer(100, this);
24464 e.preventDefault();
24472 fixKeys : function(){ // load time branching for fastest keydown performance
24474 return function(e){
24475 var k = e.getKey(), r;
24478 r = this.doc.selection.createRange();
24481 r.pasteHTML('    ');
24488 r = this.doc.selection.createRange();
24490 var target = r.parentElement();
24491 if(!target || target.tagName.toLowerCase() != 'li'){
24493 r.pasteHTML('<br />');
24499 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24500 this.cleanUpPaste.defer(100, this);
24506 }else if(Roo.isOpera){
24507 return function(e){
24508 var k = e.getKey();
24512 this.execCmd('InsertHTML','    ');
24515 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24516 this.cleanUpPaste.defer(100, this);
24521 }else if(Roo.isSafari){
24522 return function(e){
24523 var k = e.getKey();
24527 this.execCmd('InsertText','\t');
24531 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24532 this.cleanUpPaste.defer(100, this);
24540 getAllAncestors: function()
24542 var p = this.getSelectedNode();
24545 a.push(p); // push blank onto stack..
24546 p = this.getParentElement();
24550 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24554 a.push(this.doc.body);
24558 lastSelNode : false,
24561 getSelection : function()
24563 this.assignDocWin();
24564 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24567 getSelectedNode: function()
24569 // this may only work on Gecko!!!
24571 // should we cache this!!!!
24576 var range = this.createRange(this.getSelection());
24579 var parent = range.parentElement();
24581 var testRange = range.duplicate();
24582 testRange.moveToElementText(parent);
24583 if (testRange.inRange(range)) {
24586 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24589 parent = parent.parentElement;
24595 var ar = range.endContainer.childNodes;
24597 ar = range.commonAncestorContainer.childNodes;
24598 //alert(ar.length);
24601 var other_nodes = [];
24602 var has_other_nodes = false;
24603 for (var i=0;i<ar.length;i++) {
24604 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24607 // fullly contained node.
24609 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24614 // probably selected..
24615 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24616 other_nodes.push(ar[i]);
24619 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24624 has_other_nodes = true;
24626 if (!nodes.length && other_nodes.length) {
24627 nodes= other_nodes;
24629 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24635 createRange: function(sel)
24637 // this has strange effects when using with
24638 // top toolbar - not sure if it's a great idea.
24639 //this.editor.contentWindow.focus();
24640 if (typeof sel != "undefined") {
24642 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24644 return this.doc.createRange();
24647 return this.doc.createRange();
24650 getParentElement: function()
24653 this.assignDocWin();
24654 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24656 var range = this.createRange(sel);
24659 var p = range.commonAncestorContainer;
24660 while (p.nodeType == 3) { // text node
24672 // BC Hacks - cause I cant work out what i was trying to do..
24673 rangeIntersectsNode : function(range, node)
24675 var nodeRange = node.ownerDocument.createRange();
24677 nodeRange.selectNode(node);
24680 nodeRange.selectNodeContents(node);
24683 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24684 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24686 rangeCompareNode : function(range, node) {
24687 var nodeRange = node.ownerDocument.createRange();
24689 nodeRange.selectNode(node);
24691 nodeRange.selectNodeContents(node);
24693 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24694 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24696 if (nodeIsBefore && !nodeIsAfter)
24698 if (!nodeIsBefore && nodeIsAfter)
24700 if (nodeIsBefore && nodeIsAfter)
24706 // private? - in a new class?
24707 cleanUpPaste : function()
24709 // cleans up the whole document..
24710 // console.log('cleanuppaste');
24711 this.cleanUpChildren(this.doc.body)
24715 cleanUpChildren : function (n)
24717 if (!n.childNodes.length) {
24720 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24721 this.cleanUpChild(n.childNodes[i]);
24728 cleanUpChild : function (node)
24730 //console.log(node);
24731 if (node.nodeName == "#text") {
24732 // clean up silly Windows -- stuff?
24735 if (node.nodeName == "#comment") {
24736 node.parentNode.removeChild(node);
24737 // clean up silly Windows -- stuff?
24741 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24743 node.parentNode.removeChild(node);
24747 if (!node.attributes || !node.attributes.length) {
24748 this.cleanUpChildren(node);
24752 function cleanAttr(n,v)
24755 if (v.match(/^\./) || v.match(/^\//)) {
24758 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24761 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24762 node.removeAttribute(n);
24766 function cleanStyle(n,v)
24768 if (v.match(/expression/)) { //XSS?? should we even bother..
24769 node.removeAttribute(n);
24774 var parts = v.split(/;/);
24775 Roo.each(parts, function(p) {
24776 p = p.replace(/\s+/g,'');
24780 var l = p.split(':').shift().replace(/\s+/g,'');
24782 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24783 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24784 node.removeAttribute(n);
24793 for (var i = node.attributes.length-1; i > -1 ; i--) {
24794 var a = node.attributes[i];
24796 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24797 node.removeAttribute(a.name);
24800 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24801 cleanAttr(a.name,a.value); // fixme..
24804 if (a.name == 'style') {
24805 cleanStyle(a.name,a.value);
24807 /// clean up MS crap..
24808 if (a.name == 'class') {
24809 if (a.value.match(/^Mso/)) {
24810 node.className = '';
24820 this.cleanUpChildren(node);
24826 // hide stuff that is not compatible
24840 * @event specialkey
24844 * @cfg {String} fieldClass @hide
24847 * @cfg {String} focusClass @hide
24850 * @cfg {String} autoCreate @hide
24853 * @cfg {String} inputType @hide
24856 * @cfg {String} invalidClass @hide
24859 * @cfg {String} invalidText @hide
24862 * @cfg {String} msgFx @hide
24865 * @cfg {String} validateOnBlur @hide
24869 Roo.form.HtmlEditor.white = [
24870 'area', 'br', 'img', 'input', 'hr', 'wbr',
24872 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24873 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24874 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24875 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24876 'table', 'ul', 'xmp',
24878 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24881 'dir', 'menu', 'ol', 'ul', 'dl',
24887 Roo.form.HtmlEditor.black = [
24888 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24890 'base', 'basefont', 'bgsound', 'blink', 'body',
24891 'frame', 'frameset', 'head', 'html', 'ilayer',
24892 'iframe', 'layer', 'link', 'meta', 'object',
24893 'script', 'style' ,'title', 'xml' // clean later..
24895 Roo.form.HtmlEditor.clean = [
24896 'script', 'style', 'title', 'xml'
24901 Roo.form.HtmlEditor.ablack = [
24905 Roo.form.HtmlEditor.aclean = [
24906 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24910 Roo.form.HtmlEditor.pwhite= [
24911 'http', 'https', 'mailto'
24914 Roo.form.HtmlEditor.cwhite= [
24919 // <script type="text/javascript">
24922 * Ext JS Library 1.1.1
24923 * Copyright(c) 2006-2007, Ext JS, LLC.
24929 * @class Roo.form.HtmlEditorToolbar1
24934 new Roo.form.HtmlEditor({
24937 new Roo.form.HtmlEditorToolbar1({
24938 disable : { fonts: 1 , format: 1, ..., ... , ...],
24944 * @cfg {Object} disable List of elements to disable..
24945 * @cfg {Array} btns List of additional buttons.
24949 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24952 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24955 Roo.apply(this, config);
24956 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24957 // dont call parent... till later.
24960 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
24968 * @cfg {Object} disable List of toolbar elements to disable
24973 * @cfg {Array} fontFamilies An array of available font families
24991 // "á" , ?? a acute?
24996 "°" // , // degrees
24998 // "é" , // e ecute
24999 // "ú" , // u ecute?
25002 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25003 "input:submit", "input:button", "select", "textarea", "label" ],
25006 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25008 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25011 * @cfg {String} defaultFont default font to use.
25013 defaultFont: 'tahoma',
25015 fontSelect : false,
25018 formatCombo : false,
25020 init : function(editor)
25022 this.editor = editor;
25025 var fid = editor.frameId;
25027 function btn(id, toggle, handler){
25028 var xid = fid + '-'+ id ;
25032 cls : 'x-btn-icon x-edit-'+id,
25033 enableToggle:toggle !== false,
25034 scope: editor, // was editor...
25035 handler:handler||editor.relayBtnCmd,
25036 clickEvent:'mousedown',
25037 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25044 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25046 // stop form submits
25047 tb.el.on('click', function(e){
25048 e.preventDefault(); // what does this do?
25051 if(!this.disable.font && !Roo.isSafari){
25052 /* why no safari for fonts
25053 editor.fontSelect = tb.el.createChild({
25056 cls:'x-font-select',
25057 html: editor.createFontOptions()
25059 editor.fontSelect.on('change', function(){
25060 var font = editor.fontSelect.dom.value;
25061 editor.relayCmd('fontname', font);
25062 editor.deferFocus();
25065 editor.fontSelect.dom,
25070 if(!this.disable.formats){
25071 this.formatCombo = new Roo.form.ComboBox({
25072 store: new Roo.data.SimpleStore({
25075 data : this.formats // from states.js
25078 //autoCreate : {tag: "div", size: "20"},
25079 displayField:'tag',
25083 triggerAction: 'all',
25084 emptyText:'Add tag',
25085 selectOnFocus:true,
25088 'select': function(c, r, i) {
25089 editor.insertTag(r.get('tag'));
25095 tb.addField(this.formatCombo);
25099 if(!this.disable.format){
25106 if(!this.disable.fontSize){
25111 btn('increasefontsize', false, editor.adjustFont),
25112 btn('decreasefontsize', false, editor.adjustFont)
25117 if(this.disable.colors){
25120 id:editor.frameId +'-forecolor',
25121 cls:'x-btn-icon x-edit-forecolor',
25122 clickEvent:'mousedown',
25123 tooltip: this.buttonTips['forecolor'] || undefined,
25125 menu : new Roo.menu.ColorMenu({
25126 allowReselect: true,
25127 focus: Roo.emptyFn,
25130 selectHandler: function(cp, color){
25131 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25132 editor.deferFocus();
25135 clickEvent:'mousedown'
25138 id:editor.frameId +'backcolor',
25139 cls:'x-btn-icon x-edit-backcolor',
25140 clickEvent:'mousedown',
25141 tooltip: this.buttonTips['backcolor'] || undefined,
25143 menu : new Roo.menu.ColorMenu({
25144 focus: Roo.emptyFn,
25147 allowReselect: true,
25148 selectHandler: function(cp, color){
25150 editor.execCmd('useCSS', false);
25151 editor.execCmd('hilitecolor', color);
25152 editor.execCmd('useCSS', true);
25153 editor.deferFocus();
25155 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25156 Roo.isSafari || Roo.isIE ? '#'+color : color);
25157 editor.deferFocus();
25161 clickEvent:'mousedown'
25166 // now add all the items...
25169 if(!this.disable.alignments){
25172 btn('justifyleft'),
25173 btn('justifycenter'),
25174 btn('justifyright')
25178 //if(!Roo.isSafari){
25179 if(!this.disable.links){
25182 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25186 if(!this.disable.lists){
25189 btn('insertorderedlist'),
25190 btn('insertunorderedlist')
25193 if(!this.disable.sourceEdit){
25196 btn('sourceedit', true, function(btn){
25197 this.toggleSourceEdit(btn.pressed);
25204 // special menu.. - needs to be tidied up..
25205 if (!this.disable.special) {
25208 cls: 'x-edit-none',
25213 for (var i =0; i < this.specialChars.length; i++) {
25214 smenu.menu.items.push({
25216 html: this.specialChars[i],
25217 handler: function(a,b) {
25218 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25231 for(var i =0; i< this.btns.length;i++) {
25232 var b = this.btns[i];
25233 b.cls = 'x-edit-none';
25242 // disable everything...
25244 this.tb.items.each(function(item){
25245 if(item.id != editor.frameId+ '-sourceedit'){
25249 this.rendered = true;
25251 // the all the btns;
25252 editor.on('editorevent', this.updateToolbar, this);
25253 // other toolbars need to implement this..
25254 //editor.on('editmodechange', this.updateToolbar, this);
25260 * Protected method that will not generally be called directly. It triggers
25261 * a toolbar update by reading the markup state of the current selection in the editor.
25263 updateToolbar: function(){
25265 if(!this.editor.activated){
25266 this.editor.onFirstFocus();
25270 var btns = this.tb.items.map,
25271 doc = this.editor.doc,
25272 frameId = this.editor.frameId;
25274 if(!this.disable.font && !Roo.isSafari){
25276 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25277 if(name != this.fontSelect.dom.value){
25278 this.fontSelect.dom.value = name;
25282 if(!this.disable.format){
25283 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25284 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25285 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25287 if(!this.disable.alignments){
25288 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25289 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25290 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25292 if(!Roo.isSafari && !this.disable.lists){
25293 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25294 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25297 var ans = this.editor.getAllAncestors();
25298 if (this.formatCombo) {
25301 var store = this.formatCombo.store;
25302 this.formatCombo.setValue("");
25303 for (var i =0; i < ans.length;i++) {
25304 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25306 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25314 // hides menus... - so this cant be on a menu...
25315 Roo.menu.MenuMgr.hideAll();
25317 //this.editorsyncValue();
25321 createFontOptions : function(){
25322 var buf = [], fs = this.fontFamilies, ff, lc;
25323 for(var i = 0, len = fs.length; i< len; i++){
25325 lc = ff.toLowerCase();
25327 '<option value="',lc,'" style="font-family:',ff,';"',
25328 (this.defaultFont == lc ? ' selected="true">' : '>'),
25333 return buf.join('');
25336 toggleSourceEdit : function(sourceEditMode){
25337 if(sourceEditMode === undefined){
25338 sourceEditMode = !this.sourceEditMode;
25340 this.sourceEditMode = sourceEditMode === true;
25341 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25342 // just toggle the button?
25343 if(btn.pressed !== this.editor.sourceEditMode){
25344 btn.toggle(this.editor.sourceEditMode);
25348 if(this.sourceEditMode){
25349 this.tb.items.each(function(item){
25350 if(item.cmd != 'sourceedit'){
25356 if(this.initialized){
25357 this.tb.items.each(function(item){
25363 // tell the editor that it's been pressed..
25364 this.editor.toggleSourceEdit(sourceEditMode);
25368 * Object collection of toolbar tooltips for the buttons in the editor. The key
25369 * is the command id associated with that button and the value is a valid QuickTips object.
25374 title: 'Bold (Ctrl+B)',
25375 text: 'Make the selected text bold.',
25376 cls: 'x-html-editor-tip'
25379 title: 'Italic (Ctrl+I)',
25380 text: 'Make the selected text italic.',
25381 cls: 'x-html-editor-tip'
25389 title: 'Bold (Ctrl+B)',
25390 text: 'Make the selected text bold.',
25391 cls: 'x-html-editor-tip'
25394 title: 'Italic (Ctrl+I)',
25395 text: 'Make the selected text italic.',
25396 cls: 'x-html-editor-tip'
25399 title: 'Underline (Ctrl+U)',
25400 text: 'Underline the selected text.',
25401 cls: 'x-html-editor-tip'
25403 increasefontsize : {
25404 title: 'Grow Text',
25405 text: 'Increase the font size.',
25406 cls: 'x-html-editor-tip'
25408 decreasefontsize : {
25409 title: 'Shrink Text',
25410 text: 'Decrease the font size.',
25411 cls: 'x-html-editor-tip'
25414 title: 'Text Highlight Color',
25415 text: 'Change the background color of the selected text.',
25416 cls: 'x-html-editor-tip'
25419 title: 'Font Color',
25420 text: 'Change the color of the selected text.',
25421 cls: 'x-html-editor-tip'
25424 title: 'Align Text Left',
25425 text: 'Align text to the left.',
25426 cls: 'x-html-editor-tip'
25429 title: 'Center Text',
25430 text: 'Center text in the editor.',
25431 cls: 'x-html-editor-tip'
25434 title: 'Align Text Right',
25435 text: 'Align text to the right.',
25436 cls: 'x-html-editor-tip'
25438 insertunorderedlist : {
25439 title: 'Bullet List',
25440 text: 'Start a bulleted list.',
25441 cls: 'x-html-editor-tip'
25443 insertorderedlist : {
25444 title: 'Numbered List',
25445 text: 'Start a numbered list.',
25446 cls: 'x-html-editor-tip'
25449 title: 'Hyperlink',
25450 text: 'Make the selected text a hyperlink.',
25451 cls: 'x-html-editor-tip'
25454 title: 'Source Edit',
25455 text: 'Switch to source editing mode.',
25456 cls: 'x-html-editor-tip'
25460 onDestroy : function(){
25463 this.tb.items.each(function(item){
25465 item.menu.removeAll();
25467 item.menu.el.destroy();
25475 onFirstFocus: function() {
25476 this.tb.items.each(function(item){
25485 // <script type="text/javascript">
25488 * Ext JS Library 1.1.1
25489 * Copyright(c) 2006-2007, Ext JS, LLC.
25496 * @class Roo.form.HtmlEditor.ToolbarContext
25501 new Roo.form.HtmlEditor({
25504 new Roo.form.HtmlEditor.ToolbarStandard(),
25505 new Roo.form.HtmlEditor.ToolbarContext()
25510 * @config : {Object} disable List of elements to disable.. (not done yet.)
25515 Roo.form.HtmlEditor.ToolbarContext = function(config)
25518 Roo.apply(this, config);
25519 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25520 // dont call parent... till later.
25522 Roo.form.HtmlEditor.ToolbarContext.types = {
25534 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25596 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25601 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25665 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25673 * @cfg {Object} disable List of toolbar elements to disable
25682 init : function(editor)
25684 this.editor = editor;
25687 var fid = editor.frameId;
25689 function btn(id, toggle, handler){
25690 var xid = fid + '-'+ id ;
25694 cls : 'x-btn-icon x-edit-'+id,
25695 enableToggle:toggle !== false,
25696 scope: editor, // was editor...
25697 handler:handler||editor.relayBtnCmd,
25698 clickEvent:'mousedown',
25699 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25703 // create a new element.
25704 var wdiv = editor.wrap.createChild({
25706 }, editor.wrap.dom.firstChild.nextSibling, true);
25708 // can we do this more than once??
25710 // stop form submits
25713 // disable everything...
25714 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25715 this.toolbars = {};
25717 for (var i in ty) {
25719 this.toolbars[i] = this.buildToolbar(ty[i],i);
25721 this.tb = this.toolbars.BODY;
25725 this.rendered = true;
25727 // the all the btns;
25728 editor.on('editorevent', this.updateToolbar, this);
25729 // other toolbars need to implement this..
25730 //editor.on('editmodechange', this.updateToolbar, this);
25736 * Protected method that will not generally be called directly. It triggers
25737 * a toolbar update by reading the markup state of the current selection in the editor.
25739 updateToolbar: function(){
25741 if(!this.editor.activated){
25742 this.editor.onFirstFocus();
25747 var ans = this.editor.getAllAncestors();
25750 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25751 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25752 sel = sel ? sel : this.editor.doc.body;
25753 sel = sel.tagName.length ? sel : this.editor.doc.body;
25754 var tn = sel.tagName.toUpperCase();
25755 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25756 tn = sel.tagName.toUpperCase();
25757 if (this.tb.name == tn) {
25758 return; // no change
25761 ///console.log("show: " + tn);
25762 this.tb = this.toolbars[tn];
25764 this.tb.fields.each(function(e) {
25765 e.setValue(sel.getAttribute(e.name));
25767 this.tb.selectedNode = sel;
25770 Roo.menu.MenuMgr.hideAll();
25772 //this.editorsyncValue();
25777 onDestroy : function(){
25780 this.tb.items.each(function(item){
25782 item.menu.removeAll();
25784 item.menu.el.destroy();
25792 onFirstFocus: function() {
25793 // need to do this for all the toolbars..
25794 this.tb.items.each(function(item){
25798 buildToolbar: function(tlist, nm)
25800 var editor = this.editor;
25801 // create a new element.
25802 var wdiv = editor.wrap.createChild({
25804 }, editor.wrap.dom.firstChild.nextSibling, true);
25807 var tb = new Roo.Toolbar(wdiv);
25808 tb.add(nm+ ": ");
25809 for (var i in tlist) {
25810 var item = tlist[i];
25811 tb.add(item.title + ": ");
25816 tb.addField( new Roo.form.ComboBox({
25817 store: new Roo.data.SimpleStore({
25820 data : item.opts // from states.js
25823 displayField:'val',
25827 triggerAction: 'all',
25828 emptyText:'Select',
25829 selectOnFocus:true,
25830 width: item.width ? item.width : 130,
25832 'select': function(c, r, i) {
25833 tb.selectedNode.setAttribute(c.name, r.get('val'));
25844 tb.addField( new Roo.form.TextField({
25847 //allowBlank:false,
25852 tb.addField( new Roo.form.TextField({
25858 'change' : function(f, nv, ov) {
25859 tb.selectedNode.setAttribute(f.name, nv);
25865 tb.el.on('click', function(e){
25866 e.preventDefault(); // what does this do?
25868 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25871 // dont need to disable them... as they will get hidden
25888 * Ext JS Library 1.1.1
25889 * Copyright(c) 2006-2007, Ext JS, LLC.
25891 * Originally Released Under LGPL - original licence link has changed is not relivant.
25894 * <script type="text/javascript">
25898 * @class Roo.form.BasicForm
25899 * @extends Roo.util.Observable
25900 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25902 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25903 * @param {Object} config Configuration options
25905 Roo.form.BasicForm = function(el, config){
25906 this.allItems = [];
25907 this.childForms = [];
25908 Roo.apply(this, config);
25910 * The Roo.form.Field items in this form.
25911 * @type MixedCollection
25915 this.items = new Roo.util.MixedCollection(false, function(o){
25916 return o.id || (o.id = Roo.id());
25920 * @event beforeaction
25921 * Fires before any action is performed. Return false to cancel the action.
25922 * @param {Form} this
25923 * @param {Action} action The action to be performed
25925 beforeaction: true,
25927 * @event actionfailed
25928 * Fires when an action fails.
25929 * @param {Form} this
25930 * @param {Action} action The action that failed
25932 actionfailed : true,
25934 * @event actioncomplete
25935 * Fires when an action is completed.
25936 * @param {Form} this
25937 * @param {Action} action The action that completed
25939 actioncomplete : true
25944 Roo.form.BasicForm.superclass.constructor.call(this);
25947 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25949 * @cfg {String} method
25950 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25953 * @cfg {DataReader} reader
25954 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25955 * This is optional as there is built-in support for processing JSON.
25958 * @cfg {DataReader} errorReader
25959 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
25960 * This is completely optional as there is built-in support for processing JSON.
25963 * @cfg {String} url
25964 * The URL to use for form actions if one isn't supplied in the action options.
25967 * @cfg {Boolean} fileUpload
25968 * Set to true if this form is a file upload.
25971 * @cfg {Object} baseParams
25972 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
25975 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
25980 activeAction : null,
25983 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
25984 * or setValues() data instead of when the form was first created.
25986 trackResetOnLoad : false,
25990 * childForms - used for multi-tab forms
25993 childForms : false,
25996 * allItems - full list of fields.
26002 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26003 * element by passing it or its id or mask the form itself by passing in true.
26006 waitMsgTarget : undefined,
26009 initEl : function(el){
26010 this.el = Roo.get(el);
26011 this.id = this.el.id || Roo.id();
26012 this.el.on('submit', this.onSubmit, this);
26013 this.el.addClass('x-form');
26017 onSubmit : function(e){
26022 * Returns true if client-side validation on the form is successful.
26025 isValid : function(){
26027 this.items.each(function(f){
26036 * Returns true if any fields in this form have changed since their original load.
26039 isDirty : function(){
26041 this.items.each(function(f){
26051 * Performs a predefined action (submit or load) or custom actions you define on this form.
26052 * @param {String} actionName The name of the action type
26053 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26054 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26055 * accept other config options):
26057 Property Type Description
26058 ---------------- --------------- ----------------------------------------------------------------------------------
26059 url String The url for the action (defaults to the form's url)
26060 method String The form method to use (defaults to the form's method, or POST if not defined)
26061 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26062 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26063 validate the form on the client (defaults to false)
26065 * @return {BasicForm} this
26067 doAction : function(action, options){
26068 if(typeof action == 'string'){
26069 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26071 if(this.fireEvent('beforeaction', this, action) !== false){
26072 this.beforeAction(action);
26073 action.run.defer(100, action);
26079 * Shortcut to do a submit action.
26080 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26081 * @return {BasicForm} this
26083 submit : function(options){
26084 this.doAction('submit', options);
26089 * Shortcut to do a load action.
26090 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26091 * @return {BasicForm} this
26093 load : function(options){
26094 this.doAction('load', options);
26099 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26100 * @param {Record} record The record to edit
26101 * @return {BasicForm} this
26103 updateRecord : function(record){
26104 record.beginEdit();
26105 var fs = record.fields;
26106 fs.each(function(f){
26107 var field = this.findField(f.name);
26109 record.set(f.name, field.getValue());
26117 * Loads an Roo.data.Record into this form.
26118 * @param {Record} record The record to load
26119 * @return {BasicForm} this
26121 loadRecord : function(record){
26122 this.setValues(record.data);
26127 beforeAction : function(action){
26128 var o = action.options;
26130 if(this.waitMsgTarget === true){
26131 this.el.mask(o.waitMsg, 'x-mask-loading');
26132 }else if(this.waitMsgTarget){
26133 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26134 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
26136 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
26142 afterAction : function(action, success){
26143 this.activeAction = null;
26144 var o = action.options;
26146 if(this.waitMsgTarget === true){
26148 }else if(this.waitMsgTarget){
26149 this.waitMsgTarget.unmask();
26151 Roo.MessageBox.updateProgress(1);
26152 Roo.MessageBox.hide();
26159 Roo.callback(o.success, o.scope, [this, action]);
26160 this.fireEvent('actioncomplete', this, action);
26162 Roo.callback(o.failure, o.scope, [this, action]);
26163 this.fireEvent('actionfailed', this, action);
26168 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26169 * @param {String} id The value to search for
26172 findField : function(id){
26173 var field = this.items.get(id);
26175 this.items.each(function(f){
26176 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26182 return field || null;
26186 * Add a secondary form to this one,
26187 * Used to provide tabbed forms. One form is primary, with hidden values
26188 * which mirror the elements from the other forms.
26190 * @param {Roo.form.Form} form to add.
26193 addForm : function(form)
26196 if (this.childForms.indexOf(form) > -1) {
26200 this.childForms.push(form);
26202 Roo.each(form.allItems, function (fe) {
26204 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26205 if (this.findField(n)) { // already added..
26208 var add = new Roo.form.Hidden({
26211 add.render(this.el);
26218 * Mark fields in this form invalid in bulk.
26219 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26220 * @return {BasicForm} this
26222 markInvalid : function(errors){
26223 if(errors instanceof Array){
26224 for(var i = 0, len = errors.length; i < len; i++){
26225 var fieldError = errors[i];
26226 var f = this.findField(fieldError.id);
26228 f.markInvalid(fieldError.msg);
26234 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26235 field.markInvalid(errors[id]);
26239 Roo.each(this.childForms || [], function (f) {
26240 f.markInvalid(errors);
26247 * Set values for fields in this form in bulk.
26248 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26249 * @return {BasicForm} this
26251 setValues : function(values){
26252 if(values instanceof Array){ // array of objects
26253 for(var i = 0, len = values.length; i < len; i++){
26255 var f = this.findField(v.id);
26257 f.setValue(v.value);
26258 if(this.trackResetOnLoad){
26259 f.originalValue = f.getValue();
26263 }else{ // object hash
26266 if(typeof values[id] != 'function' && (field = this.findField(id))){
26268 if (field.setFromData &&
26269 field.valueField &&
26270 field.displayField &&
26271 // combos' with local stores can
26272 // be queried via setValue()
26273 // to set their value..
26274 (field.store && !field.store.isLocal)
26278 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26279 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26280 field.setFromData(sd);
26283 field.setValue(values[id]);
26287 if(this.trackResetOnLoad){
26288 field.originalValue = field.getValue();
26294 Roo.each(this.childForms || [], function (f) {
26295 f.setValues(values);
26302 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26303 * they are returned as an array.
26304 * @param {Boolean} asString
26307 getValues : function(asString){
26308 if (this.childForms) {
26309 // copy values from the child forms
26310 Roo.each(this.childForms, function (f) {
26311 this.setValues(f.getValues());
26317 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26318 if(asString === true){
26321 return Roo.urlDecode(fs);
26325 * Returns the fields in this form as an object with key/value pairs.
26326 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26329 getFieldValues : function()
26331 if (this.childForms) {
26332 // copy values from the child forms
26333 Roo.each(this.childForms, function (f) {
26334 this.setValues(f.getValues());
26339 this.items.each(function(f){
26340 if (!f.getName()) {
26343 var v = f.getValue();
26344 if ((typeof(v) == 'object') && f.getRawValue) {
26345 v = f.getRawValue() ; // dates..
26347 ret[f.getName()] = v;
26354 * Clears all invalid messages in this form.
26355 * @return {BasicForm} this
26357 clearInvalid : function(){
26358 this.items.each(function(f){
26362 Roo.each(this.childForms || [], function (f) {
26371 * Resets this form.
26372 * @return {BasicForm} this
26374 reset : function(){
26375 this.items.each(function(f){
26379 Roo.each(this.childForms || [], function (f) {
26388 * Add Roo.form components to this form.
26389 * @param {Field} field1
26390 * @param {Field} field2 (optional)
26391 * @param {Field} etc (optional)
26392 * @return {BasicForm} this
26395 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26401 * Removes a field from the items collection (does NOT remove its markup).
26402 * @param {Field} field
26403 * @return {BasicForm} this
26405 remove : function(field){
26406 this.items.remove(field);
26411 * Looks at the fields in this form, checks them for an id attribute,
26412 * and calls applyTo on the existing dom element with that id.
26413 * @return {BasicForm} this
26415 render : function(){
26416 this.items.each(function(f){
26417 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26425 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26426 * @param {Object} values
26427 * @return {BasicForm} this
26429 applyToFields : function(o){
26430 this.items.each(function(f){
26437 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26438 * @param {Object} values
26439 * @return {BasicForm} this
26441 applyIfToFields : function(o){
26442 this.items.each(function(f){
26450 Roo.BasicForm = Roo.form.BasicForm;/*
26452 * Ext JS Library 1.1.1
26453 * Copyright(c) 2006-2007, Ext JS, LLC.
26455 * Originally Released Under LGPL - original licence link has changed is not relivant.
26458 * <script type="text/javascript">
26462 * @class Roo.form.Form
26463 * @extends Roo.form.BasicForm
26464 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26466 * @param {Object} config Configuration options
26468 Roo.form.Form = function(config){
26470 if (config.items) {
26471 xitems = config.items;
26472 delete config.items;
26476 Roo.form.Form.superclass.constructor.call(this, null, config);
26477 this.url = this.url || this.action;
26479 this.root = new Roo.form.Layout(Roo.applyIf({
26483 this.active = this.root;
26485 * Array of all the buttons that have been added to this form via {@link addButton}
26489 this.allItems = [];
26492 * @event clientvalidation
26493 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26494 * @param {Form} this
26495 * @param {Boolean} valid true if the form has passed client-side validation
26497 clientvalidation: true,
26500 * Fires when the form is rendered
26501 * @param {Roo.form.Form} form
26506 if (this.progressUrl) {
26507 // push a hidden field onto the list of fields..
26511 name : 'UPLOAD_IDENTIFIER'
26516 Roo.each(xitems, this.addxtype, this);
26522 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26524 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26527 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26530 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26532 buttonAlign:'center',
26535 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26540 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26541 * This property cascades to child containers if not set.
26546 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26547 * fires a looping event with that state. This is required to bind buttons to the valid
26548 * state using the config value formBind:true on the button.
26550 monitorValid : false,
26553 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26558 * @cfg {String} progressUrl - Url to return progress data
26561 progressUrl : false,
26564 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26565 * fields are added and the column is closed. If no fields are passed the column remains open
26566 * until end() is called.
26567 * @param {Object} config The config to pass to the column
26568 * @param {Field} field1 (optional)
26569 * @param {Field} field2 (optional)
26570 * @param {Field} etc (optional)
26571 * @return Column The column container object
26573 column : function(c){
26574 var col = new Roo.form.Column(c);
26576 if(arguments.length > 1){ // duplicate code required because of Opera
26577 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26584 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26585 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26586 * until end() is called.
26587 * @param {Object} config The config to pass to the fieldset
26588 * @param {Field} field1 (optional)
26589 * @param {Field} field2 (optional)
26590 * @param {Field} etc (optional)
26591 * @return FieldSet The fieldset container object
26593 fieldset : function(c){
26594 var fs = new Roo.form.FieldSet(c);
26596 if(arguments.length > 1){ // duplicate code required because of Opera
26597 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26604 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26605 * fields are added and the container is closed. If no fields are passed the container remains open
26606 * until end() is called.
26607 * @param {Object} config The config to pass to the Layout
26608 * @param {Field} field1 (optional)
26609 * @param {Field} field2 (optional)
26610 * @param {Field} etc (optional)
26611 * @return Layout The container object
26613 container : function(c){
26614 var l = new Roo.form.Layout(c);
26616 if(arguments.length > 1){ // duplicate code required because of Opera
26617 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26624 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26625 * @param {Object} container A Roo.form.Layout or subclass of Layout
26626 * @return {Form} this
26628 start : function(c){
26629 // cascade label info
26630 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26631 this.active.stack.push(c);
26632 c.ownerCt = this.active;
26638 * Closes the current open container
26639 * @return {Form} this
26642 if(this.active == this.root){
26645 this.active = this.active.ownerCt;
26650 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26651 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26652 * as the label of the field.
26653 * @param {Field} field1
26654 * @param {Field} field2 (optional)
26655 * @param {Field} etc. (optional)
26656 * @return {Form} this
26659 this.active.stack.push.apply(this.active.stack, arguments);
26660 this.allItems.push.apply(this.allItems,arguments);
26662 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26663 if(a[i].isFormField){
26668 Roo.form.Form.superclass.add.apply(this, r);
26678 * Find any element that has been added to a form, using it's ID or name
26679 * This can include framesets, columns etc. along with regular fields..
26680 * @param {String} id - id or name to find.
26682 * @return {Element} e - or false if nothing found.
26684 findbyId : function(id)
26690 Ext.each(this.allItems, function(f){
26691 if (f.id == id || f.name == id ){
26702 * Render this form into the passed container. This should only be called once!
26703 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26704 * @return {Form} this
26706 render : function(ct)
26712 var o = this.autoCreate || {
26714 method : this.method || 'POST',
26715 id : this.id || Roo.id()
26717 this.initEl(ct.createChild(o));
26719 this.root.render(this.el);
26723 this.items.each(function(f){
26724 f.render('x-form-el-'+f.id);
26727 if(this.buttons.length > 0){
26728 // tables are required to maintain order and for correct IE layout
26729 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26730 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26731 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26733 var tr = tb.getElementsByTagName('tr')[0];
26734 for(var i = 0, len = this.buttons.length; i < len; i++) {
26735 var b = this.buttons[i];
26736 var td = document.createElement('td');
26737 td.className = 'x-form-btn-td';
26738 b.render(tr.appendChild(td));
26741 if(this.monitorValid){ // initialize after render
26742 this.startMonitoring();
26744 this.fireEvent('rendered', this);
26749 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26750 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26751 * object or a valid Roo.DomHelper element config
26752 * @param {Function} handler The function called when the button is clicked
26753 * @param {Object} scope (optional) The scope of the handler function
26754 * @return {Roo.Button}
26756 addButton : function(config, handler, scope){
26760 minWidth: this.minButtonWidth,
26763 if(typeof config == "string"){
26766 Roo.apply(bc, config);
26768 var btn = new Roo.Button(null, bc);
26769 this.buttons.push(btn);
26774 * Adds a series of form elements (using the xtype property as the factory method.
26775 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26776 * @param {Object} config
26779 addxtype : function()
26781 var ar = Array.prototype.slice.call(arguments, 0);
26783 for(var i = 0; i < ar.length; i++) {
26785 continue; // skip -- if this happends something invalid got sent, we
26786 // should ignore it, as basically that interface element will not show up
26787 // and that should be pretty obvious!!
26790 if (Roo.form[ar[i].xtype]) {
26792 var fe = Roo.factory(ar[i], Roo.form);
26798 fe.store.form = this;
26803 this.allItems.push(fe);
26804 if (fe.items && fe.addxtype) {
26805 fe.addxtype.apply(fe, fe.items);
26815 // console.log('adding ' + ar[i].xtype);
26817 if (ar[i].xtype == 'Button') {
26818 //console.log('adding button');
26819 //console.log(ar[i]);
26820 this.addButton(ar[i]);
26821 this.allItems.push(fe);
26825 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26826 alert('end is not supported on xtype any more, use items');
26828 // //console.log('adding end');
26836 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26837 * option "monitorValid"
26839 startMonitoring : function(){
26842 Roo.TaskMgr.start({
26843 run : this.bindHandler,
26844 interval : this.monitorPoll || 200,
26851 * Stops monitoring of the valid state of this form
26853 stopMonitoring : function(){
26854 this.bound = false;
26858 bindHandler : function(){
26860 return false; // stops binding
26863 this.items.each(function(f){
26864 if(!f.isValid(true)){
26869 for(var i = 0, len = this.buttons.length; i < len; i++){
26870 var btn = this.buttons[i];
26871 if(btn.formBind === true && btn.disabled === valid){
26872 btn.setDisabled(!valid);
26875 this.fireEvent('clientvalidation', this, valid);
26889 Roo.Form = Roo.form.Form;
26892 * Ext JS Library 1.1.1
26893 * Copyright(c) 2006-2007, Ext JS, LLC.
26895 * Originally Released Under LGPL - original licence link has changed is not relivant.
26898 * <script type="text/javascript">
26902 * @class Roo.form.Action
26903 * Internal Class used to handle form actions
26905 * @param {Roo.form.BasicForm} el The form element or its id
26906 * @param {Object} config Configuration options
26910 // define the action interface
26911 Roo.form.Action = function(form, options){
26913 this.options = options || {};
26916 * Client Validation Failed
26919 Roo.form.Action.CLIENT_INVALID = 'client';
26921 * Server Validation Failed
26924 Roo.form.Action.SERVER_INVALID = 'server';
26926 * Connect to Server Failed
26929 Roo.form.Action.CONNECT_FAILURE = 'connect';
26931 * Reading Data from Server Failed
26934 Roo.form.Action.LOAD_FAILURE = 'load';
26936 Roo.form.Action.prototype = {
26938 failureType : undefined,
26939 response : undefined,
26940 result : undefined,
26942 // interface method
26943 run : function(options){
26947 // interface method
26948 success : function(response){
26952 // interface method
26953 handleResponse : function(response){
26957 // default connection failure
26958 failure : function(response){
26959 this.response = response;
26960 this.failureType = Roo.form.Action.CONNECT_FAILURE;
26961 this.form.afterAction(this, false);
26964 processResponse : function(response){
26965 this.response = response;
26966 if(!response.responseText){
26969 this.result = this.handleResponse(response);
26970 return this.result;
26973 // utility functions used internally
26974 getUrl : function(appendParams){
26975 var url = this.options.url || this.form.url || this.form.el.dom.action;
26977 var p = this.getParams();
26979 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
26985 getMethod : function(){
26986 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
26989 getParams : function(){
26990 var bp = this.form.baseParams;
26991 var p = this.options.params;
26993 if(typeof p == "object"){
26994 p = Roo.urlEncode(Roo.applyIf(p, bp));
26995 }else if(typeof p == 'string' && bp){
26996 p += '&' + Roo.urlEncode(bp);
26999 p = Roo.urlEncode(bp);
27004 createCallback : function(){
27006 success: this.success,
27007 failure: this.failure,
27009 timeout: (this.form.timeout*1000),
27010 upload: this.form.fileUpload ? this.success : undefined
27015 Roo.form.Action.Submit = function(form, options){
27016 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27019 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27022 haveProgress : false,
27023 uploadComplete : false,
27025 // uploadProgress indicator.
27026 uploadProgress : function()
27028 if (!this.form.progressUrl) {
27032 if (!this.haveProgress) {
27033 Roo.MessageBox.progress("Uploading", "Uploading");
27035 if (this.uploadComplete) {
27036 Roo.MessageBox.hide();
27040 this.haveProgress = true;
27042 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27044 var c = new Roo.data.Connection();
27046 url : this.form.progressUrl,
27051 success : function(req){
27052 //console.log(data);
27056 rdata = Roo.decode(req.responseText)
27058 Roo.log("Invalid data from server..");
27062 if (!rdata || !rdata.success) {
27066 var data = rdata.data;
27068 if (this.uploadComplete) {
27069 Roo.MessageBox.hide();
27074 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27075 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27078 this.uploadProgress.defer(2000,this);
27081 failure: function(data) {
27082 Roo.log('progress url failed ');
27093 // run get Values on the form, so it syncs any secondary forms.
27094 this.form.getValues();
27096 var o = this.options;
27097 var method = this.getMethod();
27098 var isPost = method == 'POST';
27099 if(o.clientValidation === false || this.form.isValid()){
27101 if (this.form.progressUrl) {
27102 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27103 (new Date() * 1) + '' + Math.random());
27107 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27108 form:this.form.el.dom,
27109 url:this.getUrl(!isPost),
27111 params:isPost ? this.getParams() : null,
27112 isUpload: this.form.fileUpload
27115 this.uploadProgress();
27117 }else if (o.clientValidation !== false){ // client validation failed
27118 this.failureType = Roo.form.Action.CLIENT_INVALID;
27119 this.form.afterAction(this, false);
27123 success : function(response)
27125 this.uploadComplete= true;
27126 if (this.haveProgress) {
27127 Roo.MessageBox.hide();
27130 var result = this.processResponse(response);
27131 if(result === true || result.success){
27132 this.form.afterAction(this, true);
27136 this.form.markInvalid(result.errors);
27137 this.failureType = Roo.form.Action.SERVER_INVALID;
27139 this.form.afterAction(this, false);
27141 failure : function(response)
27143 this.uploadComplete= true;
27144 if (this.haveProgress) {
27145 Roo.MessageBox.hide();
27148 this.response = response;
27149 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27150 this.form.afterAction(this, false);
27153 handleResponse : function(response){
27154 if(this.form.errorReader){
27155 var rs = this.form.errorReader.read(response);
27158 for(var i = 0, len = rs.records.length; i < len; i++) {
27159 var r = rs.records[i];
27160 errors[i] = r.data;
27163 if(errors.length < 1){
27167 success : rs.success,
27173 ret = Roo.decode(response.responseText);
27177 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27187 Roo.form.Action.Load = function(form, options){
27188 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27189 this.reader = this.form.reader;
27192 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27196 Roo.Ajax.request(Roo.apply(
27197 this.createCallback(), {
27198 method:this.getMethod(),
27199 url:this.getUrl(false),
27200 params:this.getParams()
27204 success : function(response){
27205 var result = this.processResponse(response);
27206 if(result === true || !result.success || !result.data){
27207 this.failureType = Roo.form.Action.LOAD_FAILURE;
27208 this.form.afterAction(this, false);
27211 this.form.clearInvalid();
27212 this.form.setValues(result.data);
27213 this.form.afterAction(this, true);
27216 handleResponse : function(response){
27217 if(this.form.reader){
27218 var rs = this.form.reader.read(response);
27219 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27221 success : rs.success,
27225 return Roo.decode(response.responseText);
27229 Roo.form.Action.ACTION_TYPES = {
27230 'load' : Roo.form.Action.Load,
27231 'submit' : Roo.form.Action.Submit
27234 * Ext JS Library 1.1.1
27235 * Copyright(c) 2006-2007, Ext JS, LLC.
27237 * Originally Released Under LGPL - original licence link has changed is not relivant.
27240 * <script type="text/javascript">
27244 * @class Roo.form.Layout
27245 * @extends Roo.Component
27246 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27248 * @param {Object} config Configuration options
27250 Roo.form.Layout = function(config){
27252 if (config.items) {
27253 xitems = config.items;
27254 delete config.items;
27256 Roo.form.Layout.superclass.constructor.call(this, config);
27258 Roo.each(xitems, this.addxtype, this);
27262 Roo.extend(Roo.form.Layout, Roo.Component, {
27264 * @cfg {String/Object} autoCreate
27265 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27268 * @cfg {String/Object/Function} style
27269 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27270 * a function which returns such a specification.
27273 * @cfg {String} labelAlign
27274 * Valid values are "left," "top" and "right" (defaults to "left")
27277 * @cfg {Number} labelWidth
27278 * Fixed width in pixels of all field labels (defaults to undefined)
27281 * @cfg {Boolean} clear
27282 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27286 * @cfg {String} labelSeparator
27287 * The separator to use after field labels (defaults to ':')
27289 labelSeparator : ':',
27291 * @cfg {Boolean} hideLabels
27292 * True to suppress the display of field labels in this layout (defaults to false)
27294 hideLabels : false,
27297 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27302 onRender : function(ct, position){
27303 if(this.el){ // from markup
27304 this.el = Roo.get(this.el);
27305 }else { // generate
27306 var cfg = this.getAutoCreate();
27307 this.el = ct.createChild(cfg, position);
27310 this.el.applyStyles(this.style);
27312 if(this.labelAlign){
27313 this.el.addClass('x-form-label-'+this.labelAlign);
27315 if(this.hideLabels){
27316 this.labelStyle = "display:none";
27317 this.elementStyle = "padding-left:0;";
27319 if(typeof this.labelWidth == 'number'){
27320 this.labelStyle = "width:"+this.labelWidth+"px;";
27321 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27323 if(this.labelAlign == 'top'){
27324 this.labelStyle = "width:auto;";
27325 this.elementStyle = "padding-left:0;";
27328 var stack = this.stack;
27329 var slen = stack.length;
27331 if(!this.fieldTpl){
27332 var t = new Roo.Template(
27333 '<div class="x-form-item {5}">',
27334 '<label for="{0}" style="{2}">{1}{4}</label>',
27335 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27337 '</div><div class="x-form-clear-left"></div>'
27339 t.disableFormats = true;
27341 Roo.form.Layout.prototype.fieldTpl = t;
27343 for(var i = 0; i < slen; i++) {
27344 if(stack[i].isFormField){
27345 this.renderField(stack[i]);
27347 this.renderComponent(stack[i]);
27352 this.el.createChild({cls:'x-form-clear'});
27357 renderField : function(f){
27358 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27361 f.labelStyle||this.labelStyle||'', //2
27362 this.elementStyle||'', //3
27363 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27364 f.itemCls||this.itemCls||'' //5
27365 ], true).getPrevSibling());
27369 renderComponent : function(c){
27370 c.render(c.isLayout ? this.el : this.el.createChild());
27373 * Adds a object form elements (using the xtype property as the factory method.)
27374 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27375 * @param {Object} config
27377 addxtype : function(o)
27379 // create the lement.
27380 o.form = this.form;
27381 var fe = Roo.factory(o, Roo.form);
27382 this.form.allItems.push(fe);
27383 this.stack.push(fe);
27385 if (fe.isFormField) {
27386 this.form.items.add(fe);
27394 * @class Roo.form.Column
27395 * @extends Roo.form.Layout
27396 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27398 * @param {Object} config Configuration options
27400 Roo.form.Column = function(config){
27401 Roo.form.Column.superclass.constructor.call(this, config);
27404 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27406 * @cfg {Number/String} width
27407 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27410 * @cfg {String/Object} autoCreate
27411 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27415 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27418 onRender : function(ct, position){
27419 Roo.form.Column.superclass.onRender.call(this, ct, position);
27421 this.el.setWidth(this.width);
27428 * @class Roo.form.Row
27429 * @extends Roo.form.Layout
27430 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27432 * @param {Object} config Configuration options
27436 Roo.form.Row = function(config){
27437 Roo.form.Row.superclass.constructor.call(this, config);
27440 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27442 * @cfg {Number/String} width
27443 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27446 * @cfg {Number/String} height
27447 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27449 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27453 onRender : function(ct, position){
27454 //console.log('row render');
27456 var t = new Roo.Template(
27457 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27458 '<label for="{0}" style="{2}">{1}{4}</label>',
27459 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27463 t.disableFormats = true;
27465 Roo.form.Layout.prototype.rowTpl = t;
27467 this.fieldTpl = this.rowTpl;
27469 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27470 var labelWidth = 100;
27472 if ((this.labelAlign != 'top')) {
27473 if (typeof this.labelWidth == 'number') {
27474 labelWidth = this.labelWidth
27476 this.padWidth = 20 + labelWidth;
27480 Roo.form.Column.superclass.onRender.call(this, ct, position);
27482 this.el.setWidth(this.width);
27485 this.el.setHeight(this.height);
27490 renderField : function(f){
27491 f.fieldEl = this.fieldTpl.append(this.el, [
27492 f.id, f.fieldLabel,
27493 f.labelStyle||this.labelStyle||'',
27494 this.elementStyle||'',
27495 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27496 f.itemCls||this.itemCls||'',
27497 f.width ? f.width + this.padWidth : 160 + this.padWidth
27504 * @class Roo.form.FieldSet
27505 * @extends Roo.form.Layout
27506 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27508 * @param {Object} config Configuration options
27510 Roo.form.FieldSet = function(config){
27511 Roo.form.FieldSet.superclass.constructor.call(this, config);
27514 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27516 * @cfg {String} legend
27517 * The text to display as the legend for the FieldSet (defaults to '')
27520 * @cfg {String/Object} autoCreate
27521 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27525 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27528 onRender : function(ct, position){
27529 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27531 this.setLegend(this.legend);
27536 setLegend : function(text){
27538 this.el.child('legend').update(text);
27543 * Ext JS Library 1.1.1
27544 * Copyright(c) 2006-2007, Ext JS, LLC.
27546 * Originally Released Under LGPL - original licence link has changed is not relivant.
27549 * <script type="text/javascript">
27552 * @class Roo.form.VTypes
27553 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27556 Roo.form.VTypes = function(){
27557 // closure these in so they are only created once.
27558 var alpha = /^[a-zA-Z_]+$/;
27559 var alphanum = /^[a-zA-Z0-9_]+$/;
27560 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27561 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27563 // All these messages and functions are configurable
27566 * The function used to validate email addresses
27567 * @param {String} value The email address
27569 'email' : function(v){
27570 return email.test(v);
27573 * The error text to display when the email validation function returns false
27576 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27578 * The keystroke filter mask to be applied on email input
27581 'emailMask' : /[a-z0-9_\.\-@]/i,
27584 * The function used to validate URLs
27585 * @param {String} value The URL
27587 'url' : function(v){
27588 return url.test(v);
27591 * The error text to display when the url validation function returns false
27594 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27597 * The function used to validate alpha values
27598 * @param {String} value The value
27600 'alpha' : function(v){
27601 return alpha.test(v);
27604 * The error text to display when the alpha validation function returns false
27607 'alphaText' : 'This field should only contain letters and _',
27609 * The keystroke filter mask to be applied on alpha input
27612 'alphaMask' : /[a-z_]/i,
27615 * The function used to validate alphanumeric values
27616 * @param {String} value The value
27618 'alphanum' : function(v){
27619 return alphanum.test(v);
27622 * The error text to display when the alphanumeric validation function returns false
27625 'alphanumText' : 'This field should only contain letters, numbers and _',
27627 * The keystroke filter mask to be applied on alphanumeric input
27630 'alphanumMask' : /[a-z0-9_]/i
27632 }();//<script type="text/javascript">
27635 * @class Roo.form.FCKeditor
27636 * @extends Roo.form.TextArea
27637 * Wrapper around the FCKEditor http://www.fckeditor.net
27639 * Creates a new FCKeditor
27640 * @param {Object} config Configuration options
27642 Roo.form.FCKeditor = function(config){
27643 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27646 * @event editorinit
27647 * Fired when the editor is initialized - you can add extra handlers here..
27648 * @param {FCKeditor} this
27649 * @param {Object} the FCK object.
27656 Roo.form.FCKeditor.editors = { };
27657 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27659 //defaultAutoCreate : {
27660 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27664 * @cfg {Object} fck options - see fck manual for details.
27669 * @cfg {Object} fck toolbar set (Basic or Default)
27671 toolbarSet : 'Basic',
27673 * @cfg {Object} fck BasePath
27675 basePath : '/fckeditor/',
27683 onRender : function(ct, position)
27686 this.defaultAutoCreate = {
27688 style:"width:300px;height:60px;",
27689 autocomplete: "off"
27692 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27695 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27696 if(this.preventScrollbars){
27697 this.el.setStyle("overflow", "hidden");
27699 this.el.setHeight(this.growMin);
27702 //console.log('onrender' + this.getId() );
27703 Roo.form.FCKeditor.editors[this.getId()] = this;
27706 this.replaceTextarea() ;
27710 getEditor : function() {
27711 return this.fckEditor;
27714 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27715 * @param {Mixed} value The value to set
27719 setValue : function(value)
27721 //console.log('setValue: ' + value);
27723 if(typeof(value) == 'undefined') { // not sure why this is happending...
27726 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27728 //if(!this.el || !this.getEditor()) {
27729 // this.value = value;
27730 //this.setValue.defer(100,this,[value]);
27734 if(!this.getEditor()) {
27738 this.getEditor().SetData(value);
27745 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27746 * @return {Mixed} value The field value
27748 getValue : function()
27751 if (this.frame && this.frame.dom.style.display == 'none') {
27752 return Roo.form.FCKeditor.superclass.getValue.call(this);
27755 if(!this.el || !this.getEditor()) {
27757 // this.getValue.defer(100,this);
27762 var value=this.getEditor().GetData();
27763 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27764 return Roo.form.FCKeditor.superclass.getValue.call(this);
27770 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27771 * @return {Mixed} value The field value
27773 getRawValue : function()
27775 if (this.frame && this.frame.dom.style.display == 'none') {
27776 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27779 if(!this.el || !this.getEditor()) {
27780 //this.getRawValue.defer(100,this);
27787 var value=this.getEditor().GetData();
27788 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27789 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27793 setSize : function(w,h) {
27797 //if (this.frame && this.frame.dom.style.display == 'none') {
27798 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27801 //if(!this.el || !this.getEditor()) {
27802 // this.setSize.defer(100,this, [w,h]);
27808 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27810 this.frame.dom.setAttribute('width', w);
27811 this.frame.dom.setAttribute('height', h);
27812 this.frame.setSize(w,h);
27816 toggleSourceEdit : function(value) {
27820 this.el.dom.style.display = value ? '' : 'none';
27821 this.frame.dom.style.display = value ? 'none' : '';
27826 focus: function(tag)
27828 if (this.frame.dom.style.display == 'none') {
27829 return Roo.form.FCKeditor.superclass.focus.call(this);
27831 if(!this.el || !this.getEditor()) {
27832 this.focus.defer(100,this, [tag]);
27839 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27840 this.getEditor().Focus();
27842 if (!this.getEditor().Selection.GetSelection()) {
27843 this.focus.defer(100,this, [tag]);
27848 var r = this.getEditor().EditorDocument.createRange();
27849 r.setStart(tgs[0],0);
27850 r.setEnd(tgs[0],0);
27851 this.getEditor().Selection.GetSelection().removeAllRanges();
27852 this.getEditor().Selection.GetSelection().addRange(r);
27853 this.getEditor().Focus();
27860 replaceTextarea : function()
27862 if ( document.getElementById( this.getId() + '___Frame' ) )
27864 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27866 // We must check the elements firstly using the Id and then the name.
27867 var oTextarea = document.getElementById( this.getId() );
27869 var colElementsByName = document.getElementsByName( this.getId() ) ;
27871 oTextarea.style.display = 'none' ;
27873 if ( oTextarea.tabIndex ) {
27874 this.TabIndex = oTextarea.tabIndex ;
27877 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27878 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27879 this.frame = Roo.get(this.getId() + '___Frame')
27882 _getConfigHtml : function()
27886 for ( var o in this.fckconfig ) {
27887 sConfig += sConfig.length > 0 ? '&' : '';
27888 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27891 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27895 _getIFrameHtml : function()
27897 var sFile = 'fckeditor.html' ;
27898 /* no idea what this is about..
27901 if ( (/fcksource=true/i).test( window.top.location.search ) )
27902 sFile = 'fckeditor.original.html' ;
27907 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27908 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27911 var html = '<iframe id="' + this.getId() +
27912 '___Frame" src="' + sLink +
27913 '" width="' + this.width +
27914 '" height="' + this.height + '"' +
27915 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27916 ' frameborder="0" scrolling="no"></iframe>' ;
27921 _insertHtmlBefore : function( html, element )
27923 if ( element.insertAdjacentHTML ) {
27925 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27927 var oRange = document.createRange() ;
27928 oRange.setStartBefore( element ) ;
27929 var oFragment = oRange.createContextualFragment( html );
27930 element.parentNode.insertBefore( oFragment, element ) ;
27943 //Roo.reg('fckeditor', Roo.form.FCKeditor);
27945 function FCKeditor_OnComplete(editorInstance){
27946 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
27947 f.fckEditor = editorInstance;
27948 //console.log("loaded");
27949 f.fireEvent('editorinit', f, editorInstance);
27969 //<script type="text/javascript">
27971 * @class Roo.form.GridField
27972 * @extends Roo.form.Field
27973 * Embed a grid (or editable grid into a form)
27976 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
27978 * xgrid.store = Roo.data.Store
27979 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
27980 * xgrid.store.reader = Roo.data.JsonReader
27984 * Creates a new GridField
27985 * @param {Object} config Configuration options
27987 Roo.form.GridField = function(config){
27988 Roo.form.GridField.superclass.constructor.call(this, config);
27992 Roo.extend(Roo.form.GridField, Roo.form.Field, {
27994 * @cfg {Number} width - used to restrict width of grid..
27998 * @cfg {Number} height - used to restrict height of grid..
28002 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28008 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28009 * {tag: "input", type: "checkbox", autocomplete: "off"})
28011 // defaultAutoCreate : { tag: 'div' },
28012 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28014 * @cfg {String} addTitle Text to include for adding a title.
28018 onResize : function(){
28019 Roo.form.Field.superclass.onResize.apply(this, arguments);
28022 initEvents : function(){
28023 // Roo.form.Checkbox.superclass.initEvents.call(this);
28024 // has no events...
28029 getResizeEl : function(){
28033 getPositionEl : function(){
28038 onRender : function(ct, position){
28040 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28041 var style = this.style;
28044 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28045 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28046 this.viewEl = this.wrap.createChild({ tag: 'div' });
28048 this.viewEl.applyStyles(style);
28051 this.viewEl.setWidth(this.width);
28054 this.viewEl.setHeight(this.height);
28056 //if(this.inputValue !== undefined){
28057 //this.setValue(this.value);
28060 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28063 this.grid.render();
28064 this.grid.getDataSource().on('remove', this.refreshValue, this);
28065 this.grid.getDataSource().on('update', this.refreshValue, this);
28066 this.grid.on('afteredit', this.refreshValue, this);
28072 * Sets the value of the item.
28073 * @param {String} either an object or a string..
28075 setValue : function(v){
28077 v = v || []; // empty set..
28078 // this does not seem smart - it really only affects memoryproxy grids..
28079 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28080 var ds = this.grid.getDataSource();
28081 // assumes a json reader..
28083 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28084 ds.loadData( data);
28086 Roo.form.GridField.superclass.setValue.call(this, v);
28087 this.refreshValue();
28088 // should load data in the grid really....
28092 refreshValue: function() {
28094 this.grid.getDataSource().each(function(r) {
28097 this.el.dom.value = Roo.encode(val);
28105 * Ext JS Library 1.1.1
28106 * Copyright(c) 2006-2007, Ext JS, LLC.
28108 * Originally Released Under LGPL - original licence link has changed is not relivant.
28111 * <script type="text/javascript">
28114 * @class Roo.form.DisplayField
28115 * @extends Roo.form.Field
28116 * A generic Field to display non-editable data.
28118 * Creates a new Display Field item.
28119 * @param {Object} config Configuration options
28121 Roo.form.DisplayField = function(config){
28122 Roo.form.DisplayField.superclass.constructor.call(this, config);
28126 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28127 inputType: 'hidden',
28133 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28135 focusClass : undefined,
28137 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28139 fieldClass: 'x-form-field',
28142 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28144 valueRenderer: undefined,
28148 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28149 * {tag: "input", type: "checkbox", autocomplete: "off"})
28152 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28154 onResize : function(){
28155 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28159 initEvents : function(){
28160 // Roo.form.Checkbox.superclass.initEvents.call(this);
28161 // has no events...
28166 getResizeEl : function(){
28170 getPositionEl : function(){
28175 onRender : function(ct, position){
28177 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28178 //if(this.inputValue !== undefined){
28179 this.wrap = this.el.wrap();
28181 this.viewEl = this.wrap.createChild({ tag: 'div'});
28183 if (this.bodyStyle) {
28184 this.viewEl.applyStyles(this.bodyStyle);
28186 //this.viewEl.setStyle('padding', '2px');
28188 this.setValue(this.value);
28193 initValue : Roo.emptyFn,
28198 onClick : function(){
28203 * Sets the checked state of the checkbox.
28204 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28206 setValue : function(v){
28208 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28209 // this might be called before we have a dom element..
28210 if (!this.viewEl) {
28213 this.viewEl.dom.innerHTML = html;
28214 Roo.form.DisplayField.superclass.setValue.call(this, v);
28217 });//<script type="text/javasscript">
28221 * @class Roo.DDView
28222 * A DnD enabled version of Roo.View.
28223 * @param {Element/String} container The Element in which to create the View.
28224 * @param {String} tpl The template string used to create the markup for each element of the View
28225 * @param {Object} config The configuration properties. These include all the config options of
28226 * {@link Roo.View} plus some specific to this class.<br>
28228 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28229 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28231 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28232 .x-view-drag-insert-above {
28233 border-top:1px dotted #3366cc;
28235 .x-view-drag-insert-below {
28236 border-bottom:1px dotted #3366cc;
28242 Roo.DDView = function(container, tpl, config) {
28243 Roo.DDView.superclass.constructor.apply(this, arguments);
28244 this.getEl().setStyle("outline", "0px none");
28245 this.getEl().unselectable();
28246 if (this.dragGroup) {
28247 this.setDraggable(this.dragGroup.split(","));
28249 if (this.dropGroup) {
28250 this.setDroppable(this.dropGroup.split(","));
28252 if (this.deletable) {
28253 this.setDeletable();
28255 this.isDirtyFlag = false;
28261 Roo.extend(Roo.DDView, Roo.View, {
28262 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28263 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28264 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28265 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28269 reset: Roo.emptyFn,
28271 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28273 validate: function() {
28277 destroy: function() {
28278 this.purgeListeners();
28279 this.getEl.removeAllListeners();
28280 this.getEl().remove();
28281 if (this.dragZone) {
28282 if (this.dragZone.destroy) {
28283 this.dragZone.destroy();
28286 if (this.dropZone) {
28287 if (this.dropZone.destroy) {
28288 this.dropZone.destroy();
28293 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28294 getName: function() {
28298 /** Loads the View from a JSON string representing the Records to put into the Store. */
28299 setValue: function(v) {
28301 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28304 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28305 this.store.proxy = new Roo.data.MemoryProxy(data);
28309 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28310 getValue: function() {
28312 this.store.each(function(rec) {
28313 result += rec.id + ',';
28315 return result.substr(0, result.length - 1) + ')';
28318 getIds: function() {
28319 var i = 0, result = new Array(this.store.getCount());
28320 this.store.each(function(rec) {
28321 result[i++] = rec.id;
28326 isDirty: function() {
28327 return this.isDirtyFlag;
28331 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28332 * whole Element becomes the target, and this causes the drop gesture to append.
28334 getTargetFromEvent : function(e) {
28335 var target = e.getTarget();
28336 while ((target !== null) && (target.parentNode != this.el.dom)) {
28337 target = target.parentNode;
28340 target = this.el.dom.lastChild || this.el.dom;
28346 * Create the drag data which consists of an object which has the property "ddel" as
28347 * the drag proxy element.
28349 getDragData : function(e) {
28350 var target = this.findItemFromChild(e.getTarget());
28352 this.handleSelection(e);
28353 var selNodes = this.getSelectedNodes();
28356 copy: this.copy || (this.allowCopy && e.ctrlKey),
28360 var selectedIndices = this.getSelectedIndexes();
28361 for (var i = 0; i < selectedIndices.length; i++) {
28362 dragData.records.push(this.store.getAt(selectedIndices[i]));
28364 if (selNodes.length == 1) {
28365 dragData.ddel = target.cloneNode(true); // the div element
28367 var div = document.createElement('div'); // create the multi element drag "ghost"
28368 div.className = 'multi-proxy';
28369 for (var i = 0, len = selNodes.length; i < len; i++) {
28370 div.appendChild(selNodes[i].cloneNode(true));
28372 dragData.ddel = div;
28374 //console.log(dragData)
28375 //console.log(dragData.ddel.innerHTML)
28378 //console.log('nodragData')
28382 /** Specify to which ddGroup items in this DDView may be dragged. */
28383 setDraggable: function(ddGroup) {
28384 if (ddGroup instanceof Array) {
28385 Roo.each(ddGroup, this.setDraggable, this);
28388 if (this.dragZone) {
28389 this.dragZone.addToGroup(ddGroup);
28391 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28392 containerScroll: true,
28396 // Draggability implies selection. DragZone's mousedown selects the element.
28397 if (!this.multiSelect) { this.singleSelect = true; }
28399 // Wire the DragZone's handlers up to methods in *this*
28400 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28404 /** Specify from which ddGroup this DDView accepts drops. */
28405 setDroppable: function(ddGroup) {
28406 if (ddGroup instanceof Array) {
28407 Roo.each(ddGroup, this.setDroppable, this);
28410 if (this.dropZone) {
28411 this.dropZone.addToGroup(ddGroup);
28413 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28414 containerScroll: true,
28418 // Wire the DropZone's handlers up to methods in *this*
28419 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28420 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28421 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28422 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28423 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28427 /** Decide whether to drop above or below a View node. */
28428 getDropPoint : function(e, n, dd){
28429 if (n == this.el.dom) { return "above"; }
28430 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28431 var c = t + (b - t) / 2;
28432 var y = Roo.lib.Event.getPageY(e);
28440 onNodeEnter : function(n, dd, e, data){
28444 onNodeOver : function(n, dd, e, data){
28445 var pt = this.getDropPoint(e, n, dd);
28446 // set the insert point style on the target node
28447 var dragElClass = this.dropNotAllowed;
28450 if (pt == "above"){
28451 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28452 targetElClass = "x-view-drag-insert-above";
28454 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28455 targetElClass = "x-view-drag-insert-below";
28457 if (this.lastInsertClass != targetElClass){
28458 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28459 this.lastInsertClass = targetElClass;
28462 return dragElClass;
28465 onNodeOut : function(n, dd, e, data){
28466 this.removeDropIndicators(n);
28469 onNodeDrop : function(n, dd, e, data){
28470 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28473 var pt = this.getDropPoint(e, n, dd);
28474 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28475 if (pt == "below") { insertAt++; }
28476 for (var i = 0; i < data.records.length; i++) {
28477 var r = data.records[i];
28478 var dup = this.store.getById(r.id);
28479 if (dup && (dd != this.dragZone)) {
28480 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28483 this.store.insert(insertAt++, r.copy());
28485 data.source.isDirtyFlag = true;
28487 this.store.insert(insertAt++, r);
28489 this.isDirtyFlag = true;
28492 this.dragZone.cachedTarget = null;
28496 removeDropIndicators : function(n){
28498 Roo.fly(n).removeClass([
28499 "x-view-drag-insert-above",
28500 "x-view-drag-insert-below"]);
28501 this.lastInsertClass = "_noclass";
28506 * Utility method. Add a delete option to the DDView's context menu.
28507 * @param {String} imageUrl The URL of the "delete" icon image.
28509 setDeletable: function(imageUrl) {
28510 if (!this.singleSelect && !this.multiSelect) {
28511 this.singleSelect = true;
28513 var c = this.getContextMenu();
28514 this.contextMenu.on("itemclick", function(item) {
28517 this.remove(this.getSelectedIndexes());
28521 this.contextMenu.add({
28528 /** Return the context menu for this DDView. */
28529 getContextMenu: function() {
28530 if (!this.contextMenu) {
28531 // Create the View's context menu
28532 this.contextMenu = new Roo.menu.Menu({
28533 id: this.id + "-contextmenu"
28535 this.el.on("contextmenu", this.showContextMenu, this);
28537 return this.contextMenu;
28540 disableContextMenu: function() {
28541 if (this.contextMenu) {
28542 this.el.un("contextmenu", this.showContextMenu, this);
28546 showContextMenu: function(e, item) {
28547 item = this.findItemFromChild(e.getTarget());
28550 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28551 this.contextMenu.showAt(e.getXY());
28556 * Remove {@link Roo.data.Record}s at the specified indices.
28557 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28559 remove: function(selectedIndices) {
28560 selectedIndices = [].concat(selectedIndices);
28561 for (var i = 0; i < selectedIndices.length; i++) {
28562 var rec = this.store.getAt(selectedIndices[i]);
28563 this.store.remove(rec);
28568 * Double click fires the event, but also, if this is draggable, and there is only one other
28569 * related DropZone, it transfers the selected node.
28571 onDblClick : function(e){
28572 var item = this.findItemFromChild(e.getTarget());
28574 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28577 if (this.dragGroup) {
28578 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28579 while (targets.indexOf(this.dropZone) > -1) {
28580 targets.remove(this.dropZone);
28582 if (targets.length == 1) {
28583 this.dragZone.cachedTarget = null;
28584 var el = Roo.get(targets[0].getEl());
28585 var box = el.getBox(true);
28586 targets[0].onNodeDrop(el.dom, {
28588 xy: [box.x, box.y + box.height - 1]
28589 }, null, this.getDragData(e));
28595 handleSelection: function(e) {
28596 this.dragZone.cachedTarget = null;
28597 var item = this.findItemFromChild(e.getTarget());
28599 this.clearSelections(true);
28602 if (item && (this.multiSelect || this.singleSelect)){
28603 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28604 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28605 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28606 this.unselect(item);
28608 this.select(item, this.multiSelect && e.ctrlKey);
28609 this.lastSelection = item;
28614 onItemClick : function(item, index, e){
28615 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28621 unselect : function(nodeInfo, suppressEvent){
28622 var node = this.getNode(nodeInfo);
28623 if(node && this.isSelected(node)){
28624 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28625 Roo.fly(node).removeClass(this.selectedClass);
28626 this.selections.remove(node);
28627 if(!suppressEvent){
28628 this.fireEvent("selectionchange", this, this.selections);
28636 * Ext JS Library 1.1.1
28637 * Copyright(c) 2006-2007, Ext JS, LLC.
28639 * Originally Released Under LGPL - original licence link has changed is not relivant.
28642 * <script type="text/javascript">
28646 * @class Roo.LayoutManager
28647 * @extends Roo.util.Observable
28648 * Base class for layout managers.
28650 Roo.LayoutManager = function(container, config){
28651 Roo.LayoutManager.superclass.constructor.call(this);
28652 this.el = Roo.get(container);
28653 // ie scrollbar fix
28654 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28655 document.body.scroll = "no";
28656 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28657 this.el.position('relative');
28659 this.id = this.el.id;
28660 this.el.addClass("x-layout-container");
28661 /** false to disable window resize monitoring @type Boolean */
28662 this.monitorWindowResize = true;
28667 * Fires when a layout is performed.
28668 * @param {Roo.LayoutManager} this
28672 * @event regionresized
28673 * Fires when the user resizes a region.
28674 * @param {Roo.LayoutRegion} region The resized region
28675 * @param {Number} newSize The new size (width for east/west, height for north/south)
28677 "regionresized" : true,
28679 * @event regioncollapsed
28680 * Fires when a region is collapsed.
28681 * @param {Roo.LayoutRegion} region The collapsed region
28683 "regioncollapsed" : true,
28685 * @event regionexpanded
28686 * Fires when a region is expanded.
28687 * @param {Roo.LayoutRegion} region The expanded region
28689 "regionexpanded" : true
28691 this.updating = false;
28692 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28695 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28697 * Returns true if this layout is currently being updated
28698 * @return {Boolean}
28700 isUpdating : function(){
28701 return this.updating;
28705 * Suspend the LayoutManager from doing auto-layouts while
28706 * making multiple add or remove calls
28708 beginUpdate : function(){
28709 this.updating = true;
28713 * Restore auto-layouts and optionally disable the manager from performing a layout
28714 * @param {Boolean} noLayout true to disable a layout update
28716 endUpdate : function(noLayout){
28717 this.updating = false;
28723 layout: function(){
28727 onRegionResized : function(region, newSize){
28728 this.fireEvent("regionresized", region, newSize);
28732 onRegionCollapsed : function(region){
28733 this.fireEvent("regioncollapsed", region);
28736 onRegionExpanded : function(region){
28737 this.fireEvent("regionexpanded", region);
28741 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28742 * performs box-model adjustments.
28743 * @return {Object} The size as an object {width: (the width), height: (the height)}
28745 getViewSize : function(){
28747 if(this.el.dom != document.body){
28748 size = this.el.getSize();
28750 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28752 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28753 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28758 * Returns the Element this layout is bound to.
28759 * @return {Roo.Element}
28761 getEl : function(){
28766 * Returns the specified region.
28767 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
28768 * @return {Roo.LayoutRegion}
28770 getRegion : function(target){
28771 return this.regions[target.toLowerCase()];
28774 onWindowResize : function(){
28775 if(this.monitorWindowResize){
28781 * Ext JS Library 1.1.1
28782 * Copyright(c) 2006-2007, Ext JS, LLC.
28784 * Originally Released Under LGPL - original licence link has changed is not relivant.
28787 * <script type="text/javascript">
28790 * @class Roo.BorderLayout
28791 * @extends Roo.LayoutManager
28792 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
28793 * please see: <br><br>
28794 * <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>
28795 * <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>
28798 var layout = new Roo.BorderLayout(document.body, {
28832 preferredTabWidth: 150
28837 var CP = Roo.ContentPanel;
28839 layout.beginUpdate();
28840 layout.add("north", new CP("north", "North"));
28841 layout.add("south", new CP("south", {title: "South", closable: true}));
28842 layout.add("west", new CP("west", {title: "West"}));
28843 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
28844 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
28845 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
28846 layout.getRegion("center").showPanel("center1");
28847 layout.endUpdate();
28850 <b>The container the layout is rendered into can be either the body element or any other element.
28851 If it is not the body element, the container needs to either be an absolute positioned element,
28852 or you will need to add "position:relative" to the css of the container. You will also need to specify
28853 the container size if it is not the body element.</b>
28856 * Create a new BorderLayout
28857 * @param {String/HTMLElement/Element} container The container this layout is bound to
28858 * @param {Object} config Configuration options
28860 Roo.BorderLayout = function(container, config){
28861 config = config || {};
28862 Roo.BorderLayout.superclass.constructor.call(this, container, config);
28863 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
28864 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
28865 var target = this.factory.validRegions[i];
28866 if(config[target]){
28867 this.addRegion(target, config[target]);
28872 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
28874 * Creates and adds a new region if it doesn't already exist.
28875 * @param {String} target The target region key (north, south, east, west or center).
28876 * @param {Object} config The regions config object
28877 * @return {BorderLayoutRegion} The new region
28879 addRegion : function(target, config){
28880 if(!this.regions[target]){
28881 var r = this.factory.create(target, this, config);
28882 this.bindRegion(target, r);
28884 return this.regions[target];
28888 bindRegion : function(name, r){
28889 this.regions[name] = r;
28890 r.on("visibilitychange", this.layout, this);
28891 r.on("paneladded", this.layout, this);
28892 r.on("panelremoved", this.layout, this);
28893 r.on("invalidated", this.layout, this);
28894 r.on("resized", this.onRegionResized, this);
28895 r.on("collapsed", this.onRegionCollapsed, this);
28896 r.on("expanded", this.onRegionExpanded, this);
28900 * Performs a layout update.
28902 layout : function(){
28903 if(this.updating) return;
28904 var size = this.getViewSize();
28905 var w = size.width;
28906 var h = size.height;
28911 //var x = 0, y = 0;
28913 var rs = this.regions;
28914 var north = rs["north"];
28915 var south = rs["south"];
28916 var west = rs["west"];
28917 var east = rs["east"];
28918 var center = rs["center"];
28919 //if(this.hideOnLayout){ // not supported anymore
28920 //c.el.setStyle("display", "none");
28922 if(north && north.isVisible()){
28923 var b = north.getBox();
28924 var m = north.getMargins();
28925 b.width = w - (m.left+m.right);
28928 centerY = b.height + b.y + m.bottom;
28929 centerH -= centerY;
28930 north.updateBox(this.safeBox(b));
28932 if(south && south.isVisible()){
28933 var b = south.getBox();
28934 var m = south.getMargins();
28935 b.width = w - (m.left+m.right);
28937 var totalHeight = (b.height + m.top + m.bottom);
28938 b.y = h - totalHeight + m.top;
28939 centerH -= totalHeight;
28940 south.updateBox(this.safeBox(b));
28942 if(west && west.isVisible()){
28943 var b = west.getBox();
28944 var m = west.getMargins();
28945 b.height = centerH - (m.top+m.bottom);
28947 b.y = centerY + m.top;
28948 var totalWidth = (b.width + m.left + m.right);
28949 centerX += totalWidth;
28950 centerW -= totalWidth;
28951 west.updateBox(this.safeBox(b));
28953 if(east && east.isVisible()){
28954 var b = east.getBox();
28955 var m = east.getMargins();
28956 b.height = centerH - (m.top+m.bottom);
28957 var totalWidth = (b.width + m.left + m.right);
28958 b.x = w - totalWidth + m.left;
28959 b.y = centerY + m.top;
28960 centerW -= totalWidth;
28961 east.updateBox(this.safeBox(b));
28964 var m = center.getMargins();
28966 x: centerX + m.left,
28967 y: centerY + m.top,
28968 width: centerW - (m.left+m.right),
28969 height: centerH - (m.top+m.bottom)
28971 //if(this.hideOnLayout){
28972 //center.el.setStyle("display", "block");
28974 center.updateBox(this.safeBox(centerBox));
28977 this.fireEvent("layout", this);
28981 safeBox : function(box){
28982 box.width = Math.max(0, box.width);
28983 box.height = Math.max(0, box.height);
28988 * Adds a ContentPanel (or subclass) to this layout.
28989 * @param {String} target The target region key (north, south, east, west or center).
28990 * @param {Roo.ContentPanel} panel The panel to add
28991 * @return {Roo.ContentPanel} The added panel
28993 add : function(target, panel){
28995 target = target.toLowerCase();
28996 return this.regions[target].add(panel);
29000 * Remove a ContentPanel (or subclass) to this layout.
29001 * @param {String} target The target region key (north, south, east, west or center).
29002 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29003 * @return {Roo.ContentPanel} The removed panel
29005 remove : function(target, panel){
29006 target = target.toLowerCase();
29007 return this.regions[target].remove(panel);
29011 * Searches all regions for a panel with the specified id
29012 * @param {String} panelId
29013 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29015 findPanel : function(panelId){
29016 var rs = this.regions;
29017 for(var target in rs){
29018 if(typeof rs[target] != "function"){
29019 var p = rs[target].getPanel(panelId);
29029 * Searches all regions for a panel with the specified id and activates (shows) it.
29030 * @param {String/ContentPanel} panelId The panels id or the panel itself
29031 * @return {Roo.ContentPanel} The shown panel or null
29033 showPanel : function(panelId) {
29034 var rs = this.regions;
29035 for(var target in rs){
29036 var r = rs[target];
29037 if(typeof r != "function"){
29038 if(r.hasPanel(panelId)){
29039 return r.showPanel(panelId);
29047 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29048 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29050 restoreState : function(provider){
29052 provider = Roo.state.Manager;
29054 var sm = new Roo.LayoutStateManager();
29055 sm.init(this, provider);
29059 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29060 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29061 * a valid ContentPanel config object. Example:
29063 // Create the main layout
29064 var layout = new Roo.BorderLayout('main-ct', {
29075 // Create and add multiple ContentPanels at once via configs
29078 id: 'source-files',
29080 title:'Ext Source Files',
29093 * @param {Object} regions An object containing ContentPanel configs by region name
29095 batchAdd : function(regions){
29096 this.beginUpdate();
29097 for(var rname in regions){
29098 var lr = this.regions[rname];
29100 this.addTypedPanels(lr, regions[rname]);
29107 addTypedPanels : function(lr, ps){
29108 if(typeof ps == 'string'){
29109 lr.add(new Roo.ContentPanel(ps));
29111 else if(ps instanceof Array){
29112 for(var i =0, len = ps.length; i < len; i++){
29113 this.addTypedPanels(lr, ps[i]);
29116 else if(!ps.events){ // raw config?
29118 delete ps.el; // prevent conflict
29119 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29121 else { // panel object assumed!
29126 * Adds a xtype elements to the layout.
29130 xtype : 'ContentPanel',
29137 xtype : 'NestedLayoutPanel',
29143 items : [ ... list of content panels or nested layout panels.. ]
29147 * @param {Object} cfg Xtype definition of item to add.
29149 addxtype : function(cfg)
29151 // basically accepts a pannel...
29152 // can accept a layout region..!?!?
29153 // console.log('BorderLayout add ' + cfg.xtype)
29155 if (!cfg.xtype.match(/Panel$/)) {
29159 var region = cfg.region;
29165 xitems = cfg.items;
29172 case 'ContentPanel': // ContentPanel (el, cfg)
29173 case 'ScrollPanel': // ContentPanel (el, cfg)
29174 if(cfg.autoCreate) {
29175 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29177 var el = this.el.createChild();
29178 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29181 this.add(region, ret);
29185 case 'TreePanel': // our new panel!
29186 cfg.el = this.el.createChild();
29187 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29188 this.add(region, ret);
29191 case 'NestedLayoutPanel':
29192 // create a new Layout (which is a Border Layout...
29193 var el = this.el.createChild();
29194 var clayout = cfg.layout;
29196 clayout.items = clayout.items || [];
29197 // replace this exitems with the clayout ones..
29198 xitems = clayout.items;
29201 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29202 cfg.background = false;
29204 var layout = new Roo.BorderLayout(el, clayout);
29206 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29207 //console.log('adding nested layout panel ' + cfg.toSource());
29208 this.add(region, ret);
29214 // needs grid and region
29216 //var el = this.getRegion(region).el.createChild();
29217 var el = this.el.createChild();
29218 // create the grid first...
29220 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29222 if (region == 'center' && this.active ) {
29223 cfg.background = false;
29225 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29227 this.add(region, ret);
29228 if (cfg.background) {
29229 ret.on('activate', function(gp) {
29230 if (!gp.grid.rendered) {
29243 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29245 // GridPanel (grid, cfg)
29248 this.beginUpdate();
29250 Roo.each(xitems, function(i) {
29260 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29261 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29262 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29263 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29266 var CP = Roo.ContentPanel;
29268 var layout = Roo.BorderLayout.create({
29272 panels: [new CP("north", "North")]
29281 panels: [new CP("west", {title: "West"})]
29290 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29299 panels: [new CP("south", {title: "South", closable: true})]
29306 preferredTabWidth: 150,
29308 new CP("center1", {title: "Close Me", closable: true}),
29309 new CP("center2", {title: "Center Panel", closable: false})
29314 layout.getRegion("center").showPanel("center1");
29319 Roo.BorderLayout.create = function(config, targetEl){
29320 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29321 layout.beginUpdate();
29322 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29323 for(var j = 0, jlen = regions.length; j < jlen; j++){
29324 var lr = regions[j];
29325 if(layout.regions[lr] && config[lr].panels){
29326 var r = layout.regions[lr];
29327 var ps = config[lr].panels;
29328 layout.addTypedPanels(r, ps);
29331 layout.endUpdate();
29336 Roo.BorderLayout.RegionFactory = {
29338 validRegions : ["north","south","east","west","center"],
29341 create : function(target, mgr, config){
29342 target = target.toLowerCase();
29343 if(config.lightweight || config.basic){
29344 return new Roo.BasicLayoutRegion(mgr, config, target);
29348 return new Roo.NorthLayoutRegion(mgr, config);
29350 return new Roo.SouthLayoutRegion(mgr, config);
29352 return new Roo.EastLayoutRegion(mgr, config);
29354 return new Roo.WestLayoutRegion(mgr, config);
29356 return new Roo.CenterLayoutRegion(mgr, config);
29358 throw 'Layout region "'+target+'" not supported.';
29362 * Ext JS Library 1.1.1
29363 * Copyright(c) 2006-2007, Ext JS, LLC.
29365 * Originally Released Under LGPL - original licence link has changed is not relivant.
29368 * <script type="text/javascript">
29372 * @class Roo.BasicLayoutRegion
29373 * @extends Roo.util.Observable
29374 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29375 * and does not have a titlebar, tabs or any other features. All it does is size and position
29376 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29378 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29380 this.position = pos;
29383 * @scope Roo.BasicLayoutRegion
29387 * @event beforeremove
29388 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29389 * @param {Roo.LayoutRegion} this
29390 * @param {Roo.ContentPanel} panel The panel
29391 * @param {Object} e The cancel event object
29393 "beforeremove" : true,
29395 * @event invalidated
29396 * Fires when the layout for this region is changed.
29397 * @param {Roo.LayoutRegion} this
29399 "invalidated" : true,
29401 * @event visibilitychange
29402 * Fires when this region is shown or hidden
29403 * @param {Roo.LayoutRegion} this
29404 * @param {Boolean} visibility true or false
29406 "visibilitychange" : true,
29408 * @event paneladded
29409 * Fires when a panel is added.
29410 * @param {Roo.LayoutRegion} this
29411 * @param {Roo.ContentPanel} panel The panel
29413 "paneladded" : true,
29415 * @event panelremoved
29416 * Fires when a panel is removed.
29417 * @param {Roo.LayoutRegion} this
29418 * @param {Roo.ContentPanel} panel The panel
29420 "panelremoved" : true,
29423 * Fires when this region is collapsed.
29424 * @param {Roo.LayoutRegion} this
29426 "collapsed" : true,
29429 * Fires when this region is expanded.
29430 * @param {Roo.LayoutRegion} this
29435 * Fires when this region is slid into view.
29436 * @param {Roo.LayoutRegion} this
29438 "slideshow" : true,
29441 * Fires when this region slides out of view.
29442 * @param {Roo.LayoutRegion} this
29444 "slidehide" : true,
29446 * @event panelactivated
29447 * Fires when a panel is activated.
29448 * @param {Roo.LayoutRegion} this
29449 * @param {Roo.ContentPanel} panel The activated panel
29451 "panelactivated" : true,
29454 * Fires when the user resizes this region.
29455 * @param {Roo.LayoutRegion} this
29456 * @param {Number} newSize The new size (width for east/west, height for north/south)
29460 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29461 this.panels = new Roo.util.MixedCollection();
29462 this.panels.getKey = this.getPanelId.createDelegate(this);
29464 this.activePanel = null;
29465 // ensure listeners are added...
29467 if (config.listeners || config.events) {
29468 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29469 listeners : config.listeners || {},
29470 events : config.events || {}
29474 if(skipConfig !== true){
29475 this.applyConfig(config);
29479 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29480 getPanelId : function(p){
29484 applyConfig : function(config){
29485 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29486 this.config = config;
29491 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29492 * the width, for horizontal (north, south) the height.
29493 * @param {Number} newSize The new width or height
29495 resizeTo : function(newSize){
29496 var el = this.el ? this.el :
29497 (this.activePanel ? this.activePanel.getEl() : null);
29499 switch(this.position){
29502 el.setWidth(newSize);
29503 this.fireEvent("resized", this, newSize);
29507 el.setHeight(newSize);
29508 this.fireEvent("resized", this, newSize);
29514 getBox : function(){
29515 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29518 getMargins : function(){
29519 return this.margins;
29522 updateBox : function(box){
29524 var el = this.activePanel.getEl();
29525 el.dom.style.left = box.x + "px";
29526 el.dom.style.top = box.y + "px";
29527 this.activePanel.setSize(box.width, box.height);
29531 * Returns the container element for this region.
29532 * @return {Roo.Element}
29534 getEl : function(){
29535 return this.activePanel;
29539 * Returns true if this region is currently visible.
29540 * @return {Boolean}
29542 isVisible : function(){
29543 return this.activePanel ? true : false;
29546 setActivePanel : function(panel){
29547 panel = this.getPanel(panel);
29548 if(this.activePanel && this.activePanel != panel){
29549 this.activePanel.setActiveState(false);
29550 this.activePanel.getEl().setLeftTop(-10000,-10000);
29552 this.activePanel = panel;
29553 panel.setActiveState(true);
29555 panel.setSize(this.box.width, this.box.height);
29557 this.fireEvent("panelactivated", this, panel);
29558 this.fireEvent("invalidated");
29562 * Show the specified panel.
29563 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29564 * @return {Roo.ContentPanel} The shown panel or null
29566 showPanel : function(panel){
29567 if(panel = this.getPanel(panel)){
29568 this.setActivePanel(panel);
29574 * Get the active panel for this region.
29575 * @return {Roo.ContentPanel} The active panel or null
29577 getActivePanel : function(){
29578 return this.activePanel;
29582 * Add the passed ContentPanel(s)
29583 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29584 * @return {Roo.ContentPanel} The panel added (if only one was added)
29586 add : function(panel){
29587 if(arguments.length > 1){
29588 for(var i = 0, len = arguments.length; i < len; i++) {
29589 this.add(arguments[i]);
29593 if(this.hasPanel(panel)){
29594 this.showPanel(panel);
29597 var el = panel.getEl();
29598 if(el.dom.parentNode != this.mgr.el.dom){
29599 this.mgr.el.dom.appendChild(el.dom);
29601 if(panel.setRegion){
29602 panel.setRegion(this);
29604 this.panels.add(panel);
29605 el.setStyle("position", "absolute");
29606 if(!panel.background){
29607 this.setActivePanel(panel);
29608 if(this.config.initialSize && this.panels.getCount()==1){
29609 this.resizeTo(this.config.initialSize);
29612 this.fireEvent("paneladded", this, panel);
29617 * Returns true if the panel is in this region.
29618 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29619 * @return {Boolean}
29621 hasPanel : function(panel){
29622 if(typeof panel == "object"){ // must be panel obj
29623 panel = panel.getId();
29625 return this.getPanel(panel) ? true : false;
29629 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29630 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29631 * @param {Boolean} preservePanel Overrides the config preservePanel option
29632 * @return {Roo.ContentPanel} The panel that was removed
29634 remove : function(panel, preservePanel){
29635 panel = this.getPanel(panel);
29640 this.fireEvent("beforeremove", this, panel, e);
29641 if(e.cancel === true){
29644 var panelId = panel.getId();
29645 this.panels.removeKey(panelId);
29650 * Returns the panel specified or null if it's not in this region.
29651 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29652 * @return {Roo.ContentPanel}
29654 getPanel : function(id){
29655 if(typeof id == "object"){ // must be panel obj
29658 return this.panels.get(id);
29662 * Returns this regions position (north/south/east/west/center).
29665 getPosition: function(){
29666 return this.position;
29670 * Ext JS Library 1.1.1
29671 * Copyright(c) 2006-2007, Ext JS, LLC.
29673 * Originally Released Under LGPL - original licence link has changed is not relivant.
29676 * <script type="text/javascript">
29680 * @class Roo.LayoutRegion
29681 * @extends Roo.BasicLayoutRegion
29682 * This class represents a region in a layout manager.
29683 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29684 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29685 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29686 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29687 * @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})
29688 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29689 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29690 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29691 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29692 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29693 * @cfg {String} title The title for the region (overrides panel titles)
29694 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29695 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29696 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29697 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29698 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29699 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29700 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29701 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29702 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29703 * @cfg {Boolean} showPin True to show a pin button
29704 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29705 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29706 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29707 * @cfg {Number} width For East/West panels
29708 * @cfg {Number} height For North/South panels
29709 * @cfg {Boolean} split To show the splitter
29711 Roo.LayoutRegion = function(mgr, config, pos){
29712 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29713 var dh = Roo.DomHelper;
29714 /** This region's container element
29715 * @type Roo.Element */
29716 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29717 /** This region's title element
29718 * @type Roo.Element */
29720 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29721 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29722 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29724 this.titleEl.enableDisplayMode();
29725 /** This region's title text element
29726 * @type HTMLElement */
29727 this.titleTextEl = this.titleEl.dom.firstChild;
29728 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29729 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29730 this.closeBtn.enableDisplayMode();
29731 this.closeBtn.on("click", this.closeClicked, this);
29732 this.closeBtn.hide();
29734 this.createBody(config);
29735 this.visible = true;
29736 this.collapsed = false;
29738 if(config.hideWhenEmpty){
29740 this.on("paneladded", this.validateVisibility, this);
29741 this.on("panelremoved", this.validateVisibility, this);
29743 this.applyConfig(config);
29746 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29748 createBody : function(){
29749 /** This region's body element
29750 * @type Roo.Element */
29751 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29754 applyConfig : function(c){
29755 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29756 var dh = Roo.DomHelper;
29757 if(c.titlebar !== false){
29758 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
29759 this.collapseBtn.on("click", this.collapse, this);
29760 this.collapseBtn.enableDisplayMode();
29762 if(c.showPin === true || this.showPin){
29763 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
29764 this.stickBtn.enableDisplayMode();
29765 this.stickBtn.on("click", this.expand, this);
29766 this.stickBtn.hide();
29769 /** This region's collapsed element
29770 * @type Roo.Element */
29771 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
29772 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
29774 if(c.floatable !== false){
29775 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
29776 this.collapsedEl.on("click", this.collapseClick, this);
29779 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
29780 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
29781 id: "message", unselectable: "on", style:{"float":"left"}});
29782 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
29784 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
29785 this.expandBtn.on("click", this.expand, this);
29787 if(this.collapseBtn){
29788 this.collapseBtn.setVisible(c.collapsible == true);
29790 this.cmargins = c.cmargins || this.cmargins ||
29791 (this.position == "west" || this.position == "east" ?
29792 {top: 0, left: 2, right:2, bottom: 0} :
29793 {top: 2, left: 0, right:0, bottom: 2});
29794 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29795 this.bottomTabs = c.tabPosition != "top";
29796 this.autoScroll = c.autoScroll || false;
29797 if(this.autoScroll){
29798 this.bodyEl.setStyle("overflow", "auto");
29800 this.bodyEl.setStyle("overflow", "hidden");
29802 //if(c.titlebar !== false){
29803 if((!c.titlebar && !c.title) || c.titlebar === false){
29804 this.titleEl.hide();
29806 this.titleEl.show();
29808 this.titleTextEl.innerHTML = c.title;
29812 this.duration = c.duration || .30;
29813 this.slideDuration = c.slideDuration || .45;
29816 this.collapse(true);
29823 * Returns true if this region is currently visible.
29824 * @return {Boolean}
29826 isVisible : function(){
29827 return this.visible;
29831 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
29832 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
29834 setCollapsedTitle : function(title){
29835 title = title || " ";
29836 if(this.collapsedTitleTextEl){
29837 this.collapsedTitleTextEl.innerHTML = title;
29841 getBox : function(){
29843 if(!this.collapsed){
29844 b = this.el.getBox(false, true);
29846 b = this.collapsedEl.getBox(false, true);
29851 getMargins : function(){
29852 return this.collapsed ? this.cmargins : this.margins;
29855 highlight : function(){
29856 this.el.addClass("x-layout-panel-dragover");
29859 unhighlight : function(){
29860 this.el.removeClass("x-layout-panel-dragover");
29863 updateBox : function(box){
29865 if(!this.collapsed){
29866 this.el.dom.style.left = box.x + "px";
29867 this.el.dom.style.top = box.y + "px";
29868 this.updateBody(box.width, box.height);
29870 this.collapsedEl.dom.style.left = box.x + "px";
29871 this.collapsedEl.dom.style.top = box.y + "px";
29872 this.collapsedEl.setSize(box.width, box.height);
29875 this.tabs.autoSizeTabs();
29879 updateBody : function(w, h){
29881 this.el.setWidth(w);
29882 w -= this.el.getBorderWidth("rl");
29883 if(this.config.adjustments){
29884 w += this.config.adjustments[0];
29888 this.el.setHeight(h);
29889 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
29890 h -= this.el.getBorderWidth("tb");
29891 if(this.config.adjustments){
29892 h += this.config.adjustments[1];
29894 this.bodyEl.setHeight(h);
29896 h = this.tabs.syncHeight(h);
29899 if(this.panelSize){
29900 w = w !== null ? w : this.panelSize.width;
29901 h = h !== null ? h : this.panelSize.height;
29903 if(this.activePanel){
29904 var el = this.activePanel.getEl();
29905 w = w !== null ? w : el.getWidth();
29906 h = h !== null ? h : el.getHeight();
29907 this.panelSize = {width: w, height: h};
29908 this.activePanel.setSize(w, h);
29910 if(Roo.isIE && this.tabs){
29911 this.tabs.el.repaint();
29916 * Returns the container element for this region.
29917 * @return {Roo.Element}
29919 getEl : function(){
29924 * Hides this region.
29927 if(!this.collapsed){
29928 this.el.dom.style.left = "-2000px";
29931 this.collapsedEl.dom.style.left = "-2000px";
29932 this.collapsedEl.hide();
29934 this.visible = false;
29935 this.fireEvent("visibilitychange", this, false);
29939 * Shows this region if it was previously hidden.
29942 if(!this.collapsed){
29945 this.collapsedEl.show();
29947 this.visible = true;
29948 this.fireEvent("visibilitychange", this, true);
29951 closeClicked : function(){
29952 if(this.activePanel){
29953 this.remove(this.activePanel);
29957 collapseClick : function(e){
29959 e.stopPropagation();
29962 e.stopPropagation();
29968 * Collapses this region.
29969 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
29971 collapse : function(skipAnim){
29972 if(this.collapsed) return;
29973 this.collapsed = true;
29975 this.split.el.hide();
29977 if(this.config.animate && skipAnim !== true){
29978 this.fireEvent("invalidated", this);
29979 this.animateCollapse();
29981 this.el.setLocation(-20000,-20000);
29983 this.collapsedEl.show();
29984 this.fireEvent("collapsed", this);
29985 this.fireEvent("invalidated", this);
29989 animateCollapse : function(){
29994 * Expands this region if it was previously collapsed.
29995 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
29996 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
29998 expand : function(e, skipAnim){
29999 if(e) e.stopPropagation();
30000 if(!this.collapsed || this.el.hasActiveFx()) return;
30002 this.afterSlideIn();
30005 this.collapsed = false;
30006 if(this.config.animate && skipAnim !== true){
30007 this.animateExpand();
30011 this.split.el.show();
30013 this.collapsedEl.setLocation(-2000,-2000);
30014 this.collapsedEl.hide();
30015 this.fireEvent("invalidated", this);
30016 this.fireEvent("expanded", this);
30020 animateExpand : function(){
30024 initTabs : function(){
30025 this.bodyEl.setStyle("overflow", "hidden");
30026 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30027 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30028 disableTooltips: this.config.disableTabTips
30030 if(this.config.hideTabs){
30031 ts.stripWrap.setDisplayed(false);
30034 ts.resizeTabs = this.config.resizeTabs === true;
30035 ts.minTabWidth = this.config.minTabWidth || 40;
30036 ts.maxTabWidth = this.config.maxTabWidth || 250;
30037 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30038 ts.monitorResize = false;
30039 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30040 ts.bodyEl.addClass('x-layout-tabs-body');
30041 this.panels.each(this.initPanelAsTab, this);
30044 initPanelAsTab : function(panel){
30045 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30046 this.config.closeOnTab && panel.isClosable());
30047 if(panel.tabTip !== undefined){
30048 ti.setTooltip(panel.tabTip);
30050 ti.on("activate", function(){
30051 this.setActivePanel(panel);
30053 if(this.config.closeOnTab){
30054 ti.on("beforeclose", function(t, e){
30056 this.remove(panel);
30062 updatePanelTitle : function(panel, title){
30063 if(this.activePanel == panel){
30064 this.updateTitle(title);
30067 var ti = this.tabs.getTab(panel.getEl().id);
30069 if(panel.tabTip !== undefined){
30070 ti.setTooltip(panel.tabTip);
30075 updateTitle : function(title){
30076 if(this.titleTextEl && !this.config.title){
30077 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30081 setActivePanel : function(panel){
30082 panel = this.getPanel(panel);
30083 if(this.activePanel && this.activePanel != panel){
30084 this.activePanel.setActiveState(false);
30086 this.activePanel = panel;
30087 panel.setActiveState(true);
30088 if(this.panelSize){
30089 panel.setSize(this.panelSize.width, this.panelSize.height);
30092 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30094 this.updateTitle(panel.getTitle());
30096 this.fireEvent("invalidated", this);
30098 this.fireEvent("panelactivated", this, panel);
30102 * Shows the specified panel.
30103 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30104 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30106 showPanel : function(panel){
30107 if(panel = this.getPanel(panel)){
30109 var tab = this.tabs.getTab(panel.getEl().id);
30110 if(tab.isHidden()){
30111 this.tabs.unhideTab(tab.id);
30115 this.setActivePanel(panel);
30122 * Get the active panel for this region.
30123 * @return {Roo.ContentPanel} The active panel or null
30125 getActivePanel : function(){
30126 return this.activePanel;
30129 validateVisibility : function(){
30130 if(this.panels.getCount() < 1){
30131 this.updateTitle(" ");
30132 this.closeBtn.hide();
30135 if(!this.isVisible()){
30142 * Adds the passed ContentPanel(s) to this region.
30143 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30144 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30146 add : function(panel){
30147 if(arguments.length > 1){
30148 for(var i = 0, len = arguments.length; i < len; i++) {
30149 this.add(arguments[i]);
30153 if(this.hasPanel(panel)){
30154 this.showPanel(panel);
30157 panel.setRegion(this);
30158 this.panels.add(panel);
30159 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30160 this.bodyEl.dom.appendChild(panel.getEl().dom);
30161 if(panel.background !== true){
30162 this.setActivePanel(panel);
30164 this.fireEvent("paneladded", this, panel);
30170 this.initPanelAsTab(panel);
30172 if(panel.background !== true){
30173 this.tabs.activate(panel.getEl().id);
30175 this.fireEvent("paneladded", this, panel);
30180 * Hides the tab for the specified panel.
30181 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30183 hidePanel : function(panel){
30184 if(this.tabs && (panel = this.getPanel(panel))){
30185 this.tabs.hideTab(panel.getEl().id);
30190 * Unhides the tab for a previously hidden panel.
30191 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30193 unhidePanel : function(panel){
30194 if(this.tabs && (panel = this.getPanel(panel))){
30195 this.tabs.unhideTab(panel.getEl().id);
30199 clearPanels : function(){
30200 while(this.panels.getCount() > 0){
30201 this.remove(this.panels.first());
30206 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30207 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30208 * @param {Boolean} preservePanel Overrides the config preservePanel option
30209 * @return {Roo.ContentPanel} The panel that was removed
30211 remove : function(panel, preservePanel){
30212 panel = this.getPanel(panel);
30217 this.fireEvent("beforeremove", this, panel, e);
30218 if(e.cancel === true){
30221 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30222 var panelId = panel.getId();
30223 this.panels.removeKey(panelId);
30225 document.body.appendChild(panel.getEl().dom);
30228 this.tabs.removeTab(panel.getEl().id);
30229 }else if (!preservePanel){
30230 this.bodyEl.dom.removeChild(panel.getEl().dom);
30232 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30233 var p = this.panels.first();
30234 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30235 tempEl.appendChild(p.getEl().dom);
30236 this.bodyEl.update("");
30237 this.bodyEl.dom.appendChild(p.getEl().dom);
30239 this.updateTitle(p.getTitle());
30241 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30242 this.setActivePanel(p);
30244 panel.setRegion(null);
30245 if(this.activePanel == panel){
30246 this.activePanel = null;
30248 if(this.config.autoDestroy !== false && preservePanel !== true){
30249 try{panel.destroy();}catch(e){}
30251 this.fireEvent("panelremoved", this, panel);
30256 * Returns the TabPanel component used by this region
30257 * @return {Roo.TabPanel}
30259 getTabs : function(){
30263 createTool : function(parentEl, className){
30264 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30265 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30266 btn.addClassOnOver("x-layout-tools-button-over");
30271 * Ext JS Library 1.1.1
30272 * Copyright(c) 2006-2007, Ext JS, LLC.
30274 * Originally Released Under LGPL - original licence link has changed is not relivant.
30277 * <script type="text/javascript">
30283 * @class Roo.SplitLayoutRegion
30284 * @extends Roo.LayoutRegion
30285 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
30287 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
30288 this.cursor = cursor;
30289 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
30292 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
30293 splitTip : "Drag to resize.",
30294 collapsibleSplitTip : "Drag to resize. Double click to hide.",
30295 useSplitTips : false,
30297 applyConfig : function(config){
30298 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
30301 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
30302 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
30303 /** The SplitBar for this region
30304 * @type Roo.SplitBar */
30305 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
30306 this.split.on("moved", this.onSplitMove, this);
30307 this.split.useShim = config.useShim === true;
30308 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
30309 if(this.useSplitTips){
30310 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
30312 if(config.collapsible){
30313 this.split.el.on("dblclick", this.collapse, this);
30316 if(typeof config.minSize != "undefined"){
30317 this.split.minSize = config.minSize;
30319 if(typeof config.maxSize != "undefined"){
30320 this.split.maxSize = config.maxSize;
30322 if(config.hideWhenEmpty || config.hidden || config.collapsed){
30323 this.hideSplitter();
30328 getHMaxSize : function(){
30329 var cmax = this.config.maxSize || 10000;
30330 var center = this.mgr.getRegion("center");
30331 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
30334 getVMaxSize : function(){
30335 var cmax = this.config.maxSize || 10000;
30336 var center = this.mgr.getRegion("center");
30337 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
30340 onSplitMove : function(split, newSize){
30341 this.fireEvent("resized", this, newSize);
30345 * Returns the {@link Roo.SplitBar} for this region.
30346 * @return {Roo.SplitBar}
30348 getSplitBar : function(){
30353 this.hideSplitter();
30354 Roo.SplitLayoutRegion.superclass.hide.call(this);
30357 hideSplitter : function(){
30359 this.split.el.setLocation(-2000,-2000);
30360 this.split.el.hide();
30366 this.split.el.show();
30368 Roo.SplitLayoutRegion.superclass.show.call(this);
30371 beforeSlide: function(){
30372 if(Roo.isGecko){// firefox overflow auto bug workaround
30373 this.bodyEl.clip();
30374 if(this.tabs) this.tabs.bodyEl.clip();
30375 if(this.activePanel){
30376 this.activePanel.getEl().clip();
30378 if(this.activePanel.beforeSlide){
30379 this.activePanel.beforeSlide();
30385 afterSlide : function(){
30386 if(Roo.isGecko){// firefox overflow auto bug workaround
30387 this.bodyEl.unclip();
30388 if(this.tabs) this.tabs.bodyEl.unclip();
30389 if(this.activePanel){
30390 this.activePanel.getEl().unclip();
30391 if(this.activePanel.afterSlide){
30392 this.activePanel.afterSlide();
30398 initAutoHide : function(){
30399 if(this.autoHide !== false){
30400 if(!this.autoHideHd){
30401 var st = new Roo.util.DelayedTask(this.slideIn, this);
30402 this.autoHideHd = {
30403 "mouseout": function(e){
30404 if(!e.within(this.el, true)){
30408 "mouseover" : function(e){
30414 this.el.on(this.autoHideHd);
30418 clearAutoHide : function(){
30419 if(this.autoHide !== false){
30420 this.el.un("mouseout", this.autoHideHd.mouseout);
30421 this.el.un("mouseover", this.autoHideHd.mouseover);
30425 clearMonitor : function(){
30426 Roo.get(document).un("click", this.slideInIf, this);
30429 // these names are backwards but not changed for compat
30430 slideOut : function(){
30431 if(this.isSlid || this.el.hasActiveFx()){
30434 this.isSlid = true;
30435 if(this.collapseBtn){
30436 this.collapseBtn.hide();
30438 this.closeBtnState = this.closeBtn.getStyle('display');
30439 this.closeBtn.hide();
30441 this.stickBtn.show();
30444 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
30445 this.beforeSlide();
30446 this.el.setStyle("z-index", 10001);
30447 this.el.slideIn(this.getSlideAnchor(), {
30448 callback: function(){
30450 this.initAutoHide();
30451 Roo.get(document).on("click", this.slideInIf, this);
30452 this.fireEvent("slideshow", this);
30459 afterSlideIn : function(){
30460 this.clearAutoHide();
30461 this.isSlid = false;
30462 this.clearMonitor();
30463 this.el.setStyle("z-index", "");
30464 if(this.collapseBtn){
30465 this.collapseBtn.show();
30467 this.closeBtn.setStyle('display', this.closeBtnState);
30469 this.stickBtn.hide();
30471 this.fireEvent("slidehide", this);
30474 slideIn : function(cb){
30475 if(!this.isSlid || this.el.hasActiveFx()){
30479 this.isSlid = false;
30480 this.beforeSlide();
30481 this.el.slideOut(this.getSlideAnchor(), {
30482 callback: function(){
30483 this.el.setLeftTop(-10000, -10000);
30485 this.afterSlideIn();
30493 slideInIf : function(e){
30494 if(!e.within(this.el)){
30499 animateCollapse : function(){
30500 this.beforeSlide();
30501 this.el.setStyle("z-index", 20000);
30502 var anchor = this.getSlideAnchor();
30503 this.el.slideOut(anchor, {
30504 callback : function(){
30505 this.el.setStyle("z-index", "");
30506 this.collapsedEl.slideIn(anchor, {duration:.3});
30508 this.el.setLocation(-10000,-10000);
30510 this.fireEvent("collapsed", this);
30517 animateExpand : function(){
30518 this.beforeSlide();
30519 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
30520 this.el.setStyle("z-index", 20000);
30521 this.collapsedEl.hide({
30524 this.el.slideIn(this.getSlideAnchor(), {
30525 callback : function(){
30526 this.el.setStyle("z-index", "");
30529 this.split.el.show();
30531 this.fireEvent("invalidated", this);
30532 this.fireEvent("expanded", this);
30560 getAnchor : function(){
30561 return this.anchors[this.position];
30564 getCollapseAnchor : function(){
30565 return this.canchors[this.position];
30568 getSlideAnchor : function(){
30569 return this.sanchors[this.position];
30572 getAlignAdj : function(){
30573 var cm = this.cmargins;
30574 switch(this.position){
30590 getExpandAdj : function(){
30591 var c = this.collapsedEl, cm = this.cmargins;
30592 switch(this.position){
30594 return [-(cm.right+c.getWidth()+cm.left), 0];
30597 return [cm.right+c.getWidth()+cm.left, 0];
30600 return [0, -(cm.top+cm.bottom+c.getHeight())];
30603 return [0, cm.top+cm.bottom+c.getHeight()];
30609 * Ext JS Library 1.1.1
30610 * Copyright(c) 2006-2007, Ext JS, LLC.
30612 * Originally Released Under LGPL - original licence link has changed is not relivant.
30615 * <script type="text/javascript">
30618 * These classes are private internal classes
30620 Roo.CenterLayoutRegion = function(mgr, config){
30621 Roo.LayoutRegion.call(this, mgr, config, "center");
30622 this.visible = true;
30623 this.minWidth = config.minWidth || 20;
30624 this.minHeight = config.minHeight || 20;
30627 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
30629 // center panel can't be hidden
30633 // center panel can't be hidden
30636 getMinWidth: function(){
30637 return this.minWidth;
30640 getMinHeight: function(){
30641 return this.minHeight;
30646 Roo.NorthLayoutRegion = function(mgr, config){
30647 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
30649 this.split.placement = Roo.SplitBar.TOP;
30650 this.split.orientation = Roo.SplitBar.VERTICAL;
30651 this.split.el.addClass("x-layout-split-v");
30653 var size = config.initialSize || config.height;
30654 if(typeof size != "undefined"){
30655 this.el.setHeight(size);
30658 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
30659 orientation: Roo.SplitBar.VERTICAL,
30660 getBox : function(){
30661 if(this.collapsed){
30662 return this.collapsedEl.getBox();
30664 var box = this.el.getBox();
30666 box.height += this.split.el.getHeight();
30671 updateBox : function(box){
30672 if(this.split && !this.collapsed){
30673 box.height -= this.split.el.getHeight();
30674 this.split.el.setLeft(box.x);
30675 this.split.el.setTop(box.y+box.height);
30676 this.split.el.setWidth(box.width);
30678 if(this.collapsed){
30679 this.updateBody(box.width, null);
30681 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30685 Roo.SouthLayoutRegion = function(mgr, config){
30686 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
30688 this.split.placement = Roo.SplitBar.BOTTOM;
30689 this.split.orientation = Roo.SplitBar.VERTICAL;
30690 this.split.el.addClass("x-layout-split-v");
30692 var size = config.initialSize || config.height;
30693 if(typeof size != "undefined"){
30694 this.el.setHeight(size);
30697 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
30698 orientation: Roo.SplitBar.VERTICAL,
30699 getBox : function(){
30700 if(this.collapsed){
30701 return this.collapsedEl.getBox();
30703 var box = this.el.getBox();
30705 var sh = this.split.el.getHeight();
30712 updateBox : function(box){
30713 if(this.split && !this.collapsed){
30714 var sh = this.split.el.getHeight();
30717 this.split.el.setLeft(box.x);
30718 this.split.el.setTop(box.y-sh);
30719 this.split.el.setWidth(box.width);
30721 if(this.collapsed){
30722 this.updateBody(box.width, null);
30724 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30728 Roo.EastLayoutRegion = function(mgr, config){
30729 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
30731 this.split.placement = Roo.SplitBar.RIGHT;
30732 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30733 this.split.el.addClass("x-layout-split-h");
30735 var size = config.initialSize || config.width;
30736 if(typeof size != "undefined"){
30737 this.el.setWidth(size);
30740 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
30741 orientation: Roo.SplitBar.HORIZONTAL,
30742 getBox : function(){
30743 if(this.collapsed){
30744 return this.collapsedEl.getBox();
30746 var box = this.el.getBox();
30748 var sw = this.split.el.getWidth();
30755 updateBox : function(box){
30756 if(this.split && !this.collapsed){
30757 var sw = this.split.el.getWidth();
30759 this.split.el.setLeft(box.x);
30760 this.split.el.setTop(box.y);
30761 this.split.el.setHeight(box.height);
30764 if(this.collapsed){
30765 this.updateBody(null, box.height);
30767 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30771 Roo.WestLayoutRegion = function(mgr, config){
30772 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
30774 this.split.placement = Roo.SplitBar.LEFT;
30775 this.split.orientation = Roo.SplitBar.HORIZONTAL;
30776 this.split.el.addClass("x-layout-split-h");
30778 var size = config.initialSize || config.width;
30779 if(typeof size != "undefined"){
30780 this.el.setWidth(size);
30783 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
30784 orientation: Roo.SplitBar.HORIZONTAL,
30785 getBox : function(){
30786 if(this.collapsed){
30787 return this.collapsedEl.getBox();
30789 var box = this.el.getBox();
30791 box.width += this.split.el.getWidth();
30796 updateBox : function(box){
30797 if(this.split && !this.collapsed){
30798 var sw = this.split.el.getWidth();
30800 this.split.el.setLeft(box.x+box.width);
30801 this.split.el.setTop(box.y);
30802 this.split.el.setHeight(box.height);
30804 if(this.collapsed){
30805 this.updateBody(null, box.height);
30807 Roo.LayoutRegion.prototype.updateBox.call(this, box);
30812 * Ext JS Library 1.1.1
30813 * Copyright(c) 2006-2007, Ext JS, LLC.
30815 * Originally Released Under LGPL - original licence link has changed is not relivant.
30818 * <script type="text/javascript">
30823 * Private internal class for reading and applying state
30825 Roo.LayoutStateManager = function(layout){
30826 // default empty state
30835 Roo.LayoutStateManager.prototype = {
30836 init : function(layout, provider){
30837 this.provider = provider;
30838 var state = provider.get(layout.id+"-layout-state");
30840 var wasUpdating = layout.isUpdating();
30842 layout.beginUpdate();
30844 for(var key in state){
30845 if(typeof state[key] != "function"){
30846 var rstate = state[key];
30847 var r = layout.getRegion(key);
30850 r.resizeTo(rstate.size);
30852 if(rstate.collapsed == true){
30855 r.expand(null, true);
30861 layout.endUpdate();
30863 this.state = state;
30865 this.layout = layout;
30866 layout.on("regionresized", this.onRegionResized, this);
30867 layout.on("regioncollapsed", this.onRegionCollapsed, this);
30868 layout.on("regionexpanded", this.onRegionExpanded, this);
30871 storeState : function(){
30872 this.provider.set(this.layout.id+"-layout-state", this.state);
30875 onRegionResized : function(region, newSize){
30876 this.state[region.getPosition()].size = newSize;
30880 onRegionCollapsed : function(region){
30881 this.state[region.getPosition()].collapsed = true;
30885 onRegionExpanded : function(region){
30886 this.state[region.getPosition()].collapsed = false;
30891 * Ext JS Library 1.1.1
30892 * Copyright(c) 2006-2007, Ext JS, LLC.
30894 * Originally Released Under LGPL - original licence link has changed is not relivant.
30897 * <script type="text/javascript">
30900 * @class Roo.ContentPanel
30901 * @extends Roo.util.Observable
30902 * A basic ContentPanel element.
30903 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
30904 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
30905 * @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
30906 * @cfg {Boolean} closable True if the panel can be closed/removed
30907 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
30908 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
30909 * @cfg {Toolbar} toolbar A toolbar for this panel
30910 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
30911 * @cfg {String} title The title for this panel
30912 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
30913 * @cfg {String} url Calls {@link #setUrl} with this value
30914 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
30915 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
30916 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
30918 * Create a new ContentPanel.
30919 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
30920 * @param {String/Object} config A string to set only the title or a config object
30921 * @param {String} content (optional) Set the HTML content for this panel
30922 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
30924 Roo.ContentPanel = function(el, config, content){
30928 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
30932 if (config && config.parentLayout) {
30933 el = config.parentLayout.el.createChild();
30936 if(el.autoCreate){ // xtype is available if this is called from factory
30940 this.el = Roo.get(el);
30941 if(!this.el && config && config.autoCreate){
30942 if(typeof config.autoCreate == "object"){
30943 if(!config.autoCreate.id){
30944 config.autoCreate.id = config.id||el;
30946 this.el = Roo.DomHelper.append(document.body,
30947 config.autoCreate, true);
30949 this.el = Roo.DomHelper.append(document.body,
30950 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
30953 this.closable = false;
30954 this.loaded = false;
30955 this.active = false;
30956 if(typeof config == "string"){
30957 this.title = config;
30959 Roo.apply(this, config);
30962 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
30963 this.wrapEl = this.el.wrap();
30964 this.toolbar = new Roo.Toolbar(this.el.insertSibling(false, 'before'), [] , this.toolbar);
30971 this.resizeEl = Roo.get(this.resizeEl, true);
30973 this.resizeEl = this.el;
30978 * Fires when this panel is activated.
30979 * @param {Roo.ContentPanel} this
30983 * @event deactivate
30984 * Fires when this panel is activated.
30985 * @param {Roo.ContentPanel} this
30987 "deactivate" : true,
30991 * Fires when this panel is resized if fitToFrame is true.
30992 * @param {Roo.ContentPanel} this
30993 * @param {Number} width The width after any component adjustments
30994 * @param {Number} height The height after any component adjustments
30998 if(this.autoScroll){
30999 this.resizeEl.setStyle("overflow", "auto");
31001 // fix randome scrolling
31002 this.el.on('scroll', function() {
31003 this.scrollTo('top',0);
31006 content = content || this.content;
31008 this.setContent(content);
31010 if(config && config.url){
31011 this.setUrl(this.url, this.params, this.loadOnce);
31016 Roo.ContentPanel.superclass.constructor.call(this);
31019 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
31021 setRegion : function(region){
31022 this.region = region;
31024 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
31026 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
31031 * Returns the toolbar for this Panel if one was configured.
31032 * @return {Roo.Toolbar}
31034 getToolbar : function(){
31035 return this.toolbar;
31038 setActiveState : function(active){
31039 this.active = active;
31041 this.fireEvent("deactivate", this);
31043 this.fireEvent("activate", this);
31047 * Updates this panel's element
31048 * @param {String} content The new content
31049 * @param {Boolean} loadScripts (optional) true to look for and process scripts
31051 setContent : function(content, loadScripts){
31052 this.el.update(content, loadScripts);
31055 ignoreResize : function(w, h){
31056 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
31059 this.lastSize = {width: w, height: h};
31064 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
31065 * @return {Roo.UpdateManager} The UpdateManager
31067 getUpdateManager : function(){
31068 return this.el.getUpdateManager();
31071 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
31072 * @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:
31075 url: "your-url.php",
31076 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
31077 callback: yourFunction,
31078 scope: yourObject, //(optional scope)
31081 text: "Loading...",
31086 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
31087 * 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.
31088 * @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}
31089 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
31090 * @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.
31091 * @return {Roo.ContentPanel} this
31094 var um = this.el.getUpdateManager();
31095 um.update.apply(um, arguments);
31101 * 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.
31102 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
31103 * @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)
31104 * @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)
31105 * @return {Roo.UpdateManager} The UpdateManager
31107 setUrl : function(url, params, loadOnce){
31108 if(this.refreshDelegate){
31109 this.removeListener("activate", this.refreshDelegate);
31111 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
31112 this.on("activate", this.refreshDelegate);
31113 return this.el.getUpdateManager();
31116 _handleRefresh : function(url, params, loadOnce){
31117 if(!loadOnce || !this.loaded){
31118 var updater = this.el.getUpdateManager();
31119 updater.update(url, params, this._setLoaded.createDelegate(this));
31123 _setLoaded : function(){
31124 this.loaded = true;
31128 * Returns this panel's id
31131 getId : function(){
31136 * Returns this panel's element - used by regiosn to add.
31137 * @return {Roo.Element}
31139 getEl : function(){
31140 return this.wrapEl || this.el;
31143 adjustForComponents : function(width, height){
31144 if(this.resizeEl != this.el){
31145 width -= this.el.getFrameWidth('lr');
31146 height -= this.el.getFrameWidth('tb');
31149 var te = this.toolbar.getEl();
31150 height -= te.getHeight();
31151 te.setWidth(width);
31153 if(this.adjustments){
31154 width += this.adjustments[0];
31155 height += this.adjustments[1];
31157 return {"width": width, "height": height};
31160 setSize : function(width, height){
31161 if(this.fitToFrame && !this.ignoreResize(width, height)){
31162 if(this.fitContainer && this.resizeEl != this.el){
31163 this.el.setSize(width, height);
31165 var size = this.adjustForComponents(width, height);
31166 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
31167 this.fireEvent('resize', this, size.width, size.height);
31172 * Returns this panel's title
31175 getTitle : function(){
31180 * Set this panel's title
31181 * @param {String} title
31183 setTitle : function(title){
31184 this.title = title;
31186 this.region.updatePanelTitle(this, title);
31191 * Returns true is this panel was configured to be closable
31192 * @return {Boolean}
31194 isClosable : function(){
31195 return this.closable;
31198 beforeSlide : function(){
31200 this.resizeEl.clip();
31203 afterSlide : function(){
31205 this.resizeEl.unclip();
31209 * Force a content refresh from the URL specified in the {@link #setUrl} method.
31210 * Will fail silently if the {@link #setUrl} method has not been called.
31211 * This does not activate the panel, just updates its content.
31213 refresh : function(){
31214 if(this.refreshDelegate){
31215 this.loaded = false;
31216 this.refreshDelegate();
31221 * Destroys this panel
31223 destroy : function(){
31224 this.el.removeAllListeners();
31225 var tempEl = document.createElement("span");
31226 tempEl.appendChild(this.el.dom);
31227 tempEl.innerHTML = "";
31233 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
31243 * @param {Object} cfg Xtype definition of item to add.
31246 addxtype : function(cfg) {
31248 if (cfg.xtype.match(/^Form$/)) {
31249 var el = this.el.createChild();
31251 this.form = new Roo.form.Form(cfg);
31254 if ( this.form.allItems.length) this.form.render(el.dom);
31257 if (['View', 'JsonView'].indexOf(cfg.xtype) > -1) {
31259 cfg.el = this.el.appendChild(document.createElement("div"));
31261 var ret = new Roo[cfg.xtype](cfg);
31262 ret.render(false, ''); // render blank..
31272 * @class Roo.GridPanel
31273 * @extends Roo.ContentPanel
31275 * Create a new GridPanel.
31276 * @param {Roo.grid.Grid} grid The grid for this panel
31277 * @param {String/Object} config A string to set only the panel's title, or a config object
31279 Roo.GridPanel = function(grid, config){
31282 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
31283 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
31285 this.wrapper.dom.appendChild(grid.getGridEl().dom);
31287 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
31290 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
31292 // xtype created footer. - not sure if will work as we normally have to render first..
31293 if (this.footer && !this.footer.el && this.footer.xtype) {
31295 this.footer.container = this.grid.getView().getFooterPanel(true);
31296 this.footer.dataSource = this.grid.dataSource;
31297 this.footer = Roo.factory(this.footer, Roo);
31301 grid.monitorWindowResize = false; // turn off autosizing
31302 grid.autoHeight = false;
31303 grid.autoWidth = false;
31305 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
31308 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
31309 getId : function(){
31310 return this.grid.id;
31314 * Returns the grid for this panel
31315 * @return {Roo.grid.Grid}
31317 getGrid : function(){
31321 setSize : function(width, height){
31322 if(!this.ignoreResize(width, height)){
31323 var grid = this.grid;
31324 var size = this.adjustForComponents(width, height);
31325 grid.getGridEl().setSize(size.width, size.height);
31330 beforeSlide : function(){
31331 this.grid.getView().scroller.clip();
31334 afterSlide : function(){
31335 this.grid.getView().scroller.unclip();
31338 destroy : function(){
31339 this.grid.destroy();
31341 Roo.GridPanel.superclass.destroy.call(this);
31347 * @class Roo.NestedLayoutPanel
31348 * @extends Roo.ContentPanel
31350 * Create a new NestedLayoutPanel.
31353 * @param {Roo.BorderLayout} layout The layout for this panel
31354 * @param {String/Object} config A string to set only the title or a config object
31356 Roo.NestedLayoutPanel = function(layout, config)
31358 // construct with only one argument..
31359 /* FIXME - implement nicer consturctors
31360 if (layout.layout) {
31362 layout = config.layout;
31363 delete config.layout;
31365 if (layout.xtype && !layout.getEl) {
31366 // then layout needs constructing..
31367 layout = Roo.factory(layout, Roo);
31372 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
31374 layout.monitorWindowResize = false; // turn off autosizing
31375 this.layout = layout;
31376 this.layout.getEl().addClass("x-layout-nested-layout");
31383 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
31385 setSize : function(width, height){
31386 if(!this.ignoreResize(width, height)){
31387 var size = this.adjustForComponents(width, height);
31388 var el = this.layout.getEl();
31389 el.setSize(size.width, size.height);
31390 var touch = el.dom.offsetWidth;
31391 this.layout.layout();
31392 // ie requires a double layout on the first pass
31393 if(Roo.isIE && !this.initialized){
31394 this.initialized = true;
31395 this.layout.layout();
31400 // activate all subpanels if not currently active..
31402 setActiveState : function(active){
31403 this.active = active;
31405 this.fireEvent("deactivate", this);
31409 this.fireEvent("activate", this);
31410 // not sure if this should happen before or after..
31411 if (!this.layout) {
31412 return; // should not happen..
31415 for (var r in this.layout.regions) {
31416 reg = this.layout.getRegion(r);
31417 if (reg.getActivePanel()) {
31418 //reg.showPanel(reg.getActivePanel()); // force it to activate..
31419 reg.setActivePanel(reg.getActivePanel());
31422 if (!reg.panels.length) {
31425 reg.showPanel(reg.getPanel(0));
31434 * Returns the nested BorderLayout for this panel
31435 * @return {Roo.BorderLayout}
31437 getLayout : function(){
31438 return this.layout;
31442 * Adds a xtype elements to the layout of the nested panel
31446 xtype : 'ContentPanel',
31453 xtype : 'NestedLayoutPanel',
31459 items : [ ... list of content panels or nested layout panels.. ]
31463 * @param {Object} cfg Xtype definition of item to add.
31465 addxtype : function(cfg) {
31466 return this.layout.addxtype(cfg);
31471 Roo.ScrollPanel = function(el, config, content){
31472 config = config || {};
31473 config.fitToFrame = true;
31474 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
31476 this.el.dom.style.overflow = "hidden";
31477 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
31478 this.el.removeClass("x-layout-inactive-content");
31479 this.el.on("mousewheel", this.onWheel, this);
31481 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
31482 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
31483 up.unselectable(); down.unselectable();
31484 up.on("click", this.scrollUp, this);
31485 down.on("click", this.scrollDown, this);
31486 up.addClassOnOver("x-scroller-btn-over");
31487 down.addClassOnOver("x-scroller-btn-over");
31488 up.addClassOnClick("x-scroller-btn-click");
31489 down.addClassOnClick("x-scroller-btn-click");
31490 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
31492 this.resizeEl = this.el;
31493 this.el = wrap; this.up = up; this.down = down;
31496 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
31498 wheelIncrement : 5,
31499 scrollUp : function(){
31500 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
31503 scrollDown : function(){
31504 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
31507 afterScroll : function(){
31508 var el = this.resizeEl;
31509 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
31510 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31511 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
31514 setSize : function(){
31515 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
31516 this.afterScroll();
31519 onWheel : function(e){
31520 var d = e.getWheelDelta();
31521 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
31522 this.afterScroll();
31526 setContent : function(content, loadScripts){
31527 this.resizeEl.update(content, loadScripts);
31541 * @class Roo.TreePanel
31542 * @extends Roo.ContentPanel
31544 * Create a new TreePanel. - defaults to fit/scoll contents.
31545 * @param {String/Object} config A string to set only the panel's title, or a config object
31546 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
31548 Roo.TreePanel = function(config){
31549 var el = config.el;
31550 var tree = config.tree;
31551 delete config.tree;
31552 delete config.el; // hopefull!
31554 // wrapper for IE7 strict & safari scroll issue
31556 var treeEl = el.createChild();
31557 config.resizeEl = treeEl;
31561 Roo.TreePanel.superclass.constructor.call(this, el, config);
31564 this.tree = new Roo.tree.TreePanel(treeEl , tree);
31565 //console.log(tree);
31566 this.on('activate', function()
31568 if (this.tree.rendered) {
31571 //console.log('render tree');
31572 this.tree.render();
31575 this.on('resize', function (cp, w, h) {
31576 this.tree.innerCt.setWidth(w);
31577 this.tree.innerCt.setHeight(h);
31578 this.tree.innerCt.setStyle('overflow-y', 'auto');
31585 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
31602 * Ext JS Library 1.1.1
31603 * Copyright(c) 2006-2007, Ext JS, LLC.
31605 * Originally Released Under LGPL - original licence link has changed is not relivant.
31608 * <script type="text/javascript">
31613 * @class Roo.ReaderLayout
31614 * @extends Roo.BorderLayout
31615 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
31616 * center region containing two nested regions (a top one for a list view and one for item preview below),
31617 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
31618 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
31619 * expedites the setup of the overall layout and regions for this common application style.
31622 var reader = new Roo.ReaderLayout();
31623 var CP = Roo.ContentPanel; // shortcut for adding
31625 reader.beginUpdate();
31626 reader.add("north", new CP("north", "North"));
31627 reader.add("west", new CP("west", {title: "West"}));
31628 reader.add("east", new CP("east", {title: "East"}));
31630 reader.regions.listView.add(new CP("listView", "List"));
31631 reader.regions.preview.add(new CP("preview", "Preview"));
31632 reader.endUpdate();
31635 * Create a new ReaderLayout
31636 * @param {Object} config Configuration options
31637 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
31638 * document.body if omitted)
31640 Roo.ReaderLayout = function(config, renderTo){
31641 var c = config || {size:{}};
31642 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
31643 north: c.north !== false ? Roo.apply({
31647 }, c.north) : false,
31648 west: c.west !== false ? Roo.apply({
31656 margins:{left:5,right:0,bottom:5,top:5},
31657 cmargins:{left:5,right:5,bottom:5,top:5}
31658 }, c.west) : false,
31659 east: c.east !== false ? Roo.apply({
31667 margins:{left:0,right:5,bottom:5,top:5},
31668 cmargins:{left:5,right:5,bottom:5,top:5}
31669 }, c.east) : false,
31670 center: Roo.apply({
31671 tabPosition: 'top',
31675 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
31679 this.el.addClass('x-reader');
31681 this.beginUpdate();
31683 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
31684 south: c.preview !== false ? Roo.apply({
31691 cmargins:{top:5,left:0, right:0, bottom:0}
31692 }, c.preview) : false,
31693 center: Roo.apply({
31699 this.add('center', new Roo.NestedLayoutPanel(inner,
31700 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
31704 this.regions.preview = inner.getRegion('south');
31705 this.regions.listView = inner.getRegion('center');
31708 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
31710 * Ext JS Library 1.1.1
31711 * Copyright(c) 2006-2007, Ext JS, LLC.
31713 * Originally Released Under LGPL - original licence link has changed is not relivant.
31716 * <script type="text/javascript">
31720 * @class Roo.grid.Grid
31721 * @extends Roo.util.Observable
31722 * This class represents the primary interface of a component based grid control.
31723 * <br><br>Usage:<pre><code>
31724 var grid = new Roo.grid.Grid("my-container-id", {
31727 selModel: mySelectionModel,
31728 autoSizeColumns: true,
31729 monitorWindowResize: false,
31730 trackMouseOver: true
31735 * <b>Common Problems:</b><br/>
31736 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
31737 * element will correct this<br/>
31738 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
31739 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
31740 * are unpredictable.<br/>
31741 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
31742 * grid to calculate dimensions/offsets.<br/>
31744 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
31745 * The container MUST have some type of size defined for the grid to fill. The container will be
31746 * automatically set to position relative if it isn't already.
31747 * @param {Object} config A config object that sets properties on this grid.
31749 Roo.grid.Grid = function(container, config){
31750 // initialize the container
31751 this.container = Roo.get(container);
31752 this.container.update("");
31753 this.container.setStyle("overflow", "hidden");
31754 this.container.addClass('x-grid-container');
31756 this.id = this.container.id;
31758 Roo.apply(this, config);
31759 // check and correct shorthanded configs
31761 this.dataSource = this.ds;
31765 this.colModel = this.cm;
31769 this.selModel = this.sm;
31773 if (this.selModel) {
31774 this.selModel = Roo.factory(this.selModel, Roo.grid);
31775 this.sm = this.selModel;
31776 this.sm.xmodule = this.xmodule || false;
31778 if (typeof(this.colModel.config) == 'undefined') {
31779 this.colModel = new Roo.grid.ColumnModel(this.colModel);
31780 this.cm = this.colModel;
31781 this.cm.xmodule = this.xmodule || false;
31783 if (this.dataSource) {
31784 this.dataSource= Roo.factory(this.dataSource, Roo.data);
31785 this.ds = this.dataSource;
31786 this.ds.xmodule = this.xmodule || false;
31793 this.container.setWidth(this.width);
31797 this.container.setHeight(this.height);
31804 * The raw click event for the entire grid.
31805 * @param {Roo.EventObject} e
31810 * The raw dblclick event for the entire grid.
31811 * @param {Roo.EventObject} e
31815 * @event contextmenu
31816 * The raw contextmenu event for the entire grid.
31817 * @param {Roo.EventObject} e
31819 "contextmenu" : true,
31822 * The raw mousedown event for the entire grid.
31823 * @param {Roo.EventObject} e
31825 "mousedown" : true,
31828 * The raw mouseup event for the entire grid.
31829 * @param {Roo.EventObject} e
31834 * The raw mouseover event for the entire grid.
31835 * @param {Roo.EventObject} e
31837 "mouseover" : true,
31840 * The raw mouseout event for the entire grid.
31841 * @param {Roo.EventObject} e
31846 * The raw keypress event for the entire grid.
31847 * @param {Roo.EventObject} e
31852 * The raw keydown event for the entire grid.
31853 * @param {Roo.EventObject} e
31861 * Fires when a cell is clicked
31862 * @param {Grid} this
31863 * @param {Number} rowIndex
31864 * @param {Number} columnIndex
31865 * @param {Roo.EventObject} e
31867 "cellclick" : true,
31869 * @event celldblclick
31870 * Fires when a cell is double clicked
31871 * @param {Grid} this
31872 * @param {Number} rowIndex
31873 * @param {Number} columnIndex
31874 * @param {Roo.EventObject} e
31876 "celldblclick" : true,
31879 * Fires when a row is clicked
31880 * @param {Grid} this
31881 * @param {Number} rowIndex
31882 * @param {Roo.EventObject} e
31886 * @event rowdblclick
31887 * Fires when a row is double clicked
31888 * @param {Grid} this
31889 * @param {Number} rowIndex
31890 * @param {Roo.EventObject} e
31892 "rowdblclick" : true,
31894 * @event headerclick
31895 * Fires when a header is clicked
31896 * @param {Grid} this
31897 * @param {Number} columnIndex
31898 * @param {Roo.EventObject} e
31900 "headerclick" : true,
31902 * @event headerdblclick
31903 * Fires when a header cell is double clicked
31904 * @param {Grid} this
31905 * @param {Number} columnIndex
31906 * @param {Roo.EventObject} e
31908 "headerdblclick" : true,
31910 * @event rowcontextmenu
31911 * Fires when a row is right clicked
31912 * @param {Grid} this
31913 * @param {Number} rowIndex
31914 * @param {Roo.EventObject} e
31916 "rowcontextmenu" : true,
31918 * @event cellcontextmenu
31919 * Fires when a cell is right clicked
31920 * @param {Grid} this
31921 * @param {Number} rowIndex
31922 * @param {Number} cellIndex
31923 * @param {Roo.EventObject} e
31925 "cellcontextmenu" : true,
31927 * @event headercontextmenu
31928 * Fires when a header is right clicked
31929 * @param {Grid} this
31930 * @param {Number} columnIndex
31931 * @param {Roo.EventObject} e
31933 "headercontextmenu" : true,
31935 * @event bodyscroll
31936 * Fires when the body element is scrolled
31937 * @param {Number} scrollLeft
31938 * @param {Number} scrollTop
31940 "bodyscroll" : true,
31942 * @event columnresize
31943 * Fires when the user resizes a column
31944 * @param {Number} columnIndex
31945 * @param {Number} newSize
31947 "columnresize" : true,
31949 * @event columnmove
31950 * Fires when the user moves a column
31951 * @param {Number} oldIndex
31952 * @param {Number} newIndex
31954 "columnmove" : true,
31957 * Fires when row(s) start being dragged
31958 * @param {Grid} this
31959 * @param {Roo.GridDD} dd The drag drop object
31960 * @param {event} e The raw browser event
31962 "startdrag" : true,
31965 * Fires when a drag operation is complete
31966 * @param {Grid} this
31967 * @param {Roo.GridDD} dd The drag drop object
31968 * @param {event} e The raw browser event
31973 * Fires when dragged row(s) are dropped on a valid DD target
31974 * @param {Grid} this
31975 * @param {Roo.GridDD} dd The drag drop object
31976 * @param {String} targetId The target drag drop object
31977 * @param {event} e The raw browser event
31982 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
31983 * @param {Grid} this
31984 * @param {Roo.GridDD} dd The drag drop object
31985 * @param {String} targetId The target drag drop object
31986 * @param {event} e The raw browser event
31991 * Fires when the dragged row(s) first cross another DD target while being dragged
31992 * @param {Grid} this
31993 * @param {Roo.GridDD} dd The drag drop object
31994 * @param {String} targetId The target drag drop object
31995 * @param {event} e The raw browser event
31997 "dragenter" : true,
32000 * Fires when the dragged row(s) leave another DD target while being dragged
32001 * @param {Grid} this
32002 * @param {Roo.GridDD} dd The drag drop object
32003 * @param {String} targetId The target drag drop object
32004 * @param {event} e The raw browser event
32009 * Fires when the grid is rendered
32010 * @param {Grid} grid
32015 Roo.grid.Grid.superclass.constructor.call(this);
32017 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
32020 * @cfg {String} ddGroup - drag drop group.
32024 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
32026 minColumnWidth : 25,
32029 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
32030 * <b>on initial render.</b> It is more efficient to explicitly size the columns
32031 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
32033 autoSizeColumns : false,
32036 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
32038 autoSizeHeaders : true,
32041 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
32043 monitorWindowResize : true,
32046 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
32047 * rows measured to get a columns size. Default is 0 (all rows).
32049 maxRowsToMeasure : 0,
32052 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
32054 trackMouseOver : true,
32057 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
32061 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
32063 enableDragDrop : false,
32066 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
32068 enableColumnMove : true,
32071 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
32073 enableColumnHide : true,
32076 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
32078 enableRowHeightSync : false,
32081 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
32086 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
32088 autoHeight : false,
32091 * @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.
32093 autoExpandColumn : false,
32096 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
32099 autoExpandMin : 50,
32102 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
32104 autoExpandMax : 1000,
32107 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
32112 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
32116 * @cfg {Roo.dd.DropTarget} dragTarget An {@link Roo.dd.DragTarget} config
32123 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
32124 * of a fixed width. Default is false.
32127 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
32130 * Called once after all setup has been completed and the grid is ready to be rendered.
32131 * @return {Roo.grid.Grid} this
32133 render : function(){
32134 var c = this.container;
32135 // try to detect autoHeight/width mode
32136 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
32137 this.autoHeight = true;
32139 var view = this.getView();
32142 c.on("click", this.onClick, this);
32143 c.on("dblclick", this.onDblClick, this);
32144 c.on("contextmenu", this.onContextMenu, this);
32145 c.on("keydown", this.onKeyDown, this);
32147 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
32149 this.getSelectionModel().init(this);
32154 this.loadMask = new Roo.LoadMask(this.container,
32155 Roo.apply({store:this.dataSource}, this.loadMask));
32159 if (this.toolbar && this.toolbar.xtype) {
32160 this.toolbar.container = this.getView().getHeaderPanel(true);
32161 this.toolbar = new Ext.Toolbar(this.toolbar);
32163 if (this.footer && this.footer.xtype) {
32164 this.footer.dataSource = this.getDataSource();
32165 this.footer.container = this.getView().getFooterPanel(true);
32166 this.footer = Roo.factory(this.footer, Roo);
32168 if (this.dropTarget && this.dropTarget.xtype) {
32169 delete this.dropTarget.xtype;
32170 this.dropTarget = new Ext.dd.DropTarget(this.getView().mainBody, this.dropTarget);
32174 this.rendered = true;
32175 this.fireEvent('render', this);
32180 * Reconfigures the grid to use a different Store and Column Model.
32181 * The View will be bound to the new objects and refreshed.
32182 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
32183 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
32185 reconfigure : function(dataSource, colModel){
32187 this.loadMask.destroy();
32188 this.loadMask = new Roo.LoadMask(this.container,
32189 Roo.apply({store:dataSource}, this.loadMask));
32191 this.view.bind(dataSource, colModel);
32192 this.dataSource = dataSource;
32193 this.colModel = colModel;
32194 this.view.refresh(true);
32198 onKeyDown : function(e){
32199 this.fireEvent("keydown", e);
32203 * Destroy this grid.
32204 * @param {Boolean} removeEl True to remove the element
32206 destroy : function(removeEl, keepListeners){
32208 this.loadMask.destroy();
32210 var c = this.container;
32211 c.removeAllListeners();
32212 this.view.destroy();
32213 this.colModel.purgeListeners();
32214 if(!keepListeners){
32215 this.purgeListeners();
32218 if(removeEl === true){
32224 processEvent : function(name, e){
32225 this.fireEvent(name, e);
32226 var t = e.getTarget();
32228 var header = v.findHeaderIndex(t);
32229 if(header !== false){
32230 this.fireEvent("header" + name, this, header, e);
32232 var row = v.findRowIndex(t);
32233 var cell = v.findCellIndex(t);
32235 this.fireEvent("row" + name, this, row, e);
32236 if(cell !== false){
32237 this.fireEvent("cell" + name, this, row, cell, e);
32244 onClick : function(e){
32245 this.processEvent("click", e);
32249 onContextMenu : function(e, t){
32250 this.processEvent("contextmenu", e);
32254 onDblClick : function(e){
32255 this.processEvent("dblclick", e);
32259 walkCells : function(row, col, step, fn, scope){
32260 var cm = this.colModel, clen = cm.getColumnCount();
32261 var ds = this.dataSource, rlen = ds.getCount(), first = true;
32273 if(fn.call(scope || this, row, col, cm) === true){
32291 if(fn.call(scope || this, row, col, cm) === true){
32303 getSelections : function(){
32304 return this.selModel.getSelections();
32308 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
32309 * but if manual update is required this method will initiate it.
32311 autoSize : function(){
32313 this.view.layout();
32314 if(this.view.adjustForScroll){
32315 this.view.adjustForScroll();
32321 * Returns the grid's underlying element.
32322 * @return {Element} The element
32324 getGridEl : function(){
32325 return this.container;
32328 // private for compatibility, overridden by editor grid
32329 stopEditing : function(){},
32332 * Returns the grid's SelectionModel.
32333 * @return {SelectionModel}
32335 getSelectionModel : function(){
32336 if(!this.selModel){
32337 this.selModel = new Roo.grid.RowSelectionModel();
32339 return this.selModel;
32343 * Returns the grid's DataSource.
32344 * @return {DataSource}
32346 getDataSource : function(){
32347 return this.dataSource;
32351 * Returns the grid's ColumnModel.
32352 * @return {ColumnModel}
32354 getColumnModel : function(){
32355 return this.colModel;
32359 * Returns the grid's GridView object.
32360 * @return {GridView}
32362 getView : function(){
32364 this.view = new Roo.grid.GridView(this.viewConfig);
32369 * Called to get grid's drag proxy text, by default returns this.ddText.
32372 getDragDropText : function(){
32373 var count = this.selModel.getCount();
32374 return String.format(this.ddText, count, count == 1 ? '' : 's');
32378 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
32379 * %0 is replaced with the number of selected rows.
32382 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
32384 * Ext JS Library 1.1.1
32385 * Copyright(c) 2006-2007, Ext JS, LLC.
32387 * Originally Released Under LGPL - original licence link has changed is not relivant.
32390 * <script type="text/javascript">
32393 Roo.grid.AbstractGridView = function(){
32397 "beforerowremoved" : true,
32398 "beforerowsinserted" : true,
32399 "beforerefresh" : true,
32400 "rowremoved" : true,
32401 "rowsinserted" : true,
32402 "rowupdated" : true,
32405 Roo.grid.AbstractGridView.superclass.constructor.call(this);
32408 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
32409 rowClass : "x-grid-row",
32410 cellClass : "x-grid-cell",
32411 tdClass : "x-grid-td",
32412 hdClass : "x-grid-hd",
32413 splitClass : "x-grid-hd-split",
32415 init: function(grid){
32417 var cid = this.grid.getGridEl().id;
32418 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
32419 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
32420 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
32421 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
32424 getColumnRenderers : function(){
32425 var renderers = [];
32426 var cm = this.grid.colModel;
32427 var colCount = cm.getColumnCount();
32428 for(var i = 0; i < colCount; i++){
32429 renderers[i] = cm.getRenderer(i);
32434 getColumnIds : function(){
32436 var cm = this.grid.colModel;
32437 var colCount = cm.getColumnCount();
32438 for(var i = 0; i < colCount; i++){
32439 ids[i] = cm.getColumnId(i);
32444 getDataIndexes : function(){
32445 if(!this.indexMap){
32446 this.indexMap = this.buildIndexMap();
32448 return this.indexMap.colToData;
32451 getColumnIndexByDataIndex : function(dataIndex){
32452 if(!this.indexMap){
32453 this.indexMap = this.buildIndexMap();
32455 return this.indexMap.dataToCol[dataIndex];
32459 * Set a css style for a column dynamically.
32460 * @param {Number} colIndex The index of the column
32461 * @param {String} name The css property name
32462 * @param {String} value The css value
32464 setCSSStyle : function(colIndex, name, value){
32465 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
32466 Roo.util.CSS.updateRule(selector, name, value);
32469 generateRules : function(cm){
32470 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
32471 Roo.util.CSS.removeStyleSheet(rulesId);
32472 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
32473 var cid = cm.getColumnId(i);
32474 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
32475 this.tdSelector, cid, " {\n}\n",
32476 this.hdSelector, cid, " {\n}\n",
32477 this.splitSelector, cid, " {\n}\n");
32479 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
32483 * Ext JS Library 1.1.1
32484 * Copyright(c) 2006-2007, Ext JS, LLC.
32486 * Originally Released Under LGPL - original licence link has changed is not relivant.
32489 * <script type="text/javascript">
32493 // This is a support class used internally by the Grid components
32494 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
32496 this.view = grid.getView();
32497 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32498 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
32500 this.setHandleElId(Roo.id(hd));
32501 this.setOuterHandleElId(Roo.id(hd2));
32503 this.scroll = false;
32505 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
32507 getDragData : function(e){
32508 var t = Roo.lib.Event.getTarget(e);
32509 var h = this.view.findHeaderCell(t);
32511 return {ddel: h.firstChild, header:h};
32516 onInitDrag : function(e){
32517 this.view.headersDisabled = true;
32518 var clone = this.dragData.ddel.cloneNode(true);
32519 clone.id = Roo.id();
32520 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
32521 this.proxy.update(clone);
32525 afterValidDrop : function(){
32527 setTimeout(function(){
32528 v.headersDisabled = false;
32532 afterInvalidDrop : function(){
32534 setTimeout(function(){
32535 v.headersDisabled = false;
32541 * Ext JS Library 1.1.1
32542 * Copyright(c) 2006-2007, Ext JS, LLC.
32544 * Originally Released Under LGPL - original licence link has changed is not relivant.
32547 * <script type="text/javascript">
32550 // This is a support class used internally by the Grid components
32551 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
32553 this.view = grid.getView();
32554 // split the proxies so they don't interfere with mouse events
32555 this.proxyTop = Roo.DomHelper.append(document.body, {
32556 cls:"col-move-top", html:" "
32558 this.proxyBottom = Roo.DomHelper.append(document.body, {
32559 cls:"col-move-bottom", html:" "
32561 this.proxyTop.hide = this.proxyBottom.hide = function(){
32562 this.setLeftTop(-100,-100);
32563 this.setStyle("visibility", "hidden");
32565 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
32566 // temporarily disabled
32567 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
32568 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
32570 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
32571 proxyOffsets : [-4, -9],
32572 fly: Roo.Element.fly,
32574 getTargetFromEvent : function(e){
32575 var t = Roo.lib.Event.getTarget(e);
32576 var cindex = this.view.findCellIndex(t);
32577 if(cindex !== false){
32578 return this.view.getHeaderCell(cindex);
32582 nextVisible : function(h){
32583 var v = this.view, cm = this.grid.colModel;
32586 if(!cm.isHidden(v.getCellIndex(h))){
32594 prevVisible : function(h){
32595 var v = this.view, cm = this.grid.colModel;
32598 if(!cm.isHidden(v.getCellIndex(h))){
32606 positionIndicator : function(h, n, e){
32607 var x = Roo.lib.Event.getPageX(e);
32608 var r = Roo.lib.Dom.getRegion(n.firstChild);
32609 var px, pt, py = r.top + this.proxyOffsets[1];
32610 if((r.right - x) <= (r.right-r.left)/2){
32611 px = r.right+this.view.borderWidth;
32617 var oldIndex = this.view.getCellIndex(h);
32618 var newIndex = this.view.getCellIndex(n);
32620 if(this.grid.colModel.isFixed(newIndex)){
32624 var locked = this.grid.colModel.isLocked(newIndex);
32629 if(oldIndex < newIndex){
32632 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
32635 px += this.proxyOffsets[0];
32636 this.proxyTop.setLeftTop(px, py);
32637 this.proxyTop.show();
32638 if(!this.bottomOffset){
32639 this.bottomOffset = this.view.mainHd.getHeight();
32641 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
32642 this.proxyBottom.show();
32646 onNodeEnter : function(n, dd, e, data){
32647 if(data.header != n){
32648 this.positionIndicator(data.header, n, e);
32652 onNodeOver : function(n, dd, e, data){
32653 var result = false;
32654 if(data.header != n){
32655 result = this.positionIndicator(data.header, n, e);
32658 this.proxyTop.hide();
32659 this.proxyBottom.hide();
32661 return result ? this.dropAllowed : this.dropNotAllowed;
32664 onNodeOut : function(n, dd, e, data){
32665 this.proxyTop.hide();
32666 this.proxyBottom.hide();
32669 onNodeDrop : function(n, dd, e, data){
32670 var h = data.header;
32672 var cm = this.grid.colModel;
32673 var x = Roo.lib.Event.getPageX(e);
32674 var r = Roo.lib.Dom.getRegion(n.firstChild);
32675 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
32676 var oldIndex = this.view.getCellIndex(h);
32677 var newIndex = this.view.getCellIndex(n);
32678 var locked = cm.isLocked(newIndex);
32682 if(oldIndex < newIndex){
32685 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
32688 cm.setLocked(oldIndex, locked, true);
32689 cm.moveColumn(oldIndex, newIndex);
32690 this.grid.fireEvent("columnmove", oldIndex, newIndex);
32698 * Ext JS Library 1.1.1
32699 * Copyright(c) 2006-2007, Ext JS, LLC.
32701 * Originally Released Under LGPL - original licence link has changed is not relivant.
32704 * <script type="text/javascript">
32708 * @class Roo.grid.GridView
32709 * @extends Roo.util.Observable
32712 * @param {Object} config
32714 Roo.grid.GridView = function(config){
32715 Roo.grid.GridView.superclass.constructor.call(this);
32718 Roo.apply(this, config);
32721 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
32724 * Override this function to apply custom css classes to rows during rendering
32725 * @param {Record} record The record
32726 * @param {Number} index
32727 * @method getRowClass
32729 rowClass : "x-grid-row",
32731 cellClass : "x-grid-col",
32733 tdClass : "x-grid-td",
32735 hdClass : "x-grid-hd",
32737 splitClass : "x-grid-split",
32739 sortClasses : ["sort-asc", "sort-desc"],
32741 enableMoveAnim : false,
32745 dh : Roo.DomHelper,
32747 fly : Roo.Element.fly,
32749 css : Roo.util.CSS,
32755 scrollIncrement : 22,
32757 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
32759 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
32761 bind : function(ds, cm){
32763 this.ds.un("load", this.onLoad, this);
32764 this.ds.un("datachanged", this.onDataChange, this);
32765 this.ds.un("add", this.onAdd, this);
32766 this.ds.un("remove", this.onRemove, this);
32767 this.ds.un("update", this.onUpdate, this);
32768 this.ds.un("clear", this.onClear, this);
32771 ds.on("load", this.onLoad, this);
32772 ds.on("datachanged", this.onDataChange, this);
32773 ds.on("add", this.onAdd, this);
32774 ds.on("remove", this.onRemove, this);
32775 ds.on("update", this.onUpdate, this);
32776 ds.on("clear", this.onClear, this);
32781 this.cm.un("widthchange", this.onColWidthChange, this);
32782 this.cm.un("headerchange", this.onHeaderChange, this);
32783 this.cm.un("hiddenchange", this.onHiddenChange, this);
32784 this.cm.un("columnmoved", this.onColumnMove, this);
32785 this.cm.un("columnlockchange", this.onColumnLock, this);
32788 this.generateRules(cm);
32789 cm.on("widthchange", this.onColWidthChange, this);
32790 cm.on("headerchange", this.onHeaderChange, this);
32791 cm.on("hiddenchange", this.onHiddenChange, this);
32792 cm.on("columnmoved", this.onColumnMove, this);
32793 cm.on("columnlockchange", this.onColumnLock, this);
32798 init: function(grid){
32799 Roo.grid.GridView.superclass.init.call(this, grid);
32801 this.bind(grid.dataSource, grid.colModel);
32803 grid.on("headerclick", this.handleHeaderClick, this);
32805 if(grid.trackMouseOver){
32806 grid.on("mouseover", this.onRowOver, this);
32807 grid.on("mouseout", this.onRowOut, this);
32809 grid.cancelTextSelection = function(){};
32810 this.gridId = grid.id;
32812 var tpls = this.templates || {};
32815 tpls.master = new Roo.Template(
32816 '<div class="x-grid" hidefocus="true">',
32817 '<div class="x-grid-topbar"></div>',
32818 '<div class="x-grid-scroller"><div></div></div>',
32819 '<div class="x-grid-locked">',
32820 '<div class="x-grid-header">{lockedHeader}</div>',
32821 '<div class="x-grid-body">{lockedBody}</div>',
32823 '<div class="x-grid-viewport">',
32824 '<div class="x-grid-header">{header}</div>',
32825 '<div class="x-grid-body">{body}</div>',
32827 '<div class="x-grid-bottombar"></div>',
32828 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
32829 '<div class="x-grid-resize-proxy"> </div>',
32832 tpls.master.disableformats = true;
32836 tpls.header = new Roo.Template(
32837 '<table border="0" cellspacing="0" cellpadding="0">',
32838 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
32841 tpls.header.disableformats = true;
32843 tpls.header.compile();
32846 tpls.hcell = new Roo.Template(
32847 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
32848 '<div class="x-grid-hd-text" unselectable="on">{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
32851 tpls.hcell.disableFormats = true;
32853 tpls.hcell.compile();
32856 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style}" unselectable="on"> </div>');
32857 tpls.hsplit.disableFormats = true;
32859 tpls.hsplit.compile();
32862 tpls.body = new Roo.Template(
32863 '<table border="0" cellspacing="0" cellpadding="0">',
32864 "<tbody>{rows}</tbody>",
32867 tpls.body.disableFormats = true;
32869 tpls.body.compile();
32872 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
32873 tpls.row.disableFormats = true;
32875 tpls.row.compile();
32878 tpls.cell = new Roo.Template(
32879 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
32880 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text" unselectable="on" {attr}>{value}</div></div>',
32883 tpls.cell.disableFormats = true;
32885 tpls.cell.compile();
32887 this.templates = tpls;
32890 // remap these for backwards compat
32891 onColWidthChange : function(){
32892 this.updateColumns.apply(this, arguments);
32894 onHeaderChange : function(){
32895 this.updateHeaders.apply(this, arguments);
32897 onHiddenChange : function(){
32898 this.handleHiddenChange.apply(this, arguments);
32900 onColumnMove : function(){
32901 this.handleColumnMove.apply(this, arguments);
32903 onColumnLock : function(){
32904 this.handleLockChange.apply(this, arguments);
32907 onDataChange : function(){
32909 this.updateHeaderSortState();
32912 onClear : function(){
32916 onUpdate : function(ds, record){
32917 this.refreshRow(record);
32920 refreshRow : function(record){
32921 var ds = this.ds, index;
32922 if(typeof record == 'number'){
32924 record = ds.getAt(index);
32926 index = ds.indexOf(record);
32928 this.insertRows(ds, index, index, true);
32929 this.onRemove(ds, record, index+1, true);
32930 this.syncRowHeights(index, index);
32932 this.fireEvent("rowupdated", this, index, record);
32935 onAdd : function(ds, records, index){
32936 this.insertRows(ds, index, index + (records.length-1));
32939 onRemove : function(ds, record, index, isUpdate){
32940 if(isUpdate !== true){
32941 this.fireEvent("beforerowremoved", this, index, record);
32943 var bt = this.getBodyTable(), lt = this.getLockedTable();
32944 if(bt.rows[index]){
32945 bt.firstChild.removeChild(bt.rows[index]);
32947 if(lt.rows[index]){
32948 lt.firstChild.removeChild(lt.rows[index]);
32950 if(isUpdate !== true){
32951 this.stripeRows(index);
32952 this.syncRowHeights(index, index);
32954 this.fireEvent("rowremoved", this, index, record);
32958 onLoad : function(){
32959 this.scrollToTop();
32963 * Scrolls the grid to the top
32965 scrollToTop : function(){
32967 this.scroller.dom.scrollTop = 0;
32973 * Gets a panel in the header 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 header is hidden. Pass true to show the panel
32977 * @return Roo.Element
32979 getHeaderPanel : function(doShow){
32981 this.headerPanel.show();
32983 return this.headerPanel;
32987 * Gets a panel in the footer of the grid that can be used for toolbars etc.
32988 * After modifying the contents of this panel a call to grid.autoSize() may be
32989 * required to register any changes in size.
32990 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
32991 * @return Roo.Element
32993 getFooterPanel : function(doShow){
32995 this.footerPanel.show();
32997 return this.footerPanel;
33000 initElements : function(){
33001 var E = Roo.Element;
33002 var el = this.grid.getGridEl().dom.firstChild;
33003 var cs = el.childNodes;
33005 this.el = new E(el);
33006 this.headerPanel = new E(el.firstChild);
33007 this.headerPanel.enableDisplayMode("block");
33009 this.scroller = new E(cs[1]);
33010 this.scrollSizer = new E(this.scroller.dom.firstChild);
33012 this.lockedWrap = new E(cs[2]);
33013 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
33014 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
33016 this.mainWrap = new E(cs[3]);
33017 this.mainHd = new E(this.mainWrap.dom.firstChild);
33018 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
33020 this.footerPanel = new E(cs[4]);
33021 this.footerPanel.enableDisplayMode("block");
33023 this.focusEl = new E(cs[5]);
33024 this.focusEl.swallowEvent("click", true);
33025 this.resizeProxy = new E(cs[6]);
33027 this.headerSelector = String.format(
33028 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
33029 this.lockedHd.id, this.mainHd.id
33032 this.splitterSelector = String.format(
33033 '#{0} div.x-grid-split, #{1} div.x-grid-split',
33034 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
33037 idToCssName : function(s)
33039 return s.replace(/[^a-z0-9]+/ig, '-');
33042 getHeaderCell : function(index){
33043 return Roo.DomQuery.select(this.headerSelector)[index];
33046 getHeaderCellMeasure : function(index){
33047 return this.getHeaderCell(index).firstChild;
33050 getHeaderCellText : function(index){
33051 return this.getHeaderCell(index).firstChild.firstChild;
33054 getLockedTable : function(){
33055 return this.lockedBody.dom.firstChild;
33058 getBodyTable : function(){
33059 return this.mainBody.dom.firstChild;
33062 getLockedRow : function(index){
33063 return this.getLockedTable().rows[index];
33066 getRow : function(index){
33067 return this.getBodyTable().rows[index];
33070 getRowComposite : function(index){
33072 this.rowEl = new Roo.CompositeElementLite();
33074 var els = [], lrow, mrow;
33075 if(lrow = this.getLockedRow(index)){
33078 if(mrow = this.getRow(index)){
33081 this.rowEl.elements = els;
33085 getCell : function(rowIndex, colIndex){
33086 var locked = this.cm.getLockedCount();
33088 if(colIndex < locked){
33089 source = this.lockedBody.dom.firstChild;
33091 source = this.mainBody.dom.firstChild;
33092 colIndex -= locked;
33094 return source.rows[rowIndex].childNodes[colIndex];
33097 getCellText : function(rowIndex, colIndex){
33098 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
33101 getCellBox : function(cell){
33102 var b = this.fly(cell).getBox();
33103 if(Roo.isOpera){ // opera fails to report the Y
33104 b.y = cell.offsetTop + this.mainBody.getY();
33109 getCellIndex : function(cell){
33110 var id = String(cell.className).match(this.cellRE);
33112 return parseInt(id[1], 10);
33117 findHeaderIndex : function(n){
33118 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33119 return r ? this.getCellIndex(r) : false;
33122 findHeaderCell : function(n){
33123 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
33124 return r ? r : false;
33127 findRowIndex : function(n){
33131 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
33132 return r ? r.rowIndex : false;
33135 findCellIndex : function(node){
33136 var stop = this.el.dom;
33137 while(node && node != stop){
33138 if(this.findRE.test(node.className)){
33139 return this.getCellIndex(node);
33141 node = node.parentNode;
33146 getColumnId : function(index){
33147 return this.cm.getColumnId(index);
33150 getSplitters : function(){
33151 if(this.splitterSelector){
33152 return Roo.DomQuery.select(this.splitterSelector);
33158 getSplitter : function(index){
33159 return this.getSplitters()[index];
33162 onRowOver : function(e, t){
33164 if((row = this.findRowIndex(t)) !== false){
33165 this.getRowComposite(row).addClass("x-grid-row-over");
33169 onRowOut : function(e, t){
33171 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
33172 this.getRowComposite(row).removeClass("x-grid-row-over");
33176 renderHeaders : function(){
33178 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
33179 var cb = [], lb = [], sb = [], lsb = [], p = {};
33180 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33181 p.cellId = "x-grid-hd-0-" + i;
33182 p.splitId = "x-grid-csplit-0-" + i;
33183 p.id = cm.getColumnId(i);
33184 p.title = cm.getColumnTooltip(i) || "";
33185 p.value = cm.getColumnHeader(i) || "";
33186 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
33187 if(!cm.isLocked(i)){
33188 cb[cb.length] = ct.apply(p);
33189 sb[sb.length] = st.apply(p);
33191 lb[lb.length] = ct.apply(p);
33192 lsb[lsb.length] = st.apply(p);
33195 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
33196 ht.apply({cells: cb.join(""), splits:sb.join("")})];
33199 updateHeaders : function(){
33200 var html = this.renderHeaders();
33201 this.lockedHd.update(html[0]);
33202 this.mainHd.update(html[1]);
33206 * Focuses the specified row.
33207 * @param {Number} row The row index
33209 focusRow : function(row){
33210 var x = this.scroller.dom.scrollLeft;
33211 this.focusCell(row, 0, false);
33212 this.scroller.dom.scrollLeft = x;
33216 * Focuses the specified cell.
33217 * @param {Number} row The row index
33218 * @param {Number} col The column index
33219 * @param {Boolean} hscroll false to disable horizontal scrolling
33221 focusCell : function(row, col, hscroll){
33222 var el = this.ensureVisible(row, col, hscroll);
33223 this.focusEl.alignTo(el, "tl-tl");
33225 this.focusEl.focus();
33227 this.focusEl.focus.defer(1, this.focusEl);
33232 * Scrolls the specified cell into view
33233 * @param {Number} row The row index
33234 * @param {Number} col The column index
33235 * @param {Boolean} hscroll false to disable horizontal scrolling
33237 ensureVisible : function(row, col, hscroll){
33238 if(typeof row != "number"){
33239 row = row.rowIndex;
33241 if(row < 0 && row >= this.ds.getCount()){
33244 col = (col !== undefined ? col : 0);
33245 var cm = this.grid.colModel;
33246 while(cm.isHidden(col)){
33250 var el = this.getCell(row, col);
33254 var c = this.scroller.dom;
33256 var ctop = parseInt(el.offsetTop, 10);
33257 var cleft = parseInt(el.offsetLeft, 10);
33258 var cbot = ctop + el.offsetHeight;
33259 var cright = cleft + el.offsetWidth;
33261 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
33262 var stop = parseInt(c.scrollTop, 10);
33263 var sleft = parseInt(c.scrollLeft, 10);
33264 var sbot = stop + ch;
33265 var sright = sleft + c.clientWidth;
33268 c.scrollTop = ctop;
33269 }else if(cbot > sbot){
33270 c.scrollTop = cbot-ch;
33273 if(hscroll !== false){
33275 c.scrollLeft = cleft;
33276 }else if(cright > sright){
33277 c.scrollLeft = cright-c.clientWidth;
33283 updateColumns : function(){
33284 this.grid.stopEditing();
33285 var cm = this.grid.colModel, colIds = this.getColumnIds();
33286 //var totalWidth = cm.getTotalWidth();
33288 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33289 //if(cm.isHidden(i)) continue;
33290 var w = cm.getColumnWidth(i);
33291 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33292 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
33294 this.updateSplitters();
33297 generateRules : function(cm){
33298 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
33299 Roo.util.CSS.removeStyleSheet(rulesId);
33300 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33301 var cid = cm.getColumnId(i);
33303 if(cm.config[i].align){
33304 align = 'text-align:'+cm.config[i].align+';';
33307 if(cm.isHidden(i)){
33308 hidden = 'display:none;';
33310 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
33312 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
33313 this.hdSelector, cid, " {\n", align, width, "}\n",
33314 this.tdSelector, cid, " {\n",hidden,"\n}\n",
33315 this.splitSelector, cid, " {\n", hidden , "\n}\n");
33317 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
33320 updateSplitters : function(){
33321 var cm = this.cm, s = this.getSplitters();
33322 if(s){ // splitters not created yet
33323 var pos = 0, locked = true;
33324 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
33325 if(cm.isHidden(i)) continue;
33326 var w = cm.getColumnWidth(i);
33327 if(!cm.isLocked(i) && locked){
33332 s[i].style.left = (pos-this.splitOffset) + "px";
33337 handleHiddenChange : function(colModel, colIndex, hidden){
33339 this.hideColumn(colIndex);
33341 this.unhideColumn(colIndex);
33345 hideColumn : function(colIndex){
33346 var cid = this.getColumnId(colIndex);
33347 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
33348 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
33350 this.updateHeaders();
33352 this.updateSplitters();
33356 unhideColumn : function(colIndex){
33357 var cid = this.getColumnId(colIndex);
33358 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
33359 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
33362 this.updateHeaders();
33364 this.updateSplitters();
33368 insertRows : function(dm, firstRow, lastRow, isUpdate){
33369 if(firstRow == 0 && lastRow == dm.getCount()-1){
33373 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
33375 var s = this.getScrollState();
33376 var markup = this.renderRows(firstRow, lastRow);
33377 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
33378 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
33379 this.restoreScroll(s);
33381 this.fireEvent("rowsinserted", this, firstRow, lastRow);
33382 this.syncRowHeights(firstRow, lastRow);
33383 this.stripeRows(firstRow);
33389 bufferRows : function(markup, target, index){
33390 var before = null, trows = target.rows, tbody = target.tBodies[0];
33391 if(index < trows.length){
33392 before = trows[index];
33394 var b = document.createElement("div");
33395 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
33396 var rows = b.firstChild.rows;
33397 for(var i = 0, len = rows.length; i < len; i++){
33399 tbody.insertBefore(rows[0], before);
33401 tbody.appendChild(rows[0]);
33408 deleteRows : function(dm, firstRow, lastRow){
33409 if(dm.getRowCount()<1){
33410 this.fireEvent("beforerefresh", this);
33411 this.mainBody.update("");
33412 this.lockedBody.update("");
33413 this.fireEvent("refresh", this);
33415 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
33416 var bt = this.getBodyTable();
33417 var tbody = bt.firstChild;
33418 var rows = bt.rows;
33419 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
33420 tbody.removeChild(rows[firstRow]);
33422 this.stripeRows(firstRow);
33423 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
33427 updateRows : function(dataSource, firstRow, lastRow){
33428 var s = this.getScrollState();
33430 this.restoreScroll(s);
33433 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
33437 this.updateHeaderSortState();
33440 getScrollState : function(){
33441 var sb = this.scroller.dom;
33442 return {left: sb.scrollLeft, top: sb.scrollTop};
33445 stripeRows : function(startRow){
33446 if(!this.grid.stripeRows || this.ds.getCount() < 1){
33449 startRow = startRow || 0;
33450 var rows = this.getBodyTable().rows;
33451 var lrows = this.getLockedTable().rows;
33452 var cls = ' x-grid-row-alt ';
33453 for(var i = startRow, len = rows.length; i < len; i++){
33454 var row = rows[i], lrow = lrows[i];
33455 var isAlt = ((i+1) % 2 == 0);
33456 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
33457 if(isAlt == hasAlt){
33461 row.className += " x-grid-row-alt";
33463 row.className = row.className.replace("x-grid-row-alt", "");
33466 lrow.className = row.className;
33471 restoreScroll : function(state){
33472 var sb = this.scroller.dom;
33473 sb.scrollLeft = state.left;
33474 sb.scrollTop = state.top;
33478 syncScroll : function(){
33479 var sb = this.scroller.dom;
33480 var sh = this.mainHd.dom;
33481 var bs = this.mainBody.dom;
33482 var lv = this.lockedBody.dom;
33483 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
33484 lv.scrollTop = bs.scrollTop = sb.scrollTop;
33487 handleScroll : function(e){
33489 var sb = this.scroller.dom;
33490 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
33494 handleWheel : function(e){
33495 var d = e.getWheelDelta();
33496 this.scroller.dom.scrollTop -= d*22;
33497 // set this here to prevent jumpy scrolling on large tables
33498 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
33502 renderRows : function(startRow, endRow){
33503 // pull in all the crap needed to render rows
33504 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
33505 var colCount = cm.getColumnCount();
33507 if(ds.getCount() < 1){
33511 // build a map for all the columns
33513 for(var i = 0; i < colCount; i++){
33514 var name = cm.getDataIndex(i);
33516 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
33517 renderer : cm.getRenderer(i),
33518 id : cm.getColumnId(i),
33519 locked : cm.isLocked(i)
33523 startRow = startRow || 0;
33524 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
33526 // records to render
33527 var rs = ds.getRange(startRow, endRow);
33529 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
33532 // As much as I hate to duplicate code, this was branched because FireFox really hates
33533 // [].join("") on strings. The performance difference was substantial enough to
33534 // branch this function
33535 doRender : Roo.isGecko ?
33536 function(cs, rs, ds, startRow, colCount, stripe){
33537 var ts = this.templates, ct = ts.cell, rt = ts.row;
33539 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33540 for(var j = 0, len = rs.length; j < len; j++){
33541 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
33542 for(var i = 0; i < colCount; i++){
33544 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33546 p.css = p.attr = "";
33547 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33548 if(p.value == undefined || p.value === "") p.value = " ";
33549 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33550 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33552 var markup = ct.apply(p);
33560 if(stripe && ((rowIndex+1) % 2 == 0)){
33561 alt[0] = "x-grid-row-alt";
33564 alt[1] = " x-grid-dirty-row";
33567 if(this.getRowClass){
33568 alt[2] = this.getRowClass(r, rowIndex);
33570 rp.alt = alt.join(" ");
33571 lbuf+= rt.apply(rp);
33573 buf+= rt.apply(rp);
33575 return [lbuf, buf];
33577 function(cs, rs, ds, startRow, colCount, stripe){
33578 var ts = this.templates, ct = ts.cell, rt = ts.row;
33580 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
33581 for(var j = 0, len = rs.length; j < len; j++){
33582 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
33583 for(var i = 0; i < colCount; i++){
33585 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
33587 p.css = p.attr = "";
33588 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
33589 if(p.value == undefined || p.value === "") p.value = " ";
33590 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
33591 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
33593 var markup = ct.apply(p);
33595 cb[cb.length] = markup;
33597 lcb[lcb.length] = markup;
33601 if(stripe && ((rowIndex+1) % 2 == 0)){
33602 alt[0] = "x-grid-row-alt";
33605 alt[1] = " x-grid-dirty-row";
33608 if(this.getRowClass){
33609 alt[2] = this.getRowClass(r, rowIndex);
33611 rp.alt = alt.join(" ");
33612 rp.cells = lcb.join("");
33613 lbuf[lbuf.length] = rt.apply(rp);
33614 rp.cells = cb.join("");
33615 buf[buf.length] = rt.apply(rp);
33617 return [lbuf.join(""), buf.join("")];
33620 renderBody : function(){
33621 var markup = this.renderRows();
33622 var bt = this.templates.body;
33623 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
33627 * Refreshes the grid
33628 * @param {Boolean} headersToo
33630 refresh : function(headersToo){
33631 this.fireEvent("beforerefresh", this);
33632 this.grid.stopEditing();
33633 var result = this.renderBody();
33634 this.lockedBody.update(result[0]);
33635 this.mainBody.update(result[1]);
33636 if(headersToo === true){
33637 this.updateHeaders();
33638 this.updateColumns();
33639 this.updateSplitters();
33640 this.updateHeaderSortState();
33642 this.syncRowHeights();
33644 this.fireEvent("refresh", this);
33647 handleColumnMove : function(cm, oldIndex, newIndex){
33648 this.indexMap = null;
33649 var s = this.getScrollState();
33650 this.refresh(true);
33651 this.restoreScroll(s);
33652 this.afterMove(newIndex);
33655 afterMove : function(colIndex){
33656 if(this.enableMoveAnim && Roo.enableFx){
33657 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
33661 updateCell : function(dm, rowIndex, dataIndex){
33662 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
33663 if(typeof colIndex == "undefined"){ // not present in grid
33666 var cm = this.grid.colModel;
33667 var cell = this.getCell(rowIndex, colIndex);
33668 var cellText = this.getCellText(rowIndex, colIndex);
33671 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
33672 id : cm.getColumnId(colIndex),
33673 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
33675 var renderer = cm.getRenderer(colIndex);
33676 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
33677 if(typeof val == "undefined" || val === "") val = " ";
33678 cellText.innerHTML = val;
33679 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
33680 this.syncRowHeights(rowIndex, rowIndex);
33683 calcColumnWidth : function(colIndex, maxRowsToMeasure){
33685 if(this.grid.autoSizeHeaders){
33686 var h = this.getHeaderCellMeasure(colIndex);
33687 maxWidth = Math.max(maxWidth, h.scrollWidth);
33690 if(this.cm.isLocked(colIndex)){
33691 tb = this.getLockedTable();
33694 tb = this.getBodyTable();
33695 index = colIndex - this.cm.getLockedCount();
33698 var rows = tb.rows;
33699 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
33700 for(var i = 0; i < stopIndex; i++){
33701 var cell = rows[i].childNodes[index].firstChild;
33702 maxWidth = Math.max(maxWidth, cell.scrollWidth);
33705 return maxWidth + /*margin for error in IE*/ 5;
33708 * Autofit a column to its content.
33709 * @param {Number} colIndex
33710 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
33712 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
33713 if(this.cm.isHidden(colIndex)){
33714 return; // can't calc a hidden column
33717 var cid = this.cm.getColumnId(colIndex);
33718 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
33719 if(this.grid.autoSizeHeaders){
33720 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
33723 var newWidth = this.calcColumnWidth(colIndex);
33724 this.cm.setColumnWidth(colIndex,
33725 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
33726 if(!suppressEvent){
33727 this.grid.fireEvent("columnresize", colIndex, newWidth);
33732 * Autofits all columns to their content and then expands to fit any extra space in the grid
33734 autoSizeColumns : function(){
33735 var cm = this.grid.colModel;
33736 var colCount = cm.getColumnCount();
33737 for(var i = 0; i < colCount; i++){
33738 this.autoSizeColumn(i, true, true);
33740 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
33743 this.updateColumns();
33749 * Autofits all columns to the grid's width proportionate with their current size
33750 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
33752 fitColumns : function(reserveScrollSpace){
33753 var cm = this.grid.colModel;
33754 var colCount = cm.getColumnCount();
33758 for (i = 0; i < colCount; i++){
33759 if(!cm.isHidden(i) && !cm.isFixed(i)){
33760 w = cm.getColumnWidth(i);
33766 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
33767 if(reserveScrollSpace){
33770 var frac = (avail - cm.getTotalWidth())/width;
33771 while (cols.length){
33774 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
33776 this.updateColumns();
33780 onRowSelect : function(rowIndex){
33781 var row = this.getRowComposite(rowIndex);
33782 row.addClass("x-grid-row-selected");
33785 onRowDeselect : function(rowIndex){
33786 var row = this.getRowComposite(rowIndex);
33787 row.removeClass("x-grid-row-selected");
33790 onCellSelect : function(row, col){
33791 var cell = this.getCell(row, col);
33793 Roo.fly(cell).addClass("x-grid-cell-selected");
33797 onCellDeselect : function(row, col){
33798 var cell = this.getCell(row, col);
33800 Roo.fly(cell).removeClass("x-grid-cell-selected");
33804 updateHeaderSortState : function(){
33805 var state = this.ds.getSortState();
33809 this.sortState = state;
33810 var sortColumn = this.cm.findColumnIndex(state.field);
33811 if(sortColumn != -1){
33812 var sortDir = state.direction;
33813 var sc = this.sortClasses;
33814 var hds = this.el.select(this.headerSelector).removeClass(sc);
33815 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
33819 handleHeaderClick : function(g, index){
33820 if(this.headersDisabled){
33823 var dm = g.dataSource, cm = g.colModel;
33824 if(!cm.isSortable(index)){
33828 dm.sort(cm.getDataIndex(index));
33832 destroy : function(){
33834 this.colMenu.removeAll();
33835 Roo.menu.MenuMgr.unregister(this.colMenu);
33836 this.colMenu.getEl().remove();
33837 delete this.colMenu;
33840 this.hmenu.removeAll();
33841 Roo.menu.MenuMgr.unregister(this.hmenu);
33842 this.hmenu.getEl().remove();
33845 if(this.grid.enableColumnMove){
33846 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33848 for(var dd in dds){
33849 if(!dds[dd].config.isTarget && dds[dd].dragElId){
33850 var elid = dds[dd].dragElId;
33852 Roo.get(elid).remove();
33853 } else if(dds[dd].config.isTarget){
33854 dds[dd].proxyTop.remove();
33855 dds[dd].proxyBottom.remove();
33858 if(Roo.dd.DDM.locationCache[dd]){
33859 delete Roo.dd.DDM.locationCache[dd];
33862 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
33865 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
33866 this.bind(null, null);
33867 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
33870 handleLockChange : function(){
33871 this.refresh(true);
33874 onDenyColumnLock : function(){
33878 onDenyColumnHide : function(){
33882 handleHdMenuClick : function(item){
33883 var index = this.hdCtxIndex;
33884 var cm = this.cm, ds = this.ds;
33887 ds.sort(cm.getDataIndex(index), "ASC");
33890 ds.sort(cm.getDataIndex(index), "DESC");
33893 var lc = cm.getLockedCount();
33894 if(cm.getColumnCount(true) <= lc+1){
33895 this.onDenyColumnLock();
33899 cm.setLocked(index, true, true);
33900 cm.moveColumn(index, lc);
33901 this.grid.fireEvent("columnmove", index, lc);
33903 cm.setLocked(index, true);
33907 var lc = cm.getLockedCount();
33908 if((lc-1) != index){
33909 cm.setLocked(index, false, true);
33910 cm.moveColumn(index, lc-1);
33911 this.grid.fireEvent("columnmove", index, lc-1);
33913 cm.setLocked(index, false);
33917 index = cm.getIndexById(item.id.substr(4));
33919 if(item.checked && cm.getColumnCount(true) <= 1){
33920 this.onDenyColumnHide();
33923 cm.setHidden(index, item.checked);
33929 beforeColMenuShow : function(){
33930 var cm = this.cm, colCount = cm.getColumnCount();
33931 this.colMenu.removeAll();
33932 for(var i = 0; i < colCount; i++){
33933 this.colMenu.add(new Roo.menu.CheckItem({
33934 id: "col-"+cm.getColumnId(i),
33935 text: cm.getColumnHeader(i),
33936 checked: !cm.isHidden(i),
33942 handleHdCtx : function(g, index, e){
33944 var hd = this.getHeaderCell(index);
33945 this.hdCtxIndex = index;
33946 var ms = this.hmenu.items, cm = this.cm;
33947 ms.get("asc").setDisabled(!cm.isSortable(index));
33948 ms.get("desc").setDisabled(!cm.isSortable(index));
33949 if(this.grid.enableColLock !== false){
33950 ms.get("lock").setDisabled(cm.isLocked(index));
33951 ms.get("unlock").setDisabled(!cm.isLocked(index));
33953 this.hmenu.show(hd, "tl-bl");
33956 handleHdOver : function(e){
33957 var hd = this.findHeaderCell(e.getTarget());
33958 if(hd && !this.headersDisabled){
33959 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
33960 this.fly(hd).addClass("x-grid-hd-over");
33965 handleHdOut : function(e){
33966 var hd = this.findHeaderCell(e.getTarget());
33968 this.fly(hd).removeClass("x-grid-hd-over");
33972 handleSplitDblClick : function(e, t){
33973 var i = this.getCellIndex(t);
33974 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
33975 this.autoSizeColumn(i, true);
33980 render : function(){
33983 var colCount = cm.getColumnCount();
33985 if(this.grid.monitorWindowResize === true){
33986 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
33988 var header = this.renderHeaders();
33989 var body = this.templates.body.apply({rows:""});
33990 var html = this.templates.master.apply({
33993 lockedHeader: header[0],
33997 //this.updateColumns();
33999 this.grid.getGridEl().dom.innerHTML = html;
34001 this.initElements();
34003 // a kludge to fix the random scolling effect in webkit
34004 this.el.on("scroll", function() {
34005 this.el.dom.scrollTop=0; // hopefully not recursive..
34008 this.scroller.on("scroll", this.handleScroll, this);
34009 this.lockedBody.on("mousewheel", this.handleWheel, this);
34010 this.mainBody.on("mousewheel", this.handleWheel, this);
34012 this.mainHd.on("mouseover", this.handleHdOver, this);
34013 this.mainHd.on("mouseout", this.handleHdOut, this);
34014 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
34015 {delegate: "."+this.splitClass});
34017 this.lockedHd.on("mouseover", this.handleHdOver, this);
34018 this.lockedHd.on("mouseout", this.handleHdOut, this);
34019 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
34020 {delegate: "."+this.splitClass});
34022 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
34023 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34026 this.updateSplitters();
34028 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
34029 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34030 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
34033 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
34034 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
34036 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
34037 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
34039 if(this.grid.enableColLock !== false){
34040 this.hmenu.add('-',
34041 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
34042 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
34045 if(this.grid.enableColumnHide !== false){
34047 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
34048 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
34049 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
34051 this.hmenu.add('-',
34052 {id:"columns", text: this.columnsText, menu: this.colMenu}
34055 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
34057 this.grid.on("headercontextmenu", this.handleHdCtx, this);
34060 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
34061 this.dd = new Roo.grid.GridDragZone(this.grid, {
34062 ddGroup : this.grid.ddGroup || 'GridDD'
34067 for(var i = 0; i < colCount; i++){
34068 if(cm.isHidden(i)){
34069 this.hideColumn(i);
34071 if(cm.config[i].align){
34072 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
34073 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
34077 this.updateHeaderSortState();
34079 this.beforeInitialResize();
34082 // two part rendering gives faster view to the user
34083 this.renderPhase2.defer(1, this);
34086 renderPhase2 : function(){
34087 // render the rows now
34089 if(this.grid.autoSizeColumns){
34090 this.autoSizeColumns();
34094 beforeInitialResize : function(){
34098 onColumnSplitterMoved : function(i, w){
34099 this.userResized = true;
34100 var cm = this.grid.colModel;
34101 cm.setColumnWidth(i, w, true);
34102 var cid = cm.getColumnId(i);
34103 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34104 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
34105 this.updateSplitters();
34107 this.grid.fireEvent("columnresize", i, w);
34110 syncRowHeights : function(startIndex, endIndex){
34111 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
34112 startIndex = startIndex || 0;
34113 var mrows = this.getBodyTable().rows;
34114 var lrows = this.getLockedTable().rows;
34115 var len = mrows.length-1;
34116 endIndex = Math.min(endIndex || len, len);
34117 for(var i = startIndex; i <= endIndex; i++){
34118 var m = mrows[i], l = lrows[i];
34119 var h = Math.max(m.offsetHeight, l.offsetHeight);
34120 m.style.height = l.style.height = h + "px";
34125 layout : function(initialRender, is2ndPass){
34127 var auto = g.autoHeight;
34128 var scrollOffset = 16;
34129 var c = g.getGridEl(), cm = this.cm,
34130 expandCol = g.autoExpandColumn,
34132 //c.beginMeasure();
34134 if(!c.dom.offsetWidth){ // display:none?
34136 this.lockedWrap.show();
34137 this.mainWrap.show();
34142 var hasLock = this.cm.isLocked(0);
34144 var tbh = this.headerPanel.getHeight();
34145 var bbh = this.footerPanel.getHeight();
34148 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
34149 var newHeight = ch + c.getBorderWidth("tb");
34151 newHeight = Math.min(g.maxHeight, newHeight);
34153 c.setHeight(newHeight);
34157 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
34160 var s = this.scroller;
34162 var csize = c.getSize(true);
34164 this.el.setSize(csize.width, csize.height);
34166 this.headerPanel.setWidth(csize.width);
34167 this.footerPanel.setWidth(csize.width);
34169 var hdHeight = this.mainHd.getHeight();
34170 var vw = csize.width;
34171 var vh = csize.height - (tbh + bbh);
34175 var bt = this.getBodyTable();
34176 var ltWidth = hasLock ?
34177 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
34179 var scrollHeight = bt.offsetHeight;
34180 var scrollWidth = ltWidth + bt.offsetWidth;
34181 var vscroll = false, hscroll = false;
34183 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
34185 var lw = this.lockedWrap, mw = this.mainWrap;
34186 var lb = this.lockedBody, mb = this.mainBody;
34188 setTimeout(function(){
34189 var t = s.dom.offsetTop;
34190 var w = s.dom.clientWidth,
34191 h = s.dom.clientHeight;
34194 lw.setSize(ltWidth, h);
34196 mw.setLeftTop(ltWidth, t);
34197 mw.setSize(w-ltWidth, h);
34199 lb.setHeight(h-hdHeight);
34200 mb.setHeight(h-hdHeight);
34202 if(is2ndPass !== true && !gv.userResized && expandCol){
34203 // high speed resize without full column calculation
34205 var ci = cm.getIndexById(expandCol);
34207 ci = cm.findColumnIndex(expandCol);
34209 ci = Math.max(0, ci); // make sure it's got at least the first col.
34210 var expandId = cm.getColumnId(ci);
34211 var tw = cm.getTotalWidth(false);
34212 var currentWidth = cm.getColumnWidth(ci);
34213 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
34214 if(currentWidth != cw){
34215 cm.setColumnWidth(ci, cw, true);
34216 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34217 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
34218 gv.updateSplitters();
34219 gv.layout(false, true);
34231 onWindowResize : function(){
34232 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
34238 appendFooter : function(parentEl){
34242 sortAscText : "Sort Ascending",
34243 sortDescText : "Sort Descending",
34244 lockText : "Lock Column",
34245 unlockText : "Unlock Column",
34246 columnsText : "Columns"
34250 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
34251 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
34252 this.proxy.el.addClass('x-grid3-col-dd');
34255 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
34256 handleMouseDown : function(e){
34260 callHandleMouseDown : function(e){
34261 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
34266 * Ext JS Library 1.1.1
34267 * Copyright(c) 2006-2007, Ext JS, LLC.
34269 * Originally Released Under LGPL - original licence link has changed is not relivant.
34272 * <script type="text/javascript">
34276 // This is a support class used internally by the Grid components
34277 Roo.grid.SplitDragZone = function(grid, hd, hd2){
34279 this.view = grid.getView();
34280 this.proxy = this.view.resizeProxy;
34281 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
34282 "gridSplitters" + this.grid.getGridEl().id, {
34283 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
34285 this.setHandleElId(Roo.id(hd));
34286 this.setOuterHandleElId(Roo.id(hd2));
34287 this.scroll = false;
34289 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
34290 fly: Roo.Element.fly,
34292 b4StartDrag : function(x, y){
34293 this.view.headersDisabled = true;
34294 this.proxy.setHeight(this.view.mainWrap.getHeight());
34295 var w = this.cm.getColumnWidth(this.cellIndex);
34296 var minw = Math.max(w-this.grid.minColumnWidth, 0);
34297 this.resetConstraints();
34298 this.setXConstraint(minw, 1000);
34299 this.setYConstraint(0, 0);
34300 this.minX = x - minw;
34301 this.maxX = x + 1000;
34303 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
34307 handleMouseDown : function(e){
34308 ev = Roo.EventObject.setEvent(e);
34309 var t = this.fly(ev.getTarget());
34310 if(t.hasClass("x-grid-split")){
34311 this.cellIndex = this.view.getCellIndex(t.dom);
34312 this.split = t.dom;
34313 this.cm = this.grid.colModel;
34314 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
34315 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
34320 endDrag : function(e){
34321 this.view.headersDisabled = false;
34322 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
34323 var diff = endX - this.startPos;
34324 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
34327 autoOffset : function(){
34328 this.setDelta(0,0);
34332 * Ext JS Library 1.1.1
34333 * Copyright(c) 2006-2007, Ext JS, LLC.
34335 * Originally Released Under LGPL - original licence link has changed is not relivant.
34338 * <script type="text/javascript">
34342 // This is a support class used internally by the Grid components
34343 Roo.grid.GridDragZone = function(grid, config){
34344 this.view = grid.getView();
34345 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
34346 if(this.view.lockedBody){
34347 this.setHandleElId(Roo.id(this.view.mainBody.dom));
34348 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
34350 this.scroll = false;
34352 this.ddel = document.createElement('div');
34353 this.ddel.className = 'x-grid-dd-wrap';
34356 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
34357 ddGroup : "GridDD",
34359 getDragData : function(e){
34360 var t = Roo.lib.Event.getTarget(e);
34361 var rowIndex = this.view.findRowIndex(t);
34362 if(rowIndex !== false){
34363 var sm = this.grid.selModel;
34364 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
34365 // sm.mouseDown(e, t);
34367 if (e.hasModifier()){
34368 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
34370 return {grid: this.grid, ddel: this.ddel, rowIndex: rowIndex, selections:sm.getSelections()};
34375 onInitDrag : function(e){
34376 var data = this.dragData;
34377 this.ddel.innerHTML = this.grid.getDragDropText();
34378 this.proxy.update(this.ddel);
34379 // fire start drag?
34382 afterRepair : function(){
34383 this.dragging = false;
34386 getRepairXY : function(e, data){
34390 onEndDrag : function(data, e){
34394 onValidDrop : function(dd, e, id){
34399 beforeInvalidDrop : function(e, id){
34404 * Ext JS Library 1.1.1
34405 * Copyright(c) 2006-2007, Ext JS, LLC.
34407 * Originally Released Under LGPL - original licence link has changed is not relivant.
34410 * <script type="text/javascript">
34415 * @class Roo.grid.ColumnModel
34416 * @extends Roo.util.Observable
34417 * This is the default implementation of a ColumnModel used by the Grid. It defines
34418 * the columns in the grid.
34421 var colModel = new Roo.grid.ColumnModel([
34422 {header: "Ticker", width: 60, sortable: true, locked: true},
34423 {header: "Company Name", width: 150, sortable: true},
34424 {header: "Market Cap.", width: 100, sortable: true},
34425 {header: "$ Sales", width: 100, sortable: true, renderer: money},
34426 {header: "Employees", width: 100, sortable: true, resizable: false}
34431 * The config options listed for this class are options which may appear in each
34432 * individual column definition.
34433 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
34435 * @param {Object} config An Array of column config objects. See this class's
34436 * config objects for details.
34438 Roo.grid.ColumnModel = function(config){
34440 * The config passed into the constructor
34442 this.config = config;
34445 // if no id, create one
34446 // if the column does not have a dataIndex mapping,
34447 // map it to the order it is in the config
34448 for(var i = 0, len = config.length; i < len; i++){
34450 if(typeof c.dataIndex == "undefined"){
34453 if(typeof c.renderer == "string"){
34454 c.renderer = Roo.util.Format[c.renderer];
34456 if(typeof c.id == "undefined"){
34459 if(c.editor && c.editor.xtype){
34460 c.editor = Roo.factory(c.editor, Roo.grid);
34462 if(c.editor && c.editor.isFormField){
34463 c.editor = new Roo.grid.GridEditor(c.editor);
34465 this.lookup[c.id] = c;
34469 * The width of columns which have no width specified (defaults to 100)
34472 this.defaultWidth = 100;
34475 * Default sortable of columns which have no sortable specified (defaults to false)
34478 this.defaultSortable = false;
34482 * @event widthchange
34483 * Fires when the width of a column changes.
34484 * @param {ColumnModel} this
34485 * @param {Number} columnIndex The column index
34486 * @param {Number} newWidth The new width
34488 "widthchange": true,
34490 * @event headerchange
34491 * Fires when the text of a header changes.
34492 * @param {ColumnModel} this
34493 * @param {Number} columnIndex The column index
34494 * @param {Number} newText The new header text
34496 "headerchange": true,
34498 * @event hiddenchange
34499 * Fires when a column is hidden or "unhidden".
34500 * @param {ColumnModel} this
34501 * @param {Number} columnIndex The column index
34502 * @param {Boolean} hidden true if hidden, false otherwise
34504 "hiddenchange": true,
34506 * @event columnmoved
34507 * Fires when a column is moved.
34508 * @param {ColumnModel} this
34509 * @param {Number} oldIndex
34510 * @param {Number} newIndex
34512 "columnmoved" : true,
34514 * @event columlockchange
34515 * Fires when a column's locked state is changed
34516 * @param {ColumnModel} this
34517 * @param {Number} colIndex
34518 * @param {Boolean} locked true if locked
34520 "columnlockchange" : true
34522 Roo.grid.ColumnModel.superclass.constructor.call(this);
34524 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
34526 * @cfg {String} header The header text to display in the Grid view.
34529 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
34530 * {@link Roo.data.Record} definition from which to draw the column's value. If not
34531 * specified, the column's index is used as an index into the Record's data Array.
34534 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
34535 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
34538 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
34539 * Defaults to the value of the {@link #defaultSortable} property.
34540 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
34543 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
34546 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
34549 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
34552 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
34555 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
34556 * given the cell's data value. See {@link #setRenderer}. If not specified, the
34557 * default renderer uses the raw data value.
34560 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
34563 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
34567 * Returns the id of the column at the specified index.
34568 * @param {Number} index The column index
34569 * @return {String} the id
34571 getColumnId : function(index){
34572 return this.config[index].id;
34576 * Returns the column for a specified id.
34577 * @param {String} id The column id
34578 * @return {Object} the column
34580 getColumnById : function(id){
34581 return this.lookup[id];
34586 * Returns the column for a specified dataIndex.
34587 * @param {String} dataIndex The column dataIndex
34588 * @return {Object|Boolean} the column or false if not found
34590 getColumnByDataIndex: function(dataIndex){
34591 var index = this.findColumnIndex(dataIndex);
34592 return index > -1 ? this.config[index] : false;
34596 * Returns the index for a specified column id.
34597 * @param {String} id The column id
34598 * @return {Number} the index, or -1 if not found
34600 getIndexById : function(id){
34601 for(var i = 0, len = this.config.length; i < len; i++){
34602 if(this.config[i].id == id){
34610 * Returns the index for a specified column dataIndex.
34611 * @param {String} dataIndex The column dataIndex
34612 * @return {Number} the index, or -1 if not found
34615 findColumnIndex : function(dataIndex){
34616 for(var i = 0, len = this.config.length; i < len; i++){
34617 if(this.config[i].dataIndex == dataIndex){
34625 moveColumn : function(oldIndex, newIndex){
34626 var c = this.config[oldIndex];
34627 this.config.splice(oldIndex, 1);
34628 this.config.splice(newIndex, 0, c);
34629 this.dataMap = null;
34630 this.fireEvent("columnmoved", this, oldIndex, newIndex);
34633 isLocked : function(colIndex){
34634 return this.config[colIndex].locked === true;
34637 setLocked : function(colIndex, value, suppressEvent){
34638 if(this.isLocked(colIndex) == value){
34641 this.config[colIndex].locked = value;
34642 if(!suppressEvent){
34643 this.fireEvent("columnlockchange", this, colIndex, value);
34647 getTotalLockedWidth : function(){
34648 var totalWidth = 0;
34649 for(var i = 0; i < this.config.length; i++){
34650 if(this.isLocked(i) && !this.isHidden(i)){
34651 this.totalWidth += this.getColumnWidth(i);
34657 getLockedCount : function(){
34658 for(var i = 0, len = this.config.length; i < len; i++){
34659 if(!this.isLocked(i)){
34666 * Returns the number of columns.
34669 getColumnCount : function(visibleOnly){
34670 if(visibleOnly === true){
34672 for(var i = 0, len = this.config.length; i < len; i++){
34673 if(!this.isHidden(i)){
34679 return this.config.length;
34683 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
34684 * @param {Function} fn
34685 * @param {Object} scope (optional)
34686 * @return {Array} result
34688 getColumnsBy : function(fn, scope){
34690 for(var i = 0, len = this.config.length; i < len; i++){
34691 var c = this.config[i];
34692 if(fn.call(scope||this, c, i) === true){
34700 * Returns true if the specified column is sortable.
34701 * @param {Number} col The column index
34702 * @return {Boolean}
34704 isSortable : function(col){
34705 if(typeof this.config[col].sortable == "undefined"){
34706 return this.defaultSortable;
34708 return this.config[col].sortable;
34712 * Returns the rendering (formatting) function defined for the column.
34713 * @param {Number} col The column index.
34714 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
34716 getRenderer : function(col){
34717 if(!this.config[col].renderer){
34718 return Roo.grid.ColumnModel.defaultRenderer;
34720 return this.config[col].renderer;
34724 * Sets the rendering (formatting) function for a column.
34725 * @param {Number} col The column index
34726 * @param {Function} fn The function to use to process the cell's raw data
34727 * to return HTML markup for the grid view. The render function is called with
34728 * the following parameters:<ul>
34729 * <li>Data value.</li>
34730 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
34731 * <li>css A CSS style string to apply to the table cell.</li>
34732 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
34733 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
34734 * <li>Row index</li>
34735 * <li>Column index</li>
34736 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
34738 setRenderer : function(col, fn){
34739 this.config[col].renderer = fn;
34743 * Returns the width for the specified column.
34744 * @param {Number} col The column index
34747 getColumnWidth : function(col){
34748 return this.config[col].width || this.defaultWidth;
34752 * Sets the width for a column.
34753 * @param {Number} col The column index
34754 * @param {Number} width The new width
34756 setColumnWidth : function(col, width, suppressEvent){
34757 this.config[col].width = width;
34758 this.totalWidth = null;
34759 if(!suppressEvent){
34760 this.fireEvent("widthchange", this, col, width);
34765 * Returns the total width of all columns.
34766 * @param {Boolean} includeHidden True to include hidden column widths
34769 getTotalWidth : function(includeHidden){
34770 if(!this.totalWidth){
34771 this.totalWidth = 0;
34772 for(var i = 0, len = this.config.length; i < len; i++){
34773 if(includeHidden || !this.isHidden(i)){
34774 this.totalWidth += this.getColumnWidth(i);
34778 return this.totalWidth;
34782 * Returns the header for the specified column.
34783 * @param {Number} col The column index
34786 getColumnHeader : function(col){
34787 return this.config[col].header;
34791 * Sets the header for a column.
34792 * @param {Number} col The column index
34793 * @param {String} header The new header
34795 setColumnHeader : function(col, header){
34796 this.config[col].header = header;
34797 this.fireEvent("headerchange", this, col, header);
34801 * Returns the tooltip for the specified column.
34802 * @param {Number} col The column index
34805 getColumnTooltip : function(col){
34806 return this.config[col].tooltip;
34809 * Sets the tooltip for a column.
34810 * @param {Number} col The column index
34811 * @param {String} tooltip The new tooltip
34813 setColumnTooltip : function(col, tooltip){
34814 this.config[col].tooltip = tooltip;
34818 * Returns the dataIndex for the specified column.
34819 * @param {Number} col The column index
34822 getDataIndex : function(col){
34823 return this.config[col].dataIndex;
34827 * Sets the dataIndex for a column.
34828 * @param {Number} col The column index
34829 * @param {Number} dataIndex The new dataIndex
34831 setDataIndex : function(col, dataIndex){
34832 this.config[col].dataIndex = dataIndex;
34838 * Returns true if the cell is editable.
34839 * @param {Number} colIndex The column index
34840 * @param {Number} rowIndex The row index
34841 * @return {Boolean}
34843 isCellEditable : function(colIndex, rowIndex){
34844 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
34848 * Returns the editor defined for the cell/column.
34849 * return false or null to disable editing.
34850 * @param {Number} colIndex The column index
34851 * @param {Number} rowIndex The row index
34854 getCellEditor : function(colIndex, rowIndex){
34855 return this.config[colIndex].editor;
34859 * Sets if a column is editable.
34860 * @param {Number} col The column index
34861 * @param {Boolean} editable True if the column is editable
34863 setEditable : function(col, editable){
34864 this.config[col].editable = editable;
34869 * Returns true if the column is hidden.
34870 * @param {Number} colIndex The column index
34871 * @return {Boolean}
34873 isHidden : function(colIndex){
34874 return this.config[colIndex].hidden;
34879 * Returns true if the column width cannot be changed
34881 isFixed : function(colIndex){
34882 return this.config[colIndex].fixed;
34886 * Returns true if the column can be resized
34887 * @return {Boolean}
34889 isResizable : function(colIndex){
34890 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
34893 * Sets if a column is hidden.
34894 * @param {Number} colIndex The column index
34895 * @param {Boolean} hidden True if the column is hidden
34897 setHidden : function(colIndex, hidden){
34898 this.config[colIndex].hidden = hidden;
34899 this.totalWidth = null;
34900 this.fireEvent("hiddenchange", this, colIndex, hidden);
34904 * Sets the editor for a column.
34905 * @param {Number} col The column index
34906 * @param {Object} editor The editor object
34908 setEditor : function(col, editor){
34909 this.config[col].editor = editor;
34913 Roo.grid.ColumnModel.defaultRenderer = function(value){
34914 if(typeof value == "string" && value.length < 1){
34920 // Alias for backwards compatibility
34921 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
34924 * Ext JS Library 1.1.1
34925 * Copyright(c) 2006-2007, Ext JS, LLC.
34927 * Originally Released Under LGPL - original licence link has changed is not relivant.
34930 * <script type="text/javascript">
34934 * @class Roo.grid.AbstractSelectionModel
34935 * @extends Roo.util.Observable
34936 * Abstract base class for grid SelectionModels. It provides the interface that should be
34937 * implemented by descendant classes. This class should not be directly instantiated.
34940 Roo.grid.AbstractSelectionModel = function(){
34941 this.locked = false;
34942 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
34945 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
34946 /** @ignore Called by the grid automatically. Do not call directly. */
34947 init : function(grid){
34953 * Locks the selections.
34956 this.locked = true;
34960 * Unlocks the selections.
34962 unlock : function(){
34963 this.locked = false;
34967 * Returns true if the selections are locked.
34968 * @return {Boolean}
34970 isLocked : function(){
34971 return this.locked;
34975 * Ext JS Library 1.1.1
34976 * Copyright(c) 2006-2007, Ext JS, LLC.
34978 * Originally Released Under LGPL - original licence link has changed is not relivant.
34981 * <script type="text/javascript">
34984 * @extends Roo.grid.AbstractSelectionModel
34985 * @class Roo.grid.RowSelectionModel
34986 * The default SelectionModel used by {@link Roo.grid.Grid}.
34987 * It supports multiple selections and keyboard selection/navigation.
34989 * @param {Object} config
34991 Roo.grid.RowSelectionModel = function(config){
34992 Roo.apply(this, config);
34993 this.selections = new Roo.util.MixedCollection(false, function(o){
34998 this.lastActive = false;
35002 * @event selectionchange
35003 * Fires when the selection changes
35004 * @param {SelectionModel} this
35006 "selectionchange" : true,
35008 * @event afterselectionchange
35009 * Fires after the selection changes (eg. by key press or clicking)
35010 * @param {SelectionModel} this
35012 "afterselectionchange" : true,
35014 * @event beforerowselect
35015 * Fires when a row is selected being selected, return false to cancel.
35016 * @param {SelectionModel} this
35017 * @param {Number} rowIndex The selected index
35018 * @param {Boolean} keepExisting False if other selections will be cleared
35020 "beforerowselect" : true,
35023 * Fires when a row is selected.
35024 * @param {SelectionModel} this
35025 * @param {Number} rowIndex The selected index
35026 * @param {Roo.data.Record} r The record
35028 "rowselect" : true,
35030 * @event rowdeselect
35031 * Fires when a row is deselected.
35032 * @param {SelectionModel} this
35033 * @param {Number} rowIndex The selected index
35035 "rowdeselect" : true
35037 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
35038 this.locked = false;
35041 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
35043 * @cfg {Boolean} singleSelect
35044 * True to allow selection of only one row at a time (defaults to false)
35046 singleSelect : false,
35049 initEvents : function(){
35051 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
35052 this.grid.on("mousedown", this.handleMouseDown, this);
35053 }else{ // allow click to work like normal
35054 this.grid.on("rowclick", this.handleDragableRowClick, this);
35057 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
35058 "up" : function(e){
35060 this.selectPrevious(e.shiftKey);
35061 }else if(this.last !== false && this.lastActive !== false){
35062 var last = this.last;
35063 this.selectRange(this.last, this.lastActive-1);
35064 this.grid.getView().focusRow(this.lastActive);
35065 if(last !== false){
35069 this.selectFirstRow();
35071 this.fireEvent("afterselectionchange", this);
35073 "down" : function(e){
35075 this.selectNext(e.shiftKey);
35076 }else if(this.last !== false && this.lastActive !== false){
35077 var last = this.last;
35078 this.selectRange(this.last, this.lastActive+1);
35079 this.grid.getView().focusRow(this.lastActive);
35080 if(last !== false){
35084 this.selectFirstRow();
35086 this.fireEvent("afterselectionchange", this);
35091 var view = this.grid.view;
35092 view.on("refresh", this.onRefresh, this);
35093 view.on("rowupdated", this.onRowUpdated, this);
35094 view.on("rowremoved", this.onRemove, this);
35098 onRefresh : function(){
35099 var ds = this.grid.dataSource, i, v = this.grid.view;
35100 var s = this.selections;
35101 s.each(function(r){
35102 if((i = ds.indexOfId(r.id)) != -1){
35111 onRemove : function(v, index, r){
35112 this.selections.remove(r);
35116 onRowUpdated : function(v, index, r){
35117 if(this.isSelected(r)){
35118 v.onRowSelect(index);
35124 * @param {Array} records The records to select
35125 * @param {Boolean} keepExisting (optional) True to keep existing selections
35127 selectRecords : function(records, keepExisting){
35129 this.clearSelections();
35131 var ds = this.grid.dataSource;
35132 for(var i = 0, len = records.length; i < len; i++){
35133 this.selectRow(ds.indexOf(records[i]), true);
35138 * Gets the number of selected rows.
35141 getCount : function(){
35142 return this.selections.length;
35146 * Selects the first row in the grid.
35148 selectFirstRow : function(){
35153 * Select the last row.
35154 * @param {Boolean} keepExisting (optional) True to keep existing selections
35156 selectLastRow : function(keepExisting){
35157 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
35161 * Selects the row immediately following the last selected row.
35162 * @param {Boolean} keepExisting (optional) True to keep existing selections
35164 selectNext : function(keepExisting){
35165 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
35166 this.selectRow(this.last+1, keepExisting);
35167 this.grid.getView().focusRow(this.last);
35172 * Selects the row that precedes the last selected row.
35173 * @param {Boolean} keepExisting (optional) True to keep existing selections
35175 selectPrevious : function(keepExisting){
35177 this.selectRow(this.last-1, keepExisting);
35178 this.grid.getView().focusRow(this.last);
35183 * Returns the selected records
35184 * @return {Array} Array of selected records
35186 getSelections : function(){
35187 return [].concat(this.selections.items);
35191 * Returns the first selected record.
35194 getSelected : function(){
35195 return this.selections.itemAt(0);
35200 * Clears all selections.
35202 clearSelections : function(fast){
35203 if(this.locked) return;
35205 var ds = this.grid.dataSource;
35206 var s = this.selections;
35207 s.each(function(r){
35208 this.deselectRow(ds.indexOfId(r.id));
35212 this.selections.clear();
35219 * Selects all rows.
35221 selectAll : function(){
35222 if(this.locked) return;
35223 this.selections.clear();
35224 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
35225 this.selectRow(i, true);
35230 * Returns True if there is a selection.
35231 * @return {Boolean}
35233 hasSelection : function(){
35234 return this.selections.length > 0;
35238 * Returns True if the specified row is selected.
35239 * @param {Number/Record} record The record or index of the record to check
35240 * @return {Boolean}
35242 isSelected : function(index){
35243 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
35244 return (r && this.selections.key(r.id) ? true : false);
35248 * Returns True if the specified record id is selected.
35249 * @param {String} id The id of record to check
35250 * @return {Boolean}
35252 isIdSelected : function(id){
35253 return (this.selections.key(id) ? true : false);
35257 handleMouseDown : function(e, t){
35258 var view = this.grid.getView(), rowIndex;
35259 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
35262 if(e.shiftKey && this.last !== false){
35263 var last = this.last;
35264 this.selectRange(last, rowIndex, e.ctrlKey);
35265 this.last = last; // reset the last
35266 view.focusRow(rowIndex);
35268 var isSelected = this.isSelected(rowIndex);
35269 if(e.button !== 0 && isSelected){
35270 view.focusRow(rowIndex);
35271 }else if(e.ctrlKey && isSelected){
35272 this.deselectRow(rowIndex);
35273 }else if(!isSelected){
35274 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
35275 view.focusRow(rowIndex);
35278 this.fireEvent("afterselectionchange", this);
35281 handleDragableRowClick : function(grid, rowIndex, e)
35283 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
35284 this.selectRow(rowIndex, false);
35285 grid.view.focusRow(rowIndex);
35286 this.fireEvent("afterselectionchange", this);
35291 * Selects multiple rows.
35292 * @param {Array} rows Array of the indexes of the row to select
35293 * @param {Boolean} keepExisting (optional) True to keep existing selections
35295 selectRows : function(rows, keepExisting){
35297 this.clearSelections();
35299 for(var i = 0, len = rows.length; i < len; i++){
35300 this.selectRow(rows[i], true);
35305 * Selects a range of rows. All rows in between startRow and endRow are also selected.
35306 * @param {Number} startRow The index of the first row in the range
35307 * @param {Number} endRow The index of the last row in the range
35308 * @param {Boolean} keepExisting (optional) True to retain existing selections
35310 selectRange : function(startRow, endRow, keepExisting){
35311 if(this.locked) return;
35313 this.clearSelections();
35315 if(startRow <= endRow){
35316 for(var i = startRow; i <= endRow; i++){
35317 this.selectRow(i, true);
35320 for(var i = startRow; i >= endRow; i--){
35321 this.selectRow(i, true);
35327 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
35328 * @param {Number} startRow The index of the first row in the range
35329 * @param {Number} endRow The index of the last row in the range
35331 deselectRange : function(startRow, endRow, preventViewNotify){
35332 if(this.locked) return;
35333 for(var i = startRow; i <= endRow; i++){
35334 this.deselectRow(i, preventViewNotify);
35340 * @param {Number} row The index of the row to select
35341 * @param {Boolean} keepExisting (optional) True to keep existing selections
35343 selectRow : function(index, keepExisting, preventViewNotify){
35344 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
35345 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
35346 if(!keepExisting || this.singleSelect){
35347 this.clearSelections();
35349 var r = this.grid.dataSource.getAt(index);
35350 this.selections.add(r);
35351 this.last = this.lastActive = index;
35352 if(!preventViewNotify){
35353 this.grid.getView().onRowSelect(index);
35355 this.fireEvent("rowselect", this, index, r);
35356 this.fireEvent("selectionchange", this);
35362 * @param {Number} row The index of the row to deselect
35364 deselectRow : function(index, preventViewNotify){
35365 if(this.locked) return;
35366 if(this.last == index){
35369 if(this.lastActive == index){
35370 this.lastActive = false;
35372 var r = this.grid.dataSource.getAt(index);
35373 this.selections.remove(r);
35374 if(!preventViewNotify){
35375 this.grid.getView().onRowDeselect(index);
35377 this.fireEvent("rowdeselect", this, index);
35378 this.fireEvent("selectionchange", this);
35382 restoreLast : function(){
35384 this.last = this._last;
35389 acceptsNav : function(row, col, cm){
35390 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35394 onEditorKey : function(field, e){
35395 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35400 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35402 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35404 }else if(k == e.ENTER && !e.ctrlKey){
35408 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
35410 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
35412 }else if(k == e.ESC){
35416 g.startEditing(newCell[0], newCell[1]);
35421 * Ext JS Library 1.1.1
35422 * Copyright(c) 2006-2007, Ext JS, LLC.
35424 * Originally Released Under LGPL - original licence link has changed is not relivant.
35427 * <script type="text/javascript">
35430 * @class Roo.grid.CellSelectionModel
35431 * @extends Roo.grid.AbstractSelectionModel
35432 * This class provides the basic implementation for cell selection in a grid.
35434 * @param {Object} config The object containing the configuration of this model.
35436 Roo.grid.CellSelectionModel = function(config){
35437 Roo.apply(this, config);
35439 this.selection = null;
35443 * @event beforerowselect
35444 * Fires before a cell is selected.
35445 * @param {SelectionModel} this
35446 * @param {Number} rowIndex The selected row index
35447 * @param {Number} colIndex The selected cell index
35449 "beforecellselect" : true,
35451 * @event cellselect
35452 * Fires when a cell is selected.
35453 * @param {SelectionModel} this
35454 * @param {Number} rowIndex The selected row index
35455 * @param {Number} colIndex The selected cell index
35457 "cellselect" : true,
35459 * @event selectionchange
35460 * Fires when the active selection changes.
35461 * @param {SelectionModel} this
35462 * @param {Object} selection null for no selection or an object (o) with two properties
35464 <li>o.record: the record object for the row the selection is in</li>
35465 <li>o.cell: An array of [rowIndex, columnIndex]</li>
35468 "selectionchange" : true
35470 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
35473 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
35476 initEvents : function(){
35477 this.grid.on("mousedown", this.handleMouseDown, this);
35478 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
35479 var view = this.grid.view;
35480 view.on("refresh", this.onViewChange, this);
35481 view.on("rowupdated", this.onRowUpdated, this);
35482 view.on("beforerowremoved", this.clearSelections, this);
35483 view.on("beforerowsinserted", this.clearSelections, this);
35484 if(this.grid.isEditor){
35485 this.grid.on("beforeedit", this.beforeEdit, this);
35490 beforeEdit : function(e){
35491 this.select(e.row, e.column, false, true, e.record);
35495 onRowUpdated : function(v, index, r){
35496 if(this.selection && this.selection.record == r){
35497 v.onCellSelect(index, this.selection.cell[1]);
35502 onViewChange : function(){
35503 this.clearSelections(true);
35507 * Returns the currently selected cell,.
35508 * @return {Array} The selected cell (row, column) or null if none selected.
35510 getSelectedCell : function(){
35511 return this.selection ? this.selection.cell : null;
35515 * Clears all selections.
35516 * @param {Boolean} true to prevent the gridview from being notified about the change.
35518 clearSelections : function(preventNotify){
35519 var s = this.selection;
35521 if(preventNotify !== true){
35522 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
35524 this.selection = null;
35525 this.fireEvent("selectionchange", this, null);
35530 * Returns true if there is a selection.
35531 * @return {Boolean}
35533 hasSelection : function(){
35534 return this.selection ? true : false;
35538 handleMouseDown : function(e, t){
35539 var v = this.grid.getView();
35540 if(this.isLocked()){
35543 var row = v.findRowIndex(t);
35544 var cell = v.findCellIndex(t);
35545 if(row !== false && cell !== false){
35546 this.select(row, cell);
35552 * @param {Number} rowIndex
35553 * @param {Number} collIndex
35555 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
35556 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
35557 this.clearSelections();
35558 r = r || this.grid.dataSource.getAt(rowIndex);
35561 cell : [rowIndex, colIndex]
35563 if(!preventViewNotify){
35564 var v = this.grid.getView();
35565 v.onCellSelect(rowIndex, colIndex);
35566 if(preventFocus !== true){
35567 v.focusCell(rowIndex, colIndex);
35570 this.fireEvent("cellselect", this, rowIndex, colIndex);
35571 this.fireEvent("selectionchange", this, this.selection);
35576 isSelectable : function(rowIndex, colIndex, cm){
35577 return !cm.isHidden(colIndex);
35581 handleKeyDown : function(e){
35582 Roo.log('Cell Sel Model handleKeyDown');
35583 if(!e.isNavKeyPress()){
35586 var g = this.grid, s = this.selection;
35589 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
35591 this.select(cell[0], cell[1]);
35596 var walk = function(row, col, step){
35597 return g.walkCells(row, col, step, sm.isSelectable, sm);
35599 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
35604 // handled by onEditorKey
35605 if (g.isEditor && g.editing) {
35609 newCell = walk(r, c-1, -1);
35611 newCell = walk(r, c+1, 1);
35615 newCell = walk(r+1, c, 1);
35618 newCell = walk(r-1, c, -1);
35621 newCell = walk(r, c+1, 1);
35624 newCell = walk(r, c-1, -1);
35627 if(g.isEditor && !g.editing){
35628 g.startEditing(r, c);
35635 this.select(newCell[0], newCell[1]);
35640 acceptsNav : function(row, col, cm){
35641 return !cm.isHidden(col) && cm.isCellEditable(col, row);
35644 onEditorKey : function(field, e){
35646 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
35647 ///Roo.log('onEditorKey' + k);
35651 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
35653 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35656 }else if(k == e.ENTER && !e.ctrlKey){
35659 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
35660 }else if(k == e.ESC){
35666 //Roo.log('next cell after edit');
35667 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
35672 * Ext JS Library 1.1.1
35673 * Copyright(c) 2006-2007, Ext JS, LLC.
35675 * Originally Released Under LGPL - original licence link has changed is not relivant.
35678 * <script type="text/javascript">
35682 * @class Roo.grid.EditorGrid
35683 * @extends Roo.grid.Grid
35684 * Class for creating and editable grid.
35685 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35686 * The container MUST have some type of size defined for the grid to fill. The container will be
35687 * automatically set to position relative if it isn't already.
35688 * @param {Object} dataSource The data model to bind to
35689 * @param {Object} colModel The column model with info about this grid's columns
35691 Roo.grid.EditorGrid = function(container, config){
35692 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
35693 this.getGridEl().addClass("xedit-grid");
35695 if(!this.selModel){
35696 this.selModel = new Roo.grid.CellSelectionModel();
35699 this.activeEditor = null;
35703 * @event beforeedit
35704 * Fires before cell editing is triggered. The edit event object has the following properties <br />
35705 * <ul style="padding:5px;padding-left:16px;">
35706 * <li>grid - This grid</li>
35707 * <li>record - The record being edited</li>
35708 * <li>field - The field name being edited</li>
35709 * <li>value - The value for the field being edited.</li>
35710 * <li>row - The grid row index</li>
35711 * <li>column - The grid column index</li>
35712 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35714 * @param {Object} e An edit event (see above for description)
35716 "beforeedit" : true,
35719 * Fires after a cell is edited. <br />
35720 * <ul style="padding:5px;padding-left:16px;">
35721 * <li>grid - This grid</li>
35722 * <li>record - The record being edited</li>
35723 * <li>field - The field name being edited</li>
35724 * <li>value - The value being set</li>
35725 * <li>originalValue - The original value for the field, before the edit.</li>
35726 * <li>row - The grid row index</li>
35727 * <li>column - The grid column index</li>
35729 * @param {Object} e An edit event (see above for description)
35731 "afteredit" : true,
35733 * @event validateedit
35734 * Fires after a cell is edited, but before the value is set in the record.
35735 * You can use this to modify the value being set in the field, Return false
35736 * to cancel the change. The edit event object has the following properties <br />
35737 * <ul style="padding:5px;padding-left:16px;">
35738 * <li>editor - This editor</li>
35739 * <li>grid - This grid</li>
35740 * <li>record - The record being edited</li>
35741 * <li>field - The field name being edited</li>
35742 * <li>value - The value being set</li>
35743 * <li>originalValue - The original value for the field, before the edit.</li>
35744 * <li>row - The grid row index</li>
35745 * <li>column - The grid column index</li>
35746 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
35748 * @param {Object} e An edit event (see above for description)
35750 "validateedit" : true
35752 this.on("bodyscroll", this.stopEditing, this);
35753 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
35756 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
35758 * @cfg {Number} clicksToEdit
35759 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
35766 trackMouseOver: false, // causes very odd FF errors
35768 onCellDblClick : function(g, row, col){
35769 this.startEditing(row, col);
35772 onEditComplete : function(ed, value, startValue){
35773 this.editing = false;
35774 this.activeEditor = null;
35775 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
35777 var field = this.colModel.getDataIndex(ed.col);
35782 originalValue: startValue,
35789 if(String(value) !== String(startValue)){
35791 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
35792 r.set(field, e.value);
35793 // if we are dealing with a combo box..
35794 // then we also set the 'name' colum to be the displayField
35795 if (ed.field.displayField && ed.field.name) {
35796 r.set(ed.field.name, ed.field.el.dom.value);
35799 delete e.cancel; //?? why!!!
35800 this.fireEvent("afteredit", e);
35803 this.fireEvent("afteredit", e); // always fire it!
35805 this.view.focusCell(ed.row, ed.col);
35809 * Starts editing the specified for the specified row/column
35810 * @param {Number} rowIndex
35811 * @param {Number} colIndex
35813 startEditing : function(row, col){
35814 this.stopEditing();
35815 if(this.colModel.isCellEditable(col, row)){
35816 this.view.ensureVisible(row, col, true);
35817 var r = this.dataSource.getAt(row);
35818 var field = this.colModel.getDataIndex(col);
35823 value: r.data[field],
35828 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
35829 this.editing = true;
35830 var ed = this.colModel.getCellEditor(col, row);
35836 ed.render(ed.parentEl || document.body);
35839 (function(){ // complex but required for focus issues in safari, ie and opera
35843 ed.on("complete", this.onEditComplete, this, {single: true});
35844 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
35845 this.activeEditor = ed;
35846 var v = r.data[field];
35847 ed.startEdit(this.view.getCell(row, col), v);
35848 // combo's with 'displayField and name set
35849 if (ed.field.displayField && ed.field.name) {
35850 ed.field.el.dom.value = r.data[ed.field.name];
35854 }).defer(50, this);
35860 * Stops any active editing
35862 stopEditing : function(){
35863 if(this.activeEditor){
35864 this.activeEditor.completeEdit();
35866 this.activeEditor = null;
35870 * Ext JS Library 1.1.1
35871 * Copyright(c) 2006-2007, Ext JS, LLC.
35873 * Originally Released Under LGPL - original licence link has changed is not relivant.
35876 * <script type="text/javascript">
35879 // private - not really -- you end up using it !
35880 // This is a support class used internally by the Grid components
35883 * @class Roo.grid.GridEditor
35884 * @extends Roo.Editor
35885 * Class for creating and editable grid elements.
35886 * @param {Object} config any settings (must include field)
35888 Roo.grid.GridEditor = function(field, config){
35889 if (!config && field.field) {
35891 field = Roo.factory(config.field, Roo.form);
35893 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
35894 field.monitorTab = false;
35897 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
35900 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
35903 alignment: "tl-tl",
35906 cls: "x-small-editor x-grid-editor",
35911 * Ext JS Library 1.1.1
35912 * Copyright(c) 2006-2007, Ext JS, LLC.
35914 * Originally Released Under LGPL - original licence link has changed is not relivant.
35917 * <script type="text/javascript">
35922 Roo.grid.PropertyRecord = Roo.data.Record.create([
35923 {name:'name',type:'string'}, 'value'
35927 Roo.grid.PropertyStore = function(grid, source){
35929 this.store = new Roo.data.Store({
35930 recordType : Roo.grid.PropertyRecord
35932 this.store.on('update', this.onUpdate, this);
35934 this.setSource(source);
35936 Roo.grid.PropertyStore.superclass.constructor.call(this);
35941 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
35942 setSource : function(o){
35944 this.store.removeAll();
35947 if(this.isEditableValue(o[k])){
35948 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
35951 this.store.loadRecords({records: data}, {}, true);
35954 onUpdate : function(ds, record, type){
35955 if(type == Roo.data.Record.EDIT){
35956 var v = record.data['value'];
35957 var oldValue = record.modified['value'];
35958 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
35959 this.source[record.id] = v;
35961 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
35968 getProperty : function(row){
35969 return this.store.getAt(row);
35972 isEditableValue: function(val){
35973 if(val && val instanceof Date){
35975 }else if(typeof val == 'object' || typeof val == 'function'){
35981 setValue : function(prop, value){
35982 this.source[prop] = value;
35983 this.store.getById(prop).set('value', value);
35986 getSource : function(){
35987 return this.source;
35991 Roo.grid.PropertyColumnModel = function(grid, store){
35994 g.PropertyColumnModel.superclass.constructor.call(this, [
35995 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
35996 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
35998 this.store = store;
35999 this.bselect = Roo.DomHelper.append(document.body, {
36000 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
36001 {tag: 'option', value: 'true', html: 'true'},
36002 {tag: 'option', value: 'false', html: 'false'}
36005 Roo.id(this.bselect);
36008 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
36009 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
36010 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
36011 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
36012 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
36014 this.renderCellDelegate = this.renderCell.createDelegate(this);
36015 this.renderPropDelegate = this.renderProp.createDelegate(this);
36018 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
36022 valueText : 'Value',
36024 dateFormat : 'm/j/Y',
36027 renderDate : function(dateVal){
36028 return dateVal.dateFormat(this.dateFormat);
36031 renderBool : function(bVal){
36032 return bVal ? 'true' : 'false';
36035 isCellEditable : function(colIndex, rowIndex){
36036 return colIndex == 1;
36039 getRenderer : function(col){
36041 this.renderCellDelegate : this.renderPropDelegate;
36044 renderProp : function(v){
36045 return this.getPropertyName(v);
36048 renderCell : function(val){
36050 if(val instanceof Date){
36051 rv = this.renderDate(val);
36052 }else if(typeof val == 'boolean'){
36053 rv = this.renderBool(val);
36055 return Roo.util.Format.htmlEncode(rv);
36058 getPropertyName : function(name){
36059 var pn = this.grid.propertyNames;
36060 return pn && pn[name] ? pn[name] : name;
36063 getCellEditor : function(colIndex, rowIndex){
36064 var p = this.store.getProperty(rowIndex);
36065 var n = p.data['name'], val = p.data['value'];
36067 if(typeof(this.grid.customEditors[n]) == 'string'){
36068 return this.editors[this.grid.customEditors[n]];
36070 if(typeof(this.grid.customEditors[n]) != 'undefined'){
36071 return this.grid.customEditors[n];
36073 if(val instanceof Date){
36074 return this.editors['date'];
36075 }else if(typeof val == 'number'){
36076 return this.editors['number'];
36077 }else if(typeof val == 'boolean'){
36078 return this.editors['boolean'];
36080 return this.editors['string'];
36086 * @class Roo.grid.PropertyGrid
36087 * @extends Roo.grid.EditorGrid
36088 * This class represents the interface of a component based property grid control.
36089 * <br><br>Usage:<pre><code>
36090 var grid = new Roo.grid.PropertyGrid("my-container-id", {
36098 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
36099 * The container MUST have some type of size defined for the grid to fill. The container will be
36100 * automatically set to position relative if it isn't already.
36101 * @param {Object} config A config object that sets properties on this grid.
36103 Roo.grid.PropertyGrid = function(container, config){
36104 config = config || {};
36105 var store = new Roo.grid.PropertyStore(this);
36106 this.store = store;
36107 var cm = new Roo.grid.PropertyColumnModel(this, store);
36108 store.store.sort('name', 'ASC');
36109 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
36112 enableColLock:false,
36113 enableColumnMove:false,
36115 trackMouseOver: false,
36118 this.getGridEl().addClass('x-props-grid');
36119 this.lastEditRow = null;
36120 this.on('columnresize', this.onColumnResize, this);
36123 * @event beforepropertychange
36124 * Fires before a property changes (return false to stop?)
36125 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36126 * @param {String} id Record Id
36127 * @param {String} newval New Value
36128 * @param {String} oldval Old Value
36130 "beforepropertychange": true,
36132 * @event propertychange
36133 * Fires after a property changes
36134 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
36135 * @param {String} id Record Id
36136 * @param {String} newval New Value
36137 * @param {String} oldval Old Value
36139 "propertychange": true
36141 this.customEditors = this.customEditors || {};
36143 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
36146 * @cfg {Object} customEditors map of colnames=> custom editors.
36147 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
36148 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
36149 * false disables editing of the field.
36153 * @cfg {Object} propertyNames map of property Names to their displayed value
36156 render : function(){
36157 Roo.grid.PropertyGrid.superclass.render.call(this);
36158 this.autoSize.defer(100, this);
36161 autoSize : function(){
36162 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
36164 this.view.fitColumns();
36168 onColumnResize : function(){
36169 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
36173 * Sets the data for the Grid
36174 * accepts a Key => Value object of all the elements avaiable.
36175 * @param {Object} data to appear in grid.
36177 setSource : function(source){
36178 this.store.setSource(source);
36182 * Gets all the data from the grid.
36183 * @return {Object} data data stored in grid
36185 getSource : function(){
36186 return this.store.getSource();
36190 * Ext JS Library 1.1.1
36191 * Copyright(c) 2006-2007, Ext JS, LLC.
36193 * Originally Released Under LGPL - original licence link has changed is not relivant.
36196 * <script type="text/javascript">
36200 * @class Roo.LoadMask
36201 * A simple utility class for generically masking elements while loading data. If the element being masked has
36202 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
36203 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
36204 * element's UpdateManager load indicator and will be destroyed after the initial load.
36206 * Create a new LoadMask
36207 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
36208 * @param {Object} config The config object
36210 Roo.LoadMask = function(el, config){
36211 this.el = Roo.get(el);
36212 Roo.apply(this, config);
36214 this.store.on('beforeload', this.onBeforeLoad, this);
36215 this.store.on('load', this.onLoad, this);
36216 this.store.on('loadexception', this.onLoad, this);
36217 this.removeMask = false;
36219 var um = this.el.getUpdateManager();
36220 um.showLoadIndicator = false; // disable the default indicator
36221 um.on('beforeupdate', this.onBeforeLoad, this);
36222 um.on('update', this.onLoad, this);
36223 um.on('failure', this.onLoad, this);
36224 this.removeMask = true;
36228 Roo.LoadMask.prototype = {
36230 * @cfg {Boolean} removeMask
36231 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
36232 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
36235 * @cfg {String} msg
36236 * The text to display in a centered loading message box (defaults to 'Loading...')
36238 msg : 'Loading...',
36240 * @cfg {String} msgCls
36241 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
36243 msgCls : 'x-mask-loading',
36246 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
36252 * Disables the mask to prevent it from being displayed
36254 disable : function(){
36255 this.disabled = true;
36259 * Enables the mask so that it can be displayed
36261 enable : function(){
36262 this.disabled = false;
36266 onLoad : function(){
36267 this.el.unmask(this.removeMask);
36271 onBeforeLoad : function(){
36272 if(!this.disabled){
36273 this.el.mask(this.msg, this.msgCls);
36278 destroy : function(){
36280 this.store.un('beforeload', this.onBeforeLoad, this);
36281 this.store.un('load', this.onLoad, this);
36282 this.store.un('loadexception', this.onLoad, this);
36284 var um = this.el.getUpdateManager();
36285 um.un('beforeupdate', this.onBeforeLoad, this);
36286 um.un('update', this.onLoad, this);
36287 um.un('failure', this.onLoad, this);
36292 * Ext JS Library 1.1.1
36293 * Copyright(c) 2006-2007, Ext JS, LLC.
36295 * Originally Released Under LGPL - original licence link has changed is not relivant.
36298 * <script type="text/javascript">
36300 Roo.XTemplate = function(){
36301 Roo.XTemplate.superclass.constructor.apply(this, arguments);
36304 s = ['<tpl>', s, '</tpl>'].join('');
36306 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/;
36308 var nameRe = /^<tpl\b[^>]*?for="(.*?)"/;
36309 var ifRe = /^<tpl\b[^>]*?if="(.*?)"/;
36310 var execRe = /^<tpl\b[^>]*?exec="(.*?)"/;
36314 while(m = s.match(re)){
36315 var m2 = m[0].match(nameRe);
36316 var m3 = m[0].match(ifRe);
36317 var m4 = m[0].match(execRe);
36318 var exp = null, fn = null, exec = null;
36319 var name = m2 && m2[1] ? m2[1] : '';
36321 exp = m3 && m3[1] ? m3[1] : null;
36323 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
36327 exp = m4 && m4[1] ? m4[1] : null;
36329 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
36334 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
36335 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
36336 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
36346 s = s.replace(m[0], '{xtpl'+ id + '}');
36349 for(var i = tpls.length-1; i >= 0; --i){
36350 this.compileTpl(tpls[i]);
36352 this.master = tpls[tpls.length-1];
36355 Roo.extend(Roo.XTemplate, Roo.Template, {
36357 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
36359 applySubTemplate : function(id, values, parent){
36360 var t = this.tpls[id];
36361 if(t.test && !t.test.call(this, values, parent)){
36364 if(t.exec && t.exec.call(this, values, parent)){
36367 var vs = t.target ? t.target.call(this, values, parent) : values;
36368 parent = t.target ? values : parent;
36369 if(t.target && vs instanceof Array){
36371 for(var i = 0, len = vs.length; i < len; i++){
36372 buf[buf.length] = t.compiled.call(this, vs[i], parent);
36374 return buf.join('');
36376 return t.compiled.call(this, vs, parent);
36379 compileTpl : function(tpl){
36380 var fm = Roo.util.Format;
36381 var useF = this.disableFormats !== true;
36382 var sep = Roo.isGecko ? "+" : ",";
36383 var fn = function(m, name, format, args){
36384 if(name.substr(0, 4) == 'xtpl'){
36385 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
36388 if(name.indexOf('.') != -1){
36391 v = "values['" + name + "']";
36393 if(format && useF){
36394 args = args ? ',' + args : "";
36395 if(format.substr(0, 5) != "this."){
36396 format = "fm." + format + '(';
36398 format = 'this.call("'+ format.substr(5) + '", ';
36402 args= ''; format = "("+v+" === undefined ? '' : ";
36404 return "'"+ sep + format + v + args + ")"+sep+"'";
36407 // branched to use + in gecko and [].join() in others
36409 body = "tpl.compiled = function(values, parent){ return '" +
36410 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
36413 body = ["tpl.compiled = function(values, parent){ return ['"];
36414 body.push(tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
36415 body.push("'].join('');};");
36416 body = body.join('');
36418 /** eval:var:zzzzzzz */
36423 applyTemplate : function(values){
36424 return this.master.compiled.call(this, values, {});
36428 apply : function(){
36429 return this.applyTemplate.apply(this, arguments);
36432 compile : function(){return this;}
36435 Roo.XTemplate.from = function(el){
36436 el = Roo.getDom(el);
36437 return new Roo.XTemplate(el.value || el.innerHTML);
36439 * Original code for Roojs - LGPL
36440 * <script type="text/javascript">
36444 * @class Roo.XComponent
36445 * A delayed Element creator...
36447 * Mypart.xyx = new Roo.XComponent({
36449 parent : 'Mypart.xyz', // empty == document.element.!!
36453 disabled : function() {}
36455 tree : function() { // return an tree of xtype declared components
36459 xtype : 'NestedLayoutPanel',
36464 * @extends Roo.util.Observable
36466 * @param cfg {Object} configuration of component
36469 Roo.XComponent = function(cfg) {
36470 Roo.apply(this, cfg);
36474 * Fires when this the componnt is built
36475 * @param {Roo.XComponent} c the component
36479 * @event buildcomplete
36480 * Fires on the top level element when all elements have been built
36481 * @param {Roo.XComponent} c the top level component.
36483 'buildcomplete' : true
36487 Roo.XComponent.register(this);
36488 this.modules = false;
36489 this.el = false; // where the layout goes..
36493 Roo.extend(Roo.XComponent, Roo.util.Observable, {
36496 * The created element (with Roo.factory())
36497 * @type {Roo.Layout}
36503 * for BC - use el in new code
36504 * @type {Roo.Layout}
36510 * for BC - use el in new code
36511 * @type {Roo.Layout}
36516 * @cfg {Function|boolean} disabled
36517 * If this module is disabled by some rule, return true from the funtion
36522 * @cfg {String} parent
36523 * Name of parent element which it get xtype added to..
36528 * @cfg {String} order
36529 * Used to set the order in which elements are created (usefull for multiple tabs)
36534 * @cfg {String} name
36535 * String to display while loading.
36539 * @cfg {Array} items
36540 * A single item array - the first element is the root of the tree..
36541 * It's done this way to stay compatible with the Xtype system...
36549 Roo.apply(Roo.XComponent, {
36552 * @property buildCompleted
36553 * True when the builder has completed building the interface.
36556 buildCompleted : false,
36559 * @property topModule
36560 * the upper most module - uses document.element as it's constructor.
36567 * @property modules
36568 * array of modules to be created by registration system.
36569 * @type Roo.XComponent
36576 * Register components to be built later.
36578 * This solves the following issues
36579 * - Building is not done on page load, but after an authentication process has occured.
36580 * - Interface elements are registered on page load
36581 * - Parent Interface elements may not be loaded before child, so this handles that..
36588 module : 'Pman.Tab.projectMgr',
36590 parent : 'Pman.layout',
36591 disabled : false, // or use a function..
36594 * * @param {Object} details about module
36596 register : function(obj) {
36597 this.modules.push(obj);
36601 * convert a string to an object..
36605 toObject : function(str)
36607 if (!str || typeof(str) == 'object') {
36610 var ar = str.split('.');
36614 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
36616 throw "Module not found : " + str;
36618 Roo.each(ar, function(e) {
36619 if (typeof(o[e]) == 'undefined') {
36620 throw "Module not found : " + str;
36630 * move modules into their correct place in the tree..
36633 preBuild : function ()
36636 Roo.each(this.modules , function (obj)
36638 obj.parent = this.toObject(obj.parent);
36641 this.topModule = obj;
36645 if (!obj.parent.modules) {
36646 obj.parent.modules = new Roo.util.MixedCollection(false,
36647 function(o) { return o.order + '' }
36651 obj.parent.modules.add(obj);
36656 * make a list of modules to build.
36657 * @return {Array} list of modules.
36660 buildOrder : function()
36663 var cmp = function(a,b) {
36664 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
36667 if (!this.topModule || !this.topModule.modules) {
36668 throw "No top level modules to build";
36671 // make a flat list in order of modules to build.
36672 var mods = [ this.topModule ];
36675 // add modules to their parents..
36676 var addMod = function(m) {
36677 // Roo.debug && Roo.log(m.modKey);
36681 m.modules.keySort('ASC', cmp );
36682 m.modules.each(addMod);
36684 // not sure if this is used any more..
36686 m.finalize.name = m.name + " (clean up) ";
36687 mods.push(m.finalize);
36691 this.topModule.modules.keySort('ASC', cmp );
36692 this.topModule.modules.each(addMod);
36697 * Build the registered modules.
36698 * @param {Object} parent element.
36699 * @param {Function} optional method to call after module has been added.
36707 var mods = this.buildOrder();
36709 //this.allmods = mods;
36710 //Roo.debug && Roo.log(mods);
36712 if (!mods.length) { // should not happen
36713 throw "NO modules!!!";
36718 // flash it up as modal - so we store the mask!?
36719 Roo.MessageBox.show({ title: 'loading' });
36720 Roo.MessageBox.show({
36721 title: "Please wait...",
36722 msg: "Building Interface...",
36729 var total = mods.length;
36732 var progressRun = function() {
36733 if (!mods.length) {
36734 Roo.debug && Roo.log('hide?');
36735 Roo.MessageBox.hide();
36736 _this.topModule.fireEvent('buildcomplete', _this.topModule);
36740 var m = mods.shift();
36741 Roo.debug && Roo.log(m);
36742 if (typeof(m) == 'function') { // not sure if this is supported any more..
36744 return progressRun.defer(10, _this);
36747 Roo.MessageBox.updateProgress(
36748 (total - mods.length)/total, "Building Interface " + (total - mods.length) +
36750 (m.name ? (' - ' + m.name) : '')
36755 var disabled = (typeof(m.disabled) == 'function') ?
36756 m.disabled.call(m.module.disabled) : m.disabled;
36760 return progressRun(); // we do not update the display!
36764 // it's a top level one..
36765 var layoutbase = new Ext.BorderLayout(document.body, {
36771 tabPosition: 'top',
36772 //resizeTabs: true,
36773 alwaysShowTabs: true,
36777 var tree = m.tree();
36778 tree.region = 'center';
36779 m.el = layoutbase.addxtype(tree);
36781 m.layout = m.panel.layout;
36782 return progressRun.defer(10, _this);
36785 var tree = m.tree();
36786 tree.region = tree.region || m.region;
36787 m.el = m.parent.el.addxtype(tree);
36788 m.fireEvent('built', m);
36790 m.layout = m.panel.layout;
36791 progressRun.defer(10, _this);
36794 progressRun.defer(1, _this);
36804 //<script type="text/javascript">
36809 * @extends Roo.LayoutDialog
36810 * A generic Login Dialog..... - only one needed in theory!?!?
36812 * Fires XComponent builder on success...
36815 * username,password, lang = for login actions.
36816 * check = 1 for periodic checking that sesion is valid.
36817 * passwordRequest = email request password
36818 * logout = 1 = to logout
36820 * Affects: (this id="????" elements)
36821 * loading (removed) (used to indicate application is loading)
36822 * loading-mask (hides) (used to hide application when it's building loading)
36828 * Myapp.login = Roo.Login({
36844 Roo.Login = function(cfg)
36850 Roo.apply(this,cfg);
36852 Roo.onReady(function() {
36858 Roo.Login.superclass.constructor.call(this, this);
36859 //this.addxtype(this.items[0]);
36865 Roo.extend(Roo.Login, Roo.LayoutDialog, {
36868 * @cfg {String} method
36869 * Method used to query for login details.
36874 * @cfg {String} url
36875 * URL to query login data. - eg. baseURL + '/Login.php'
36881 * The user data - if user.id < 0 then login will be bypassed. (used for inital setup situation.
36886 * @property checkFails
36887 * Number of times we have attempted to get authentication check, and failed.
36892 * @property intervalID
36893 * The window interval that does the constant login checking.
36899 onLoad : function() // called on page load...
36903 if (Roo.get('loading')) { // clear any loading indicator..
36904 Roo.get('loading').remove();
36907 //this.switchLang('en'); // set the language to english..
36910 success: function(response, opts) { // check successfull...
36912 var res = this.processResponse(response);
36913 this.checkFails =0;
36914 if (!res.success) { // error!
36915 this.checkFails = 5;
36916 //console.log('call failure');
36917 return this.failure(response,opts);
36920 if (!res.data.id) { // id=0 == login failure.
36921 return this.show();
36925 //console.log(success);
36926 this.fillAuth(res.data);
36927 this.checkFails =0;
36928 Roo.XComponent.build();
36930 failure : this.show
36936 check: function(cfg) // called every so often to refresh cookie etc..
36938 if (cfg.again) { // could be undefined..
36941 this.checkFails = 0;
36944 if (this.sending) {
36945 if ( this.checkFails > 4) {
36946 Roo.MessageBox.alert("Error",
36947 "Error getting authentication status. - try reloading, or wait a while", function() {
36948 _this.sending = false;
36953 _this.check.defer(10000, _this, [ cfg ]); // check in 10 secs.
36956 this.sending = true;
36963 method: this.method,
36964 success: cfg.success || this.success,
36965 failure : cfg.failure || this.failure,
36975 window.onbeforeunload = function() { }; // false does not work for IE..
36985 failure : function() {
36986 Roo.MessageBox.alert("Error", "Error logging out. - continuing anyway.", function() {
36987 document.location = document.location.toString() + '?ts=' + Math.random();
36991 success : function() {
36992 _this.user = false;
36993 this.checkFails =0;
36995 document.location = document.location.toString() + '?ts=' + Math.random();
37002 processResponse : function (response)
37006 res = Roo.decode(response.responseText);
37008 if (typeof(res) != 'object') {
37009 res = { success : false, errorMsg : res, errors : true };
37011 if (typeof(res.success) == 'undefined') {
37012 res.success = false;
37016 res = { success : false, errorMsg : response.responseText, errors : true };
37021 success : function(response, opts) // check successfull...
37023 this.sending = false;
37024 var res = this.processResponse(response);
37025 if (!res.success) {
37026 return this.failure(response, opts);
37028 if (!res.data || !res.data.id) {
37029 return this.failure(response,opts);
37031 //console.log(res);
37032 this.fillAuth(res.data);
37034 this.checkFails =0;
37039 failure : function (response, opts) // called if login 'check' fails.. (causes re-check)
37041 this.authUser = -1;
37042 this.sending = false;
37043 var res = this.processResponse(response);
37044 //console.log(res);
37045 if ( this.checkFails > 2) {
37047 Roo.MessageBox.alert("Error", res.errorMsg ? res.errorMsg :
37048 "Error getting authentication status. - try reloading");
37051 opts.callCfg.again = true;
37052 this.check.defer(1000, this, [ opts.callCfg ]);
37058 fillAuth: function(au) {
37059 this.startAuthCheck();
37060 this.authUserId = au.id;
37061 this.authUser = au;
37062 this.lastChecked = new Date();
37063 this.fireEvent('refreshed', au);
37064 //Pman.Tab.FaxQueue.newMaxId(au.faxMax);
37065 //Pman.Tab.FaxTab.setTitle(au.faxNumPending);
37066 au.lang = au.lang || 'en';
37067 //this.switchLang(Roo.state.Manager.get('Pman.Login.lang', 'en'));
37068 Roo.state.Manager.set( this.realm + 'lang' , au.lang);
37069 this.switchLang(au.lang );
37072 // open system... - -on setyp..
37073 if (this.authUserId < 0) {
37074 Roo.MessageBox.alert("Warning",
37075 "This is an open system - please set up a admin user with a password.");
37078 //Pman.onload(); // which should do nothing if it's a re-auth result...
37083 startAuthCheck : function() // starter for timeout checking..
37085 if (this.intervalID) { // timer already in place...
37089 this.intervalID = window.setInterval(function() {
37090 _this.check(false);
37091 }, 120000); // every 120 secs = 2mins..
37097 switchLang : function (lang)
37099 _T = typeof(_T) == 'undefined' ? false : _T;
37100 if (!_T || !lang.length) {
37104 if (!_T && lang != 'en') {
37105 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37109 if (typeof(_T.en) == 'undefined') {
37111 Roo.apply(_T.en, _T);
37114 if (typeof(_T[lang]) == 'undefined') {
37115 Roo.MessageBox.alert("Sorry", "Language not available yet (" + lang +')');
37120 Roo.apply(_T, _T[lang]);
37121 // just need to set the text values for everything...
37123 /* this will not work ...
37127 function formLabel(name, val) {
37128 _this.form.findField(name).fieldEl.child('label').dom.innerHTML = val;
37131 formLabel('password', "Password"+':');
37132 formLabel('username', "Email Address"+':');
37133 formLabel('lang', "Language"+':');
37134 this.dialog.setTitle("Login");
37135 this.dialog.buttons[0].setText("Forgot Password");
37136 this.dialog.buttons[1].setText("Login");
37155 collapsible: false,
37157 center: { // needed??
37160 // tabPosition: 'top',
37163 alwaysShowTabs: false
37167 show : function(dlg)
37169 //console.log(this);
37170 this.form = this.layout.getRegion('center').activePanel.form;
37171 this.form.dialog = dlg;
37172 this.buttons[0].form = this.form;
37173 this.buttons[0].dialog = dlg;
37174 this.buttons[1].form = this.form;
37175 this.buttons[1].dialog = dlg;
37177 //this.resizeToLogo.defer(1000,this);
37178 // this is all related to resizing for logos..
37179 //var sz = Roo.get(Pman.Login.form.el.query('img')[0]).getSize();
37181 // this.resizeToLogo.defer(1000,this);
37184 //var w = Ext.lib.Dom.getViewWidth() - 100;
37185 //var h = Ext.lib.Dom.getViewHeight() - 100;
37186 //this.resizeTo(Math.max(350, Math.min(sz.width + 30, w)),Math.min(sz.height+200, h));
37188 if (this.disabled) {
37193 if (this.user.id < 0) { // used for inital setup situations.
37197 if (this.intervalID) {
37198 // remove the timer
37199 window.clearInterval(this.intervalID);
37200 this.intervalID = false;
37204 if (Roo.get('loading')) {
37205 Roo.get('loading').remove();
37207 if (Roo.get('loading-mask')) {
37208 Roo.get('loading-mask').hide();
37211 //incomming._node = tnode;
37213 //this.dialog.modal = !modal;
37214 //this.dialog.show();
37218 this.form.setValues({
37219 'username' : Roo.state.Manager.get(this.realm + '.username', ''),
37220 'lang' : Roo.state.Manager.get(this.realm + '.lang', 'en')
37223 this.switchLang(Roo.state.Manager.get(this.realm + '.lang', 'en'));
37224 if (this.form.findField('username').getValue().length > 0 ){
37225 this.form.findField('password').focus();
37227 this.form.findField('username').focus();
37235 xtype : 'ContentPanel',
37247 style : 'margin: 10px;',
37250 actionfailed : function(f, act) {
37251 // form can return { errors: .... }
37253 //act.result.errors // invalid form element list...
37254 //act.result.errorMsg// invalid form element list...
37256 this.dialog.el.unmask();
37257 Roo.MessageBox.alert("Error", act.result.errorMsg ? act.result.errorMsg :
37258 "Login failed - communication error - try again.");
37261 actioncomplete: function(re, act) {
37263 Roo.state.Manager.set(
37264 this.dialog.realm + '.username',
37265 this.findField('username').getValue()
37267 Roo.state.Manager.set(
37268 this.dialog.realm + '.lang',
37269 this.findField('lang').getValue()
37272 this.dialog.fillAuth(act.result.data);
37274 this.dialog.hide();
37276 if (Roo.get('loading-mask')) {
37277 Roo.get('loading-mask').show();
37279 Roo.XComponent.build();
37287 xtype : 'TextField',
37289 fieldLabel: "Email Address",
37292 autoCreate : {tag: "input", type: "text", size: "20"}
37295 xtype : 'TextField',
37297 fieldLabel: "Password",
37298 inputType: 'password',
37301 autoCreate : {tag: "input", type: "text", size: "20"},
37303 specialkey : function(e,ev) {
37304 if (ev.keyCode == 13) {
37305 this.form.dialog.el.mask("Logging in");
37306 this.form.doAction('submit', {
37307 url: this.form.dialog.url,
37308 method: this.form.dialog.method
37315 xtype : 'ComboBox',
37317 fieldLabel: "Language",
37320 xtype : 'SimpleStore',
37321 fields: ['lang', 'ldisp'],
37323 [ 'en', 'English' ],
37324 [ 'zh_HK' , '\u7E41\u4E2D' ],
37325 [ 'zh_CN', '\u7C21\u4E2D' ]
37329 valueField : 'lang',
37330 hiddenName: 'lang',
37332 displayField:'ldisp',
37336 triggerAction: 'all',
37337 emptyText:'Select a Language...',
37338 selectOnFocus:true,
37340 select : function(cb, rec, ix) {
37341 this.form.switchLang(rec.data.lang);
37357 text : "Forgot Password",
37359 click : function() {
37360 //console.log(this);
37361 var n = this.form.findField('username').getValue();
37363 Roo.MessageBox.alert("Error", "Fill in your email address");
37367 url: this.dialog.url,
37371 method: this.dialog.method,
37372 success: function(response, opts) { // check successfull...
37374 var res = this.dialog.processResponse(response);
37375 if (!res.success) { // error!
37376 Roo.MessageBox.alert("Error" ,
37377 res.errorMsg ? res.errorMsg : "Problem Requesting Password Reset");
37380 Roo.MessageBox.alert("Notice" ,
37381 "Please check you email for the Password Reset message");
37383 failure : function() {
37384 Roo.MessageBox.alert("Error" , "Problem Requesting Password Reset");
37397 click : function () {
37399 this.dialog.el.mask("Logging in");
37400 this.form.doAction('submit', {
37401 url: this.dialog.url,
37402 method: this.dialog.method