4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * @extends Roo.util.Observable
30 * Defines the interface and base operation of items that that can be
31 * dragged or can be drop targets. It was designed to be extended, overriding
32 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
33 * Up to three html elements can be associated with a DragDrop instance:
35 * <li>linked element: the element that is passed into the constructor.
36 * This is the element which defines the boundaries for interaction with
37 * other DragDrop objects.</li>
38 * <li>handle element(s): The drag operation only occurs if the element that
39 * was clicked matches a handle element. By default this is the linked
40 * element, but there are times that you will want only a portion of the
41 * linked element to initiate the drag operation, and the setHandleElId()
42 * method provides a way to define this.</li>
43 * <li>drag element: this represents the element that would be moved along
44 * with the cursor during a drag operation. By default, this is the linked
45 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
46 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
49 * This class should not be instantiated until the onload event to ensure that
50 * the associated elements are available.
51 * The following would define a DragDrop obj that would interact with any
52 * other DragDrop obj in the "group1" group:
54 * dd = new Roo.dd.DragDrop("div1", "group1");
56 * Since none of the event handlers have been implemented, nothing would
57 * actually happen if you were to run the code above. Normally you would
58 * override this class or one of the default implementations, but you can
59 * also override the methods you want on an instance of the class...
61 * dd.onDragDrop = function(e, id) {
62 * alert("dd was dropped on " + id);
66 * @param {String} id of the element that is linked to this instance
67 * @param {String} sGroup the group of related DragDrop objects
68 * @param {object} config an object containing configurable attributes
69 * Valid properties for DragDrop:
70 * padding, isTarget, maintainOffset, primaryButtonOnly
72 Roo.dd.DragDrop = function(id, sGroup, config) {
74 this.init(id, sGroup, config);
79 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
82 * The id of the element associated with this object. This is what we
83 * refer to as the "linked element" because the size and position of
84 * this element is used to determine when the drag and drop objects have
92 * Configuration attributes passed into the constructor
99 * The id of the element that will be dragged. By default this is same
100 * as the linked element , but could be changed to another element. Ex:
109 * the id of the element that initiates the drag operation. By default
110 * this is the linked element, but could be changed to be a child of this
111 * element. This lets us do things like only starting the drag when the
112 * header element within the linked html element is clicked.
113 * @property handleElId
120 * An associative array of HTML tags that will be ignored if clicked.
121 * @property invalidHandleTypes
122 * @type {string: string}
124 invalidHandleTypes: null,
127 * An associative array of ids for elements that will be ignored if clicked
128 * @property invalidHandleIds
129 * @type {string: string}
131 invalidHandleIds: null,
134 * An indexted array of css class names for elements that will be ignored
136 * @property invalidHandleClasses
139 invalidHandleClasses: null,
142 * The linked element's absolute X position at the time the drag was
144 * @property startPageX
151 * The linked element's absolute X position at the time the drag was
153 * @property startPageY
160 * The group defines a logical collection of DragDrop objects that are
161 * related. Instances only get events when interacting with other
162 * DragDrop object in the same group. This lets us define multiple
163 * groups using a single DragDrop subclass if we want.
165 * @type {string: string}
170 * Individual drag/drop instances can be locked. This will prevent
171 * onmousedown start drag.
182 lock: function() { this.locked = true; },
185 * Unlock this instace
188 unlock: function() { this.locked = false; },
191 * By default, all insances can be a drop target. This can be disabled by
192 * setting isTarget to false.
199 * The padding configured for this drag and drop object for calculating
200 * the drop zone intersection with this object.
207 * Cached reference to the linked element
214 * Internal typeof flag
215 * @property __ygDragDrop
221 * Set to true when horizontal contraints are applied
222 * @property constrainX
229 * Set to true when vertical contraints are applied
230 * @property constrainY
237 * The left constraint
245 * The right constraint
262 * The down constraint
270 * Maintain offsets when we resetconstraints. Set to true when you want
271 * the position of the element relative to its parent to stay the same
272 * when the page changes
274 * @property maintainOffset
277 maintainOffset: false,
280 * Array of pixel locations the element will snap to if we specified a
281 * horizontal graduation/interval. This array is generated automatically
282 * when you define a tick interval.
289 * Array of pixel locations the element will snap to if we specified a
290 * vertical graduation/interval. This array is generated automatically
291 * when you define a tick interval.
298 * By default the drag and drop instance will only respond to the primary
299 * button click (left button for a right-handed mouse). Set to true to
300 * allow drag and drop to start with any mouse click that is propogated
302 * @property primaryButtonOnly
305 primaryButtonOnly: true,
308 * The availabe property is false until the linked dom element is accessible.
309 * @property available
315 * By default, drags can only be initiated if the mousedown occurs in the
316 * region the linked element is. This is done in part to work around a
317 * bug in some browsers that mis-report the mousedown if the previous
318 * mouseup happened outside of the window. This property is set to true
319 * if outer handles are defined.
321 * @property hasOuterHandles
325 hasOuterHandles: false,
328 * Code that executes immediately before the startDrag event
329 * @method b4StartDrag
332 b4StartDrag: function(x, y) { },
335 * Abstract method called after a drag/drop object is clicked
336 * and the drag or mousedown time thresholds have beeen met.
338 * @param {int} X click location
339 * @param {int} Y click location
341 startDrag: function(x, y) { /* override this */ },
344 * Code that executes immediately before the onDrag event
348 b4Drag: function(e) { },
351 * Abstract method called during the onMouseMove event while dragging an
354 * @param {Event} e the mousemove event
356 onDrag: function(e) { /* override this */ },
359 * Abstract method called when this element fist begins hovering over
360 * another DragDrop obj
361 * @method onDragEnter
362 * @param {Event} e the mousemove event
363 * @param {String|DragDrop[]} id In POINT mode, the element
364 * id this is hovering over. In INTERSECT mode, an array of one or more
365 * dragdrop items being hovered over.
367 onDragEnter: function(e, id) { /* override this */ },
370 * Code that executes immediately before the onDragOver event
374 b4DragOver: function(e) { },
377 * Abstract method called when this element is hovering over another
380 * @param {Event} e the mousemove event
381 * @param {String|DragDrop[]} id In POINT mode, the element
382 * id this is hovering over. In INTERSECT mode, an array of dd items
383 * being hovered over.
385 onDragOver: function(e, id) { /* override this */ },
388 * Code that executes immediately before the onDragOut event
392 b4DragOut: function(e) { },
395 * Abstract method called when we are no longer hovering over an element
397 * @param {Event} e the mousemove event
398 * @param {String|DragDrop[]} id In POINT mode, the element
399 * id this was hovering over. In INTERSECT mode, an array of dd items
400 * that the mouse is no longer over.
402 onDragOut: function(e, id) { /* override this */ },
405 * Code that executes immediately before the onDragDrop event
409 b4DragDrop: function(e) { },
412 * Abstract method called when this item is dropped on another DragDrop
415 * @param {Event} e the mouseup event
416 * @param {String|DragDrop[]} id In POINT mode, the element
417 * id this was dropped on. In INTERSECT mode, an array of dd items this
420 onDragDrop: function(e, id) { /* override this */ },
423 * Abstract method called when this item is dropped on an area with no
425 * @method onInvalidDrop
426 * @param {Event} e the mouseup event
428 onInvalidDrop: function(e) { /* override this */ },
431 * Code that executes immediately before the endDrag event
435 b4EndDrag: function(e) { },
438 * Fired when we are done dragging the object
440 * @param {Event} e the mouseup event
442 endDrag: function(e) { /* override this */ },
445 * Code executed immediately before the onMouseDown event
446 * @method b4MouseDown
447 * @param {Event} e the mousedown event
450 b4MouseDown: function(e) { },
453 * Event handler that fires when a drag/drop obj gets a mousedown
454 * @method onMouseDown
455 * @param {Event} e the mousedown event
457 onMouseDown: function(e) { /* override this */ },
460 * Event handler that fires when a drag/drop obj gets a mouseup
462 * @param {Event} e the mouseup event
464 onMouseUp: function(e) { /* override this */ },
467 * Override the onAvailable method to do what is needed after the initial
468 * position was determined.
469 * @method onAvailable
471 onAvailable: function () {
475 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
478 defaultPadding : {left:0, right:0, top:0, bottom:0},
481 * Initializes the drag drop object's constraints to restrict movement to a certain element.
485 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
486 { dragElId: "existingProxyDiv" });
487 dd.startDrag = function(){
488 this.constrainTo("parent-id");
491 * Or you can initalize it using the {@link Roo.Element} object:
493 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
494 startDrag : function(){
495 this.constrainTo("parent-id");
499 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
500 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
501 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
502 * an object containing the sides to pad. For example: {right:10, bottom:10}
503 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
505 constrainTo : function(constrainTo, pad, inContent){
506 if(typeof pad == "number"){
507 pad = {left: pad, right:pad, top:pad, bottom:pad};
509 pad = pad || this.defaultPadding;
510 var b = Roo.get(this.getEl()).getBox();
511 var ce = Roo.get(constrainTo);
512 var s = ce.getScroll();
514 if(cd == document.body){
515 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
518 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
522 var topSpace = b.y - c.y;
523 var leftSpace = b.x - c.x;
525 this.resetConstraints();
526 this.setXConstraint(leftSpace - (pad.left||0), // left
527 c.width - leftSpace - b.width - (pad.right||0) //right
529 this.setYConstraint(topSpace - (pad.top||0), //top
530 c.height - topSpace - b.height - (pad.bottom||0) //bottom
535 * Returns a reference to the linked element
537 * @return {HTMLElement} the html element
541 this._domRef = Roo.getDom(this.id);
548 * Returns a reference to the actual element to drag. By default this is
549 * the same as the html element, but it can be assigned to another
550 * element. An example of this can be found in Roo.dd.DDProxy
552 * @return {HTMLElement} the html element
554 getDragEl: function() {
555 return Roo.getDom(this.dragElId);
559 * Sets up the DragDrop object. Must be called in the constructor of any
560 * Roo.dd.DragDrop subclass
562 * @param id the id of the linked element
563 * @param {String} sGroup the group of related items
564 * @param {object} config configuration attributes
566 init: function(id, sGroup, config) {
567 this.initTarget(id, sGroup, config);
569 Event.on(this.id, "mousedown", this.handleMouseDown, this);
571 Event.on(this.id, "touchstart", this.handleMouseDown, this);
572 // Event.on(this.id, "selectstart", Event.preventDefault);
576 * Initializes Targeting functionality only... the object does not
577 * get a mousedown handler.
579 * @param id the id of the linked element
580 * @param {String} sGroup the group of related items
581 * @param {object} config configuration attributes
583 initTarget: function(id, sGroup, config) {
585 // configuration attributes
586 this.config = config || {};
588 // create a local reference to the drag and drop manager
589 this.DDM = Roo.dd.DDM;
590 // initialize the groups array
593 // assume that we have an element reference instead of an id if the
594 // parameter is not a string
595 if (typeof id !== "string") {
602 // add to an interaction group
603 this.addToGroup((sGroup) ? sGroup : "default");
605 // We don't want to register this as the handle with the manager
606 // so we just set the id rather than calling the setter.
607 this.handleElId = id;
609 // the linked element is the element that gets dragged by default
610 this.setDragElId(id);
612 // by default, clicked anchors will not start drag operations.
613 this.invalidHandleTypes = { A: "A" };
614 this.invalidHandleIds = {};
615 this.invalidHandleClasses = [];
619 this.handleOnAvailable();
623 * Applies the configuration parameters that were passed into the constructor.
624 * This is supposed to happen at each level through the inheritance chain. So
625 * a DDProxy implentation will execute apply config on DDProxy, DD, and
626 * DragDrop in order to get all of the parameters that are available in
628 * @method applyConfig
630 applyConfig: function() {
632 // configurable properties:
633 // padding, isTarget, maintainOffset, primaryButtonOnly
634 this.padding = this.config.padding || [0, 0, 0, 0];
635 this.isTarget = (this.config.isTarget !== false);
636 this.maintainOffset = (this.config.maintainOffset);
637 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
642 * Executed when the linked element is available
643 * @method handleOnAvailable
646 handleOnAvailable: function() {
647 this.available = true;
648 this.resetConstraints();
653 * Configures the padding for the target zone in px. Effectively expands
654 * (or reduces) the virtual object size for targeting calculations.
655 * Supports css-style shorthand; if only one parameter is passed, all sides
656 * will have that padding, and if only two are passed, the top and bottom
657 * will have the first param, the left and right the second.
659 * @param {int} iTop Top pad
660 * @param {int} iRight Right pad
661 * @param {int} iBot Bot pad
662 * @param {int} iLeft Left pad
664 setPadding: function(iTop, iRight, iBot, iLeft) {
665 // this.padding = [iLeft, iRight, iTop, iBot];
666 if (!iRight && 0 !== iRight) {
667 this.padding = [iTop, iTop, iTop, iTop];
668 } else if (!iBot && 0 !== iBot) {
669 this.padding = [iTop, iRight, iTop, iRight];
671 this.padding = [iTop, iRight, iBot, iLeft];
676 * Stores the initial placement of the linked element.
677 * @method setInitialPosition
678 * @param {int} diffX the X offset, default 0
679 * @param {int} diffY the Y offset, default 0
681 setInitPosition: function(diffX, diffY) {
682 var el = this.getEl();
684 if (!this.DDM.verifyEl(el)) {
691 var p = Dom.getXY( el );
693 this.initPageX = p[0] - dx;
694 this.initPageY = p[1] - dy;
696 this.lastPageX = p[0];
697 this.lastPageY = p[1];
700 this.setStartPosition(p);
704 * Sets the start position of the element. This is set when the obj
705 * is initialized, the reset when a drag is started.
706 * @method setStartPosition
707 * @param pos current position (from previous lookup)
710 setStartPosition: function(pos) {
711 var p = pos || Dom.getXY( this.getEl() );
712 this.deltaSetXY = null;
714 this.startPageX = p[0];
715 this.startPageY = p[1];
719 * Add this instance to a group of related drag/drop objects. All
720 * instances belong to at least one group, and can belong to as many
723 * @param sGroup {string} the name of the group
725 addToGroup: function(sGroup) {
726 this.groups[sGroup] = true;
727 this.DDM.regDragDrop(this, sGroup);
731 * Remove's this instance from the supplied interaction group
732 * @method removeFromGroup
733 * @param {string} sGroup The group to drop
735 removeFromGroup: function(sGroup) {
736 if (this.groups[sGroup]) {
737 delete this.groups[sGroup];
740 this.DDM.removeDDFromGroup(this, sGroup);
744 * Allows you to specify that an element other than the linked element
745 * will be moved with the cursor during a drag
746 * @method setDragElId
747 * @param id {string} the id of the element that will be used to initiate the drag
749 setDragElId: function(id) {
754 * Allows you to specify a child of the linked element that should be
755 * used to initiate the drag operation. An example of this would be if
756 * you have a content div with text and links. Clicking anywhere in the
757 * content area would normally start the drag operation. Use this method
758 * to specify that an element inside of the content div is the element
759 * that starts the drag operation.
760 * @method setHandleElId
761 * @param id {string} the id of the element that will be used to
764 setHandleElId: function(id) {
765 if (typeof id !== "string") {
768 this.handleElId = id;
769 this.DDM.regHandle(this.id, id);
773 * Allows you to set an element outside of the linked element as a drag
775 * @method setOuterHandleElId
776 * @param id the id of the element that will be used to initiate the drag
778 setOuterHandleElId: function(id) {
779 if (typeof id !== "string") {
782 Event.on(id, "mousedown",
783 this.handleMouseDown, this);
784 this.setHandleElId(id);
786 this.hasOuterHandles = true;
790 * Remove all drag and drop hooks for this element
794 Event.un(this.id, "mousedown",
795 this.handleMouseDown);
796 Event.un(this.id, "touchstart",
797 this.handleMouseDown);
799 this.DDM._remove(this);
802 destroy : function(){
807 * Returns true if this instance is locked, or the drag drop mgr is locked
808 * (meaning that all drag/drop is disabled on the page.)
810 * @return {boolean} true if this obj or all drag/drop is locked, else
813 isLocked: function() {
814 return (this.DDM.isLocked() || this.locked);
818 * Fired when this object is clicked
819 * @method handleMouseDown
821 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
824 handleMouseDown: function(e, oDD){
827 if (!Roo.isTouch && this.primaryButtonOnly && e.button != 0) {
828 //Roo.log('not touch/ button !=0');
831 if (ev.browserEvent.touches && ev.browserEvent.touches.length != 1) {
832 return; // double touch..
836 if (this.isLocked()) {
841 this.DDM.refreshCache(this.groups);
842 Roo.log([Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e)]);
843 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
844 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
845 //Roo.log('no outer handes or not over target');
848 Roo.log('check validator');
849 if (this.clickValidator(e)) {
850 Roo.log('validate success');
851 // set the initial element position
852 this.setStartPosition();
858 this.DDM.handleMouseDown(e, this);
860 this.DDM.stopEvent(e);
868 clickValidator: function(e) {
869 var target = e.getTarget();
870 return ( this.isValidHandleChild(target) &&
871 (this.id == this.handleElId ||
872 this.DDM.handleWasClicked(target, this.id)) );
876 * Allows you to specify a tag name that should not start a drag operation
877 * when clicked. This is designed to facilitate embedding links within a
878 * drag handle that do something other than start the drag.
879 * @method addInvalidHandleType
880 * @param {string} tagName the type of element to exclude
882 addInvalidHandleType: function(tagName) {
883 var type = tagName.toUpperCase();
884 this.invalidHandleTypes[type] = type;
888 * Lets you to specify an element id for a child of a drag handle
889 * that should not initiate a drag
890 * @method addInvalidHandleId
891 * @param {string} id the element id of the element you wish to ignore
893 addInvalidHandleId: function(id) {
894 if (typeof id !== "string") {
897 this.invalidHandleIds[id] = id;
901 * Lets you specify a css class of elements that will not initiate a drag
902 * @method addInvalidHandleClass
903 * @param {string} cssClass the class of the elements you wish to ignore
905 addInvalidHandleClass: function(cssClass) {
906 this.invalidHandleClasses.push(cssClass);
910 * Unsets an excluded tag name set by addInvalidHandleType
911 * @method removeInvalidHandleType
912 * @param {string} tagName the type of element to unexclude
914 removeInvalidHandleType: function(tagName) {
915 var type = tagName.toUpperCase();
916 // this.invalidHandleTypes[type] = null;
917 delete this.invalidHandleTypes[type];
921 * Unsets an invalid handle id
922 * @method removeInvalidHandleId
923 * @param {string} id the id of the element to re-enable
925 removeInvalidHandleId: function(id) {
926 if (typeof id !== "string") {
929 delete this.invalidHandleIds[id];
933 * Unsets an invalid css class
934 * @method removeInvalidHandleClass
935 * @param {string} cssClass the class of the element(s) you wish to
938 removeInvalidHandleClass: function(cssClass) {
939 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
940 if (this.invalidHandleClasses[i] == cssClass) {
941 delete this.invalidHandleClasses[i];
947 * Checks the tag exclusion list to see if this click should be ignored
948 * @method isValidHandleChild
949 * @param {HTMLElement} node the HTMLElement to evaluate
950 * @return {boolean} true if this is a valid tag type, false if not
952 isValidHandleChild: function(node) {
955 // var n = (node.nodeName == "#text") ? node.parentNode : node;
958 nodeName = node.nodeName.toUpperCase();
960 nodeName = node.nodeName;
962 valid = valid && !this.invalidHandleTypes[nodeName];
963 valid = valid && !this.invalidHandleIds[node.id];
965 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
966 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
975 * Create the array of horizontal tick marks if an interval was specified
976 * in setXConstraint().
980 setXTicks: function(iStartX, iTickSize) {
982 this.xTickSize = iTickSize;
986 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
988 this.xTicks[this.xTicks.length] = i;
993 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
995 this.xTicks[this.xTicks.length] = i;
1000 this.xTicks.sort(this.DDM.numericSort) ;
1004 * Create the array of vertical tick marks if an interval was specified in
1009 setYTicks: function(iStartY, iTickSize) {
1011 this.yTickSize = iTickSize;
1015 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1017 this.yTicks[this.yTicks.length] = i;
1022 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1024 this.yTicks[this.yTicks.length] = i;
1029 this.yTicks.sort(this.DDM.numericSort) ;
1033 * By default, the element can be dragged any place on the screen. Use
1034 * this method to limit the horizontal travel of the element. Pass in
1035 * 0,0 for the parameters if you want to lock the drag to the y axis.
1036 * @method setXConstraint
1037 * @param {int} iLeft the number of pixels the element can move to the left
1038 * @param {int} iRight the number of pixels the element can move to the
1040 * @param {int} iTickSize optional parameter for specifying that the
1042 * should move iTickSize pixels at a time.
1044 setXConstraint: function(iLeft, iRight, iTickSize) {
1045 this.leftConstraint = iLeft;
1046 this.rightConstraint = iRight;
1048 this.minX = this.initPageX - iLeft;
1049 this.maxX = this.initPageX + iRight;
1050 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1052 this.constrainX = true;
1056 * Clears any constraints applied to this instance. Also clears ticks
1057 * since they can't exist independent of a constraint at this time.
1058 * @method clearConstraints
1060 clearConstraints: function() {
1061 this.constrainX = false;
1062 this.constrainY = false;
1067 * Clears any tick interval defined for this instance
1068 * @method clearTicks
1070 clearTicks: function() {
1078 * By default, the element can be dragged any place on the screen. Set
1079 * this to limit the vertical travel of the element. Pass in 0,0 for the
1080 * parameters if you want to lock the drag to the x axis.
1081 * @method setYConstraint
1082 * @param {int} iUp the number of pixels the element can move up
1083 * @param {int} iDown the number of pixels the element can move down
1084 * @param {int} iTickSize optional parameter for specifying that the
1085 * element should move iTickSize pixels at a time.
1087 setYConstraint: function(iUp, iDown, iTickSize) {
1088 this.topConstraint = iUp;
1089 this.bottomConstraint = iDown;
1091 this.minY = this.initPageY - iUp;
1092 this.maxY = this.initPageY + iDown;
1093 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1095 this.constrainY = true;
1100 * resetConstraints must be called if you manually reposition a dd element.
1101 * @method resetConstraints
1102 * @param {boolean} maintainOffset
1104 resetConstraints: function() {
1107 // Maintain offsets if necessary
1108 if (this.initPageX || this.initPageX === 0) {
1109 // figure out how much this thing has moved
1110 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1111 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1113 this.setInitPosition(dx, dy);
1115 // This is the first time we have detected the element's position
1117 this.setInitPosition();
1120 if (this.constrainX) {
1121 this.setXConstraint( this.leftConstraint,
1122 this.rightConstraint,
1126 if (this.constrainY) {
1127 this.setYConstraint( this.topConstraint,
1128 this.bottomConstraint,
1134 * Normally the drag element is moved pixel by pixel, but we can specify
1135 * that it move a number of pixels at a time. This method resolves the
1136 * location when we have it set up like this.
1138 * @param {int} val where we want to place the object
1139 * @param {int[]} tickArray sorted array of valid points
1140 * @return {int} the closest tick
1143 getTick: function(val, tickArray) {
1146 // If tick interval is not defined, it is effectively 1 pixel,
1147 // so we return the value passed to us.
1149 } else if (tickArray[0] >= val) {
1150 // The value is lower than the first tick, so we return the first
1152 return tickArray[0];
1154 for (var i=0, len=tickArray.length; i<len; ++i) {
1156 if (tickArray[next] && tickArray[next] >= val) {
1157 var diff1 = val - tickArray[i];
1158 var diff2 = tickArray[next] - val;
1159 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1163 // The value is larger than the last tick, so we return the last
1165 return tickArray[tickArray.length - 1];
1172 * @return {string} string representation of the dd obj
1174 toString: function() {
1175 return ("DragDrop " + this.id);
1183 * Ext JS Library 1.1.1
1184 * Copyright(c) 2006-2007, Ext JS, LLC.
1186 * Originally Released Under LGPL - original licence link has changed is not relivant.
1189 * <script type="text/javascript">
1194 * The drag and drop utility provides a framework for building drag and drop
1195 * applications. In addition to enabling drag and drop for specific elements,
1196 * the drag and drop elements are tracked by the manager class, and the
1197 * interactions between the various elements are tracked during the drag and
1198 * the implementing code is notified about these important moments.
1201 // Only load the library once. Rewriting the manager class would orphan
1202 // existing drag and drop instances.
1203 if (!Roo.dd.DragDropMgr) {
1206 * @class Roo.dd.DragDropMgr
1207 * DragDropMgr is a singleton that tracks the element interaction for
1208 * all DragDrop items in the window. Generally, you will not call
1209 * this class directly, but it does have helper methods that could
1210 * be useful in your DragDrop implementations.
1213 Roo.dd.DragDropMgr = function() {
1215 var Event = Roo.EventManager;
1220 * Two dimensional Array of registered DragDrop objects. The first
1221 * dimension is the DragDrop item group, the second the DragDrop
1224 * @type {string: string}
1231 * Array of element ids defined as drag handles. Used to determine
1232 * if the element that generated the mousedown event is actually the
1233 * handle and not the html element itself.
1234 * @property handleIds
1235 * @type {string: string}
1242 * the DragDrop object that is currently being dragged
1243 * @property dragCurrent
1251 * the DragDrop object(s) that are being hovered over
1252 * @property dragOvers
1260 * the X distance between the cursor and the object being dragged
1269 * the Y distance between the cursor and the object being dragged
1278 * Flag to determine if we should prevent the default behavior of the
1279 * events we define. By default this is true, but this can be set to
1280 * false if you need the default behavior (not recommended)
1281 * @property preventDefault
1285 preventDefault: true,
1288 * Flag to determine if we should stop the propagation of the events
1289 * we generate. This is true by default but you may want to set it to
1290 * false if the html element contains other features that require the
1292 * @property stopPropagation
1296 stopPropagation: true,
1299 * Internal flag that is set to true when drag and drop has been
1301 * @property initialized
1308 * All drag and drop can be disabled.
1316 * Called the first time an element is registered.
1322 this.initialized = true;
1326 * In point mode, drag and drop interaction is defined by the
1327 * location of the cursor during the drag/drop
1335 * In intersect mode, drag and drop interactio nis defined by the
1336 * overlap of two or more drag and drop objects.
1337 * @property INTERSECT
1344 * The current drag and drop mode. Default: POINT
1352 * Runs method on all drag and drop objects
1353 * @method _execOnAll
1357 _execOnAll: function(sMethod, args) {
1358 for (var i in this.ids) {
1359 for (var j in this.ids[i]) {
1360 var oDD = this.ids[i][j];
1361 if (! this.isTypeOfDD(oDD)) {
1364 oDD[sMethod].apply(oDD, args);
1370 * Drag and drop initialization. Sets up the global event handlers
1375 _onLoad: function() {
1380 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1381 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1383 Event.on(document, "touchend", this.handleMouseUp, this, true);
1384 Event.on(document, "touchmove", this.handleMouseMove, this, true);
1386 Event.on(window, "unload", this._onUnload, this, true);
1387 Event.on(window, "resize", this._onResize, this, true);
1388 // Event.on(window, "mouseout", this._test);
1393 * Reset constraints on all drag and drop objs
1398 _onResize: function(e) {
1399 this._execOnAll("resetConstraints", []);
1403 * Lock all drag and drop functionality
1407 lock: function() { this.locked = true; },
1410 * Unlock all drag and drop functionality
1414 unlock: function() { this.locked = false; },
1417 * Is drag and drop locked?
1419 * @return {boolean} True if drag and drop is locked, false otherwise.
1422 isLocked: function() { return this.locked; },
1425 * Location cache that is set for all drag drop objects when a drag is
1426 * initiated, cleared when the drag is finished.
1427 * @property locationCache
1434 * Set useCache to false if you want to force object the lookup of each
1435 * drag and drop linked element constantly during a drag.
1436 * @property useCache
1443 * The number of pixels that the mouse needs to move after the
1444 * mousedown before the drag is initiated. Default=3;
1445 * @property clickPixelThresh
1449 clickPixelThresh: 3,
1452 * The number of milliseconds after the mousedown event to initiate the
1453 * drag if we don't get a mouseup event. Default=1000
1454 * @property clickTimeThresh
1458 clickTimeThresh: 350,
1461 * Flag that indicates that either the drag pixel threshold or the
1462 * mousdown time threshold has been met
1463 * @property dragThreshMet
1468 dragThreshMet: false,
1471 * Timeout used for the click time threshold
1472 * @property clickTimeout
1480 * The X position of the mousedown event stored for later use when a
1481 * drag threshold is met.
1490 * The Y position of the mousedown event stored for later use when a
1491 * drag threshold is met.
1500 * Each DragDrop instance must be registered with the DragDropMgr.
1501 * This is executed in DragDrop.init()
1502 * @method regDragDrop
1503 * @param {DragDrop} oDD the DragDrop object to register
1504 * @param {String} sGroup the name of the group this element belongs to
1507 regDragDrop: function(oDD, sGroup) {
1508 if (!this.initialized) { this.init(); }
1510 if (!this.ids[sGroup]) {
1511 this.ids[sGroup] = {};
1513 this.ids[sGroup][oDD.id] = oDD;
1517 * Removes the supplied dd instance from the supplied group. Executed
1518 * by DragDrop.removeFromGroup, so don't call this function directly.
1519 * @method removeDDFromGroup
1523 removeDDFromGroup: function(oDD, sGroup) {
1524 if (!this.ids[sGroup]) {
1525 this.ids[sGroup] = {};
1528 var obj = this.ids[sGroup];
1529 if (obj && obj[oDD.id]) {
1535 * Unregisters a drag and drop item. This is executed in
1536 * DragDrop.unreg, use that method instead of calling this directly.
1541 _remove: function(oDD) {
1542 for (var g in oDD.groups) {
1543 if (g && this.ids[g][oDD.id]) {
1544 delete this.ids[g][oDD.id];
1547 delete this.handleIds[oDD.id];
1551 * Each DragDrop handle element must be registered. This is done
1552 * automatically when executing DragDrop.setHandleElId()
1554 * @param {String} sDDId the DragDrop id this element is a handle for
1555 * @param {String} sHandleId the id of the element that is the drag
1559 regHandle: function(sDDId, sHandleId) {
1560 if (!this.handleIds[sDDId]) {
1561 this.handleIds[sDDId] = {};
1563 this.handleIds[sDDId][sHandleId] = sHandleId;
1567 * Utility function to determine if a given element has been
1568 * registered as a drag drop item.
1569 * @method isDragDrop
1570 * @param {String} id the element id to check
1571 * @return {boolean} true if this element is a DragDrop item,
1575 isDragDrop: function(id) {
1576 return ( this.getDDById(id) ) ? true : false;
1580 * Returns the drag and drop instances that are in all groups the
1581 * passed in instance belongs to.
1582 * @method getRelated
1583 * @param {DragDrop} p_oDD the obj to get related data for
1584 * @param {boolean} bTargetsOnly if true, only return targetable objs
1585 * @return {DragDrop[]} the related instances
1588 getRelated: function(p_oDD, bTargetsOnly) {
1590 for (var i in p_oDD.groups) {
1591 for (j in this.ids[i]) {
1592 var dd = this.ids[i][j];
1593 if (! this.isTypeOfDD(dd)) {
1596 if (!bTargetsOnly || dd.isTarget) {
1597 oDDs[oDDs.length] = dd;
1606 * Returns true if the specified dd target is a legal target for
1607 * the specifice drag obj
1608 * @method isLegalTarget
1609 * @param {DragDrop} the drag obj
1610 * @param {DragDrop} the target
1611 * @return {boolean} true if the target is a legal target for the
1615 isLegalTarget: function (oDD, oTargetDD) {
1616 var targets = this.getRelated(oDD, true);
1617 for (var i=0, len=targets.length;i<len;++i) {
1618 if (targets[i].id == oTargetDD.id) {
1627 * My goal is to be able to transparently determine if an object is
1628 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1629 * returns "object", oDD.constructor.toString() always returns
1630 * "DragDrop" and not the name of the subclass. So for now it just
1631 * evaluates a well-known variable in DragDrop.
1632 * @method isTypeOfDD
1633 * @param {Object} the object to evaluate
1634 * @return {boolean} true if typeof oDD = DragDrop
1637 isTypeOfDD: function (oDD) {
1638 return (oDD && oDD.__ygDragDrop);
1642 * Utility function to determine if a given element has been
1643 * registered as a drag drop handle for the given Drag Drop object.
1645 * @param {String} id the element id to check
1646 * @return {boolean} true if this element is a DragDrop handle, false
1650 isHandle: function(sDDId, sHandleId) {
1651 return ( this.handleIds[sDDId] &&
1652 this.handleIds[sDDId][sHandleId] );
1656 * Returns the DragDrop instance for a given id
1658 * @param {String} id the id of the DragDrop object
1659 * @return {DragDrop} the drag drop object, null if it is not found
1662 getDDById: function(id) {
1663 for (var i in this.ids) {
1664 if (this.ids[i][id]) {
1665 return this.ids[i][id];
1672 * Fired after a registered DragDrop object gets the mousedown event.
1673 * Sets up the events required to track the object being dragged
1674 * @method handleMouseDown
1675 * @param {Event} e the event
1676 * @param oDD the DragDrop object being dragged
1680 handleMouseDown: function(e, oDD) {
1682 Roo.QuickTips.disable();
1684 this.currentTarget = e.getTarget();
1686 this.dragCurrent = oDD;
1688 var el = oDD.getEl();
1690 // track start position
1691 this.startX = e.getPageX();
1692 this.startY = e.getPageY();
1694 this.deltaX = this.startX - el.offsetLeft;
1695 this.deltaY = this.startY - el.offsetTop;
1697 this.dragThreshMet = false;
1699 this.clickTimeout = setTimeout(
1701 var DDM = Roo.dd.DDM;
1702 DDM.startDrag(DDM.startX, DDM.startY);
1704 this.clickTimeThresh );
1708 * Fired when either the drag pixel threshol or the mousedown hold
1709 * time threshold has been met.
1711 * @param x {int} the X position of the original mousedown
1712 * @param y {int} the Y position of the original mousedown
1715 startDrag: function(x, y) {
1716 clearTimeout(this.clickTimeout);
1717 if (this.dragCurrent) {
1718 this.dragCurrent.b4StartDrag(x, y);
1719 this.dragCurrent.startDrag(x, y);
1721 this.dragThreshMet = true;
1725 * Internal function to handle the mouseup event. Will be invoked
1726 * from the context of the document.
1727 * @method handleMouseUp
1728 * @param {Event} e the event
1732 handleMouseUp: function(e) {
1735 Roo.QuickTips.enable();
1737 if (! this.dragCurrent) {
1741 clearTimeout(this.clickTimeout);
1743 if (this.dragThreshMet) {
1744 this.fireEvents(e, true);
1754 * Utility to stop event propagation and event default, if these
1755 * features are turned on.
1757 * @param {Event} e the event as returned by this.getEvent()
1760 stopEvent: function(e){
1761 if(this.stopPropagation) {
1762 e.stopPropagation();
1765 if (this.preventDefault) {
1771 * Internal function to clean up event handlers after the drag
1772 * operation is complete
1774 * @param {Event} e the event
1778 stopDrag: function(e) {
1779 // Fire the drag end event for the item that was dragged
1780 if (this.dragCurrent) {
1781 if (this.dragThreshMet) {
1782 this.dragCurrent.b4EndDrag(e);
1783 this.dragCurrent.endDrag(e);
1786 this.dragCurrent.onMouseUp(e);
1789 this.dragCurrent = null;
1790 this.dragOvers = {};
1794 * Internal function to handle the mousemove event. Will be invoked
1795 * from the context of the html element.
1797 * @TODO figure out what we can do about mouse events lost when the
1798 * user drags objects beyond the window boundary. Currently we can
1799 * detect this in internet explorer by verifying that the mouse is
1800 * down during the mousemove event. Firefox doesn't give us the
1801 * button state on the mousemove event.
1802 * @method handleMouseMove
1803 * @param {Event} e the event
1807 handleMouseMove: function(e) {
1808 if (! this.dragCurrent) {
1812 // var button = e.which || e.button;
1814 // check for IE mouseup outside of page boundary
1815 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1817 return this.handleMouseUp(e);
1820 if (!this.dragThreshMet) {
1821 var diffX = Math.abs(this.startX - e.getPageX());
1822 var diffY = Math.abs(this.startY - e.getPageY());
1823 if (diffX > this.clickPixelThresh ||
1824 diffY > this.clickPixelThresh) {
1825 this.startDrag(this.startX, this.startY);
1829 if (this.dragThreshMet) {
1830 this.dragCurrent.b4Drag(e);
1831 this.dragCurrent.onDrag(e);
1832 if(!this.dragCurrent.moveOnly){
1833 this.fireEvents(e, false);
1843 * Iterates over all of the DragDrop elements to find ones we are
1844 * hovering over or dropping on
1845 * @method fireEvents
1846 * @param {Event} e the event
1847 * @param {boolean} isDrop is this a drop op or a mouseover op?
1851 fireEvents: function(e, isDrop) {
1852 var dc = this.dragCurrent;
1854 // If the user did the mouse up outside of the window, we could
1855 // get here even though we have ended the drag.
1856 if (!dc || dc.isLocked()) {
1860 var pt = e.getPoint();
1862 // cache the previous dragOver array
1870 // Check to see if the object(s) we were hovering over is no longer
1871 // being hovered over so we can fire the onDragOut event
1872 for (var i in this.dragOvers) {
1874 var ddo = this.dragOvers[i];
1876 if (! this.isTypeOfDD(ddo)) {
1880 if (! this.isOverTarget(pt, ddo, this.mode)) {
1881 outEvts.push( ddo );
1885 delete this.dragOvers[i];
1888 for (var sGroup in dc.groups) {
1890 if ("string" != typeof sGroup) {
1894 for (i in this.ids[sGroup]) {
1895 var oDD = this.ids[sGroup][i];
1896 if (! this.isTypeOfDD(oDD)) {
1900 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1901 if (this.isOverTarget(pt, oDD, this.mode)) {
1902 // look for drop interactions
1904 dropEvts.push( oDD );
1905 // look for drag enter and drag over interactions
1908 // initial drag over: dragEnter fires
1909 if (!oldOvers[oDD.id]) {
1910 enterEvts.push( oDD );
1911 // subsequent drag overs: dragOver fires
1913 overEvts.push( oDD );
1916 this.dragOvers[oDD.id] = oDD;
1924 if (outEvts.length) {
1925 dc.b4DragOut(e, outEvts);
1926 dc.onDragOut(e, outEvts);
1929 if (enterEvts.length) {
1930 dc.onDragEnter(e, enterEvts);
1933 if (overEvts.length) {
1934 dc.b4DragOver(e, overEvts);
1935 dc.onDragOver(e, overEvts);
1938 if (dropEvts.length) {
1939 dc.b4DragDrop(e, dropEvts);
1940 dc.onDragDrop(e, dropEvts);
1944 // fire dragout events
1946 for (i=0, len=outEvts.length; i<len; ++i) {
1947 dc.b4DragOut(e, outEvts[i].id);
1948 dc.onDragOut(e, outEvts[i].id);
1951 // fire enter events
1952 for (i=0,len=enterEvts.length; i<len; ++i) {
1953 // dc.b4DragEnter(e, oDD.id);
1954 dc.onDragEnter(e, enterEvts[i].id);
1958 for (i=0,len=overEvts.length; i<len; ++i) {
1959 dc.b4DragOver(e, overEvts[i].id);
1960 dc.onDragOver(e, overEvts[i].id);
1964 for (i=0, len=dropEvts.length; i<len; ++i) {
1965 dc.b4DragDrop(e, dropEvts[i].id);
1966 dc.onDragDrop(e, dropEvts[i].id);
1971 // notify about a drop that did not find a target
1972 if (isDrop && !dropEvts.length) {
1973 dc.onInvalidDrop(e);
1979 * Helper function for getting the best match from the list of drag
1980 * and drop objects returned by the drag and drop events when we are
1981 * in INTERSECT mode. It returns either the first object that the
1982 * cursor is over, or the object that has the greatest overlap with
1983 * the dragged element.
1984 * @method getBestMatch
1985 * @param {DragDrop[]} dds The array of drag and drop objects
1987 * @return {DragDrop} The best single match
1990 getBestMatch: function(dds) {
1992 // Return null if the input is not what we expect
1993 //if (!dds || !dds.length || dds.length == 0) {
1995 // If there is only one item, it wins
1996 //} else if (dds.length == 1) {
1998 var len = dds.length;
2003 // Loop through the targeted items
2004 for (var i=0; i<len; ++i) {
2006 // If the cursor is over the object, it wins. If the
2007 // cursor is over multiple matches, the first one we come
2009 if (dd.cursorIsOver) {
2012 // Otherwise the object with the most overlap wins
2015 winner.overlap.getArea() < dd.overlap.getArea()) {
2026 * Refreshes the cache of the top-left and bottom-right points of the
2027 * drag and drop objects in the specified group(s). This is in the
2028 * format that is stored in the drag and drop instance, so typical
2031 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2035 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2037 * @TODO this really should be an indexed array. Alternatively this
2038 * method could accept both.
2039 * @method refreshCache
2040 * @param {Object} groups an associative array of groups to refresh
2043 refreshCache: function(groups) {
2044 for (var sGroup in groups) {
2045 if ("string" != typeof sGroup) {
2048 for (var i in this.ids[sGroup]) {
2049 var oDD = this.ids[sGroup][i];
2051 if (this.isTypeOfDD(oDD)) {
2052 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2053 var loc = this.getLocation(oDD);
2055 this.locationCache[oDD.id] = loc;
2057 delete this.locationCache[oDD.id];
2058 // this will unregister the drag and drop object if
2059 // the element is not in a usable state
2068 * This checks to make sure an element exists and is in the DOM. The
2069 * main purpose is to handle cases where innerHTML is used to remove
2070 * drag and drop objects from the DOM. IE provides an 'unspecified
2071 * error' when trying to access the offsetParent of such an element
2073 * @param {HTMLElement} el the element to check
2074 * @return {boolean} true if the element looks usable
2077 verifyEl: function(el) {
2082 parent = el.offsetParent;
2085 parent = el.offsetParent;
2096 * Returns a Region object containing the drag and drop element's position
2097 * and size, including the padding configured for it
2098 * @method getLocation
2099 * @param {DragDrop} oDD the drag and drop object to get the
2101 * @return {Roo.lib.Region} a Region object representing the total area
2102 * the element occupies, including any padding
2103 * the instance is configured for.
2106 getLocation: function(oDD) {
2107 if (! this.isTypeOfDD(oDD)) {
2111 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2114 pos= Roo.lib.Dom.getXY(el);
2122 x2 = x1 + el.offsetWidth;
2124 y2 = y1 + el.offsetHeight;
2126 t = y1 - oDD.padding[0];
2127 r = x2 + oDD.padding[1];
2128 b = y2 + oDD.padding[2];
2129 l = x1 - oDD.padding[3];
2131 return new Roo.lib.Region( t, r, b, l );
2135 * Checks the cursor location to see if it over the target
2136 * @method isOverTarget
2137 * @param {Roo.lib.Point} pt The point to evaluate
2138 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2139 * @return {boolean} true if the mouse is over the target
2143 isOverTarget: function(pt, oTarget, intersect) {
2144 // use cache if available
2145 var loc = this.locationCache[oTarget.id];
2146 if (!loc || !this.useCache) {
2147 loc = this.getLocation(oTarget);
2148 this.locationCache[oTarget.id] = loc;
2156 oTarget.cursorIsOver = loc.contains( pt );
2158 // DragDrop is using this as a sanity check for the initial mousedown
2159 // in this case we are done. In POINT mode, if the drag obj has no
2160 // contraints, we are also done. Otherwise we need to evaluate the
2161 // location of the target as related to the actual location of the
2163 var dc = this.dragCurrent;
2164 if (!dc || !dc.getTargetCoord ||
2165 (!intersect && !dc.constrainX && !dc.constrainY)) {
2166 return oTarget.cursorIsOver;
2169 oTarget.overlap = null;
2171 // Get the current location of the drag element, this is the
2172 // location of the mouse event less the delta that represents
2173 // where the original mousedown happened on the element. We
2174 // need to consider constraints and ticks as well.
2175 var pos = dc.getTargetCoord(pt.x, pt.y);
2177 var el = dc.getDragEl();
2178 var curRegion = new Roo.lib.Region( pos.y,
2179 pos.x + el.offsetWidth,
2180 pos.y + el.offsetHeight,
2183 var overlap = curRegion.intersect(loc);
2186 oTarget.overlap = overlap;
2187 return (intersect) ? true : oTarget.cursorIsOver;
2194 * unload event handler
2199 _onUnload: function(e, me) {
2200 Roo.dd.DragDropMgr.unregAll();
2204 * Cleans up the drag and drop events and objects.
2209 unregAll: function() {
2211 if (this.dragCurrent) {
2213 this.dragCurrent = null;
2216 this._execOnAll("unreg", []);
2218 for (i in this.elementCache) {
2219 delete this.elementCache[i];
2222 this.elementCache = {};
2227 * A cache of DOM elements
2228 * @property elementCache
2235 * Get the wrapper for the DOM element specified
2236 * @method getElWrapper
2237 * @param {String} id the id of the element to get
2238 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2240 * @deprecated This wrapper isn't that useful
2243 getElWrapper: function(id) {
2244 var oWrapper = this.elementCache[id];
2245 if (!oWrapper || !oWrapper.el) {
2246 oWrapper = this.elementCache[id] =
2247 new this.ElementWrapper(Roo.getDom(id));
2253 * Returns the actual DOM element
2254 * @method getElement
2255 * @param {String} id the id of the elment to get
2256 * @return {Object} The element
2257 * @deprecated use Roo.getDom instead
2260 getElement: function(id) {
2261 return Roo.getDom(id);
2265 * Returns the style property for the DOM element (i.e.,
2266 * document.getElById(id).style)
2268 * @param {String} id the id of the elment to get
2269 * @return {Object} The style property of the element
2270 * @deprecated use Roo.getDom instead
2273 getCss: function(id) {
2274 var el = Roo.getDom(id);
2275 return (el) ? el.style : null;
2279 * Inner class for cached elements
2280 * @class DragDropMgr.ElementWrapper
2285 ElementWrapper: function(el) {
2290 this.el = el || null;
2295 this.id = this.el && el.id;
2297 * A reference to the style property
2300 this.css = this.el && el.style;
2304 * Returns the X position of an html element
2306 * @param el the element for which to get the position
2307 * @return {int} the X coordinate
2309 * @deprecated use Roo.lib.Dom.getX instead
2312 getPosX: function(el) {
2313 return Roo.lib.Dom.getX(el);
2317 * Returns the Y position of an html element
2319 * @param el the element for which to get the position
2320 * @return {int} the Y coordinate
2321 * @deprecated use Roo.lib.Dom.getY instead
2324 getPosY: function(el) {
2325 return Roo.lib.Dom.getY(el);
2329 * Swap two nodes. In IE, we use the native method, for others we
2330 * emulate the IE behavior
2332 * @param n1 the first node to swap
2333 * @param n2 the other node to swap
2336 swapNode: function(n1, n2) {
2340 var p = n2.parentNode;
2341 var s = n2.nextSibling;
2344 p.insertBefore(n1, n2);
2345 } else if (n2 == n1.nextSibling) {
2346 p.insertBefore(n2, n1);
2348 n1.parentNode.replaceChild(n2, n1);
2349 p.insertBefore(n1, s);
2355 * Returns the current scroll position
2360 getScroll: function () {
2361 var t, l, dde=document.documentElement, db=document.body;
2362 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2371 return { top: t, left: l };
2375 * Returns the specified element style property
2377 * @param {HTMLElement} el the element
2378 * @param {string} styleProp the style property
2379 * @return {string} The value of the style property
2380 * @deprecated use Roo.lib.Dom.getStyle
2383 getStyle: function(el, styleProp) {
2384 return Roo.fly(el).getStyle(styleProp);
2388 * Gets the scrollTop
2389 * @method getScrollTop
2390 * @return {int} the document's scrollTop
2393 getScrollTop: function () { return this.getScroll().top; },
2396 * Gets the scrollLeft
2397 * @method getScrollLeft
2398 * @return {int} the document's scrollTop
2401 getScrollLeft: function () { return this.getScroll().left; },
2404 * Sets the x/y position of an element to the location of the
2407 * @param {HTMLElement} moveEl The element to move
2408 * @param {HTMLElement} targetEl The position reference element
2411 moveToEl: function (moveEl, targetEl) {
2412 var aCoord = Roo.lib.Dom.getXY(targetEl);
2413 Roo.lib.Dom.setXY(moveEl, aCoord);
2417 * Numeric array sort function
2418 * @method numericSort
2421 numericSort: function(a, b) { return (a - b); },
2425 * @property _timeoutCount
2432 * Trying to make the load order less important. Without this we get
2433 * an error if this file is loaded before the Event Utility.
2434 * @method _addListeners
2438 _addListeners: function() {
2439 var DDM = Roo.dd.DDM;
2440 if ( Roo.lib.Event && document ) {
2443 if (DDM._timeoutCount > 2000) {
2445 setTimeout(DDM._addListeners, 10);
2446 if (document && document.body) {
2447 DDM._timeoutCount += 1;
2454 * Recursively searches the immediate parent and all child nodes for
2455 * the handle element in order to determine wheter or not it was
2457 * @method handleWasClicked
2458 * @param node the html element to inspect
2461 handleWasClicked: function(node, id) {
2462 if (this.isHandle(id, node.id)) {
2465 // check to see if this is a text node child of the one we want
2466 var p = node.parentNode;
2469 if (this.isHandle(id, p.id)) {
2484 // shorter alias, save a few bytes
2485 Roo.dd.DDM = Roo.dd.DragDropMgr;
2486 Roo.dd.DDM._addListeners();
2490 * Ext JS Library 1.1.1
2491 * Copyright(c) 2006-2007, Ext JS, LLC.
2493 * Originally Released Under LGPL - original licence link has changed is not relivant.
2496 * <script type="text/javascript">
2501 * A DragDrop implementation where the linked element follows the
2502 * mouse cursor during a drag.
2503 * @extends Roo.dd.DragDrop
2505 * @param {String} id the id of the linked element
2506 * @param {String} sGroup the group of related DragDrop items
2507 * @param {object} config an object containing configurable attributes
2508 * Valid properties for DD:
2511 Roo.dd.DD = function(id, sGroup, config) {
2513 this.init(id, sGroup, config);
2517 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2520 * When set to true, the utility automatically tries to scroll the browser
2521 * window wehn a drag and drop element is dragged near the viewport boundary.
2529 * Sets the pointer offset to the distance between the linked element's top
2530 * left corner and the location the element was clicked
2531 * @method autoOffset
2532 * @param {int} iPageX the X coordinate of the click
2533 * @param {int} iPageY the Y coordinate of the click
2535 autoOffset: function(iPageX, iPageY) {
2536 var x = iPageX - this.startPageX;
2537 var y = iPageY - this.startPageY;
2538 this.setDelta(x, y);
2542 * Sets the pointer offset. You can call this directly to force the
2543 * offset to be in a particular location (e.g., pass in 0,0 to set it
2544 * to the center of the object)
2546 * @param {int} iDeltaX the distance from the left
2547 * @param {int} iDeltaY the distance from the top
2549 setDelta: function(iDeltaX, iDeltaY) {
2550 this.deltaX = iDeltaX;
2551 this.deltaY = iDeltaY;
2555 * Sets the drag element to the location of the mousedown or click event,
2556 * maintaining the cursor location relative to the location on the element
2557 * that was clicked. Override this if you want to place the element in a
2558 * location other than where the cursor is.
2559 * @method setDragElPos
2560 * @param {int} iPageX the X coordinate of the mousedown or drag event
2561 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2563 setDragElPos: function(iPageX, iPageY) {
2564 // the first time we do this, we are going to check to make sure
2565 // the element has css positioning
2567 var el = this.getDragEl();
2568 this.alignElWithMouse(el, iPageX, iPageY);
2572 * Sets the element to the location of the mousedown or click event,
2573 * maintaining the cursor location relative to the location on the element
2574 * that was clicked. Override this if you want to place the element in a
2575 * location other than where the cursor is.
2576 * @method alignElWithMouse
2577 * @param {HTMLElement} el the element to move
2578 * @param {int} iPageX the X coordinate of the mousedown or drag event
2579 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2581 alignElWithMouse: function(el, iPageX, iPageY) {
2582 var oCoord = this.getTargetCoord(iPageX, iPageY);
2583 var fly = el.dom ? el : Roo.fly(el);
2584 if (!this.deltaSetXY) {
2585 var aCoord = [oCoord.x, oCoord.y];
2587 var newLeft = fly.getLeft(true);
2588 var newTop = fly.getTop(true);
2589 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2591 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2594 this.cachePosition(oCoord.x, oCoord.y);
2595 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2600 * Saves the most recent position so that we can reset the constraints and
2601 * tick marks on-demand. We need to know this so that we can calculate the
2602 * number of pixels the element is offset from its original position.
2603 * @method cachePosition
2604 * @param iPageX the current x position (optional, this just makes it so we
2605 * don't have to look it up again)
2606 * @param iPageY the current y position (optional, this just makes it so we
2607 * don't have to look it up again)
2609 cachePosition: function(iPageX, iPageY) {
2611 this.lastPageX = iPageX;
2612 this.lastPageY = iPageY;
2614 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2615 this.lastPageX = aCoord[0];
2616 this.lastPageY = aCoord[1];
2621 * Auto-scroll the window if the dragged object has been moved beyond the
2622 * visible window boundary.
2623 * @method autoScroll
2624 * @param {int} x the drag element's x position
2625 * @param {int} y the drag element's y position
2626 * @param {int} h the height of the drag element
2627 * @param {int} w the width of the drag element
2630 autoScroll: function(x, y, h, w) {
2633 // The client height
2634 var clientH = Roo.lib.Dom.getViewWidth();
2637 var clientW = Roo.lib.Dom.getViewHeight();
2639 // The amt scrolled down
2640 var st = this.DDM.getScrollTop();
2642 // The amt scrolled right
2643 var sl = this.DDM.getScrollLeft();
2645 // Location of the bottom of the element
2648 // Location of the right of the element
2651 // The distance from the cursor to the bottom of the visible area,
2652 // adjusted so that we don't scroll if the cursor is beyond the
2653 // element drag constraints
2654 var toBot = (clientH + st - y - this.deltaY);
2656 // The distance from the cursor to the right of the visible area
2657 var toRight = (clientW + sl - x - this.deltaX);
2660 // How close to the edge the cursor must be before we scroll
2661 // var thresh = (document.all) ? 100 : 40;
2664 // How many pixels to scroll per autoscroll op. This helps to reduce
2665 // clunky scrolling. IE is more sensitive about this ... it needs this
2666 // value to be higher.
2667 var scrAmt = (document.all) ? 80 : 30;
2669 // Scroll down if we are near the bottom of the visible page and the
2670 // obj extends below the crease
2671 if ( bot > clientH && toBot < thresh ) {
2672 window.scrollTo(sl, st + scrAmt);
2675 // Scroll up if the window is scrolled down and the top of the object
2676 // goes above the top border
2677 if ( y < st && st > 0 && y - st < thresh ) {
2678 window.scrollTo(sl, st - scrAmt);
2681 // Scroll right if the obj is beyond the right border and the cursor is
2683 if ( right > clientW && toRight < thresh ) {
2684 window.scrollTo(sl + scrAmt, st);
2687 // Scroll left if the window has been scrolled to the right and the obj
2688 // extends past the left border
2689 if ( x < sl && sl > 0 && x - sl < thresh ) {
2690 window.scrollTo(sl - scrAmt, st);
2696 * Finds the location the element should be placed if we want to move
2697 * it to where the mouse location less the click offset would place us.
2698 * @method getTargetCoord
2699 * @param {int} iPageX the X coordinate of the click
2700 * @param {int} iPageY the Y coordinate of the click
2701 * @return an object that contains the coordinates (Object.x and Object.y)
2704 getTargetCoord: function(iPageX, iPageY) {
2707 var x = iPageX - this.deltaX;
2708 var y = iPageY - this.deltaY;
2710 if (this.constrainX) {
2711 if (x < this.minX) { x = this.minX; }
2712 if (x > this.maxX) { x = this.maxX; }
2715 if (this.constrainY) {
2716 if (y < this.minY) { y = this.minY; }
2717 if (y > this.maxY) { y = this.maxY; }
2720 x = this.getTick(x, this.xTicks);
2721 y = this.getTick(y, this.yTicks);
2728 * Sets up config options specific to this class. Overrides
2729 * Roo.dd.DragDrop, but all versions of this method through the
2730 * inheritance chain are called
2732 applyConfig: function() {
2733 Roo.dd.DD.superclass.applyConfig.call(this);
2734 this.scroll = (this.config.scroll !== false);
2738 * Event that fires prior to the onMouseDown event. Overrides
2741 b4MouseDown: function(e) {
2742 // this.resetConstraints();
2743 this.autoOffset(e.getPageX(),
2748 * Event that fires prior to the onDrag event. Overrides
2751 b4Drag: function(e) {
2752 this.setDragElPos(e.getPageX(),
2756 toString: function() {
2757 return ("DD " + this.id);
2760 //////////////////////////////////////////////////////////////////////////
2761 // Debugging ygDragDrop events that can be overridden
2762 //////////////////////////////////////////////////////////////////////////
2764 startDrag: function(x, y) {
2767 onDrag: function(e) {
2770 onDragEnter: function(e, id) {
2773 onDragOver: function(e, id) {
2776 onDragOut: function(e, id) {
2779 onDragDrop: function(e, id) {
2782 endDrag: function(e) {
2789 * Ext JS Library 1.1.1
2790 * Copyright(c) 2006-2007, Ext JS, LLC.
2792 * Originally Released Under LGPL - original licence link has changed is not relivant.
2795 * <script type="text/javascript">
2799 * @class Roo.dd.DDProxy
2800 * A DragDrop implementation that inserts an empty, bordered div into
2801 * the document that follows the cursor during drag operations. At the time of
2802 * the click, the frame div is resized to the dimensions of the linked html
2803 * element, and moved to the exact location of the linked element.
2805 * References to the "frame" element refer to the single proxy element that
2806 * was created to be dragged in place of all DDProxy elements on the
2809 * @extends Roo.dd.DD
2811 * @param {String} id the id of the linked html element
2812 * @param {String} sGroup the group of related DragDrop objects
2813 * @param {object} config an object containing configurable attributes
2814 * Valid properties for DDProxy in addition to those in DragDrop:
2815 * resizeFrame, centerFrame, dragElId
2817 Roo.dd.DDProxy = function(id, sGroup, config) {
2819 this.init(id, sGroup, config);
2825 * The default drag frame div id
2826 * @property Roo.dd.DDProxy.dragElId
2830 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2832 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2835 * By default we resize the drag frame to be the same size as the element
2836 * we want to drag (this is to get the frame effect). We can turn it off
2837 * if we want a different behavior.
2838 * @property resizeFrame
2844 * By default the frame is positioned exactly where the drag element is, so
2845 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2846 * you do not have constraints on the obj is to have the drag frame centered
2847 * around the cursor. Set centerFrame to true for this effect.
2848 * @property centerFrame
2854 * Creates the proxy element if it does not yet exist
2855 * @method createFrame
2857 createFrame: function() {
2859 var body = document.body;
2861 if (!body || !body.firstChild) {
2862 setTimeout( function() { self.createFrame(); }, 50 );
2866 var div = this.getDragEl();
2869 div = document.createElement("div");
2870 div.id = this.dragElId;
2873 s.position = "absolute";
2874 s.visibility = "hidden";
2876 s.border = "2px solid #aaa";
2879 // appendChild can blow up IE if invoked prior to the window load event
2880 // while rendering a table. It is possible there are other scenarios
2881 // that would cause this to happen as well.
2882 body.insertBefore(div, body.firstChild);
2887 * Initialization for the drag frame element. Must be called in the
2888 * constructor of all subclasses
2891 initFrame: function() {
2895 applyConfig: function() {
2896 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2898 this.resizeFrame = (this.config.resizeFrame !== false);
2899 this.centerFrame = (this.config.centerFrame);
2900 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2904 * Resizes the drag frame to the dimensions of the clicked object, positions
2905 * it over the object, and finally displays it
2907 * @param {int} iPageX X click position
2908 * @param {int} iPageY Y click position
2911 showFrame: function(iPageX, iPageY) {
2912 var el = this.getEl();
2913 var dragEl = this.getDragEl();
2914 var s = dragEl.style;
2916 this._resizeProxy();
2918 if (this.centerFrame) {
2919 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2920 Math.round(parseInt(s.height, 10)/2) );
2923 this.setDragElPos(iPageX, iPageY);
2925 Roo.fly(dragEl).show();
2929 * The proxy is automatically resized to the dimensions of the linked
2930 * element when a drag is initiated, unless resizeFrame is set to false
2931 * @method _resizeProxy
2934 _resizeProxy: function() {
2935 if (this.resizeFrame) {
2936 var el = this.getEl();
2937 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2941 // overrides Roo.dd.DragDrop
2942 b4MouseDown: function(e) {
2943 var x = e.getPageX();
2944 var y = e.getPageY();
2945 this.autoOffset(x, y);
2946 this.setDragElPos(x, y);
2949 // overrides Roo.dd.DragDrop
2950 b4StartDrag: function(x, y) {
2951 // show the drag frame
2952 this.showFrame(x, y);
2955 // overrides Roo.dd.DragDrop
2956 b4EndDrag: function(e) {
2957 Roo.fly(this.getDragEl()).hide();
2960 // overrides Roo.dd.DragDrop
2961 // By default we try to move the element to the last location of the frame.
2962 // This is so that the default behavior mirrors that of Roo.dd.DD.
2963 endDrag: function(e) {
2965 var lel = this.getEl();
2966 var del = this.getDragEl();
2968 // Show the drag frame briefly so we can get its position
2969 del.style.visibility = "";
2972 // Hide the linked element before the move to get around a Safari
2974 lel.style.visibility = "hidden";
2975 Roo.dd.DDM.moveToEl(lel, del);
2976 del.style.visibility = "hidden";
2977 lel.style.visibility = "";
2982 beforeMove : function(){
2986 afterDrag : function(){
2990 toString: function() {
2991 return ("DDProxy " + this.id);
2997 * Ext JS Library 1.1.1
2998 * Copyright(c) 2006-2007, Ext JS, LLC.
3000 * Originally Released Under LGPL - original licence link has changed is not relivant.
3003 * <script type="text/javascript">
3007 * @class Roo.dd.DDTarget
3008 * A DragDrop implementation that does not move, but can be a drop
3009 * target. You would get the same result by simply omitting implementation
3010 * for the event callbacks, but this way we reduce the processing cost of the
3011 * event listener and the callbacks.
3012 * @extends Roo.dd.DragDrop
3014 * @param {String} id the id of the element that is a drop target
3015 * @param {String} sGroup the group of related DragDrop objects
3016 * @param {object} config an object containing configurable attributes
3017 * Valid properties for DDTarget in addition to those in
3021 Roo.dd.DDTarget = function(id, sGroup, config) {
3023 this.initTarget(id, sGroup, config);
3025 if (config.listeners || config.events) {
3026 Roo.dd.DragDrop.superclass.constructor.call(this, {
3027 listeners : config.listeners || {},
3028 events : config.events || {}
3033 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3034 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3035 toString: function() {
3036 return ("DDTarget " + this.id);
3041 * Ext JS Library 1.1.1
3042 * Copyright(c) 2006-2007, Ext JS, LLC.
3044 * Originally Released Under LGPL - original licence link has changed is not relivant.
3047 * <script type="text/javascript">
3052 * @class Roo.dd.ScrollManager
3053 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3054 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3057 Roo.dd.ScrollManager = function(){
3058 var ddm = Roo.dd.DragDropMgr;
3065 var onStop = function(e){
3070 var triggerRefresh = function(){
3071 if(ddm.dragCurrent){
3072 ddm.refreshCache(ddm.dragCurrent.groups);
3076 var doScroll = function(){
3077 if(ddm.dragCurrent){
3078 var dds = Roo.dd.ScrollManager;
3080 if(proc.el.scroll(proc.dir, dds.increment)){
3084 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3089 var clearProc = function(){
3091 clearInterval(proc.id);
3098 var startProc = function(el, dir){
3099 Roo.log('scroll startproc');
3103 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3106 var onFire = function(e, isDrop){
3108 if(isDrop || !ddm.dragCurrent){ return; }
3109 var dds = Roo.dd.ScrollManager;
3110 if(!dragEl || dragEl != ddm.dragCurrent){
3111 dragEl = ddm.dragCurrent;
3112 // refresh regions on drag start
3116 var xy = Roo.lib.Event.getXY(e);
3117 var pt = new Roo.lib.Point(xy[0], xy[1]);
3119 var el = els[id], r = el._region;
3120 if(r && r.contains(pt) && el.isScrollable()){
3121 if(r.bottom - pt.y <= dds.thresh){
3123 startProc(el, "down");
3126 }else if(r.right - pt.x <= dds.thresh){
3128 startProc(el, "left");
3131 }else if(pt.y - r.top <= dds.thresh){
3133 startProc(el, "up");
3136 }else if(pt.x - r.left <= dds.thresh){
3138 startProc(el, "right");
3147 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3148 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3152 * Registers new overflow element(s) to auto scroll
3153 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3155 register : function(el){
3156 if(el instanceof Array){
3157 for(var i = 0, len = el.length; i < len; i++) {
3158 this.register(el[i]);
3164 Roo.dd.ScrollManager.els = els;
3168 * Unregisters overflow element(s) so they are no longer scrolled
3169 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3171 unregister : function(el){
3172 if(el instanceof Array){
3173 for(var i = 0, len = el.length; i < len; i++) {
3174 this.unregister(el[i]);
3183 * The number of pixels from the edge of a container the pointer needs to be to
3184 * trigger scrolling (defaults to 25)
3190 * The number of pixels to scroll in each scroll increment (defaults to 50)
3196 * The frequency of scrolls in milliseconds (defaults to 500)
3202 * True to animate the scroll (defaults to true)
3208 * The animation duration in seconds -
3209 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3215 * Manually trigger a cache refresh.
3217 refreshCache : function(){
3219 if(typeof els[id] == 'object'){ // for people extending the object prototype
3220 els[id]._region = els[id].getRegion();
3227 * Ext JS Library 1.1.1
3228 * Copyright(c) 2006-2007, Ext JS, LLC.
3230 * Originally Released Under LGPL - original licence link has changed is not relivant.
3233 * <script type="text/javascript">
3238 * @class Roo.dd.Registry
3239 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3240 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3243 Roo.dd.Registry = function(){
3248 var getId = function(el, autogen){
3249 if(typeof el == "string"){
3253 if(!id && autogen !== false){
3254 id = "roodd-" + (++autoIdSeed);
3262 * Register a drag drop element
3263 * @param {String|HTMLElement} element The id or DOM node to register
3264 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3265 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3266 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3267 * populated in the data object (if applicable):
3269 Value Description<br />
3270 --------- ------------------------------------------<br />
3271 handles Array of DOM nodes that trigger dragging<br />
3272 for the element being registered<br />
3273 isHandle True if the element passed in triggers<br />
3274 dragging itself, else false
3277 register : function(el, data){
3279 if(typeof el == "string"){
3280 el = document.getElementById(el);
3283 elements[getId(el)] = data;
3284 if(data.isHandle !== false){
3285 handles[data.ddel.id] = data;
3288 var hs = data.handles;
3289 for(var i = 0, len = hs.length; i < len; i++){
3290 handles[getId(hs[i])] = data;
3296 * Unregister a drag drop element
3297 * @param {String|HTMLElement} element The id or DOM node to unregister
3299 unregister : function(el){
3300 var id = getId(el, false);
3301 var data = elements[id];
3303 delete elements[id];
3305 var hs = data.handles;
3306 for(var i = 0, len = hs.length; i < len; i++){
3307 delete handles[getId(hs[i], false)];
3314 * Returns the handle registered for a DOM Node by id
3315 * @param {String|HTMLElement} id The DOM node or id to look up
3316 * @return {Object} handle The custom handle data
3318 getHandle : function(id){
3319 if(typeof id != "string"){ // must be element?
3326 * Returns the handle that is registered for the DOM node that is the target of the event
3327 * @param {Event} e The event
3328 * @return {Object} handle The custom handle data
3330 getHandleFromEvent : function(e){
3331 var t = Roo.lib.Event.getTarget(e);
3332 return t ? handles[t.id] : null;
3336 * Returns a custom data object that is registered for a DOM node by id
3337 * @param {String|HTMLElement} id The DOM node or id to look up
3338 * @return {Object} data The custom data
3340 getTarget : function(id){
3341 if(typeof id != "string"){ // must be element?
3344 return elements[id];
3348 * Returns a custom data object that is registered for the DOM node that is the target of the event
3349 * @param {Event} e The event
3350 * @return {Object} data The custom data
3352 getTargetFromEvent : function(e){
3353 var t = Roo.lib.Event.getTarget(e);
3354 return t ? elements[t.id] || handles[t.id] : null;
3359 * Ext JS Library 1.1.1
3360 * Copyright(c) 2006-2007, Ext JS, LLC.
3362 * Originally Released Under LGPL - original licence link has changed is not relivant.
3365 * <script type="text/javascript">
3370 * @class Roo.dd.StatusProxy
3371 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3372 * default drag proxy used by all Roo.dd components.
3374 * @param {Object} config
3376 Roo.dd.StatusProxy = function(config){
3377 Roo.apply(this, config);
3378 this.id = this.id || Roo.id();
3379 this.el = new Roo.Layer({
3381 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3382 {tag: "div", cls: "x-dd-drop-icon"},
3383 {tag: "div", cls: "x-dd-drag-ghost"}
3386 shadow: !config || config.shadow !== false
3388 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3389 this.dropStatus = this.dropNotAllowed;
3392 Roo.dd.StatusProxy.prototype = {
3394 * @cfg {String} dropAllowed
3395 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3397 dropAllowed : "x-dd-drop-ok",
3399 * @cfg {String} dropNotAllowed
3400 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3402 dropNotAllowed : "x-dd-drop-nodrop",
3405 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3406 * over the current target element.
3407 * @param {String} cssClass The css class for the new drop status indicator image
3409 setStatus : function(cssClass){
3410 cssClass = cssClass || this.dropNotAllowed;
3411 if(this.dropStatus != cssClass){
3412 this.el.replaceClass(this.dropStatus, cssClass);
3413 this.dropStatus = cssClass;
3418 * Resets the status indicator to the default dropNotAllowed value
3419 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3421 reset : function(clearGhost){
3422 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3423 this.dropStatus = this.dropNotAllowed;
3425 this.ghost.update("");
3430 * Updates the contents of the ghost element
3431 * @param {String} html The html that will replace the current innerHTML of the ghost element
3433 update : function(html){
3434 if(typeof html == "string"){
3435 this.ghost.update(html);
3437 this.ghost.update("");
3438 html.style.margin = "0";
3439 this.ghost.dom.appendChild(html);
3441 // ensure float = none set?? cant remember why though.
3442 var el = this.ghost.dom.firstChild;
3444 Roo.fly(el).setStyle('float', 'none');
3449 * Returns the underlying proxy {@link Roo.Layer}
3450 * @return {Roo.Layer} el
3457 * Returns the ghost element
3458 * @return {Roo.Element} el
3460 getGhost : function(){
3466 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3468 hide : function(clear){
3476 * Stops the repair animation if it's currently running
3479 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3485 * Displays this proxy
3492 * Force the Layer to sync its shadow and shim positions to the element
3499 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3500 * invalid drop operation by the item being dragged.
3501 * @param {Array} xy The XY position of the element ([x, y])
3502 * @param {Function} callback The function to call after the repair is complete
3503 * @param {Object} scope The scope in which to execute the callback
3505 repair : function(xy, callback, scope){
3506 this.callback = callback;
3508 if(xy && this.animRepair !== false){
3509 this.el.addClass("x-dd-drag-repair");
3510 this.el.hideUnders(true);
3511 this.anim = this.el.shift({
3512 duration: this.repairDuration || .5,
3516 callback: this.afterRepair,
3525 afterRepair : function(){
3527 if(typeof this.callback == "function"){
3528 this.callback.call(this.scope || this);
3530 this.callback = null;
3535 * Ext JS Library 1.1.1
3536 * Copyright(c) 2006-2007, Ext JS, LLC.
3538 * Originally Released Under LGPL - original licence link has changed is not relivant.
3541 * <script type="text/javascript">
3545 * @class Roo.dd.DragSource
3546 * @extends Roo.dd.DDProxy
3547 * A simple class that provides the basic implementation needed to make any element draggable.
3549 * @param {String/HTMLElement/Element} el The container element
3550 * @param {Object} config
3552 Roo.dd.DragSource = function(el, config){
3553 this.el = Roo.get(el);
3556 Roo.apply(this, config);
3559 this.proxy = new Roo.dd.StatusProxy();
3562 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3563 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3565 this.dragging = false;
3568 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3570 * @cfg {String} dropAllowed
3571 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3573 dropAllowed : "x-dd-drop-ok",
3575 * @cfg {String} dropNotAllowed
3576 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3578 dropNotAllowed : "x-dd-drop-nodrop",
3581 * Returns the data object associated with this drag source
3582 * @return {Object} data An object containing arbitrary data
3584 getDragData : function(e){
3585 return this.dragData;
3589 onDragEnter : function(e, id){
3590 var target = Roo.dd.DragDropMgr.getDDById(id);
3591 this.cachedTarget = target;
3592 if(this.beforeDragEnter(target, e, id) !== false){
3593 if(target.isNotifyTarget){
3594 var status = target.notifyEnter(this, e, this.dragData);
3595 this.proxy.setStatus(status);
3597 this.proxy.setStatus(this.dropAllowed);
3600 if(this.afterDragEnter){
3602 * An empty function by default, but provided so that you can perform a custom action
3603 * when the dragged item enters the drop target by providing an implementation.
3604 * @param {Roo.dd.DragDrop} target The drop target
3605 * @param {Event} e The event object
3606 * @param {String} id The id of the dragged element
3607 * @method afterDragEnter
3609 this.afterDragEnter(target, e, id);
3615 * An empty function by default, but provided so that you can perform a custom action
3616 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3617 * @param {Roo.dd.DragDrop} target The drop target
3618 * @param {Event} e The event object
3619 * @param {String} id The id of the dragged element
3620 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3622 beforeDragEnter : function(target, e, id){
3627 alignElWithMouse: function() {
3628 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3633 onDragOver : function(e, id){
3634 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3635 if(this.beforeDragOver(target, e, id) !== false){
3636 if(target.isNotifyTarget){
3637 var status = target.notifyOver(this, e, this.dragData);
3638 this.proxy.setStatus(status);
3641 if(this.afterDragOver){
3643 * An empty function by default, but provided so that you can perform a custom action
3644 * while the dragged item is over the drop target by providing an implementation.
3645 * @param {Roo.dd.DragDrop} target The drop target
3646 * @param {Event} e The event object
3647 * @param {String} id The id of the dragged element
3648 * @method afterDragOver
3650 this.afterDragOver(target, e, id);
3656 * An empty function by default, but provided so that you can perform a custom action
3657 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3658 * @param {Roo.dd.DragDrop} target The drop target
3659 * @param {Event} e The event object
3660 * @param {String} id The id of the dragged element
3661 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3663 beforeDragOver : function(target, e, id){
3668 onDragOut : function(e, id){
3669 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3670 if(this.beforeDragOut(target, e, id) !== false){
3671 if(target.isNotifyTarget){
3672 target.notifyOut(this, e, this.dragData);
3675 if(this.afterDragOut){
3677 * An empty function by default, but provided so that you can perform a custom action
3678 * after the dragged item is dragged out of the target without dropping.
3679 * @param {Roo.dd.DragDrop} target The drop target
3680 * @param {Event} e The event object
3681 * @param {String} id The id of the dragged element
3682 * @method afterDragOut
3684 this.afterDragOut(target, e, id);
3687 this.cachedTarget = null;
3691 * An empty function by default, but provided so that you can perform a custom action before the dragged
3692 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dragged element
3696 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3698 beforeDragOut : function(target, e, id){
3703 onDragDrop : function(e, id){
3704 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3705 if(this.beforeDragDrop(target, e, id) !== false){
3706 if(target.isNotifyTarget){
3707 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3708 this.onValidDrop(target, e, id);
3710 this.onInvalidDrop(target, e, id);
3713 this.onValidDrop(target, e, id);
3716 if(this.afterDragDrop){
3718 * An empty function by default, but provided so that you can perform a custom action
3719 * after a valid drag drop has occurred by providing an implementation.
3720 * @param {Roo.dd.DragDrop} target The drop target
3721 * @param {Event} e The event object
3722 * @param {String} id The id of the dropped element
3723 * @method afterDragDrop
3725 this.afterDragDrop(target, e, id);
3728 delete this.cachedTarget;
3732 * An empty function by default, but provided so that you can perform a custom action before the dragged
3733 * item is dropped onto the target and optionally cancel the onDragDrop.
3734 * @param {Roo.dd.DragDrop} target The drop target
3735 * @param {Event} e The event object
3736 * @param {String} id The id of the dragged element
3737 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3739 beforeDragDrop : function(target, e, id){
3744 onValidDrop : function(target, e, id){
3746 if(this.afterValidDrop){
3748 * An empty function by default, but provided so that you can perform a custom action
3749 * after a valid drop has occurred by providing an implementation.
3750 * @param {Object} target The target DD
3751 * @param {Event} e The event object
3752 * @param {String} id The id of the dropped element
3753 * @method afterInvalidDrop
3755 this.afterValidDrop(target, e, id);
3760 getRepairXY : function(e, data){
3761 return this.el.getXY();
3765 onInvalidDrop : function(target, e, id){
3766 this.beforeInvalidDrop(target, e, id);
3767 if(this.cachedTarget){
3768 if(this.cachedTarget.isNotifyTarget){
3769 this.cachedTarget.notifyOut(this, e, this.dragData);
3771 this.cacheTarget = null;
3773 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3775 if(this.afterInvalidDrop){
3777 * An empty function by default, but provided so that you can perform a custom action
3778 * after an invalid drop has occurred by providing an implementation.
3779 * @param {Event} e The event object
3780 * @param {String} id The id of the dropped element
3781 * @method afterInvalidDrop
3783 this.afterInvalidDrop(e, id);
3788 afterRepair : function(){
3790 this.el.highlight(this.hlColor || "c3daf9");
3792 this.dragging = false;
3796 * An empty function by default, but provided so that you can perform a custom action after an invalid
3797 * drop has occurred.
3798 * @param {Roo.dd.DragDrop} target The drop target
3799 * @param {Event} e The event object
3800 * @param {String} id The id of the dragged element
3801 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3803 beforeInvalidDrop : function(target, e, id){
3808 handleMouseDown : function(e){
3812 var data = this.getDragData(e);
3813 if(data && this.onBeforeDrag(data, e) !== false){
3814 this.dragData = data;
3816 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3821 * An empty function by default, but provided so that you can perform a custom action before the initial
3822 * drag event begins and optionally cancel it.
3823 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3824 * @param {Event} e The event object
3825 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3827 onBeforeDrag : function(data, e){
3832 * An empty function by default, but provided so that you can perform a custom action once the initial
3833 * drag event has begun. The drag cannot be canceled from this function.
3834 * @param {Number} x The x position of the click on the dragged object
3835 * @param {Number} y The y position of the click on the dragged object
3837 onStartDrag : Roo.emptyFn,
3839 // private - YUI override
3840 startDrag : function(x, y){
3842 this.dragging = true;
3843 this.proxy.update("");
3844 this.onInitDrag(x, y);
3849 onInitDrag : function(x, y){
3850 var clone = this.el.dom.cloneNode(true);
3851 clone.id = Roo.id(); // prevent duplicate ids
3852 this.proxy.update(clone);
3853 this.onStartDrag(x, y);
3858 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3859 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3861 getProxy : function(){
3866 * Hides the drag source's {@link Roo.dd.StatusProxy}
3868 hideProxy : function(){
3870 this.proxy.reset(true);
3871 this.dragging = false;
3875 triggerCacheRefresh : function(){
3876 Roo.dd.DDM.refreshCache(this.groups);
3879 // private - override to prevent hiding
3880 b4EndDrag: function(e) {
3883 // private - override to prevent moving
3884 endDrag : function(e){
3885 this.onEndDrag(this.dragData, e);
3889 onEndDrag : function(data, e){
3892 // private - pin to cursor
3893 autoOffset : function(x, y) {
3894 this.setDelta(-12, -20);
3898 * Ext JS Library 1.1.1
3899 * Copyright(c) 2006-2007, Ext JS, LLC.
3901 * Originally Released Under LGPL - original licence link has changed is not relivant.
3904 * <script type="text/javascript">
3909 * @class Roo.dd.DropTarget
3910 * @extends Roo.dd.DDTarget
3911 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3912 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3914 * @param {String/HTMLElement/Element} el The container element
3915 * @param {Object} config
3917 Roo.dd.DropTarget = function(el, config){
3918 this.el = Roo.get(el);
3920 var listeners = false; ;
3921 if (config && config.listeners) {
3922 listeners= config.listeners;
3923 delete config.listeners;
3925 Roo.apply(this, config);
3927 if(this.containerScroll){
3928 Roo.dd.ScrollManager.register(this.el);
3932 * @scope Roo.dd.DropTarget
3937 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3938 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3939 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3941 * IMPORTANT : it should set this.overClass and this.dropAllowed
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 continuously while it is being dragged over the target.
3952 * This method will be called on every mouse movement while the drag source is over the drop target.
3953 * This default implementation simply returns the dropAllowed config value.
3955 * IMPORTANT : it should set this.dropAllowed
3957 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3958 * @param {Event} e The event
3959 * @param {Object} data An object containing arbitrary data supplied by the drag source
3965 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3966 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3967 * overClass (if any) from the drop element.
3969 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3970 * @param {Event} e The event
3971 * @param {Object} data An object containing arbitrary data supplied by the drag source
3977 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3978 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3979 * implementation that does something to process the drop event and returns true so that the drag source's
3980 * repair action does not run.
3982 * IMPORTANT : it should set this.success
3984 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3985 * @param {Event} e The event
3986 * @param {Object} data An object containing arbitrary data supplied by the drag source
3992 Roo.dd.DropTarget.superclass.constructor.call( this,
3994 this.ddGroup || this.group,
3997 listeners : listeners || {}
4005 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
4007 * @cfg {String} overClass
4008 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
4011 * @cfg {String} ddGroup
4012 * The drag drop group to handle drop events for
4016 * @cfg {String} dropAllowed
4017 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
4019 dropAllowed : "x-dd-drop-ok",
4021 * @cfg {String} dropNotAllowed
4022 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
4024 dropNotAllowed : "x-dd-drop-nodrop",
4026 * @cfg {boolean} success
4027 * set this after drop listener..
4031 * @cfg {boolean|String} valid true/false or string (ok-add/ok-sub/ok/nodrop)
4032 * if the drop point is valid for over/enter..
4039 isNotifyTarget : true,
4044 notifyEnter : function(dd, e, data)
4047 this.fireEvent('enter', dd, e, data);
4049 this.el.addClass(this.overClass);
4051 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4052 this.valid ? this.dropAllowed : this.dropNotAllowed
4059 notifyOver : function(dd, e, data)
4062 this.fireEvent('over', dd, e, data);
4063 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4064 this.valid ? this.dropAllowed : this.dropNotAllowed
4071 notifyOut : function(dd, e, data)
4073 this.fireEvent('out', dd, e, data);
4075 this.el.removeClass(this.overClass);
4082 notifyDrop : function(dd, e, data)
4084 this.success = false;
4085 this.fireEvent('drop', dd, e, data);
4086 return this.success;
4090 * Ext JS Library 1.1.1
4091 * Copyright(c) 2006-2007, Ext JS, LLC.
4093 * Originally Released Under LGPL - original licence link has changed is not relivant.
4096 * <script type="text/javascript">
4101 * @class Roo.dd.DragZone
4102 * @extends Roo.dd.DragSource
4103 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4104 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4106 * @param {String/HTMLElement/Element} el The container element
4107 * @param {Object} config
4109 Roo.dd.DragZone = function(el, config){
4110 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4111 if(this.containerScroll){
4112 Roo.dd.ScrollManager.register(this.el);
4116 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4118 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4119 * for auto scrolling during drag operations.
4122 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4123 * method after a failed drop (defaults to "c3daf9" - light blue)
4127 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4128 * for a valid target to drag based on the mouse down. Override this method
4129 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4130 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4131 * @param {EventObject} e The mouse down event
4132 * @return {Object} The dragData
4134 getDragData : function(e){
4135 return Roo.dd.Registry.getHandleFromEvent(e);
4139 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4140 * this.dragData.ddel
4141 * @param {Number} x The x position of the click on the dragged object
4142 * @param {Number} y The y position of the click on the dragged object
4143 * @return {Boolean} true to continue the drag, false to cancel
4145 onInitDrag : function(x, y){
4146 this.proxy.update(this.dragData.ddel.cloneNode(true));
4147 this.onStartDrag(x, y);
4152 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4154 afterRepair : function(){
4156 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4158 this.dragging = false;
4162 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4163 * the XY of this.dragData.ddel
4164 * @param {EventObject} e The mouse up event
4165 * @return {Array} The xy location (e.g. [100, 200])
4167 getRepairXY : function(e){
4168 return Roo.Element.fly(this.dragData.ddel).getXY();
4172 * Ext JS Library 1.1.1
4173 * Copyright(c) 2006-2007, Ext JS, LLC.
4175 * Originally Released Under LGPL - original licence link has changed is not relivant.
4178 * <script type="text/javascript">
4181 * @class Roo.dd.DropZone
4182 * @extends Roo.dd.DropTarget
4183 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4184 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4186 * @param {String/HTMLElement/Element} el The container element
4187 * @param {Object} config
4189 Roo.dd.DropZone = function(el, config){
4190 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4193 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4195 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4196 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4197 * provide your own custom lookup.
4198 * @param {Event} e The event
4199 * @return {Object} data The custom data
4201 getTargetFromEvent : function(e){
4202 return Roo.dd.Registry.getTargetFromEvent(e);
4206 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4207 * that it has registered. This method has no default implementation and should be overridden to provide
4208 * node-specific processing if necessary.
4209 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4210 * {@link #getTargetFromEvent} for this node)
4211 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4212 * @param {Event} e The event
4213 * @param {Object} data An object containing arbitrary data supplied by the drag source
4215 onNodeEnter : function(n, dd, e, data){
4220 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4221 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4222 * overridden to provide the proper feedback.
4223 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4224 * {@link #getTargetFromEvent} for this node)
4225 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4226 * @param {Event} e The event
4227 * @param {Object} data An object containing arbitrary data supplied by the drag source
4228 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4229 * underlying {@link Roo.dd.StatusProxy} can be updated
4231 onNodeOver : function(n, dd, e, data){
4232 return this.dropAllowed;
4236 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4237 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4238 * node-specific processing if necessary.
4239 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4240 * {@link #getTargetFromEvent} for this node)
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
4245 onNodeOut : function(n, dd, e, data){
4250 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4251 * the drop node. The default implementation returns false, so it should be overridden to provide the
4252 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4253 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4254 * {@link #getTargetFromEvent} for this node)
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 {Boolean} True if the drop was valid, else false
4260 onNodeDrop : function(n, dd, e, data){
4265 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4266 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4267 * it should be overridden to provide the proper feedback if necessary.
4268 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4269 * @param {Event} e The event
4270 * @param {Object} data An object containing arbitrary data supplied by the drag source
4271 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4272 * underlying {@link Roo.dd.StatusProxy} can be updated
4274 onContainerOver : function(dd, e, data){
4275 return this.dropNotAllowed;
4279 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4280 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4281 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4282 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4283 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4284 * @param {Event} e The event
4285 * @param {Object} data An object containing arbitrary data supplied by the drag source
4286 * @return {Boolean} True if the drop was valid, else false
4288 onContainerDrop : function(dd, e, data){
4293 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4294 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4295 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4296 * you should override this method and provide a custom implementation.
4297 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4298 * @param {Event} e The event
4299 * @param {Object} data An object containing arbitrary data supplied by the drag source
4300 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4301 * underlying {@link Roo.dd.StatusProxy} can be updated
4303 notifyEnter : function(dd, e, data){
4304 return this.dropNotAllowed;
4308 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4309 * This method will be called on every mouse movement while the drag source is over the drop zone.
4310 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4311 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4312 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4313 * registered node, it will call {@link #onContainerOver}.
4314 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4315 * @param {Event} e The event
4316 * @param {Object} data An object containing arbitrary data supplied by the drag source
4317 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4318 * underlying {@link Roo.dd.StatusProxy} can be updated
4320 notifyOver : function(dd, e, data){
4321 var n = this.getTargetFromEvent(e);
4322 if(!n){ // not over valid drop target
4323 if(this.lastOverNode){
4324 this.onNodeOut(this.lastOverNode, dd, e, data);
4325 this.lastOverNode = null;
4327 return this.onContainerOver(dd, e, data);
4329 if(this.lastOverNode != n){
4330 if(this.lastOverNode){
4331 this.onNodeOut(this.lastOverNode, dd, e, data);
4333 this.onNodeEnter(n, dd, e, data);
4334 this.lastOverNode = n;
4336 return this.onNodeOver(n, dd, e, data);
4340 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4341 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4342 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4343 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4344 * @param {Event} e The event
4345 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4347 notifyOut : function(dd, e, data){
4348 if(this.lastOverNode){
4349 this.onNodeOut(this.lastOverNode, dd, e, data);
4350 this.lastOverNode = null;
4355 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4356 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4357 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4358 * otherwise it will call {@link #onContainerDrop}.
4359 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4360 * @param {Event} e The event
4361 * @param {Object} data An object containing arbitrary data supplied by the drag source
4362 * @return {Boolean} True if the drop was valid, else false
4364 notifyDrop : function(dd, e, data){
4365 if(this.lastOverNode){
4366 this.onNodeOut(this.lastOverNode, dd, e, data);
4367 this.lastOverNode = null;
4369 var n = this.getTargetFromEvent(e);
4371 this.onNodeDrop(n, dd, e, data) :
4372 this.onContainerDrop(dd, e, data);
4376 triggerCacheRefresh : function(){
4377 Roo.dd.DDM.refreshCache(this.groups);
4381 * Ext JS Library 1.1.1
4382 * Copyright(c) 2006-2007, Ext JS, LLC.
4384 * Originally Released Under LGPL - original licence link has changed is not relivant.
4387 * <script type="text/javascript">
4392 * @class Roo.data.SortTypes
4394 * Defines the default sorting (casting?) comparison functions used when sorting data.
4396 Roo.data.SortTypes = {
4398 * Default sort that does nothing
4399 * @param {Mixed} s The value being converted
4400 * @return {Mixed} The comparison value
4407 * The regular expression used to strip tags
4411 stripTagsRE : /<\/?[^>]+>/gi,
4414 * Strips all HTML tags to sort on text only
4415 * @param {Mixed} s The value being converted
4416 * @return {String} The comparison value
4418 asText : function(s){
4419 return String(s).replace(this.stripTagsRE, "");
4423 * Strips all HTML tags to sort on text only - Case insensitive
4424 * @param {Mixed} s The value being converted
4425 * @return {String} The comparison value
4427 asUCText : function(s){
4428 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4432 * Case insensitive string
4433 * @param {Mixed} s The value being converted
4434 * @return {String} The comparison value
4436 asUCString : function(s) {
4437 return String(s).toUpperCase();
4442 * @param {Mixed} s The value being converted
4443 * @return {Number} The comparison value
4445 asDate : function(s) {
4449 if(s instanceof Date){
4452 return Date.parse(String(s));
4457 * @param {Mixed} s The value being converted
4458 * @return {Float} The comparison value
4460 asFloat : function(s) {
4461 var val = parseFloat(String(s).replace(/,/g, ""));
4462 if(isNaN(val)) val = 0;
4468 * @param {Mixed} s The value being converted
4469 * @return {Number} The comparison value
4471 asInt : function(s) {
4472 var val = parseInt(String(s).replace(/,/g, ""));
4473 if(isNaN(val)) val = 0;
4478 * Ext JS Library 1.1.1
4479 * Copyright(c) 2006-2007, Ext JS, LLC.
4481 * Originally Released Under LGPL - original licence link has changed is not relivant.
4484 * <script type="text/javascript">
4488 * @class Roo.data.Record
4489 * Instances of this class encapsulate both record <em>definition</em> information, and record
4490 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4491 * to access Records cached in an {@link Roo.data.Store} object.<br>
4493 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4494 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4497 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4499 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4500 * {@link #create}. The parameters are the same.
4501 * @param {Array} data An associative Array of data values keyed by the field name.
4502 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4503 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4504 * not specified an integer id is generated.
4506 Roo.data.Record = function(data, id){
4507 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4512 * Generate a constructor for a specific record layout.
4513 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4514 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4515 * Each field definition object may contain the following properties: <ul>
4516 * <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,
4517 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4518 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4519 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4520 * is being used, then this is a string containing the javascript expression to reference the data relative to
4521 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4522 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4523 * this may be omitted.</p></li>
4524 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4525 * <ul><li>auto (Default, implies no conversion)</li>
4530 * <li>date</li></ul></p></li>
4531 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4532 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4533 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4534 * by the Reader into an object that will be stored in the Record. It is passed the
4535 * following parameters:<ul>
4536 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4538 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4540 * <br>usage:<br><pre><code>
4541 var TopicRecord = Roo.data.Record.create(
4542 {name: 'title', mapping: 'topic_title'},
4543 {name: 'author', mapping: 'username'},
4544 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4545 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4546 {name: 'lastPoster', mapping: 'user2'},
4547 {name: 'excerpt', mapping: 'post_text'}
4550 var myNewRecord = new TopicRecord({
4551 title: 'Do my job please',
4554 lastPost: new Date(),
4555 lastPoster: 'Animal',
4556 excerpt: 'No way dude!'
4558 myStore.add(myNewRecord);
4563 Roo.data.Record.create = function(o){
4565 f.superclass.constructor.apply(this, arguments);
4567 Roo.extend(f, Roo.data.Record);
4568 var p = f.prototype;
4569 p.fields = new Roo.util.MixedCollection(false, function(field){
4572 for(var i = 0, len = o.length; i < len; i++){
4573 p.fields.add(new Roo.data.Field(o[i]));
4575 f.getField = function(name){
4576 return p.fields.get(name);
4581 Roo.data.Record.AUTO_ID = 1000;
4582 Roo.data.Record.EDIT = 'edit';
4583 Roo.data.Record.REJECT = 'reject';
4584 Roo.data.Record.COMMIT = 'commit';
4586 Roo.data.Record.prototype = {
4588 * Readonly flag - true if this record has been modified.
4597 join : function(store){
4602 * Set the named field to the specified value.
4603 * @param {String} name The name of the field to set.
4604 * @param {Object} value The value to set the field to.
4606 set : function(name, value){
4607 if(this.data[name] == value){
4614 if(typeof this.modified[name] == 'undefined'){
4615 this.modified[name] = this.data[name];
4617 this.data[name] = value;
4618 if(!this.editing && this.store){
4619 this.store.afterEdit(this);
4624 * Get the value of the named field.
4625 * @param {String} name The name of the field to get the value of.
4626 * @return {Object} The value of the field.
4628 get : function(name){
4629 return this.data[name];
4633 beginEdit : function(){
4634 this.editing = true;
4639 cancelEdit : function(){
4640 this.editing = false;
4641 delete this.modified;
4645 endEdit : function(){
4646 this.editing = false;
4647 if(this.dirty && this.store){
4648 this.store.afterEdit(this);
4653 * Usually called by the {@link Roo.data.Store} which owns the Record.
4654 * Rejects all changes made to the Record since either creation, or the last commit operation.
4655 * Modified fields are reverted to their original values.
4657 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4658 * of reject operations.
4660 reject : function(){
4661 var m = this.modified;
4663 if(typeof m[n] != "function"){
4664 this.data[n] = m[n];
4668 delete this.modified;
4669 this.editing = false;
4671 this.store.afterReject(this);
4676 * Usually called by the {@link Roo.data.Store} which owns the Record.
4677 * Commits all changes made to the Record since either creation, or the last commit operation.
4679 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4680 * of commit operations.
4682 commit : function(){
4684 delete this.modified;
4685 this.editing = false;
4687 this.store.afterCommit(this);
4692 hasError : function(){
4693 return this.error != null;
4697 clearError : function(){
4702 * Creates a copy of this record.
4703 * @param {String} id (optional) A new record id if you don't want to use this record's id
4706 copy : function(newId) {
4707 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4711 * Ext JS Library 1.1.1
4712 * Copyright(c) 2006-2007, Ext JS, LLC.
4714 * Originally Released Under LGPL - original licence link has changed is not relivant.
4717 * <script type="text/javascript">
4723 * @class Roo.data.Store
4724 * @extends Roo.util.Observable
4725 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4726 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4728 * 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
4729 * has no knowledge of the format of the data returned by the Proxy.<br>
4731 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4732 * instances from the data object. These records are cached and made available through accessor functions.
4734 * Creates a new Store.
4735 * @param {Object} config A config object containing the objects needed for the Store to access data,
4736 * and read the data into Records.
4738 Roo.data.Store = function(config){
4739 this.data = new Roo.util.MixedCollection(false);
4740 this.data.getKey = function(o){
4743 this.baseParams = {};
4750 "multisort" : "_multisort"
4753 if(config && config.data){
4754 this.inlineData = config.data;
4758 Roo.apply(this, config);
4760 if(this.reader){ // reader passed
4761 this.reader = Roo.factory(this.reader, Roo.data);
4762 this.reader.xmodule = this.xmodule || false;
4763 if(!this.recordType){
4764 this.recordType = this.reader.recordType;
4766 if(this.reader.onMetaChange){
4767 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4771 if(this.recordType){
4772 this.fields = this.recordType.prototype.fields;
4778 * @event datachanged
4779 * Fires when the data cache has changed, and a widget which is using this Store
4780 * as a Record cache should refresh its view.
4781 * @param {Store} this
4786 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4787 * @param {Store} this
4788 * @param {Object} meta The JSON metadata
4793 * Fires when Records have been added to the Store
4794 * @param {Store} this
4795 * @param {Roo.data.Record[]} records The array of Records added
4796 * @param {Number} index The index at which the record(s) were added
4801 * Fires when a Record has been removed from the Store
4802 * @param {Store} this
4803 * @param {Roo.data.Record} record The Record that was removed
4804 * @param {Number} index The index at which the record was removed
4809 * Fires when a Record has been updated
4810 * @param {Store} this
4811 * @param {Roo.data.Record} record The Record that was updated
4812 * @param {String} operation The update operation being performed. Value may be one of:
4814 Roo.data.Record.EDIT
4815 Roo.data.Record.REJECT
4816 Roo.data.Record.COMMIT
4822 * Fires when the data cache has been cleared.
4823 * @param {Store} this
4828 * Fires before a request is made for a new data object. If the beforeload handler returns false
4829 * the load action will be canceled.
4830 * @param {Store} this
4831 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4835 * @event beforeloadadd
4836 * Fires after a new set of Records has been loaded.
4837 * @param {Store} this
4838 * @param {Roo.data.Record[]} records The Records that were loaded
4839 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4841 beforeloadadd : true,
4844 * Fires after a new set of Records has been loaded, before they are added to the store.
4845 * @param {Store} this
4846 * @param {Roo.data.Record[]} records The Records that were loaded
4847 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4848 * @params {Object} return from reader
4852 * @event loadexception
4853 * Fires if an exception occurs in the Proxy during loading.
4854 * Called with the signature of the Proxy's "loadexception" event.
4855 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4858 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4859 * @param {Object} load options
4860 * @param {Object} jsonData from your request (normally this contains the Exception)
4862 loadexception : true
4866 this.proxy = Roo.factory(this.proxy, Roo.data);
4867 this.proxy.xmodule = this.xmodule || false;
4868 this.relayEvents(this.proxy, ["loadexception"]);
4870 this.sortToggle = {};
4871 this.sortOrder = []; // array of order of sorting - updated by grid if multisort is enabled.
4873 Roo.data.Store.superclass.constructor.call(this);
4875 if(this.inlineData){
4876 this.loadData(this.inlineData);
4877 delete this.inlineData;
4881 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4883 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4884 * without a remote query - used by combo/forms at present.
4888 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4891 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4894 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4895 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4898 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4899 * on any HTTP request
4902 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4905 * @cfg {Boolean} multiSort enable multi column sorting (sort is based on the order of columns, remote only at present)
4909 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4910 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4915 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4916 * loaded or when a record is removed. (defaults to false).
4918 pruneModifiedRecords : false,
4924 * Add Records to the Store and fires the add event.
4925 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4927 add : function(records){
4928 records = [].concat(records);
4929 for(var i = 0, len = records.length; i < len; i++){
4930 records[i].join(this);
4932 var index = this.data.length;
4933 this.data.addAll(records);
4934 this.fireEvent("add", this, records, index);
4938 * Remove a Record from the Store and fires the remove event.
4939 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4941 remove : function(record){
4942 var index = this.data.indexOf(record);
4943 this.data.removeAt(index);
4944 if(this.pruneModifiedRecords){
4945 this.modified.remove(record);
4947 this.fireEvent("remove", this, record, index);
4951 * Remove all Records from the Store and fires the clear event.
4953 removeAll : function(){
4955 if(this.pruneModifiedRecords){
4958 this.fireEvent("clear", this);
4962 * Inserts Records to the Store at the given index and fires the add event.
4963 * @param {Number} index The start index at which to insert the passed Records.
4964 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4966 insert : function(index, records){
4967 records = [].concat(records);
4968 for(var i = 0, len = records.length; i < len; i++){
4969 this.data.insert(index, records[i]);
4970 records[i].join(this);
4972 this.fireEvent("add", this, records, index);
4976 * Get the index within the cache of the passed Record.
4977 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4978 * @return {Number} The index of the passed Record. Returns -1 if not found.
4980 indexOf : function(record){
4981 return this.data.indexOf(record);
4985 * Get the index within the cache of the Record with the passed id.
4986 * @param {String} id The id of the Record to find.
4987 * @return {Number} The index of the Record. Returns -1 if not found.
4989 indexOfId : function(id){
4990 return this.data.indexOfKey(id);
4994 * Get the Record with the specified id.
4995 * @param {String} id The id of the Record to find.
4996 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4998 getById : function(id){
4999 return this.data.key(id);
5003 * Get the Record at the specified index.
5004 * @param {Number} index The index of the Record to find.
5005 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
5007 getAt : function(index){
5008 return this.data.itemAt(index);
5012 * Returns a range of Records between specified indices.
5013 * @param {Number} startIndex (optional) The starting index (defaults to 0)
5014 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
5015 * @return {Roo.data.Record[]} An array of Records
5017 getRange : function(start, end){
5018 return this.data.getRange(start, end);
5022 storeOptions : function(o){
5023 o = Roo.apply({}, o);
5026 this.lastOptions = o;
5030 * Loads the Record cache from the configured Proxy using the configured Reader.
5032 * If using remote paging, then the first load call must specify the <em>start</em>
5033 * and <em>limit</em> properties in the options.params property to establish the initial
5034 * position within the dataset, and the number of Records to cache on each read from the Proxy.
5036 * <strong>It is important to note that for remote data sources, loading is asynchronous,
5037 * and this call will return before the new data has been loaded. Perform any post-processing
5038 * in a callback function, or in a "load" event handler.</strong>
5040 * @param {Object} options An object containing properties which control loading options:<ul>
5041 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
5042 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
5043 * passed the following arguments:<ul>
5044 * <li>r : Roo.data.Record[]</li>
5045 * <li>options: Options object from the load call</li>
5046 * <li>success: Boolean success indicator</li></ul></li>
5047 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5048 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5051 load : function(options){
5052 options = options || {};
5053 if(this.fireEvent("beforeload", this, options) !== false){
5054 this.storeOptions(options);
5055 var p = Roo.apply(options.params || {}, this.baseParams);
5056 // if meta was not loaded from remote source.. try requesting it.
5057 if (!this.reader.metaFromRemote) {
5060 if(this.sortInfo && this.remoteSort){
5061 var pn = this.paramNames;
5062 p[pn["sort"]] = this.sortInfo.field;
5063 p[pn["dir"]] = this.sortInfo.direction;
5065 if (this.multiSort) {
5066 var pn = this.paramNames;
5067 p[pn["multisort"]] = Roo.encode( { sort : this.sortToggle, order: this.sortOrder });
5070 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5075 * Reloads the Record cache from the configured Proxy using the configured Reader and
5076 * the options from the last load operation performed.
5077 * @param {Object} options (optional) An object containing properties which may override the options
5078 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5079 * the most recently used options are reused).
5081 reload : function(options){
5082 this.load(Roo.applyIf(options||{}, this.lastOptions));
5086 // Called as a callback by the Reader during a load operation.
5087 loadRecords : function(o, options, success){
5088 if(!o || success === false){
5089 if(success !== false){
5090 this.fireEvent("load", this, [], options, o);
5092 if(options.callback){
5093 options.callback.call(options.scope || this, [], options, false);
5097 // if data returned failure - throw an exception.
5098 if (o.success === false) {
5099 // show a message if no listener is registered.
5100 if (!this.hasListener('loadexception') && typeof(o.raw.errorMsg) != 'undefined') {
5101 Roo.MessageBox.alert("Error loading",o.raw.errorMsg);
5103 // loadmask wil be hooked into this..
5104 this.fireEvent("loadexception", this, o, options, o.raw.errorMsg);
5107 var r = o.records, t = o.totalRecords || r.length;
5109 this.fireEvent("beforeloadadd", this, r, options, o);
5111 if(!options || options.add !== true){
5112 if(this.pruneModifiedRecords){
5115 for(var i = 0, len = r.length; i < len; i++){
5119 this.data = this.snapshot;
5120 delete this.snapshot;
5123 this.data.addAll(r);
5124 this.totalLength = t;
5126 this.fireEvent("datachanged", this);
5128 this.totalLength = Math.max(t, this.data.length+r.length);
5131 this.fireEvent("load", this, r, options, o);
5132 if(options.callback){
5133 options.callback.call(options.scope || this, r, options, true);
5139 * Loads data from a passed data block. A Reader which understands the format of the data
5140 * must have been configured in the constructor.
5141 * @param {Object} data The data block from which to read the Records. The format of the data expected
5142 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5143 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5145 loadData : function(o, append){
5146 var r = this.reader.readRecords(o);
5147 this.loadRecords(r, {add: append}, true);
5151 * Gets the number of cached records.
5153 * <em>If using paging, this may not be the total size of the dataset. If the data object
5154 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5155 * the data set size</em>
5157 getCount : function(){
5158 return this.data.length || 0;
5162 * Gets the total number of records in the dataset as returned by the server.
5164 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5165 * the dataset size</em>
5167 getTotalCount : function(){
5168 return this.totalLength || 0;
5172 * Returns the sort state of the Store as an object with two properties:
5174 field {String} The name of the field by which the Records are sorted
5175 direction {String} The sort order, "ASC" or "DESC"
5178 getSortState : function(){
5179 return this.sortInfo;
5183 applySort : function(){
5184 if(this.sortInfo && !this.remoteSort){
5185 var s = this.sortInfo, f = s.field;
5186 var st = this.fields.get(f).sortType;
5187 var fn = function(r1, r2){
5188 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5189 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5191 this.data.sort(s.direction, fn);
5192 if(this.snapshot && this.snapshot != this.data){
5193 this.snapshot.sort(s.direction, fn);
5199 * Sets the default sort column and order to be used by the next load operation.
5200 * @param {String} fieldName The name of the field to sort by.
5201 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5203 setDefaultSort : function(field, dir){
5204 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5209 * If remote sorting is used, the sort is performed on the server, and the cache is
5210 * reloaded. If local sorting is used, the cache is sorted internally.
5211 * @param {String} fieldName The name of the field to sort by.
5212 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5214 sort : function(fieldName, dir){
5215 var f = this.fields.get(fieldName);
5217 this.sortToggle[f.name] = this.sortToggle[f.name] || f.sortDir;
5219 if(this.multiSort || (this.sortInfo && this.sortInfo.field == f.name) ){ // toggle sort dir
5220 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5225 this.sortToggle[f.name] = dir;
5226 this.sortInfo = {field: f.name, direction: dir};
5227 if(!this.remoteSort){
5229 this.fireEvent("datachanged", this);
5231 this.load(this.lastOptions);
5236 * Calls the specified function for each of the Records in the cache.
5237 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5238 * Returning <em>false</em> aborts and exits the iteration.
5239 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5241 each : function(fn, scope){
5242 this.data.each(fn, scope);
5246 * Gets all records modified since the last commit. Modified records are persisted across load operations
5247 * (e.g., during paging).
5248 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5250 getModifiedRecords : function(){
5251 return this.modified;
5255 createFilterFn : function(property, value, anyMatch){
5256 if(!value.exec){ // not a regex
5257 value = String(value);
5258 if(value.length == 0){
5261 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5264 return value.test(r.data[property]);
5269 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5270 * @param {String} property A field on your records
5271 * @param {Number} start The record index to start at (defaults to 0)
5272 * @param {Number} end The last record index to include (defaults to length - 1)
5273 * @return {Number} The sum
5275 sum : function(property, start, end){
5276 var rs = this.data.items, v = 0;
5278 end = (end || end === 0) ? end : rs.length-1;
5280 for(var i = start; i <= end; i++){
5281 v += (rs[i].data[property] || 0);
5287 * Filter the records by a specified property.
5288 * @param {String} field A field on your records
5289 * @param {String/RegExp} value Either a string that the field
5290 * should start with or a RegExp to test against the field
5291 * @param {Boolean} anyMatch True to match any part not just the beginning
5293 filter : function(property, value, anyMatch){
5294 var fn = this.createFilterFn(property, value, anyMatch);
5295 return fn ? this.filterBy(fn) : this.clearFilter();
5299 * Filter by a function. The specified function will be called with each
5300 * record in this data source. If the function returns true the record is included,
5301 * otherwise it is filtered.
5302 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5303 * @param {Object} scope (optional) The scope of the function (defaults to this)
5305 filterBy : function(fn, scope){
5306 this.snapshot = this.snapshot || this.data;
5307 this.data = this.queryBy(fn, scope||this);
5308 this.fireEvent("datachanged", this);
5312 * Query the records by a specified property.
5313 * @param {String} field A field on your records
5314 * @param {String/RegExp} value Either a string that the field
5315 * should start with or a RegExp to test against the field
5316 * @param {Boolean} anyMatch True to match any part not just the beginning
5317 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5319 query : function(property, value, anyMatch){
5320 var fn = this.createFilterFn(property, value, anyMatch);
5321 return fn ? this.queryBy(fn) : this.data.clone();
5325 * Query by a function. The specified function will be called with each
5326 * record in this data source. If the function returns true the record is included
5328 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5329 * @param {Object} scope (optional) The scope of the function (defaults to this)
5330 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5332 queryBy : function(fn, scope){
5333 var data = this.snapshot || this.data;
5334 return data.filterBy(fn, scope||this);
5338 * Collects unique values for a particular dataIndex from this store.
5339 * @param {String} dataIndex The property to collect
5340 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5341 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5342 * @return {Array} An array of the unique values
5344 collect : function(dataIndex, allowNull, bypassFilter){
5345 var d = (bypassFilter === true && this.snapshot) ?
5346 this.snapshot.items : this.data.items;
5347 var v, sv, r = [], l = {};
5348 for(var i = 0, len = d.length; i < len; i++){
5349 v = d[i].data[dataIndex];
5351 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5360 * Revert to a view of the Record cache with no filtering applied.
5361 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5363 clearFilter : function(suppressEvent){
5364 if(this.snapshot && this.snapshot != this.data){
5365 this.data = this.snapshot;
5366 delete this.snapshot;
5367 if(suppressEvent !== true){
5368 this.fireEvent("datachanged", this);
5374 afterEdit : function(record){
5375 if(this.modified.indexOf(record) == -1){
5376 this.modified.push(record);
5378 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5382 afterReject : function(record){
5383 this.modified.remove(record);
5384 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5388 afterCommit : function(record){
5389 this.modified.remove(record);
5390 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5394 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5395 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5397 commitChanges : function(){
5398 var m = this.modified.slice(0);
5400 for(var i = 0, len = m.length; i < len; i++){
5406 * Cancel outstanding changes on all changed records.
5408 rejectChanges : function(){
5409 var m = this.modified.slice(0);
5411 for(var i = 0, len = m.length; i < len; i++){
5416 onMetaChange : function(meta, rtype, o){
5417 this.recordType = rtype;
5418 this.fields = rtype.prototype.fields;
5419 delete this.snapshot;
5420 this.sortInfo = meta.sortInfo || this.sortInfo;
5422 this.fireEvent('metachange', this, this.reader.meta);
5426 * Ext JS Library 1.1.1
5427 * Copyright(c) 2006-2007, Ext JS, LLC.
5429 * Originally Released Under LGPL - original licence link has changed is not relivant.
5432 * <script type="text/javascript">
5436 * @class Roo.data.SimpleStore
5437 * @extends Roo.data.Store
5438 * Small helper class to make creating Stores from Array data easier.
5439 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5440 * @cfg {Array} fields An array of field definition objects, or field name strings.
5441 * @cfg {Array} data The multi-dimensional array of data
5443 * @param {Object} config
5445 Roo.data.SimpleStore = function(config){
5446 Roo.data.SimpleStore.superclass.constructor.call(this, {
5448 reader: new Roo.data.ArrayReader({
5451 Roo.data.Record.create(config.fields)
5453 proxy : new Roo.data.MemoryProxy(config.data)
5457 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5459 * Ext JS Library 1.1.1
5460 * Copyright(c) 2006-2007, Ext JS, LLC.
5462 * Originally Released Under LGPL - original licence link has changed is not relivant.
5465 * <script type="text/javascript">
5470 * @extends Roo.data.Store
5471 * @class Roo.data.JsonStore
5472 * Small helper class to make creating Stores for JSON data easier. <br/>
5474 var store = new Roo.data.JsonStore({
5475 url: 'get-images.php',
5477 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5480 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5481 * JsonReader and HttpProxy (unless inline data is provided).</b>
5482 * @cfg {Array} fields An array of field definition objects, or field name strings.
5484 * @param {Object} config
5486 Roo.data.JsonStore = function(c){
5487 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5488 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5489 reader: new Roo.data.JsonReader(c, c.fields)
5492 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5494 * Ext JS Library 1.1.1
5495 * Copyright(c) 2006-2007, Ext JS, LLC.
5497 * Originally Released Under LGPL - original licence link has changed is not relivant.
5500 * <script type="text/javascript">
5504 Roo.data.Field = function(config){
5505 if(typeof config == "string"){
5506 config = {name: config};
5508 Roo.apply(this, config);
5514 var st = Roo.data.SortTypes;
5515 // named sortTypes are supported, here we look them up
5516 if(typeof this.sortType == "string"){
5517 this.sortType = st[this.sortType];
5520 // set default sortType for strings and dates
5524 this.sortType = st.asUCString;
5527 this.sortType = st.asDate;
5530 this.sortType = st.none;
5535 var stripRe = /[\$,%]/g;
5537 // prebuilt conversion function for this field, instead of
5538 // switching every time we're reading a value
5540 var cv, dateFormat = this.dateFormat;
5545 cv = function(v){ return v; };
5548 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5552 return v !== undefined && v !== null && v !== '' ?
5553 parseInt(String(v).replace(stripRe, ""), 10) : '';
5558 return v !== undefined && v !== null && v !== '' ?
5559 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5564 cv = function(v){ return v === true || v === "true" || v == 1; };
5571 if(v instanceof Date){
5575 if(dateFormat == "timestamp"){
5576 return new Date(v*1000);
5578 return Date.parseDate(v, dateFormat);
5580 var parsed = Date.parse(v);
5581 return parsed ? new Date(parsed) : null;
5590 Roo.data.Field.prototype = {
5598 * Ext JS Library 1.1.1
5599 * Copyright(c) 2006-2007, Ext JS, LLC.
5601 * Originally Released Under LGPL - original licence link has changed is not relivant.
5604 * <script type="text/javascript">
5607 // Base class for reading structured data from a data source. This class is intended to be
5608 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5611 * @class Roo.data.DataReader
5612 * Base class for reading structured data from a data source. This class is intended to be
5613 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5616 Roo.data.DataReader = function(meta, recordType){
5620 this.recordType = recordType instanceof Array ?
5621 Roo.data.Record.create(recordType) : recordType;
5624 Roo.data.DataReader.prototype = {
5626 * Create an empty record
5627 * @param {Object} data (optional) - overlay some values
5628 * @return {Roo.data.Record} record created.
5630 newRow : function(d) {
5632 this.recordType.prototype.fields.each(function(c) {
5634 case 'int' : da[c.name] = 0; break;
5635 case 'date' : da[c.name] = new Date(); break;
5636 case 'float' : da[c.name] = 0.0; break;
5637 case 'boolean' : da[c.name] = false; break;
5638 default : da[c.name] = ""; break;
5642 return new this.recordType(Roo.apply(da, d));
5647 * Ext JS Library 1.1.1
5648 * Copyright(c) 2006-2007, Ext JS, LLC.
5650 * Originally Released Under LGPL - original licence link has changed is not relivant.
5653 * <script type="text/javascript">
5657 * @class Roo.data.DataProxy
5658 * @extends Roo.data.Observable
5659 * This class is an abstract base class for implementations which provide retrieval of
5660 * unformatted data objects.<br>
5662 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5663 * (of the appropriate type which knows how to parse the data object) to provide a block of
5664 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5666 * Custom implementations must implement the load method as described in
5667 * {@link Roo.data.HttpProxy#load}.
5669 Roo.data.DataProxy = function(){
5673 * Fires before a network request is made to retrieve a data object.
5674 * @param {Object} This DataProxy object.
5675 * @param {Object} params The params parameter to the load function.
5680 * Fires before the load method's callback is called.
5681 * @param {Object} This DataProxy object.
5682 * @param {Object} o The data object.
5683 * @param {Object} arg The callback argument object passed to the load function.
5687 * @event loadexception
5688 * Fires if an Exception occurs during data retrieval.
5689 * @param {Object} This DataProxy object.
5690 * @param {Object} o The data object.
5691 * @param {Object} arg The callback argument object passed to the load function.
5692 * @param {Object} e The Exception.
5694 loadexception : true
5696 Roo.data.DataProxy.superclass.constructor.call(this);
5699 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5702 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5706 * Ext JS Library 1.1.1
5707 * Copyright(c) 2006-2007, Ext JS, LLC.
5709 * Originally Released Under LGPL - original licence link has changed is not relivant.
5712 * <script type="text/javascript">
5715 * @class Roo.data.MemoryProxy
5716 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5717 * to the Reader when its load method is called.
5719 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5721 Roo.data.MemoryProxy = function(data){
5725 Roo.data.MemoryProxy.superclass.constructor.call(this);
5729 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5731 * Load data from the requested source (in this case an in-memory
5732 * data object passed to the constructor), read the data object into
5733 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5734 * process that block using the passed callback.
5735 * @param {Object} params This parameter is not used by the MemoryProxy class.
5736 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5737 * object into a block of Roo.data.Records.
5738 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5739 * The function must be passed <ul>
5740 * <li>The Record block object</li>
5741 * <li>The "arg" argument from the load function</li>
5742 * <li>A boolean success indicator</li>
5744 * @param {Object} scope The scope in which to call the callback
5745 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5747 load : function(params, reader, callback, scope, arg){
5748 params = params || {};
5751 result = reader.readRecords(this.data);
5753 this.fireEvent("loadexception", this, arg, null, e);
5754 callback.call(scope, null, arg, false);
5757 callback.call(scope, result, arg, true);
5761 update : function(params, records){
5766 * Ext JS Library 1.1.1
5767 * Copyright(c) 2006-2007, Ext JS, LLC.
5769 * Originally Released Under LGPL - original licence link has changed is not relivant.
5772 * <script type="text/javascript">
5775 * @class Roo.data.HttpProxy
5776 * @extends Roo.data.DataProxy
5777 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5778 * configured to reference a certain URL.<br><br>
5780 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5781 * from which the running page was served.<br><br>
5783 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5785 * Be aware that to enable the browser to parse an XML document, the server must set
5786 * the Content-Type header in the HTTP response to "text/xml".
5788 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5789 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5790 * will be used to make the request.
5792 Roo.data.HttpProxy = function(conn){
5793 Roo.data.HttpProxy.superclass.constructor.call(this);
5794 // is conn a conn config or a real conn?
5796 this.useAjax = !conn || !conn.events;
5800 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5801 // thse are take from connection...
5804 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5807 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5808 * extra parameters to each request made by this object. (defaults to undefined)
5811 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5812 * to each request made by this object. (defaults to undefined)
5815 * @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)
5818 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5821 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5827 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5831 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5832 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5833 * a finer-grained basis than the DataProxy events.
5835 getConnection : function(){
5836 return this.useAjax ? Roo.Ajax : this.conn;
5840 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5841 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5842 * process that block using the passed callback.
5843 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5844 * for the request to the remote server.
5845 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5846 * object into a block of Roo.data.Records.
5847 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5848 * The function must be passed <ul>
5849 * <li>The Record block object</li>
5850 * <li>The "arg" argument from the load function</li>
5851 * <li>A boolean success indicator</li>
5853 * @param {Object} scope The scope in which to call the callback
5854 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5856 load : function(params, reader, callback, scope, arg){
5857 if(this.fireEvent("beforeload", this, params) !== false){
5859 params : params || {},
5861 callback : callback,
5866 callback : this.loadResponse,
5870 Roo.applyIf(o, this.conn);
5871 if(this.activeRequest){
5872 Roo.Ajax.abort(this.activeRequest);
5874 this.activeRequest = Roo.Ajax.request(o);
5876 this.conn.request(o);
5879 callback.call(scope||this, null, arg, false);
5884 loadResponse : function(o, success, response){
5885 delete this.activeRequest;
5887 this.fireEvent("loadexception", this, o, response);
5888 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5893 result = o.reader.read(response);
5895 this.fireEvent("loadexception", this, o, response, e);
5896 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5900 this.fireEvent("load", this, o, o.request.arg);
5901 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5905 update : function(dataSet){
5910 updateResponse : function(dataSet){
5915 * Ext JS Library 1.1.1
5916 * Copyright(c) 2006-2007, Ext JS, LLC.
5918 * Originally Released Under LGPL - original licence link has changed is not relivant.
5921 * <script type="text/javascript">
5925 * @class Roo.data.ScriptTagProxy
5926 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5927 * other than the originating domain of the running page.<br><br>
5929 * <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
5930 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5932 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5933 * source code that is used as the source inside a <script> tag.<br><br>
5935 * In order for the browser to process the returned data, the server must wrap the data object
5936 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5937 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5938 * depending on whether the callback name was passed:
5941 boolean scriptTag = false;
5942 String cb = request.getParameter("callback");
5945 response.setContentType("text/javascript");
5947 response.setContentType("application/x-json");
5949 Writer out = response.getWriter();
5951 out.write(cb + "(");
5953 out.print(dataBlock.toJsonString());
5960 * @param {Object} config A configuration object.
5962 Roo.data.ScriptTagProxy = function(config){
5963 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5964 Roo.apply(this, config);
5965 this.head = document.getElementsByTagName("head")[0];
5968 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5970 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5972 * @cfg {String} url The URL from which to request the data object.
5975 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5979 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5980 * the server the name of the callback function set up by the load call to process the returned data object.
5981 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5982 * javascript output which calls this named function passing the data object as its only parameter.
5984 callbackParam : "callback",
5986 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5987 * name to the request.
5992 * Load data from the configured URL, read the data object into
5993 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5994 * process that block using the passed callback.
5995 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5996 * for the request to the remote server.
5997 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5998 * object into a block of Roo.data.Records.
5999 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
6000 * The function must be passed <ul>
6001 * <li>The Record block object</li>
6002 * <li>The "arg" argument from the load function</li>
6003 * <li>A boolean success indicator</li>
6005 * @param {Object} scope The scope in which to call the callback
6006 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
6008 load : function(params, reader, callback, scope, arg){
6009 if(this.fireEvent("beforeload", this, params) !== false){
6011 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
6014 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
6016 url += "&_dc=" + (new Date().getTime());
6018 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
6021 cb : "stcCallback"+transId,
6022 scriptId : "stcScript"+transId,
6026 callback : callback,
6032 window[trans.cb] = function(o){
6033 conn.handleResponse(o, trans);
6036 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
6038 if(this.autoAbort !== false){
6042 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
6044 var script = document.createElement("script");
6045 script.setAttribute("src", url);
6046 script.setAttribute("type", "text/javascript");
6047 script.setAttribute("id", trans.scriptId);
6048 this.head.appendChild(script);
6052 callback.call(scope||this, null, arg, false);
6057 isLoading : function(){
6058 return this.trans ? true : false;
6062 * Abort the current server request.
6065 if(this.isLoading()){
6066 this.destroyTrans(this.trans);
6071 destroyTrans : function(trans, isLoaded){
6072 this.head.removeChild(document.getElementById(trans.scriptId));
6073 clearTimeout(trans.timeoutId);
6075 window[trans.cb] = undefined;
6077 delete window[trans.cb];
6080 // if hasn't been loaded, wait for load to remove it to prevent script error
6081 window[trans.cb] = function(){
6082 window[trans.cb] = undefined;
6084 delete window[trans.cb];
6091 handleResponse : function(o, trans){
6093 this.destroyTrans(trans, true);
6096 result = trans.reader.readRecords(o);
6098 this.fireEvent("loadexception", this, o, trans.arg, e);
6099 trans.callback.call(trans.scope||window, null, trans.arg, false);
6102 this.fireEvent("load", this, o, trans.arg);
6103 trans.callback.call(trans.scope||window, result, trans.arg, true);
6107 handleFailure : function(trans){
6109 this.destroyTrans(trans, false);
6110 this.fireEvent("loadexception", this, null, trans.arg);
6111 trans.callback.call(trans.scope||window, null, trans.arg, false);
6115 * Ext JS Library 1.1.1
6116 * Copyright(c) 2006-2007, Ext JS, LLC.
6118 * Originally Released Under LGPL - original licence link has changed is not relivant.
6121 * <script type="text/javascript">
6125 * @class Roo.data.JsonReader
6126 * @extends Roo.data.DataReader
6127 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6128 * based on mappings in a provided Roo.data.Record constructor.
6130 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6131 * in the reply previously.
6136 var RecordDef = Roo.data.Record.create([
6137 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6138 {name: 'occupation'} // This field will use "occupation" as the mapping.
6140 var myReader = new Roo.data.JsonReader({
6141 totalProperty: "results", // The property which contains the total dataset size (optional)
6142 root: "rows", // The property which contains an Array of row objects
6143 id: "id" // The property within each row object that provides an ID for the record (optional)
6147 * This would consume a JSON file like this:
6149 { 'results': 2, 'rows': [
6150 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6151 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6154 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6155 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6156 * paged from the remote server.
6157 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6158 * @cfg {String} root name of the property which contains the Array of row objects.
6159 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6161 * Create a new JsonReader
6162 * @param {Object} meta Metadata configuration options
6163 * @param {Object} recordType Either an Array of field definition objects,
6164 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6166 Roo.data.JsonReader = function(meta, recordType){
6169 // set some defaults:
6171 totalProperty: 'total',
6172 successProperty : 'success',
6177 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6179 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6182 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6183 * Used by Store query builder to append _requestMeta to params.
6186 metaFromRemote : false,
6188 * This method is only used by a DataProxy which has retrieved data from a remote server.
6189 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6190 * @return {Object} data A data block which is used by an Roo.data.Store object as
6191 * a cache of Roo.data.Records.
6193 read : function(response){
6194 var json = response.responseText;
6196 var o = /* eval:var:o */ eval("("+json+")");
6198 throw {message: "JsonReader.read: Json object not found"};
6204 this.metaFromRemote = true;
6205 this.meta = o.metaData;
6206 this.recordType = Roo.data.Record.create(o.metaData.fields);
6207 this.onMetaChange(this.meta, this.recordType, o);
6209 return this.readRecords(o);
6212 // private function a store will implement
6213 onMetaChange : function(meta, recordType, o){
6220 simpleAccess: function(obj, subsc) {
6227 getJsonAccessor: function(){
6229 return function(expr) {
6231 return(re.test(expr))
6232 ? new Function("obj", "return obj." + expr)
6242 * Create a data block containing Roo.data.Records from an XML document.
6243 * @param {Object} o An object which contains an Array of row objects in the property specified
6244 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6245 * which contains the total size of the dataset.
6246 * @return {Object} data A data block which is used by an Roo.data.Store object as
6247 * a cache of Roo.data.Records.
6249 readRecords : function(o){
6251 * After any data loads, the raw JSON data is available for further custom processing.
6255 var s = this.meta, Record = this.recordType,
6256 f = Record.prototype.fields, fi = f.items, fl = f.length;
6258 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6260 if(s.totalProperty) {
6261 this.getTotal = this.getJsonAccessor(s.totalProperty);
6263 if(s.successProperty) {
6264 this.getSuccess = this.getJsonAccessor(s.successProperty);
6266 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6268 var g = this.getJsonAccessor(s.id);
6269 this.getId = function(rec) {
6271 return (r === undefined || r === "") ? null : r;
6274 this.getId = function(){return null;};
6277 for(var jj = 0; jj < fl; jj++){
6279 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6280 this.ef[jj] = this.getJsonAccessor(map);
6284 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6285 if(s.totalProperty){
6286 var vt = parseInt(this.getTotal(o), 10);
6291 if(s.successProperty){
6292 var vs = this.getSuccess(o);
6293 if(vs === false || vs === 'false'){
6298 for(var i = 0; i < c; i++){
6301 var id = this.getId(n);
6302 for(var j = 0; j < fl; j++){
6304 var v = this.ef[j](n);
6306 Roo.log('missing convert for ' + f.name);
6310 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6312 var record = new Record(values, id);
6314 records[i] = record;
6320 totalRecords : totalRecords
6325 * Ext JS Library 1.1.1
6326 * Copyright(c) 2006-2007, Ext JS, LLC.
6328 * Originally Released Under LGPL - original licence link has changed is not relivant.
6331 * <script type="text/javascript">
6335 * @class Roo.data.XmlReader
6336 * @extends Roo.data.DataReader
6337 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6338 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6340 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6341 * header in the HTTP response must be set to "text/xml".</em>
6345 var RecordDef = Roo.data.Record.create([
6346 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6347 {name: 'occupation'} // This field will use "occupation" as the mapping.
6349 var myReader = new Roo.data.XmlReader({
6350 totalRecords: "results", // The element which contains the total dataset size (optional)
6351 record: "row", // The repeated element which contains row information
6352 id: "id" // The element within the row that provides an ID for the record (optional)
6356 * This would consume an XML file like this:
6360 <results>2</results>
6363 <name>Bill</name>
6364 <occupation>Gardener</occupation>
6368 <name>Ben</name>
6369 <occupation>Horticulturalist</occupation>
6373 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6374 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6375 * paged from the remote server.
6376 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6377 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6378 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6379 * a record identifier value.
6381 * Create a new XmlReader
6382 * @param {Object} meta Metadata configuration options
6383 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6384 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6385 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6387 Roo.data.XmlReader = function(meta, recordType){
6389 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6391 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6393 * This method is only used by a DataProxy which has retrieved data from a remote server.
6394 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6395 * to contain a method called 'responseXML' that returns an XML document object.
6396 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6397 * a cache of Roo.data.Records.
6399 read : function(response){
6400 var doc = response.responseXML;
6402 throw {message: "XmlReader.read: XML Document not available"};
6404 return this.readRecords(doc);
6408 * Create a data block containing Roo.data.Records from an XML document.
6409 * @param {Object} doc A parsed XML document.
6410 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6411 * a cache of Roo.data.Records.
6413 readRecords : function(doc){
6415 * After any data loads/reads, the raw XML Document is available for further custom processing.
6419 var root = doc.documentElement || doc;
6420 var q = Roo.DomQuery;
6421 var recordType = this.recordType, fields = recordType.prototype.fields;
6422 var sid = this.meta.id;
6423 var totalRecords = 0, success = true;
6424 if(this.meta.totalRecords){
6425 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6428 if(this.meta.success){
6429 var sv = q.selectValue(this.meta.success, root, true);
6430 success = sv !== false && sv !== 'false';
6433 var ns = q.select(this.meta.record, root);
6434 for(var i = 0, len = ns.length; i < len; i++) {
6437 var id = sid ? q.selectValue(sid, n) : undefined;
6438 for(var j = 0, jlen = fields.length; j < jlen; j++){
6439 var f = fields.items[j];
6440 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6444 var record = new recordType(values, id);
6446 records[records.length] = record;
6452 totalRecords : totalRecords || records.length
6457 * Ext JS Library 1.1.1
6458 * Copyright(c) 2006-2007, Ext JS, LLC.
6460 * Originally Released Under LGPL - original licence link has changed is not relivant.
6463 * <script type="text/javascript">
6467 * @class Roo.data.ArrayReader
6468 * @extends Roo.data.DataReader
6469 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6470 * Each element of that Array represents a row of data fields. The
6471 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6472 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6476 var RecordDef = Roo.data.Record.create([
6477 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6478 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6480 var myReader = new Roo.data.ArrayReader({
6481 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6485 * This would consume an Array like this:
6487 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6489 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6491 * Create a new JsonReader
6492 * @param {Object} meta Metadata configuration options.
6493 * @param {Object} recordType Either an Array of field definition objects
6494 * as specified to {@link Roo.data.Record#create},
6495 * or an {@link Roo.data.Record} object
6496 * created using {@link Roo.data.Record#create}.
6498 Roo.data.ArrayReader = function(meta, recordType){
6499 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6502 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6504 * Create a data block containing Roo.data.Records from an XML document.
6505 * @param {Object} o An Array of row objects which represents the dataset.
6506 * @return {Object} data A data block which is used by an Roo.data.Store object as
6507 * a cache of Roo.data.Records.
6509 readRecords : function(o){
6510 var sid = this.meta ? this.meta.id : null;
6511 var recordType = this.recordType, fields = recordType.prototype.fields;
6514 for(var i = 0; i < root.length; i++){
6517 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6518 for(var j = 0, jlen = fields.length; j < jlen; j++){
6519 var f = fields.items[j];
6520 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6521 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6525 var record = new recordType(values, id);
6527 records[records.length] = record;
6531 totalRecords : records.length
6536 * Ext JS Library 1.1.1
6537 * Copyright(c) 2006-2007, Ext JS, LLC.
6539 * Originally Released Under LGPL - original licence link has changed is not relivant.
6542 * <script type="text/javascript">
6547 * @class Roo.data.Tree
6548 * @extends Roo.util.Observable
6549 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6550 * in the tree have most standard DOM functionality.
6552 * @param {Node} root (optional) The root node
6554 Roo.data.Tree = function(root){
6557 * The root node for this tree
6562 this.setRootNode(root);
6567 * Fires when a new child node is appended to a node in this tree.
6568 * @param {Tree} tree The owner tree
6569 * @param {Node} parent The parent node
6570 * @param {Node} node The newly appended node
6571 * @param {Number} index The index of the newly appended node
6576 * Fires when a child node is removed from a node in this tree.
6577 * @param {Tree} tree The owner tree
6578 * @param {Node} parent The parent node
6579 * @param {Node} node The child node removed
6584 * Fires when a node is moved to a new location in the tree
6585 * @param {Tree} tree The owner tree
6586 * @param {Node} node The node moved
6587 * @param {Node} oldParent The old parent of this node
6588 * @param {Node} newParent The new parent of this node
6589 * @param {Number} index The index it was moved to
6594 * Fires when a new child node is inserted in a node in this tree.
6595 * @param {Tree} tree The owner tree
6596 * @param {Node} parent The parent node
6597 * @param {Node} node The child node inserted
6598 * @param {Node} refNode The child node the node was inserted before
6602 * @event beforeappend
6603 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6604 * @param {Tree} tree The owner tree
6605 * @param {Node} parent The parent node
6606 * @param {Node} node The child node to be appended
6608 "beforeappend" : true,
6610 * @event beforeremove
6611 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6612 * @param {Tree} tree The owner tree
6613 * @param {Node} parent The parent node
6614 * @param {Node} node The child node to be removed
6616 "beforeremove" : true,
6619 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6620 * @param {Tree} tree The owner tree
6621 * @param {Node} node The node being moved
6622 * @param {Node} oldParent The parent of the node
6623 * @param {Node} newParent The new parent the node is moving to
6624 * @param {Number} index The index it is being moved to
6626 "beforemove" : true,
6628 * @event beforeinsert
6629 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6630 * @param {Tree} tree The owner tree
6631 * @param {Node} parent The parent node
6632 * @param {Node} node The child node to be inserted
6633 * @param {Node} refNode The child node the node is being inserted before
6635 "beforeinsert" : true
6638 Roo.data.Tree.superclass.constructor.call(this);
6641 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6644 proxyNodeEvent : function(){
6645 return this.fireEvent.apply(this, arguments);
6649 * Returns the root node for this tree.
6652 getRootNode : function(){
6657 * Sets the root node for this tree.
6658 * @param {Node} node
6661 setRootNode : function(node){
6663 node.ownerTree = this;
6665 this.registerNode(node);
6670 * Gets a node in this tree by its id.
6671 * @param {String} id
6674 getNodeById : function(id){
6675 return this.nodeHash[id];
6678 registerNode : function(node){
6679 this.nodeHash[node.id] = node;
6682 unregisterNode : function(node){
6683 delete this.nodeHash[node.id];
6686 toString : function(){
6687 return "[Tree"+(this.id?" "+this.id:"")+"]";
6692 * @class Roo.data.Node
6693 * @extends Roo.util.Observable
6694 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6695 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6697 * @param {Object} attributes The attributes/config for the node
6699 Roo.data.Node = function(attributes){
6701 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6704 this.attributes = attributes || {};
6705 this.leaf = this.attributes.leaf;
6707 * The node id. @type String
6709 this.id = this.attributes.id;
6711 this.id = Roo.id(null, "ynode-");
6712 this.attributes.id = this.id;
6717 * All child nodes of this node. @type Array
6719 this.childNodes = [];
6720 if(!this.childNodes.indexOf){ // indexOf is a must
6721 this.childNodes.indexOf = function(o){
6722 for(var i = 0, len = this.length; i < len; i++){
6731 * The parent node for this node. @type Node
6733 this.parentNode = null;
6735 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6737 this.firstChild = null;
6739 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6741 this.lastChild = null;
6743 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6745 this.previousSibling = null;
6747 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6749 this.nextSibling = null;
6754 * Fires when a new child node is appended
6755 * @param {Tree} tree The owner tree
6756 * @param {Node} this This node
6757 * @param {Node} node The newly appended node
6758 * @param {Number} index The index of the newly appended node
6763 * Fires when a child node is removed
6764 * @param {Tree} tree The owner tree
6765 * @param {Node} this This node
6766 * @param {Node} node The removed node
6771 * Fires when this node is moved to a new location in the tree
6772 * @param {Tree} tree The owner tree
6773 * @param {Node} this This node
6774 * @param {Node} oldParent The old parent of this node
6775 * @param {Node} newParent The new parent of this node
6776 * @param {Number} index The index it was moved to
6781 * Fires when a new child node is inserted.
6782 * @param {Tree} tree The owner tree
6783 * @param {Node} this This node
6784 * @param {Node} node The child node inserted
6785 * @param {Node} refNode The child node the node was inserted before
6789 * @event beforeappend
6790 * Fires before a new child is appended, return false to cancel the append.
6791 * @param {Tree} tree The owner tree
6792 * @param {Node} this This node
6793 * @param {Node} node The child node to be appended
6795 "beforeappend" : true,
6797 * @event beforeremove
6798 * Fires before a child is removed, return false to cancel the remove.
6799 * @param {Tree} tree The owner tree
6800 * @param {Node} this This node
6801 * @param {Node} node The child node to be removed
6803 "beforeremove" : true,
6806 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6807 * @param {Tree} tree The owner tree
6808 * @param {Node} this This node
6809 * @param {Node} oldParent The parent of this node
6810 * @param {Node} newParent The new parent this node is moving to
6811 * @param {Number} index The index it is being moved to
6813 "beforemove" : true,
6815 * @event beforeinsert
6816 * Fires before a new child is inserted, return false to cancel the insert.
6817 * @param {Tree} tree The owner tree
6818 * @param {Node} this This node
6819 * @param {Node} node The child node to be inserted
6820 * @param {Node} refNode The child node the node is being inserted before
6822 "beforeinsert" : true
6824 this.listeners = this.attributes.listeners;
6825 Roo.data.Node.superclass.constructor.call(this);
6828 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6829 fireEvent : function(evtName){
6830 // first do standard event for this node
6831 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6834 // then bubble it up to the tree if the event wasn't cancelled
6835 var ot = this.getOwnerTree();
6837 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6845 * Returns true if this node is a leaf
6848 isLeaf : function(){
6849 return this.leaf === true;
6853 setFirstChild : function(node){
6854 this.firstChild = node;
6858 setLastChild : function(node){
6859 this.lastChild = node;
6864 * Returns true if this node is the last child of its parent
6867 isLast : function(){
6868 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6872 * Returns true if this node is the first child of its parent
6875 isFirst : function(){
6876 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6879 hasChildNodes : function(){
6880 return !this.isLeaf() && this.childNodes.length > 0;
6884 * Insert node(s) as the last child node of this node.
6885 * @param {Node/Array} node The node or Array of nodes to append
6886 * @return {Node} The appended node if single append, or null if an array was passed
6888 appendChild : function(node){
6890 if(node instanceof Array){
6892 }else if(arguments.length > 1){
6895 // if passed an array or multiple args do them one by one
6897 for(var i = 0, len = multi.length; i < len; i++) {
6898 this.appendChild(multi[i]);
6901 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6904 var index = this.childNodes.length;
6905 var oldParent = node.parentNode;
6906 // it's a move, make sure we move it cleanly
6908 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6911 oldParent.removeChild(node);
6913 index = this.childNodes.length;
6915 this.setFirstChild(node);
6917 this.childNodes.push(node);
6918 node.parentNode = this;
6919 var ps = this.childNodes[index-1];
6921 node.previousSibling = ps;
6922 ps.nextSibling = node;
6924 node.previousSibling = null;
6926 node.nextSibling = null;
6927 this.setLastChild(node);
6928 node.setOwnerTree(this.getOwnerTree());
6929 this.fireEvent("append", this.ownerTree, this, node, index);
6931 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6938 * Removes a child node from this node.
6939 * @param {Node} node The node to remove
6940 * @return {Node} The removed node
6942 removeChild : function(node){
6943 var index = this.childNodes.indexOf(node);
6947 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6951 // remove it from childNodes collection
6952 this.childNodes.splice(index, 1);
6955 if(node.previousSibling){
6956 node.previousSibling.nextSibling = node.nextSibling;
6958 if(node.nextSibling){
6959 node.nextSibling.previousSibling = node.previousSibling;
6962 // update child refs
6963 if(this.firstChild == node){
6964 this.setFirstChild(node.nextSibling);
6966 if(this.lastChild == node){
6967 this.setLastChild(node.previousSibling);
6970 node.setOwnerTree(null);
6971 // clear any references from the node
6972 node.parentNode = null;
6973 node.previousSibling = null;
6974 node.nextSibling = null;
6975 this.fireEvent("remove", this.ownerTree, this, node);
6980 * Inserts the first node before the second node in this nodes childNodes collection.
6981 * @param {Node} node The node to insert
6982 * @param {Node} refNode The node to insert before (if null the node is appended)
6983 * @return {Node} The inserted node
6985 insertBefore : function(node, refNode){
6986 if(!refNode){ // like standard Dom, refNode can be null for append
6987 return this.appendChild(node);
6990 if(node == refNode){
6994 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6997 var index = this.childNodes.indexOf(refNode);
6998 var oldParent = node.parentNode;
6999 var refIndex = index;
7001 // when moving internally, indexes will change after remove
7002 if(oldParent == this && this.childNodes.indexOf(node) < index){
7006 // it's a move, make sure we move it cleanly
7008 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
7011 oldParent.removeChild(node);
7014 this.setFirstChild(node);
7016 this.childNodes.splice(refIndex, 0, node);
7017 node.parentNode = this;
7018 var ps = this.childNodes[refIndex-1];
7020 node.previousSibling = ps;
7021 ps.nextSibling = node;
7023 node.previousSibling = null;
7025 node.nextSibling = refNode;
7026 refNode.previousSibling = node;
7027 node.setOwnerTree(this.getOwnerTree());
7028 this.fireEvent("insert", this.ownerTree, this, node, refNode);
7030 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
7036 * Returns the child node at the specified index.
7037 * @param {Number} index
7040 item : function(index){
7041 return this.childNodes[index];
7045 * Replaces one child node in this node with another.
7046 * @param {Node} newChild The replacement node
7047 * @param {Node} oldChild The node to replace
7048 * @return {Node} The replaced node
7050 replaceChild : function(newChild, oldChild){
7051 this.insertBefore(newChild, oldChild);
7052 this.removeChild(oldChild);
7057 * Returns the index of a child node
7058 * @param {Node} node
7059 * @return {Number} The index of the node or -1 if it was not found
7061 indexOf : function(child){
7062 return this.childNodes.indexOf(child);
7066 * Returns the tree this node is in.
7069 getOwnerTree : function(){
7070 // if it doesn't have one, look for one
7071 if(!this.ownerTree){
7075 this.ownerTree = p.ownerTree;
7081 return this.ownerTree;
7085 * Returns depth of this node (the root node has a depth of 0)
7088 getDepth : function(){
7091 while(p.parentNode){
7099 setOwnerTree : function(tree){
7100 // if it's move, we need to update everyone
7101 if(tree != this.ownerTree){
7103 this.ownerTree.unregisterNode(this);
7105 this.ownerTree = tree;
7106 var cs = this.childNodes;
7107 for(var i = 0, len = cs.length; i < len; i++) {
7108 cs[i].setOwnerTree(tree);
7111 tree.registerNode(this);
7117 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7118 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7119 * @return {String} The path
7121 getPath : function(attr){
7122 attr = attr || "id";
7123 var p = this.parentNode;
7124 var b = [this.attributes[attr]];
7126 b.unshift(p.attributes[attr]);
7129 var sep = this.getOwnerTree().pathSeparator;
7130 return sep + b.join(sep);
7134 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7135 * function call will be the scope provided or the current node. The arguments to the function
7136 * will be the args provided or the current node. If the function returns false at any point,
7137 * the bubble is stopped.
7138 * @param {Function} fn The function to call
7139 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7140 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7142 bubble : function(fn, scope, args){
7145 if(fn.call(scope || p, args || p) === false){
7153 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7154 * function call will be the scope provided or the current node. The arguments to the function
7155 * will be the args provided or the current node. If the function returns false at any point,
7156 * the cascade is stopped on that branch.
7157 * @param {Function} fn The function to call
7158 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7159 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7161 cascade : function(fn, scope, args){
7162 if(fn.call(scope || this, args || this) !== false){
7163 var cs = this.childNodes;
7164 for(var i = 0, len = cs.length; i < len; i++) {
7165 cs[i].cascade(fn, scope, args);
7171 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7172 * function call will be the scope provided or the current node. The arguments to the function
7173 * will be the args provided or the current node. If the function returns false at any point,
7174 * the iteration stops.
7175 * @param {Function} fn The function to call
7176 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7177 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7179 eachChild : function(fn, scope, args){
7180 var cs = this.childNodes;
7181 for(var i = 0, len = cs.length; i < len; i++) {
7182 if(fn.call(scope || this, args || cs[i]) === false){
7189 * Finds the first child that has the attribute with the specified value.
7190 * @param {String} attribute The attribute name
7191 * @param {Mixed} value The value to search for
7192 * @return {Node} The found child or null if none was found
7194 findChild : function(attribute, value){
7195 var cs = this.childNodes;
7196 for(var i = 0, len = cs.length; i < len; i++) {
7197 if(cs[i].attributes[attribute] == value){
7205 * Finds the first child by a custom function. The child matches if the function passed
7207 * @param {Function} fn
7208 * @param {Object} scope (optional)
7209 * @return {Node} The found child or null if none was found
7211 findChildBy : function(fn, scope){
7212 var cs = this.childNodes;
7213 for(var i = 0, len = cs.length; i < len; i++) {
7214 if(fn.call(scope||cs[i], cs[i]) === true){
7222 * Sorts this nodes children using the supplied sort function
7223 * @param {Function} fn
7224 * @param {Object} scope (optional)
7226 sort : function(fn, scope){
7227 var cs = this.childNodes;
7228 var len = cs.length;
7230 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7232 for(var i = 0; i < len; i++){
7234 n.previousSibling = cs[i-1];
7235 n.nextSibling = cs[i+1];
7237 this.setFirstChild(n);
7240 this.setLastChild(n);
7247 * Returns true if this node is an ancestor (at any point) of the passed node.
7248 * @param {Node} node
7251 contains : function(node){
7252 return node.isAncestor(this);
7256 * Returns true if the passed node is an ancestor (at any point) of this node.
7257 * @param {Node} node
7260 isAncestor : function(node){
7261 var p = this.parentNode;
7271 toString : function(){
7272 return "[Node"+(this.id?" "+this.id:"")+"]";
7276 * Ext JS Library 1.1.1
7277 * Copyright(c) 2006-2007, Ext JS, LLC.
7279 * Originally Released Under LGPL - original licence link has changed is not relivant.
7282 * <script type="text/javascript">
7287 * @class Roo.ComponentMgr
7288 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7291 Roo.ComponentMgr = function(){
7292 var all = new Roo.util.MixedCollection();
7296 * Registers a component.
7297 * @param {Roo.Component} c The component
7299 register : function(c){
7304 * Unregisters a component.
7305 * @param {Roo.Component} c The component
7307 unregister : function(c){
7312 * Returns a component by id
7313 * @param {String} id The component id
7320 * Registers a function that will be called when a specified component is added to ComponentMgr
7321 * @param {String} id The component id
7322 * @param {Funtction} fn The callback function
7323 * @param {Object} scope The scope of the callback
7325 onAvailable : function(id, fn, scope){
7326 all.on("add", function(index, o){
7328 fn.call(scope || o, o);
7329 all.un("add", fn, scope);
7336 * Ext JS Library 1.1.1
7337 * Copyright(c) 2006-2007, Ext JS, LLC.
7339 * Originally Released Under LGPL - original licence link has changed is not relivant.
7342 * <script type="text/javascript">
7346 * @class Roo.Component
7347 * @extends Roo.util.Observable
7348 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7349 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7350 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7351 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7352 * All visual components (widgets) that require rendering into a layout should subclass Component.
7354 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7355 * 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
7356 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7358 Roo.Component = function(config){
7359 config = config || {};
7360 if(config.tagName || config.dom || typeof config == "string"){ // element object
7361 config = {el: config, id: config.id || config};
7363 this.initialConfig = config;
7365 Roo.apply(this, config);
7369 * Fires after the component is disabled.
7370 * @param {Roo.Component} this
7375 * Fires after the component is enabled.
7376 * @param {Roo.Component} this
7381 * Fires before the component is shown. Return false to stop the show.
7382 * @param {Roo.Component} this
7387 * Fires after the component is shown.
7388 * @param {Roo.Component} this
7393 * Fires before the component is hidden. Return false to stop the hide.
7394 * @param {Roo.Component} this
7399 * Fires after the component is hidden.
7400 * @param {Roo.Component} this
7404 * @event beforerender
7405 * Fires before the component is rendered. Return false to stop the render.
7406 * @param {Roo.Component} this
7408 beforerender : true,
7411 * Fires after the component is rendered.
7412 * @param {Roo.Component} this
7416 * @event beforedestroy
7417 * Fires before the component is destroyed. Return false to stop the destroy.
7418 * @param {Roo.Component} this
7420 beforedestroy : true,
7423 * Fires after the component is destroyed.
7424 * @param {Roo.Component} this
7429 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7431 Roo.ComponentMgr.register(this);
7432 Roo.Component.superclass.constructor.call(this);
7433 this.initComponent();
7434 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7435 this.render(this.renderTo);
7436 delete this.renderTo;
7441 Roo.Component.AUTO_ID = 1000;
7443 Roo.extend(Roo.Component, Roo.util.Observable, {
7445 * @scope Roo.Component.prototype
7447 * true if this component is hidden. Read-only.
7452 * true if this component is disabled. Read-only.
7457 * true if this component has been rendered. Read-only.
7461 /** @cfg {String} disableClass
7462 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7464 disabledClass : "x-item-disabled",
7465 /** @cfg {Boolean} allowDomMove
7466 * Whether the component can move the Dom node when rendering (defaults to true).
7468 allowDomMove : true,
7469 /** @cfg {String} hideMode
7470 * How this component should hidden. Supported values are
7471 * "visibility" (css visibility), "offsets" (negative offset position) and
7472 * "display" (css display) - defaults to "display".
7474 hideMode: 'display',
7477 ctype : "Roo.Component",
7480 * @cfg {String} actionMode
7481 * which property holds the element that used for hide() / show() / disable() / enable()
7487 getActionEl : function(){
7488 return this[this.actionMode];
7491 initComponent : Roo.emptyFn,
7493 * If this is a lazy rendering component, render it to its container element.
7494 * @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.
7496 render : function(container, position){
7497 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7498 if(!container && this.el){
7499 this.el = Roo.get(this.el);
7500 container = this.el.dom.parentNode;
7501 this.allowDomMove = false;
7503 this.container = Roo.get(container);
7504 this.rendered = true;
7505 if(position !== undefined){
7506 if(typeof position == 'number'){
7507 position = this.container.dom.childNodes[position];
7509 position = Roo.getDom(position);
7512 this.onRender(this.container, position || null);
7514 this.el.addClass(this.cls);
7518 this.el.applyStyles(this.style);
7521 this.fireEvent("render", this);
7522 this.afterRender(this.container);
7534 // default function is not really useful
7535 onRender : function(ct, position){
7537 this.el = Roo.get(this.el);
7538 if(this.allowDomMove !== false){
7539 ct.dom.insertBefore(this.el.dom, position);
7545 getAutoCreate : function(){
7546 var cfg = typeof this.autoCreate == "object" ?
7547 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7548 if(this.id && !cfg.id){
7555 afterRender : Roo.emptyFn,
7558 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7559 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7561 destroy : function(){
7562 if(this.fireEvent("beforedestroy", this) !== false){
7563 this.purgeListeners();
7564 this.beforeDestroy();
7566 this.el.removeAllListeners();
7568 if(this.actionMode == "container"){
7569 this.container.remove();
7573 Roo.ComponentMgr.unregister(this);
7574 this.fireEvent("destroy", this);
7579 beforeDestroy : function(){
7584 onDestroy : function(){
7589 * Returns the underlying {@link Roo.Element}.
7590 * @return {Roo.Element} The element
7597 * Returns the id of this component.
7605 * Try to focus this component.
7606 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7607 * @return {Roo.Component} this
7609 focus : function(selectText){
7612 if(selectText === true){
7613 this.el.dom.select();
7628 * Disable this component.
7629 * @return {Roo.Component} this
7631 disable : function(){
7635 this.disabled = true;
7636 this.fireEvent("disable", this);
7641 onDisable : function(){
7642 this.getActionEl().addClass(this.disabledClass);
7643 this.el.dom.disabled = true;
7647 * Enable this component.
7648 * @return {Roo.Component} this
7650 enable : function(){
7654 this.disabled = false;
7655 this.fireEvent("enable", this);
7660 onEnable : function(){
7661 this.getActionEl().removeClass(this.disabledClass);
7662 this.el.dom.disabled = false;
7666 * Convenience function for setting disabled/enabled by boolean.
7667 * @param {Boolean} disabled
7669 setDisabled : function(disabled){
7670 this[disabled ? "disable" : "enable"]();
7674 * Show this component.
7675 * @return {Roo.Component} this
7678 if(this.fireEvent("beforeshow", this) !== false){
7679 this.hidden = false;
7683 this.fireEvent("show", this);
7689 onShow : function(){
7690 var ae = this.getActionEl();
7691 if(this.hideMode == 'visibility'){
7692 ae.dom.style.visibility = "visible";
7693 }else if(this.hideMode == 'offsets'){
7694 ae.removeClass('x-hidden');
7696 ae.dom.style.display = "";
7701 * Hide this component.
7702 * @return {Roo.Component} this
7705 if(this.fireEvent("beforehide", this) !== false){
7710 this.fireEvent("hide", this);
7716 onHide : function(){
7717 var ae = this.getActionEl();
7718 if(this.hideMode == 'visibility'){
7719 ae.dom.style.visibility = "hidden";
7720 }else if(this.hideMode == 'offsets'){
7721 ae.addClass('x-hidden');
7723 ae.dom.style.display = "none";
7728 * Convenience function to hide or show this component by boolean.
7729 * @param {Boolean} visible True to show, false to hide
7730 * @return {Roo.Component} this
7732 setVisible: function(visible){
7742 * Returns true if this component is visible.
7744 isVisible : function(){
7745 return this.getActionEl().isVisible();
7748 cloneConfig : function(overrides){
7749 overrides = overrides || {};
7750 var id = overrides.id || Roo.id();
7751 var cfg = Roo.applyIf(overrides, this.initialConfig);
7752 cfg.id = id; // prevent dup id
7753 return new this.constructor(cfg);
7757 * Ext JS Library 1.1.1
7758 * Copyright(c) 2006-2007, Ext JS, LLC.
7760 * Originally Released Under LGPL - original licence link has changed is not relivant.
7763 * <script type="text/javascript">
7768 * @extends Roo.Element
7769 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7770 * automatic maintaining of shadow/shim positions.
7771 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7772 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7773 * you can pass a string with a CSS class name. False turns off the shadow.
7774 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7775 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7776 * @cfg {String} cls CSS class to add to the element
7777 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7778 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7780 * @param {Object} config An object with config options.
7781 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7784 Roo.Layer = function(config, existingEl){
7785 config = config || {};
7786 var dh = Roo.DomHelper;
7787 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7789 this.dom = Roo.getDom(existingEl);
7792 var o = config.dh || {tag: "div", cls: "x-layer"};
7793 this.dom = dh.append(pel, o);
7796 this.addClass(config.cls);
7798 this.constrain = config.constrain !== false;
7799 this.visibilityMode = Roo.Element.VISIBILITY;
7801 this.id = this.dom.id = config.id;
7803 this.id = Roo.id(this.dom);
7805 this.zindex = config.zindex || this.getZIndex();
7806 this.position("absolute", this.zindex);
7808 this.shadowOffset = config.shadowOffset || 4;
7809 this.shadow = new Roo.Shadow({
7810 offset : this.shadowOffset,
7811 mode : config.shadow
7814 this.shadowOffset = 0;
7816 this.useShim = config.shim !== false && Roo.useShims;
7817 this.useDisplay = config.useDisplay;
7821 var supr = Roo.Element.prototype;
7823 // shims are shared among layer to keep from having 100 iframes
7826 Roo.extend(Roo.Layer, Roo.Element, {
7828 getZIndex : function(){
7829 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7832 getShim : function(){
7839 var shim = shims.shift();
7841 shim = this.createShim();
7842 shim.enableDisplayMode('block');
7843 shim.dom.style.display = 'none';
7844 shim.dom.style.visibility = 'visible';
7846 var pn = this.dom.parentNode;
7847 if(shim.dom.parentNode != pn){
7848 pn.insertBefore(shim.dom, this.dom);
7850 shim.setStyle('z-index', this.getZIndex()-2);
7855 hideShim : function(){
7857 this.shim.setDisplayed(false);
7858 shims.push(this.shim);
7863 disableShadow : function(){
7865 this.shadowDisabled = true;
7867 this.lastShadowOffset = this.shadowOffset;
7868 this.shadowOffset = 0;
7872 enableShadow : function(show){
7874 this.shadowDisabled = false;
7875 this.shadowOffset = this.lastShadowOffset;
7876 delete this.lastShadowOffset;
7884 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7885 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7886 sync : function(doShow){
7887 var sw = this.shadow;
7888 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7889 var sh = this.getShim();
7891 var w = this.getWidth(),
7892 h = this.getHeight();
7894 var l = this.getLeft(true),
7895 t = this.getTop(true);
7897 if(sw && !this.shadowDisabled){
7898 if(doShow && !sw.isVisible()){
7901 sw.realign(l, t, w, h);
7907 // fit the shim behind the shadow, so it is shimmed too
7908 var a = sw.adjusts, s = sh.dom.style;
7909 s.left = (Math.min(l, l+a.l))+"px";
7910 s.top = (Math.min(t, t+a.t))+"px";
7911 s.width = (w+a.w)+"px";
7912 s.height = (h+a.h)+"px";
7919 sh.setLeftTop(l, t);
7926 destroy : function(){
7931 this.removeAllListeners();
7932 var pn = this.dom.parentNode;
7934 pn.removeChild(this.dom);
7936 Roo.Element.uncache(this.id);
7939 remove : function(){
7944 beginUpdate : function(){
7945 this.updating = true;
7949 endUpdate : function(){
7950 this.updating = false;
7955 hideUnders : function(negOffset){
7963 constrainXY : function(){
7965 var vw = Roo.lib.Dom.getViewWidth(),
7966 vh = Roo.lib.Dom.getViewHeight();
7967 var s = Roo.get(document).getScroll();
7969 var xy = this.getXY();
7970 var x = xy[0], y = xy[1];
7971 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7972 // only move it if it needs it
7974 // first validate right/bottom
7975 if((x + w) > vw+s.left){
7976 x = vw - w - this.shadowOffset;
7979 if((y + h) > vh+s.top){
7980 y = vh - h - this.shadowOffset;
7983 // then make sure top/left isn't negative
7994 var ay = this.avoidY;
7995 if(y <= ay && (y+h) >= ay){
8001 supr.setXY.call(this, xy);
8007 isVisible : function(){
8008 return this.visible;
8012 showAction : function(){
8013 this.visible = true; // track visibility to prevent getStyle calls
8014 if(this.useDisplay === true){
8015 this.setDisplayed("");
8016 }else if(this.lastXY){
8017 supr.setXY.call(this, this.lastXY);
8018 }else if(this.lastLT){
8019 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
8024 hideAction : function(){
8025 this.visible = false;
8026 if(this.useDisplay === true){
8027 this.setDisplayed(false);
8029 this.setLeftTop(-10000,-10000);
8033 // overridden Element method
8034 setVisible : function(v, a, d, c, e){
8039 var cb = function(){
8044 }.createDelegate(this);
8045 supr.setVisible.call(this, true, true, d, cb, e);
8048 this.hideUnders(true);
8057 }.createDelegate(this);
8059 supr.setVisible.call(this, v, a, d, cb, e);
8068 storeXY : function(xy){
8073 storeLeftTop : function(left, top){
8075 this.lastLT = [left, top];
8079 beforeFx : function(){
8080 this.beforeAction();
8081 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8085 afterFx : function(){
8086 Roo.Layer.superclass.afterFx.apply(this, arguments);
8087 this.sync(this.isVisible());
8091 beforeAction : function(){
8092 if(!this.updating && this.shadow){
8097 // overridden Element method
8098 setLeft : function(left){
8099 this.storeLeftTop(left, this.getTop(true));
8100 supr.setLeft.apply(this, arguments);
8104 setTop : function(top){
8105 this.storeLeftTop(this.getLeft(true), top);
8106 supr.setTop.apply(this, arguments);
8110 setLeftTop : function(left, top){
8111 this.storeLeftTop(left, top);
8112 supr.setLeftTop.apply(this, arguments);
8116 setXY : function(xy, a, d, c, e){
8118 this.beforeAction();
8120 var cb = this.createCB(c);
8121 supr.setXY.call(this, xy, a, d, cb, e);
8128 createCB : function(c){
8139 // overridden Element method
8140 setX : function(x, a, d, c, e){
8141 this.setXY([x, this.getY()], a, d, c, e);
8144 // overridden Element method
8145 setY : function(y, a, d, c, e){
8146 this.setXY([this.getX(), y], a, d, c, e);
8149 // overridden Element method
8150 setSize : function(w, h, a, d, c, e){
8151 this.beforeAction();
8152 var cb = this.createCB(c);
8153 supr.setSize.call(this, w, h, a, d, cb, e);
8159 // overridden Element method
8160 setWidth : function(w, a, d, c, e){
8161 this.beforeAction();
8162 var cb = this.createCB(c);
8163 supr.setWidth.call(this, w, a, d, cb, e);
8169 // overridden Element method
8170 setHeight : function(h, a, d, c, e){
8171 this.beforeAction();
8172 var cb = this.createCB(c);
8173 supr.setHeight.call(this, h, a, d, cb, e);
8179 // overridden Element method
8180 setBounds : function(x, y, w, h, a, d, c, e){
8181 this.beforeAction();
8182 var cb = this.createCB(c);
8184 this.storeXY([x, y]);
8185 supr.setXY.call(this, [x, y]);
8186 supr.setSize.call(this, w, h, a, d, cb, e);
8189 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8195 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8196 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8197 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8198 * @param {Number} zindex The new z-index to set
8199 * @return {this} The Layer
8201 setZIndex : function(zindex){
8202 this.zindex = zindex;
8203 this.setStyle("z-index", zindex + 2);
8205 this.shadow.setZIndex(zindex + 1);
8208 this.shim.setStyle("z-index", zindex);
8214 * Ext JS Library 1.1.1
8215 * Copyright(c) 2006-2007, Ext JS, LLC.
8217 * Originally Released Under LGPL - original licence link has changed is not relivant.
8220 * <script type="text/javascript">
8226 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8227 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8228 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8230 * Create a new Shadow
8231 * @param {Object} config The config object
8233 Roo.Shadow = function(config){
8234 Roo.apply(this, config);
8235 if(typeof this.mode != "string"){
8236 this.mode = this.defaultMode;
8238 var o = this.offset, a = {h: 0};
8239 var rad = Math.floor(this.offset/2);
8240 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8246 a.l -= this.offset + rad;
8247 a.t -= this.offset + rad;
8258 a.l -= (this.offset - rad);
8259 a.t -= this.offset + rad;
8261 a.w -= (this.offset - rad)*2;
8272 a.l -= (this.offset - rad);
8273 a.t -= (this.offset - rad);
8275 a.w -= (this.offset + rad + 1);
8276 a.h -= (this.offset + rad);
8285 Roo.Shadow.prototype = {
8287 * @cfg {String} mode
8288 * The shadow display mode. Supports the following options:<br />
8289 * sides: Shadow displays on both sides and bottom only<br />
8290 * frame: Shadow displays equally on all four sides<br />
8291 * drop: Traditional bottom-right drop shadow (default)
8294 * @cfg {String} offset
8295 * The number of pixels to offset the shadow from the element (defaults to 4)
8300 defaultMode: "drop",
8303 * Displays the shadow under the target element
8304 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8306 show : function(target){
8307 target = Roo.get(target);
8309 this.el = Roo.Shadow.Pool.pull();
8310 if(this.el.dom.nextSibling != target.dom){
8311 this.el.insertBefore(target);
8314 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8316 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8319 target.getLeft(true),
8320 target.getTop(true),
8324 this.el.dom.style.display = "block";
8328 * Returns true if the shadow is visible, else false
8330 isVisible : function(){
8331 return this.el ? true : false;
8335 * Direct alignment when values are already available. Show must be called at least once before
8336 * calling this method to ensure it is initialized.
8337 * @param {Number} left The target element left position
8338 * @param {Number} top The target element top position
8339 * @param {Number} width The target element width
8340 * @param {Number} height The target element height
8342 realign : function(l, t, w, h){
8346 var a = this.adjusts, d = this.el.dom, s = d.style;
8348 s.left = (l+a.l)+"px";
8349 s.top = (t+a.t)+"px";
8350 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8352 if(s.width != sws || s.height != shs){
8356 var cn = d.childNodes;
8357 var sww = Math.max(0, (sw-12))+"px";
8358 cn[0].childNodes[1].style.width = sww;
8359 cn[1].childNodes[1].style.width = sww;
8360 cn[2].childNodes[1].style.width = sww;
8361 cn[1].style.height = Math.max(0, (sh-12))+"px";
8371 this.el.dom.style.display = "none";
8372 Roo.Shadow.Pool.push(this.el);
8378 * Adjust the z-index of this shadow
8379 * @param {Number} zindex The new z-index
8381 setZIndex : function(z){
8384 this.el.setStyle("z-index", z);
8389 // Private utility class that manages the internal Shadow cache
8390 Roo.Shadow.Pool = function(){
8392 var markup = Roo.isIE ?
8393 '<div class="x-ie-shadow"></div>' :
8394 '<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>';
8399 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8400 sh.autoBoxAdjust = false;
8405 push : function(sh){
8411 * Ext JS Library 1.1.1
8412 * Copyright(c) 2006-2007, Ext JS, LLC.
8414 * Originally Released Under LGPL - original licence link has changed is not relivant.
8417 * <script type="text/javascript">
8421 * @class Roo.BoxComponent
8422 * @extends Roo.Component
8423 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8424 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8425 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8426 * layout containers.
8428 * @param {Roo.Element/String/Object} config The configuration options.
8430 Roo.BoxComponent = function(config){
8431 Roo.Component.call(this, config);
8435 * Fires after the component is resized.
8436 * @param {Roo.Component} this
8437 * @param {Number} adjWidth The box-adjusted width that was set
8438 * @param {Number} adjHeight The box-adjusted height that was set
8439 * @param {Number} rawWidth The width that was originally specified
8440 * @param {Number} rawHeight The height that was originally specified
8445 * Fires after the component is moved.
8446 * @param {Roo.Component} this
8447 * @param {Number} x The new x position
8448 * @param {Number} y The new y position
8454 Roo.extend(Roo.BoxComponent, Roo.Component, {
8455 // private, set in afterRender to signify that the component has been rendered
8457 // private, used to defer height settings to subclasses
8459 /** @cfg {Number} width
8460 * width (optional) size of component
8462 /** @cfg {Number} height
8463 * height (optional) size of component
8467 * Sets the width and height of the component. This method fires the resize event. This method can accept
8468 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8469 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8470 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8471 * @return {Roo.BoxComponent} this
8473 setSize : function(w, h){
8474 // support for standard size objects
8475 if(typeof w == 'object'){
8486 // prevent recalcs when not needed
8487 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8490 this.lastSize = {width: w, height: h};
8492 var adj = this.adjustSize(w, h);
8493 var aw = adj.width, ah = adj.height;
8494 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8495 var rz = this.getResizeEl();
8496 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8498 }else if(!this.deferHeight && ah !== undefined){
8500 }else if(aw !== undefined){
8503 this.onResize(aw, ah, w, h);
8504 this.fireEvent('resize', this, aw, ah, w, h);
8510 * Gets the current size of the component's underlying element.
8511 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8513 getSize : function(){
8514 return this.el.getSize();
8518 * Gets the current XY position of the component's underlying element.
8519 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8520 * @return {Array} The XY position of the element (e.g., [100, 200])
8522 getPosition : function(local){
8524 return [this.el.getLeft(true), this.el.getTop(true)];
8526 return this.xy || this.el.getXY();
8530 * Gets the current box measurements of the component's underlying element.
8531 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8532 * @returns {Object} box An object in the format {x, y, width, height}
8534 getBox : function(local){
8535 var s = this.el.getSize();
8537 s.x = this.el.getLeft(true);
8538 s.y = this.el.getTop(true);
8540 var xy = this.xy || this.el.getXY();
8548 * Sets the current box measurements of the component's underlying element.
8549 * @param {Object} box An object in the format {x, y, width, height}
8550 * @returns {Roo.BoxComponent} this
8552 updateBox : function(box){
8553 this.setSize(box.width, box.height);
8554 this.setPagePosition(box.x, box.y);
8559 getResizeEl : function(){
8560 return this.resizeEl || this.el;
8564 getPositionEl : function(){
8565 return this.positionEl || this.el;
8569 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8570 * This method fires the move event.
8571 * @param {Number} left The new left
8572 * @param {Number} top The new top
8573 * @returns {Roo.BoxComponent} this
8575 setPosition : function(x, y){
8581 var adj = this.adjustPosition(x, y);
8582 var ax = adj.x, ay = adj.y;
8584 var el = this.getPositionEl();
8585 if(ax !== undefined || ay !== undefined){
8586 if(ax !== undefined && ay !== undefined){
8587 el.setLeftTop(ax, ay);
8588 }else if(ax !== undefined){
8590 }else if(ay !== undefined){
8593 this.onPosition(ax, ay);
8594 this.fireEvent('move', this, ax, ay);
8600 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8601 * This method fires the move event.
8602 * @param {Number} x The new x position
8603 * @param {Number} y The new y position
8604 * @returns {Roo.BoxComponent} this
8606 setPagePosition : function(x, y){
8612 if(x === undefined || y === undefined){ // cannot translate undefined points
8615 var p = this.el.translatePoints(x, y);
8616 this.setPosition(p.left, p.top);
8621 onRender : function(ct, position){
8622 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8624 this.resizeEl = Roo.get(this.resizeEl);
8626 if(this.positionEl){
8627 this.positionEl = Roo.get(this.positionEl);
8632 afterRender : function(){
8633 Roo.BoxComponent.superclass.afterRender.call(this);
8634 this.boxReady = true;
8635 this.setSize(this.width, this.height);
8636 if(this.x || this.y){
8637 this.setPosition(this.x, this.y);
8639 if(this.pageX || this.pageY){
8640 this.setPagePosition(this.pageX, this.pageY);
8645 * Force the component's size to recalculate based on the underlying element's current height and width.
8646 * @returns {Roo.BoxComponent} this
8648 syncSize : function(){
8649 delete this.lastSize;
8650 this.setSize(this.el.getWidth(), this.el.getHeight());
8655 * Called after the component is resized, this method is empty by default but can be implemented by any
8656 * subclass that needs to perform custom logic after a resize occurs.
8657 * @param {Number} adjWidth The box-adjusted width that was set
8658 * @param {Number} adjHeight The box-adjusted height that was set
8659 * @param {Number} rawWidth The width that was originally specified
8660 * @param {Number} rawHeight The height that was originally specified
8662 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8667 * Called after the component is moved, this method is empty by default but can be implemented by any
8668 * subclass that needs to perform custom logic after a move occurs.
8669 * @param {Number} x The new x position
8670 * @param {Number} y The new y position
8672 onPosition : function(x, y){
8677 adjustSize : function(w, h){
8681 if(this.autoHeight){
8684 return {width : w, height: h};
8688 adjustPosition : function(x, y){
8689 return {x : x, y: y};
8693 * Ext JS Library 1.1.1
8694 * Copyright(c) 2006-2007, Ext JS, LLC.
8696 * Originally Released Under LGPL - original licence link has changed is not relivant.
8699 * <script type="text/javascript">
8704 * @class Roo.SplitBar
8705 * @extends Roo.util.Observable
8706 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8710 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8711 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8712 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8713 split.minSize = 100;
8714 split.maxSize = 600;
8715 split.animate = true;
8716 split.on('moved', splitterMoved);
8719 * Create a new SplitBar
8720 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8721 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8722 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8723 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8724 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8725 position of the SplitBar).
8727 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8730 this.el = Roo.get(dragElement, true);
8731 this.el.dom.unselectable = "on";
8733 this.resizingEl = Roo.get(resizingElement, true);
8737 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8738 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8741 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8744 * The minimum size of the resizing element. (Defaults to 0)
8750 * The maximum size of the resizing element. (Defaults to 2000)
8753 this.maxSize = 2000;
8756 * Whether to animate the transition to the new size
8759 this.animate = false;
8762 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8765 this.useShim = false;
8772 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8774 this.proxy = Roo.get(existingProxy).dom;
8777 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8780 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8783 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8786 this.dragSpecs = {};
8789 * @private The adapter to use to positon and resize elements
8791 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8792 this.adapter.init(this);
8794 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8796 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8797 this.el.addClass("x-splitbar-h");
8800 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8801 this.el.addClass("x-splitbar-v");
8807 * Fires when the splitter is moved (alias for {@link #event-moved})
8808 * @param {Roo.SplitBar} this
8809 * @param {Number} newSize the new width or height
8814 * Fires when the splitter is moved
8815 * @param {Roo.SplitBar} this
8816 * @param {Number} newSize the new width or height
8820 * @event beforeresize
8821 * Fires before the splitter is dragged
8822 * @param {Roo.SplitBar} this
8824 "beforeresize" : true,
8826 "beforeapply" : true
8829 Roo.util.Observable.call(this);
8832 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8833 onStartProxyDrag : function(x, y){
8834 this.fireEvent("beforeresize", this);
8836 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8838 o.enableDisplayMode("block");
8839 // all splitbars share the same overlay
8840 Roo.SplitBar.prototype.overlay = o;
8842 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8843 this.overlay.show();
8844 Roo.get(this.proxy).setDisplayed("block");
8845 var size = this.adapter.getElementSize(this);
8846 this.activeMinSize = this.getMinimumSize();;
8847 this.activeMaxSize = this.getMaximumSize();;
8848 var c1 = size - this.activeMinSize;
8849 var c2 = Math.max(this.activeMaxSize - size, 0);
8850 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8851 this.dd.resetConstraints();
8852 this.dd.setXConstraint(
8853 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8854 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8856 this.dd.setYConstraint(0, 0);
8858 this.dd.resetConstraints();
8859 this.dd.setXConstraint(0, 0);
8860 this.dd.setYConstraint(
8861 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8862 this.placement == Roo.SplitBar.TOP ? c2 : c1
8865 this.dragSpecs.startSize = size;
8866 this.dragSpecs.startPoint = [x, y];
8867 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8871 * @private Called after the drag operation by the DDProxy
8873 onEndProxyDrag : function(e){
8874 Roo.get(this.proxy).setDisplayed(false);
8875 var endPoint = Roo.lib.Event.getXY(e);
8877 this.overlay.hide();
8880 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8881 newSize = this.dragSpecs.startSize +
8882 (this.placement == Roo.SplitBar.LEFT ?
8883 endPoint[0] - this.dragSpecs.startPoint[0] :
8884 this.dragSpecs.startPoint[0] - endPoint[0]
8887 newSize = this.dragSpecs.startSize +
8888 (this.placement == Roo.SplitBar.TOP ?
8889 endPoint[1] - this.dragSpecs.startPoint[1] :
8890 this.dragSpecs.startPoint[1] - endPoint[1]
8893 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8894 if(newSize != this.dragSpecs.startSize){
8895 if(this.fireEvent('beforeapply', this, newSize) !== false){
8896 this.adapter.setElementSize(this, newSize);
8897 this.fireEvent("moved", this, newSize);
8898 this.fireEvent("resize", this, newSize);
8904 * Get the adapter this SplitBar uses
8905 * @return The adapter object
8907 getAdapter : function(){
8908 return this.adapter;
8912 * Set the adapter this SplitBar uses
8913 * @param {Object} adapter A SplitBar adapter object
8915 setAdapter : function(adapter){
8916 this.adapter = adapter;
8917 this.adapter.init(this);
8921 * Gets the minimum size for the resizing element
8922 * @return {Number} The minimum size
8924 getMinimumSize : function(){
8925 return this.minSize;
8929 * Sets the minimum size for the resizing element
8930 * @param {Number} minSize The minimum size
8932 setMinimumSize : function(minSize){
8933 this.minSize = minSize;
8937 * Gets the maximum size for the resizing element
8938 * @return {Number} The maximum size
8940 getMaximumSize : function(){
8941 return this.maxSize;
8945 * Sets the maximum size for the resizing element
8946 * @param {Number} maxSize The maximum size
8948 setMaximumSize : function(maxSize){
8949 this.maxSize = maxSize;
8953 * Sets the initialize size for the resizing element
8954 * @param {Number} size The initial size
8956 setCurrentSize : function(size){
8957 var oldAnimate = this.animate;
8958 this.animate = false;
8959 this.adapter.setElementSize(this, size);
8960 this.animate = oldAnimate;
8964 * Destroy this splitbar.
8965 * @param {Boolean} removeEl True to remove the element
8967 destroy : function(removeEl){
8972 this.proxy.parentNode.removeChild(this.proxy);
8980 * @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.
8982 Roo.SplitBar.createProxy = function(dir){
8983 var proxy = new Roo.Element(document.createElement("div"));
8984 proxy.unselectable();
8985 var cls = 'x-splitbar-proxy';
8986 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8987 document.body.appendChild(proxy.dom);
8992 * @class Roo.SplitBar.BasicLayoutAdapter
8993 * Default Adapter. It assumes the splitter and resizing element are not positioned
8994 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8996 Roo.SplitBar.BasicLayoutAdapter = function(){
8999 Roo.SplitBar.BasicLayoutAdapter.prototype = {
9000 // do nothing for now
9005 * Called before drag operations to get the current size of the resizing element.
9006 * @param {Roo.SplitBar} s The SplitBar using this adapter
9008 getElementSize : function(s){
9009 if(s.orientation == Roo.SplitBar.HORIZONTAL){
9010 return s.resizingEl.getWidth();
9012 return s.resizingEl.getHeight();
9017 * Called after drag operations to set the size of the resizing element.
9018 * @param {Roo.SplitBar} s The SplitBar using this adapter
9019 * @param {Number} newSize The new size to set
9020 * @param {Function} onComplete A function to be invoked when resizing is complete
9022 setElementSize : function(s, newSize, onComplete){
9023 if(s.orientation == Roo.SplitBar.HORIZONTAL){
9025 s.resizingEl.setWidth(newSize);
9027 onComplete(s, newSize);
9030 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
9035 s.resizingEl.setHeight(newSize);
9037 onComplete(s, newSize);
9040 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
9047 *@class Roo.SplitBar.AbsoluteLayoutAdapter
9048 * @extends Roo.SplitBar.BasicLayoutAdapter
9049 * Adapter that moves the splitter element to align with the resized sizing element.
9050 * Used with an absolute positioned SplitBar.
9051 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
9052 * document.body, make sure you assign an id to the body element.
9054 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
9055 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
9056 this.container = Roo.get(container);
9059 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
9064 getElementSize : function(s){
9065 return this.basic.getElementSize(s);
9068 setElementSize : function(s, newSize, onComplete){
9069 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9072 moveSplitter : function(s){
9073 var yes = Roo.SplitBar;
9074 switch(s.placement){
9076 s.el.setX(s.resizingEl.getRight());
9079 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9082 s.el.setY(s.resizingEl.getBottom());
9085 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9092 * Orientation constant - Create a vertical SplitBar
9096 Roo.SplitBar.VERTICAL = 1;
9099 * Orientation constant - Create a horizontal SplitBar
9103 Roo.SplitBar.HORIZONTAL = 2;
9106 * Placement constant - The resizing element is to the left of the splitter element
9110 Roo.SplitBar.LEFT = 1;
9113 * Placement constant - The resizing element is to the right of the splitter element
9117 Roo.SplitBar.RIGHT = 2;
9120 * Placement constant - The resizing element is positioned above the splitter element
9124 Roo.SplitBar.TOP = 3;
9127 * Placement constant - The resizing element is positioned under splitter element
9131 Roo.SplitBar.BOTTOM = 4;
9134 * Ext JS Library 1.1.1
9135 * Copyright(c) 2006-2007, Ext JS, LLC.
9137 * Originally Released Under LGPL - original licence link has changed is not relivant.
9140 * <script type="text/javascript">
9145 * @extends Roo.util.Observable
9146 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9147 * This class also supports single and multi selection modes. <br>
9148 * Create a data model bound view:
9150 var store = new Roo.data.Store(...);
9152 var view = new Roo.View({
9154 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9157 selectedClass: "ydataview-selected",
9161 // listen for node click?
9162 view.on("click", function(vw, index, node, e){
9163 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9167 dataModel.load("foobar.xml");
9169 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9171 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9172 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9174 * Note: old style constructor is still suported (container, template, config)
9178 * @param {Object} config The config object
9181 Roo.View = function(config, depreciated_tpl, depreciated_config){
9183 if (typeof(depreciated_tpl) == 'undefined') {
9184 // new way.. - universal constructor.
9185 Roo.apply(this, config);
9186 this.el = Roo.get(this.el);
9189 this.el = Roo.get(config);
9190 this.tpl = depreciated_tpl;
9191 Roo.apply(this, depreciated_config);
9193 this.wrapEl = this.el.wrap().wrap();
9194 ///this.el = this.wrapEla.appendChild(document.createElement("div"));
9197 if(typeof(this.tpl) == "string"){
9198 this.tpl = new Roo.Template(this.tpl);
9200 // support xtype ctors..
9201 this.tpl = new Roo.factory(this.tpl, Roo);
9213 * @event beforeclick
9214 * Fires before a click is processed. Returns false to cancel the default action.
9215 * @param {Roo.View} this
9216 * @param {Number} index The index of the target node
9217 * @param {HTMLElement} node The target node
9218 * @param {Roo.EventObject} e The raw event object
9220 "beforeclick" : true,
9223 * Fires when a template node is clicked.
9224 * @param {Roo.View} this
9225 * @param {Number} index The index of the target node
9226 * @param {HTMLElement} node The target node
9227 * @param {Roo.EventObject} e The raw event object
9232 * Fires when a template node is double clicked.
9233 * @param {Roo.View} this
9234 * @param {Number} index The index of the target node
9235 * @param {HTMLElement} node The target node
9236 * @param {Roo.EventObject} e The raw event object
9240 * @event contextmenu
9241 * Fires when a template node is right clicked.
9242 * @param {Roo.View} this
9243 * @param {Number} index The index of the target node
9244 * @param {HTMLElement} node The target node
9245 * @param {Roo.EventObject} e The raw event object
9247 "contextmenu" : true,
9249 * @event selectionchange
9250 * Fires when the selected nodes change.
9251 * @param {Roo.View} this
9252 * @param {Array} selections Array of the selected nodes
9254 "selectionchange" : true,
9257 * @event beforeselect
9258 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9259 * @param {Roo.View} this
9260 * @param {HTMLElement} node The node to be selected
9261 * @param {Array} selections Array of currently selected nodes
9263 "beforeselect" : true,
9265 * @event preparedata
9266 * Fires on every row to render, to allow you to change the data.
9267 * @param {Roo.View} this
9268 * @param {Object} data to be rendered (change this)
9270 "preparedata" : true
9278 "click": this.onClick,
9279 "dblclick": this.onDblClick,
9280 "contextmenu": this.onContextMenu,
9284 this.selections = [];
9286 this.cmp = new Roo.CompositeElementLite([]);
9288 this.store = Roo.factory(this.store, Roo.data);
9289 this.setStore(this.store, true);
9292 if ( this.footer && this.footer.xtype) {
9294 var fctr = this.wrapEl.appendChild(document.createElement("div"));
9296 this.footer.dataSource = this.store
9297 this.footer.container = fctr;
9298 this.footer = Roo.factory(this.footer, Roo);
9299 fctr.insertFirst(this.el);
9301 // this is a bit insane - as the paging toolbar seems to detach the el..
9302 // dom.parentNode.parentNode.parentNode
9303 // they get detached?
9307 Roo.View.superclass.constructor.call(this);
9312 Roo.extend(Roo.View, Roo.util.Observable, {
9315 * @cfg {Roo.data.Store} store Data store to load data from.
9320 * @cfg {String|Roo.Element} el The container element.
9325 * @cfg {String|Roo.Template} tpl The template used by this View
9329 * @cfg {String} dataName the named area of the template to use as the data area
9330 * Works with domtemplates roo-name="name"
9334 * @cfg {String} selectedClass The css class to add to selected nodes
9336 selectedClass : "x-view-selected",
9338 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9343 * @cfg {String} text to display on mask (default Loading)
9347 * @cfg {Boolean} multiSelect Allow multiple selection
9349 multiSelect : false,
9351 * @cfg {Boolean} singleSelect Allow single selection
9353 singleSelect: false,
9356 * @cfg {Boolean} toggleSelect - selecting
9358 toggleSelect : false,
9361 * Returns the element this view is bound to.
9362 * @return {Roo.Element}
9371 * Refreshes the view. - called by datachanged on the store. - do not call directly.
9373 refresh : function(){
9376 // if we are using something like 'domtemplate', then
9377 // the what gets used is:
9378 // t.applySubtemplate(NAME, data, wrapping data..)
9379 // the outer template then get' applied with
9380 // the store 'extra data'
9381 // and the body get's added to the
9382 // roo-name="data" node?
9383 // <span class='roo-tpl-{name}'></span> ?????
9387 this.clearSelections();
9390 var records = this.store.getRange();
9391 if(records.length < 1) {
9393 // is this valid?? = should it render a template??
9395 this.el.update(this.emptyText);
9399 if (this.dataName) {
9400 this.el.update(t.apply(this.store.meta)); //????
9401 el = this.el.child('.roo-tpl-' + this.dataName);
9404 for(var i = 0, len = records.length; i < len; i++){
9405 var data = this.prepareData(records[i].data, i, records[i]);
9406 this.fireEvent("preparedata", this, data, i, records[i]);
9407 html[html.length] = Roo.util.Format.trim(
9409 t.applySubtemplate(this.dataName, data, this.store.meta) :
9416 el.update(html.join(""));
9417 this.nodes = el.dom.childNodes;
9418 this.updateIndexes(0);
9422 * Function to override to reformat the data that is sent to
9423 * the template for each node.
9424 * DEPRICATED - use the preparedata event handler.
9425 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9426 * a JSON object for an UpdateManager bound view).
9428 prepareData : function(data, index, record)
9430 this.fireEvent("preparedata", this, data, index, record);
9434 onUpdate : function(ds, record){
9435 this.clearSelections();
9436 var index = this.store.indexOf(record);
9437 var n = this.nodes[index];
9438 this.tpl.insertBefore(n, this.prepareData(record.data, index, record));
9439 n.parentNode.removeChild(n);
9440 this.updateIndexes(index, index);
9446 onAdd : function(ds, records, index)
9448 this.clearSelections();
9449 if(this.nodes.length == 0){
9453 var n = this.nodes[index];
9454 for(var i = 0, len = records.length; i < len; i++){
9455 var d = this.prepareData(records[i].data, i, records[i]);
9457 this.tpl.insertBefore(n, d);
9460 this.tpl.append(this.el, d);
9463 this.updateIndexes(index);
9466 onRemove : function(ds, record, index){
9467 this.clearSelections();
9468 var el = this.dataName ?
9469 this.el.child('.roo-tpl-' + this.dataName) :
9471 el.dom.removeChild(this.nodes[index]);
9472 this.updateIndexes(index);
9476 * Refresh an individual node.
9477 * @param {Number} index
9479 refreshNode : function(index){
9480 this.onUpdate(this.store, this.store.getAt(index));
9483 updateIndexes : function(startIndex, endIndex){
9484 var ns = this.nodes;
9485 startIndex = startIndex || 0;
9486 endIndex = endIndex || ns.length - 1;
9487 for(var i = startIndex; i <= endIndex; i++){
9488 ns[i].nodeIndex = i;
9493 * Changes the data store this view uses and refresh the view.
9494 * @param {Store} store
9496 setStore : function(store, initial){
9497 if(!initial && this.store){
9498 this.store.un("datachanged", this.refresh);
9499 this.store.un("add", this.onAdd);
9500 this.store.un("remove", this.onRemove);
9501 this.store.un("update", this.onUpdate);
9502 this.store.un("clear", this.refresh);
9503 this.store.un("beforeload", this.onBeforeLoad);
9504 this.store.un("load", this.onLoad);
9505 this.store.un("loadexception", this.onLoad);
9509 store.on("datachanged", this.refresh, this);
9510 store.on("add", this.onAdd, this);
9511 store.on("remove", this.onRemove, this);
9512 store.on("update", this.onUpdate, this);
9513 store.on("clear", this.refresh, this);
9514 store.on("beforeload", this.onBeforeLoad, this);
9515 store.on("load", this.onLoad, this);
9516 store.on("loadexception", this.onLoad, this);
9524 * onbeforeLoad - masks the loading area.
9527 onBeforeLoad : function()
9530 this.el.mask(this.mask ? this.mask : "Loading" );
9532 onLoad : function ()
9539 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9540 * @param {HTMLElement} node
9541 * @return {HTMLElement} The template node
9543 findItemFromChild : function(node){
9544 var el = this.dataName ?
9545 this.el.child('.roo-tpl-' + this.dataName,true) :
9548 if(!node || node.parentNode == el){
9551 var p = node.parentNode;
9552 while(p && p != el){
9553 if(p.parentNode == el){
9562 onClick : function(e){
9563 var item = this.findItemFromChild(e.getTarget());
9565 var index = this.indexOf(item);
9566 if(this.onItemClick(item, index, e) !== false){
9567 this.fireEvent("click", this, index, item, e);
9570 this.clearSelections();
9575 onContextMenu : function(e){
9576 var item = this.findItemFromChild(e.getTarget());
9578 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9583 onDblClick : function(e){
9584 var item = this.findItemFromChild(e.getTarget());
9586 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9590 onItemClick : function(item, index, e)
9592 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9595 if (this.toggleSelect) {
9596 var m = this.isSelected(item) ? 'unselect' : 'select';
9599 _t[m](item, true, false);
9602 if(this.multiSelect || this.singleSelect){
9603 if(this.multiSelect && e.shiftKey && this.lastSelection){
9604 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9606 this.select(item, this.multiSelect && e.ctrlKey);
9607 this.lastSelection = item;
9615 * Get the number of selected nodes.
9618 getSelectionCount : function(){
9619 return this.selections.length;
9623 * Get the currently selected nodes.
9624 * @return {Array} An array of HTMLElements
9626 getSelectedNodes : function(){
9627 return this.selections;
9631 * Get the indexes of the selected nodes.
9634 getSelectedIndexes : function(){
9635 var indexes = [], s = this.selections;
9636 for(var i = 0, len = s.length; i < len; i++){
9637 indexes.push(s[i].nodeIndex);
9643 * Clear all selections
9644 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9646 clearSelections : function(suppressEvent){
9647 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9648 this.cmp.elements = this.selections;
9649 this.cmp.removeClass(this.selectedClass);
9650 this.selections = [];
9652 this.fireEvent("selectionchange", this, this.selections);
9658 * Returns true if the passed node is selected
9659 * @param {HTMLElement/Number} node The node or node index
9662 isSelected : function(node){
9663 var s = this.selections;
9667 node = this.getNode(node);
9668 return s.indexOf(node) !== -1;
9673 * @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
9674 * @param {Boolean} keepExisting (optional) true to keep existing selections
9675 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9677 select : function(nodeInfo, keepExisting, suppressEvent){
9678 if(nodeInfo instanceof Array){
9680 this.clearSelections(true);
9682 for(var i = 0, len = nodeInfo.length; i < len; i++){
9683 this.select(nodeInfo[i], true, true);
9687 var node = this.getNode(nodeInfo);
9688 if(!node || this.isSelected(node)){
9689 return; // already selected.
9692 this.clearSelections(true);
9694 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9695 Roo.fly(node).addClass(this.selectedClass);
9696 this.selections.push(node);
9698 this.fireEvent("selectionchange", this, this.selections);
9706 * @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
9707 * @param {Boolean} keepExisting (optional) true IGNORED (for campatibility with select)
9708 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9710 unselect : function(nodeInfo, keepExisting, suppressEvent)
9712 if(nodeInfo instanceof Array){
9713 Roo.each(this.selections, function(s) {
9714 this.unselect(s, nodeInfo);
9718 var node = this.getNode(nodeInfo);
9719 if(!node || !this.isSelected(node)){
9720 Roo.log("not selected");
9721 return; // not selected.
9725 Roo.each(this.selections, function(s) {
9727 Roo.fly(node).removeClass(this.selectedClass);
9734 this.selections= ns;
9735 this.fireEvent("selectionchange", this, this.selections);
9739 * Gets a template node.
9740 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9741 * @return {HTMLElement} The node or null if it wasn't found
9743 getNode : function(nodeInfo){
9744 if(typeof nodeInfo == "string"){
9745 return document.getElementById(nodeInfo);
9746 }else if(typeof nodeInfo == "number"){
9747 return this.nodes[nodeInfo];
9753 * Gets a range template nodes.
9754 * @param {Number} startIndex
9755 * @param {Number} endIndex
9756 * @return {Array} An array of nodes
9758 getNodes : function(start, end){
9759 var ns = this.nodes;
9761 end = typeof end == "undefined" ? ns.length - 1 : end;
9764 for(var i = start; i <= end; i++){
9768 for(var i = start; i >= end; i--){
9776 * Finds the index of the passed node
9777 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9778 * @return {Number} The index of the node or -1
9780 indexOf : function(node){
9781 node = this.getNode(node);
9782 if(typeof node.nodeIndex == "number"){
9783 return node.nodeIndex;
9785 var ns = this.nodes;
9786 for(var i = 0, len = ns.length; i < len; i++){
9796 * Ext JS Library 1.1.1
9797 * Copyright(c) 2006-2007, Ext JS, LLC.
9799 * Originally Released Under LGPL - original licence link has changed is not relivant.
9802 * <script type="text/javascript">
9806 * @class Roo.JsonView
9808 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9810 var view = new Roo.JsonView({
9811 container: "my-element",
9812 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9817 // listen for node click?
9818 view.on("click", function(vw, index, node, e){
9819 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9822 // direct load of JSON data
9823 view.load("foobar.php");
9825 // Example from my blog list
9826 var tpl = new Roo.Template(
9827 '<div class="entry">' +
9828 '<a class="entry-title" href="{link}">{title}</a>' +
9829 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9830 "</div><hr />"
9833 var moreView = new Roo.JsonView({
9834 container : "entry-list",
9838 moreView.on("beforerender", this.sortEntries, this);
9840 url: "/blog/get-posts.php",
9841 params: "allposts=true",
9842 text: "Loading Blog Entries..."
9846 * Note: old code is supported with arguments : (container, template, config)
9850 * Create a new JsonView
9852 * @param {Object} config The config object
9855 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9858 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9860 var um = this.el.getUpdateManager();
9861 um.setRenderer(this);
9862 um.on("update", this.onLoad, this);
9863 um.on("failure", this.onLoadException, this);
9866 * @event beforerender
9867 * Fires before rendering of the downloaded JSON data.
9868 * @param {Roo.JsonView} this
9869 * @param {Object} data The JSON data loaded
9873 * Fires when data is loaded.
9874 * @param {Roo.JsonView} this
9875 * @param {Object} data The JSON data loaded
9876 * @param {Object} response The raw Connect response object
9879 * @event loadexception
9880 * Fires when loading fails.
9881 * @param {Roo.JsonView} this
9882 * @param {Object} response The raw Connect response object
9885 'beforerender' : true,
9887 'loadexception' : true
9890 Roo.extend(Roo.JsonView, Roo.View, {
9892 * @type {String} The root property in the loaded JSON object that contains the data
9897 * Refreshes the view.
9899 refresh : function(){
9900 this.clearSelections();
9903 var o = this.jsonData;
9904 if(o && o.length > 0){
9905 for(var i = 0, len = o.length; i < len; i++){
9906 var data = this.prepareData(o[i], i, o);
9907 html[html.length] = this.tpl.apply(data);
9910 html.push(this.emptyText);
9912 this.el.update(html.join(""));
9913 this.nodes = this.el.dom.childNodes;
9914 this.updateIndexes(0);
9918 * 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.
9919 * @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:
9922 url: "your-url.php",
9923 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9924 callback: yourFunction,
9925 scope: yourObject, //(optional scope)
9933 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9934 * 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.
9935 * @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}
9936 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9937 * @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.
9940 var um = this.el.getUpdateManager();
9941 um.update.apply(um, arguments);
9944 render : function(el, response){
9945 this.clearSelections();
9949 o = Roo.util.JSON.decode(response.responseText);
9952 o = o[this.jsonRoot];
9957 * The current JSON data or null
9960 this.beforeRender();
9965 * Get the number of records in the current JSON dataset
9968 getCount : function(){
9969 return this.jsonData ? this.jsonData.length : 0;
9973 * Returns the JSON object for the specified node(s)
9974 * @param {HTMLElement/Array} node The node or an array of nodes
9975 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9976 * you get the JSON object for the node
9978 getNodeData : function(node){
9979 if(node instanceof Array){
9981 for(var i = 0, len = node.length; i < len; i++){
9982 data.push(this.getNodeData(node[i]));
9986 return this.jsonData[this.indexOf(node)] || null;
9989 beforeRender : function(){
9990 this.snapshot = this.jsonData;
9992 this.sort.apply(this, this.sortInfo);
9994 this.fireEvent("beforerender", this, this.jsonData);
9997 onLoad : function(el, o){
9998 this.fireEvent("load", this, this.jsonData, o);
10001 onLoadException : function(el, o){
10002 this.fireEvent("loadexception", this, o);
10006 * Filter the data by a specific property.
10007 * @param {String} property A property on your JSON objects
10008 * @param {String/RegExp} value Either string that the property values
10009 * should start with, or a RegExp to test against the property
10011 filter : function(property, value){
10014 var ss = this.snapshot;
10015 if(typeof value == "string"){
10016 var vlen = value.length;
10018 this.clearFilter();
10021 value = value.toLowerCase();
10022 for(var i = 0, len = ss.length; i < len; i++){
10024 if(o[property].substr(0, vlen).toLowerCase() == value){
10028 } else if(value.exec){ // regex?
10029 for(var i = 0, len = ss.length; i < len; i++){
10031 if(value.test(o[property])){
10038 this.jsonData = data;
10044 * Filter by a function. The passed function will be called with each
10045 * object in the current dataset. If the function returns true the value is kept,
10046 * otherwise it is filtered.
10047 * @param {Function} fn
10048 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
10050 filterBy : function(fn, scope){
10053 var ss = this.snapshot;
10054 for(var i = 0, len = ss.length; i < len; i++){
10056 if(fn.call(scope || this, o)){
10060 this.jsonData = data;
10066 * Clears the current filter.
10068 clearFilter : function(){
10069 if(this.snapshot && this.jsonData != this.snapshot){
10070 this.jsonData = this.snapshot;
10077 * Sorts the data for this view and refreshes it.
10078 * @param {String} property A property on your JSON objects to sort on
10079 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
10080 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
10082 sort : function(property, dir, sortType){
10083 this.sortInfo = Array.prototype.slice.call(arguments, 0);
10086 var dsc = dir && dir.toLowerCase() == "desc";
10087 var f = function(o1, o2){
10088 var v1 = sortType ? sortType(o1[p]) : o1[p];
10089 var v2 = sortType ? sortType(o2[p]) : o2[p];
10092 return dsc ? +1 : -1;
10093 } else if(v1 > v2){
10094 return dsc ? -1 : +1;
10099 this.jsonData.sort(f);
10101 if(this.jsonData != this.snapshot){
10102 this.snapshot.sort(f);
10108 * Ext JS Library 1.1.1
10109 * Copyright(c) 2006-2007, Ext JS, LLC.
10111 * Originally Released Under LGPL - original licence link has changed is not relivant.
10114 * <script type="text/javascript">
10119 * @class Roo.ColorPalette
10120 * @extends Roo.Component
10121 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
10122 * Here's an example of typical usage:
10124 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
10125 cp.render('my-div');
10127 cp.on('select', function(palette, selColor){
10128 // do something with selColor
10132 * Create a new ColorPalette
10133 * @param {Object} config The config object
10135 Roo.ColorPalette = function(config){
10136 Roo.ColorPalette.superclass.constructor.call(this, config);
10140 * Fires when a color is selected
10141 * @param {ColorPalette} this
10142 * @param {String} color The 6-digit color hex code (without the # symbol)
10148 this.on("select", this.handler, this.scope, true);
10151 Roo.extend(Roo.ColorPalette, Roo.Component, {
10153 * @cfg {String} itemCls
10154 * The CSS class to apply to the containing element (defaults to "x-color-palette")
10156 itemCls : "x-color-palette",
10158 * @cfg {String} value
10159 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
10160 * the hex codes are case-sensitive.
10163 clickEvent:'click',
10165 ctype: "Roo.ColorPalette",
10168 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
10170 allowReselect : false,
10173 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
10174 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
10175 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
10176 * of colors with the width setting until the box is symmetrical.</p>
10177 * <p>You can override individual colors if needed:</p>
10179 var cp = new Roo.ColorPalette();
10180 cp.colors[0] = "FF0000"; // change the first box to red
10183 Or you can provide a custom array of your own for complete control:
10185 var cp = new Roo.ColorPalette();
10186 cp.colors = ["000000", "993300", "333300"];
10191 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
10192 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
10193 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
10194 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
10195 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
10199 onRender : function(container, position){
10200 var t = new Roo.MasterTemplate(
10201 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
10203 var c = this.colors;
10204 for(var i = 0, len = c.length; i < len; i++){
10207 var el = document.createElement("div");
10208 el.className = this.itemCls;
10210 container.dom.insertBefore(el, position);
10211 this.el = Roo.get(el);
10212 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
10213 if(this.clickEvent != 'click'){
10214 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
10219 afterRender : function(){
10220 Roo.ColorPalette.superclass.afterRender.call(this);
10222 var s = this.value;
10229 handleClick : function(e, t){
10230 e.preventDefault();
10231 if(!this.disabled){
10232 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10233 this.select(c.toUpperCase());
10238 * Selects the specified color in the palette (fires the select event)
10239 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10241 select : function(color){
10242 color = color.replace("#", "");
10243 if(color != this.value || this.allowReselect){
10246 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10248 el.child("a.color-"+color).addClass("x-color-palette-sel");
10249 this.value = color;
10250 this.fireEvent("select", this, color);
10255 * Ext JS Library 1.1.1
10256 * Copyright(c) 2006-2007, Ext JS, LLC.
10258 * Originally Released Under LGPL - original licence link has changed is not relivant.
10261 * <script type="text/javascript">
10265 * @class Roo.DatePicker
10266 * @extends Roo.Component
10267 * Simple date picker class.
10269 * Create a new DatePicker
10270 * @param {Object} config The config object
10272 Roo.DatePicker = function(config){
10273 Roo.DatePicker.superclass.constructor.call(this, config);
10275 this.value = config && config.value ?
10276 config.value.clearTime() : new Date().clearTime();
10281 * Fires when a date is selected
10282 * @param {DatePicker} this
10283 * @param {Date} date The selected date
10287 * @event monthchange
10288 * Fires when the displayed month changes
10289 * @param {DatePicker} this
10290 * @param {Date} date The selected month
10292 'monthchange': true
10296 this.on("select", this.handler, this.scope || this);
10298 // build the disabledDatesRE
10299 if(!this.disabledDatesRE && this.disabledDates){
10300 var dd = this.disabledDates;
10302 for(var i = 0; i < dd.length; i++){
10304 if(i != dd.length-1) re += "|";
10306 this.disabledDatesRE = new RegExp(re + ")");
10310 Roo.extend(Roo.DatePicker, Roo.Component, {
10312 * @cfg {String} todayText
10313 * The text to display on the button that selects the current date (defaults to "Today")
10315 todayText : "Today",
10317 * @cfg {String} okText
10318 * The text to display on the ok button
10320 okText : " OK ", //   to give the user extra clicking room
10322 * @cfg {String} cancelText
10323 * The text to display on the cancel button
10325 cancelText : "Cancel",
10327 * @cfg {String} todayTip
10328 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10330 todayTip : "{0} (Spacebar)",
10332 * @cfg {Date} minDate
10333 * Minimum allowable date (JavaScript date object, defaults to null)
10337 * @cfg {Date} maxDate
10338 * Maximum allowable date (JavaScript date object, defaults to null)
10342 * @cfg {String} minText
10343 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10345 minText : "This date is before the minimum date",
10347 * @cfg {String} maxText
10348 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10350 maxText : "This date is after the maximum date",
10352 * @cfg {String} format
10353 * The default date format string which can be overriden for localization support. The format must be
10354 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10358 * @cfg {Array} disabledDays
10359 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10361 disabledDays : null,
10363 * @cfg {String} disabledDaysText
10364 * The tooltip to display when the date falls on a disabled day (defaults to "")
10366 disabledDaysText : "",
10368 * @cfg {RegExp} disabledDatesRE
10369 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10371 disabledDatesRE : null,
10373 * @cfg {String} disabledDatesText
10374 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10376 disabledDatesText : "",
10378 * @cfg {Boolean} constrainToViewport
10379 * True to constrain the date picker to the viewport (defaults to true)
10381 constrainToViewport : true,
10383 * @cfg {Array} monthNames
10384 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10386 monthNames : Date.monthNames,
10388 * @cfg {Array} dayNames
10389 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10391 dayNames : Date.dayNames,
10393 * @cfg {String} nextText
10394 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10396 nextText: 'Next Month (Control+Right)',
10398 * @cfg {String} prevText
10399 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10401 prevText: 'Previous Month (Control+Left)',
10403 * @cfg {String} monthYearText
10404 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10406 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10408 * @cfg {Number} startDay
10409 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10413 * @cfg {Bool} showClear
10414 * Show a clear button (usefull for date form elements that can be blank.)
10420 * Sets the value of the date field
10421 * @param {Date} value The date to set
10423 setValue : function(value){
10424 var old = this.value;
10426 if (typeof(value) == 'string') {
10428 value = Date.parseDate(value, this.format);
10431 value = new Date();
10434 this.value = value.clearTime(true);
10436 this.update(this.value);
10441 * Gets the current selected value of the date field
10442 * @return {Date} The selected date
10444 getValue : function(){
10449 focus : function(){
10451 this.update(this.activeDate);
10456 onRender : function(container, position){
10459 '<table cellspacing="0">',
10460 '<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>',
10461 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10462 var dn = this.dayNames;
10463 for(var i = 0; i < 7; i++){
10464 var d = this.startDay+i;
10468 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10470 m[m.length] = "</tr></thead><tbody><tr>";
10471 for(var i = 0; i < 42; i++) {
10472 if(i % 7 == 0 && i != 0){
10473 m[m.length] = "</tr><tr>";
10475 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10477 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10478 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10480 var el = document.createElement("div");
10481 el.className = "x-date-picker";
10482 el.innerHTML = m.join("");
10484 container.dom.insertBefore(el, position);
10486 this.el = Roo.get(el);
10487 this.eventEl = Roo.get(el.firstChild);
10489 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10490 handler: this.showPrevMonth,
10492 preventDefault:true,
10496 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10497 handler: this.showNextMonth,
10499 preventDefault:true,
10503 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10505 this.monthPicker = this.el.down('div.x-date-mp');
10506 this.monthPicker.enableDisplayMode('block');
10508 var kn = new Roo.KeyNav(this.eventEl, {
10509 "left" : function(e){
10511 this.showPrevMonth() :
10512 this.update(this.activeDate.add("d", -1));
10515 "right" : function(e){
10517 this.showNextMonth() :
10518 this.update(this.activeDate.add("d", 1));
10521 "up" : function(e){
10523 this.showNextYear() :
10524 this.update(this.activeDate.add("d", -7));
10527 "down" : function(e){
10529 this.showPrevYear() :
10530 this.update(this.activeDate.add("d", 7));
10533 "pageUp" : function(e){
10534 this.showNextMonth();
10537 "pageDown" : function(e){
10538 this.showPrevMonth();
10541 "enter" : function(e){
10542 e.stopPropagation();
10549 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10551 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10553 this.el.unselectable();
10555 this.cells = this.el.select("table.x-date-inner tbody td");
10556 this.textNodes = this.el.query("table.x-date-inner tbody span");
10558 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10560 tooltip: this.monthYearText
10563 this.mbtn.on('click', this.showMonthPicker, this);
10564 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10567 var today = (new Date()).dateFormat(this.format);
10569 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10570 if (this.showClear) {
10571 baseTb.add( new Roo.Toolbar.Fill());
10574 text: String.format(this.todayText, today),
10575 tooltip: String.format(this.todayTip, today),
10576 handler: this.selectToday,
10580 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10583 if (this.showClear) {
10585 baseTb.add( new Roo.Toolbar.Fill());
10588 cls: 'x-btn-icon x-btn-clear',
10589 handler: function() {
10591 this.fireEvent("select", this, '');
10601 this.update(this.value);
10604 createMonthPicker : function(){
10605 if(!this.monthPicker.dom.firstChild){
10606 var buf = ['<table border="0" cellspacing="0">'];
10607 for(var i = 0; i < 6; i++){
10609 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10610 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10612 '<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>' :
10613 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10617 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10619 '</button><button type="button" class="x-date-mp-cancel">',
10621 '</button></td></tr>',
10624 this.monthPicker.update(buf.join(''));
10625 this.monthPicker.on('click', this.onMonthClick, this);
10626 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10628 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10629 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10631 this.mpMonths.each(function(m, a, i){
10634 m.dom.xmonth = 5 + Math.round(i * .5);
10636 m.dom.xmonth = Math.round((i-1) * .5);
10642 showMonthPicker : function(){
10643 this.createMonthPicker();
10644 var size = this.el.getSize();
10645 this.monthPicker.setSize(size);
10646 this.monthPicker.child('table').setSize(size);
10648 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10649 this.updateMPMonth(this.mpSelMonth);
10650 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10651 this.updateMPYear(this.mpSelYear);
10653 this.monthPicker.slideIn('t', {duration:.2});
10656 updateMPYear : function(y){
10658 var ys = this.mpYears.elements;
10659 for(var i = 1; i <= 10; i++){
10660 var td = ys[i-1], y2;
10662 y2 = y + Math.round(i * .5);
10663 td.firstChild.innerHTML = y2;
10666 y2 = y - (5-Math.round(i * .5));
10667 td.firstChild.innerHTML = y2;
10670 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10674 updateMPMonth : function(sm){
10675 this.mpMonths.each(function(m, a, i){
10676 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10680 selectMPMonth: function(m){
10684 onMonthClick : function(e, t){
10686 var el = new Roo.Element(t), pn;
10687 if(el.is('button.x-date-mp-cancel')){
10688 this.hideMonthPicker();
10690 else if(el.is('button.x-date-mp-ok')){
10691 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10692 this.hideMonthPicker();
10694 else if(pn = el.up('td.x-date-mp-month', 2)){
10695 this.mpMonths.removeClass('x-date-mp-sel');
10696 pn.addClass('x-date-mp-sel');
10697 this.mpSelMonth = pn.dom.xmonth;
10699 else if(pn = el.up('td.x-date-mp-year', 2)){
10700 this.mpYears.removeClass('x-date-mp-sel');
10701 pn.addClass('x-date-mp-sel');
10702 this.mpSelYear = pn.dom.xyear;
10704 else if(el.is('a.x-date-mp-prev')){
10705 this.updateMPYear(this.mpyear-10);
10707 else if(el.is('a.x-date-mp-next')){
10708 this.updateMPYear(this.mpyear+10);
10712 onMonthDblClick : function(e, t){
10714 var el = new Roo.Element(t), pn;
10715 if(pn = el.up('td.x-date-mp-month', 2)){
10716 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10717 this.hideMonthPicker();
10719 else if(pn = el.up('td.x-date-mp-year', 2)){
10720 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10721 this.hideMonthPicker();
10725 hideMonthPicker : function(disableAnim){
10726 if(this.monthPicker){
10727 if(disableAnim === true){
10728 this.monthPicker.hide();
10730 this.monthPicker.slideOut('t', {duration:.2});
10736 showPrevMonth : function(e){
10737 this.update(this.activeDate.add("mo", -1));
10741 showNextMonth : function(e){
10742 this.update(this.activeDate.add("mo", 1));
10746 showPrevYear : function(){
10747 this.update(this.activeDate.add("y", -1));
10751 showNextYear : function(){
10752 this.update(this.activeDate.add("y", 1));
10756 handleMouseWheel : function(e){
10757 var delta = e.getWheelDelta();
10759 this.showPrevMonth();
10761 } else if(delta < 0){
10762 this.showNextMonth();
10768 handleDateClick : function(e, t){
10770 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10771 this.setValue(new Date(t.dateValue));
10772 this.fireEvent("select", this, this.value);
10777 selectToday : function(){
10778 this.setValue(new Date().clearTime());
10779 this.fireEvent("select", this, this.value);
10783 update : function(date)
10785 var vd = this.activeDate;
10786 this.activeDate = date;
10788 var t = date.getTime();
10789 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10790 this.cells.removeClass("x-date-selected");
10791 this.cells.each(function(c){
10792 if(c.dom.firstChild.dateValue == t){
10793 c.addClass("x-date-selected");
10794 setTimeout(function(){
10795 try{c.dom.firstChild.focus();}catch(e){}
10804 var days = date.getDaysInMonth();
10805 var firstOfMonth = date.getFirstDateOfMonth();
10806 var startingPos = firstOfMonth.getDay()-this.startDay;
10808 if(startingPos <= this.startDay){
10812 var pm = date.add("mo", -1);
10813 var prevStart = pm.getDaysInMonth()-startingPos;
10815 var cells = this.cells.elements;
10816 var textEls = this.textNodes;
10817 days += startingPos;
10819 // convert everything to numbers so it's fast
10820 var day = 86400000;
10821 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10822 var today = new Date().clearTime().getTime();
10823 var sel = date.clearTime().getTime();
10824 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10825 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10826 var ddMatch = this.disabledDatesRE;
10827 var ddText = this.disabledDatesText;
10828 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10829 var ddaysText = this.disabledDaysText;
10830 var format = this.format;
10832 var setCellClass = function(cal, cell){
10834 var t = d.getTime();
10835 cell.firstChild.dateValue = t;
10837 cell.className += " x-date-today";
10838 cell.title = cal.todayText;
10841 cell.className += " x-date-selected";
10842 setTimeout(function(){
10843 try{cell.firstChild.focus();}catch(e){}
10848 cell.className = " x-date-disabled";
10849 cell.title = cal.minText;
10853 cell.className = " x-date-disabled";
10854 cell.title = cal.maxText;
10858 if(ddays.indexOf(d.getDay()) != -1){
10859 cell.title = ddaysText;
10860 cell.className = " x-date-disabled";
10863 if(ddMatch && format){
10864 var fvalue = d.dateFormat(format);
10865 if(ddMatch.test(fvalue)){
10866 cell.title = ddText.replace("%0", fvalue);
10867 cell.className = " x-date-disabled";
10873 for(; i < startingPos; i++) {
10874 textEls[i].innerHTML = (++prevStart);
10875 d.setDate(d.getDate()+1);
10876 cells[i].className = "x-date-prevday";
10877 setCellClass(this, cells[i]);
10879 for(; i < days; i++){
10880 intDay = i - startingPos + 1;
10881 textEls[i].innerHTML = (intDay);
10882 d.setDate(d.getDate()+1);
10883 cells[i].className = "x-date-active";
10884 setCellClass(this, cells[i]);
10887 for(; i < 42; i++) {
10888 textEls[i].innerHTML = (++extraDays);
10889 d.setDate(d.getDate()+1);
10890 cells[i].className = "x-date-nextday";
10891 setCellClass(this, cells[i]);
10894 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10895 this.fireEvent('monthchange', this, date);
10897 if(!this.internalRender){
10898 var main = this.el.dom.firstChild;
10899 var w = main.offsetWidth;
10900 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10901 Roo.fly(main).setWidth(w);
10902 this.internalRender = true;
10903 // opera does not respect the auto grow header center column
10904 // then, after it gets a width opera refuses to recalculate
10905 // without a second pass
10906 if(Roo.isOpera && !this.secondPass){
10907 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10908 this.secondPass = true;
10909 this.update.defer(10, this, [date]);
10917 * Ext JS Library 1.1.1
10918 * Copyright(c) 2006-2007, Ext JS, LLC.
10920 * Originally Released Under LGPL - original licence link has changed is not relivant.
10923 * <script type="text/javascript">
10926 * @class Roo.TabPanel
10927 * @extends Roo.util.Observable
10928 * A lightweight tab container.
10932 // basic tabs 1, built from existing content
10933 var tabs = new Roo.TabPanel("tabs1");
10934 tabs.addTab("script", "View Script");
10935 tabs.addTab("markup", "View Markup");
10936 tabs.activate("script");
10938 // more advanced tabs, built from javascript
10939 var jtabs = new Roo.TabPanel("jtabs");
10940 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10942 // set up the UpdateManager
10943 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10944 var updater = tab2.getUpdateManager();
10945 updater.setDefaultUrl("ajax1.htm");
10946 tab2.on('activate', updater.refresh, updater, true);
10948 // Use setUrl for Ajax loading
10949 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10950 tab3.setUrl("ajax2.htm", null, true);
10953 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10956 jtabs.activate("jtabs-1");
10959 * Create a new TabPanel.
10960 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10961 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10963 Roo.TabPanel = function(container, config){
10965 * The container element for this TabPanel.
10966 * @type Roo.Element
10968 this.el = Roo.get(container, true);
10970 if(typeof config == "boolean"){
10971 this.tabPosition = config ? "bottom" : "top";
10973 Roo.apply(this, config);
10976 if(this.tabPosition == "bottom"){
10977 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10978 this.el.addClass("x-tabs-bottom");
10980 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10981 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10982 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10984 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10986 if(this.tabPosition != "bottom"){
10987 /** The body element that contains {@link Roo.TabPanelItem} bodies. +
10988 * @type Roo.Element
10990 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10991 this.el.addClass("x-tabs-top");
10995 this.bodyEl.setStyle("position", "relative");
10997 this.active = null;
10998 this.activateDelegate = this.activate.createDelegate(this);
11003 * Fires when the active tab changes
11004 * @param {Roo.TabPanel} this
11005 * @param {Roo.TabPanelItem} activePanel The new active tab
11009 * @event beforetabchange
11010 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
11011 * @param {Roo.TabPanel} this
11012 * @param {Object} e Set cancel to true on this object to cancel the tab change
11013 * @param {Roo.TabPanelItem} tab The tab being changed to
11015 "beforetabchange" : true
11018 Roo.EventManager.onWindowResize(this.onResize, this);
11019 this.cpad = this.el.getPadding("lr");
11020 this.hiddenCount = 0;
11023 // toolbar on the tabbar support...
11024 if (this.toolbar) {
11025 var tcfg = this.toolbar;
11026 tcfg.container = this.stripEl.child('td.x-tab-strip-toolbar');
11027 this.toolbar = new Roo.Toolbar(tcfg);
11028 if (Roo.isSafari) {
11029 var tbl = tcfg.container.child('table', true);
11030 tbl.setAttribute('width', '100%');
11037 Roo.TabPanel.superclass.constructor.call(this);
11040 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
11042 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
11044 tabPosition : "top",
11046 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
11048 currentTabWidth : 0,
11050 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
11054 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
11058 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
11060 preferredTabWidth : 175,
11062 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
11064 resizeTabs : false,
11066 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
11068 monitorResize : true,
11070 *@cfg {Object} toolbar xtype description of toolbar to show at the right of the tab bar.
11075 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
11076 * @param {String} id The id of the div to use <b>or create</b>
11077 * @param {String} text The text for the tab
11078 * @param {String} content (optional) Content to put in the TabPanelItem body
11079 * @param {Boolean} closable (optional) True to create a close icon on the tab
11080 * @return {Roo.TabPanelItem} The created TabPanelItem
11082 addTab : function(id, text, content, closable){
11083 var item = new Roo.TabPanelItem(this, id, text, closable);
11084 this.addTabItem(item);
11086 item.setContent(content);
11092 * Returns the {@link Roo.TabPanelItem} with the specified id/index
11093 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
11094 * @return {Roo.TabPanelItem}
11096 getTab : function(id){
11097 return this.items[id];
11101 * Hides the {@link Roo.TabPanelItem} with the specified id/index
11102 * @param {String/Number} id The id or index of the TabPanelItem to hide.
11104 hideTab : function(id){
11105 var t = this.items[id];
11108 this.hiddenCount++;
11109 this.autoSizeTabs();
11114 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
11115 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
11117 unhideTab : function(id){
11118 var t = this.items[id];
11120 t.setHidden(false);
11121 this.hiddenCount--;
11122 this.autoSizeTabs();
11127 * Adds an existing {@link Roo.TabPanelItem}.
11128 * @param {Roo.TabPanelItem} item The TabPanelItem to add
11130 addTabItem : function(item){
11131 this.items[item.id] = item;
11132 this.items.push(item);
11133 if(this.resizeTabs){
11134 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
11135 this.autoSizeTabs();
11142 * Removes a {@link Roo.TabPanelItem}.
11143 * @param {String/Number} id The id or index of the TabPanelItem to remove.
11145 removeTab : function(id){
11146 var items = this.items;
11147 var tab = items[id];
11148 if(!tab) { return; }
11149 var index = items.indexOf(tab);
11150 if(this.active == tab && items.length > 1){
11151 var newTab = this.getNextAvailable(index);
11156 this.stripEl.dom.removeChild(tab.pnode.dom);
11157 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
11158 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
11160 items.splice(index, 1);
11161 delete this.items[tab.id];
11162 tab.fireEvent("close", tab);
11163 tab.purgeListeners();
11164 this.autoSizeTabs();
11167 getNextAvailable : function(start){
11168 var items = this.items;
11170 // look for a next tab that will slide over to
11171 // replace the one being removed
11172 while(index < items.length){
11173 var item = items[++index];
11174 if(item && !item.isHidden()){
11178 // if one isn't found select the previous tab (on the left)
11181 var item = items[--index];
11182 if(item && !item.isHidden()){
11190 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
11191 * @param {String/Number} id The id or index of the TabPanelItem to disable.
11193 disableTab : function(id){
11194 var tab = this.items[id];
11195 if(tab && this.active != tab){
11201 * Enables a {@link Roo.TabPanelItem} that is disabled.
11202 * @param {String/Number} id The id or index of the TabPanelItem to enable.
11204 enableTab : function(id){
11205 var tab = this.items[id];
11210 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
11211 * @param {String/Number} id The id or index of the TabPanelItem to activate.
11212 * @return {Roo.TabPanelItem} The TabPanelItem.
11214 activate : function(id){
11215 var tab = this.items[id];
11219 if(tab == this.active || tab.disabled){
11223 this.fireEvent("beforetabchange", this, e, tab);
11224 if(e.cancel !== true && !tab.disabled){
11226 this.active.hide();
11228 this.active = this.items[id];
11229 this.active.show();
11230 this.fireEvent("tabchange", this, this.active);
11236 * Gets the active {@link Roo.TabPanelItem}.
11237 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
11239 getActiveTab : function(){
11240 return this.active;
11244 * Updates the tab body element to fit the height of the container element
11245 * for overflow scrolling
11246 * @param {Number} targetHeight (optional) Override the starting height from the elements height
11248 syncHeight : function(targetHeight){
11249 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
11250 var bm = this.bodyEl.getMargins();
11251 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
11252 this.bodyEl.setHeight(newHeight);
11256 onResize : function(){
11257 if(this.monitorResize){
11258 this.autoSizeTabs();
11263 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11265 beginUpdate : function(){
11266 this.updating = true;
11270 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11272 endUpdate : function(){
11273 this.updating = false;
11274 this.autoSizeTabs();
11278 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11280 autoSizeTabs : function(){
11281 var count = this.items.length;
11282 var vcount = count - this.hiddenCount;
11283 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11284 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11285 var availWidth = Math.floor(w / vcount);
11286 var b = this.stripBody;
11287 if(b.getWidth() > w){
11288 var tabs = this.items;
11289 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11290 if(availWidth < this.minTabWidth){
11291 /*if(!this.sleft){ // incomplete scrolling code
11292 this.createScrollButtons();
11295 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11298 if(this.currentTabWidth < this.preferredTabWidth){
11299 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11305 * Returns the number of tabs in this TabPanel.
11308 getCount : function(){
11309 return this.items.length;
11313 * Resizes all the tabs to the passed width
11314 * @param {Number} The new width
11316 setTabWidth : function(width){
11317 this.currentTabWidth = width;
11318 for(var i = 0, len = this.items.length; i < len; i++) {
11319 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11324 * Destroys this TabPanel
11325 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11327 destroy : function(removeEl){
11328 Roo.EventManager.removeResizeListener(this.onResize, this);
11329 for(var i = 0, len = this.items.length; i < len; i++){
11330 this.items[i].purgeListeners();
11332 if(removeEl === true){
11333 this.el.update("");
11340 * @class Roo.TabPanelItem
11341 * @extends Roo.util.Observable
11342 * Represents an individual item (tab plus body) in a TabPanel.
11343 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11344 * @param {String} id The id of this TabPanelItem
11345 * @param {String} text The text for the tab of this TabPanelItem
11346 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11348 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11350 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11351 * @type Roo.TabPanel
11353 this.tabPanel = tabPanel;
11355 * The id for this TabPanelItem
11360 this.disabled = false;
11364 this.loaded = false;
11365 this.closable = closable;
11368 * The body element for this TabPanelItem.
11369 * @type Roo.Element
11371 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11372 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11373 this.bodyEl.setStyle("display", "block");
11374 this.bodyEl.setStyle("zoom", "1");
11377 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11379 this.el = Roo.get(els.el, true);
11380 this.inner = Roo.get(els.inner, true);
11381 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11382 this.pnode = Roo.get(els.el.parentNode, true);
11383 this.el.on("mousedown", this.onTabMouseDown, this);
11384 this.el.on("click", this.onTabClick, this);
11387 var c = Roo.get(els.close, true);
11388 c.dom.title = this.closeText;
11389 c.addClassOnOver("close-over");
11390 c.on("click", this.closeClick, this);
11396 * Fires when this tab becomes the active tab.
11397 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11398 * @param {Roo.TabPanelItem} this
11402 * @event beforeclose
11403 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11404 * @param {Roo.TabPanelItem} this
11405 * @param {Object} e Set cancel to true on this object to cancel the close.
11407 "beforeclose": true,
11410 * Fires when this tab is closed.
11411 * @param {Roo.TabPanelItem} this
11415 * @event deactivate
11416 * Fires when this tab is no longer the active tab.
11417 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11418 * @param {Roo.TabPanelItem} this
11420 "deactivate" : true
11422 this.hidden = false;
11424 Roo.TabPanelItem.superclass.constructor.call(this);
11427 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11428 purgeListeners : function(){
11429 Roo.util.Observable.prototype.purgeListeners.call(this);
11430 this.el.removeAllListeners();
11433 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11436 this.pnode.addClass("on");
11439 this.tabPanel.stripWrap.repaint();
11441 this.fireEvent("activate", this.tabPanel, this);
11445 * Returns true if this tab is the active tab.
11446 * @return {Boolean}
11448 isActive : function(){
11449 return this.tabPanel.getActiveTab() == this;
11453 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11456 this.pnode.removeClass("on");
11458 this.fireEvent("deactivate", this.tabPanel, this);
11461 hideAction : function(){
11462 this.bodyEl.hide();
11463 this.bodyEl.setStyle("position", "absolute");
11464 this.bodyEl.setLeft("-20000px");
11465 this.bodyEl.setTop("-20000px");
11468 showAction : function(){
11469 this.bodyEl.setStyle("position", "relative");
11470 this.bodyEl.setTop("");
11471 this.bodyEl.setLeft("");
11472 this.bodyEl.show();
11476 * Set the tooltip for the tab.
11477 * @param {String} tooltip The tab's tooltip
11479 setTooltip : function(text){
11480 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11481 this.textEl.dom.qtip = text;
11482 this.textEl.dom.removeAttribute('title');
11484 this.textEl.dom.title = text;
11488 onTabClick : function(e){
11489 e.preventDefault();
11490 this.tabPanel.activate(this.id);
11493 onTabMouseDown : function(e){
11494 e.preventDefault();
11495 this.tabPanel.activate(this.id);
11498 getWidth : function(){
11499 return this.inner.getWidth();
11502 setWidth : function(width){
11503 var iwidth = width - this.pnode.getPadding("lr");
11504 this.inner.setWidth(iwidth);
11505 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11506 this.pnode.setWidth(width);
11510 * Show or hide the tab
11511 * @param {Boolean} hidden True to hide or false to show.
11513 setHidden : function(hidden){
11514 this.hidden = hidden;
11515 this.pnode.setStyle("display", hidden ? "none" : "");
11519 * Returns true if this tab is "hidden"
11520 * @return {Boolean}
11522 isHidden : function(){
11523 return this.hidden;
11527 * Returns the text for this tab
11530 getText : function(){
11534 autoSize : function(){
11535 //this.el.beginMeasure();
11536 this.textEl.setWidth(1);
11537 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11538 //this.el.endMeasure();
11542 * Sets the text for the tab (Note: this also sets the tooltip text)
11543 * @param {String} text The tab's text and tooltip
11545 setText : function(text){
11547 this.textEl.update(text);
11548 this.setTooltip(text);
11549 if(!this.tabPanel.resizeTabs){
11554 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11556 activate : function(){
11557 this.tabPanel.activate(this.id);
11561 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11563 disable : function(){
11564 if(this.tabPanel.active != this){
11565 this.disabled = true;
11566 this.pnode.addClass("disabled");
11571 * Enables this TabPanelItem if it was previously disabled.
11573 enable : function(){
11574 this.disabled = false;
11575 this.pnode.removeClass("disabled");
11579 * Sets the content for this TabPanelItem.
11580 * @param {String} content The content
11581 * @param {Boolean} loadScripts true to look for and load scripts
11583 setContent : function(content, loadScripts){
11584 this.bodyEl.update(content, loadScripts);
11588 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11589 * @return {Roo.UpdateManager} The UpdateManager
11591 getUpdateManager : function(){
11592 return this.bodyEl.getUpdateManager();
11596 * Set a URL to be used to load the content for this TabPanelItem.
11597 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11598 * @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)
11599 * @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)
11600 * @return {Roo.UpdateManager} The UpdateManager
11602 setUrl : function(url, params, loadOnce){
11603 if(this.refreshDelegate){
11604 this.un('activate', this.refreshDelegate);
11606 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11607 this.on("activate", this.refreshDelegate);
11608 return this.bodyEl.getUpdateManager();
11612 _handleRefresh : function(url, params, loadOnce){
11613 if(!loadOnce || !this.loaded){
11614 var updater = this.bodyEl.getUpdateManager();
11615 updater.update(url, params, this._setLoaded.createDelegate(this));
11620 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11621 * Will fail silently if the setUrl method has not been called.
11622 * This does not activate the panel, just updates its content.
11624 refresh : function(){
11625 if(this.refreshDelegate){
11626 this.loaded = false;
11627 this.refreshDelegate();
11632 _setLoaded : function(){
11633 this.loaded = true;
11637 closeClick : function(e){
11640 this.fireEvent("beforeclose", this, o);
11641 if(o.cancel !== true){
11642 this.tabPanel.removeTab(this.id);
11646 * The text displayed in the tooltip for the close icon.
11649 closeText : "Close this tab"
11653 Roo.TabPanel.prototype.createStrip = function(container){
11654 var strip = document.createElement("div");
11655 strip.className = "x-tabs-wrap";
11656 container.appendChild(strip);
11660 Roo.TabPanel.prototype.createStripList = function(strip){
11661 // div wrapper for retard IE
11662 // returns the "tr" element.
11663 strip.innerHTML = '<div class="x-tabs-strip-wrap">'+
11664 '<table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr>'+
11665 '<td class="x-tab-strip-toolbar"></td></tr></tbody></table></div>';
11666 return strip.firstChild.firstChild.firstChild.firstChild;
11669 Roo.TabPanel.prototype.createBody = function(container){
11670 var body = document.createElement("div");
11671 Roo.id(body, "tab-body");
11672 Roo.fly(body).addClass("x-tabs-body");
11673 container.appendChild(body);
11677 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11678 var body = Roo.getDom(id);
11680 body = document.createElement("div");
11683 Roo.fly(body).addClass("x-tabs-item-body");
11684 bodyEl.insertBefore(body, bodyEl.firstChild);
11688 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11689 var td = document.createElement("td");
11690 stripEl.insertBefore(td, stripEl.childNodes[stripEl.childNodes.length-1]);
11691 //stripEl.appendChild(td);
11693 td.className = "x-tabs-closable";
11694 if(!this.closeTpl){
11695 this.closeTpl = new Roo.Template(
11696 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11697 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11698 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11701 var el = this.closeTpl.overwrite(td, {"text": text});
11702 var close = el.getElementsByTagName("div")[0];
11703 var inner = el.getElementsByTagName("em")[0];
11704 return {"el": el, "close": close, "inner": inner};
11707 this.tabTpl = new Roo.Template(
11708 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11709 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11712 var el = this.tabTpl.overwrite(td, {"text": text});
11713 var inner = el.getElementsByTagName("em")[0];
11714 return {"el": el, "inner": inner};
11718 * Ext JS Library 1.1.1
11719 * Copyright(c) 2006-2007, Ext JS, LLC.
11721 * Originally Released Under LGPL - original licence link has changed is not relivant.
11724 * <script type="text/javascript">
11728 * @class Roo.Button
11729 * @extends Roo.util.Observable
11730 * Simple Button class
11731 * @cfg {String} text The button text
11732 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11733 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11734 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11735 * @cfg {Object} scope The scope of the handler
11736 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11737 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11738 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11739 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11740 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11741 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11742 applies if enableToggle = true)
11743 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11744 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11745 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11747 * Create a new button
11748 * @param {Object} config The config object
11750 Roo.Button = function(renderTo, config)
11754 renderTo = config.renderTo || false;
11757 Roo.apply(this, config);
11761 * Fires when this button is clicked
11762 * @param {Button} this
11763 * @param {EventObject} e The click event
11768 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11769 * @param {Button} this
11770 * @param {Boolean} pressed
11775 * Fires when the mouse hovers over the button
11776 * @param {Button} this
11777 * @param {Event} e The event object
11779 'mouseover' : true,
11782 * Fires when the mouse exits the button
11783 * @param {Button} this
11784 * @param {Event} e The event object
11789 * Fires when the button is rendered
11790 * @param {Button} this
11795 this.menu = Roo.menu.MenuMgr.get(this.menu);
11797 // register listeners first!! - so render can be captured..
11798 Roo.util.Observable.call(this);
11800 this.render(renderTo);
11806 Roo.extend(Roo.Button, Roo.util.Observable, {
11812 * Read-only. True if this button is hidden
11817 * Read-only. True if this button is disabled
11822 * Read-only. True if this button is pressed (only if enableToggle = true)
11828 * @cfg {Number} tabIndex
11829 * The DOM tabIndex for this button (defaults to undefined)
11831 tabIndex : undefined,
11834 * @cfg {Boolean} enableToggle
11835 * True to enable pressed/not pressed toggling (defaults to false)
11837 enableToggle: false,
11839 * @cfg {Mixed} menu
11840 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11844 * @cfg {String} menuAlign
11845 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11847 menuAlign : "tl-bl?",
11850 * @cfg {String} iconCls
11851 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11853 iconCls : undefined,
11855 * @cfg {String} type
11856 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11861 menuClassTarget: 'tr',
11864 * @cfg {String} clickEvent
11865 * The type of event to map to the button's event handler (defaults to 'click')
11867 clickEvent : 'click',
11870 * @cfg {Boolean} handleMouseEvents
11871 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11873 handleMouseEvents : true,
11876 * @cfg {String} tooltipType
11877 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11879 tooltipType : 'qtip',
11882 * @cfg {String} cls
11883 * A CSS class to apply to the button's main element.
11887 * @cfg {Roo.Template} template (Optional)
11888 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11889 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11890 * require code modifications if required elements (e.g. a button) aren't present.
11894 render : function(renderTo){
11896 if(this.hideParent){
11897 this.parentEl = Roo.get(renderTo);
11899 if(!this.dhconfig){
11900 if(!this.template){
11901 if(!Roo.Button.buttonTemplate){
11902 // hideous table template
11903 Roo.Button.buttonTemplate = new Roo.Template(
11904 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11905 '<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>',
11906 "</tr></tbody></table>");
11908 this.template = Roo.Button.buttonTemplate;
11910 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11911 var btnEl = btn.child("button:first");
11912 btnEl.on('focus', this.onFocus, this);
11913 btnEl.on('blur', this.onBlur, this);
11915 btn.addClass(this.cls);
11918 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11921 btnEl.addClass(this.iconCls);
11923 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11926 if(this.tabIndex !== undefined){
11927 btnEl.dom.tabIndex = this.tabIndex;
11930 if(typeof this.tooltip == 'object'){
11931 Roo.QuickTips.tips(Roo.apply({
11935 btnEl.dom[this.tooltipType] = this.tooltip;
11939 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11943 this.el.dom.id = this.el.id = this.id;
11946 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11947 this.menu.on("show", this.onMenuShow, this);
11948 this.menu.on("hide", this.onMenuHide, this);
11950 btn.addClass("x-btn");
11951 if(Roo.isIE && !Roo.isIE7){
11952 this.autoWidth.defer(1, this);
11956 if(this.handleMouseEvents){
11957 btn.on("mouseover", this.onMouseOver, this);
11958 btn.on("mouseout", this.onMouseOut, this);
11959 btn.on("mousedown", this.onMouseDown, this);
11961 btn.on(this.clickEvent, this.onClick, this);
11962 //btn.on("mouseup", this.onMouseUp, this);
11969 Roo.ButtonToggleMgr.register(this);
11971 this.el.addClass("x-btn-pressed");
11974 var repeater = new Roo.util.ClickRepeater(btn,
11975 typeof this.repeat == "object" ? this.repeat : {}
11977 repeater.on("click", this.onClick, this);
11980 this.fireEvent('render', this);
11984 * Returns the button's underlying element
11985 * @return {Roo.Element} The element
11987 getEl : function(){
11992 * Destroys this Button and removes any listeners.
11994 destroy : function(){
11995 Roo.ButtonToggleMgr.unregister(this);
11996 this.el.removeAllListeners();
11997 this.purgeListeners();
12002 autoWidth : function(){
12004 this.el.setWidth("auto");
12005 if(Roo.isIE7 && Roo.isStrict){
12006 var ib = this.el.child('button');
12007 if(ib && ib.getWidth() > 20){
12009 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12014 this.el.beginMeasure();
12016 if(this.el.getWidth() < this.minWidth){
12017 this.el.setWidth(this.minWidth);
12020 this.el.endMeasure();
12027 * Assigns this button's click handler
12028 * @param {Function} handler The function to call when the button is clicked
12029 * @param {Object} scope (optional) Scope for the function passed in
12031 setHandler : function(handler, scope){
12032 this.handler = handler;
12033 this.scope = scope;
12037 * Sets this button's text
12038 * @param {String} text The button text
12040 setText : function(text){
12043 this.el.child("td.x-btn-center button.x-btn-text").update(text);
12049 * Gets the text for this button
12050 * @return {String} The button text
12052 getText : function(){
12060 this.hidden = false;
12062 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
12070 this.hidden = true;
12072 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
12077 * Convenience function for boolean show/hide
12078 * @param {Boolean} visible True to show, false to hide
12080 setVisible: function(visible){
12089 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
12090 * @param {Boolean} state (optional) Force a particular state
12092 toggle : function(state){
12093 state = state === undefined ? !this.pressed : state;
12094 if(state != this.pressed){
12096 this.el.addClass("x-btn-pressed");
12097 this.pressed = true;
12098 this.fireEvent("toggle", this, true);
12100 this.el.removeClass("x-btn-pressed");
12101 this.pressed = false;
12102 this.fireEvent("toggle", this, false);
12104 if(this.toggleHandler){
12105 this.toggleHandler.call(this.scope || this, this, state);
12113 focus : function(){
12114 this.el.child('button:first').focus();
12118 * Disable this button
12120 disable : function(){
12122 this.el.addClass("x-btn-disabled");
12124 this.disabled = true;
12128 * Enable this button
12130 enable : function(){
12132 this.el.removeClass("x-btn-disabled");
12134 this.disabled = false;
12138 * Convenience function for boolean enable/disable
12139 * @param {Boolean} enabled True to enable, false to disable
12141 setDisabled : function(v){
12142 this[v !== true ? "enable" : "disable"]();
12146 onClick : function(e){
12148 e.preventDefault();
12153 if(!this.disabled){
12154 if(this.enableToggle){
12157 if(this.menu && !this.menu.isVisible()){
12158 this.menu.show(this.el, this.menuAlign);
12160 this.fireEvent("click", this, e);
12162 this.el.removeClass("x-btn-over");
12163 this.handler.call(this.scope || this, this, e);
12168 onMouseOver : function(e){
12169 if(!this.disabled){
12170 this.el.addClass("x-btn-over");
12171 this.fireEvent('mouseover', this, e);
12175 onMouseOut : function(e){
12176 if(!e.within(this.el, true)){
12177 this.el.removeClass("x-btn-over");
12178 this.fireEvent('mouseout', this, e);
12182 onFocus : function(e){
12183 if(!this.disabled){
12184 this.el.addClass("x-btn-focus");
12188 onBlur : function(e){
12189 this.el.removeClass("x-btn-focus");
12192 onMouseDown : function(e){
12193 if(!this.disabled && e.button == 0){
12194 this.el.addClass("x-btn-click");
12195 Roo.get(document).on('mouseup', this.onMouseUp, this);
12199 onMouseUp : function(e){
12201 this.el.removeClass("x-btn-click");
12202 Roo.get(document).un('mouseup', this.onMouseUp, this);
12206 onMenuShow : function(e){
12207 this.el.addClass("x-btn-menu-active");
12210 onMenuHide : function(e){
12211 this.el.removeClass("x-btn-menu-active");
12215 // Private utility class used by Button
12216 Roo.ButtonToggleMgr = function(){
12219 function toggleGroup(btn, state){
12221 var g = groups[btn.toggleGroup];
12222 for(var i = 0, l = g.length; i < l; i++){
12224 g[i].toggle(false);
12231 register : function(btn){
12232 if(!btn.toggleGroup){
12235 var g = groups[btn.toggleGroup];
12237 g = groups[btn.toggleGroup] = [];
12240 btn.on("toggle", toggleGroup);
12243 unregister : function(btn){
12244 if(!btn.toggleGroup){
12247 var g = groups[btn.toggleGroup];
12250 btn.un("toggle", toggleGroup);
12256 * Ext JS Library 1.1.1
12257 * Copyright(c) 2006-2007, Ext JS, LLC.
12259 * Originally Released Under LGPL - original licence link has changed is not relivant.
12262 * <script type="text/javascript">
12266 * @class Roo.SplitButton
12267 * @extends Roo.Button
12268 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12269 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
12270 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12271 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12272 * @cfg {String} arrowTooltip The title attribute of the arrow
12274 * Create a new menu button
12275 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12276 * @param {Object} config The config object
12278 Roo.SplitButton = function(renderTo, config){
12279 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12281 * @event arrowclick
12282 * Fires when this button's arrow is clicked
12283 * @param {SplitButton} this
12284 * @param {EventObject} e The click event
12286 this.addEvents({"arrowclick":true});
12289 Roo.extend(Roo.SplitButton, Roo.Button, {
12290 render : function(renderTo){
12291 // this is one sweet looking template!
12292 var tpl = new Roo.Template(
12293 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12294 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12295 '<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>',
12296 "</tbody></table></td><td>",
12297 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12298 '<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>',
12299 "</tbody></table></td></tr></table>"
12301 var btn = tpl.append(renderTo, [this.text, this.type], true);
12302 var btnEl = btn.child("button");
12304 btn.addClass(this.cls);
12307 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12310 btnEl.addClass(this.iconCls);
12312 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12316 if(this.handleMouseEvents){
12317 btn.on("mouseover", this.onMouseOver, this);
12318 btn.on("mouseout", this.onMouseOut, this);
12319 btn.on("mousedown", this.onMouseDown, this);
12320 btn.on("mouseup", this.onMouseUp, this);
12322 btn.on(this.clickEvent, this.onClick, this);
12324 if(typeof this.tooltip == 'object'){
12325 Roo.QuickTips.tips(Roo.apply({
12329 btnEl.dom[this.tooltipType] = this.tooltip;
12332 if(this.arrowTooltip){
12333 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12342 this.el.addClass("x-btn-pressed");
12344 if(Roo.isIE && !Roo.isIE7){
12345 this.autoWidth.defer(1, this);
12350 this.menu.on("show", this.onMenuShow, this);
12351 this.menu.on("hide", this.onMenuHide, this);
12353 this.fireEvent('render', this);
12357 autoWidth : function(){
12359 var tbl = this.el.child("table:first");
12360 var tbl2 = this.el.child("table:last");
12361 this.el.setWidth("auto");
12362 tbl.setWidth("auto");
12363 if(Roo.isIE7 && Roo.isStrict){
12364 var ib = this.el.child('button:first');
12365 if(ib && ib.getWidth() > 20){
12367 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12372 this.el.beginMeasure();
12374 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12375 tbl.setWidth(this.minWidth-tbl2.getWidth());
12378 this.el.endMeasure();
12381 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12385 * Sets this button's click handler
12386 * @param {Function} handler The function to call when the button is clicked
12387 * @param {Object} scope (optional) Scope for the function passed above
12389 setHandler : function(handler, scope){
12390 this.handler = handler;
12391 this.scope = scope;
12395 * Sets this button's arrow click handler
12396 * @param {Function} handler The function to call when the arrow is clicked
12397 * @param {Object} scope (optional) Scope for the function passed above
12399 setArrowHandler : function(handler, scope){
12400 this.arrowHandler = handler;
12401 this.scope = scope;
12407 focus : function(){
12409 this.el.child("button:first").focus();
12414 onClick : function(e){
12415 e.preventDefault();
12416 if(!this.disabled){
12417 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12418 if(this.menu && !this.menu.isVisible()){
12419 this.menu.show(this.el, this.menuAlign);
12421 this.fireEvent("arrowclick", this, e);
12422 if(this.arrowHandler){
12423 this.arrowHandler.call(this.scope || this, this, e);
12426 this.fireEvent("click", this, e);
12428 this.handler.call(this.scope || this, this, e);
12434 onMouseDown : function(e){
12435 if(!this.disabled){
12436 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12440 onMouseUp : function(e){
12441 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12446 // backwards compat
12447 Roo.MenuButton = Roo.SplitButton;/*
12449 * Ext JS Library 1.1.1
12450 * Copyright(c) 2006-2007, Ext JS, LLC.
12452 * Originally Released Under LGPL - original licence link has changed is not relivant.
12455 * <script type="text/javascript">
12459 * @class Roo.Toolbar
12460 * Basic Toolbar class.
12462 * Creates a new Toolbar
12463 * @param {Object} container The config object
12465 Roo.Toolbar = function(container, buttons, config)
12467 /// old consturctor format still supported..
12468 if(container instanceof Array){ // omit the container for later rendering
12469 buttons = container;
12473 if (typeof(container) == 'object' && container.xtype) {
12474 config = container;
12475 container = config.container;
12476 buttons = config.buttons || []; // not really - use items!!
12479 if (config && config.items) {
12480 xitems = config.items;
12481 delete config.items;
12483 Roo.apply(this, config);
12484 this.buttons = buttons;
12487 this.render(container);
12489 this.xitems = xitems;
12490 Roo.each(xitems, function(b) {
12496 Roo.Toolbar.prototype = {
12498 * @cfg {Array} items
12499 * array of button configs or elements to add (will be converted to a MixedCollection)
12503 * @cfg {String/HTMLElement/Element} container
12504 * The id or element that will contain the toolbar
12507 render : function(ct){
12508 this.el = Roo.get(ct);
12510 this.el.addClass(this.cls);
12512 // using a table allows for vertical alignment
12513 // 100% width is needed by Safari...
12514 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12515 this.tr = this.el.child("tr", true);
12517 this.items = new Roo.util.MixedCollection(false, function(o){
12518 return o.id || ("item" + (++autoId));
12521 this.add.apply(this, this.buttons);
12522 delete this.buttons;
12527 * Adds element(s) to the toolbar -- this function takes a variable number of
12528 * arguments of mixed type and adds them to the toolbar.
12529 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12531 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12532 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12533 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12534 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12535 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12536 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12537 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12538 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12539 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12541 * @param {Mixed} arg2
12542 * @param {Mixed} etc.
12545 var a = arguments, l = a.length;
12546 for(var i = 0; i < l; i++){
12551 _add : function(el) {
12554 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12557 if (el.applyTo){ // some kind of form field
12558 return this.addField(el);
12560 if (el.render){ // some kind of Toolbar.Item
12561 return this.addItem(el);
12563 if (typeof el == "string"){ // string
12564 if(el == "separator" || el == "-"){
12565 return this.addSeparator();
12568 return this.addSpacer();
12571 return this.addFill();
12573 return this.addText(el);
12576 if(el.tagName){ // element
12577 return this.addElement(el);
12579 if(typeof el == "object"){ // must be button config?
12580 return this.addButton(el);
12582 // and now what?!?!
12588 * Add an Xtype element
12589 * @param {Object} xtype Xtype Object
12590 * @return {Object} created Object
12592 addxtype : function(e){
12593 return this.add(e);
12597 * Returns the Element for this toolbar.
12598 * @return {Roo.Element}
12600 getEl : function(){
12606 * @return {Roo.Toolbar.Item} The separator item
12608 addSeparator : function(){
12609 return this.addItem(new Roo.Toolbar.Separator());
12613 * Adds a spacer element
12614 * @return {Roo.Toolbar.Spacer} The spacer item
12616 addSpacer : function(){
12617 return this.addItem(new Roo.Toolbar.Spacer());
12621 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12622 * @return {Roo.Toolbar.Fill} The fill item
12624 addFill : function(){
12625 return this.addItem(new Roo.Toolbar.Fill());
12629 * Adds any standard HTML element to the toolbar
12630 * @param {String/HTMLElement/Element} el The element or id of the element to add
12631 * @return {Roo.Toolbar.Item} The element's item
12633 addElement : function(el){
12634 return this.addItem(new Roo.Toolbar.Item(el));
12637 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12638 * @type Roo.util.MixedCollection
12643 * Adds any Toolbar.Item or subclass
12644 * @param {Roo.Toolbar.Item} item
12645 * @return {Roo.Toolbar.Item} The item
12647 addItem : function(item){
12648 var td = this.nextBlock();
12650 this.items.add(item);
12655 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12656 * @param {Object/Array} config A button config or array of configs
12657 * @return {Roo.Toolbar.Button/Array}
12659 addButton : function(config){
12660 if(config instanceof Array){
12662 for(var i = 0, len = config.length; i < len; i++) {
12663 buttons.push(this.addButton(config[i]));
12668 if(!(config instanceof Roo.Toolbar.Button)){
12670 new Roo.Toolbar.SplitButton(config) :
12671 new Roo.Toolbar.Button(config);
12673 var td = this.nextBlock();
12680 * Adds text to the toolbar
12681 * @param {String} text The text to add
12682 * @return {Roo.Toolbar.Item} The element's item
12684 addText : function(text){
12685 return this.addItem(new Roo.Toolbar.TextItem(text));
12689 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12690 * @param {Number} index The index where the item is to be inserted
12691 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12692 * @return {Roo.Toolbar.Button/Item}
12694 insertButton : function(index, item){
12695 if(item instanceof Array){
12697 for(var i = 0, len = item.length; i < len; i++) {
12698 buttons.push(this.insertButton(index + i, item[i]));
12702 if (!(item instanceof Roo.Toolbar.Button)){
12703 item = new Roo.Toolbar.Button(item);
12705 var td = document.createElement("td");
12706 this.tr.insertBefore(td, this.tr.childNodes[index]);
12708 this.items.insert(index, item);
12713 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12714 * @param {Object} config
12715 * @return {Roo.Toolbar.Item} The element's item
12717 addDom : function(config, returnEl){
12718 var td = this.nextBlock();
12719 Roo.DomHelper.overwrite(td, config);
12720 var ti = new Roo.Toolbar.Item(td.firstChild);
12722 this.items.add(ti);
12727 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12728 * @type Roo.util.MixedCollection
12733 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc).
12734 * Note: the field should not have been rendered yet. For a field that has already been
12735 * rendered, use {@link #addElement}.
12736 * @param {Roo.form.Field} field
12737 * @return {Roo.ToolbarItem}
12741 addField : function(field) {
12742 if (!this.fields) {
12744 this.fields = new Roo.util.MixedCollection(false, function(o){
12745 return o.id || ("item" + (++autoId));
12750 var td = this.nextBlock();
12752 var ti = new Roo.Toolbar.Item(td.firstChild);
12754 this.items.add(ti);
12755 this.fields.add(field);
12766 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12767 this.el.child('div').hide();
12775 this.el.child('div').show();
12779 nextBlock : function(){
12780 var td = document.createElement("td");
12781 this.tr.appendChild(td);
12786 destroy : function(){
12787 if(this.items){ // rendered?
12788 Roo.destroy.apply(Roo, this.items.items);
12790 if(this.fields){ // rendered?
12791 Roo.destroy.apply(Roo, this.fields.items);
12793 Roo.Element.uncache(this.el, this.tr);
12798 * @class Roo.Toolbar.Item
12799 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12801 * Creates a new Item
12802 * @param {HTMLElement} el
12804 Roo.Toolbar.Item = function(el){
12805 this.el = Roo.getDom(el);
12806 this.id = Roo.id(this.el);
12807 this.hidden = false;
12810 Roo.Toolbar.Item.prototype = {
12813 * Get this item's HTML Element
12814 * @return {HTMLElement}
12816 getEl : function(){
12821 render : function(td){
12823 td.appendChild(this.el);
12827 * Removes and destroys this item.
12829 destroy : function(){
12830 this.td.parentNode.removeChild(this.td);
12837 this.hidden = false;
12838 this.td.style.display = "";
12845 this.hidden = true;
12846 this.td.style.display = "none";
12850 * Convenience function for boolean show/hide.
12851 * @param {Boolean} visible true to show/false to hide
12853 setVisible: function(visible){
12862 * Try to focus this item.
12864 focus : function(){
12865 Roo.fly(this.el).focus();
12869 * Disables this item.
12871 disable : function(){
12872 Roo.fly(this.td).addClass("x-item-disabled");
12873 this.disabled = true;
12874 this.el.disabled = true;
12878 * Enables this item.
12880 enable : function(){
12881 Roo.fly(this.td).removeClass("x-item-disabled");
12882 this.disabled = false;
12883 this.el.disabled = false;
12889 * @class Roo.Toolbar.Separator
12890 * @extends Roo.Toolbar.Item
12891 * A simple toolbar separator class
12893 * Creates a new Separator
12895 Roo.Toolbar.Separator = function(){
12896 var s = document.createElement("span");
12897 s.className = "ytb-sep";
12898 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12900 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12901 enable:Roo.emptyFn,
12902 disable:Roo.emptyFn,
12907 * @class Roo.Toolbar.Spacer
12908 * @extends Roo.Toolbar.Item
12909 * A simple element that adds extra horizontal space to a toolbar.
12911 * Creates a new Spacer
12913 Roo.Toolbar.Spacer = function(){
12914 var s = document.createElement("div");
12915 s.className = "ytb-spacer";
12916 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12918 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12919 enable:Roo.emptyFn,
12920 disable:Roo.emptyFn,
12925 * @class Roo.Toolbar.Fill
12926 * @extends Roo.Toolbar.Spacer
12927 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12929 * Creates a new Spacer
12931 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12933 render : function(td){
12934 td.style.width = '100%';
12935 Roo.Toolbar.Fill.superclass.render.call(this, td);
12940 * @class Roo.Toolbar.TextItem
12941 * @extends Roo.Toolbar.Item
12942 * A simple class that renders text directly into a toolbar.
12944 * Creates a new TextItem
12945 * @param {String} text
12947 Roo.Toolbar.TextItem = function(text){
12948 if (typeof(text) == 'object') {
12951 var s = document.createElement("span");
12952 s.className = "ytb-text";
12953 s.innerHTML = text;
12954 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12956 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12957 enable:Roo.emptyFn,
12958 disable:Roo.emptyFn,
12963 * @class Roo.Toolbar.Button
12964 * @extends Roo.Button
12965 * A button that renders into a toolbar.
12967 * Creates a new Button
12968 * @param {Object} config A standard {@link Roo.Button} config object
12970 Roo.Toolbar.Button = function(config){
12971 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12973 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12974 render : function(td){
12976 Roo.Toolbar.Button.superclass.render.call(this, td);
12980 * Removes and destroys this button
12982 destroy : function(){
12983 Roo.Toolbar.Button.superclass.destroy.call(this);
12984 this.td.parentNode.removeChild(this.td);
12988 * Shows this button
12991 this.hidden = false;
12992 this.td.style.display = "";
12996 * Hides this button
12999 this.hidden = true;
13000 this.td.style.display = "none";
13004 * Disables this item
13006 disable : function(){
13007 Roo.fly(this.td).addClass("x-item-disabled");
13008 this.disabled = true;
13012 * Enables this item
13014 enable : function(){
13015 Roo.fly(this.td).removeClass("x-item-disabled");
13016 this.disabled = false;
13019 // backwards compat
13020 Roo.ToolbarButton = Roo.Toolbar.Button;
13023 * @class Roo.Toolbar.SplitButton
13024 * @extends Roo.SplitButton
13025 * A menu button that renders into a toolbar.
13027 * Creates a new SplitButton
13028 * @param {Object} config A standard {@link Roo.SplitButton} config object
13030 Roo.Toolbar.SplitButton = function(config){
13031 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
13033 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
13034 render : function(td){
13036 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
13040 * Removes and destroys this button
13042 destroy : function(){
13043 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
13044 this.td.parentNode.removeChild(this.td);
13048 * Shows this button
13051 this.hidden = false;
13052 this.td.style.display = "";
13056 * Hides this button
13059 this.hidden = true;
13060 this.td.style.display = "none";
13064 // backwards compat
13065 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
13067 * Ext JS Library 1.1.1
13068 * Copyright(c) 2006-2007, Ext JS, LLC.
13070 * Originally Released Under LGPL - original licence link has changed is not relivant.
13073 * <script type="text/javascript">
13077 * @class Roo.PagingToolbar
13078 * @extends Roo.Toolbar
13079 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
13081 * Create a new PagingToolbar
13082 * @param {Object} config The config object
13084 Roo.PagingToolbar = function(el, ds, config)
13086 // old args format still supported... - xtype is prefered..
13087 if (typeof(el) == 'object' && el.xtype) {
13088 // created from xtype...
13090 ds = el.dataSource;
13091 el = config.container;
13094 if (config.items) {
13095 items = config.items;
13099 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
13102 this.renderButtons(this.el);
13105 // supprot items array.
13107 Roo.each(items, function(e) {
13108 this.add(Roo.factory(e));
13113 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
13115 * @cfg {Roo.data.Store} dataSource
13116 * The underlying data store providing the paged data
13119 * @cfg {String/HTMLElement/Element} container
13120 * container The id or element that will contain the toolbar
13123 * @cfg {Boolean} displayInfo
13124 * True to display the displayMsg (defaults to false)
13127 * @cfg {Number} pageSize
13128 * The number of records to display per page (defaults to 20)
13132 * @cfg {String} displayMsg
13133 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
13135 displayMsg : 'Displaying {0} - {1} of {2}',
13137 * @cfg {String} emptyMsg
13138 * The message to display when no records are found (defaults to "No data to display")
13140 emptyMsg : 'No data to display',
13142 * Customizable piece of the default paging text (defaults to "Page")
13145 beforePageText : "Page",
13147 * Customizable piece of the default paging text (defaults to "of %0")
13150 afterPageText : "of {0}",
13152 * Customizable piece of the default paging text (defaults to "First Page")
13155 firstText : "First Page",
13157 * Customizable piece of the default paging text (defaults to "Previous Page")
13160 prevText : "Previous Page",
13162 * Customizable piece of the default paging text (defaults to "Next Page")
13165 nextText : "Next Page",
13167 * Customizable piece of the default paging text (defaults to "Last Page")
13170 lastText : "Last Page",
13172 * Customizable piece of the default paging text (defaults to "Refresh")
13175 refreshText : "Refresh",
13178 renderButtons : function(el){
13179 Roo.PagingToolbar.superclass.render.call(this, el);
13180 this.first = this.addButton({
13181 tooltip: this.firstText,
13182 cls: "x-btn-icon x-grid-page-first",
13184 handler: this.onClick.createDelegate(this, ["first"])
13186 this.prev = this.addButton({
13187 tooltip: this.prevText,
13188 cls: "x-btn-icon x-grid-page-prev",
13190 handler: this.onClick.createDelegate(this, ["prev"])
13192 //this.addSeparator();
13193 this.add(this.beforePageText);
13194 this.field = Roo.get(this.addDom({
13199 cls: "x-grid-page-number"
13201 this.field.on("keydown", this.onPagingKeydown, this);
13202 this.field.on("focus", function(){this.dom.select();});
13203 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
13204 this.field.setHeight(18);
13205 //this.addSeparator();
13206 this.next = this.addButton({
13207 tooltip: this.nextText,
13208 cls: "x-btn-icon x-grid-page-next",
13210 handler: this.onClick.createDelegate(this, ["next"])
13212 this.last = this.addButton({
13213 tooltip: this.lastText,
13214 cls: "x-btn-icon x-grid-page-last",
13216 handler: this.onClick.createDelegate(this, ["last"])
13218 //this.addSeparator();
13219 this.loading = this.addButton({
13220 tooltip: this.refreshText,
13221 cls: "x-btn-icon x-grid-loading",
13222 handler: this.onClick.createDelegate(this, ["refresh"])
13225 if(this.displayInfo){
13226 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
13231 updateInfo : function(){
13232 if(this.displayEl){
13233 var count = this.ds.getCount();
13234 var msg = count == 0 ?
13238 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
13240 this.displayEl.update(msg);
13245 onLoad : function(ds, r, o){
13246 this.cursor = o.params ? o.params.start : 0;
13247 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
13249 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
13250 this.field.dom.value = ap;
13251 this.first.setDisabled(ap == 1);
13252 this.prev.setDisabled(ap == 1);
13253 this.next.setDisabled(ap == ps);
13254 this.last.setDisabled(ap == ps);
13255 this.loading.enable();
13260 getPageData : function(){
13261 var total = this.ds.getTotalCount();
13264 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
13265 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13270 onLoadError : function(){
13271 this.loading.enable();
13275 onPagingKeydown : function(e){
13276 var k = e.getKey();
13277 var d = this.getPageData();
13279 var v = this.field.dom.value, pageNum;
13280 if(!v || isNaN(pageNum = parseInt(v, 10))){
13281 this.field.dom.value = d.activePage;
13284 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13285 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13288 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))
13290 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13291 this.field.dom.value = pageNum;
13292 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13295 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13297 var v = this.field.dom.value, pageNum;
13298 var increment = (e.shiftKey) ? 10 : 1;
13299 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13301 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13302 this.field.dom.value = d.activePage;
13305 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13307 this.field.dom.value = parseInt(v, 10) + increment;
13308 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13309 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13316 beforeLoad : function(){
13318 this.loading.disable();
13323 onClick : function(which){
13327 ds.load({params:{start: 0, limit: this.pageSize}});
13330 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13333 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13336 var total = ds.getTotalCount();
13337 var extra = total % this.pageSize;
13338 var lastStart = extra ? (total - extra) : total-this.pageSize;
13339 ds.load({params:{start: lastStart, limit: this.pageSize}});
13342 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13348 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13349 * @param {Roo.data.Store} store The data store to unbind
13351 unbind : function(ds){
13352 ds.un("beforeload", this.beforeLoad, this);
13353 ds.un("load", this.onLoad, this);
13354 ds.un("loadexception", this.onLoadError, this);
13355 ds.un("remove", this.updateInfo, this);
13356 ds.un("add", this.updateInfo, this);
13357 this.ds = undefined;
13361 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13362 * @param {Roo.data.Store} store The data store to bind
13364 bind : function(ds){
13365 ds.on("beforeload", this.beforeLoad, this);
13366 ds.on("load", this.onLoad, this);
13367 ds.on("loadexception", this.onLoadError, this);
13368 ds.on("remove", this.updateInfo, this);
13369 ds.on("add", this.updateInfo, this);
13374 * Ext JS Library 1.1.1
13375 * Copyright(c) 2006-2007, Ext JS, LLC.
13377 * Originally Released Under LGPL - original licence link has changed is not relivant.
13380 * <script type="text/javascript">
13384 * @class Roo.Resizable
13385 * @extends Roo.util.Observable
13386 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13387 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13388 * 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
13389 * the element will be wrapped for you automatically.</p>
13390 * <p>Here is the list of valid resize handles:</p>
13393 ------ -------------------
13402 'hd' horizontal drag
13405 * <p>Here's an example showing the creation of a typical Resizable:</p>
13407 var resizer = new Roo.Resizable("element-id", {
13415 resizer.on("resize", myHandler);
13417 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13418 * resizer.east.setDisplayed(false);</p>
13419 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13420 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13421 * resize operation's new size (defaults to [0, 0])
13422 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13423 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13424 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13425 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13426 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13427 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13428 * @cfg {Number} width The width of the element in pixels (defaults to null)
13429 * @cfg {Number} height The height of the element in pixels (defaults to null)
13430 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13431 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13432 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13433 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13434 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13435 * in favor of the handles config option (defaults to false)
13436 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13437 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13438 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13439 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13440 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13441 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13442 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13443 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13444 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13445 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13446 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13448 * Create a new resizable component
13449 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13450 * @param {Object} config configuration options
13452 Roo.Resizable = function(el, config)
13454 this.el = Roo.get(el);
13456 if(config && config.wrap){
13457 config.resizeChild = this.el;
13458 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13459 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13460 this.el.setStyle("overflow", "hidden");
13461 this.el.setPositioning(config.resizeChild.getPositioning());
13462 config.resizeChild.clearPositioning();
13463 if(!config.width || !config.height){
13464 var csize = config.resizeChild.getSize();
13465 this.el.setSize(csize.width, csize.height);
13467 if(config.pinned && !config.adjustments){
13468 config.adjustments = "auto";
13472 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13473 this.proxy.unselectable();
13474 this.proxy.enableDisplayMode('block');
13476 Roo.apply(this, config);
13479 this.disableTrackOver = true;
13480 this.el.addClass("x-resizable-pinned");
13482 // if the element isn't positioned, make it relative
13483 var position = this.el.getStyle("position");
13484 if(position != "absolute" && position != "fixed"){
13485 this.el.setStyle("position", "relative");
13487 if(!this.handles){ // no handles passed, must be legacy style
13488 this.handles = 's,e,se';
13489 if(this.multiDirectional){
13490 this.handles += ',n,w';
13493 if(this.handles == "all"){
13494 this.handles = "n s e w ne nw se sw";
13496 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13497 var ps = Roo.Resizable.positions;
13498 for(var i = 0, len = hs.length; i < len; i++){
13499 if(hs[i] && ps[hs[i]]){
13500 var pos = ps[hs[i]];
13501 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13505 this.corner = this.southeast;
13507 // updateBox = the box can move..
13508 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13509 this.updateBox = true;
13512 this.activeHandle = null;
13514 if(this.resizeChild){
13515 if(typeof this.resizeChild == "boolean"){
13516 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13518 this.resizeChild = Roo.get(this.resizeChild, true);
13522 if(this.adjustments == "auto"){
13523 var rc = this.resizeChild;
13524 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13525 if(rc && (hw || hn)){
13526 rc.position("relative");
13527 rc.setLeft(hw ? hw.el.getWidth() : 0);
13528 rc.setTop(hn ? hn.el.getHeight() : 0);
13530 this.adjustments = [
13531 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13532 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13536 if(this.draggable){
13537 this.dd = this.dynamic ?
13538 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13539 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13545 * @event beforeresize
13546 * Fired before resize is allowed. Set enabled to false to cancel resize.
13547 * @param {Roo.Resizable} this
13548 * @param {Roo.EventObject} e The mousedown event
13550 "beforeresize" : true,
13553 * Fired a resizing.
13554 * @param {Roo.Resizable} this
13555 * @param {Number} x The new x position
13556 * @param {Number} y The new y position
13557 * @param {Number} w The new w width
13558 * @param {Number} h The new h hight
13559 * @param {Roo.EventObject} e The mouseup event
13564 * Fired after a resize.
13565 * @param {Roo.Resizable} this
13566 * @param {Number} width The new width
13567 * @param {Number} height The new height
13568 * @param {Roo.EventObject} e The mouseup event
13573 if(this.width !== null && this.height !== null){
13574 this.resizeTo(this.width, this.height);
13576 this.updateChildSize();
13579 this.el.dom.style.zoom = 1;
13581 Roo.Resizable.superclass.constructor.call(this);
13584 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13585 resizeChild : false,
13586 adjustments : [0, 0],
13596 multiDirectional : false,
13597 disableTrackOver : false,
13598 easing : 'easeOutStrong',
13599 widthIncrement : 0,
13600 heightIncrement : 0,
13604 preserveRatio : false,
13605 transparent: false,
13611 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13613 constrainTo: undefined,
13615 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13617 resizeRegion: undefined,
13621 * Perform a manual resize
13622 * @param {Number} width
13623 * @param {Number} height
13625 resizeTo : function(width, height){
13626 this.el.setSize(width, height);
13627 this.updateChildSize();
13628 this.fireEvent("resize", this, width, height, null);
13632 startSizing : function(e, handle){
13633 this.fireEvent("beforeresize", this, e);
13634 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13637 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13638 this.overlay.unselectable();
13639 this.overlay.enableDisplayMode("block");
13640 this.overlay.on("mousemove", this.onMouseMove, this);
13641 this.overlay.on("mouseup", this.onMouseUp, this);
13643 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13645 this.resizing = true;
13646 this.startBox = this.el.getBox();
13647 this.startPoint = e.getXY();
13648 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13649 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13651 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13652 this.overlay.show();
13654 if(this.constrainTo) {
13655 var ct = Roo.get(this.constrainTo);
13656 this.resizeRegion = ct.getRegion().adjust(
13657 ct.getFrameWidth('t'),
13658 ct.getFrameWidth('l'),
13659 -ct.getFrameWidth('b'),
13660 -ct.getFrameWidth('r')
13664 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13666 this.proxy.setBox(this.startBox);
13668 this.proxy.setStyle('visibility', 'visible');
13674 onMouseDown : function(handle, e){
13677 this.activeHandle = handle;
13678 this.startSizing(e, handle);
13683 onMouseUp : function(e){
13684 var size = this.resizeElement();
13685 this.resizing = false;
13687 this.overlay.hide();
13689 this.fireEvent("resize", this, size.width, size.height, e);
13693 updateChildSize : function(){
13695 if(this.resizeChild){
13697 var child = this.resizeChild;
13698 var adj = this.adjustments;
13699 if(el.dom.offsetWidth){
13700 var b = el.getSize(true);
13701 child.setSize(b.width+adj[0], b.height+adj[1]);
13703 // Second call here for IE
13704 // The first call enables instant resizing and
13705 // the second call corrects scroll bars if they
13708 setTimeout(function(){
13709 if(el.dom.offsetWidth){
13710 var b = el.getSize(true);
13711 child.setSize(b.width+adj[0], b.height+adj[1]);
13719 snap : function(value, inc, min){
13720 if(!inc || !value) return value;
13721 var newValue = value;
13722 var m = value % inc;
13725 newValue = value + (inc-m);
13727 newValue = value - m;
13730 return Math.max(min, newValue);
13734 resizeElement : function(){
13735 var box = this.proxy.getBox();
13736 if(this.updateBox){
13737 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13739 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13741 this.updateChildSize();
13749 constrain : function(v, diff, m, mx){
13752 }else if(v - diff > mx){
13759 onMouseMove : function(e){
13762 try{// try catch so if something goes wrong the user doesn't get hung
13764 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13768 //var curXY = this.startPoint;
13769 var curSize = this.curSize || this.startBox;
13770 var x = this.startBox.x, y = this.startBox.y;
13771 var ox = x, oy = y;
13772 var w = curSize.width, h = curSize.height;
13773 var ow = w, oh = h;
13774 var mw = this.minWidth, mh = this.minHeight;
13775 var mxw = this.maxWidth, mxh = this.maxHeight;
13776 var wi = this.widthIncrement;
13777 var hi = this.heightIncrement;
13779 var eventXY = e.getXY();
13780 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13781 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13783 var pos = this.activeHandle.position;
13788 w = Math.min(Math.max(mw, w), mxw);
13793 h = Math.min(Math.max(mh, h), mxh);
13798 w = Math.min(Math.max(mw, w), mxw);
13799 h = Math.min(Math.max(mh, h), mxh);
13802 diffY = this.constrain(h, diffY, mh, mxh);
13809 var adiffX = Math.abs(diffX);
13810 var sub = (adiffX % wi); // how much
13811 if (sub > (wi/2)) { // far enough to snap
13812 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13814 // remove difference..
13815 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13819 x = Math.max(this.minX, x);
13822 diffX = this.constrain(w, diffX, mw, mxw);
13828 w = Math.min(Math.max(mw, w), mxw);
13829 diffY = this.constrain(h, diffY, mh, mxh);
13834 diffX = this.constrain(w, diffX, mw, mxw);
13835 diffY = this.constrain(h, diffY, mh, mxh);
13842 diffX = this.constrain(w, diffX, mw, mxw);
13844 h = Math.min(Math.max(mh, h), mxh);
13850 var sw = this.snap(w, wi, mw);
13851 var sh = this.snap(h, hi, mh);
13852 if(sw != w || sh != h){
13875 if(this.preserveRatio){
13880 h = Math.min(Math.max(mh, h), mxh);
13885 w = Math.min(Math.max(mw, w), mxw);
13890 w = Math.min(Math.max(mw, w), mxw);
13896 w = Math.min(Math.max(mw, w), mxw);
13902 h = Math.min(Math.max(mh, h), mxh);
13910 h = Math.min(Math.max(mh, h), mxh);
13920 h = Math.min(Math.max(mh, h), mxh);
13928 if (pos == 'hdrag') {
13931 this.proxy.setBounds(x, y, w, h);
13933 this.resizeElement();
13937 this.fireEvent("resizing", this, x, y, w, h, e);
13941 handleOver : function(){
13943 this.el.addClass("x-resizable-over");
13948 handleOut : function(){
13949 if(!this.resizing){
13950 this.el.removeClass("x-resizable-over");
13955 * Returns the element this component is bound to.
13956 * @return {Roo.Element}
13958 getEl : function(){
13963 * Returns the resizeChild element (or null).
13964 * @return {Roo.Element}
13966 getResizeChild : function(){
13967 return this.resizeChild;
13969 groupHandler : function()
13974 * Destroys this resizable. If the element was wrapped and
13975 * removeEl is not true then the element remains.
13976 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13978 destroy : function(removeEl){
13979 this.proxy.remove();
13981 this.overlay.removeAllListeners();
13982 this.overlay.remove();
13984 var ps = Roo.Resizable.positions;
13986 if(typeof ps[k] != "function" && this[ps[k]]){
13987 var h = this[ps[k]];
13988 h.el.removeAllListeners();
13993 this.el.update("");
14000 // hash to map config positions to true positions
14001 Roo.Resizable.positions = {
14002 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
14007 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
14009 // only initialize the template if resizable is used
14010 var tpl = Roo.DomHelper.createTemplate(
14011 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
14014 Roo.Resizable.Handle.prototype.tpl = tpl;
14016 this.position = pos;
14018 // show north drag fro topdra
14019 var handlepos = pos == 'hdrag' ? 'north' : pos;
14021 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
14022 if (pos == 'hdrag') {
14023 this.el.setStyle('cursor', 'pointer');
14025 this.el.unselectable();
14027 this.el.setOpacity(0);
14029 this.el.on("mousedown", this.onMouseDown, this);
14030 if(!disableTrackOver){
14031 this.el.on("mouseover", this.onMouseOver, this);
14032 this.el.on("mouseout", this.onMouseOut, this);
14037 Roo.Resizable.Handle.prototype = {
14038 afterResize : function(rz){
14042 onMouseDown : function(e){
14043 this.rz.onMouseDown(this, e);
14046 onMouseOver : function(e){
14047 this.rz.handleOver(this, e);
14050 onMouseOut : function(e){
14051 this.rz.handleOut(this, e);
14055 * Ext JS Library 1.1.1
14056 * Copyright(c) 2006-2007, Ext JS, LLC.
14058 * Originally Released Under LGPL - original licence link has changed is not relivant.
14061 * <script type="text/javascript">
14065 * @class Roo.Editor
14066 * @extends Roo.Component
14067 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
14069 * Create a new Editor
14070 * @param {Roo.form.Field} field The Field object (or descendant)
14071 * @param {Object} config The config object
14073 Roo.Editor = function(field, config){
14074 Roo.Editor.superclass.constructor.call(this, config);
14075 this.field = field;
14078 * @event beforestartedit
14079 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
14080 * false from the handler of this event.
14081 * @param {Editor} this
14082 * @param {Roo.Element} boundEl The underlying element bound to this editor
14083 * @param {Mixed} value The field value being set
14085 "beforestartedit" : true,
14088 * Fires when this editor is displayed
14089 * @param {Roo.Element} boundEl The underlying element bound to this editor
14090 * @param {Mixed} value The starting field value
14092 "startedit" : true,
14094 * @event beforecomplete
14095 * Fires after a change has been made to the field, but before the change is reflected in the underlying
14096 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
14097 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
14098 * event will not fire since no edit actually occurred.
14099 * @param {Editor} this
14100 * @param {Mixed} value The current field value
14101 * @param {Mixed} startValue The original field value
14103 "beforecomplete" : true,
14106 * Fires after editing is complete and any changed value has been written to the underlying field.
14107 * @param {Editor} this
14108 * @param {Mixed} value The current field value
14109 * @param {Mixed} startValue The original field value
14113 * @event specialkey
14114 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
14115 * {@link Roo.EventObject#getKey} to determine which key was pressed.
14116 * @param {Roo.form.Field} this
14117 * @param {Roo.EventObject} e The event object
14119 "specialkey" : true
14123 Roo.extend(Roo.Editor, Roo.Component, {
14125 * @cfg {Boolean/String} autosize
14126 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
14127 * or "height" to adopt the height only (defaults to false)
14130 * @cfg {Boolean} revertInvalid
14131 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
14132 * validation fails (defaults to true)
14135 * @cfg {Boolean} ignoreNoChange
14136 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
14137 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
14138 * will never be ignored.
14141 * @cfg {Boolean} hideEl
14142 * False to keep the bound element visible while the editor is displayed (defaults to true)
14145 * @cfg {Mixed} value
14146 * The data value of the underlying field (defaults to "")
14150 * @cfg {String} alignment
14151 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
14155 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
14156 * for bottom-right shadow (defaults to "frame")
14160 * @cfg {Boolean} constrain True to constrain the editor to the viewport
14164 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
14166 completeOnEnter : false,
14168 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
14170 cancelOnEsc : false,
14172 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
14177 onRender : function(ct, position){
14178 this.el = new Roo.Layer({
14179 shadow: this.shadow,
14185 constrain: this.constrain
14187 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
14188 if(this.field.msgTarget != 'title'){
14189 this.field.msgTarget = 'qtip';
14191 this.field.render(this.el);
14193 this.field.el.dom.setAttribute('autocomplete', 'off');
14195 this.field.on("specialkey", this.onSpecialKey, this);
14196 if(this.swallowKeys){
14197 this.field.el.swallowEvent(['keydown','keypress']);
14200 this.field.on("blur", this.onBlur, this);
14201 if(this.field.grow){
14202 this.field.on("autosize", this.el.sync, this.el, {delay:1});
14206 onSpecialKey : function(field, e)
14208 //Roo.log('editor onSpecialKey');
14209 if(this.completeOnEnter && e.getKey() == e.ENTER){
14211 this.completeEdit();
14214 // do not fire special key otherwise it might hide close the editor...
14215 if(e.getKey() == e.ENTER){
14218 if(this.cancelOnEsc && e.getKey() == e.ESC){
14222 this.fireEvent('specialkey', field, e);
14227 * Starts the editing process and shows the editor.
14228 * @param {String/HTMLElement/Element} el The element to edit
14229 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
14230 * to the innerHTML of el.
14232 startEdit : function(el, value){
14234 this.completeEdit();
14236 this.boundEl = Roo.get(el);
14237 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
14238 if(!this.rendered){
14239 this.render(this.parentEl || document.body);
14241 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
14244 this.startValue = v;
14245 this.field.setValue(v);
14247 var sz = this.boundEl.getSize();
14248 switch(this.autoSize){
14250 this.setSize(sz.width, "");
14253 this.setSize("", sz.height);
14256 this.setSize(sz.width, sz.height);
14259 this.el.alignTo(this.boundEl, this.alignment);
14260 this.editing = true;
14262 Roo.QuickTips.disable();
14268 * Sets the height and width of this editor.
14269 * @param {Number} width The new width
14270 * @param {Number} height The new height
14272 setSize : function(w, h){
14273 this.field.setSize(w, h);
14280 * Realigns the editor to the bound field based on the current alignment config value.
14282 realign : function(){
14283 this.el.alignTo(this.boundEl, this.alignment);
14287 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
14288 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
14290 completeEdit : function(remainVisible){
14294 var v = this.getValue();
14295 if(this.revertInvalid !== false && !this.field.isValid()){
14296 v = this.startValue;
14297 this.cancelEdit(true);
14299 if(String(v) === String(this.startValue) && this.ignoreNoChange){
14300 this.editing = false;
14304 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
14305 this.editing = false;
14306 if(this.updateEl && this.boundEl){
14307 this.boundEl.update(v);
14309 if(remainVisible !== true){
14312 this.fireEvent("complete", this, v, this.startValue);
14317 onShow : function(){
14319 if(this.hideEl !== false){
14320 this.boundEl.hide();
14323 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14324 this.fixIEFocus = true;
14325 this.deferredFocus.defer(50, this);
14327 this.field.focus();
14329 this.fireEvent("startedit", this.boundEl, this.startValue);
14332 deferredFocus : function(){
14334 this.field.focus();
14339 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14340 * reverted to the original starting value.
14341 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14342 * cancel (defaults to false)
14344 cancelEdit : function(remainVisible){
14346 this.setValue(this.startValue);
14347 if(remainVisible !== true){
14354 onBlur : function(){
14355 if(this.allowBlur !== true && this.editing){
14356 this.completeEdit();
14361 onHide : function(){
14363 this.completeEdit();
14367 if(this.field.collapse){
14368 this.field.collapse();
14371 if(this.hideEl !== false){
14372 this.boundEl.show();
14375 Roo.QuickTips.enable();
14380 * Sets the data value of the editor
14381 * @param {Mixed} value Any valid value supported by the underlying field
14383 setValue : function(v){
14384 this.field.setValue(v);
14388 * Gets the data value of the editor
14389 * @return {Mixed} The data value
14391 getValue : function(){
14392 return this.field.getValue();
14396 * Ext JS Library 1.1.1
14397 * Copyright(c) 2006-2007, Ext JS, LLC.
14399 * Originally Released Under LGPL - original licence link has changed is not relivant.
14402 * <script type="text/javascript">
14406 * @class Roo.BasicDialog
14407 * @extends Roo.util.Observable
14408 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14410 var dlg = new Roo.BasicDialog("my-dlg", {
14419 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14420 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14421 dlg.addButton('Cancel', dlg.hide, dlg);
14424 <b>A Dialog should always be a direct child of the body element.</b>
14425 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14426 * @cfg {String} title Default text to display in the title bar (defaults to null)
14427 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14428 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14429 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14430 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14431 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14432 * (defaults to null with no animation)
14433 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14434 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14435 * property for valid values (defaults to 'all')
14436 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14437 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14438 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14439 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14440 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14441 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14442 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14443 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14444 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14445 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14446 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14447 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14448 * draggable = true (defaults to false)
14449 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14450 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14451 * shadow (defaults to false)
14452 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14453 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14454 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14455 * @cfg {Array} buttons Array of buttons
14456 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14458 * Create a new BasicDialog.
14459 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14460 * @param {Object} config Configuration options
14462 Roo.BasicDialog = function(el, config){
14463 this.el = Roo.get(el);
14464 var dh = Roo.DomHelper;
14465 if(!this.el && config && config.autoCreate){
14466 if(typeof config.autoCreate == "object"){
14467 if(!config.autoCreate.id){
14468 config.autoCreate.id = el;
14470 this.el = dh.append(document.body,
14471 config.autoCreate, true);
14473 this.el = dh.append(document.body,
14474 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14478 el.setDisplayed(true);
14479 el.hide = this.hideAction;
14481 el.addClass("x-dlg");
14483 Roo.apply(this, config);
14485 this.proxy = el.createProxy("x-dlg-proxy");
14486 this.proxy.hide = this.hideAction;
14487 this.proxy.setOpacity(.5);
14491 el.setWidth(config.width);
14494 el.setHeight(config.height);
14496 this.size = el.getSize();
14497 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14498 this.xy = [config.x,config.y];
14500 this.xy = el.getCenterXY(true);
14502 /** The header element @type Roo.Element */
14503 this.header = el.child("> .x-dlg-hd");
14504 /** The body element @type Roo.Element */
14505 this.body = el.child("> .x-dlg-bd");
14506 /** The footer element @type Roo.Element */
14507 this.footer = el.child("> .x-dlg-ft");
14510 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14513 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14516 this.header.unselectable();
14518 this.header.update(this.title);
14520 // this element allows the dialog to be focused for keyboard event
14521 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14522 this.focusEl.swallowEvent("click", true);
14524 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14526 // wrap the body and footer for special rendering
14527 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14529 this.bwrap.dom.appendChild(this.footer.dom);
14532 this.bg = this.el.createChild({
14533 tag: "div", cls:"x-dlg-bg",
14534 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14536 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14539 if(this.autoScroll !== false && !this.autoTabs){
14540 this.body.setStyle("overflow", "auto");
14543 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14545 if(this.closable !== false){
14546 this.el.addClass("x-dlg-closable");
14547 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14548 this.close.on("click", this.closeClick, this);
14549 this.close.addClassOnOver("x-dlg-close-over");
14551 if(this.collapsible !== false){
14552 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14553 this.collapseBtn.on("click", this.collapseClick, this);
14554 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14555 this.header.on("dblclick", this.collapseClick, this);
14557 if(this.resizable !== false){
14558 this.el.addClass("x-dlg-resizable");
14559 this.resizer = new Roo.Resizable(el, {
14560 minWidth: this.minWidth || 80,
14561 minHeight:this.minHeight || 80,
14562 handles: this.resizeHandles || "all",
14565 this.resizer.on("beforeresize", this.beforeResize, this);
14566 this.resizer.on("resize", this.onResize, this);
14568 if(this.draggable !== false){
14569 el.addClass("x-dlg-draggable");
14570 if (!this.proxyDrag) {
14571 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14574 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14576 dd.setHandleElId(this.header.id);
14577 dd.endDrag = this.endMove.createDelegate(this);
14578 dd.startDrag = this.startMove.createDelegate(this);
14579 dd.onDrag = this.onDrag.createDelegate(this);
14584 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14585 this.mask.enableDisplayMode("block");
14587 this.el.addClass("x-dlg-modal");
14590 this.shadow = new Roo.Shadow({
14591 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14592 offset : this.shadowOffset
14595 this.shadowOffset = 0;
14597 if(Roo.useShims && this.shim !== false){
14598 this.shim = this.el.createShim();
14599 this.shim.hide = this.hideAction;
14607 if (this.buttons) {
14608 var bts= this.buttons;
14610 Roo.each(bts, function(b) {
14619 * Fires when a key is pressed
14620 * @param {Roo.BasicDialog} this
14621 * @param {Roo.EventObject} e
14626 * Fires when this dialog is moved by the user.
14627 * @param {Roo.BasicDialog} this
14628 * @param {Number} x The new page X
14629 * @param {Number} y The new page Y
14634 * Fires when this dialog is resized by the user.
14635 * @param {Roo.BasicDialog} this
14636 * @param {Number} width The new width
14637 * @param {Number} height The new height
14641 * @event beforehide
14642 * Fires before this dialog is hidden.
14643 * @param {Roo.BasicDialog} this
14645 "beforehide" : true,
14648 * Fires when this dialog is hidden.
14649 * @param {Roo.BasicDialog} this
14653 * @event beforeshow
14654 * Fires before this dialog is shown.
14655 * @param {Roo.BasicDialog} this
14657 "beforeshow" : true,
14660 * Fires when this dialog is shown.
14661 * @param {Roo.BasicDialog} this
14665 el.on("keydown", this.onKeyDown, this);
14666 el.on("mousedown", this.toFront, this);
14667 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14669 Roo.DialogManager.register(this);
14670 Roo.BasicDialog.superclass.constructor.call(this);
14673 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14674 shadowOffset: Roo.isIE ? 6 : 5,
14677 minButtonWidth: 75,
14678 defaultButton: null,
14679 buttonAlign: "right",
14684 * Sets the dialog title text
14685 * @param {String} text The title text to display
14686 * @return {Roo.BasicDialog} this
14688 setTitle : function(text){
14689 this.header.update(text);
14694 closeClick : function(){
14699 collapseClick : function(){
14700 this[this.collapsed ? "expand" : "collapse"]();
14704 * Collapses the dialog to its minimized state (only the title bar is visible).
14705 * Equivalent to the user clicking the collapse dialog button.
14707 collapse : function(){
14708 if(!this.collapsed){
14709 this.collapsed = true;
14710 this.el.addClass("x-dlg-collapsed");
14711 this.restoreHeight = this.el.getHeight();
14712 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14717 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14718 * clicking the expand dialog button.
14720 expand : function(){
14721 if(this.collapsed){
14722 this.collapsed = false;
14723 this.el.removeClass("x-dlg-collapsed");
14724 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14729 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14730 * @return {Roo.TabPanel} The tabs component
14732 initTabs : function(){
14733 var tabs = this.getTabs();
14734 while(tabs.getTab(0)){
14737 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14739 tabs.addTab(Roo.id(dom), dom.title);
14747 beforeResize : function(){
14748 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14752 onResize : function(){
14753 this.refreshSize();
14754 this.syncBodyHeight();
14755 this.adjustAssets();
14757 this.fireEvent("resize", this, this.size.width, this.size.height);
14761 onKeyDown : function(e){
14762 if(this.isVisible()){
14763 this.fireEvent("keydown", this, e);
14768 * Resizes the dialog.
14769 * @param {Number} width
14770 * @param {Number} height
14771 * @return {Roo.BasicDialog} this
14773 resizeTo : function(width, height){
14774 this.el.setSize(width, height);
14775 this.size = {width: width, height: height};
14776 this.syncBodyHeight();
14777 if(this.fixedcenter){
14780 if(this.isVisible()){
14781 this.constrainXY();
14782 this.adjustAssets();
14784 this.fireEvent("resize", this, width, height);
14790 * Resizes the dialog to fit the specified content size.
14791 * @param {Number} width
14792 * @param {Number} height
14793 * @return {Roo.BasicDialog} this
14795 setContentSize : function(w, h){
14796 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14797 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14798 //if(!this.el.isBorderBox()){
14799 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14800 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14803 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14804 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14806 this.resizeTo(w, h);
14811 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14812 * executed in response to a particular key being pressed while the dialog is active.
14813 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14814 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14815 * @param {Function} fn The function to call
14816 * @param {Object} scope (optional) The scope of the function
14817 * @return {Roo.BasicDialog} this
14819 addKeyListener : function(key, fn, scope){
14820 var keyCode, shift, ctrl, alt;
14821 if(typeof key == "object" && !(key instanceof Array)){
14822 keyCode = key["key"];
14823 shift = key["shift"];
14824 ctrl = key["ctrl"];
14829 var handler = function(dlg, e){
14830 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14831 var k = e.getKey();
14832 if(keyCode instanceof Array){
14833 for(var i = 0, len = keyCode.length; i < len; i++){
14834 if(keyCode[i] == k){
14835 fn.call(scope || window, dlg, k, e);
14841 fn.call(scope || window, dlg, k, e);
14846 this.on("keydown", handler);
14851 * Returns the TabPanel component (creates it if it doesn't exist).
14852 * Note: If you wish to simply check for the existence of tabs without creating them,
14853 * check for a null 'tabs' property.
14854 * @return {Roo.TabPanel} The tabs component
14856 getTabs : function(){
14858 this.el.addClass("x-dlg-auto-tabs");
14859 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14860 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14866 * Adds a button to the footer section of the dialog.
14867 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14868 * object or a valid Roo.DomHelper element config
14869 * @param {Function} handler The function called when the button is clicked
14870 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14871 * @return {Roo.Button} The new button
14873 addButton : function(config, handler, scope){
14874 var dh = Roo.DomHelper;
14876 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14878 if(!this.btnContainer){
14879 var tb = this.footer.createChild({
14881 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14882 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14884 this.btnContainer = tb.firstChild.firstChild.firstChild;
14889 minWidth: this.minButtonWidth,
14892 if(typeof config == "string"){
14893 bconfig.text = config;
14896 bconfig.dhconfig = config;
14898 Roo.apply(bconfig, config);
14902 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14903 bconfig.position = Math.max(0, bconfig.position);
14904 fc = this.btnContainer.childNodes[bconfig.position];
14907 var btn = new Roo.Button(
14909 this.btnContainer.insertBefore(document.createElement("td"),fc)
14910 : this.btnContainer.appendChild(document.createElement("td")),
14911 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14914 this.syncBodyHeight();
14917 * Array of all the buttons that have been added to this dialog via addButton
14922 this.buttons.push(btn);
14927 * Sets the default button to be focused when the dialog is displayed.
14928 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14929 * @return {Roo.BasicDialog} this
14931 setDefaultButton : function(btn){
14932 this.defaultButton = btn;
14937 getHeaderFooterHeight : function(safe){
14940 height += this.header.getHeight();
14943 var fm = this.footer.getMargins();
14944 height += (this.footer.getHeight()+fm.top+fm.bottom);
14946 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14947 height += this.centerBg.getPadding("tb");
14952 syncBodyHeight : function()
14954 var bd = this.body, // the text
14955 cb = this.centerBg, // wrapper around bottom.. but does not seem to be used..
14957 var height = this.size.height - this.getHeaderFooterHeight(false);
14958 bd.setHeight(height-bd.getMargins("tb"));
14959 var hh = this.header.getHeight();
14960 var h = this.size.height-hh;
14963 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14964 bw.setHeight(h-cb.getPadding("tb"));
14966 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14967 bd.setWidth(bw.getWidth(true));
14969 this.tabs.syncHeight();
14971 this.tabs.el.repaint();
14977 * Restores the previous state of the dialog if Roo.state is configured.
14978 * @return {Roo.BasicDialog} this
14980 restoreState : function(){
14981 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14982 if(box && box.width){
14983 this.xy = [box.x, box.y];
14984 this.resizeTo(box.width, box.height);
14990 beforeShow : function(){
14992 if(this.fixedcenter){
14993 this.xy = this.el.getCenterXY(true);
14996 Roo.get(document.body).addClass("x-body-masked");
14997 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15000 this.constrainXY();
15004 animShow : function(){
15005 var b = Roo.get(this.animateTarget).getBox();
15006 this.proxy.setSize(b.width, b.height);
15007 this.proxy.setLocation(b.x, b.y);
15009 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
15010 true, .35, this.showEl.createDelegate(this));
15014 * Shows the dialog.
15015 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
15016 * @return {Roo.BasicDialog} this
15018 show : function(animateTarget){
15019 if (this.fireEvent("beforeshow", this) === false){
15022 if(this.syncHeightBeforeShow){
15023 this.syncBodyHeight();
15024 }else if(this.firstShow){
15025 this.firstShow = false;
15026 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
15028 this.animateTarget = animateTarget || this.animateTarget;
15029 if(!this.el.isVisible()){
15031 if(this.animateTarget && Roo.get(this.animateTarget)){
15041 showEl : function(){
15043 this.el.setXY(this.xy);
15045 this.adjustAssets(true);
15048 // IE peekaboo bug - fix found by Dave Fenwick
15052 this.fireEvent("show", this);
15056 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
15057 * dialog itself will receive focus.
15059 focus : function(){
15060 if(this.defaultButton){
15061 this.defaultButton.focus();
15063 this.focusEl.focus();
15068 constrainXY : function(){
15069 if(this.constraintoviewport !== false){
15070 if(!this.viewSize){
15071 if(this.container){
15072 var s = this.container.getSize();
15073 this.viewSize = [s.width, s.height];
15075 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
15078 var s = Roo.get(this.container||document).getScroll();
15080 var x = this.xy[0], y = this.xy[1];
15081 var w = this.size.width, h = this.size.height;
15082 var vw = this.viewSize[0], vh = this.viewSize[1];
15083 // only move it if it needs it
15085 // first validate right/bottom
15086 if(x + w > vw+s.left){
15090 if(y + h > vh+s.top){
15094 // then make sure top/left isn't negative
15106 if(this.isVisible()){
15107 this.el.setLocation(x, y);
15108 this.adjustAssets();
15115 onDrag : function(){
15116 if(!this.proxyDrag){
15117 this.xy = this.el.getXY();
15118 this.adjustAssets();
15123 adjustAssets : function(doShow){
15124 var x = this.xy[0], y = this.xy[1];
15125 var w = this.size.width, h = this.size.height;
15126 if(doShow === true){
15128 this.shadow.show(this.el);
15134 if(this.shadow && this.shadow.isVisible()){
15135 this.shadow.show(this.el);
15137 if(this.shim && this.shim.isVisible()){
15138 this.shim.setBounds(x, y, w, h);
15143 adjustViewport : function(w, h){
15145 w = Roo.lib.Dom.getViewWidth();
15146 h = Roo.lib.Dom.getViewHeight();
15149 this.viewSize = [w, h];
15150 if(this.modal && this.mask.isVisible()){
15151 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
15152 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
15154 if(this.isVisible()){
15155 this.constrainXY();
15160 * Destroys this dialog and all its supporting elements (including any tabs, shim,
15161 * shadow, proxy, mask, etc.) Also removes all event listeners.
15162 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
15164 destroy : function(removeEl){
15165 if(this.isVisible()){
15166 this.animateTarget = null;
15169 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
15171 this.tabs.destroy(removeEl);
15184 for(var i = 0, len = this.buttons.length; i < len; i++){
15185 this.buttons[i].destroy();
15188 this.el.removeAllListeners();
15189 if(removeEl === true){
15190 this.el.update("");
15193 Roo.DialogManager.unregister(this);
15197 startMove : function(){
15198 if(this.proxyDrag){
15201 if(this.constraintoviewport !== false){
15202 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
15207 endMove : function(){
15208 if(!this.proxyDrag){
15209 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
15211 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
15214 this.refreshSize();
15215 this.adjustAssets();
15217 this.fireEvent("move", this, this.xy[0], this.xy[1]);
15221 * Brings this dialog to the front of any other visible dialogs
15222 * @return {Roo.BasicDialog} this
15224 toFront : function(){
15225 Roo.DialogManager.bringToFront(this);
15230 * Sends this dialog to the back (under) of any other visible dialogs
15231 * @return {Roo.BasicDialog} this
15233 toBack : function(){
15234 Roo.DialogManager.sendToBack(this);
15239 * Centers this dialog in the viewport
15240 * @return {Roo.BasicDialog} this
15242 center : function(){
15243 var xy = this.el.getCenterXY(true);
15244 this.moveTo(xy[0], xy[1]);
15249 * Moves the dialog's top-left corner to the specified point
15250 * @param {Number} x
15251 * @param {Number} y
15252 * @return {Roo.BasicDialog} this
15254 moveTo : function(x, y){
15256 if(this.isVisible()){
15257 this.el.setXY(this.xy);
15258 this.adjustAssets();
15264 * Aligns the dialog to the specified element
15265 * @param {String/HTMLElement/Roo.Element} element The element to align to.
15266 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
15267 * @param {Array} offsets (optional) Offset the positioning by [x, y]
15268 * @return {Roo.BasicDialog} this
15270 alignTo : function(element, position, offsets){
15271 this.xy = this.el.getAlignToXY(element, position, offsets);
15272 if(this.isVisible()){
15273 this.el.setXY(this.xy);
15274 this.adjustAssets();
15280 * Anchors an element to another element and realigns it when the window is resized.
15281 * @param {String/HTMLElement/Roo.Element} element The element to align to.
15282 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
15283 * @param {Array} offsets (optional) Offset the positioning by [x, y]
15284 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
15285 * is a number, it is used as the buffer delay (defaults to 50ms).
15286 * @return {Roo.BasicDialog} this
15288 anchorTo : function(el, alignment, offsets, monitorScroll){
15289 var action = function(){
15290 this.alignTo(el, alignment, offsets);
15292 Roo.EventManager.onWindowResize(action, this);
15293 var tm = typeof monitorScroll;
15294 if(tm != 'undefined'){
15295 Roo.EventManager.on(window, 'scroll', action, this,
15296 {buffer: tm == 'number' ? monitorScroll : 50});
15303 * Returns true if the dialog is visible
15304 * @return {Boolean}
15306 isVisible : function(){
15307 return this.el.isVisible();
15311 animHide : function(callback){
15312 var b = Roo.get(this.animateTarget).getBox();
15314 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15316 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15317 this.hideEl.createDelegate(this, [callback]));
15321 * Hides the dialog.
15322 * @param {Function} callback (optional) Function to call when the dialog is hidden
15323 * @return {Roo.BasicDialog} this
15325 hide : function(callback){
15326 if (this.fireEvent("beforehide", this) === false){
15330 this.shadow.hide();
15335 // sometimes animateTarget seems to get set.. causing problems...
15336 // this just double checks..
15337 if(this.animateTarget && Roo.get(this.animateTarget)) {
15338 this.animHide(callback);
15341 this.hideEl(callback);
15347 hideEl : function(callback){
15351 Roo.get(document.body).removeClass("x-body-masked");
15353 this.fireEvent("hide", this);
15354 if(typeof callback == "function"){
15360 hideAction : function(){
15361 this.setLeft("-10000px");
15362 this.setTop("-10000px");
15363 this.setStyle("visibility", "hidden");
15367 refreshSize : function(){
15368 this.size = this.el.getSize();
15369 this.xy = this.el.getXY();
15370 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15374 // z-index is managed by the DialogManager and may be overwritten at any time
15375 setZIndex : function(index){
15377 this.mask.setStyle("z-index", index);
15380 this.shim.setStyle("z-index", ++index);
15383 this.shadow.setZIndex(++index);
15385 this.el.setStyle("z-index", ++index);
15387 this.proxy.setStyle("z-index", ++index);
15390 this.resizer.proxy.setStyle("z-index", ++index);
15393 this.lastZIndex = index;
15397 * Returns the element for this dialog
15398 * @return {Roo.Element} The underlying dialog Element
15400 getEl : function(){
15406 * @class Roo.DialogManager
15407 * Provides global access to BasicDialogs that have been created and
15408 * support for z-indexing (layering) multiple open dialogs.
15410 Roo.DialogManager = function(){
15412 var accessList = [];
15416 var sortDialogs = function(d1, d2){
15417 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15421 var orderDialogs = function(){
15422 accessList.sort(sortDialogs);
15423 var seed = Roo.DialogManager.zseed;
15424 for(var i = 0, len = accessList.length; i < len; i++){
15425 var dlg = accessList[i];
15427 dlg.setZIndex(seed + (i*10));
15434 * The starting z-index for BasicDialogs (defaults to 9000)
15435 * @type Number The z-index value
15440 register : function(dlg){
15441 list[dlg.id] = dlg;
15442 accessList.push(dlg);
15446 unregister : function(dlg){
15447 delete list[dlg.id];
15450 if(!accessList.indexOf){
15451 for( i = 0, len = accessList.length; i < len; i++){
15452 if(accessList[i] == dlg){
15453 accessList.splice(i, 1);
15458 i = accessList.indexOf(dlg);
15460 accessList.splice(i, 1);
15466 * Gets a registered dialog by id
15467 * @param {String/Object} id The id of the dialog or a dialog
15468 * @return {Roo.BasicDialog} this
15470 get : function(id){
15471 return typeof id == "object" ? id : list[id];
15475 * Brings the specified dialog to the front
15476 * @param {String/Object} dlg The id of the dialog or a dialog
15477 * @return {Roo.BasicDialog} this
15479 bringToFront : function(dlg){
15480 dlg = this.get(dlg);
15483 dlg._lastAccess = new Date().getTime();
15490 * Sends the specified dialog to the back
15491 * @param {String/Object} dlg The id of the dialog or a dialog
15492 * @return {Roo.BasicDialog} this
15494 sendToBack : function(dlg){
15495 dlg = this.get(dlg);
15496 dlg._lastAccess = -(new Date().getTime());
15502 * Hides all dialogs
15504 hideAll : function(){
15505 for(var id in list){
15506 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15515 * @class Roo.LayoutDialog
15516 * @extends Roo.BasicDialog
15517 * Dialog which provides adjustments for working with a layout in a Dialog.
15518 * Add your necessary layout config options to the dialog's config.<br>
15519 * Example usage (including a nested layout):
15522 dialog = new Roo.LayoutDialog("download-dlg", {
15531 // layout config merges with the dialog config
15533 tabPosition: "top",
15534 alwaysShowTabs: true
15537 dialog.addKeyListener(27, dialog.hide, dialog);
15538 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15539 dialog.addButton("Build It!", this.getDownload, this);
15541 // we can even add nested layouts
15542 var innerLayout = new Roo.BorderLayout("dl-inner", {
15552 innerLayout.beginUpdate();
15553 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15554 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15555 innerLayout.endUpdate(true);
15557 var layout = dialog.getLayout();
15558 layout.beginUpdate();
15559 layout.add("center", new Roo.ContentPanel("standard-panel",
15560 {title: "Download the Source", fitToFrame:true}));
15561 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15562 {title: "Build your own roo.js"}));
15563 layout.getRegion("center").showPanel(sp);
15564 layout.endUpdate();
15568 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15569 * @param {Object} config configuration options
15571 Roo.LayoutDialog = function(el, cfg){
15574 if (typeof(cfg) == 'undefined') {
15575 config = Roo.apply({}, el);
15576 // not sure why we use documentElement here.. - it should always be body.
15577 // IE7 borks horribly if we use documentElement.
15578 // webkit also does not like documentElement - it creates a body element...
15579 el = Roo.get( document.body || document.documentElement ).createChild();
15580 //config.autoCreate = true;
15584 config.autoTabs = false;
15585 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15586 this.body.setStyle({overflow:"hidden", position:"relative"});
15587 this.layout = new Roo.BorderLayout(this.body.dom, config);
15588 this.layout.monitorWindowResize = false;
15589 this.el.addClass("x-dlg-auto-layout");
15590 // fix case when center region overwrites center function
15591 this.center = Roo.BasicDialog.prototype.center;
15592 this.on("show", this.layout.layout, this.layout, true);
15593 if (config.items) {
15594 var xitems = config.items;
15595 delete config.items;
15596 Roo.each(xitems, this.addxtype, this);
15601 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15603 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15606 endUpdate : function(){
15607 this.layout.endUpdate();
15611 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15614 beginUpdate : function(){
15615 this.layout.beginUpdate();
15619 * Get the BorderLayout for this dialog
15620 * @return {Roo.BorderLayout}
15622 getLayout : function(){
15623 return this.layout;
15626 showEl : function(){
15627 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15629 this.layout.layout();
15634 // Use the syncHeightBeforeShow config option to control this automatically
15635 syncBodyHeight : function(){
15636 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15637 if(this.layout){this.layout.layout();}
15641 * Add an xtype element (actually adds to the layout.)
15642 * @return {Object} xdata xtype object data.
15645 addxtype : function(c) {
15646 return this.layout.addxtype(c);
15650 * Ext JS Library 1.1.1
15651 * Copyright(c) 2006-2007, Ext JS, LLC.
15653 * Originally Released Under LGPL - original licence link has changed is not relivant.
15656 * <script type="text/javascript">
15660 * @class Roo.MessageBox
15661 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15665 Roo.Msg.alert('Status', 'Changes saved successfully.');
15667 // Prompt for user data:
15668 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15670 // process text value...
15674 // Show a dialog using config options:
15676 title:'Save Changes?',
15677 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15678 buttons: Roo.Msg.YESNOCANCEL,
15685 Roo.MessageBox = function(){
15686 var dlg, opt, mask, waitTimer;
15687 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15688 var buttons, activeTextEl, bwidth;
15691 var handleButton = function(button){
15693 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15697 var handleHide = function(){
15698 if(opt && opt.cls){
15699 dlg.el.removeClass(opt.cls);
15702 Roo.TaskMgr.stop(waitTimer);
15708 var updateButtons = function(b){
15711 buttons["ok"].hide();
15712 buttons["cancel"].hide();
15713 buttons["yes"].hide();
15714 buttons["no"].hide();
15715 dlg.footer.dom.style.display = 'none';
15718 dlg.footer.dom.style.display = '';
15719 for(var k in buttons){
15720 if(typeof buttons[k] != "function"){
15723 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15724 width += buttons[k].el.getWidth()+15;
15734 var handleEsc = function(d, k, e){
15735 if(opt && opt.closable !== false){
15745 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15746 * @return {Roo.BasicDialog} The BasicDialog element
15748 getDialog : function(){
15750 dlg = new Roo.BasicDialog("x-msg-box", {
15755 constraintoviewport:false,
15757 collapsible : false,
15760 width:400, height:100,
15761 buttonAlign:"center",
15762 closeClick : function(){
15763 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15764 handleButton("no");
15766 handleButton("cancel");
15770 dlg.on("hide", handleHide);
15772 dlg.addKeyListener(27, handleEsc);
15774 var bt = this.buttonText;
15775 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15776 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15777 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15778 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15779 bodyEl = dlg.body.createChild({
15781 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>'
15783 msgEl = bodyEl.dom.firstChild;
15784 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15785 textboxEl.enableDisplayMode();
15786 textboxEl.addKeyListener([10,13], function(){
15787 if(dlg.isVisible() && opt && opt.buttons){
15788 if(opt.buttons.ok){
15789 handleButton("ok");
15790 }else if(opt.buttons.yes){
15791 handleButton("yes");
15795 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15796 textareaEl.enableDisplayMode();
15797 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15798 progressEl.enableDisplayMode();
15799 var pf = progressEl.dom.firstChild;
15801 pp = Roo.get(pf.firstChild);
15802 pp.setHeight(pf.offsetHeight);
15810 * Updates the message box body text
15811 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15812 * the XHTML-compliant non-breaking space character '&#160;')
15813 * @return {Roo.MessageBox} This message box
15815 updateText : function(text){
15816 if(!dlg.isVisible() && !opt.width){
15817 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15819 msgEl.innerHTML = text || ' ';
15821 var cw = Math.max(msgEl.offsetWidth, msgEl.parentNode.scrollWidth);
15822 //Roo.log("guesed size: " + JSON.stringify([cw,msgEl.offsetWidth, msgEl.parentNode.scrollWidth]));
15824 Math.min(opt.width || cw , this.maxWidth),
15825 Math.max(opt.minWidth || this.minWidth, bwidth)
15828 activeTextEl.setWidth(w);
15830 if(dlg.isVisible()){
15831 dlg.fixedcenter = false;
15833 // to big, make it scroll. = But as usual stupid IE does not support
15836 if ( bodyEl.getHeight() > (Roo.lib.Dom.getViewHeight() - 100)) {
15837 bodyEl.setHeight ( Roo.lib.Dom.getViewHeight() - 100 );
15838 bodyEl.dom.style.overflowY = 'auto' + ( Roo.isIE ? '' : ' !important');
15840 bodyEl.dom.style.height = '';
15841 bodyEl.dom.style.overflowY = '';
15844 bodyEl.dom.style.get = 'auto' + ( Roo.isIE ? '' : ' !important');
15846 bodyEl.dom.style.overflowX = '';
15849 dlg.setContentSize(w, bodyEl.getHeight());
15850 if(dlg.isVisible()){
15851 dlg.fixedcenter = true;
15857 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15858 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15859 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15860 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15861 * @return {Roo.MessageBox} This message box
15863 updateProgress : function(value, text){
15865 this.updateText(text);
15867 if (pp) { // weird bug on my firefox - for some reason this is not defined
15868 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15874 * Returns true if the message box is currently displayed
15875 * @return {Boolean} True if the message box is visible, else false
15877 isVisible : function(){
15878 return dlg && dlg.isVisible();
15882 * Hides the message box if it is displayed
15885 if(this.isVisible()){
15891 * Displays a new message box, or reinitializes an existing message box, based on the config options
15892 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15893 * The following config object properties are supported:
15895 Property Type Description
15896 ---------- --------------- ------------------------------------------------------------------------------------
15897 animEl String/Element An id or Element from which the message box should animate as it opens and
15898 closes (defaults to undefined)
15899 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15900 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15901 closable Boolean False to hide the top-right close button (defaults to true). Note that
15902 progress and wait dialogs will ignore this property and always hide the
15903 close button as they can only be closed programmatically.
15904 cls String A custom CSS class to apply to the message box element
15905 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15906 displayed (defaults to 75)
15907 fn Function A callback function to execute after closing the dialog. The arguments to the
15908 function will be btn (the name of the button that was clicked, if applicable,
15909 e.g. "ok"), and text (the value of the active text field, if applicable).
15910 Progress and wait dialogs will ignore this option since they do not respond to
15911 user actions and can only be closed programmatically, so any required function
15912 should be called by the same code after it closes the dialog.
15913 icon String A CSS class that provides a background image to be used as an icon for
15914 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15915 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15916 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15917 modal Boolean False to allow user interaction with the page while the message box is
15918 displayed (defaults to true)
15919 msg String A string that will replace the existing message box body text (defaults
15920 to the XHTML-compliant non-breaking space character ' ')
15921 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15922 progress Boolean True to display a progress bar (defaults to false)
15923 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15924 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15925 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15926 title String The title text
15927 value String The string value to set into the active textbox element if displayed
15928 wait Boolean True to display a progress bar (defaults to false)
15929 width Number The width of the dialog in pixels
15936 msg: 'Please enter your address:',
15938 buttons: Roo.MessageBox.OKCANCEL,
15941 animEl: 'addAddressBtn'
15944 * @param {Object} config Configuration options
15945 * @return {Roo.MessageBox} This message box
15947 show : function(options)
15950 // this causes nightmares if you show one dialog after another
15951 // especially on callbacks..
15953 if(this.isVisible()){
15956 Roo.log("[Roo.Messagebox] Show called while message displayed:" );
15957 Roo.log("Old Dialog Message:" + msgEl.innerHTML );
15958 Roo.log("New Dialog Message:" + options.msg )
15959 //this.alert("ERROR", "Multiple dialogs where displayed at the same time");
15960 //throw "Roo.MessageBox ERROR : Multiple dialogs where displayed at the same time";
15963 var d = this.getDialog();
15965 d.setTitle(opt.title || " ");
15966 d.close.setDisplayed(opt.closable !== false);
15967 activeTextEl = textboxEl;
15968 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15973 textareaEl.setHeight(typeof opt.multiline == "number" ?
15974 opt.multiline : this.defaultTextHeight);
15975 activeTextEl = textareaEl;
15984 progressEl.setDisplayed(opt.progress === true);
15985 this.updateProgress(0);
15986 activeTextEl.dom.value = opt.value || "";
15988 dlg.setDefaultButton(activeTextEl);
15990 var bs = opt.buttons;
15993 db = buttons["ok"];
15994 }else if(bs && bs.yes){
15995 db = buttons["yes"];
15997 dlg.setDefaultButton(db);
15999 bwidth = updateButtons(opt.buttons);
16000 this.updateText(opt.msg);
16002 d.el.addClass(opt.cls);
16004 d.proxyDrag = opt.proxyDrag === true;
16005 d.modal = opt.modal !== false;
16006 d.mask = opt.modal !== false ? mask : false;
16007 if(!d.isVisible()){
16008 // force it to the end of the z-index stack so it gets a cursor in FF
16009 document.body.appendChild(dlg.el.dom);
16010 d.animateTarget = null;
16011 d.show(options.animEl);
16017 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
16018 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
16019 * and closing the message box when the process is complete.
16020 * @param {String} title The title bar text
16021 * @param {String} msg The message box body text
16022 * @return {Roo.MessageBox} This message box
16024 progress : function(title, msg){
16031 minWidth: this.minProgressWidth,
16038 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
16039 * If a callback function is passed it will be called after the user clicks the button, and the
16040 * id of the button that was clicked will be passed as the only parameter to the callback
16041 * (could also be the top-right close button).
16042 * @param {String} title The title bar text
16043 * @param {String} msg The message box body text
16044 * @param {Function} fn (optional) The callback function invoked after the message box is closed
16045 * @param {Object} scope (optional) The scope of the callback function
16046 * @return {Roo.MessageBox} This message box
16048 alert : function(title, msg, fn, scope){
16061 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
16062 * interaction while waiting for a long-running process to complete that does not have defined intervals.
16063 * You are responsible for closing the message box when the process is complete.
16064 * @param {String} msg The message box body text
16065 * @param {String} title (optional) The title bar text
16066 * @return {Roo.MessageBox} This message box
16068 wait : function(msg, title){
16079 waitTimer = Roo.TaskMgr.start({
16081 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
16089 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
16090 * If a callback function is passed it will be called after the user clicks either button, and the id of the
16091 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
16092 * @param {String} title The title bar text
16093 * @param {String} msg The message box body text
16094 * @param {Function} fn (optional) The callback function invoked after the message box is closed
16095 * @param {Object} scope (optional) The scope of the callback function
16096 * @return {Roo.MessageBox} This message box
16098 confirm : function(title, msg, fn, scope){
16102 buttons: this.YESNO,
16111 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
16112 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
16113 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
16114 * (could also be the top-right close button) and the text that was entered will be passed as the two
16115 * parameters to the callback.
16116 * @param {String} title The title bar text
16117 * @param {String} msg The message box body text
16118 * @param {Function} fn (optional) The callback function invoked after the message box is closed
16119 * @param {Object} scope (optional) The scope of the callback function
16120 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
16121 * property, or the height in pixels to create the textbox (defaults to false / single-line)
16122 * @return {Roo.MessageBox} This message box
16124 prompt : function(title, msg, fn, scope, multiline){
16128 buttons: this.OKCANCEL,
16133 multiline: multiline,
16140 * Button config that displays a single OK button
16145 * Button config that displays Yes and No buttons
16148 YESNO : {yes:true, no:true},
16150 * Button config that displays OK and Cancel buttons
16153 OKCANCEL : {ok:true, cancel:true},
16155 * Button config that displays Yes, No and Cancel buttons
16158 YESNOCANCEL : {yes:true, no:true, cancel:true},
16161 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
16164 defaultTextHeight : 75,
16166 * The maximum width in pixels of the message box (defaults to 600)
16171 * The minimum width in pixels of the message box (defaults to 100)
16176 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
16177 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
16180 minProgressWidth : 250,
16182 * An object containing the default button text strings that can be overriden for localized language support.
16183 * Supported properties are: ok, cancel, yes and no.
16184 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
16197 * Shorthand for {@link Roo.MessageBox}
16199 Roo.Msg = Roo.MessageBox;/*
16201 * Ext JS Library 1.1.1
16202 * Copyright(c) 2006-2007, Ext JS, LLC.
16204 * Originally Released Under LGPL - original licence link has changed is not relivant.
16207 * <script type="text/javascript">
16210 * @class Roo.QuickTips
16211 * Provides attractive and customizable tooltips for any element.
16214 Roo.QuickTips = function(){
16215 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
16216 var ce, bd, xy, dd;
16217 var visible = false, disabled = true, inited = false;
16218 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
16220 var onOver = function(e){
16224 var t = e.getTarget();
16225 if(!t || t.nodeType !== 1 || t == document || t == document.body){
16228 if(ce && t == ce.el){
16229 clearTimeout(hideProc);
16232 if(t && tagEls[t.id]){
16233 tagEls[t.id].el = t;
16234 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
16237 var ttp, et = Roo.fly(t);
16238 var ns = cfg.namespace;
16239 if(tm.interceptTitles && t.title){
16242 t.removeAttribute("title");
16243 e.preventDefault();
16245 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
16248 showProc = show.defer(tm.showDelay, tm, [{
16251 width: et.getAttributeNS(ns, cfg.width),
16252 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
16253 title: et.getAttributeNS(ns, cfg.title),
16254 cls: et.getAttributeNS(ns, cfg.cls)
16259 var onOut = function(e){
16260 clearTimeout(showProc);
16261 var t = e.getTarget();
16262 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
16263 hideProc = setTimeout(hide, tm.hideDelay);
16267 var onMove = function(e){
16273 if(tm.trackMouse && ce){
16278 var onDown = function(e){
16279 clearTimeout(showProc);
16280 clearTimeout(hideProc);
16282 if(tm.hideOnClick){
16285 tm.enable.defer(100, tm);
16290 var getPad = function(){
16291 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
16294 var show = function(o){
16298 clearTimeout(dismissProc);
16300 if(removeCls){ // in case manually hidden
16301 el.removeClass(removeCls);
16305 el.addClass(ce.cls);
16306 removeCls = ce.cls;
16309 tipTitle.update(ce.title);
16312 tipTitle.update('');
16315 el.dom.style.width = tm.maxWidth+'px';
16316 //tipBody.dom.style.width = '';
16317 tipBodyText.update(o.text);
16318 var p = getPad(), w = ce.width;
16320 var td = tipBodyText.dom;
16321 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
16322 if(aw > tm.maxWidth){
16324 }else if(aw < tm.minWidth){
16330 //tipBody.setWidth(w);
16331 el.setWidth(parseInt(w, 10) + p);
16332 if(ce.autoHide === false){
16333 close.setDisplayed(true);
16338 close.setDisplayed(false);
16344 el.avoidY = xy[1]-18;
16349 el.setStyle("visibility", "visible");
16350 el.fadeIn({callback: afterShow});
16356 var afterShow = function(){
16360 if(tm.autoDismiss && ce.autoHide !== false){
16361 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16366 var hide = function(noanim){
16367 clearTimeout(dismissProc);
16368 clearTimeout(hideProc);
16370 if(el.isVisible()){
16372 if(noanim !== true && tm.animate){
16373 el.fadeOut({callback: afterHide});
16380 var afterHide = function(){
16383 el.removeClass(removeCls);
16390 * @cfg {Number} minWidth
16391 * The minimum width of the quick tip (defaults to 40)
16395 * @cfg {Number} maxWidth
16396 * The maximum width of the quick tip (defaults to 300)
16400 * @cfg {Boolean} interceptTitles
16401 * True to automatically use the element's DOM title value if available (defaults to false)
16403 interceptTitles : false,
16405 * @cfg {Boolean} trackMouse
16406 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16408 trackMouse : false,
16410 * @cfg {Boolean} hideOnClick
16411 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16413 hideOnClick : true,
16415 * @cfg {Number} showDelay
16416 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16420 * @cfg {Number} hideDelay
16421 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16425 * @cfg {Boolean} autoHide
16426 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16427 * Used in conjunction with hideDelay.
16432 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16433 * (defaults to true). Used in conjunction with autoDismissDelay.
16435 autoDismiss : true,
16438 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16440 autoDismissDelay : 5000,
16442 * @cfg {Boolean} animate
16443 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16448 * @cfg {String} title
16449 * Title text to display (defaults to ''). This can be any valid HTML markup.
16453 * @cfg {String} text
16454 * Body text to display (defaults to ''). This can be any valid HTML markup.
16458 * @cfg {String} cls
16459 * A CSS class to apply to the base quick tip element (defaults to '').
16463 * @cfg {Number} width
16464 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16465 * minWidth or maxWidth.
16470 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16471 * or display QuickTips in a page.
16474 tm = Roo.QuickTips;
16475 cfg = tm.tagConfig;
16477 if(!Roo.isReady){ // allow calling of init() before onReady
16478 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16481 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16482 el.fxDefaults = {stopFx: true};
16483 // maximum custom styling
16484 //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>');
16485 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>');
16486 tipTitle = el.child('h3');
16487 tipTitle.enableDisplayMode("block");
16488 tipBody = el.child('div.x-tip-bd');
16489 tipBodyText = el.child('div.x-tip-bd-inner');
16490 //bdLeft = el.child('div.x-tip-bd-left');
16491 //bdRight = el.child('div.x-tip-bd-right');
16492 close = el.child('div.x-tip-close');
16493 close.enableDisplayMode("block");
16494 close.on("click", hide);
16495 var d = Roo.get(document);
16496 d.on("mousedown", onDown);
16497 d.on("mouseover", onOver);
16498 d.on("mouseout", onOut);
16499 d.on("mousemove", onMove);
16500 esc = d.addKeyListener(27, hide);
16503 dd = el.initDD("default", null, {
16504 onDrag : function(){
16508 dd.setHandleElId(tipTitle.id);
16517 * Configures a new quick tip instance and assigns it to a target element. The following config options
16520 Property Type Description
16521 ---------- --------------------- ------------------------------------------------------------------------
16522 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16524 * @param {Object} config The config object
16526 register : function(config){
16527 var cs = config instanceof Array ? config : arguments;
16528 for(var i = 0, len = cs.length; i < len; i++) {
16530 var target = c.target;
16532 if(target instanceof Array){
16533 for(var j = 0, jlen = target.length; j < jlen; j++){
16534 tagEls[target[j]] = c;
16537 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16544 * Removes this quick tip from its element and destroys it.
16545 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16547 unregister : function(el){
16548 delete tagEls[Roo.id(el)];
16552 * Enable this quick tip.
16554 enable : function(){
16555 if(inited && disabled){
16557 if(locks.length < 1){
16564 * Disable this quick tip.
16566 disable : function(){
16568 clearTimeout(showProc);
16569 clearTimeout(hideProc);
16570 clearTimeout(dismissProc);
16578 * Returns true if the quick tip is enabled, else false.
16580 isEnabled : function(){
16587 attribute : "qtip",
16597 // backwards compat
16598 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16600 * Ext JS Library 1.1.1
16601 * Copyright(c) 2006-2007, Ext JS, LLC.
16603 * Originally Released Under LGPL - original licence link has changed is not relivant.
16606 * <script type="text/javascript">
16611 * @class Roo.tree.TreePanel
16612 * @extends Roo.data.Tree
16614 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16615 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16616 * @cfg {Boolean} enableDD true to enable drag and drop
16617 * @cfg {Boolean} enableDrag true to enable just drag
16618 * @cfg {Boolean} enableDrop true to enable just drop
16619 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16620 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16621 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16622 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16623 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16624 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16625 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16626 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16627 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16628 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16629 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16630 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16631 * @cfg {Object|Roo.tree.TreeEditor} editor The TreeEditor or xtype data to display when clicked.
16632 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16633 * @cfg {Function} renderer DEPRECATED - use TreeLoader:create event / 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>
16634 * @cfg {Function} rendererTip DEPRECATED - use TreeLoader:create event / 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>
16637 * @param {String/HTMLElement/Element} el The container element
16638 * @param {Object} config
16640 Roo.tree.TreePanel = function(el, config){
16642 var loader = false;
16644 root = config.root;
16645 delete config.root;
16647 if (config.loader) {
16648 loader = config.loader;
16649 delete config.loader;
16652 Roo.apply(this, config);
16653 Roo.tree.TreePanel.superclass.constructor.call(this);
16654 this.el = Roo.get(el);
16655 this.el.addClass('x-tree');
16656 //console.log(root);
16658 this.setRootNode( Roo.factory(root, Roo.tree));
16661 this.loader = Roo.factory(loader, Roo.tree);
16664 * Read-only. The id of the container element becomes this TreePanel's id.
16666 this.id = this.el.id;
16669 * @event beforeload
16670 * Fires before a node is loaded, return false to cancel
16671 * @param {Node} node The node being loaded
16673 "beforeload" : true,
16676 * Fires when a node is loaded
16677 * @param {Node} node The node that was loaded
16681 * @event textchange
16682 * Fires when the text for a node is changed
16683 * @param {Node} node The node
16684 * @param {String} text The new text
16685 * @param {String} oldText The old text
16687 "textchange" : true,
16689 * @event beforeexpand
16690 * Fires before a node is expanded, return false to cancel.
16691 * @param {Node} node The node
16692 * @param {Boolean} deep
16693 * @param {Boolean} anim
16695 "beforeexpand" : true,
16697 * @event beforecollapse
16698 * Fires before a node is collapsed, return false to cancel.
16699 * @param {Node} node The node
16700 * @param {Boolean} deep
16701 * @param {Boolean} anim
16703 "beforecollapse" : true,
16706 * Fires when a node is expanded
16707 * @param {Node} node The node
16711 * @event disabledchange
16712 * Fires when the disabled status of a node changes
16713 * @param {Node} node The node
16714 * @param {Boolean} disabled
16716 "disabledchange" : true,
16719 * Fires when a node is collapsed
16720 * @param {Node} node The node
16724 * @event beforeclick
16725 * Fires before click processing on a node. Return false to cancel the default action.
16726 * @param {Node} node The node
16727 * @param {Roo.EventObject} e The event object
16729 "beforeclick":true,
16731 * @event checkchange
16732 * Fires when a node with a checkbox's checked property changes
16733 * @param {Node} this This node
16734 * @param {Boolean} checked
16736 "checkchange":true,
16739 * Fires when a node is clicked
16740 * @param {Node} node The node
16741 * @param {Roo.EventObject} e The event object
16746 * Fires when a node is double clicked
16747 * @param {Node} node The node
16748 * @param {Roo.EventObject} e The event object
16752 * @event contextmenu
16753 * Fires when a node is right clicked
16754 * @param {Node} node The node
16755 * @param {Roo.EventObject} e The event object
16757 "contextmenu":true,
16759 * @event beforechildrenrendered
16760 * Fires right before the child nodes for a node are rendered
16761 * @param {Node} node The node
16763 "beforechildrenrendered":true,
16766 * Fires when a node starts being dragged
16767 * @param {Roo.tree.TreePanel} this
16768 * @param {Roo.tree.TreeNode} node
16769 * @param {event} e The raw browser event
16771 "startdrag" : true,
16774 * Fires when a drag operation is complete
16775 * @param {Roo.tree.TreePanel} this
16776 * @param {Roo.tree.TreeNode} node
16777 * @param {event} e The raw browser event
16782 * Fires when a dragged node is dropped on a valid DD target
16783 * @param {Roo.tree.TreePanel} this
16784 * @param {Roo.tree.TreeNode} node
16785 * @param {DD} dd The dd it was dropped on
16786 * @param {event} e The raw browser event
16790 * @event beforenodedrop
16791 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16792 * passed to handlers has the following properties:<br />
16793 * <ul style="padding:5px;padding-left:16px;">
16794 * <li>tree - The TreePanel</li>
16795 * <li>target - The node being targeted for the drop</li>
16796 * <li>data - The drag data from the drag source</li>
16797 * <li>point - The point of the drop - append, above or below</li>
16798 * <li>source - The drag source</li>
16799 * <li>rawEvent - Raw mouse event</li>
16800 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16801 * to be inserted by setting them on this object.</li>
16802 * <li>cancel - Set this to true to cancel the drop.</li>
16804 * @param {Object} dropEvent
16806 "beforenodedrop" : true,
16809 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16810 * passed to handlers has the following properties:<br />
16811 * <ul style="padding:5px;padding-left:16px;">
16812 * <li>tree - The TreePanel</li>
16813 * <li>target - The node being targeted for the drop</li>
16814 * <li>data - The drag data from the drag source</li>
16815 * <li>point - The point of the drop - append, above or below</li>
16816 * <li>source - The drag source</li>
16817 * <li>rawEvent - Raw mouse event</li>
16818 * <li>dropNode - Dropped node(s).</li>
16820 * @param {Object} dropEvent
16824 * @event nodedragover
16825 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16826 * passed to handlers has the following properties:<br />
16827 * <ul style="padding:5px;padding-left:16px;">
16828 * <li>tree - The TreePanel</li>
16829 * <li>target - The node being targeted for the drop</li>
16830 * <li>data - The drag data from the drag source</li>
16831 * <li>point - The point of the drop - append, above or below</li>
16832 * <li>source - The drag source</li>
16833 * <li>rawEvent - Raw mouse event</li>
16834 * <li>dropNode - Drop node(s) provided by the source.</li>
16835 * <li>cancel - Set this to true to signal drop not allowed.</li>
16837 * @param {Object} dragOverEvent
16839 "nodedragover" : true
16842 if(this.singleExpand){
16843 this.on("beforeexpand", this.restrictExpand, this);
16846 this.editor.tree = this;
16847 this.editor = Roo.factory(this.editor, Roo.tree);
16850 if (this.selModel) {
16851 this.selModel = Roo.factory(this.selModel, Roo.tree);
16855 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16856 rootVisible : true,
16857 animate: Roo.enableFx,
16860 hlDrop : Roo.enableFx,
16864 rendererTip: false,
16866 restrictExpand : function(node){
16867 var p = node.parentNode;
16869 if(p.expandedChild && p.expandedChild.parentNode == p){
16870 p.expandedChild.collapse();
16872 p.expandedChild = node;
16876 // private override
16877 setRootNode : function(node){
16878 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16879 if(!this.rootVisible){
16880 node.ui = new Roo.tree.RootTreeNodeUI(node);
16886 * Returns the container element for this TreePanel
16888 getEl : function(){
16893 * Returns the default TreeLoader for this TreePanel
16895 getLoader : function(){
16896 return this.loader;
16902 expandAll : function(){
16903 this.root.expand(true);
16907 * Collapse all nodes
16909 collapseAll : function(){
16910 this.root.collapse(true);
16914 * Returns the selection model used by this TreePanel
16916 getSelectionModel : function(){
16917 if(!this.selModel){
16918 this.selModel = new Roo.tree.DefaultSelectionModel();
16920 return this.selModel;
16924 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16925 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16926 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16929 getChecked : function(a, startNode){
16930 startNode = startNode || this.root;
16932 var f = function(){
16933 if(this.attributes.checked){
16934 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16937 startNode.cascade(f);
16942 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16943 * @param {String} path
16944 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16945 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16946 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16948 expandPath : function(path, attr, callback){
16949 attr = attr || "id";
16950 var keys = path.split(this.pathSeparator);
16951 var curNode = this.root;
16952 if(curNode.attributes[attr] != keys[1]){ // invalid root
16954 callback(false, null);
16959 var f = function(){
16960 if(++index == keys.length){
16962 callback(true, curNode);
16966 var c = curNode.findChild(attr, keys[index]);
16969 callback(false, curNode);
16974 c.expand(false, false, f);
16976 curNode.expand(false, false, f);
16980 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16981 * @param {String} path
16982 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16983 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16984 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16986 selectPath : function(path, attr, callback){
16987 attr = attr || "id";
16988 var keys = path.split(this.pathSeparator);
16989 var v = keys.pop();
16990 if(keys.length > 0){
16991 var f = function(success, node){
16992 if(success && node){
16993 var n = node.findChild(attr, v);
16999 }else if(callback){
17000 callback(false, n);
17004 callback(false, n);
17008 this.expandPath(keys.join(this.pathSeparator), attr, f);
17010 this.root.select();
17012 callback(true, this.root);
17017 getTreeEl : function(){
17022 * Trigger rendering of this TreePanel
17024 render : function(){
17025 if (this.innerCt) {
17026 return this; // stop it rendering more than once!!
17029 this.innerCt = this.el.createChild({tag:"ul",
17030 cls:"x-tree-root-ct " +
17031 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
17033 if(this.containerScroll){
17034 Roo.dd.ScrollManager.register(this.el);
17036 if((this.enableDD || this.enableDrop) && !this.dropZone){
17038 * The dropZone used by this tree if drop is enabled
17039 * @type Roo.tree.TreeDropZone
17041 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
17042 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
17045 if((this.enableDD || this.enableDrag) && !this.dragZone){
17047 * The dragZone used by this tree if drag is enabled
17048 * @type Roo.tree.TreeDragZone
17050 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
17051 ddGroup: this.ddGroup || "TreeDD",
17052 scroll: this.ddScroll
17055 this.getSelectionModel().init(this);
17057 Roo.log("ROOT not set in tree");
17060 this.root.render();
17061 if(!this.rootVisible){
17062 this.root.renderChildren();
17068 * Ext JS Library 1.1.1
17069 * Copyright(c) 2006-2007, Ext JS, LLC.
17071 * Originally Released Under LGPL - original licence link has changed is not relivant.
17074 * <script type="text/javascript">
17079 * @class Roo.tree.DefaultSelectionModel
17080 * @extends Roo.util.Observable
17081 * The default single selection for a TreePanel.
17082 * @param {Object} cfg Configuration
17084 Roo.tree.DefaultSelectionModel = function(cfg){
17085 this.selNode = null;
17091 * @event selectionchange
17092 * Fires when the selected node changes
17093 * @param {DefaultSelectionModel} this
17094 * @param {TreeNode} node the new selection
17096 "selectionchange" : true,
17099 * @event beforeselect
17100 * Fires before the selected node changes, return false to cancel the change
17101 * @param {DefaultSelectionModel} this
17102 * @param {TreeNode} node the new selection
17103 * @param {TreeNode} node the old selection
17105 "beforeselect" : true
17108 Roo.tree.DefaultSelectionModel.superclass.constructor.call(this,cfg);
17111 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
17112 init : function(tree){
17114 tree.getTreeEl().on("keydown", this.onKeyDown, this);
17115 tree.on("click", this.onNodeClick, this);
17118 onNodeClick : function(node, e){
17119 if (e.ctrlKey && this.selNode == node) {
17120 this.unselect(node);
17128 * @param {TreeNode} node The node to select
17129 * @return {TreeNode} The selected node
17131 select : function(node){
17132 var last = this.selNode;
17133 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
17135 last.ui.onSelectedChange(false);
17137 this.selNode = node;
17138 node.ui.onSelectedChange(true);
17139 this.fireEvent("selectionchange", this, node, last);
17146 * @param {TreeNode} node The node to unselect
17148 unselect : function(node){
17149 if(this.selNode == node){
17150 this.clearSelections();
17155 * Clear all selections
17157 clearSelections : function(){
17158 var n = this.selNode;
17160 n.ui.onSelectedChange(false);
17161 this.selNode = null;
17162 this.fireEvent("selectionchange", this, null);
17168 * Get the selected node
17169 * @return {TreeNode} The selected node
17171 getSelectedNode : function(){
17172 return this.selNode;
17176 * Returns true if the node is selected
17177 * @param {TreeNode} node The node to check
17178 * @return {Boolean}
17180 isSelected : function(node){
17181 return this.selNode == node;
17185 * Selects the node above the selected node in the tree, intelligently walking the nodes
17186 * @return TreeNode The new selection
17188 selectPrevious : function(){
17189 var s = this.selNode || this.lastSelNode;
17193 var ps = s.previousSibling;
17195 if(!ps.isExpanded() || ps.childNodes.length < 1){
17196 return this.select(ps);
17198 var lc = ps.lastChild;
17199 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
17202 return this.select(lc);
17204 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
17205 return this.select(s.parentNode);
17211 * Selects the node above the selected node in the tree, intelligently walking the nodes
17212 * @return TreeNode The new selection
17214 selectNext : function(){
17215 var s = this.selNode || this.lastSelNode;
17219 if(s.firstChild && s.isExpanded()){
17220 return this.select(s.firstChild);
17221 }else if(s.nextSibling){
17222 return this.select(s.nextSibling);
17223 }else if(s.parentNode){
17225 s.parentNode.bubble(function(){
17226 if(this.nextSibling){
17227 newS = this.getOwnerTree().selModel.select(this.nextSibling);
17236 onKeyDown : function(e){
17237 var s = this.selNode || this.lastSelNode;
17238 // undesirable, but required
17243 var k = e.getKey();
17251 this.selectPrevious();
17254 e.preventDefault();
17255 if(s.hasChildNodes()){
17256 if(!s.isExpanded()){
17258 }else if(s.firstChild){
17259 this.select(s.firstChild, e);
17264 e.preventDefault();
17265 if(s.hasChildNodes() && s.isExpanded()){
17267 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
17268 this.select(s.parentNode, e);
17276 * @class Roo.tree.MultiSelectionModel
17277 * @extends Roo.util.Observable
17278 * Multi selection for a TreePanel.
17279 * @param {Object} cfg Configuration
17281 Roo.tree.MultiSelectionModel = function(){
17282 this.selNodes = [];
17286 * @event selectionchange
17287 * Fires when the selected nodes change
17288 * @param {MultiSelectionModel} this
17289 * @param {Array} nodes Array of the selected nodes
17291 "selectionchange" : true
17293 Roo.tree.MultiSelectionModel.superclass.constructor.call(this,cfg);
17297 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
17298 init : function(tree){
17300 tree.getTreeEl().on("keydown", this.onKeyDown, this);
17301 tree.on("click", this.onNodeClick, this);
17304 onNodeClick : function(node, e){
17305 this.select(node, e, e.ctrlKey);
17310 * @param {TreeNode} node The node to select
17311 * @param {EventObject} e (optional) An event associated with the selection
17312 * @param {Boolean} keepExisting True to retain existing selections
17313 * @return {TreeNode} The selected node
17315 select : function(node, e, keepExisting){
17316 if(keepExisting !== true){
17317 this.clearSelections(true);
17319 if(this.isSelected(node)){
17320 this.lastSelNode = node;
17323 this.selNodes.push(node);
17324 this.selMap[node.id] = node;
17325 this.lastSelNode = node;
17326 node.ui.onSelectedChange(true);
17327 this.fireEvent("selectionchange", this, this.selNodes);
17333 * @param {TreeNode} node The node to unselect
17335 unselect : function(node){
17336 if(this.selMap[node.id]){
17337 node.ui.onSelectedChange(false);
17338 var sn = this.selNodes;
17341 index = sn.indexOf(node);
17343 for(var i = 0, len = sn.length; i < len; i++){
17351 this.selNodes.splice(index, 1);
17353 delete this.selMap[node.id];
17354 this.fireEvent("selectionchange", this, this.selNodes);
17359 * Clear all selections
17361 clearSelections : function(suppressEvent){
17362 var sn = this.selNodes;
17364 for(var i = 0, len = sn.length; i < len; i++){
17365 sn[i].ui.onSelectedChange(false);
17367 this.selNodes = [];
17369 if(suppressEvent !== true){
17370 this.fireEvent("selectionchange", this, this.selNodes);
17376 * Returns true if the node is selected
17377 * @param {TreeNode} node The node to check
17378 * @return {Boolean}
17380 isSelected : function(node){
17381 return this.selMap[node.id] ? true : false;
17385 * Returns an array of the selected nodes
17388 getSelectedNodes : function(){
17389 return this.selNodes;
17392 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17394 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17396 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17399 * Ext JS Library 1.1.1
17400 * Copyright(c) 2006-2007, Ext JS, LLC.
17402 * Originally Released Under LGPL - original licence link has changed is not relivant.
17405 * <script type="text/javascript">
17409 * @class Roo.tree.TreeNode
17410 * @extends Roo.data.Node
17411 * @cfg {String} text The text for this node
17412 * @cfg {Boolean} expanded true to start the node expanded
17413 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17414 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17415 * @cfg {Boolean} disabled true to start the node disabled
17416 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17417 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17418 * @cfg {String} cls A css class to be added to the node
17419 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17420 * @cfg {String} href URL of the link used for the node (defaults to #)
17421 * @cfg {String} hrefTarget target frame for the link
17422 * @cfg {String} qtip An Ext QuickTip for the node
17423 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17424 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17425 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17426 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17427 * (defaults to undefined with no checkbox rendered)
17429 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17431 Roo.tree.TreeNode = function(attributes){
17432 attributes = attributes || {};
17433 if(typeof attributes == "string"){
17434 attributes = {text: attributes};
17436 this.childrenRendered = false;
17437 this.rendered = false;
17438 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17439 this.expanded = attributes.expanded === true;
17440 this.isTarget = attributes.isTarget !== false;
17441 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17442 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17445 * Read-only. The text for this node. To change it use setText().
17448 this.text = attributes.text;
17450 * True if this node is disabled.
17453 this.disabled = attributes.disabled === true;
17457 * @event textchange
17458 * Fires when the text for this node is changed
17459 * @param {Node} this This node
17460 * @param {String} text The new text
17461 * @param {String} oldText The old text
17463 "textchange" : true,
17465 * @event beforeexpand
17466 * Fires before this node is expanded, return false to cancel.
17467 * @param {Node} this This node
17468 * @param {Boolean} deep
17469 * @param {Boolean} anim
17471 "beforeexpand" : true,
17473 * @event beforecollapse
17474 * Fires before this node is collapsed, return false to cancel.
17475 * @param {Node} this This node
17476 * @param {Boolean} deep
17477 * @param {Boolean} anim
17479 "beforecollapse" : true,
17482 * Fires when this node is expanded
17483 * @param {Node} this This node
17487 * @event disabledchange
17488 * Fires when the disabled status of this node changes
17489 * @param {Node} this This node
17490 * @param {Boolean} disabled
17492 "disabledchange" : true,
17495 * Fires when this node is collapsed
17496 * @param {Node} this This node
17500 * @event beforeclick
17501 * Fires before click processing. Return false to cancel the default action.
17502 * @param {Node} this This node
17503 * @param {Roo.EventObject} e The event object
17505 "beforeclick":true,
17507 * @event checkchange
17508 * Fires when a node with a checkbox's checked property changes
17509 * @param {Node} this This node
17510 * @param {Boolean} checked
17512 "checkchange":true,
17515 * Fires when this node is clicked
17516 * @param {Node} this This node
17517 * @param {Roo.EventObject} e The event object
17522 * Fires when this node is double clicked
17523 * @param {Node} this This node
17524 * @param {Roo.EventObject} e The event object
17528 * @event contextmenu
17529 * Fires when this node is right clicked
17530 * @param {Node} this This node
17531 * @param {Roo.EventObject} e The event object
17533 "contextmenu":true,
17535 * @event beforechildrenrendered
17536 * Fires right before the child nodes for this node are rendered
17537 * @param {Node} this This node
17539 "beforechildrenrendered":true
17542 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17545 * Read-only. The UI for this node
17548 this.ui = new uiClass(this);
17550 // finally support items[]
17551 if (typeof(this.attributes.items) == 'undefined' || !this.attributes.items) {
17556 Roo.each(this.attributes.items, function(c) {
17557 this.appendChild(Roo.factory(c,Roo.Tree));
17559 delete this.attributes.items;
17564 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17565 preventHScroll: true,
17567 * Returns true if this node is expanded
17568 * @return {Boolean}
17570 isExpanded : function(){
17571 return this.expanded;
17575 * Returns the UI object for this node
17576 * @return {TreeNodeUI}
17578 getUI : function(){
17582 // private override
17583 setFirstChild : function(node){
17584 var of = this.firstChild;
17585 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17586 if(this.childrenRendered && of && node != of){
17587 of.renderIndent(true, true);
17590 this.renderIndent(true, true);
17594 // private override
17595 setLastChild : function(node){
17596 var ol = this.lastChild;
17597 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17598 if(this.childrenRendered && ol && node != ol){
17599 ol.renderIndent(true, true);
17602 this.renderIndent(true, true);
17606 // these methods are overridden to provide lazy rendering support
17607 // private override
17608 appendChild : function()
17610 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17611 if(node && this.childrenRendered){
17614 this.ui.updateExpandIcon();
17618 // private override
17619 removeChild : function(node){
17620 this.ownerTree.getSelectionModel().unselect(node);
17621 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17622 // if it's been rendered remove dom node
17623 if(this.childrenRendered){
17626 if(this.childNodes.length < 1){
17627 this.collapse(false, false);
17629 this.ui.updateExpandIcon();
17631 if(!this.firstChild) {
17632 this.childrenRendered = false;
17637 // private override
17638 insertBefore : function(node, refNode){
17639 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17640 if(newNode && refNode && this.childrenRendered){
17643 this.ui.updateExpandIcon();
17648 * Sets the text for this node
17649 * @param {String} text
17651 setText : function(text){
17652 var oldText = this.text;
17654 this.attributes.text = text;
17655 if(this.rendered){ // event without subscribing
17656 this.ui.onTextChange(this, text, oldText);
17658 this.fireEvent("textchange", this, text, oldText);
17662 * Triggers selection of this node
17664 select : function(){
17665 this.getOwnerTree().getSelectionModel().select(this);
17669 * Triggers deselection of this node
17671 unselect : function(){
17672 this.getOwnerTree().getSelectionModel().unselect(this);
17676 * Returns true if this node is selected
17677 * @return {Boolean}
17679 isSelected : function(){
17680 return this.getOwnerTree().getSelectionModel().isSelected(this);
17684 * Expand this node.
17685 * @param {Boolean} deep (optional) True to expand all children as well
17686 * @param {Boolean} anim (optional) false to cancel the default animation
17687 * @param {Function} callback (optional) A callback to be called when
17688 * expanding this node completes (does not wait for deep expand to complete).
17689 * Called with 1 parameter, this node.
17691 expand : function(deep, anim, callback){
17692 if(!this.expanded){
17693 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17696 if(!this.childrenRendered){
17697 this.renderChildren();
17699 this.expanded = true;
17700 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17701 this.ui.animExpand(function(){
17702 this.fireEvent("expand", this);
17703 if(typeof callback == "function"){
17707 this.expandChildNodes(true);
17709 }.createDelegate(this));
17713 this.fireEvent("expand", this);
17714 if(typeof callback == "function"){
17719 if(typeof callback == "function"){
17724 this.expandChildNodes(true);
17728 isHiddenRoot : function(){
17729 return this.isRoot && !this.getOwnerTree().rootVisible;
17733 * Collapse this node.
17734 * @param {Boolean} deep (optional) True to collapse all children as well
17735 * @param {Boolean} anim (optional) false to cancel the default animation
17737 collapse : function(deep, anim){
17738 if(this.expanded && !this.isHiddenRoot()){
17739 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17742 this.expanded = false;
17743 if((this.getOwnerTree().animate && anim !== false) || anim){
17744 this.ui.animCollapse(function(){
17745 this.fireEvent("collapse", this);
17747 this.collapseChildNodes(true);
17749 }.createDelegate(this));
17752 this.ui.collapse();
17753 this.fireEvent("collapse", this);
17757 var cs = this.childNodes;
17758 for(var i = 0, len = cs.length; i < len; i++) {
17759 cs[i].collapse(true, false);
17765 delayedExpand : function(delay){
17766 if(!this.expandProcId){
17767 this.expandProcId = this.expand.defer(delay, this);
17772 cancelExpand : function(){
17773 if(this.expandProcId){
17774 clearTimeout(this.expandProcId);
17776 this.expandProcId = false;
17780 * Toggles expanded/collapsed state of the node
17782 toggle : function(){
17791 * Ensures all parent nodes are expanded
17793 ensureVisible : function(callback){
17794 var tree = this.getOwnerTree();
17795 tree.expandPath(this.parentNode.getPath(), false, function(){
17796 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17797 Roo.callback(callback);
17798 }.createDelegate(this));
17802 * Expand all child nodes
17803 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17805 expandChildNodes : function(deep){
17806 var cs = this.childNodes;
17807 for(var i = 0, len = cs.length; i < len; i++) {
17808 cs[i].expand(deep);
17813 * Collapse all child nodes
17814 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17816 collapseChildNodes : function(deep){
17817 var cs = this.childNodes;
17818 for(var i = 0, len = cs.length; i < len; i++) {
17819 cs[i].collapse(deep);
17824 * Disables this node
17826 disable : function(){
17827 this.disabled = true;
17829 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17830 this.ui.onDisableChange(this, true);
17832 this.fireEvent("disabledchange", this, true);
17836 * Enables this node
17838 enable : function(){
17839 this.disabled = false;
17840 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17841 this.ui.onDisableChange(this, false);
17843 this.fireEvent("disabledchange", this, false);
17847 renderChildren : function(suppressEvent){
17848 if(suppressEvent !== false){
17849 this.fireEvent("beforechildrenrendered", this);
17851 var cs = this.childNodes;
17852 for(var i = 0, len = cs.length; i < len; i++){
17853 cs[i].render(true);
17855 this.childrenRendered = true;
17859 sort : function(fn, scope){
17860 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17861 if(this.childrenRendered){
17862 var cs = this.childNodes;
17863 for(var i = 0, len = cs.length; i < len; i++){
17864 cs[i].render(true);
17870 render : function(bulkRender){
17871 this.ui.render(bulkRender);
17872 if(!this.rendered){
17873 this.rendered = true;
17875 this.expanded = false;
17876 this.expand(false, false);
17882 renderIndent : function(deep, refresh){
17884 this.ui.childIndent = null;
17886 this.ui.renderIndent();
17887 if(deep === true && this.childrenRendered){
17888 var cs = this.childNodes;
17889 for(var i = 0, len = cs.length; i < len; i++){
17890 cs[i].renderIndent(true, refresh);
17896 * Ext JS Library 1.1.1
17897 * Copyright(c) 2006-2007, Ext JS, LLC.
17899 * Originally Released Under LGPL - original licence link has changed is not relivant.
17902 * <script type="text/javascript">
17906 * @class Roo.tree.AsyncTreeNode
17907 * @extends Roo.tree.TreeNode
17908 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17910 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17912 Roo.tree.AsyncTreeNode = function(config){
17913 this.loaded = false;
17914 this.loading = false;
17915 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17917 * @event beforeload
17918 * Fires before this node is loaded, return false to cancel
17919 * @param {Node} this This node
17921 this.addEvents({'beforeload':true, 'load': true});
17924 * Fires when this node is loaded
17925 * @param {Node} this This node
17928 * The loader used by this node (defaults to using the tree's defined loader)
17933 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17934 expand : function(deep, anim, callback){
17935 if(this.loading){ // if an async load is already running, waiting til it's done
17937 var f = function(){
17938 if(!this.loading){ // done loading
17939 clearInterval(timer);
17940 this.expand(deep, anim, callback);
17942 }.createDelegate(this);
17943 timer = setInterval(f, 200);
17947 if(this.fireEvent("beforeload", this) === false){
17950 this.loading = true;
17951 this.ui.beforeLoad(this);
17952 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17954 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17958 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17962 * Returns true if this node is currently loading
17963 * @return {Boolean}
17965 isLoading : function(){
17966 return this.loading;
17969 loadComplete : function(deep, anim, callback){
17970 this.loading = false;
17971 this.loaded = true;
17972 this.ui.afterLoad(this);
17973 this.fireEvent("load", this);
17974 this.expand(deep, anim, callback);
17978 * Returns true if this node has been loaded
17979 * @return {Boolean}
17981 isLoaded : function(){
17982 return this.loaded;
17985 hasChildNodes : function(){
17986 if(!this.isLeaf() && !this.loaded){
17989 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17994 * Trigger a reload for this node
17995 * @param {Function} callback
17997 reload : function(callback){
17998 this.collapse(false, false);
17999 while(this.firstChild){
18000 this.removeChild(this.firstChild);
18002 this.childrenRendered = false;
18003 this.loaded = false;
18004 if(this.isHiddenRoot()){
18005 this.expanded = false;
18007 this.expand(false, false, callback);
18011 * Ext JS Library 1.1.1
18012 * Copyright(c) 2006-2007, Ext JS, LLC.
18014 * Originally Released Under LGPL - original licence link has changed is not relivant.
18017 * <script type="text/javascript">
18021 * @class Roo.tree.TreeNodeUI
18023 * @param {Object} node The node to render
18024 * The TreeNode UI implementation is separate from the
18025 * tree implementation. Unless you are customizing the tree UI,
18026 * you should never have to use this directly.
18028 Roo.tree.TreeNodeUI = function(node){
18030 this.rendered = false;
18031 this.animating = false;
18032 this.emptyIcon = Roo.BLANK_IMAGE_URL;
18035 Roo.tree.TreeNodeUI.prototype = {
18036 removeChild : function(node){
18038 this.ctNode.removeChild(node.ui.getEl());
18042 beforeLoad : function(){
18043 this.addClass("x-tree-node-loading");
18046 afterLoad : function(){
18047 this.removeClass("x-tree-node-loading");
18050 onTextChange : function(node, text, oldText){
18052 this.textNode.innerHTML = text;
18056 onDisableChange : function(node, state){
18057 this.disabled = state;
18059 this.addClass("x-tree-node-disabled");
18061 this.removeClass("x-tree-node-disabled");
18065 onSelectedChange : function(state){
18068 this.addClass("x-tree-selected");
18071 this.removeClass("x-tree-selected");
18075 onMove : function(tree, node, oldParent, newParent, index, refNode){
18076 this.childIndent = null;
18078 var targetNode = newParent.ui.getContainer();
18079 if(!targetNode){//target not rendered
18080 this.holder = document.createElement("div");
18081 this.holder.appendChild(this.wrap);
18084 var insertBefore = refNode ? refNode.ui.getEl() : null;
18086 targetNode.insertBefore(this.wrap, insertBefore);
18088 targetNode.appendChild(this.wrap);
18090 this.node.renderIndent(true);
18094 addClass : function(cls){
18096 Roo.fly(this.elNode).addClass(cls);
18100 removeClass : function(cls){
18102 Roo.fly(this.elNode).removeClass(cls);
18106 remove : function(){
18108 this.holder = document.createElement("div");
18109 this.holder.appendChild(this.wrap);
18113 fireEvent : function(){
18114 return this.node.fireEvent.apply(this.node, arguments);
18117 initEvents : function(){
18118 this.node.on("move", this.onMove, this);
18119 var E = Roo.EventManager;
18120 var a = this.anchor;
18122 var el = Roo.fly(a, '_treeui');
18124 if(Roo.isOpera){ // opera render bug ignores the CSS
18125 el.setStyle("text-decoration", "none");
18128 el.on("click", this.onClick, this);
18129 el.on("dblclick", this.onDblClick, this);
18132 Roo.EventManager.on(this.checkbox,
18133 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
18136 el.on("contextmenu", this.onContextMenu, this);
18138 var icon = Roo.fly(this.iconNode);
18139 icon.on("click", this.onClick, this);
18140 icon.on("dblclick", this.onDblClick, this);
18141 icon.on("contextmenu", this.onContextMenu, this);
18142 E.on(this.ecNode, "click", this.ecClick, this, true);
18144 if(this.node.disabled){
18145 this.addClass("x-tree-node-disabled");
18147 if(this.node.hidden){
18148 this.addClass("x-tree-node-disabled");
18150 var ot = this.node.getOwnerTree();
18151 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
18152 if(dd && (!this.node.isRoot || ot.rootVisible)){
18153 Roo.dd.Registry.register(this.elNode, {
18155 handles: this.getDDHandles(),
18161 getDDHandles : function(){
18162 return [this.iconNode, this.textNode];
18167 this.wrap.style.display = "none";
18173 this.wrap.style.display = "";
18177 onContextMenu : function(e){
18178 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
18179 e.preventDefault();
18181 this.fireEvent("contextmenu", this.node, e);
18185 onClick : function(e){
18190 if(this.fireEvent("beforeclick", this.node, e) !== false){
18191 if(!this.disabled && this.node.attributes.href){
18192 this.fireEvent("click", this.node, e);
18195 e.preventDefault();
18200 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
18201 this.node.toggle();
18204 this.fireEvent("click", this.node, e);
18210 onDblClick : function(e){
18211 e.preventDefault();
18216 this.toggleCheck();
18218 if(!this.animating && this.node.hasChildNodes()){
18219 this.node.toggle();
18221 this.fireEvent("dblclick", this.node, e);
18224 onCheckChange : function(){
18225 var checked = this.checkbox.checked;
18226 this.node.attributes.checked = checked;
18227 this.fireEvent('checkchange', this.node, checked);
18230 ecClick : function(e){
18231 if(!this.animating && this.node.hasChildNodes()){
18232 this.node.toggle();
18236 startDrop : function(){
18237 this.dropping = true;
18240 // delayed drop so the click event doesn't get fired on a drop
18241 endDrop : function(){
18242 setTimeout(function(){
18243 this.dropping = false;
18244 }.createDelegate(this), 50);
18247 expand : function(){
18248 this.updateExpandIcon();
18249 this.ctNode.style.display = "";
18252 focus : function(){
18253 if(!this.node.preventHScroll){
18254 try{this.anchor.focus();
18256 }else if(!Roo.isIE){
18258 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
18259 var l = noscroll.scrollLeft;
18260 this.anchor.focus();
18261 noscroll.scrollLeft = l;
18266 toggleCheck : function(value){
18267 var cb = this.checkbox;
18269 cb.checked = (value === undefined ? !cb.checked : value);
18275 this.anchor.blur();
18279 animExpand : function(callback){
18280 var ct = Roo.get(this.ctNode);
18282 if(!this.node.hasChildNodes()){
18283 this.updateExpandIcon();
18284 this.ctNode.style.display = "";
18285 Roo.callback(callback);
18288 this.animating = true;
18289 this.updateExpandIcon();
18292 callback : function(){
18293 this.animating = false;
18294 Roo.callback(callback);
18297 duration: this.node.ownerTree.duration || .25
18301 highlight : function(){
18302 var tree = this.node.getOwnerTree();
18303 Roo.fly(this.wrap).highlight(
18304 tree.hlColor || "C3DAF9",
18305 {endColor: tree.hlBaseColor}
18309 collapse : function(){
18310 this.updateExpandIcon();
18311 this.ctNode.style.display = "none";
18314 animCollapse : function(callback){
18315 var ct = Roo.get(this.ctNode);
18316 ct.enableDisplayMode('block');
18319 this.animating = true;
18320 this.updateExpandIcon();
18323 callback : function(){
18324 this.animating = false;
18325 Roo.callback(callback);
18328 duration: this.node.ownerTree.duration || .25
18332 getContainer : function(){
18333 return this.ctNode;
18336 getEl : function(){
18340 appendDDGhost : function(ghostNode){
18341 ghostNode.appendChild(this.elNode.cloneNode(true));
18344 getDDRepairXY : function(){
18345 return Roo.lib.Dom.getXY(this.iconNode);
18348 onRender : function(){
18352 render : function(bulkRender){
18353 var n = this.node, a = n.attributes;
18354 var targetNode = n.parentNode ?
18355 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
18357 if(!this.rendered){
18358 this.rendered = true;
18360 this.renderElements(n, a, targetNode, bulkRender);
18363 if(this.textNode.setAttributeNS){
18364 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
18366 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
18369 this.textNode.setAttribute("ext:qtip", a.qtip);
18371 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
18374 }else if(a.qtipCfg){
18375 a.qtipCfg.target = Roo.id(this.textNode);
18376 Roo.QuickTips.register(a.qtipCfg);
18379 if(!this.node.expanded){
18380 this.updateExpandIcon();
18383 if(bulkRender === true) {
18384 targetNode.appendChild(this.wrap);
18389 renderElements : function(n, a, targetNode, bulkRender)
18391 // add some indent caching, this helps performance when rendering a large tree
18392 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18393 var t = n.getOwnerTree();
18394 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18395 if (typeof(n.attributes.html) != 'undefined') {
18396 txt = n.attributes.html;
18398 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18399 var cb = typeof a.checked == 'boolean';
18400 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18401 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18402 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18403 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18404 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18405 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18406 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18407 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18408 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18409 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18412 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18413 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18414 n.nextSibling.ui.getEl(), buf.join(""));
18416 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18419 this.elNode = this.wrap.childNodes[0];
18420 this.ctNode = this.wrap.childNodes[1];
18421 var cs = this.elNode.childNodes;
18422 this.indentNode = cs[0];
18423 this.ecNode = cs[1];
18424 this.iconNode = cs[2];
18427 this.checkbox = cs[3];
18430 this.anchor = cs[index];
18431 this.textNode = cs[index].firstChild;
18434 getAnchor : function(){
18435 return this.anchor;
18438 getTextEl : function(){
18439 return this.textNode;
18442 getIconEl : function(){
18443 return this.iconNode;
18446 isChecked : function(){
18447 return this.checkbox ? this.checkbox.checked : false;
18450 updateExpandIcon : function(){
18452 var n = this.node, c1, c2;
18453 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18454 var hasChild = n.hasChildNodes();
18458 c1 = "x-tree-node-collapsed";
18459 c2 = "x-tree-node-expanded";
18462 c1 = "x-tree-node-expanded";
18463 c2 = "x-tree-node-collapsed";
18466 this.removeClass("x-tree-node-leaf");
18467 this.wasLeaf = false;
18469 if(this.c1 != c1 || this.c2 != c2){
18470 Roo.fly(this.elNode).replaceClass(c1, c2);
18471 this.c1 = c1; this.c2 = c2;
18474 // this changes non-leafs into leafs if they have no children.
18475 // it's not very rational behaviour..
18477 if(!this.wasLeaf && this.node.leaf){
18478 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18481 this.wasLeaf = true;
18484 var ecc = "x-tree-ec-icon "+cls;
18485 if(this.ecc != ecc){
18486 this.ecNode.className = ecc;
18492 getChildIndent : function(){
18493 if(!this.childIndent){
18497 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18499 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18501 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18506 this.childIndent = buf.join("");
18508 return this.childIndent;
18511 renderIndent : function(){
18514 var p = this.node.parentNode;
18516 indent = p.ui.getChildIndent();
18518 if(this.indentMarkup != indent){ // don't rerender if not required
18519 this.indentNode.innerHTML = indent;
18520 this.indentMarkup = indent;
18522 this.updateExpandIcon();
18527 Roo.tree.RootTreeNodeUI = function(){
18528 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18530 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18531 render : function(){
18532 if(!this.rendered){
18533 var targetNode = this.node.ownerTree.innerCt.dom;
18534 this.node.expanded = true;
18535 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18536 this.wrap = this.ctNode = targetNode.firstChild;
18539 collapse : function(){
18541 expand : function(){
18545 * Ext JS Library 1.1.1
18546 * Copyright(c) 2006-2007, Ext JS, LLC.
18548 * Originally Released Under LGPL - original licence link has changed is not relivant.
18551 * <script type="text/javascript">
18554 * @class Roo.tree.TreeLoader
18555 * @extends Roo.util.Observable
18556 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18557 * nodes from a specified URL. The response must be a javascript Array definition
18558 * who's elements are node definition objects. eg:
18563 { 'id': 1, 'text': 'A folder Node', 'leaf': false },
18564 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }
18571 * The old style respose with just an array is still supported, but not recommended.
18574 * A server request is sent, and child nodes are loaded only when a node is expanded.
18575 * The loading node's id is passed to the server under the parameter name "node" to
18576 * enable the server to produce the correct child nodes.
18578 * To pass extra parameters, an event handler may be attached to the "beforeload"
18579 * event, and the parameters specified in the TreeLoader's baseParams property:
18581 myTreeLoader.on("beforeload", function(treeLoader, node) {
18582 this.baseParams.category = node.attributes.category;
18585 * This would pass an HTTP parameter called "category" to the server containing
18586 * the value of the Node's "category" attribute.
18588 * Creates a new Treeloader.
18589 * @param {Object} config A config object containing config properties.
18591 Roo.tree.TreeLoader = function(config){
18592 this.baseParams = {};
18593 this.requestMethod = "POST";
18594 Roo.apply(this, config);
18599 * @event beforeload
18600 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18601 * @param {Object} This TreeLoader object.
18602 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18603 * @param {Object} callback The callback function specified in the {@link #load} call.
18608 * Fires when the node has been successfuly loaded.
18609 * @param {Object} This TreeLoader object.
18610 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18611 * @param {Object} response The response object containing the data from the server.
18615 * @event loadexception
18616 * Fires if the network request failed.
18617 * @param {Object} This TreeLoader object.
18618 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18619 * @param {Object} response The response object containing the data from the server.
18621 loadexception : true,
18624 * Fires before a node is created, enabling you to return custom Node types
18625 * @param {Object} This TreeLoader object.
18626 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18631 Roo.tree.TreeLoader.superclass.constructor.call(this);
18634 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18636 * @cfg {String} dataUrl The URL from which to request a Json string which
18637 * specifies an array of node definition object representing the child nodes
18641 * @cfg {String} requestMethod either GET or POST
18642 * defaults to POST (due to BC)
18646 * @cfg {Object} baseParams (optional) An object containing properties which
18647 * specify HTTP parameters to be passed to each request for child nodes.
18650 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18651 * created by this loader. If the attributes sent by the server have an attribute in this object,
18652 * they take priority.
18655 * @cfg {Object} uiProviders (optional) An object containing properties which
18657 * DEPRECATED - use 'create' event handler to modify attributes - which affect creation.
18658 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18659 * <i>uiProvider</i> attribute of a returned child node is a string rather
18660 * than a reference to a TreeNodeUI implementation, this that string value
18661 * is used as a property name in the uiProviders object. You can define the provider named
18662 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18667 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18668 * child nodes before loading.
18670 clearOnLoad : true,
18673 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18674 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18675 * Grid query { data : [ .....] }
18680 * @cfg {String} queryParam (optional)
18681 * Name of the query as it will be passed on the querystring (defaults to 'node')
18682 * eg. the request will be ?node=[id]
18689 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18690 * This is called automatically when a node is expanded, but may be used to reload
18691 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18692 * @param {Roo.tree.TreeNode} node
18693 * @param {Function} callback
18695 load : function(node, callback){
18696 if(this.clearOnLoad){
18697 while(node.firstChild){
18698 node.removeChild(node.firstChild);
18701 if(node.attributes.children){ // preloaded json children
18702 var cs = node.attributes.children;
18703 for(var i = 0, len = cs.length; i < len; i++){
18704 node.appendChild(this.createNode(cs[i]));
18706 if(typeof callback == "function"){
18709 }else if(this.dataUrl){
18710 this.requestData(node, callback);
18714 getParams: function(node){
18715 var buf = [], bp = this.baseParams;
18716 for(var key in bp){
18717 if(typeof bp[key] != "function"){
18718 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18721 var n = this.queryParam === false ? 'node' : this.queryParam;
18722 buf.push(n + "=", encodeURIComponent(node.id));
18723 return buf.join("");
18726 requestData : function(node, callback){
18727 if(this.fireEvent("beforeload", this, node, callback) !== false){
18728 this.transId = Roo.Ajax.request({
18729 method:this.requestMethod,
18730 url: this.dataUrl||this.url,
18731 success: this.handleResponse,
18732 failure: this.handleFailure,
18734 argument: {callback: callback, node: node},
18735 params: this.getParams(node)
18738 // if the load is cancelled, make sure we notify
18739 // the node that we are done
18740 if(typeof callback == "function"){
18746 isLoading : function(){
18747 return this.transId ? true : false;
18750 abort : function(){
18751 if(this.isLoading()){
18752 Roo.Ajax.abort(this.transId);
18757 createNode : function(attr)
18759 // apply baseAttrs, nice idea Corey!
18760 if(this.baseAttrs){
18761 Roo.applyIf(attr, this.baseAttrs);
18763 if(this.applyLoader !== false){
18764 attr.loader = this;
18766 // uiProvider = depreciated..
18768 if(typeof(attr.uiProvider) == 'string'){
18769 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18770 /** eval:var:attr */ eval(attr.uiProvider);
18772 if(typeof(this.uiProviders['default']) != 'undefined') {
18773 attr.uiProvider = this.uiProviders['default'];
18776 this.fireEvent('create', this, attr);
18778 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18780 new Roo.tree.TreeNode(attr) :
18781 new Roo.tree.AsyncTreeNode(attr));
18784 processResponse : function(response, node, callback)
18786 var json = response.responseText;
18789 var o = Roo.decode(json);
18791 if (this.root === false && typeof(o.success) != undefined) {
18792 this.root = 'data'; // the default behaviour for list like data..
18795 if (this.root !== false && !o.success) {
18796 // it's a failure condition.
18797 var a = response.argument;
18798 this.fireEvent("loadexception", this, a.node, response);
18799 Roo.log("Load failed - should have a handler really");
18805 if (this.root !== false) {
18809 for(var i = 0, len = o.length; i < len; i++){
18810 var n = this.createNode(o[i]);
18812 node.appendChild(n);
18815 if(typeof callback == "function"){
18816 callback(this, node);
18819 this.handleFailure(response);
18823 handleResponse : function(response){
18824 this.transId = false;
18825 var a = response.argument;
18826 this.processResponse(response, a.node, a.callback);
18827 this.fireEvent("load", this, a.node, response);
18830 handleFailure : function(response)
18832 // should handle failure better..
18833 this.transId = false;
18834 var a = response.argument;
18835 this.fireEvent("loadexception", this, a.node, response);
18836 if(typeof a.callback == "function"){
18837 a.callback(this, a.node);
18842 * Ext JS Library 1.1.1
18843 * Copyright(c) 2006-2007, Ext JS, LLC.
18845 * Originally Released Under LGPL - original licence link has changed is not relivant.
18848 * <script type="text/javascript">
18852 * @class Roo.tree.TreeFilter
18853 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18854 * @param {TreePanel} tree
18855 * @param {Object} config (optional)
18857 Roo.tree.TreeFilter = function(tree, config){
18859 this.filtered = {};
18860 Roo.apply(this, config);
18863 Roo.tree.TreeFilter.prototype = {
18870 * Filter the data by a specific attribute.
18871 * @param {String/RegExp} value Either string that the attribute value
18872 * should start with or a RegExp to test against the attribute
18873 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18874 * @param {TreeNode} startNode (optional) The node to start the filter at.
18876 filter : function(value, attr, startNode){
18877 attr = attr || "text";
18879 if(typeof value == "string"){
18880 var vlen = value.length;
18881 // auto clear empty filter
18882 if(vlen == 0 && this.clearBlank){
18886 value = value.toLowerCase();
18888 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18890 }else if(value.exec){ // regex?
18892 return value.test(n.attributes[attr]);
18895 throw 'Illegal filter type, must be string or regex';
18897 this.filterBy(f, null, startNode);
18901 * Filter by a function. The passed function will be called with each
18902 * node in the tree (or from the startNode). If the function returns true, the node is kept
18903 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18904 * @param {Function} fn The filter function
18905 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18907 filterBy : function(fn, scope, startNode){
18908 startNode = startNode || this.tree.root;
18909 if(this.autoClear){
18912 var af = this.filtered, rv = this.reverse;
18913 var f = function(n){
18914 if(n == startNode){
18920 var m = fn.call(scope || n, n);
18928 startNode.cascade(f);
18931 if(typeof id != "function"){
18933 if(n && n.parentNode){
18934 n.parentNode.removeChild(n);
18942 * Clears the current filter. Note: with the "remove" option
18943 * set a filter cannot be cleared.
18945 clear : function(){
18947 var af = this.filtered;
18949 if(typeof id != "function"){
18956 this.filtered = {};
18961 * Ext JS Library 1.1.1
18962 * Copyright(c) 2006-2007, Ext JS, LLC.
18964 * Originally Released Under LGPL - original licence link has changed is not relivant.
18967 * <script type="text/javascript">
18972 * @class Roo.tree.TreeSorter
18973 * Provides sorting of nodes in a TreePanel
18975 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18976 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18977 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18978 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18979 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18980 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18982 * @param {TreePanel} tree
18983 * @param {Object} config
18985 Roo.tree.TreeSorter = function(tree, config){
18986 Roo.apply(this, config);
18987 tree.on("beforechildrenrendered", this.doSort, this);
18988 tree.on("append", this.updateSort, this);
18989 tree.on("insert", this.updateSort, this);
18991 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18992 var p = this.property || "text";
18993 var sortType = this.sortType;
18994 var fs = this.folderSort;
18995 var cs = this.caseSensitive === true;
18996 var leafAttr = this.leafAttr || 'leaf';
18998 this.sortFn = function(n1, n2){
19000 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
19003 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
19007 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
19008 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
19010 return dsc ? +1 : -1;
19012 return dsc ? -1 : +1;
19019 Roo.tree.TreeSorter.prototype = {
19020 doSort : function(node){
19021 node.sort(this.sortFn);
19024 compareNodes : function(n1, n2){
19025 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
19028 updateSort : function(tree, node){
19029 if(node.childrenRendered){
19030 this.doSort.defer(1, this, [node]);
19035 * Ext JS Library 1.1.1
19036 * Copyright(c) 2006-2007, Ext JS, LLC.
19038 * Originally Released Under LGPL - original licence link has changed is not relivant.
19041 * <script type="text/javascript">
19044 if(Roo.dd.DropZone){
19046 Roo.tree.TreeDropZone = function(tree, config){
19047 this.allowParentInsert = false;
19048 this.allowContainerDrop = false;
19049 this.appendOnly = false;
19050 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
19052 this.lastInsertClass = "x-tree-no-status";
19053 this.dragOverData = {};
19056 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
19057 ddGroup : "TreeDD",
19060 expandDelay : 1000,
19062 expandNode : function(node){
19063 if(node.hasChildNodes() && !node.isExpanded()){
19064 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
19068 queueExpand : function(node){
19069 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
19072 cancelExpand : function(){
19073 if(this.expandProcId){
19074 clearTimeout(this.expandProcId);
19075 this.expandProcId = false;
19079 isValidDropPoint : function(n, pt, dd, e, data){
19080 if(!n || !data){ return false; }
19081 var targetNode = n.node;
19082 var dropNode = data.node;
19083 // default drop rules
19084 if(!(targetNode && targetNode.isTarget && pt)){
19087 if(pt == "append" && targetNode.allowChildren === false){
19090 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
19093 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
19096 // reuse the object
19097 var overEvent = this.dragOverData;
19098 overEvent.tree = this.tree;
19099 overEvent.target = targetNode;
19100 overEvent.data = data;
19101 overEvent.point = pt;
19102 overEvent.source = dd;
19103 overEvent.rawEvent = e;
19104 overEvent.dropNode = dropNode;
19105 overEvent.cancel = false;
19106 var result = this.tree.fireEvent("nodedragover", overEvent);
19107 return overEvent.cancel === false && result !== false;
19110 getDropPoint : function(e, n, dd)
19114 return tn.allowChildren !== false ? "append" : false; // always append for root
19116 var dragEl = n.ddel;
19117 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
19118 var y = Roo.lib.Event.getPageY(e);
19119 //var noAppend = tn.allowChildren === false || tn.isLeaf();
19121 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
19122 var noAppend = tn.allowChildren === false;
19123 if(this.appendOnly || tn.parentNode.allowChildren === false){
19124 return noAppend ? false : "append";
19126 var noBelow = false;
19127 if(!this.allowParentInsert){
19128 noBelow = tn.hasChildNodes() && tn.isExpanded();
19130 var q = (b - t) / (noAppend ? 2 : 3);
19131 if(y >= t && y < (t + q)){
19133 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
19140 onNodeEnter : function(n, dd, e, data)
19142 this.cancelExpand();
19145 onNodeOver : function(n, dd, e, data)
19148 var pt = this.getDropPoint(e, n, dd);
19151 // auto node expand check
19152 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
19153 this.queueExpand(node);
19154 }else if(pt != "append"){
19155 this.cancelExpand();
19158 // set the insert point style on the target node
19159 var returnCls = this.dropNotAllowed;
19160 if(this.isValidDropPoint(n, pt, dd, e, data)){
19165 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
19166 cls = "x-tree-drag-insert-above";
19167 }else if(pt == "below"){
19168 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
19169 cls = "x-tree-drag-insert-below";
19171 returnCls = "x-tree-drop-ok-append";
19172 cls = "x-tree-drag-append";
19174 if(this.lastInsertClass != cls){
19175 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
19176 this.lastInsertClass = cls;
19183 onNodeOut : function(n, dd, e, data){
19185 this.cancelExpand();
19186 this.removeDropIndicators(n);
19189 onNodeDrop : function(n, dd, e, data){
19190 var point = this.getDropPoint(e, n, dd);
19191 var targetNode = n.node;
19192 targetNode.ui.startDrop();
19193 if(!this.isValidDropPoint(n, point, dd, e, data)){
19194 targetNode.ui.endDrop();
19197 // first try to find the drop node
19198 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
19201 target: targetNode,
19206 dropNode: dropNode,
19209 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
19210 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
19211 targetNode.ui.endDrop();
19214 // allow target changing
19215 targetNode = dropEvent.target;
19216 if(point == "append" && !targetNode.isExpanded()){
19217 targetNode.expand(false, null, function(){
19218 this.completeDrop(dropEvent);
19219 }.createDelegate(this));
19221 this.completeDrop(dropEvent);
19226 completeDrop : function(de){
19227 var ns = de.dropNode, p = de.point, t = de.target;
19228 if(!(ns instanceof Array)){
19232 for(var i = 0, len = ns.length; i < len; i++){
19235 t.parentNode.insertBefore(n, t);
19236 }else if(p == "below"){
19237 t.parentNode.insertBefore(n, t.nextSibling);
19243 if(this.tree.hlDrop){
19247 this.tree.fireEvent("nodedrop", de);
19250 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
19251 if(this.tree.hlDrop){
19252 dropNode.ui.focus();
19253 dropNode.ui.highlight();
19255 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
19258 getTree : function(){
19262 removeDropIndicators : function(n){
19265 Roo.fly(el).removeClass([
19266 "x-tree-drag-insert-above",
19267 "x-tree-drag-insert-below",
19268 "x-tree-drag-append"]);
19269 this.lastInsertClass = "_noclass";
19273 beforeDragDrop : function(target, e, id){
19274 this.cancelExpand();
19278 afterRepair : function(data){
19279 if(data && Roo.enableFx){
19280 data.node.ui.highlight();
19290 * Ext JS Library 1.1.1
19291 * Copyright(c) 2006-2007, Ext JS, LLC.
19293 * Originally Released Under LGPL - original licence link has changed is not relivant.
19296 * <script type="text/javascript">
19300 if(Roo.dd.DragZone){
19301 Roo.tree.TreeDragZone = function(tree, config){
19302 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
19306 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
19307 ddGroup : "TreeDD",
19309 onBeforeDrag : function(data, e){
19311 return n && n.draggable && !n.disabled;
19315 onInitDrag : function(e){
19316 var data = this.dragData;
19317 this.tree.getSelectionModel().select(data.node);
19318 this.proxy.update("");
19319 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
19320 this.tree.fireEvent("startdrag", this.tree, data.node, e);
19323 getRepairXY : function(e, data){
19324 return data.node.ui.getDDRepairXY();
19327 onEndDrag : function(data, e){
19328 this.tree.fireEvent("enddrag", this.tree, data.node, e);
19333 onValidDrop : function(dd, e, id){
19334 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
19338 beforeInvalidDrop : function(e, id){
19339 // this scrolls the original position back into view
19340 var sm = this.tree.getSelectionModel();
19341 sm.clearSelections();
19342 sm.select(this.dragData.node);
19347 * Ext JS Library 1.1.1
19348 * Copyright(c) 2006-2007, Ext JS, LLC.
19350 * Originally Released Under LGPL - original licence link has changed is not relivant.
19353 * <script type="text/javascript">
19356 * @class Roo.tree.TreeEditor
19357 * @extends Roo.Editor
19358 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
19359 * as the editor field.
19361 * @param {Object} config (used to be the tree panel.)
19362 * @param {Object} oldconfig DEPRECIATED Either a prebuilt {@link Roo.form.Field} instance or a Field config object
19364 * @cfg {Roo.tree.TreePanel} tree The tree to bind to.
19365 * @cfg {Roo.form.TextField|Object} field The field configuration
19369 Roo.tree.TreeEditor = function(config, oldconfig) { // was -- (tree, config){
19372 if (oldconfig) { // old style..
19373 field = oldconfig.events ? oldconfig : new Roo.form.TextField(oldconfig);
19376 tree = config.tree;
19377 config.field = config.field || {};
19378 config.field.xtype = 'TextField';
19379 field = Roo.factory(config.field, Roo.form);
19381 config = config || {};
19386 * @event beforenodeedit
19387 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
19388 * false from the handler of this event.
19389 * @param {Editor} this
19390 * @param {Roo.tree.Node} node
19392 "beforenodeedit" : true
19396 Roo.tree.TreeEditor.superclass.constructor.call(this, field, config);
19400 tree.on('beforeclick', this.beforeNodeClick, this);
19401 tree.getTreeEl().on('mousedown', this.hide, this);
19402 this.on('complete', this.updateNode, this);
19403 this.on('beforestartedit', this.fitToTree, this);
19404 this.on('startedit', this.bindScroll, this, {delay:10});
19405 this.on('specialkey', this.onSpecialKey, this);
19408 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
19410 * @cfg {String} alignment
19411 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
19417 * @cfg {Boolean} hideEl
19418 * True to hide the bound element while the editor is displayed (defaults to false)
19422 * @cfg {String} cls
19423 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
19425 cls: "x-small-editor x-tree-editor",
19427 * @cfg {Boolean} shim
19428 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
19434 * @cfg {Number} maxWidth
19435 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
19436 * the containing tree element's size, it will be automatically limited for you to the container width, taking
19437 * scroll and client offsets into account prior to each edit.
19444 fitToTree : function(ed, el){
19445 var td = this.tree.getTreeEl().dom, nd = el.dom;
19446 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
19447 td.scrollLeft = nd.offsetLeft;
19451 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
19452 this.setSize(w, '');
19454 return this.fireEvent('beforenodeedit', this, this.editNode);
19459 triggerEdit : function(node){
19460 this.completeEdit();
19461 this.editNode = node;
19462 this.startEdit(node.ui.textNode, node.text);
19466 bindScroll : function(){
19467 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19471 beforeNodeClick : function(node, e){
19472 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19473 this.lastClick = new Date();
19474 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19476 this.triggerEdit(node);
19483 updateNode : function(ed, value){
19484 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19485 this.editNode.setText(value);
19489 onHide : function(){
19490 Roo.tree.TreeEditor.superclass.onHide.call(this);
19492 this.editNode.ui.focus();
19497 onSpecialKey : function(field, e){
19498 var k = e.getKey();
19502 }else if(k == e.ENTER && !e.hasModifier()){
19504 this.completeEdit();
19507 });//<Script type="text/javascript">
19510 * Ext JS Library 1.1.1
19511 * Copyright(c) 2006-2007, Ext JS, LLC.
19513 * Originally Released Under LGPL - original licence link has changed is not relivant.
19516 * <script type="text/javascript">
19520 * Not documented??? - probably should be...
19523 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19524 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19526 renderElements : function(n, a, targetNode, bulkRender){
19527 //consel.log("renderElements?");
19528 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19530 var t = n.getOwnerTree();
19531 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19533 var cols = t.columns;
19534 var bw = t.borderWidth;
19536 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19537 var cb = typeof a.checked == "boolean";
19538 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19539 var colcls = 'x-t-' + tid + '-c0';
19541 '<li class="x-tree-node">',
19544 '<div class="x-tree-node-el ', a.cls,'">',
19546 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19549 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19550 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19551 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19552 (a.icon ? ' x-tree-node-inline-icon' : ''),
19553 (a.iconCls ? ' '+a.iconCls : ''),
19554 '" unselectable="on" />',
19555 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19556 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19558 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19559 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19560 '<span unselectable="on" qtip="' + tx + '">',
19564 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19565 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19567 for(var i = 1, len = cols.length; i < len; i++){
19569 colcls = 'x-t-' + tid + '-c' +i;
19570 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19571 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19572 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19578 '<div class="x-clear"></div></div>',
19579 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19582 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19583 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19584 n.nextSibling.ui.getEl(), buf.join(""));
19586 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19588 var el = this.wrap.firstChild;
19590 this.elNode = el.firstChild;
19591 this.ranchor = el.childNodes[1];
19592 this.ctNode = this.wrap.childNodes[1];
19593 var cs = el.firstChild.childNodes;
19594 this.indentNode = cs[0];
19595 this.ecNode = cs[1];
19596 this.iconNode = cs[2];
19599 this.checkbox = cs[3];
19602 this.anchor = cs[index];
19604 this.textNode = cs[index].firstChild;
19606 //el.on("click", this.onClick, this);
19607 //el.on("dblclick", this.onDblClick, this);
19610 // console.log(this);
19612 initEvents : function(){
19613 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19616 var a = this.ranchor;
19618 var el = Roo.get(a);
19620 if(Roo.isOpera){ // opera render bug ignores the CSS
19621 el.setStyle("text-decoration", "none");
19624 el.on("click", this.onClick, this);
19625 el.on("dblclick", this.onDblClick, this);
19626 el.on("contextmenu", this.onContextMenu, this);
19630 /*onSelectedChange : function(state){
19633 this.addClass("x-tree-selected");
19636 this.removeClass("x-tree-selected");
19639 addClass : function(cls){
19641 Roo.fly(this.elRow).addClass(cls);
19647 removeClass : function(cls){
19649 Roo.fly(this.elRow).removeClass(cls);
19655 });//<Script type="text/javascript">
19659 * Ext JS Library 1.1.1
19660 * Copyright(c) 2006-2007, Ext JS, LLC.
19662 * Originally Released Under LGPL - original licence link has changed is not relivant.
19665 * <script type="text/javascript">
19670 * @class Roo.tree.ColumnTree
19671 * @extends Roo.data.TreePanel
19672 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19673 * @cfg {int} borderWidth compined right/left border allowance
19675 * @param {String/HTMLElement/Element} el The container element
19676 * @param {Object} config
19678 Roo.tree.ColumnTree = function(el, config)
19680 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19684 * Fire this event on a container when it resizes
19685 * @param {int} w Width
19686 * @param {int} h Height
19690 this.on('resize', this.onResize, this);
19693 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19697 borderWidth: Roo.isBorderBox ? 0 : 2,
19700 render : function(){
19701 // add the header.....
19703 Roo.tree.ColumnTree.superclass.render.apply(this);
19705 this.el.addClass('x-column-tree');
19707 this.headers = this.el.createChild(
19708 {cls:'x-tree-headers'},this.innerCt.dom);
19710 var cols = this.columns, c;
19711 var totalWidth = 0;
19713 var len = cols.length;
19714 for(var i = 0; i < len; i++){
19716 totalWidth += c.width;
19717 this.headEls.push(this.headers.createChild({
19718 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19720 cls:'x-tree-hd-text',
19723 style:'width:'+(c.width-this.borderWidth)+'px;'
19726 this.headers.createChild({cls:'x-clear'});
19727 // prevent floats from wrapping when clipped
19728 this.headers.setWidth(totalWidth);
19729 //this.innerCt.setWidth(totalWidth);
19730 this.innerCt.setStyle({ overflow: 'auto' });
19731 this.onResize(this.width, this.height);
19735 onResize : function(w,h)
19740 this.innerCt.setWidth(this.width);
19741 this.innerCt.setHeight(this.height-20);
19744 var cols = this.columns, c;
19745 var totalWidth = 0;
19747 var len = cols.length;
19748 for(var i = 0; i < len; i++){
19750 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19751 // it's the expander..
19752 expEl = this.headEls[i];
19755 totalWidth += c.width;
19759 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19761 this.headers.setWidth(w-20);
19770 * Ext JS Library 1.1.1
19771 * Copyright(c) 2006-2007, Ext JS, LLC.
19773 * Originally Released Under LGPL - original licence link has changed is not relivant.
19776 * <script type="text/javascript">
19780 * @class Roo.menu.Menu
19781 * @extends Roo.util.Observable
19782 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19783 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19785 * Creates a new Menu
19786 * @param {Object} config Configuration options
19788 Roo.menu.Menu = function(config){
19789 Roo.apply(this, config);
19790 this.id = this.id || Roo.id();
19793 * @event beforeshow
19794 * Fires before this menu is displayed
19795 * @param {Roo.menu.Menu} this
19799 * @event beforehide
19800 * Fires before this menu is hidden
19801 * @param {Roo.menu.Menu} this
19806 * Fires after this menu is displayed
19807 * @param {Roo.menu.Menu} this
19812 * Fires after this menu is hidden
19813 * @param {Roo.menu.Menu} this
19818 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19819 * @param {Roo.menu.Menu} this
19820 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19821 * @param {Roo.EventObject} e
19826 * Fires when the mouse is hovering over this menu
19827 * @param {Roo.menu.Menu} this
19828 * @param {Roo.EventObject} e
19829 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19834 * Fires when the mouse exits this menu
19835 * @param {Roo.menu.Menu} this
19836 * @param {Roo.EventObject} e
19837 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19842 * Fires when a menu item contained in this menu is clicked
19843 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19844 * @param {Roo.EventObject} e
19848 if (this.registerMenu) {
19849 Roo.menu.MenuMgr.register(this);
19852 var mis = this.items;
19853 this.items = new Roo.util.MixedCollection();
19855 this.add.apply(this, mis);
19859 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19861 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19865 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19866 * for bottom-right shadow (defaults to "sides")
19870 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19871 * this menu (defaults to "tl-tr?")
19873 subMenuAlign : "tl-tr?",
19875 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19876 * relative to its element of origin (defaults to "tl-bl?")
19878 defaultAlign : "tl-bl?",
19880 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19882 allowOtherMenus : false,
19884 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19886 registerMenu : true,
19891 render : function(){
19895 var el = this.el = new Roo.Layer({
19897 shadow:this.shadow,
19899 parentEl: this.parentEl || document.body,
19903 this.keyNav = new Roo.menu.MenuNav(this);
19906 el.addClass("x-menu-plain");
19909 el.addClass(this.cls);
19911 // generic focus element
19912 this.focusEl = el.createChild({
19913 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19915 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19916 ul.on("click", this.onClick, this);
19917 ul.on("mouseover", this.onMouseOver, this);
19918 ul.on("mouseout", this.onMouseOut, this);
19919 this.items.each(function(item){
19924 var li = document.createElement("li");
19925 li.className = "x-menu-list-item";
19926 ul.dom.appendChild(li);
19927 item.render(li, this);
19934 autoWidth : function(){
19935 var el = this.el, ul = this.ul;
19939 var w = this.width;
19942 }else if(Roo.isIE){
19943 el.setWidth(this.minWidth);
19944 var t = el.dom.offsetWidth; // force recalc
19945 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19950 delayAutoWidth : function(){
19953 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19955 this.awTask.delay(20);
19960 findTargetItem : function(e){
19961 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19962 if(t && t.menuItemId){
19963 return this.items.get(t.menuItemId);
19968 onClick : function(e){
19970 if(t = this.findTargetItem(e)){
19972 this.fireEvent("click", this, t, e);
19977 setActiveItem : function(item, autoExpand){
19978 if(item != this.activeItem){
19979 if(this.activeItem){
19980 this.activeItem.deactivate();
19982 this.activeItem = item;
19983 item.activate(autoExpand);
19984 }else if(autoExpand){
19990 tryActivate : function(start, step){
19991 var items = this.items;
19992 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19993 var item = items.get(i);
19994 if(!item.disabled && item.canActivate){
19995 this.setActiveItem(item, false);
20003 onMouseOver : function(e){
20005 if(t = this.findTargetItem(e)){
20006 if(t.canActivate && !t.disabled){
20007 this.setActiveItem(t, true);
20010 this.fireEvent("mouseover", this, e, t);
20014 onMouseOut : function(e){
20016 if(t = this.findTargetItem(e)){
20017 if(t == this.activeItem && t.shouldDeactivate(e)){
20018 this.activeItem.deactivate();
20019 delete this.activeItem;
20022 this.fireEvent("mouseout", this, e, t);
20026 * Read-only. Returns true if the menu is currently displayed, else false.
20029 isVisible : function(){
20030 return this.el && !this.hidden;
20034 * Displays this menu relative to another element
20035 * @param {String/HTMLElement/Roo.Element} element The element to align to
20036 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
20037 * the element (defaults to this.defaultAlign)
20038 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
20040 show : function(el, pos, parentMenu){
20041 this.parentMenu = parentMenu;
20045 this.fireEvent("beforeshow", this);
20046 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
20050 * Displays this menu at a specific xy position
20051 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
20052 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
20054 showAt : function(xy, parentMenu, /* private: */_e){
20055 this.parentMenu = parentMenu;
20060 this.fireEvent("beforeshow", this);
20061 xy = this.el.adjustForConstraints(xy);
20065 this.hidden = false;
20067 this.fireEvent("show", this);
20070 focus : function(){
20072 this.doFocus.defer(50, this);
20076 doFocus : function(){
20078 this.focusEl.focus();
20083 * Hides this menu and optionally all parent menus
20084 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
20086 hide : function(deep){
20087 if(this.el && this.isVisible()){
20088 this.fireEvent("beforehide", this);
20089 if(this.activeItem){
20090 this.activeItem.deactivate();
20091 this.activeItem = null;
20094 this.hidden = true;
20095 this.fireEvent("hide", this);
20097 if(deep === true && this.parentMenu){
20098 this.parentMenu.hide(true);
20103 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
20104 * Any of the following are valid:
20106 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
20107 * <li>An HTMLElement object which will be converted to a menu item</li>
20108 * <li>A menu item config object that will be created as a new menu item</li>
20109 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
20110 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
20115 var menu = new Roo.menu.Menu();
20117 // Create a menu item to add by reference
20118 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
20120 // Add a bunch of items at once using different methods.
20121 // Only the last item added will be returned.
20122 var item = menu.add(
20123 menuItem, // add existing item by ref
20124 'Dynamic Item', // new TextItem
20125 '-', // new separator
20126 { text: 'Config Item' } // new item by config
20129 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
20130 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
20133 var a = arguments, l = a.length, item;
20134 for(var i = 0; i < l; i++){
20136 if ((typeof(el) == "object") && el.xtype && el.xns) {
20137 el = Roo.factory(el, Roo.menu);
20140 if(el.render){ // some kind of Item
20141 item = this.addItem(el);
20142 }else if(typeof el == "string"){ // string
20143 if(el == "separator" || el == "-"){
20144 item = this.addSeparator();
20146 item = this.addText(el);
20148 }else if(el.tagName || el.el){ // element
20149 item = this.addElement(el);
20150 }else if(typeof el == "object"){ // must be menu item config?
20151 item = this.addMenuItem(el);
20158 * Returns this menu's underlying {@link Roo.Element} object
20159 * @return {Roo.Element} The element
20161 getEl : function(){
20169 * Adds a separator bar to the menu
20170 * @return {Roo.menu.Item} The menu item that was added
20172 addSeparator : function(){
20173 return this.addItem(new Roo.menu.Separator());
20177 * Adds an {@link Roo.Element} object to the menu
20178 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
20179 * @return {Roo.menu.Item} The menu item that was added
20181 addElement : function(el){
20182 return this.addItem(new Roo.menu.BaseItem(el));
20186 * Adds an existing object based on {@link Roo.menu.Item} to the menu
20187 * @param {Roo.menu.Item} item The menu item to add
20188 * @return {Roo.menu.Item} The menu item that was added
20190 addItem : function(item){
20191 this.items.add(item);
20193 var li = document.createElement("li");
20194 li.className = "x-menu-list-item";
20195 this.ul.dom.appendChild(li);
20196 item.render(li, this);
20197 this.delayAutoWidth();
20203 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
20204 * @param {Object} config A MenuItem config object
20205 * @return {Roo.menu.Item} The menu item that was added
20207 addMenuItem : function(config){
20208 if(!(config instanceof Roo.menu.Item)){
20209 if(typeof config.checked == "boolean"){ // must be check menu item config?
20210 config = new Roo.menu.CheckItem(config);
20212 config = new Roo.menu.Item(config);
20215 return this.addItem(config);
20219 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
20220 * @param {String} text The text to display in the menu item
20221 * @return {Roo.menu.Item} The menu item that was added
20223 addText : function(text){
20224 return this.addItem(new Roo.menu.TextItem({ text : text }));
20228 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
20229 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
20230 * @param {Roo.menu.Item} item The menu item to add
20231 * @return {Roo.menu.Item} The menu item that was added
20233 insert : function(index, item){
20234 this.items.insert(index, item);
20236 var li = document.createElement("li");
20237 li.className = "x-menu-list-item";
20238 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
20239 item.render(li, this);
20240 this.delayAutoWidth();
20246 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
20247 * @param {Roo.menu.Item} item The menu item to remove
20249 remove : function(item){
20250 this.items.removeKey(item.id);
20255 * Removes and destroys all items in the menu
20257 removeAll : function(){
20259 while(f = this.items.first()){
20265 // MenuNav is a private utility class used internally by the Menu
20266 Roo.menu.MenuNav = function(menu){
20267 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
20268 this.scope = this.menu = menu;
20271 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
20272 doRelay : function(e, h){
20273 var k = e.getKey();
20274 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
20275 this.menu.tryActivate(0, 1);
20278 return h.call(this.scope || this, e, this.menu);
20281 up : function(e, m){
20282 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
20283 m.tryActivate(m.items.length-1, -1);
20287 down : function(e, m){
20288 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
20289 m.tryActivate(0, 1);
20293 right : function(e, m){
20295 m.activeItem.expandMenu(true);
20299 left : function(e, m){
20301 if(m.parentMenu && m.parentMenu.activeItem){
20302 m.parentMenu.activeItem.activate();
20306 enter : function(e, m){
20308 e.stopPropagation();
20309 m.activeItem.onClick(e);
20310 m.fireEvent("click", this, m.activeItem);
20316 * Ext JS Library 1.1.1
20317 * Copyright(c) 2006-2007, Ext JS, LLC.
20319 * Originally Released Under LGPL - original licence link has changed is not relivant.
20322 * <script type="text/javascript">
20326 * @class Roo.menu.MenuMgr
20327 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
20330 Roo.menu.MenuMgr = function(){
20331 var menus, active, groups = {}, attached = false, lastShow = new Date();
20333 // private - called when first menu is created
20336 active = new Roo.util.MixedCollection();
20337 Roo.get(document).addKeyListener(27, function(){
20338 if(active.length > 0){
20345 function hideAll(){
20346 if(active && active.length > 0){
20347 var c = active.clone();
20348 c.each(function(m){
20355 function onHide(m){
20357 if(active.length < 1){
20358 Roo.get(document).un("mousedown", onMouseDown);
20364 function onShow(m){
20365 var last = active.last();
20366 lastShow = new Date();
20369 Roo.get(document).on("mousedown", onMouseDown);
20373 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
20374 m.parentMenu.activeChild = m;
20375 }else if(last && last.isVisible()){
20376 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
20381 function onBeforeHide(m){
20383 m.activeChild.hide();
20385 if(m.autoHideTimer){
20386 clearTimeout(m.autoHideTimer);
20387 delete m.autoHideTimer;
20392 function onBeforeShow(m){
20393 var pm = m.parentMenu;
20394 if(!pm && !m.allowOtherMenus){
20396 }else if(pm && pm.activeChild && active != m){
20397 pm.activeChild.hide();
20402 function onMouseDown(e){
20403 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
20409 function onBeforeCheck(mi, state){
20411 var g = groups[mi.group];
20412 for(var i = 0, l = g.length; i < l; i++){
20414 g[i].setChecked(false);
20423 * Hides all menus that are currently visible
20425 hideAll : function(){
20430 register : function(menu){
20434 menus[menu.id] = menu;
20435 menu.on("beforehide", onBeforeHide);
20436 menu.on("hide", onHide);
20437 menu.on("beforeshow", onBeforeShow);
20438 menu.on("show", onShow);
20439 var g = menu.group;
20440 if(g && menu.events["checkchange"]){
20444 groups[g].push(menu);
20445 menu.on("checkchange", onCheck);
20450 * Returns a {@link Roo.menu.Menu} object
20451 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
20452 * be used to generate and return a new Menu instance.
20454 get : function(menu){
20455 if(typeof menu == "string"){ // menu id
20456 return menus[menu];
20457 }else if(menu.events){ // menu instance
20459 }else if(typeof menu.length == 'number'){ // array of menu items?
20460 return new Roo.menu.Menu({items:menu});
20461 }else{ // otherwise, must be a config
20462 return new Roo.menu.Menu(menu);
20467 unregister : function(menu){
20468 delete menus[menu.id];
20469 menu.un("beforehide", onBeforeHide);
20470 menu.un("hide", onHide);
20471 menu.un("beforeshow", onBeforeShow);
20472 menu.un("show", onShow);
20473 var g = menu.group;
20474 if(g && menu.events["checkchange"]){
20475 groups[g].remove(menu);
20476 menu.un("checkchange", onCheck);
20481 registerCheckable : function(menuItem){
20482 var g = menuItem.group;
20487 groups[g].push(menuItem);
20488 menuItem.on("beforecheckchange", onBeforeCheck);
20493 unregisterCheckable : function(menuItem){
20494 var g = menuItem.group;
20496 groups[g].remove(menuItem);
20497 menuItem.un("beforecheckchange", onBeforeCheck);
20503 * Ext JS Library 1.1.1
20504 * Copyright(c) 2006-2007, Ext JS, LLC.
20506 * Originally Released Under LGPL - original licence link has changed is not relivant.
20509 * <script type="text/javascript">
20514 * @class Roo.menu.BaseItem
20515 * @extends Roo.Component
20516 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20517 * management and base configuration options shared by all menu components.
20519 * Creates a new BaseItem
20520 * @param {Object} config Configuration options
20522 Roo.menu.BaseItem = function(config){
20523 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20528 * Fires when this item is clicked
20529 * @param {Roo.menu.BaseItem} this
20530 * @param {Roo.EventObject} e
20535 * Fires when this item is activated
20536 * @param {Roo.menu.BaseItem} this
20540 * @event deactivate
20541 * Fires when this item is deactivated
20542 * @param {Roo.menu.BaseItem} this
20548 this.on("click", this.handler, this.scope, true);
20552 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20554 * @cfg {Function} handler
20555 * A function that will handle the click event of this menu item (defaults to undefined)
20558 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20560 canActivate : false,
20563 * @cfg {Boolean} hidden True to prevent creation of this menu item (defaults to false)
20568 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20570 activeClass : "x-menu-item-active",
20572 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20574 hideOnClick : true,
20576 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20581 ctype: "Roo.menu.BaseItem",
20584 actionMode : "container",
20587 render : function(container, parentMenu){
20588 this.parentMenu = parentMenu;
20589 Roo.menu.BaseItem.superclass.render.call(this, container);
20590 this.container.menuItemId = this.id;
20594 onRender : function(container, position){
20595 this.el = Roo.get(this.el);
20596 container.dom.appendChild(this.el.dom);
20600 onClick : function(e){
20601 if(!this.disabled && this.fireEvent("click", this, e) !== false
20602 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20603 this.handleClick(e);
20610 activate : function(){
20614 var li = this.container;
20615 li.addClass(this.activeClass);
20616 this.region = li.getRegion().adjust(2, 2, -2, -2);
20617 this.fireEvent("activate", this);
20622 deactivate : function(){
20623 this.container.removeClass(this.activeClass);
20624 this.fireEvent("deactivate", this);
20628 shouldDeactivate : function(e){
20629 return !this.region || !this.region.contains(e.getPoint());
20633 handleClick : function(e){
20634 if(this.hideOnClick){
20635 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20640 expandMenu : function(autoActivate){
20645 hideMenu : function(){
20650 * Ext JS Library 1.1.1
20651 * Copyright(c) 2006-2007, Ext JS, LLC.
20653 * Originally Released Under LGPL - original licence link has changed is not relivant.
20656 * <script type="text/javascript">
20660 * @class Roo.menu.Adapter
20661 * @extends Roo.menu.BaseItem
20662 * 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.
20663 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20665 * Creates a new Adapter
20666 * @param {Object} config Configuration options
20668 Roo.menu.Adapter = function(component, config){
20669 Roo.menu.Adapter.superclass.constructor.call(this, config);
20670 this.component = component;
20672 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20674 canActivate : true,
20677 onRender : function(container, position){
20678 this.component.render(container);
20679 this.el = this.component.getEl();
20683 activate : function(){
20687 this.component.focus();
20688 this.fireEvent("activate", this);
20693 deactivate : function(){
20694 this.fireEvent("deactivate", this);
20698 disable : function(){
20699 this.component.disable();
20700 Roo.menu.Adapter.superclass.disable.call(this);
20704 enable : function(){
20705 this.component.enable();
20706 Roo.menu.Adapter.superclass.enable.call(this);
20710 * Ext JS Library 1.1.1
20711 * Copyright(c) 2006-2007, Ext JS, LLC.
20713 * Originally Released Under LGPL - original licence link has changed is not relivant.
20716 * <script type="text/javascript">
20720 * @class Roo.menu.TextItem
20721 * @extends Roo.menu.BaseItem
20722 * Adds a static text string to a menu, usually used as either a heading or group separator.
20723 * Note: old style constructor with text is still supported.
20726 * Creates a new TextItem
20727 * @param {Object} cfg Configuration
20729 Roo.menu.TextItem = function(cfg){
20730 if (typeof(cfg) == 'string') {
20733 Roo.apply(this,cfg);
20736 Roo.menu.TextItem.superclass.constructor.call(this);
20739 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20741 * @cfg {Boolean} text Text to show on item.
20746 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20748 hideOnClick : false,
20750 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20752 itemCls : "x-menu-text",
20755 onRender : function(){
20756 var s = document.createElement("span");
20757 s.className = this.itemCls;
20758 s.innerHTML = this.text;
20760 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20764 * Ext JS Library 1.1.1
20765 * Copyright(c) 2006-2007, Ext JS, LLC.
20767 * Originally Released Under LGPL - original licence link has changed is not relivant.
20770 * <script type="text/javascript">
20774 * @class Roo.menu.Separator
20775 * @extends Roo.menu.BaseItem
20776 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20777 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20779 * @param {Object} config Configuration options
20781 Roo.menu.Separator = function(config){
20782 Roo.menu.Separator.superclass.constructor.call(this, config);
20785 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20787 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20789 itemCls : "x-menu-sep",
20791 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20793 hideOnClick : false,
20796 onRender : function(li){
20797 var s = document.createElement("span");
20798 s.className = this.itemCls;
20799 s.innerHTML = " ";
20801 li.addClass("x-menu-sep-li");
20802 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20806 * Ext JS Library 1.1.1
20807 * Copyright(c) 2006-2007, Ext JS, LLC.
20809 * Originally Released Under LGPL - original licence link has changed is not relivant.
20812 * <script type="text/javascript">
20815 * @class Roo.menu.Item
20816 * @extends Roo.menu.BaseItem
20817 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20818 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20819 * activation and click handling.
20821 * Creates a new Item
20822 * @param {Object} config Configuration options
20824 Roo.menu.Item = function(config){
20825 Roo.menu.Item.superclass.constructor.call(this, config);
20827 this.menu = Roo.menu.MenuMgr.get(this.menu);
20830 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20833 * @cfg {String} text
20834 * The text to show on the menu item.
20838 * @cfg {String} HTML to render in menu
20839 * The text to show on the menu item (HTML version).
20843 * @cfg {String} icon
20844 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20848 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20850 itemCls : "x-menu-item",
20852 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20854 canActivate : true,
20856 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20859 // doc'd in BaseItem
20863 ctype: "Roo.menu.Item",
20866 onRender : function(container, position){
20867 var el = document.createElement("a");
20868 el.hideFocus = true;
20869 el.unselectable = "on";
20870 el.href = this.href || "#";
20871 if(this.hrefTarget){
20872 el.target = this.hrefTarget;
20874 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20876 var html = this.html.length ? this.html : String.format('{0}',this.text);
20878 el.innerHTML = String.format(
20879 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20880 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20882 Roo.menu.Item.superclass.onRender.call(this, container, position);
20886 * Sets the text to display in this menu item
20887 * @param {String} text The text to display
20888 * @param {Boolean} isHTML true to indicate text is pure html.
20890 setText : function(text, isHTML){
20898 var html = this.html.length ? this.html : String.format('{0}',this.text);
20900 this.el.update(String.format(
20901 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20902 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20903 this.parentMenu.autoWidth();
20908 handleClick : function(e){
20909 if(!this.href){ // if no link defined, stop the event automatically
20912 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20916 activate : function(autoExpand){
20917 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20927 shouldDeactivate : function(e){
20928 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20929 if(this.menu && this.menu.isVisible()){
20930 return !this.menu.getEl().getRegion().contains(e.getPoint());
20938 deactivate : function(){
20939 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20944 expandMenu : function(autoActivate){
20945 if(!this.disabled && this.menu){
20946 clearTimeout(this.hideTimer);
20947 delete this.hideTimer;
20948 if(!this.menu.isVisible() && !this.showTimer){
20949 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20950 }else if (this.menu.isVisible() && autoActivate){
20951 this.menu.tryActivate(0, 1);
20957 deferExpand : function(autoActivate){
20958 delete this.showTimer;
20959 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20961 this.menu.tryActivate(0, 1);
20966 hideMenu : function(){
20967 clearTimeout(this.showTimer);
20968 delete this.showTimer;
20969 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20970 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20975 deferHide : function(){
20976 delete this.hideTimer;
20981 * Ext JS Library 1.1.1
20982 * Copyright(c) 2006-2007, Ext JS, LLC.
20984 * Originally Released Under LGPL - original licence link has changed is not relivant.
20987 * <script type="text/javascript">
20991 * @class Roo.menu.CheckItem
20992 * @extends Roo.menu.Item
20993 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20995 * Creates a new CheckItem
20996 * @param {Object} config Configuration options
20998 Roo.menu.CheckItem = function(config){
20999 Roo.menu.CheckItem.superclass.constructor.call(this, config);
21002 * @event beforecheckchange
21003 * Fires before the checked value is set, providing an opportunity to cancel if needed
21004 * @param {Roo.menu.CheckItem} this
21005 * @param {Boolean} checked The new checked value that will be set
21007 "beforecheckchange" : true,
21009 * @event checkchange
21010 * Fires after the checked value has been set
21011 * @param {Roo.menu.CheckItem} this
21012 * @param {Boolean} checked The checked value that was set
21014 "checkchange" : true
21016 if(this.checkHandler){
21017 this.on('checkchange', this.checkHandler, this.scope);
21020 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
21022 * @cfg {String} group
21023 * All check items with the same group name will automatically be grouped into a single-select
21024 * radio button group (defaults to '')
21027 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
21029 itemCls : "x-menu-item x-menu-check-item",
21031 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
21033 groupClass : "x-menu-group-item",
21036 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
21037 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
21038 * initialized with checked = true will be rendered as checked.
21043 ctype: "Roo.menu.CheckItem",
21046 onRender : function(c){
21047 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
21049 this.el.addClass(this.groupClass);
21051 Roo.menu.MenuMgr.registerCheckable(this);
21053 this.checked = false;
21054 this.setChecked(true, true);
21059 destroy : function(){
21061 Roo.menu.MenuMgr.unregisterCheckable(this);
21063 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
21067 * Set the checked state of this item
21068 * @param {Boolean} checked The new checked value
21069 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
21071 setChecked : function(state, suppressEvent){
21072 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
21073 if(this.container){
21074 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
21076 this.checked = state;
21077 if(suppressEvent !== true){
21078 this.fireEvent("checkchange", this, state);
21084 handleClick : function(e){
21085 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
21086 this.setChecked(!this.checked);
21088 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
21092 * Ext JS Library 1.1.1
21093 * Copyright(c) 2006-2007, Ext JS, LLC.
21095 * Originally Released Under LGPL - original licence link has changed is not relivant.
21098 * <script type="text/javascript">
21102 * @class Roo.menu.DateItem
21103 * @extends Roo.menu.Adapter
21104 * A menu item that wraps the {@link Roo.DatPicker} component.
21106 * Creates a new DateItem
21107 * @param {Object} config Configuration options
21109 Roo.menu.DateItem = function(config){
21110 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
21111 /** The Roo.DatePicker object @type Roo.DatePicker */
21112 this.picker = this.component;
21113 this.addEvents({select: true});
21115 this.picker.on("render", function(picker){
21116 picker.getEl().swallowEvent("click");
21117 picker.container.addClass("x-menu-date-item");
21120 this.picker.on("select", this.onSelect, this);
21123 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
21125 onSelect : function(picker, date){
21126 this.fireEvent("select", this, date, picker);
21127 Roo.menu.DateItem.superclass.handleClick.call(this);
21131 * Ext JS Library 1.1.1
21132 * Copyright(c) 2006-2007, Ext JS, LLC.
21134 * Originally Released Under LGPL - original licence link has changed is not relivant.
21137 * <script type="text/javascript">
21141 * @class Roo.menu.ColorItem
21142 * @extends Roo.menu.Adapter
21143 * A menu item that wraps the {@link Roo.ColorPalette} component.
21145 * Creates a new ColorItem
21146 * @param {Object} config Configuration options
21148 Roo.menu.ColorItem = function(config){
21149 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
21150 /** The Roo.ColorPalette object @type Roo.ColorPalette */
21151 this.palette = this.component;
21152 this.relayEvents(this.palette, ["select"]);
21153 if(this.selectHandler){
21154 this.on('select', this.selectHandler, this.scope);
21157 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
21159 * Ext JS Library 1.1.1
21160 * Copyright(c) 2006-2007, Ext JS, LLC.
21162 * Originally Released Under LGPL - original licence link has changed is not relivant.
21165 * <script type="text/javascript">
21170 * @class Roo.menu.DateMenu
21171 * @extends Roo.menu.Menu
21172 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
21174 * Creates a new DateMenu
21175 * @param {Object} config Configuration options
21177 Roo.menu.DateMenu = function(config){
21178 Roo.menu.DateMenu.superclass.constructor.call(this, config);
21180 var di = new Roo.menu.DateItem(config);
21183 * The {@link Roo.DatePicker} instance for this DateMenu
21186 this.picker = di.picker;
21189 * @param {DatePicker} picker
21190 * @param {Date} date
21192 this.relayEvents(di, ["select"]);
21193 this.on('beforeshow', function(){
21195 this.picker.hideMonthPicker(false);
21199 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
21203 * Ext JS Library 1.1.1
21204 * Copyright(c) 2006-2007, Ext JS, LLC.
21206 * Originally Released Under LGPL - original licence link has changed is not relivant.
21209 * <script type="text/javascript">
21214 * @class Roo.menu.ColorMenu
21215 * @extends Roo.menu.Menu
21216 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
21218 * Creates a new ColorMenu
21219 * @param {Object} config Configuration options
21221 Roo.menu.ColorMenu = function(config){
21222 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
21224 var ci = new Roo.menu.ColorItem(config);
21227 * The {@link Roo.ColorPalette} instance for this ColorMenu
21228 * @type ColorPalette
21230 this.palette = ci.palette;
21233 * @param {ColorPalette} palette
21234 * @param {String} color
21236 this.relayEvents(ci, ["select"]);
21238 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
21240 * Ext JS Library 1.1.1
21241 * Copyright(c) 2006-2007, Ext JS, LLC.
21243 * Originally Released Under LGPL - original licence link has changed is not relivant.
21246 * <script type="text/javascript">
21250 * @class Roo.form.Field
21251 * @extends Roo.BoxComponent
21252 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
21254 * Creates a new Field
21255 * @param {Object} config Configuration options
21257 Roo.form.Field = function(config){
21258 Roo.form.Field.superclass.constructor.call(this, config);
21261 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
21263 * @cfg {String} fieldLabel Label to use when rendering a form.
21266 * @cfg {String} qtip Mouse over tip
21270 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
21272 invalidClass : "x-form-invalid",
21274 * @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")
21276 invalidText : "The value in this field is invalid",
21278 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
21280 focusClass : "x-form-focus",
21282 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
21283 automatic validation (defaults to "keyup").
21285 validationEvent : "keyup",
21287 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
21289 validateOnBlur : true,
21291 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
21293 validationDelay : 250,
21295 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21296 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
21298 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
21300 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
21302 fieldClass : "x-form-field",
21304 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
21307 ----------- ----------------------------------------------------------------------
21308 qtip Display a quick tip when the user hovers over the field
21309 title Display a default browser title attribute popup
21310 under Add a block div beneath the field containing the error text
21311 side Add an error icon to the right of the field with a popup on hover
21312 [element id] Add the error text directly to the innerHTML of the specified element
21315 msgTarget : 'qtip',
21317 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
21322 * @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.
21327 * @cfg {Boolean} disabled True to disable the field (defaults to false).
21332 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
21334 inputType : undefined,
21337 * @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).
21339 tabIndex : undefined,
21342 isFormField : true,
21347 * @property {Roo.Element} fieldEl
21348 * Element Containing the rendered Field (with label etc.)
21351 * @cfg {Mixed} value A value to initialize this field with.
21356 * @cfg {String} name The field's HTML name attribute.
21359 * @cfg {String} cls A CSS class to apply to the field's underlying element.
21363 initComponent : function(){
21364 Roo.form.Field.superclass.initComponent.call(this);
21368 * Fires when this field receives input focus.
21369 * @param {Roo.form.Field} this
21374 * Fires when this field loses input focus.
21375 * @param {Roo.form.Field} this
21379 * @event specialkey
21380 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
21381 * {@link Roo.EventObject#getKey} to determine which key was pressed.
21382 * @param {Roo.form.Field} this
21383 * @param {Roo.EventObject} e The event object
21388 * Fires just before the field blurs if the field value has changed.
21389 * @param {Roo.form.Field} this
21390 * @param {Mixed} newValue The new value
21391 * @param {Mixed} oldValue The original value
21396 * Fires after the field has been marked as invalid.
21397 * @param {Roo.form.Field} this
21398 * @param {String} msg The validation message
21403 * Fires after the field has been validated with no errors.
21404 * @param {Roo.form.Field} this
21409 * Fires after the key up
21410 * @param {Roo.form.Field} this
21411 * @param {Roo.EventObject} e The event Object
21418 * Returns the name attribute of the field if available
21419 * @return {String} name The field name
21421 getName: function(){
21422 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
21426 onRender : function(ct, position){
21427 Roo.form.Field.superclass.onRender.call(this, ct, position);
21429 var cfg = this.getAutoCreate();
21431 cfg.name = typeof(this.name) == 'undefined' ? this.id : this.name;
21433 if (!cfg.name.length) {
21436 if(this.inputType){
21437 cfg.type = this.inputType;
21439 this.el = ct.createChild(cfg, position);
21441 var type = this.el.dom.type;
21443 if(type == 'password'){
21446 this.el.addClass('x-form-'+type);
21449 this.el.dom.readOnly = true;
21451 if(this.tabIndex !== undefined){
21452 this.el.dom.setAttribute('tabIndex', this.tabIndex);
21455 this.el.addClass([this.fieldClass, this.cls]);
21460 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
21461 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
21462 * @return {Roo.form.Field} this
21464 applyTo : function(target){
21465 this.allowDomMove = false;
21466 this.el = Roo.get(target);
21467 this.render(this.el.dom.parentNode);
21472 initValue : function(){
21473 if(this.value !== undefined){
21474 this.setValue(this.value);
21475 }else if(this.el.dom.value.length > 0){
21476 this.setValue(this.el.dom.value);
21481 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21483 isDirty : function() {
21484 if(this.disabled) {
21487 return String(this.getValue()) !== String(this.originalValue);
21491 afterRender : function(){
21492 Roo.form.Field.superclass.afterRender.call(this);
21497 fireKey : function(e){
21498 //Roo.log('field ' + e.getKey());
21499 if(e.isNavKeyPress()){
21500 this.fireEvent("specialkey", this, e);
21505 * Resets the current field value to the originally loaded value and clears any validation messages
21507 reset : function(){
21508 this.setValue(this.originalValue);
21509 this.clearInvalid();
21513 initEvents : function(){
21514 // safari killled keypress - so keydown is now used..
21515 this.el.on("keydown" , this.fireKey, this);
21516 this.el.on("focus", this.onFocus, this);
21517 this.el.on("blur", this.onBlur, this);
21518 this.el.relayEvent('keyup', this);
21520 // reference to original value for reset
21521 this.originalValue = this.getValue();
21525 onFocus : function(){
21526 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21527 this.el.addClass(this.focusClass);
21529 if(!this.hasFocus){
21530 this.hasFocus = true;
21531 this.startValue = this.getValue();
21532 this.fireEvent("focus", this);
21536 beforeBlur : Roo.emptyFn,
21539 onBlur : function(){
21541 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21542 this.el.removeClass(this.focusClass);
21544 this.hasFocus = false;
21545 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21548 var v = this.getValue();
21549 if(String(v) !== String(this.startValue)){
21550 this.fireEvent('change', this, v, this.startValue);
21552 this.fireEvent("blur", this);
21556 * Returns whether or not the field value is currently valid
21557 * @param {Boolean} preventMark True to disable marking the field invalid
21558 * @return {Boolean} True if the value is valid, else false
21560 isValid : function(preventMark){
21564 var restore = this.preventMark;
21565 this.preventMark = preventMark === true;
21566 var v = this.validateValue(this.processValue(this.getRawValue()));
21567 this.preventMark = restore;
21572 * Validates the field value
21573 * @return {Boolean} True if the value is valid, else false
21575 validate : function(){
21576 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21577 this.clearInvalid();
21583 processValue : function(value){
21588 // Subclasses should provide the validation implementation by overriding this
21589 validateValue : function(value){
21594 * Mark this field as invalid
21595 * @param {String} msg The validation message
21597 markInvalid : function(msg){
21598 if(!this.rendered || this.preventMark){ // not rendered
21601 this.el.addClass(this.invalidClass);
21602 msg = msg || this.invalidText;
21603 switch(this.msgTarget){
21605 this.el.dom.qtip = msg;
21606 this.el.dom.qclass = 'x-form-invalid-tip';
21607 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21608 Roo.QuickTips.enable();
21612 this.el.dom.title = msg;
21616 var elp = this.el.findParent('.x-form-element', 5, true);
21617 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21618 this.errorEl.setWidth(elp.getWidth(true)-20);
21620 this.errorEl.update(msg);
21621 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21624 if(!this.errorIcon){
21625 var elp = this.el.findParent('.x-form-element', 5, true);
21626 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21628 this.alignErrorIcon();
21629 this.errorIcon.dom.qtip = msg;
21630 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21631 this.errorIcon.show();
21632 this.on('resize', this.alignErrorIcon, this);
21635 var t = Roo.getDom(this.msgTarget);
21637 t.style.display = this.msgDisplay;
21640 this.fireEvent('invalid', this, msg);
21644 alignErrorIcon : function(){
21645 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21649 * Clear any invalid styles/messages for this field
21651 clearInvalid : function(){
21652 if(!this.rendered || this.preventMark){ // not rendered
21655 this.el.removeClass(this.invalidClass);
21656 switch(this.msgTarget){
21658 this.el.dom.qtip = '';
21661 this.el.dom.title = '';
21665 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21669 if(this.errorIcon){
21670 this.errorIcon.dom.qtip = '';
21671 this.errorIcon.hide();
21672 this.un('resize', this.alignErrorIcon, this);
21676 var t = Roo.getDom(this.msgTarget);
21678 t.style.display = 'none';
21681 this.fireEvent('valid', this);
21685 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21686 * @return {Mixed} value The field value
21688 getRawValue : function(){
21689 var v = this.el.getValue();
21695 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21696 * @return {Mixed} value The field value
21698 getValue : function(){
21699 var v = this.el.getValue();
21705 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21706 * @param {Mixed} value The value to set
21708 setRawValue : function(v){
21709 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21713 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21714 * @param {Mixed} value The value to set
21716 setValue : function(v){
21719 this.el.dom.value = (v === null || v === undefined ? '' : v);
21724 adjustSize : function(w, h){
21725 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21726 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21730 adjustWidth : function(tag, w){
21731 tag = tag.toLowerCase();
21732 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21733 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21734 if(tag == 'input'){
21737 if(tag == 'textarea'){
21740 }else if(Roo.isOpera){
21741 if(tag == 'input'){
21744 if(tag == 'textarea'){
21754 // anything other than normal should be considered experimental
21755 Roo.form.Field.msgFx = {
21757 show: function(msgEl, f){
21758 msgEl.setDisplayed('block');
21761 hide : function(msgEl, f){
21762 msgEl.setDisplayed(false).update('');
21767 show: function(msgEl, f){
21768 msgEl.slideIn('t', {stopFx:true});
21771 hide : function(msgEl, f){
21772 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21777 show: function(msgEl, f){
21778 msgEl.fixDisplay();
21779 msgEl.alignTo(f.el, 'tl-tr');
21780 msgEl.slideIn('l', {stopFx:true});
21783 hide : function(msgEl, f){
21784 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21789 * Ext JS Library 1.1.1
21790 * Copyright(c) 2006-2007, Ext JS, LLC.
21792 * Originally Released Under LGPL - original licence link has changed is not relivant.
21795 * <script type="text/javascript">
21800 * @class Roo.form.TextField
21801 * @extends Roo.form.Field
21802 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21803 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21805 * Creates a new TextField
21806 * @param {Object} config Configuration options
21808 Roo.form.TextField = function(config){
21809 Roo.form.TextField.superclass.constructor.call(this, config);
21813 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21814 * according to the default logic, but this event provides a hook for the developer to apply additional
21815 * logic at runtime to resize the field if needed.
21816 * @param {Roo.form.Field} this This text field
21817 * @param {Number} width The new field width
21823 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21825 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21829 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21833 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21837 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21841 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21845 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21847 disableKeyFilter : false,
21849 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21853 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21857 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21859 maxLength : Number.MAX_VALUE,
21861 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21863 minLengthText : "The minimum length for this field is {0}",
21865 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21867 maxLengthText : "The maximum length for this field is {0}",
21869 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21871 selectOnFocus : false,
21873 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21875 blankText : "This field is required",
21877 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21878 * If available, this function will be called only after the basic validators all return true, and will be passed the
21879 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21883 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21884 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21885 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21889 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21893 * @cfg {String} emptyText The default text to display in an empty field - placeholder... (defaults to null).
21899 initEvents : function()
21901 if (this.emptyText) {
21902 this.el.attr('placeholder', this.emptyText);
21905 Roo.form.TextField.superclass.initEvents.call(this);
21906 if(this.validationEvent == 'keyup'){
21907 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21908 this.el.on('keyup', this.filterValidation, this);
21910 else if(this.validationEvent !== false){
21911 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21914 if(this.selectOnFocus){
21915 this.on("focus", this.preFocus, this);
21918 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21919 this.el.on("keypress", this.filterKeys, this);
21922 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21923 this.el.on("click", this.autoSize, this);
21925 if(this.el.is('input[type=password]') && Roo.isSafari){
21926 this.el.on('keydown', this.SafariOnKeyDown, this);
21930 processValue : function(value){
21931 if(this.stripCharsRe){
21932 var newValue = value.replace(this.stripCharsRe, '');
21933 if(newValue !== value){
21934 this.setRawValue(newValue);
21941 filterValidation : function(e){
21942 if(!e.isNavKeyPress()){
21943 this.validationTask.delay(this.validationDelay);
21948 onKeyUp : function(e){
21949 if(!e.isNavKeyPress()){
21955 * Resets the current field value to the originally-loaded value and clears any validation messages.
21958 reset : function(){
21959 Roo.form.TextField.superclass.reset.call(this);
21965 preFocus : function(){
21967 if(this.selectOnFocus){
21968 this.el.dom.select();
21974 filterKeys : function(e){
21975 var k = e.getKey();
21976 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21979 var c = e.getCharCode(), cc = String.fromCharCode(c);
21980 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21983 if(!this.maskRe.test(cc)){
21988 setValue : function(v){
21990 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21996 * Validates a value according to the field's validation rules and marks the field as invalid
21997 * if the validation fails
21998 * @param {Mixed} value The value to validate
21999 * @return {Boolean} True if the value is valid, else false
22001 validateValue : function(value){
22002 if(value.length < 1) { // if it's blank
22003 if(this.allowBlank){
22004 this.clearInvalid();
22007 this.markInvalid(this.blankText);
22011 if(value.length < this.minLength){
22012 this.markInvalid(String.format(this.minLengthText, this.minLength));
22015 if(value.length > this.maxLength){
22016 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
22020 var vt = Roo.form.VTypes;
22021 if(!vt[this.vtype](value, this)){
22022 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
22026 if(typeof this.validator == "function"){
22027 var msg = this.validator(value);
22029 this.markInvalid(msg);
22033 if(this.regex && !this.regex.test(value)){
22034 this.markInvalid(this.regexText);
22041 * Selects text in this field
22042 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
22043 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
22045 selectText : function(start, end){
22046 var v = this.getRawValue();
22048 start = start === undefined ? 0 : start;
22049 end = end === undefined ? v.length : end;
22050 var d = this.el.dom;
22051 if(d.setSelectionRange){
22052 d.setSelectionRange(start, end);
22053 }else if(d.createTextRange){
22054 var range = d.createTextRange();
22055 range.moveStart("character", start);
22056 range.moveEnd("character", v.length-end);
22063 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
22064 * This only takes effect if grow = true, and fires the autosize event.
22066 autoSize : function(){
22067 if(!this.grow || !this.rendered){
22071 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
22074 var v = el.dom.value;
22075 var d = document.createElement('div');
22076 d.appendChild(document.createTextNode(v));
22080 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
22081 this.el.setWidth(w);
22082 this.fireEvent("autosize", this, w);
22086 SafariOnKeyDown : function(event)
22088 // this is a workaround for a password hang bug on chrome/ webkit.
22090 var isSelectAll = false;
22092 if(this.el.dom.selectionEnd > 0){
22093 isSelectAll = (this.el.dom.selectionEnd - this.el.dom.selectionStart - this.getValue().length == 0) ? true : false;
22095 if(((event.getKey() == 8 || event.getKey() == 46) && this.getValue().length ==1)){ // backspace and delete key
22096 event.preventDefault();
22101 if(isSelectAll){ // backspace and delete key
22103 event.preventDefault();
22104 // this is very hacky as keydown always get's upper case.
22106 var cc = String.fromCharCode(event.getCharCode());
22107 this.setValue( event.shiftKey ? cc : cc.toLowerCase());
22115 * Ext JS Library 1.1.1
22116 * Copyright(c) 2006-2007, Ext JS, LLC.
22118 * Originally Released Under LGPL - original licence link has changed is not relivant.
22121 * <script type="text/javascript">
22125 * @class Roo.form.Hidden
22126 * @extends Roo.form.TextField
22127 * Simple Hidden element used on forms
22129 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
22132 * Creates a new Hidden form element.
22133 * @param {Object} config Configuration options
22138 // easy hidden field...
22139 Roo.form.Hidden = function(config){
22140 Roo.form.Hidden.superclass.constructor.call(this, config);
22143 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
22145 inputType: 'hidden',
22148 labelSeparator: '',
22150 itemCls : 'x-form-item-display-none'
22158 * Ext JS Library 1.1.1
22159 * Copyright(c) 2006-2007, Ext JS, LLC.
22161 * Originally Released Under LGPL - original licence link has changed is not relivant.
22164 * <script type="text/javascript">
22168 * @class Roo.form.TriggerField
22169 * @extends Roo.form.TextField
22170 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
22171 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
22172 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
22173 * for which you can provide a custom implementation. For example:
22175 var trigger = new Roo.form.TriggerField();
22176 trigger.onTriggerClick = myTriggerFn;
22177 trigger.applyTo('my-field');
22180 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
22181 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
22182 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22183 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
22185 * Create a new TriggerField.
22186 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
22187 * to the base TextField)
22189 Roo.form.TriggerField = function(config){
22190 this.mimicing = false;
22191 Roo.form.TriggerField.superclass.constructor.call(this, config);
22194 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
22196 * @cfg {String} triggerClass A CSS class to apply to the trigger
22199 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
22200 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
22202 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
22204 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
22208 /** @cfg {Boolean} grow @hide */
22209 /** @cfg {Number} growMin @hide */
22210 /** @cfg {Number} growMax @hide */
22216 autoSize: Roo.emptyFn,
22220 deferHeight : true,
22223 actionMode : 'wrap',
22225 onResize : function(w, h){
22226 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
22227 if(typeof w == 'number'){
22228 var x = w - this.trigger.getWidth();
22229 this.el.setWidth(this.adjustWidth('input', x));
22230 this.trigger.setStyle('left', x+'px');
22235 adjustSize : Roo.BoxComponent.prototype.adjustSize,
22238 getResizeEl : function(){
22243 getPositionEl : function(){
22248 alignErrorIcon : function(){
22249 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
22253 onRender : function(ct, position){
22254 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
22255 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
22256 this.trigger = this.wrap.createChild(this.triggerConfig ||
22257 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
22258 if(this.hideTrigger){
22259 this.trigger.setDisplayed(false);
22261 this.initTrigger();
22263 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
22268 initTrigger : function(){
22269 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
22270 this.trigger.addClassOnOver('x-form-trigger-over');
22271 this.trigger.addClassOnClick('x-form-trigger-click');
22275 onDestroy : function(){
22277 this.trigger.removeAllListeners();
22278 this.trigger.remove();
22281 this.wrap.remove();
22283 Roo.form.TriggerField.superclass.onDestroy.call(this);
22287 onFocus : function(){
22288 Roo.form.TriggerField.superclass.onFocus.call(this);
22289 if(!this.mimicing){
22290 this.wrap.addClass('x-trigger-wrap-focus');
22291 this.mimicing = true;
22292 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
22293 if(this.monitorTab){
22294 this.el.on("keydown", this.checkTab, this);
22300 checkTab : function(e){
22301 if(e.getKey() == e.TAB){
22302 this.triggerBlur();
22307 onBlur : function(){
22312 mimicBlur : function(e, t){
22313 if(!this.wrap.contains(t) && this.validateBlur()){
22314 this.triggerBlur();
22319 triggerBlur : function(){
22320 this.mimicing = false;
22321 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
22322 if(this.monitorTab){
22323 this.el.un("keydown", this.checkTab, this);
22325 this.wrap.removeClass('x-trigger-wrap-focus');
22326 Roo.form.TriggerField.superclass.onBlur.call(this);
22330 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
22331 validateBlur : function(e, t){
22336 onDisable : function(){
22337 Roo.form.TriggerField.superclass.onDisable.call(this);
22339 this.wrap.addClass('x-item-disabled');
22344 onEnable : function(){
22345 Roo.form.TriggerField.superclass.onEnable.call(this);
22347 this.wrap.removeClass('x-item-disabled');
22352 onShow : function(){
22353 var ae = this.getActionEl();
22356 ae.dom.style.display = '';
22357 ae.dom.style.visibility = 'visible';
22363 onHide : function(){
22364 var ae = this.getActionEl();
22365 ae.dom.style.display = 'none';
22369 * The function that should handle the trigger's click event. This method does nothing by default until overridden
22370 * by an implementing function.
22372 * @param {EventObject} e
22374 onTriggerClick : Roo.emptyFn
22377 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
22378 // to be extended by an implementing class. For an example of implementing this class, see the custom
22379 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
22380 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
22381 initComponent : function(){
22382 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
22384 this.triggerConfig = {
22385 tag:'span', cls:'x-form-twin-triggers', cn:[
22386 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
22387 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
22391 getTrigger : function(index){
22392 return this.triggers[index];
22395 initTrigger : function(){
22396 var ts = this.trigger.select('.x-form-trigger', true);
22397 this.wrap.setStyle('overflow', 'hidden');
22398 var triggerField = this;
22399 ts.each(function(t, all, index){
22400 t.hide = function(){
22401 var w = triggerField.wrap.getWidth();
22402 this.dom.style.display = 'none';
22403 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
22405 t.show = function(){
22406 var w = triggerField.wrap.getWidth();
22407 this.dom.style.display = '';
22408 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
22410 var triggerIndex = 'Trigger'+(index+1);
22412 if(this['hide'+triggerIndex]){
22413 t.dom.style.display = 'none';
22415 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
22416 t.addClassOnOver('x-form-trigger-over');
22417 t.addClassOnClick('x-form-trigger-click');
22419 this.triggers = ts.elements;
22422 onTrigger1Click : Roo.emptyFn,
22423 onTrigger2Click : Roo.emptyFn
22426 * Ext JS Library 1.1.1
22427 * Copyright(c) 2006-2007, Ext JS, LLC.
22429 * Originally Released Under LGPL - original licence link has changed is not relivant.
22432 * <script type="text/javascript">
22436 * @class Roo.form.TextArea
22437 * @extends Roo.form.TextField
22438 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
22439 * support for auto-sizing.
22441 * Creates a new TextArea
22442 * @param {Object} config Configuration options
22444 Roo.form.TextArea = function(config){
22445 Roo.form.TextArea.superclass.constructor.call(this, config);
22446 // these are provided exchanges for backwards compat
22447 // minHeight/maxHeight were replaced by growMin/growMax to be
22448 // compatible with TextField growing config values
22449 if(this.minHeight !== undefined){
22450 this.growMin = this.minHeight;
22452 if(this.maxHeight !== undefined){
22453 this.growMax = this.maxHeight;
22457 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
22459 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
22463 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
22467 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
22468 * in the field (equivalent to setting overflow: hidden, defaults to false)
22470 preventScrollbars: false,
22472 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
22473 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
22477 onRender : function(ct, position){
22479 this.defaultAutoCreate = {
22481 style:"width:300px;height:60px;",
22482 autocomplete: "off"
22485 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22487 this.textSizeEl = Roo.DomHelper.append(document.body, {
22488 tag: "pre", cls: "x-form-grow-sizer"
22490 if(this.preventScrollbars){
22491 this.el.setStyle("overflow", "hidden");
22493 this.el.setHeight(this.growMin);
22497 onDestroy : function(){
22498 if(this.textSizeEl){
22499 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22501 Roo.form.TextArea.superclass.onDestroy.call(this);
22505 onKeyUp : function(e){
22506 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22512 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22513 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22515 autoSize : function(){
22516 if(!this.grow || !this.textSizeEl){
22520 var v = el.dom.value;
22521 var ts = this.textSizeEl;
22524 ts.appendChild(document.createTextNode(v));
22527 Roo.fly(ts).setWidth(this.el.getWidth());
22529 v = "  ";
22532 v = v.replace(/\n/g, '<p> </p>');
22534 v += " \n ";
22537 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22538 if(h != this.lastHeight){
22539 this.lastHeight = h;
22540 this.el.setHeight(h);
22541 this.fireEvent("autosize", this, h);
22546 * Ext JS Library 1.1.1
22547 * Copyright(c) 2006-2007, Ext JS, LLC.
22549 * Originally Released Under LGPL - original licence link has changed is not relivant.
22552 * <script type="text/javascript">
22557 * @class Roo.form.NumberField
22558 * @extends Roo.form.TextField
22559 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22561 * Creates a new NumberField
22562 * @param {Object} config Configuration options
22564 Roo.form.NumberField = function(config){
22565 Roo.form.NumberField.superclass.constructor.call(this, config);
22568 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22570 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22572 fieldClass: "x-form-field x-form-num-field",
22574 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22576 allowDecimals : true,
22578 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22580 decimalSeparator : ".",
22582 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22584 decimalPrecision : 2,
22586 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22588 allowNegative : true,
22590 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22592 minValue : Number.NEGATIVE_INFINITY,
22594 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22596 maxValue : Number.MAX_VALUE,
22598 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22600 minText : "The minimum value for this field is {0}",
22602 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22604 maxText : "The maximum value for this field is {0}",
22606 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22607 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22609 nanText : "{0} is not a valid number",
22612 initEvents : function(){
22613 Roo.form.NumberField.superclass.initEvents.call(this);
22614 var allowed = "0123456789";
22615 if(this.allowDecimals){
22616 allowed += this.decimalSeparator;
22618 if(this.allowNegative){
22621 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22622 var keyPress = function(e){
22623 var k = e.getKey();
22624 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22627 var c = e.getCharCode();
22628 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22632 this.el.on("keypress", keyPress, this);
22636 validateValue : function(value){
22637 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22640 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22643 var num = this.parseValue(value);
22645 this.markInvalid(String.format(this.nanText, value));
22648 if(num < this.minValue){
22649 this.markInvalid(String.format(this.minText, this.minValue));
22652 if(num > this.maxValue){
22653 this.markInvalid(String.format(this.maxText, this.maxValue));
22659 getValue : function(){
22660 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22664 parseValue : function(value){
22665 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22666 return isNaN(value) ? '' : value;
22670 fixPrecision : function(value){
22671 var nan = isNaN(value);
22672 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22673 return nan ? '' : value;
22675 return parseFloat(value).toFixed(this.decimalPrecision);
22678 setValue : function(v){
22679 v = this.fixPrecision(v);
22680 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22684 decimalPrecisionFcn : function(v){
22685 return Math.floor(v);
22688 beforeBlur : function(){
22689 var v = this.parseValue(this.getRawValue());
22696 * Ext JS Library 1.1.1
22697 * Copyright(c) 2006-2007, Ext JS, LLC.
22699 * Originally Released Under LGPL - original licence link has changed is not relivant.
22702 * <script type="text/javascript">
22706 * @class Roo.form.DateField
22707 * @extends Roo.form.TriggerField
22708 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22710 * Create a new DateField
22711 * @param {Object} config
22713 Roo.form.DateField = function(config){
22714 Roo.form.DateField.superclass.constructor.call(this, config);
22720 * Fires when a date is selected
22721 * @param {Roo.form.DateField} combo This combo box
22722 * @param {Date} date The date selected
22729 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22730 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22731 this.ddMatch = null;
22732 if(this.disabledDates){
22733 var dd = this.disabledDates;
22735 for(var i = 0; i < dd.length; i++){
22737 if(i != dd.length-1) re += "|";
22739 this.ddMatch = new RegExp(re + ")");
22743 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22745 * @cfg {String} format
22746 * The default date format string which can be overriden for localization support. The format must be
22747 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22751 * @cfg {String} altFormats
22752 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22753 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22755 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22757 * @cfg {Array} disabledDays
22758 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22760 disabledDays : null,
22762 * @cfg {String} disabledDaysText
22763 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22765 disabledDaysText : "Disabled",
22767 * @cfg {Array} disabledDates
22768 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22769 * expression so they are very powerful. Some examples:
22771 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22772 * <li>["03/08", "09/16"] would disable those days for every year</li>
22773 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22774 * <li>["03/../2006"] would disable every day in March 2006</li>
22775 * <li>["^03"] would disable every day in every March</li>
22777 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22778 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22780 disabledDates : null,
22782 * @cfg {String} disabledDatesText
22783 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22785 disabledDatesText : "Disabled",
22787 * @cfg {Date/String} minValue
22788 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22789 * valid format (defaults to null).
22793 * @cfg {Date/String} maxValue
22794 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22795 * valid format (defaults to null).
22799 * @cfg {String} minText
22800 * The error text to display when the date in the cell is before minValue (defaults to
22801 * 'The date in this field must be after {minValue}').
22803 minText : "The date in this field must be equal to or after {0}",
22805 * @cfg {String} maxText
22806 * The error text to display when the date in the cell is after maxValue (defaults to
22807 * 'The date in this field must be before {maxValue}').
22809 maxText : "The date in this field must be equal to or before {0}",
22811 * @cfg {String} invalidText
22812 * The error text to display when the date in the field is invalid (defaults to
22813 * '{value} is not a valid date - it must be in the format {format}').
22815 invalidText : "{0} is not a valid date - it must be in the format {1}",
22817 * @cfg {String} triggerClass
22818 * An additional CSS class used to style the trigger button. The trigger will always get the
22819 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22820 * which displays a calendar icon).
22822 triggerClass : 'x-form-date-trigger',
22826 * @cfg {Boolean} useIso
22827 * if enabled, then the date field will use a hidden field to store the
22828 * real value as iso formated date. default (false)
22832 * @cfg {String/Object} autoCreate
22833 * A DomHelper element spec, or true for a default element spec (defaults to
22834 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22837 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22840 hiddenField: false,
22842 onRender : function(ct, position)
22844 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22846 //this.el.dom.removeAttribute('name');
22847 Roo.log("Changing name?");
22848 this.el.dom.setAttribute('name', this.name + '____hidden___' );
22849 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22851 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
22852 // prevent input submission
22853 this.hiddenName = this.name;
22860 validateValue : function(value)
22862 value = this.formatDate(value);
22863 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22864 Roo.log('super failed');
22867 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22870 var svalue = value;
22871 value = this.parseDate(value);
22873 Roo.log('parse date failed' + svalue);
22874 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22877 var time = value.getTime();
22878 if(this.minValue && time < this.minValue.getTime()){
22879 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22882 if(this.maxValue && time > this.maxValue.getTime()){
22883 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22886 if(this.disabledDays){
22887 var day = value.getDay();
22888 for(var i = 0; i < this.disabledDays.length; i++) {
22889 if(day === this.disabledDays[i]){
22890 this.markInvalid(this.disabledDaysText);
22895 var fvalue = this.formatDate(value);
22896 if(this.ddMatch && this.ddMatch.test(fvalue)){
22897 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22904 // Provides logic to override the default TriggerField.validateBlur which just returns true
22905 validateBlur : function(){
22906 return !this.menu || !this.menu.isVisible();
22909 getName: function()
22911 // returns hidden if it's set..
22912 if (!this.rendered) {return ''};
22913 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
22918 * Returns the current date value of the date field.
22919 * @return {Date} The date value
22921 getValue : function(){
22923 return this.hiddenField ?
22924 this.hiddenField.value :
22925 this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22929 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22930 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22931 * (the default format used is "m/d/y").
22934 //All of these calls set the same date value (May 4, 2006)
22936 //Pass a date object:
22937 var dt = new Date('5/4/06');
22938 dateField.setValue(dt);
22940 //Pass a date string (default format):
22941 dateField.setValue('5/4/06');
22943 //Pass a date string (custom format):
22944 dateField.format = 'Y-m-d';
22945 dateField.setValue('2006-5-4');
22947 * @param {String/Date} date The date or valid date string
22949 setValue : function(date){
22950 if (this.hiddenField) {
22951 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22953 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22954 // make sure the value field is always stored as a date..
22955 this.value = this.parseDate(date);
22961 parseDate : function(value){
22962 if(!value || value instanceof Date){
22965 var v = Date.parseDate(value, this.format);
22966 if (!v && this.useIso) {
22967 v = Date.parseDate(value, 'Y-m-d');
22969 if(!v && this.altFormats){
22970 if(!this.altFormatsArray){
22971 this.altFormatsArray = this.altFormats.split("|");
22973 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22974 v = Date.parseDate(value, this.altFormatsArray[i]);
22981 formatDate : function(date, fmt){
22982 return (!date || !(date instanceof Date)) ?
22983 date : date.dateFormat(fmt || this.format);
22988 select: function(m, d){
22991 this.fireEvent('select', this, d);
22993 show : function(){ // retain focus styling
22997 this.focus.defer(10, this);
22998 var ml = this.menuListeners;
22999 this.menu.un("select", ml.select, this);
23000 this.menu.un("show", ml.show, this);
23001 this.menu.un("hide", ml.hide, this);
23006 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
23007 onTriggerClick : function(){
23011 if(this.menu == null){
23012 this.menu = new Roo.menu.DateMenu();
23014 Roo.apply(this.menu.picker, {
23015 showClear: this.allowBlank,
23016 minDate : this.minValue,
23017 maxDate : this.maxValue,
23018 disabledDatesRE : this.ddMatch,
23019 disabledDatesText : this.disabledDatesText,
23020 disabledDays : this.disabledDays,
23021 disabledDaysText : this.disabledDaysText,
23022 format : this.useIso ? 'Y-m-d' : this.format,
23023 minText : String.format(this.minText, this.formatDate(this.minValue)),
23024 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
23026 this.menu.on(Roo.apply({}, this.menuListeners, {
23029 this.menu.picker.setValue(this.getValue() || new Date());
23030 this.menu.show(this.el, "tl-bl?");
23033 beforeBlur : function(){
23034 var v = this.parseDate(this.getRawValue());
23040 /** @cfg {Boolean} grow @hide */
23041 /** @cfg {Number} growMin @hide */
23042 /** @cfg {Number} growMax @hide */
23049 * Ext JS Library 1.1.1
23050 * Copyright(c) 2006-2007, Ext JS, LLC.
23052 * Originally Released Under LGPL - original licence link has changed is not relivant.
23055 * <script type="text/javascript">
23059 * @class Roo.form.MonthField
23060 * @extends Roo.form.TriggerField
23061 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
23063 * Create a new MonthField
23064 * @param {Object} config
23066 Roo.form.MonthField = function(config){
23068 Roo.form.MonthField.superclass.constructor.call(this, config);
23074 * Fires when a date is selected
23075 * @param {Roo.form.MonthFieeld} combo This combo box
23076 * @param {Date} date The date selected
23083 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
23084 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
23085 this.ddMatch = null;
23086 if(this.disabledDates){
23087 var dd = this.disabledDates;
23089 for(var i = 0; i < dd.length; i++){
23091 if(i != dd.length-1) re += "|";
23093 this.ddMatch = new RegExp(re + ")");
23097 Roo.extend(Roo.form.MonthField, Roo.form.TriggerField, {
23099 * @cfg {String} format
23100 * The default date format string which can be overriden for localization support. The format must be
23101 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
23105 * @cfg {String} altFormats
23106 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
23107 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
23109 altFormats : "M Y|m/Y|m-y|m-Y|my|mY",
23111 * @cfg {Array} disabledDays
23112 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
23114 disabledDays : [0,1,2,3,4,5,6],
23116 * @cfg {String} disabledDaysText
23117 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
23119 disabledDaysText : "Disabled",
23121 * @cfg {Array} disabledDates
23122 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
23123 * expression so they are very powerful. Some examples:
23125 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
23126 * <li>["03/08", "09/16"] would disable those days for every year</li>
23127 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
23128 * <li>["03/../2006"] would disable every day in March 2006</li>
23129 * <li>["^03"] would disable every day in every March</li>
23131 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
23132 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
23134 disabledDates : null,
23136 * @cfg {String} disabledDatesText
23137 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
23139 disabledDatesText : "Disabled",
23141 * @cfg {Date/String} minValue
23142 * The minimum allowed date. Can be either a Javascript date object or a string date in a
23143 * valid format (defaults to null).
23147 * @cfg {Date/String} maxValue
23148 * The maximum allowed date. Can be either a Javascript date object or a string date in a
23149 * valid format (defaults to null).
23153 * @cfg {String} minText
23154 * The error text to display when the date in the cell is before minValue (defaults to
23155 * 'The date in this field must be after {minValue}').
23157 minText : "The date in this field must be equal to or after {0}",
23159 * @cfg {String} maxTextf
23160 * The error text to display when the date in the cell is after maxValue (defaults to
23161 * 'The date in this field must be before {maxValue}').
23163 maxText : "The date in this field must be equal to or before {0}",
23165 * @cfg {String} invalidText
23166 * The error text to display when the date in the field is invalid (defaults to
23167 * '{value} is not a valid date - it must be in the format {format}').
23169 invalidText : "{0} is not a valid date - it must be in the format {1}",
23171 * @cfg {String} triggerClass
23172 * An additional CSS class used to style the trigger button. The trigger will always get the
23173 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
23174 * which displays a calendar icon).
23176 triggerClass : 'x-form-date-trigger',
23180 * @cfg {Boolean} useIso
23181 * if enabled, then the date field will use a hidden field to store the
23182 * real value as iso formated date. default (true)
23186 * @cfg {String/Object} autoCreate
23187 * A DomHelper element spec, or true for a default element spec (defaults to
23188 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
23191 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
23194 hiddenField: false,
23196 hideMonthPicker : false,
23198 onRender : function(ct, position)
23200 Roo.form.MonthField.superclass.onRender.call(this, ct, position);
23202 this.el.dom.removeAttribute('name');
23203 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
23205 this.hiddenField.value = this.value ? this.formatDate(this.value, 'Y-m-d') : '';
23206 // prevent input submission
23207 this.hiddenName = this.name;
23214 validateValue : function(value)
23216 value = this.formatDate(value);
23217 if(!Roo.form.MonthField.superclass.validateValue.call(this, value)){
23220 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
23223 var svalue = value;
23224 value = this.parseDate(value);
23226 this.markInvalid(String.format(this.invalidText, svalue, this.format));
23229 var time = value.getTime();
23230 if(this.minValue && time < this.minValue.getTime()){
23231 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
23234 if(this.maxValue && time > this.maxValue.getTime()){
23235 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
23238 /*if(this.disabledDays){
23239 var day = value.getDay();
23240 for(var i = 0; i < this.disabledDays.length; i++) {
23241 if(day === this.disabledDays[i]){
23242 this.markInvalid(this.disabledDaysText);
23248 var fvalue = this.formatDate(value);
23249 /*if(this.ddMatch && this.ddMatch.test(fvalue)){
23250 this.markInvalid(String.format(this.disabledDatesText, fvalue));
23258 // Provides logic to override the default TriggerField.validateBlur which just returns true
23259 validateBlur : function(){
23260 return !this.menu || !this.menu.isVisible();
23264 * Returns the current date value of the date field.
23265 * @return {Date} The date value
23267 getValue : function(){
23271 return this.hiddenField ?
23272 this.hiddenField.value :
23273 this.parseDate(Roo.form.MonthField.superclass.getValue.call(this)) || "";
23277 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
23278 * date, using MonthField.format as the date format, according to the same rules as {@link Date#parseDate}
23279 * (the default format used is "m/d/y").
23282 //All of these calls set the same date value (May 4, 2006)
23284 //Pass a date object:
23285 var dt = new Date('5/4/06');
23286 monthField.setValue(dt);
23288 //Pass a date string (default format):
23289 monthField.setValue('5/4/06');
23291 //Pass a date string (custom format):
23292 monthField.format = 'Y-m-d';
23293 monthField.setValue('2006-5-4');
23295 * @param {String/Date} date The date or valid date string
23297 setValue : function(date){
23298 Roo.log('month setValue' + date);
23299 // can only be first of month..
23301 var val = this.parseDate(date);
23303 if (this.hiddenField) {
23304 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
23306 Roo.form.MonthField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
23307 this.value = this.parseDate(date);
23311 parseDate : function(value){
23312 if(!value || value instanceof Date){
23313 value = value ? Date.parseDate(value.format('Y-m') + '-01', 'Y-m-d') : null;
23316 var v = Date.parseDate(value, this.format);
23317 if (!v && this.useIso) {
23318 v = Date.parseDate(value, 'Y-m-d');
23322 v = Date.parseDate(v.format('Y-m') +'-01', 'Y-m-d');
23326 if(!v && this.altFormats){
23327 if(!this.altFormatsArray){
23328 this.altFormatsArray = this.altFormats.split("|");
23330 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
23331 v = Date.parseDate(value, this.altFormatsArray[i]);
23338 formatDate : function(date, fmt){
23339 return (!date || !(date instanceof Date)) ?
23340 date : date.dateFormat(fmt || this.format);
23345 select: function(m, d){
23347 this.fireEvent('select', this, d);
23349 show : function(){ // retain focus styling
23353 this.focus.defer(10, this);
23354 var ml = this.menuListeners;
23355 this.menu.un("select", ml.select, this);
23356 this.menu.un("show", ml.show, this);
23357 this.menu.un("hide", ml.hide, this);
23361 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
23362 onTriggerClick : function(){
23366 if(this.menu == null){
23367 this.menu = new Roo.menu.DateMenu();
23371 Roo.apply(this.menu.picker, {
23373 showClear: this.allowBlank,
23374 minDate : this.minValue,
23375 maxDate : this.maxValue,
23376 disabledDatesRE : this.ddMatch,
23377 disabledDatesText : this.disabledDatesText,
23379 format : this.useIso ? 'Y-m-d' : this.format,
23380 minText : String.format(this.minText, this.formatDate(this.minValue)),
23381 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
23384 this.menu.on(Roo.apply({}, this.menuListeners, {
23392 // hide month picker get's called when we called by 'before hide';
23394 var ignorehide = true;
23395 p.hideMonthPicker = function(disableAnim){
23399 if(this.monthPicker){
23400 Roo.log("hideMonthPicker called");
23401 if(disableAnim === true){
23402 this.monthPicker.hide();
23404 this.monthPicker.slideOut('t', {duration:.2});
23405 p.setValue(new Date(m.picker.mpSelYear, m.picker.mpSelMonth, 1));
23406 p.fireEvent("select", this, this.value);
23412 Roo.log('picker set value');
23413 Roo.log(this.getValue());
23414 p.setValue(this.getValue() ? this.parseDate(this.getValue()) : new Date());
23415 m.show(this.el, 'tl-bl?');
23416 ignorehide = false;
23417 // this will trigger hideMonthPicker..
23420 // hidden the day picker
23421 Roo.select('.x-date-picker table', true).first().dom.style.visibility = "hidden";
23427 p.showMonthPicker.defer(100, p);
23433 beforeBlur : function(){
23434 var v = this.parseDate(this.getRawValue());
23440 /** @cfg {Boolean} grow @hide */
23441 /** @cfg {Number} growMin @hide */
23442 /** @cfg {Number} growMax @hide */
23449 * Ext JS Library 1.1.1
23450 * Copyright(c) 2006-2007, Ext JS, LLC.
23452 * Originally Released Under LGPL - original licence link has changed is not relivant.
23455 * <script type="text/javascript">
23460 * @class Roo.form.ComboBox
23461 * @extends Roo.form.TriggerField
23462 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
23464 * Create a new ComboBox.
23465 * @param {Object} config Configuration options
23467 Roo.form.ComboBox = function(config){
23468 Roo.form.ComboBox.superclass.constructor.call(this, config);
23472 * Fires when the dropdown list is expanded
23473 * @param {Roo.form.ComboBox} combo This combo box
23478 * Fires when the dropdown list is collapsed
23479 * @param {Roo.form.ComboBox} combo This combo box
23483 * @event beforeselect
23484 * Fires before a list item is selected. Return false to cancel the selection.
23485 * @param {Roo.form.ComboBox} combo This combo box
23486 * @param {Roo.data.Record} record The data record returned from the underlying store
23487 * @param {Number} index The index of the selected item in the dropdown list
23489 'beforeselect' : true,
23492 * Fires when a list item is selected
23493 * @param {Roo.form.ComboBox} combo This combo box
23494 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
23495 * @param {Number} index The index of the selected item in the dropdown list
23499 * @event beforequery
23500 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
23501 * The event object passed has these properties:
23502 * @param {Roo.form.ComboBox} combo This combo box
23503 * @param {String} query The query
23504 * @param {Boolean} forceAll true to force "all" query
23505 * @param {Boolean} cancel true to cancel the query
23506 * @param {Object} e The query event object
23508 'beforequery': true,
23511 * Fires when the 'add' icon is pressed (add a listener to enable add button)
23512 * @param {Roo.form.ComboBox} combo This combo box
23517 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
23518 * @param {Roo.form.ComboBox} combo This combo box
23519 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
23525 if(this.transform){
23526 this.allowDomMove = false;
23527 var s = Roo.getDom(this.transform);
23528 if(!this.hiddenName){
23529 this.hiddenName = s.name;
23532 this.mode = 'local';
23533 var d = [], opts = s.options;
23534 for(var i = 0, len = opts.length;i < len; i++){
23536 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
23538 this.value = value;
23540 d.push([value, o.text]);
23542 this.store = new Roo.data.SimpleStore({
23544 fields: ['value', 'text'],
23547 this.valueField = 'value';
23548 this.displayField = 'text';
23550 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
23551 if(!this.lazyRender){
23552 this.target = true;
23553 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
23554 s.parentNode.removeChild(s); // remove it
23555 this.render(this.el.parentNode);
23557 s.parentNode.removeChild(s); // remove it
23562 this.store = Roo.factory(this.store, Roo.data);
23565 this.selectedIndex = -1;
23566 if(this.mode == 'local'){
23567 if(config.queryDelay === undefined){
23568 this.queryDelay = 10;
23570 if(config.minChars === undefined){
23576 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
23578 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
23581 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
23582 * rendering into an Roo.Editor, defaults to false)
23585 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
23586 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
23589 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
23592 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
23593 * the dropdown list (defaults to undefined, with no header element)
23597 * @cfg {String/Roo.Template} tpl The template to use to render the output
23601 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
23603 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
23605 listWidth: undefined,
23607 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
23608 * mode = 'remote' or 'text' if mode = 'local')
23610 displayField: undefined,
23612 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
23613 * mode = 'remote' or 'value' if mode = 'local').
23614 * Note: use of a valueField requires the user make a selection
23615 * in order for a value to be mapped.
23617 valueField: undefined,
23621 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
23622 * field's data value (defaults to the underlying DOM element's name)
23624 hiddenName: undefined,
23626 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
23630 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
23632 selectedClass: 'x-combo-selected',
23634 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
23635 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
23636 * which displays a downward arrow icon).
23638 triggerClass : 'x-form-arrow-trigger',
23640 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
23644 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
23645 * anchor positions (defaults to 'tl-bl')
23647 listAlign: 'tl-bl?',
23649 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
23653 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
23654 * query specified by the allQuery config option (defaults to 'query')
23656 triggerAction: 'query',
23658 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
23659 * (defaults to 4, does not apply if editable = false)
23663 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
23664 * delay (typeAheadDelay) if it matches a known value (defaults to false)
23668 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
23669 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
23673 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
23674 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
23678 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
23679 * when editable = true (defaults to false)
23681 selectOnFocus:false,
23683 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
23685 queryParam: 'query',
23687 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
23688 * when mode = 'remote' (defaults to 'Loading...')
23690 loadingText: 'Loading...',
23692 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
23696 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
23700 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
23701 * traditional select (defaults to true)
23705 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
23709 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
23713 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
23714 * listWidth has a higher value)
23718 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
23719 * allow the user to set arbitrary text into the field (defaults to false)
23721 forceSelection:false,
23723 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
23724 * if typeAhead = true (defaults to 250)
23726 typeAheadDelay : 250,
23728 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
23729 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
23731 valueNotFoundText : undefined,
23733 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
23735 blockFocus : false,
23738 * @cfg {Boolean} disableClear Disable showing of clear button.
23740 disableClear : false,
23742 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
23744 alwaysQuery : false,
23750 // element that contains real text value.. (when hidden is used..)
23753 onRender : function(ct, position){
23754 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
23755 if(this.hiddenName){
23756 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
23758 this.hiddenField.value =
23759 this.hiddenValue !== undefined ? this.hiddenValue :
23760 this.value !== undefined ? this.value : '';
23762 // prevent input submission
23763 this.el.dom.removeAttribute('name');
23768 this.el.dom.setAttribute('autocomplete', 'off');
23771 var cls = 'x-combo-list';
23773 this.list = new Roo.Layer({
23774 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
23777 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
23778 this.list.setWidth(lw);
23779 this.list.swallowEvent('mousewheel');
23780 this.assetHeight = 0;
23783 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
23784 this.assetHeight += this.header.getHeight();
23787 this.innerList = this.list.createChild({cls:cls+'-inner'});
23788 this.innerList.on('mouseover', this.onViewOver, this);
23789 this.innerList.on('mousemove', this.onViewMove, this);
23790 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23792 if(this.allowBlank && !this.pageSize && !this.disableClear){
23793 this.footer = this.list.createChild({cls:cls+'-ft'});
23794 this.pageTb = new Roo.Toolbar(this.footer);
23798 this.footer = this.list.createChild({cls:cls+'-ft'});
23799 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
23800 {pageSize: this.pageSize});
23804 if (this.pageTb && this.allowBlank && !this.disableClear) {
23806 this.pageTb.add(new Roo.Toolbar.Fill(), {
23807 cls: 'x-btn-icon x-btn-clear',
23809 handler: function()
23812 _this.clearValue();
23813 _this.onSelect(false, -1);
23818 this.assetHeight += this.footer.getHeight();
23823 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
23826 this.view = new Roo.View(this.innerList, this.tpl, {
23827 singleSelect:true, store: this.store, selectedClass: this.selectedClass
23830 this.view.on('click', this.onViewClick, this);
23832 this.store.on('beforeload', this.onBeforeLoad, this);
23833 this.store.on('load', this.onLoad, this);
23834 this.store.on('loadexception', this.onLoadException, this);
23836 if(this.resizable){
23837 this.resizer = new Roo.Resizable(this.list, {
23838 pinned:true, handles:'se'
23840 this.resizer.on('resize', function(r, w, h){
23841 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
23842 this.listWidth = w;
23843 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
23844 this.restrictHeight();
23846 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
23848 if(!this.editable){
23849 this.editable = true;
23850 this.setEditable(false);
23854 if (typeof(this.events.add.listeners) != 'undefined') {
23856 this.addicon = this.wrap.createChild(
23857 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
23859 this.addicon.on('click', function(e) {
23860 this.fireEvent('add', this);
23863 if (typeof(this.events.edit.listeners) != 'undefined') {
23865 this.editicon = this.wrap.createChild(
23866 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
23867 if (this.addicon) {
23868 this.editicon.setStyle('margin-left', '40px');
23870 this.editicon.on('click', function(e) {
23872 // we fire even if inothing is selected..
23873 this.fireEvent('edit', this, this.lastData );
23883 initEvents : function(){
23884 Roo.form.ComboBox.superclass.initEvents.call(this);
23886 this.keyNav = new Roo.KeyNav(this.el, {
23887 "up" : function(e){
23888 this.inKeyMode = true;
23892 "down" : function(e){
23893 if(!this.isExpanded()){
23894 this.onTriggerClick();
23896 this.inKeyMode = true;
23901 "enter" : function(e){
23902 this.onViewClick();
23906 "esc" : function(e){
23910 "tab" : function(e){
23911 this.onViewClick(false);
23912 this.fireEvent("specialkey", this, e);
23918 doRelay : function(foo, bar, hname){
23919 if(hname == 'down' || this.scope.isExpanded()){
23920 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23927 this.queryDelay = Math.max(this.queryDelay || 10,
23928 this.mode == 'local' ? 10 : 250);
23929 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23930 if(this.typeAhead){
23931 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23933 if(this.editable !== false){
23934 this.el.on("keyup", this.onKeyUp, this);
23936 if(this.forceSelection){
23937 this.on('blur', this.doForce, this);
23941 onDestroy : function(){
23943 this.view.setStore(null);
23944 this.view.el.removeAllListeners();
23945 this.view.el.remove();
23946 this.view.purgeListeners();
23949 this.list.destroy();
23952 this.store.un('beforeload', this.onBeforeLoad, this);
23953 this.store.un('load', this.onLoad, this);
23954 this.store.un('loadexception', this.onLoadException, this);
23956 Roo.form.ComboBox.superclass.onDestroy.call(this);
23960 fireKey : function(e){
23961 if(e.isNavKeyPress() && !this.list.isVisible()){
23962 this.fireEvent("specialkey", this, e);
23967 onResize: function(w, h){
23968 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23970 if(typeof w != 'number'){
23971 // we do not handle it!?!?
23974 var tw = this.trigger.getWidth();
23975 tw += this.addicon ? this.addicon.getWidth() : 0;
23976 tw += this.editicon ? this.editicon.getWidth() : 0;
23978 this.el.setWidth( this.adjustWidth('input', x));
23980 this.trigger.setStyle('left', x+'px');
23982 if(this.list && this.listWidth === undefined){
23983 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23984 this.list.setWidth(lw);
23985 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23993 * Allow or prevent the user from directly editing the field text. If false is passed,
23994 * the user will only be able to select from the items defined in the dropdown list. This method
23995 * is the runtime equivalent of setting the 'editable' config option at config time.
23996 * @param {Boolean} value True to allow the user to directly edit the field text
23998 setEditable : function(value){
23999 if(value == this.editable){
24002 this.editable = value;
24004 this.el.dom.setAttribute('readOnly', true);
24005 this.el.on('mousedown', this.onTriggerClick, this);
24006 this.el.addClass('x-combo-noedit');
24008 this.el.dom.setAttribute('readOnly', false);
24009 this.el.un('mousedown', this.onTriggerClick, this);
24010 this.el.removeClass('x-combo-noedit');
24015 onBeforeLoad : function(){
24016 if(!this.hasFocus){
24019 this.innerList.update(this.loadingText ?
24020 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
24021 this.restrictHeight();
24022 this.selectedIndex = -1;
24026 onLoad : function(){
24027 if(!this.hasFocus){
24030 if(this.store.getCount() > 0){
24032 this.restrictHeight();
24033 if(this.lastQuery == this.allQuery){
24035 this.el.dom.select();
24037 if(!this.selectByValue(this.value, true)){
24038 this.select(0, true);
24042 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
24043 this.taTask.delay(this.typeAheadDelay);
24047 this.onEmptyResults();
24052 onLoadException : function()
24055 Roo.log(this.store.reader.jsonData);
24056 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
24057 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
24063 onTypeAhead : function(){
24064 if(this.store.getCount() > 0){
24065 var r = this.store.getAt(0);
24066 var newValue = r.data[this.displayField];
24067 var len = newValue.length;
24068 var selStart = this.getRawValue().length;
24069 if(selStart != len){
24070 this.setRawValue(newValue);
24071 this.selectText(selStart, newValue.length);
24077 onSelect : function(record, index){
24078 if(this.fireEvent('beforeselect', this, record, index) !== false){
24079 this.setFromData(index > -1 ? record.data : false);
24081 this.fireEvent('select', this, record, index);
24086 * Returns the currently selected field value or empty string if no value is set.
24087 * @return {String} value The selected value
24089 getValue : function(){
24090 if(this.valueField){
24091 return typeof this.value != 'undefined' ? this.value : '';
24093 return Roo.form.ComboBox.superclass.getValue.call(this);
24098 * Clears any text/value currently set in the field
24100 clearValue : function(){
24101 if(this.hiddenField){
24102 this.hiddenField.value = '';
24105 this.setRawValue('');
24106 this.lastSelectionText = '';
24111 * Sets the specified value into the field. If the value finds a match, the corresponding record text
24112 * will be displayed in the field. If the value does not match the data value of an existing item,
24113 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
24114 * Otherwise the field will be blank (although the value will still be set).
24115 * @param {String} value The value to match
24117 setValue : function(v){
24119 if(this.valueField){
24120 var r = this.findRecord(this.valueField, v);
24122 text = r.data[this.displayField];
24123 }else if(this.valueNotFoundText !== undefined){
24124 text = this.valueNotFoundText;
24127 this.lastSelectionText = text;
24128 if(this.hiddenField){
24129 this.hiddenField.value = v;
24131 Roo.form.ComboBox.superclass.setValue.call(this, text);
24135 * @property {Object} the last set data for the element
24140 * Sets the value of the field based on a object which is related to the record format for the store.
24141 * @param {Object} value the value to set as. or false on reset?
24143 setFromData : function(o){
24144 var dv = ''; // display value
24145 var vv = ''; // value value..
24147 if (this.displayField) {
24148 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
24150 // this is an error condition!!!
24151 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
24154 if(this.valueField){
24155 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
24157 if(this.hiddenField){
24158 this.hiddenField.value = vv;
24160 this.lastSelectionText = dv;
24161 Roo.form.ComboBox.superclass.setValue.call(this, dv);
24165 // no hidden field.. - we store the value in 'value', but still display
24166 // display field!!!!
24167 this.lastSelectionText = dv;
24168 Roo.form.ComboBox.superclass.setValue.call(this, dv);
24174 reset : function(){
24175 // overridden so that last data is reset..
24176 this.setValue(this.originalValue);
24177 this.clearInvalid();
24178 this.lastData = false;
24180 this.view.clearSelections();
24184 findRecord : function(prop, value){
24186 if(this.store.getCount() > 0){
24187 this.store.each(function(r){
24188 if(r.data[prop] == value){
24198 getName: function()
24200 // returns hidden if it's set..
24201 if (!this.rendered) {return ''};
24202 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
24206 onViewMove : function(e, t){
24207 this.inKeyMode = false;
24211 onViewOver : function(e, t){
24212 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
24215 var item = this.view.findItemFromChild(t);
24217 var index = this.view.indexOf(item);
24218 this.select(index, false);
24223 onViewClick : function(doFocus)
24225 var index = this.view.getSelectedIndexes()[0];
24226 var r = this.store.getAt(index);
24228 this.onSelect(r, index);
24230 if(doFocus !== false && !this.blockFocus){
24236 restrictHeight : function(){
24237 this.innerList.dom.style.height = '';
24238 var inner = this.innerList.dom;
24239 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
24240 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
24241 this.list.beginUpdate();
24242 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
24243 this.list.alignTo(this.el, this.listAlign);
24244 this.list.endUpdate();
24248 onEmptyResults : function(){
24253 * Returns true if the dropdown list is expanded, else false.
24255 isExpanded : function(){
24256 return this.list.isVisible();
24260 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
24261 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
24262 * @param {String} value The data value of the item to select
24263 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
24264 * selected item if it is not currently in view (defaults to true)
24265 * @return {Boolean} True if the value matched an item in the list, else false
24267 selectByValue : function(v, scrollIntoView){
24268 if(v !== undefined && v !== null){
24269 var r = this.findRecord(this.valueField || this.displayField, v);
24271 this.select(this.store.indexOf(r), scrollIntoView);
24279 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
24280 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
24281 * @param {Number} index The zero-based index of the list item to select
24282 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
24283 * selected item if it is not currently in view (defaults to true)
24285 select : function(index, scrollIntoView){
24286 this.selectedIndex = index;
24287 this.view.select(index);
24288 if(scrollIntoView !== false){
24289 var el = this.view.getNode(index);
24291 this.innerList.scrollChildIntoView(el, false);
24297 selectNext : function(){
24298 var ct = this.store.getCount();
24300 if(this.selectedIndex == -1){
24302 }else if(this.selectedIndex < ct-1){
24303 this.select(this.selectedIndex+1);
24309 selectPrev : function(){
24310 var ct = this.store.getCount();
24312 if(this.selectedIndex == -1){
24314 }else if(this.selectedIndex != 0){
24315 this.select(this.selectedIndex-1);
24321 onKeyUp : function(e){
24322 if(this.editable !== false && !e.isSpecialKey()){
24323 this.lastKey = e.getKey();
24324 this.dqTask.delay(this.queryDelay);
24329 validateBlur : function(){
24330 return !this.list || !this.list.isVisible();
24334 initQuery : function(){
24335 this.doQuery(this.getRawValue());
24339 doForce : function(){
24340 if(this.el.dom.value.length > 0){
24341 this.el.dom.value =
24342 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
24348 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
24349 * query allowing the query action to be canceled if needed.
24350 * @param {String} query The SQL query to execute
24351 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
24352 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
24353 * saved in the current store (defaults to false)
24355 doQuery : function(q, forceAll){
24356 if(q === undefined || q === null){
24361 forceAll: forceAll,
24365 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
24369 forceAll = qe.forceAll;
24370 if(forceAll === true || (q.length >= this.minChars)){
24371 if(this.lastQuery != q || this.alwaysQuery){
24372 this.lastQuery = q;
24373 if(this.mode == 'local'){
24374 this.selectedIndex = -1;
24376 this.store.clearFilter();
24378 this.store.filter(this.displayField, q);
24382 this.store.baseParams[this.queryParam] = q;
24384 params: this.getParams(q)
24389 this.selectedIndex = -1;
24396 getParams : function(q){
24398 //p[this.queryParam] = q;
24401 p.limit = this.pageSize;
24407 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
24409 collapse : function(){
24410 if(!this.isExpanded()){
24414 Roo.get(document).un('mousedown', this.collapseIf, this);
24415 Roo.get(document).un('mousewheel', this.collapseIf, this);
24416 if (!this.editable) {
24417 Roo.get(document).un('keydown', this.listKeyPress, this);
24419 this.fireEvent('collapse', this);
24423 collapseIf : function(e){
24424 if(!e.within(this.wrap) && !e.within(this.list)){
24430 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
24432 expand : function(){
24433 if(this.isExpanded() || !this.hasFocus){
24436 this.list.alignTo(this.el, this.listAlign);
24438 Roo.get(document).on('mousedown', this.collapseIf, this);
24439 Roo.get(document).on('mousewheel', this.collapseIf, this);
24440 if (!this.editable) {
24441 Roo.get(document).on('keydown', this.listKeyPress, this);
24444 this.fireEvent('expand', this);
24448 // Implements the default empty TriggerField.onTriggerClick function
24449 onTriggerClick : function(){
24453 if(this.isExpanded()){
24455 if (!this.blockFocus) {
24460 this.hasFocus = true;
24461 if(this.triggerAction == 'all') {
24462 this.doQuery(this.allQuery, true);
24464 this.doQuery(this.getRawValue());
24466 if (!this.blockFocus) {
24471 listKeyPress : function(e)
24473 //Roo.log('listkeypress');
24474 // scroll to first matching element based on key pres..
24475 if (e.isSpecialKey()) {
24478 var k = String.fromCharCode(e.getKey()).toUpperCase();
24481 var csel = this.view.getSelectedNodes();
24482 var cselitem = false;
24484 var ix = this.view.indexOf(csel[0]);
24485 cselitem = this.store.getAt(ix);
24486 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
24492 this.store.each(function(v) {
24494 // start at existing selection.
24495 if (cselitem.id == v.id) {
24501 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
24502 match = this.store.indexOf(v);
24507 if (match === false) {
24508 return true; // no more action?
24511 this.view.select(match);
24512 var sn = Roo.get(this.view.getSelectedNodes()[0])
24513 sn.scrollIntoView(sn.dom.parentNode, false);
24517 * @cfg {Boolean} grow
24521 * @cfg {Number} growMin
24525 * @cfg {Number} growMax
24533 * Copyright(c) 2010-2012, Roo J Solutions Limited
24540 * @class Roo.form.ComboBoxArray
24541 * @extends Roo.form.TextField
24542 * A facebook style adder... for lists of email / people / countries etc...
24543 * pick multiple items from a combo box, and shows each one.
24545 * Fred [x] Brian [x] [Pick another |v]
24548 * For this to work: it needs various extra information
24549 * - normal combo problay has
24551 * + displayField, valueField
24553 * For our purpose...
24556 * If we change from 'extends' to wrapping...
24563 * Create a new ComboBoxArray.
24564 * @param {Object} config Configuration options
24568 Roo.form.ComboBoxArray = function(config)
24571 Roo.form.ComboBoxArray.superclass.constructor.call(this, config);
24573 this.items = new Roo.util.MixedCollection(false);
24575 // construct the child combo...
24585 Roo.extend(Roo.form.ComboBoxArray, Roo.form.TextField,
24588 * @cfg {Roo.form.Combo} combo The combo box that is wrapped
24593 // behavies liek a hiddne field
24594 inputType: 'hidden',
24596 * @cfg {Number} width The width of the box that displays the selected element
24603 * @cfg {String} name The name of the visable items on this form (eg. titles not ids)
24607 * @cfg {String} hiddenName The hidden name of the field, often contains an comma seperated list of names
24609 hiddenName : false,
24612 // private the array of items that are displayed..
24614 // private - the hidden field el.
24616 // private - the filed el..
24619 //validateValue : function() { return true; }, // all values are ok!
24620 //onAddClick: function() { },
24622 onRender : function(ct, position)
24625 // create the standard hidden element
24626 //Roo.form.ComboBoxArray.superclass.onRender.call(this, ct, position);
24629 // give fake names to child combo;
24630 this.combo.hiddenName = this.hiddenName ? (this.hiddenName+'-subcombo') : this.hiddenName;
24631 this.combo.name = this.name? (this.name+'-subcombo') : this.name;
24633 this.combo = Roo.factory(this.combo, Roo.form);
24634 this.combo.onRender(ct, position);
24635 if (typeof(this.combo.width) != 'undefined') {
24636 this.combo.onResize(this.combo.width,0);
24639 this.combo.initEvents();
24641 // assigned so form know we need to do this..
24642 this.store = this.combo.store;
24643 this.valueField = this.combo.valueField;
24644 this.displayField = this.combo.displayField ;
24647 this.combo.wrap.addClass('x-cbarray-grp');
24649 var cbwrap = this.combo.wrap.createChild(
24650 {tag: 'div', cls: 'x-cbarray-cb'},
24655 this.hiddenEl = this.combo.wrap.createChild({
24656 tag: 'input', type:'hidden' , name: this.hiddenName, value : ''
24658 this.el = this.combo.wrap.createChild({
24659 tag: 'input', type:'hidden' , name: this.name, value : ''
24661 // this.el.dom.removeAttribute("name");
24664 this.outerWrap = this.combo.wrap;
24665 this.wrap = cbwrap;
24667 this.outerWrap.setWidth(this.width);
24668 this.outerWrap.dom.removeChild(this.el.dom);
24670 this.wrap.dom.appendChild(this.el.dom);
24671 this.outerWrap.dom.removeChild(this.combo.trigger.dom);
24672 this.combo.wrap.dom.appendChild(this.combo.trigger.dom);
24674 this.combo.trigger.setStyle('position','relative');
24675 this.combo.trigger.setStyle('left', '0px');
24676 this.combo.trigger.setStyle('top', '2px');
24678 this.combo.el.setStyle('vertical-align', 'text-bottom');
24680 //this.trigger.setStyle('vertical-align', 'top');
24682 // this should use the code from combo really... on('add' ....)
24686 this.adder = this.outerWrap.createChild(
24687 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-adder', style: 'margin-left:2px'});
24689 this.adder.on('click', function(e) {
24690 _t.fireEvent('adderclick', this, e);
24694 //this.adder.on('click', this.onAddClick, _t);
24697 this.combo.on('select', function(cb, rec, ix) {
24698 this.addItem(rec.data);
24701 cb.el.dom.value = '';
24702 //cb.lastData = rec.data;
24711 getName: function()
24713 // returns hidden if it's set..
24714 if (!this.rendered) {return ''};
24715 return this.hiddenName ? this.hiddenName : this.name;
24720 onResize: function(w, h){
24723 // not sure if this is needed..
24724 //this.combo.onResize(w,h);
24726 if(typeof w != 'number'){
24727 // we do not handle it!?!?
24730 var tw = this.combo.trigger.getWidth();
24731 tw += this.addicon ? this.addicon.getWidth() : 0;
24732 tw += this.editicon ? this.editicon.getWidth() : 0;
24734 this.combo.el.setWidth( this.combo.adjustWidth('input', x));
24736 this.combo.trigger.setStyle('left', '0px');
24738 if(this.list && this.listWidth === undefined){
24739 var lw = Math.max(x + this.combo.trigger.getWidth(), this.combo.minListWidth);
24740 this.list.setWidth(lw);
24741 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
24748 addItem: function(rec)
24750 var valueField = this.combo.valueField;
24751 var displayField = this.combo.displayField;
24752 if (this.items.indexOfKey(rec[valueField]) > -1) {
24753 //console.log("GOT " + rec.data.id);
24757 var x = new Roo.form.ComboBoxArray.Item({
24758 //id : rec[this.idField],
24760 displayField : displayField ,
24761 tipField : displayField ,
24765 this.items.add(rec[valueField],x);
24766 // add it before the element..
24767 this.updateHiddenEl();
24768 x.render(this.outerWrap, this.wrap.dom);
24769 // add the image handler..
24772 updateHiddenEl : function()
24775 if (!this.hiddenEl) {
24779 var idField = this.combo.valueField;
24781 this.items.each(function(f) {
24782 ar.push(f.data[idField]);
24785 this.hiddenEl.dom.value = ar.join(',');
24791 //Roo.form.ComboBoxArray.superclass.reset.call(this);
24792 this.items.each(function(f) {
24795 this.el.dom.value = '';
24796 if (this.hiddenEl) {
24797 this.hiddenEl.dom.value = '';
24801 getValue: function()
24803 return this.hiddenEl ? this.hiddenEl.dom.value : '';
24805 setValue: function(v) // not a valid action - must use addItems..
24812 if (this.store.isLocal && (typeof(v) == 'string')) {
24813 // then we can use the store to find the values..
24814 // comma seperated at present.. this needs to allow JSON based encoding..
24815 this.hiddenEl.value = v;
24817 Roo.each(v.split(','), function(k) {
24818 Roo.log("CHECK " + this.valueField + ',' + k);
24819 var li = this.store.query(this.valueField, k);
24824 add[this.valueField] = k;
24825 add[this.displayField] = li.item(0).data[this.displayField];
24831 if (typeof(v) == 'object') {
24832 // then let's assume it's an array of objects..
24833 Roo.each(v, function(l) {
24841 setFromData: function(v)
24843 // this recieves an object, if setValues is called.
24845 this.el.dom.value = v[this.displayField];
24846 this.hiddenEl.dom.value = v[this.valueField];
24847 if (typeof(v[this.valueField]) != 'string' || !v[this.valueField].length) {
24850 var kv = v[this.valueField];
24851 var dv = v[this.displayField];
24852 kv = typeof(kv) != 'string' ? '' : kv;
24853 dv = typeof(dv) != 'string' ? '' : dv;
24856 var keys = kv.split(',');
24857 var display = dv.split(',');
24858 for (var i = 0 ; i < keys.length; i++) {
24861 add[this.valueField] = keys[i];
24862 add[this.displayField] = display[i];
24870 validateValue : function(value){
24871 return Roo.form.ComboBoxArray.superclass.validateValue.call(this, this.getValue());
24880 * @class Roo.form.ComboBoxArray.Item
24881 * @extends Roo.BoxComponent
24882 * A selected item in the list
24883 * Fred [x] Brian [x] [Pick another |v]
24886 * Create a new item.
24887 * @param {Object} config Configuration options
24890 Roo.form.ComboBoxArray.Item = function(config) {
24891 config.id = Roo.id();
24892 Roo.form.ComboBoxArray.Item.superclass.constructor.call(this, config);
24895 Roo.extend(Roo.form.ComboBoxArray.Item, Roo.BoxComponent, {
24898 displayField : false,
24902 defaultAutoCreate : {
24904 cls: 'x-cbarray-item',
24911 src : Roo.BLANK_IMAGE_URL ,
24919 onRender : function(ct, position)
24921 Roo.form.Field.superclass.onRender.call(this, ct, position);
24924 var cfg = this.getAutoCreate();
24925 this.el = ct.createChild(cfg, position);
24928 this.el.child('img').dom.setAttribute('src', Roo.BLANK_IMAGE_URL);
24930 this.el.child('div').dom.innerHTML = this.cb.renderer ?
24931 this.cb.renderer(this.data) :
24932 String.format('{0}',this.data[this.displayField]);
24935 this.el.child('div').dom.setAttribute('qtip',
24936 String.format('{0}',this.data[this.tipField])
24939 this.el.child('img').on('click', this.remove, this);
24943 remove : function()
24946 this.cb.items.remove(this);
24947 this.el.child('img').un('click', this.remove, this);
24949 this.cb.updateHiddenEl();
24955 * Ext JS Library 1.1.1
24956 * Copyright(c) 2006-2007, Ext JS, LLC.
24958 * Originally Released Under LGPL - original licence link has changed is not relivant.
24961 * <script type="text/javascript">
24964 * @class Roo.form.Checkbox
24965 * @extends Roo.form.Field
24966 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
24968 * Creates a new Checkbox
24969 * @param {Object} config Configuration options
24971 Roo.form.Checkbox = function(config){
24972 Roo.form.Checkbox.superclass.constructor.call(this, config);
24976 * Fires when the checkbox is checked or unchecked.
24977 * @param {Roo.form.Checkbox} this This checkbox
24978 * @param {Boolean} checked The new checked value
24984 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
24986 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
24988 focusClass : undefined,
24990 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
24992 fieldClass: "x-form-field",
24994 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
24998 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
24999 * {tag: "input", type: "checkbox", autocomplete: "off"})
25001 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
25003 * @cfg {String} boxLabel The text that appears beside the checkbox
25007 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
25011 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
25013 valueOff: '0', // value when not checked..
25015 actionMode : 'viewEl',
25018 itemCls : 'x-menu-check-item x-form-item',
25019 groupClass : 'x-menu-group-item',
25020 inputType : 'hidden',
25023 inSetChecked: false, // check that we are not calling self...
25025 inputElement: false, // real input element?
25026 basedOn: false, // ????
25028 isFormField: true, // not sure where this is needed!!!!
25030 onResize : function(){
25031 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
25032 if(!this.boxLabel){
25033 this.el.alignTo(this.wrap, 'c-c');
25037 initEvents : function(){
25038 Roo.form.Checkbox.superclass.initEvents.call(this);
25039 this.el.on("click", this.onClick, this);
25040 this.el.on("change", this.onClick, this);
25044 getResizeEl : function(){
25048 getPositionEl : function(){
25053 onRender : function(ct, position){
25054 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
25056 if(this.inputValue !== undefined){
25057 this.el.dom.value = this.inputValue;
25060 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
25061 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
25062 var viewEl = this.wrap.createChild({
25063 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
25064 this.viewEl = viewEl;
25065 this.wrap.on('click', this.onClick, this);
25067 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
25068 this.el.on('propertychange', this.setFromHidden, this); //ie
25073 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
25074 // viewEl.on('click', this.onClick, this);
25076 //if(this.checked){
25077 this.setChecked(this.checked);
25079 //this.checked = this.el.dom;
25085 initValue : Roo.emptyFn,
25088 * Returns the checked state of the checkbox.
25089 * @return {Boolean} True if checked, else false
25091 getValue : function(){
25093 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
25095 return this.valueOff;
25100 onClick : function(){
25101 this.setChecked(!this.checked);
25103 //if(this.el.dom.checked != this.checked){
25104 // this.setValue(this.el.dom.checked);
25109 * Sets the checked state of the checkbox.
25110 * On is always based on a string comparison between inputValue and the param.
25111 * @param {Boolean/String} value - the value to set
25112 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
25114 setValue : function(v,suppressEvent){
25117 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
25118 //if(this.el && this.el.dom){
25119 // this.el.dom.checked = this.checked;
25120 // this.el.dom.defaultChecked = this.checked;
25122 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
25123 //this.fireEvent("check", this, this.checked);
25126 setChecked : function(state,suppressEvent)
25128 if (this.inSetChecked) {
25129 this.checked = state;
25135 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
25137 this.checked = state;
25138 if(suppressEvent !== true){
25139 this.fireEvent('check', this, state);
25141 this.inSetChecked = true;
25142 this.el.dom.value = state ? this.inputValue : this.valueOff;
25143 this.inSetChecked = false;
25146 // handle setting of hidden value by some other method!!?!?
25147 setFromHidden: function()
25152 //console.log("SET FROM HIDDEN");
25153 //alert('setFrom hidden');
25154 this.setValue(this.el.dom.value);
25157 onDestroy : function()
25160 Roo.get(this.viewEl).remove();
25163 Roo.form.Checkbox.superclass.onDestroy.call(this);
25168 * Ext JS Library 1.1.1
25169 * Copyright(c) 2006-2007, Ext JS, LLC.
25171 * Originally Released Under LGPL - original licence link has changed is not relivant.
25174 * <script type="text/javascript">
25178 * @class Roo.form.Radio
25179 * @extends Roo.form.Checkbox
25180 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
25181 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
25183 * Creates a new Radio
25184 * @param {Object} config Configuration options
25186 Roo.form.Radio = function(){
25187 Roo.form.Radio.superclass.constructor.apply(this, arguments);
25189 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
25190 inputType: 'radio',
25193 * If this radio is part of a group, it will return the selected value
25196 getGroupValue : function(){
25197 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
25201 onRender : function(ct, position){
25202 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
25204 if(this.inputValue !== undefined){
25205 this.el.dom.value = this.inputValue;
25208 this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
25209 //this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
25210 //var viewEl = this.wrap.createChild({
25211 // tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
25212 //this.viewEl = viewEl;
25213 //this.wrap.on('click', this.onClick, this);
25215 //this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
25216 //this.el.on('propertychange', this.setFromHidden, this); //ie
25221 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
25222 // viewEl.on('click', this.onClick, this);
25225 this.el.dom.checked = 'checked' ;
25231 });//<script type="text/javascript">
25234 * Ext JS Library 1.1.1
25235 * Copyright(c) 2006-2007, Ext JS, LLC.
25236 * licensing@extjs.com
25238 * http://www.extjs.com/license
25244 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
25245 * - IE ? - no idea how much works there.
25253 * @class Ext.form.HtmlEditor
25254 * @extends Ext.form.Field
25255 * Provides a lightweight HTML Editor component.
25257 * This has been tested on Fireforx / Chrome.. IE may not be so great..
25259 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
25260 * supported by this editor.</b><br/><br/>
25261 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
25262 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
25264 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
25266 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
25270 * @cfg {String} createLinkText The default text for the create link prompt
25272 createLinkText : 'Please enter the URL for the link:',
25274 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
25276 defaultLinkValue : 'http:/'+'/',
25279 * @cfg {String} resizable 's' or 'se' or 'e' - wrapps the element in a
25284 * @cfg {Number} height (in pixels)
25288 * @cfg {Number} width (in pixels)
25293 * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets.
25296 stylesheets: false,
25301 // private properties
25302 validationEvent : false,
25304 initialized : false,
25306 sourceEditMode : false,
25307 onFocus : Roo.emptyFn,
25309 hideMode:'offsets',
25311 defaultAutoCreate : { // modified by initCompnoent..
25313 style:"width:500px;height:300px;",
25314 autocomplete: "off"
25318 initComponent : function(){
25321 * @event initialize
25322 * Fires when the editor is fully initialized (including the iframe)
25323 * @param {HtmlEditor} this
25328 * Fires when the editor is first receives the focus. Any insertion must wait
25329 * until after this event.
25330 * @param {HtmlEditor} this
25334 * @event beforesync
25335 * Fires before the textarea is updated with content from the editor iframe. Return false
25336 * to cancel the sync.
25337 * @param {HtmlEditor} this
25338 * @param {String} html
25342 * @event beforepush
25343 * Fires before the iframe editor is updated with content from the textarea. Return false
25344 * to cancel the push.
25345 * @param {HtmlEditor} this
25346 * @param {String} html
25351 * Fires when the textarea is updated with content from the editor iframe.
25352 * @param {HtmlEditor} this
25353 * @param {String} html
25358 * Fires when the iframe editor is updated with content from the textarea.
25359 * @param {HtmlEditor} this
25360 * @param {String} html
25364 * @event editmodechange
25365 * Fires when the editor switches edit modes
25366 * @param {HtmlEditor} this
25367 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
25369 editmodechange: true,
25371 * @event editorevent
25372 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
25373 * @param {HtmlEditor} this
25377 this.defaultAutoCreate = {
25379 style:'width: ' + this.width + 'px;height: ' + this.height + 'px;',
25380 autocomplete: "off"
25385 * Protected method that will not generally be called directly. It
25386 * is called when the editor creates its toolbar. Override this method if you need to
25387 * add custom toolbar buttons.
25388 * @param {HtmlEditor} editor
25390 createToolbar : function(editor){
25391 if (!editor.toolbars || !editor.toolbars.length) {
25392 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
25395 for (var i =0 ; i < editor.toolbars.length;i++) {
25396 editor.toolbars[i] = Roo.factory(
25397 typeof(editor.toolbars[i]) == 'string' ?
25398 { xtype: editor.toolbars[i]} : editor.toolbars[i],
25399 Roo.form.HtmlEditor);
25400 editor.toolbars[i].init(editor);
25407 * Protected method that will not generally be called directly. It
25408 * is called when the editor initializes the iframe with HTML contents. Override this method if you
25409 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
25411 getDocMarkup : function(){
25414 if (this.stylesheets === false) {
25416 Roo.get(document.head).select('style').each(function(node) {
25417 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
25420 Roo.get(document.head).select('link').each(function(node) {
25421 st += node.dom.outerHTML || new XMLSerializer().serializeToString(node.dom);
25424 } else if (!this.stylesheets.length) {
25426 st = '<style type="text/css">' +
25427 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
25430 Roo.each(this.stylesheets, function(s) {
25431 st += '<link rel="stylesheet" type="text/css" href="' + s +'" />'
25436 st += '<style type="text/css">' +
25437 'IMG { cursor: pointer } ' +
25441 return '<html><head>' + st +
25442 //<style type="text/css">' +
25443 //'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' +
25445 ' </head><body class="roo-htmleditor-body"></body></html>';
25449 onRender : function(ct, position)
25452 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
25453 this.el.dom.style.border = '0 none';
25454 this.el.dom.setAttribute('tabIndex', -1);
25455 this.el.addClass('x-hidden');
25456 if(Roo.isIE){ // fix IE 1px bogus margin
25457 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
25459 this.wrap = this.el.wrap({
25460 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
25463 if (this.resizable) {
25464 this.resizeEl = new Roo.Resizable(this.wrap, {
25468 minHeight : this.height,
25469 height: this.height,
25470 handles : this.resizable,
25473 resize : function(r, w, h) {
25474 _t.onResize(w,h); // -something
25481 this.frameId = Roo.id();
25483 this.createToolbar(this);
25487 var iframe = this.wrap.createChild({
25490 name: this.frameId,
25491 frameBorder : 'no',
25492 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
25496 // console.log(iframe);
25497 //this.wrap.dom.appendChild(iframe);
25499 this.iframe = iframe.dom;
25501 this.assignDocWin();
25503 this.doc.designMode = 'on';
25506 this.doc.write(this.getDocMarkup());
25510 var task = { // must defer to wait for browser to be ready
25512 //console.log("run task?" + this.doc.readyState);
25513 this.assignDocWin();
25514 if(this.doc.body || this.doc.readyState == 'complete'){
25516 this.doc.designMode="on";
25520 Roo.TaskMgr.stop(task);
25521 this.initEditor.defer(10, this);
25528 Roo.TaskMgr.start(task);
25531 this.setSize(this.wrap.getSize());
25533 if (this.resizeEl) {
25534 this.resizeEl.resizeTo.defer(100, this.resizeEl,[ this.width,this.height ] );
25535 // should trigger onReize..
25540 onResize : function(w, h)
25542 //Roo.log('resize: ' +w + ',' + h );
25543 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
25544 if(this.el && this.iframe){
25545 if(typeof w == 'number'){
25546 var aw = w - this.wrap.getFrameWidth('lr');
25547 this.el.setWidth(this.adjustWidth('textarea', aw));
25548 this.iframe.style.width = aw + 'px';
25550 if(typeof h == 'number'){
25552 for (var i =0; i < this.toolbars.length;i++) {
25553 // fixme - ask toolbars for heights?
25554 tbh += this.toolbars[i].tb.el.getHeight();
25555 if (this.toolbars[i].footer) {
25556 tbh += this.toolbars[i].footer.el.getHeight();
25563 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
25564 ah -= 5; // knock a few pixes off for look..
25565 this.el.setHeight(this.adjustWidth('textarea', ah));
25566 this.iframe.style.height = ah + 'px';
25568 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
25575 * Toggles the editor between standard and source edit mode.
25576 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
25578 toggleSourceEdit : function(sourceEditMode){
25580 this.sourceEditMode = sourceEditMode === true;
25582 if(this.sourceEditMode){
25584 // Roo.log(this.syncValue());
25586 this.iframe.className = 'x-hidden';
25587 this.el.removeClass('x-hidden');
25588 this.el.dom.removeAttribute('tabIndex');
25592 // Roo.log(this.pushValue());
25594 this.iframe.className = '';
25595 this.el.addClass('x-hidden');
25596 this.el.dom.setAttribute('tabIndex', -1);
25599 this.setSize(this.wrap.getSize());
25600 this.fireEvent('editmodechange', this, this.sourceEditMode);
25603 // private used internally
25604 createLink : function(){
25605 var url = prompt(this.createLinkText, this.defaultLinkValue);
25606 if(url && url != 'http:/'+'/'){
25607 this.relayCmd('createlink', url);
25611 // private (for BoxComponent)
25612 adjustSize : Roo.BoxComponent.prototype.adjustSize,
25614 // private (for BoxComponent)
25615 getResizeEl : function(){
25619 // private (for BoxComponent)
25620 getPositionEl : function(){
25625 initEvents : function(){
25626 this.originalValue = this.getValue();
25630 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25633 markInvalid : Roo.emptyFn,
25635 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
25638 clearInvalid : Roo.emptyFn,
25640 setValue : function(v){
25641 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
25646 * Protected method that will not generally be called directly. If you need/want
25647 * custom HTML cleanup, this is the method you should override.
25648 * @param {String} html The HTML to be cleaned
25649 * return {String} The cleaned HTML
25651 cleanHtml : function(html){
25652 html = String(html);
25653 if(html.length > 5){
25654 if(Roo.isSafari){ // strip safari nonsense
25655 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
25658 if(html == ' '){
25665 * Protected method that will not generally be called directly. Syncs the contents
25666 * of the editor iframe with the textarea.
25668 syncValue : function(){
25669 if(this.initialized){
25670 var bd = (this.doc.body || this.doc.documentElement);
25671 //this.cleanUpPaste(); -- this is done else where and causes havoc..
25672 var html = bd.innerHTML;
25674 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
25675 var m = bs.match(/text-align:(.*?);/i);
25677 html = '<div style="'+m[0]+'">' + html + '</div>';
25680 html = this.cleanHtml(html);
25681 // fix up the special chars.. normaly like back quotes in word...
25682 // however we do not want to do this with chinese..
25683 html = html.replace(/([\x80-\uffff])/g, function (a, b) {
25684 var cc = b.charCodeAt();
25686 (cc >= 0x4E00 && cc < 0xA000 ) ||
25687 (cc >= 0x3400 && cc < 0x4E00 ) ||
25688 (cc >= 0xf900 && cc < 0xfb00 )
25694 if(this.fireEvent('beforesync', this, html) !== false){
25695 this.el.dom.value = html;
25696 this.fireEvent('sync', this, html);
25702 * Protected method that will not generally be called directly. Pushes the value of the textarea
25703 * into the iframe editor.
25705 pushValue : function(){
25706 if(this.initialized){
25707 var v = this.el.dom.value;
25713 if(this.fireEvent('beforepush', this, v) !== false){
25714 var d = (this.doc.body || this.doc.documentElement);
25716 this.cleanUpPaste();
25717 this.el.dom.value = d.innerHTML;
25718 this.fireEvent('push', this, v);
25724 deferFocus : function(){
25725 this.focus.defer(10, this);
25729 focus : function(){
25730 if(this.win && !this.sourceEditMode){
25737 assignDocWin: function()
25739 var iframe = this.iframe;
25742 this.doc = iframe.contentWindow.document;
25743 this.win = iframe.contentWindow;
25745 if (!Roo.get(this.frameId)) {
25748 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
25749 this.win = Roo.get(this.frameId).dom.contentWindow;
25754 initEditor : function(){
25755 //console.log("INIT EDITOR");
25756 this.assignDocWin();
25760 this.doc.designMode="on";
25762 this.doc.write(this.getDocMarkup());
25765 var dbody = (this.doc.body || this.doc.documentElement);
25766 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
25767 // this copies styles from the containing element into thsi one..
25768 // not sure why we need all of this..
25769 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
25770 ss['background-attachment'] = 'fixed'; // w3c
25771 dbody.bgProperties = 'fixed'; // ie
25772 Roo.DomHelper.applyStyles(dbody, ss);
25773 Roo.EventManager.on(this.doc, {
25774 //'mousedown': this.onEditorEvent,
25775 'mouseup': this.onEditorEvent,
25776 'dblclick': this.onEditorEvent,
25777 'click': this.onEditorEvent,
25778 'keyup': this.onEditorEvent,
25783 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
25785 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
25786 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
25788 this.initialized = true;
25790 this.fireEvent('initialize', this);
25795 onDestroy : function(){
25801 for (var i =0; i < this.toolbars.length;i++) {
25802 // fixme - ask toolbars for heights?
25803 this.toolbars[i].onDestroy();
25806 this.wrap.dom.innerHTML = '';
25807 this.wrap.remove();
25812 onFirstFocus : function(){
25814 this.assignDocWin();
25817 this.activated = true;
25818 for (var i =0; i < this.toolbars.length;i++) {
25819 this.toolbars[i].onFirstFocus();
25822 if(Roo.isGecko){ // prevent silly gecko errors
25824 var s = this.win.getSelection();
25825 if(!s.focusNode || s.focusNode.nodeType != 3){
25826 var r = s.getRangeAt(0);
25827 r.selectNodeContents((this.doc.body || this.doc.documentElement));
25832 this.execCmd('useCSS', true);
25833 this.execCmd('styleWithCSS', false);
25836 this.fireEvent('activate', this);
25840 adjustFont: function(btn){
25841 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
25842 //if(Roo.isSafari){ // safari
25845 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
25846 if(Roo.isSafari){ // safari
25847 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
25848 v = (v < 10) ? 10 : v;
25849 v = (v > 48) ? 48 : v;
25850 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
25855 v = Math.max(1, v+adjust);
25857 this.execCmd('FontSize', v );
25860 onEditorEvent : function(e){
25861 this.fireEvent('editorevent', this, e);
25862 // this.updateToolbar();
25863 this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff
25866 insertTag : function(tg)
25868 // could be a bit smarter... -> wrap the current selected tRoo..
25869 if (tg.toLowerCase() == 'span' || tg.toLowerCase() == 'code') {
25871 range = this.createRange(this.getSelection());
25872 var wrappingNode = this.doc.createElement(tg.toLowerCase());
25873 wrappingNode.appendChild(range.extractContents());
25874 range.insertNode(wrappingNode);
25881 this.execCmd("formatblock", tg);
25885 insertText : function(txt)
25889 var range = this.createRange();
25890 range.deleteContents();
25891 //alert(Sender.getAttribute('label'));
25893 range.insertNode(this.doc.createTextNode(txt));
25897 relayBtnCmd : function(btn){
25898 this.relayCmd(btn.cmd);
25902 * Executes a Midas editor command on the editor document and performs necessary focus and
25903 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
25904 * @param {String} cmd The Midas command
25905 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
25907 relayCmd : function(cmd, value){
25909 this.execCmd(cmd, value);
25910 this.fireEvent('editorevent', this);
25911 //this.updateToolbar();
25916 * Executes a Midas editor command directly on the editor document.
25917 * For visual commands, you should use {@link #relayCmd} instead.
25918 * <b>This should only be called after the editor is initialized.</b>
25919 * @param {String} cmd The Midas command
25920 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
25922 execCmd : function(cmd, value){
25923 this.doc.execCommand(cmd, false, value === undefined ? null : value);
25930 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
25932 * @param {String} text | dom node..
25934 insertAtCursor : function(text)
25939 if(!this.activated){
25945 var r = this.doc.selection.createRange();
25956 if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
25960 // from jquery ui (MIT licenced)
25962 var win = this.win;
25964 if (win.getSelection && win.getSelection().getRangeAt) {
25965 range = win.getSelection().getRangeAt(0);
25966 node = typeof(text) == 'string' ? range.createContextualFragment(text) : text;
25967 range.insertNode(node);
25968 } else if (win.document.selection && win.document.selection.createRange) {
25969 // no firefox support
25970 var txt = typeof(text) == 'string' ? text : text.outerHTML;
25971 win.document.selection.createRange().pasteHTML(txt);
25973 // no firefox support
25974 var txt = typeof(text) == 'string' ? text : text.outerHTML;
25975 this.execCmd('InsertHTML', txt);
25984 mozKeyPress : function(e){
25986 var c = e.getCharCode(), cmd;
25989 c = String.fromCharCode(c).toLowerCase();
26003 this.cleanUpPaste.defer(100, this);
26011 e.preventDefault();
26019 fixKeys : function(){ // load time branching for fastest keydown performance
26021 return function(e){
26022 var k = e.getKey(), r;
26025 r = this.doc.selection.createRange();
26028 r.pasteHTML('    ');
26035 r = this.doc.selection.createRange();
26037 var target = r.parentElement();
26038 if(!target || target.tagName.toLowerCase() != 'li'){
26040 r.pasteHTML('<br />');
26046 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
26047 this.cleanUpPaste.defer(100, this);
26053 }else if(Roo.isOpera){
26054 return function(e){
26055 var k = e.getKey();
26059 this.execCmd('InsertHTML','    ');
26062 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
26063 this.cleanUpPaste.defer(100, this);
26068 }else if(Roo.isSafari){
26069 return function(e){
26070 var k = e.getKey();
26074 this.execCmd('InsertText','\t');
26078 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
26079 this.cleanUpPaste.defer(100, this);
26087 getAllAncestors: function()
26089 var p = this.getSelectedNode();
26092 a.push(p); // push blank onto stack..
26093 p = this.getParentElement();
26097 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
26101 a.push(this.doc.body);
26105 lastSelNode : false,
26108 getSelection : function()
26110 this.assignDocWin();
26111 return Roo.isIE ? this.doc.selection : this.win.getSelection();
26114 getSelectedNode: function()
26116 // this may only work on Gecko!!!
26118 // should we cache this!!!!
26123 var range = this.createRange(this.getSelection()).cloneRange();
26126 var parent = range.parentElement();
26128 var testRange = range.duplicate();
26129 testRange.moveToElementText(parent);
26130 if (testRange.inRange(range)) {
26133 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
26136 parent = parent.parentElement;
26141 // is ancestor a text element.
26142 var ac = range.commonAncestorContainer;
26143 if (ac.nodeType == 3) {
26144 ac = ac.parentNode;
26147 var ar = ac.childNodes;
26150 var other_nodes = [];
26151 var has_other_nodes = false;
26152 for (var i=0;i<ar.length;i++) {
26153 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
26156 // fullly contained node.
26158 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
26163 // probably selected..
26164 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
26165 other_nodes.push(ar[i]);
26169 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
26174 has_other_nodes = true;
26176 if (!nodes.length && other_nodes.length) {
26177 nodes= other_nodes;
26179 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
26185 createRange: function(sel)
26187 // this has strange effects when using with
26188 // top toolbar - not sure if it's a great idea.
26189 //this.editor.contentWindow.focus();
26190 if (typeof sel != "undefined") {
26192 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
26194 return this.doc.createRange();
26197 return this.doc.createRange();
26200 getParentElement: function()
26203 this.assignDocWin();
26204 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
26206 var range = this.createRange(sel);
26209 var p = range.commonAncestorContainer;
26210 while (p.nodeType == 3) { // text node
26221 * Range intersection.. the hard stuff...
26225 * [ -- selected range --- ]
26229 * if end is before start or hits it. fail.
26230 * if start is after end or hits it fail.
26232 * if either hits (but other is outside. - then it's not
26238 // @see http://www.thismuchiknow.co.uk/?p=64.
26239 rangeIntersectsNode : function(range, node)
26241 var nodeRange = node.ownerDocument.createRange();
26243 nodeRange.selectNode(node);
26245 nodeRange.selectNodeContents(node);
26248 var rangeStartRange = range.cloneRange();
26249 rangeStartRange.collapse(true);
26251 var rangeEndRange = range.cloneRange();
26252 rangeEndRange.collapse(false);
26254 var nodeStartRange = nodeRange.cloneRange();
26255 nodeStartRange.collapse(true);
26257 var nodeEndRange = nodeRange.cloneRange();
26258 nodeEndRange.collapse(false);
26260 return rangeStartRange.compareBoundaryPoints(
26261 Range.START_TO_START, nodeEndRange) == -1 &&
26262 rangeEndRange.compareBoundaryPoints(
26263 Range.START_TO_START, nodeStartRange) == 1;
26267 rangeCompareNode : function(range, node)
26269 var nodeRange = node.ownerDocument.createRange();
26271 nodeRange.selectNode(node);
26273 nodeRange.selectNodeContents(node);
26277 range.collapse(true);
26279 nodeRange.collapse(true);
26281 var ss = range.compareBoundaryPoints( Range.START_TO_START, nodeRange);
26282 var ee = range.compareBoundaryPoints( Range.END_TO_END, nodeRange);
26284 //Roo.log(node.tagName + ': ss='+ss +', ee='+ee)
26286 var nodeIsBefore = ss == 1;
26287 var nodeIsAfter = ee == -1;
26289 if (nodeIsBefore && nodeIsAfter)
26291 if (!nodeIsBefore && nodeIsAfter)
26292 return 1; //right trailed.
26294 if (nodeIsBefore && !nodeIsAfter)
26295 return 2; // left trailed.
26300 // private? - in a new class?
26301 cleanUpPaste : function()
26303 // cleans up the whole document..
26304 Roo.log('cleanuppaste');
26305 this.cleanUpChildren(this.doc.body);
26306 var clean = this.cleanWordChars(this.doc.body.innerHTML);
26307 if (clean != this.doc.body.innerHTML) {
26308 this.doc.body.innerHTML = clean;
26313 cleanWordChars : function(input) {// change the chars to hex code
26314 var he = Roo.form.HtmlEditor;
26316 var output = input;
26317 Roo.each(he.swapCodes, function(sw) {
26318 var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes
26320 output = output.replace(swapper, sw[1]);
26327 cleanUpChildren : function (n)
26329 if (!n.childNodes.length) {
26332 for (var i = n.childNodes.length-1; i > -1 ; i--) {
26333 this.cleanUpChild(n.childNodes[i]);
26340 cleanUpChild : function (node)
26343 //console.log(node);
26344 if (node.nodeName == "#text") {
26345 // clean up silly Windows -- stuff?
26348 if (node.nodeName == "#comment") {
26349 node.parentNode.removeChild(node);
26350 // clean up silly Windows -- stuff?
26354 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
26356 node.parentNode.removeChild(node);
26361 var remove_keep_children= Roo.form.HtmlEditor.remove.indexOf(node.tagName.toLowerCase()) > -1;
26363 // remove <a name=....> as rendering on yahoo mailer is borked with this.
26364 // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer..
26366 //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) {
26367 // remove_keep_children = true;
26370 if (remove_keep_children) {
26371 this.cleanUpChildren(node);
26372 // inserts everything just before this node...
26373 while (node.childNodes.length) {
26374 var cn = node.childNodes[0];
26375 node.removeChild(cn);
26376 node.parentNode.insertBefore(cn, node);
26378 node.parentNode.removeChild(node);
26382 if (!node.attributes || !node.attributes.length) {
26383 this.cleanUpChildren(node);
26387 function cleanAttr(n,v)
26390 if (v.match(/^\./) || v.match(/^\//)) {
26393 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
26396 if (v.match(/^#/)) {
26399 // Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v);
26400 node.removeAttribute(n);
26404 function cleanStyle(n,v)
26406 if (v.match(/expression/)) { //XSS?? should we even bother..
26407 node.removeAttribute(n);
26410 var cwhite = typeof(ed.cwhite) == 'undefined' ? Roo.form.HtmlEditor.cwhite : ed.cwhite;
26411 var cblack = typeof(ed.cblack) == 'undefined' ? Roo.form.HtmlEditor.cblack : ed.cblack;
26414 var parts = v.split(/;/);
26417 Roo.each(parts, function(p) {
26418 p = p.replace(/^\s+/g,'').replace(/\s+$/g,'');
26422 var l = p.split(':').shift().replace(/\s+/g,'');
26423 l = l.replace(/^\s+/g,'').replace(/\s+$/g,'');
26426 if ( cblack.indexOf(l) > -1) {
26427 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
26428 //node.removeAttribute(n);
26432 // only allow 'c whitelisted system attributes'
26433 if ( cwhite.length && cwhite.indexOf(l) < 0) {
26434 // Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v);
26435 //node.removeAttribute(n);
26445 if (clean.length) {
26446 node.setAttribute(n, clean.join(';'));
26448 node.removeAttribute(n);
26454 for (var i = node.attributes.length-1; i > -1 ; i--) {
26455 var a = node.attributes[i];
26458 if (a.name.toLowerCase().substr(0,2)=='on') {
26459 node.removeAttribute(a.name);
26462 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
26463 node.removeAttribute(a.name);
26466 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
26467 cleanAttr(a.name,a.value); // fixme..
26470 if (a.name == 'style') {
26471 cleanStyle(a.name,a.value);
26474 /// clean up MS crap..
26475 // tecnically this should be a list of valid class'es..
26478 if (a.name == 'class') {
26479 if (a.value.match(/^Mso/)) {
26480 node.className = '';
26483 if (a.value.match(/body/)) {
26484 node.className = '';
26495 this.cleanUpChildren(node);
26501 // hide stuff that is not compatible
26515 * @event specialkey
26519 * @cfg {String} fieldClass @hide
26522 * @cfg {String} focusClass @hide
26525 * @cfg {String} autoCreate @hide
26528 * @cfg {String} inputType @hide
26531 * @cfg {String} invalidClass @hide
26534 * @cfg {String} invalidText @hide
26537 * @cfg {String} msgFx @hide
26540 * @cfg {String} validateOnBlur @hide
26544 Roo.form.HtmlEditor.white = [
26545 'area', 'br', 'img', 'input', 'hr', 'wbr',
26547 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
26548 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
26549 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
26550 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
26551 'table', 'ul', 'xmp',
26553 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
26556 'dir', 'menu', 'ol', 'ul', 'dl',
26562 Roo.form.HtmlEditor.black = [
26563 // 'embed', 'object', // enable - backend responsiblity to clean thiese
26565 'base', 'basefont', 'bgsound', 'blink', 'body',
26566 'frame', 'frameset', 'head', 'html', 'ilayer',
26567 'iframe', 'layer', 'link', 'meta', 'object',
26568 'script', 'style' ,'title', 'xml' // clean later..
26570 Roo.form.HtmlEditor.clean = [
26571 'script', 'style', 'title', 'xml'
26573 Roo.form.HtmlEditor.remove = [
26578 Roo.form.HtmlEditor.ablack = [
26582 Roo.form.HtmlEditor.aclean = [
26583 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
26587 Roo.form.HtmlEditor.pwhite= [
26588 'http', 'https', 'mailto'
26591 // white listed style attributes.
26592 Roo.form.HtmlEditor.cwhite= [
26593 // 'text-align', /// default is to allow most things..
26599 // black listed style attributes.
26600 Roo.form.HtmlEditor.cblack= [
26601 // 'font-size' -- this can be set by the project
26605 Roo.form.HtmlEditor.swapCodes =[
26616 // <script type="text/javascript">
26619 * Ext JS Library 1.1.1
26620 * Copyright(c) 2006-2007, Ext JS, LLC.
26626 * @class Roo.form.HtmlEditorToolbar1
26631 new Roo.form.HtmlEditor({
26634 new Roo.form.HtmlEditorToolbar1({
26635 disable : { fonts: 1 , format: 1, ..., ... , ...],
26641 * @cfg {Object} disable List of elements to disable..
26642 * @cfg {Array} btns List of additional buttons.
26646 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
26649 Roo.form.HtmlEditor.ToolbarStandard = function(config)
26652 Roo.apply(this, config);
26654 // default disabled, based on 'good practice'..
26655 this.disable = this.disable || {};
26656 Roo.applyIf(this.disable, {
26659 specialElements : true
26663 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
26664 // dont call parent... till later.
26667 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
26675 * @cfg {Object} disable List of toolbar elements to disable
26680 * @cfg {Array} fontFamilies An array of available font families
26698 // "á" , ?? a acute?
26703 "°" // , // degrees
26705 // "é" , // e ecute
26706 // "ú" , // u ecute?
26709 specialElements : [
26711 text: "Insert Table",
26714 ihtml : '<table><tr><td>Cell</td></tr></table>'
26718 text: "Insert Image",
26721 ihtml : '<img src="about:blank"/>'
26730 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
26731 "input:submit", "input:button", "select", "textarea", "label" ],
26734 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
26736 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"],
26744 * @cfg {String} defaultFont default font to use.
26746 defaultFont: 'tahoma',
26748 fontSelect : false,
26751 formatCombo : false,
26753 init : function(editor)
26755 this.editor = editor;
26758 var fid = editor.frameId;
26760 function btn(id, toggle, handler){
26761 var xid = fid + '-'+ id ;
26765 cls : 'x-btn-icon x-edit-'+id,
26766 enableToggle:toggle !== false,
26767 scope: editor, // was editor...
26768 handler:handler||editor.relayBtnCmd,
26769 clickEvent:'mousedown',
26770 tooltip: etb.buttonTips[id] || undefined, ///tips ???
26777 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
26779 // stop form submits
26780 tb.el.on('click', function(e){
26781 e.preventDefault(); // what does this do?
26784 if(!this.disable.font) { // && !Roo.isSafari){
26785 /* why no safari for fonts
26786 editor.fontSelect = tb.el.createChild({
26789 cls:'x-font-select',
26790 html: this.createFontOptions()
26793 editor.fontSelect.on('change', function(){
26794 var font = editor.fontSelect.dom.value;
26795 editor.relayCmd('fontname', font);
26796 editor.deferFocus();
26800 editor.fontSelect.dom,
26806 if(!this.disable.formats){
26807 this.formatCombo = new Roo.form.ComboBox({
26808 store: new Roo.data.SimpleStore({
26811 data : this.formats // from states.js
26815 //autoCreate : {tag: "div", size: "20"},
26816 displayField:'tag',
26820 triggerAction: 'all',
26821 emptyText:'Add tag',
26822 selectOnFocus:true,
26825 'select': function(c, r, i) {
26826 editor.insertTag(r.get('tag'));
26832 tb.addField(this.formatCombo);
26836 if(!this.disable.format){
26843 if(!this.disable.fontSize){
26848 btn('increasefontsize', false, editor.adjustFont),
26849 btn('decreasefontsize', false, editor.adjustFont)
26854 if(!this.disable.colors){
26857 id:editor.frameId +'-forecolor',
26858 cls:'x-btn-icon x-edit-forecolor',
26859 clickEvent:'mousedown',
26860 tooltip: this.buttonTips['forecolor'] || undefined,
26862 menu : new Roo.menu.ColorMenu({
26863 allowReselect: true,
26864 focus: Roo.emptyFn,
26867 selectHandler: function(cp, color){
26868 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
26869 editor.deferFocus();
26872 clickEvent:'mousedown'
26875 id:editor.frameId +'backcolor',
26876 cls:'x-btn-icon x-edit-backcolor',
26877 clickEvent:'mousedown',
26878 tooltip: this.buttonTips['backcolor'] || undefined,
26880 menu : new Roo.menu.ColorMenu({
26881 focus: Roo.emptyFn,
26884 allowReselect: true,
26885 selectHandler: function(cp, color){
26887 editor.execCmd('useCSS', false);
26888 editor.execCmd('hilitecolor', color);
26889 editor.execCmd('useCSS', true);
26890 editor.deferFocus();
26892 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
26893 Roo.isSafari || Roo.isIE ? '#'+color : color);
26894 editor.deferFocus();
26898 clickEvent:'mousedown'
26903 // now add all the items...
26906 if(!this.disable.alignments){
26909 btn('justifyleft'),
26910 btn('justifycenter'),
26911 btn('justifyright')
26915 //if(!Roo.isSafari){
26916 if(!this.disable.links){
26919 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
26923 if(!this.disable.lists){
26926 btn('insertorderedlist'),
26927 btn('insertunorderedlist')
26930 if(!this.disable.sourceEdit){
26933 btn('sourceedit', true, function(btn){
26934 this.toggleSourceEdit(btn.pressed);
26941 // special menu.. - needs to be tidied up..
26942 if (!this.disable.special) {
26945 cls: 'x-edit-none',
26951 for (var i =0; i < this.specialChars.length; i++) {
26952 smenu.menu.items.push({
26954 html: this.specialChars[i],
26955 handler: function(a,b) {
26956 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
26957 //editor.insertAtCursor(a.html);
26971 if (!this.disable.cleanStyles) {
26973 cls: 'x-btn-icon x-btn-clear',
26979 for (var i =0; i < this.cleanStyles.length; i++) {
26980 cmenu.menu.items.push({
26982 html: this.cleanStyles[i],
26983 handler: function(a,b) {
26984 var c = Roo.get(editor.doc.body);
26985 c.select('[style]').each(function(s) {
26986 s.dom.style.removeProperty(a.html);
26997 if (!this.disable.specialElements) {
27000 cls: 'x-edit-none',
27005 for (var i =0; i < this.specialElements.length; i++) {
27006 semenu.menu.items.push(
27008 handler: function(a,b) {
27009 editor.insertAtCursor(this.ihtml);
27011 }, this.specialElements[i])
27023 for(var i =0; i< this.btns.length;i++) {
27024 var b = Roo.factory(this.btns[i],Roo.form);
27025 b.cls = 'x-edit-none';
27034 // disable everything...
27036 this.tb.items.each(function(item){
27037 if(item.id != editor.frameId+ '-sourceedit'){
27041 this.rendered = true;
27043 // the all the btns;
27044 editor.on('editorevent', this.updateToolbar, this);
27045 // other toolbars need to implement this..
27046 //editor.on('editmodechange', this.updateToolbar, this);
27052 * Protected method that will not generally be called directly. It triggers
27053 * a toolbar update by reading the markup state of the current selection in the editor.
27055 updateToolbar: function(){
27057 if(!this.editor.activated){
27058 this.editor.onFirstFocus();
27062 var btns = this.tb.items.map,
27063 doc = this.editor.doc,
27064 frameId = this.editor.frameId;
27066 if(!this.disable.font && !Roo.isSafari){
27068 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
27069 if(name != this.fontSelect.dom.value){
27070 this.fontSelect.dom.value = name;
27074 if(!this.disable.format){
27075 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
27076 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
27077 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
27079 if(!this.disable.alignments){
27080 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
27081 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
27082 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
27084 if(!Roo.isSafari && !this.disable.lists){
27085 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
27086 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
27089 var ans = this.editor.getAllAncestors();
27090 if (this.formatCombo) {
27093 var store = this.formatCombo.store;
27094 this.formatCombo.setValue("");
27095 for (var i =0; i < ans.length;i++) {
27096 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
27098 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
27106 // hides menus... - so this cant be on a menu...
27107 Roo.menu.MenuMgr.hideAll();
27109 //this.editorsyncValue();
27113 createFontOptions : function(){
27114 var buf = [], fs = this.fontFamilies, ff, lc;
27118 for(var i = 0, len = fs.length; i< len; i++){
27120 lc = ff.toLowerCase();
27122 '<option value="',lc,'" style="font-family:',ff,';"',
27123 (this.defaultFont == lc ? ' selected="true">' : '>'),
27128 return buf.join('');
27131 toggleSourceEdit : function(sourceEditMode){
27132 if(sourceEditMode === undefined){
27133 sourceEditMode = !this.sourceEditMode;
27135 this.sourceEditMode = sourceEditMode === true;
27136 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
27137 // just toggle the button?
27138 if(btn.pressed !== this.editor.sourceEditMode){
27139 btn.toggle(this.editor.sourceEditMode);
27143 if(this.sourceEditMode){
27144 this.tb.items.each(function(item){
27145 if(item.cmd != 'sourceedit'){
27151 if(this.initialized){
27152 this.tb.items.each(function(item){
27158 // tell the editor that it's been pressed..
27159 this.editor.toggleSourceEdit(sourceEditMode);
27163 * Object collection of toolbar tooltips for the buttons in the editor. The key
27164 * is the command id associated with that button and the value is a valid QuickTips object.
27169 title: 'Bold (Ctrl+B)',
27170 text: 'Make the selected text bold.',
27171 cls: 'x-html-editor-tip'
27174 title: 'Italic (Ctrl+I)',
27175 text: 'Make the selected text italic.',
27176 cls: 'x-html-editor-tip'
27184 title: 'Bold (Ctrl+B)',
27185 text: 'Make the selected text bold.',
27186 cls: 'x-html-editor-tip'
27189 title: 'Italic (Ctrl+I)',
27190 text: 'Make the selected text italic.',
27191 cls: 'x-html-editor-tip'
27194 title: 'Underline (Ctrl+U)',
27195 text: 'Underline the selected text.',
27196 cls: 'x-html-editor-tip'
27198 increasefontsize : {
27199 title: 'Grow Text',
27200 text: 'Increase the font size.',
27201 cls: 'x-html-editor-tip'
27203 decreasefontsize : {
27204 title: 'Shrink Text',
27205 text: 'Decrease the font size.',
27206 cls: 'x-html-editor-tip'
27209 title: 'Text Highlight Color',
27210 text: 'Change the background color of the selected text.',
27211 cls: 'x-html-editor-tip'
27214 title: 'Font Color',
27215 text: 'Change the color of the selected text.',
27216 cls: 'x-html-editor-tip'
27219 title: 'Align Text Left',
27220 text: 'Align text to the left.',
27221 cls: 'x-html-editor-tip'
27224 title: 'Center Text',
27225 text: 'Center text in the editor.',
27226 cls: 'x-html-editor-tip'
27229 title: 'Align Text Right',
27230 text: 'Align text to the right.',
27231 cls: 'x-html-editor-tip'
27233 insertunorderedlist : {
27234 title: 'Bullet List',
27235 text: 'Start a bulleted list.',
27236 cls: 'x-html-editor-tip'
27238 insertorderedlist : {
27239 title: 'Numbered List',
27240 text: 'Start a numbered list.',
27241 cls: 'x-html-editor-tip'
27244 title: 'Hyperlink',
27245 text: 'Make the selected text a hyperlink.',
27246 cls: 'x-html-editor-tip'
27249 title: 'Source Edit',
27250 text: 'Switch to source editing mode.',
27251 cls: 'x-html-editor-tip'
27255 onDestroy : function(){
27258 this.tb.items.each(function(item){
27260 item.menu.removeAll();
27262 item.menu.el.destroy();
27270 onFirstFocus: function() {
27271 this.tb.items.each(function(item){
27280 // <script type="text/javascript">
27283 * Ext JS Library 1.1.1
27284 * Copyright(c) 2006-2007, Ext JS, LLC.
27291 * @class Roo.form.HtmlEditor.ToolbarContext
27296 new Roo.form.HtmlEditor({
27299 { xtype: 'ToolbarStandard', styles : {} }
27300 { xtype: 'ToolbarContext', disable : {} }
27306 * @config : {Object} disable List of elements to disable.. (not done yet.)
27307 * @config : {Object} styles Map of styles available.
27311 Roo.form.HtmlEditor.ToolbarContext = function(config)
27314 Roo.apply(this, config);
27315 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
27316 // dont call parent... till later.
27317 this.styles = this.styles || {};
27322 Roo.form.HtmlEditor.ToolbarContext.types = {
27334 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
27396 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
27401 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
27411 style : 'fontFamily',
27412 displayField: 'display',
27413 optname : 'font-family',
27462 // should we really allow this??
27463 // should this just be
27474 style : 'fontFamily',
27475 displayField: 'display',
27476 optname : 'font-family',
27483 style : 'fontFamily',
27484 displayField: 'display',
27485 optname : 'font-family',
27492 style : 'fontFamily',
27493 displayField: 'display',
27494 optname : 'font-family',
27505 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
27506 Roo.form.HtmlEditor.ToolbarContext.stores = false;
27508 Roo.form.HtmlEditor.ToolbarContext.options = {
27510 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
27511 [ 'Courier New', 'Courier New'],
27512 [ 'Tahoma', 'Tahoma'],
27513 [ 'Times New Roman,serif', 'Times'],
27514 [ 'Verdana','Verdana' ]
27518 // fixme - these need to be configurable..
27521 Roo.form.HtmlEditor.ToolbarContext.types
27524 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
27532 * @cfg {Object} disable List of toolbar elements to disable
27537 * @cfg {Object} styles List of styles
27538 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
27540 * These must be defined in the page, so they get rendered correctly..
27551 init : function(editor)
27553 this.editor = editor;
27556 var fid = editor.frameId;
27558 function btn(id, toggle, handler){
27559 var xid = fid + '-'+ id ;
27563 cls : 'x-btn-icon x-edit-'+id,
27564 enableToggle:toggle !== false,
27565 scope: editor, // was editor...
27566 handler:handler||editor.relayBtnCmd,
27567 clickEvent:'mousedown',
27568 tooltip: etb.buttonTips[id] || undefined, ///tips ???
27572 // create a new element.
27573 var wdiv = editor.wrap.createChild({
27575 }, editor.wrap.dom.firstChild.nextSibling, true);
27577 // can we do this more than once??
27579 // stop form submits
27582 // disable everything...
27583 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27584 this.toolbars = {};
27586 for (var i in ty) {
27588 this.toolbars[i] = this.buildToolbar(ty[i],i);
27590 this.tb = this.toolbars.BODY;
27592 this.buildFooter();
27593 this.footer.show();
27594 editor.on('hide', function( ) { this.footer.hide() }, this);
27595 editor.on('show', function( ) { this.footer.show() }, this);
27598 this.rendered = true;
27600 // the all the btns;
27601 editor.on('editorevent', this.updateToolbar, this);
27602 // other toolbars need to implement this..
27603 //editor.on('editmodechange', this.updateToolbar, this);
27609 * Protected method that will not generally be called directly. It triggers
27610 * a toolbar update by reading the markup state of the current selection in the editor.
27612 updateToolbar: function(editor,ev,sel){
27615 // capture mouse up - this is handy for selecting images..
27616 // perhaps should go somewhere else...
27617 if(!this.editor.activated){
27618 this.editor.onFirstFocus();
27622 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
27623 // selectNode - might want to handle IE?
27625 (ev.type == 'mouseup' || ev.type == 'click' ) &&
27626 ev.target && ev.target.tagName == 'IMG') {
27627 // they have click on an image...
27628 // let's see if we can change the selection...
27631 var nodeRange = sel.ownerDocument.createRange();
27633 nodeRange.selectNode(sel);
27635 nodeRange.selectNodeContents(sel);
27637 //nodeRange.collapse(true);
27638 var s = editor.win.getSelection();
27639 s.removeAllRanges();
27640 s.addRange(nodeRange);
27644 var updateFooter = sel ? false : true;
27647 var ans = this.editor.getAllAncestors();
27650 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27653 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
27654 sel = sel ? sel : this.editor.doc.body;
27655 sel = sel.tagName.length ? sel : this.editor.doc.body;
27658 // pick a menu that exists..
27659 var tn = sel.tagName.toUpperCase();
27660 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
27662 tn = sel.tagName.toUpperCase();
27664 var lastSel = this.tb.selectedNode
27666 this.tb.selectedNode = sel;
27668 // if current menu does not match..
27669 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
27672 ///console.log("show: " + tn);
27673 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
27676 this.tb.items.first().el.innerHTML = tn + ': ';
27679 // update attributes
27680 if (this.tb.fields) {
27681 this.tb.fields.each(function(e) {
27683 e.setValue(sel.style[e.stylename]);
27686 e.setValue(sel.getAttribute(e.attrname));
27690 var hasStyles = false;
27691 for(var i in this.styles) {
27698 var st = this.tb.fields.item(0);
27700 st.store.removeAll();
27703 var cn = sel.className.split(/\s+/);
27706 if (this.styles['*']) {
27708 Roo.each(this.styles['*'], function(v) {
27709 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27712 if (this.styles[tn]) {
27713 Roo.each(this.styles[tn], function(v) {
27714 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27718 st.store.loadData(avs);
27722 // flag our selected Node.
27723 this.tb.selectedNode = sel;
27726 Roo.menu.MenuMgr.hideAll();
27730 if (!updateFooter) {
27731 //this.footDisp.dom.innerHTML = '';
27734 // update the footer
27738 this.footerEls = ans.reverse();
27739 Roo.each(this.footerEls, function(a,i) {
27740 if (!a) { return; }
27741 html += html.length ? ' > ' : '';
27743 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
27748 var sz = this.footDisp.up('td').getSize();
27749 this.footDisp.dom.style.width = (sz.width -10) + 'px';
27750 this.footDisp.dom.style.marginLeft = '5px';
27752 this.footDisp.dom.style.overflow = 'hidden';
27754 this.footDisp.dom.innerHTML = html;
27756 //this.editorsyncValue();
27763 onDestroy : function(){
27766 this.tb.items.each(function(item){
27768 item.menu.removeAll();
27770 item.menu.el.destroy();
27778 onFirstFocus: function() {
27779 // need to do this for all the toolbars..
27780 this.tb.items.each(function(item){
27784 buildToolbar: function(tlist, nm)
27786 var editor = this.editor;
27787 // create a new element.
27788 var wdiv = editor.wrap.createChild({
27790 }, editor.wrap.dom.firstChild.nextSibling, true);
27793 var tb = new Roo.Toolbar(wdiv);
27796 tb.add(nm+ ": ");
27799 for(var i in this.styles) {
27804 if (styles && styles.length) {
27806 // this needs a multi-select checkbox...
27807 tb.addField( new Roo.form.ComboBox({
27808 store: new Roo.data.SimpleStore({
27810 fields: ['val', 'selected'],
27813 name : '-roo-edit-className',
27814 attrname : 'className',
27815 displayField: 'val',
27819 triggerAction: 'all',
27820 emptyText:'Select Style',
27821 selectOnFocus:true,
27824 'select': function(c, r, i) {
27825 // initial support only for on class per el..
27826 tb.selectedNode.className = r ? r.get('val') : '';
27827 editor.syncValue();
27834 var tbc = Roo.form.HtmlEditor.ToolbarContext;
27835 var tbops = tbc.options;
27837 for (var i in tlist) {
27839 var item = tlist[i];
27840 tb.add(item.title + ": ");
27843 //optname == used so you can configure the options available..
27844 var opts = item.opts ? item.opts : false;
27845 if (item.optname) {
27846 opts = tbops[item.optname];
27851 // opts == pulldown..
27852 tb.addField( new Roo.form.ComboBox({
27853 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
27855 fields: ['val', 'display'],
27858 name : '-roo-edit-' + i,
27860 stylename : item.style ? item.style : false,
27861 displayField: item.displayField ? item.displayField : 'val',
27862 valueField : 'val',
27864 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
27866 triggerAction: 'all',
27867 emptyText:'Select',
27868 selectOnFocus:true,
27869 width: item.width ? item.width : 130,
27871 'select': function(c, r, i) {
27873 tb.selectedNode.style[c.stylename] = r.get('val');
27876 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
27885 tb.addField( new Roo.form.TextField({
27888 //allowBlank:false,
27893 tb.addField( new Roo.form.TextField({
27894 name: '-roo-edit-' + i,
27901 'change' : function(f, nv, ov) {
27902 tb.selectedNode.setAttribute(f.attrname, nv);
27911 text: 'Remove Tag',
27914 click : function ()
27917 // undo does not work.
27919 var sn = tb.selectedNode;
27921 var pn = sn.parentNode;
27923 var stn = sn.childNodes[0];
27924 var en = sn.childNodes[sn.childNodes.length - 1 ];
27925 while (sn.childNodes.length) {
27926 var node = sn.childNodes[0];
27927 sn.removeChild(node);
27929 pn.insertBefore(node, sn);
27932 pn.removeChild(sn);
27933 var range = editor.createRange();
27935 range.setStart(stn,0);
27936 range.setEnd(en,0); //????
27937 //range.selectNode(sel);
27940 var selection = editor.getSelection();
27941 selection.removeAllRanges();
27942 selection.addRange(range);
27946 //_this.updateToolbar(null, null, pn);
27947 _this.updateToolbar(null, null, null);
27948 _this.footDisp.dom.innerHTML = '';
27958 tb.el.on('click', function(e){
27959 e.preventDefault(); // what does this do?
27961 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
27964 // dont need to disable them... as they will get hidden
27969 buildFooter : function()
27972 var fel = this.editor.wrap.createChild();
27973 this.footer = new Roo.Toolbar(fel);
27974 // toolbar has scrolly on left / right?
27975 var footDisp= new Roo.Toolbar.Fill();
27981 handler : function() {
27982 _t.footDisp.scrollTo('left',0,true)
27986 this.footer.add( footDisp );
27991 handler : function() {
27993 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
27997 var fel = Roo.get(footDisp.el);
27998 fel.addClass('x-editor-context');
27999 this.footDispWrap = fel;
28000 this.footDispWrap.overflow = 'hidden';
28002 this.footDisp = fel.createChild();
28003 this.footDispWrap.on('click', this.onContextClick, this)
28007 onContextClick : function (ev,dom)
28009 ev.preventDefault();
28010 var cn = dom.className;
28012 if (!cn.match(/x-ed-loc-/)) {
28015 var n = cn.split('-').pop();
28016 var ans = this.footerEls;
28020 var range = this.editor.createRange();
28022 range.selectNodeContents(sel);
28023 //range.selectNode(sel);
28026 var selection = this.editor.getSelection();
28027 selection.removeAllRanges();
28028 selection.addRange(range);
28032 this.updateToolbar(null, null, sel);
28049 * Ext JS Library 1.1.1
28050 * Copyright(c) 2006-2007, Ext JS, LLC.
28052 * Originally Released Under LGPL - original licence link has changed is not relivant.
28055 * <script type="text/javascript">
28059 * @class Roo.form.BasicForm
28060 * @extends Roo.util.Observable
28061 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
28063 * @param {String/HTMLElement/Roo.Element} el The form element or its id
28064 * @param {Object} config Configuration options
28066 Roo.form.BasicForm = function(el, config){
28067 this.allItems = [];
28068 this.childForms = [];
28069 Roo.apply(this, config);
28071 * The Roo.form.Field items in this form.
28072 * @type MixedCollection
28076 this.items = new Roo.util.MixedCollection(false, function(o){
28077 return o.id || (o.id = Roo.id());
28081 * @event beforeaction
28082 * Fires before any action is performed. Return false to cancel the action.
28083 * @param {Form} this
28084 * @param {Action} action The action to be performed
28086 beforeaction: true,
28088 * @event actionfailed
28089 * Fires when an action fails.
28090 * @param {Form} this
28091 * @param {Action} action The action that failed
28093 actionfailed : true,
28095 * @event actioncomplete
28096 * Fires when an action is completed.
28097 * @param {Form} this
28098 * @param {Action} action The action that completed
28100 actioncomplete : true
28105 Roo.form.BasicForm.superclass.constructor.call(this);
28108 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
28110 * @cfg {String} method
28111 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
28114 * @cfg {DataReader} reader
28115 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
28116 * This is optional as there is built-in support for processing JSON.
28119 * @cfg {DataReader} errorReader
28120 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
28121 * This is completely optional as there is built-in support for processing JSON.
28124 * @cfg {String} url
28125 * The URL to use for form actions if one isn't supplied in the action options.
28128 * @cfg {Boolean} fileUpload
28129 * Set to true if this form is a file upload.
28133 * @cfg {Object} baseParams
28134 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
28139 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
28144 activeAction : null,
28147 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
28148 * or setValues() data instead of when the form was first created.
28150 trackResetOnLoad : false,
28154 * childForms - used for multi-tab forms
28157 childForms : false,
28160 * allItems - full list of fields.
28166 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
28167 * element by passing it or its id or mask the form itself by passing in true.
28170 waitMsgTarget : false,
28173 initEl : function(el){
28174 this.el = Roo.get(el);
28175 this.id = this.el.id || Roo.id();
28176 this.el.on('submit', this.onSubmit, this);
28177 this.el.addClass('x-form');
28181 onSubmit : function(e){
28186 * Returns true if client-side validation on the form is successful.
28189 isValid : function(){
28191 this.items.each(function(f){
28200 * Returns true if any fields in this form have changed since their original load.
28203 isDirty : function(){
28205 this.items.each(function(f){
28215 * Performs a predefined action (submit or load) or custom actions you define on this form.
28216 * @param {String} actionName The name of the action type
28217 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
28218 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
28219 * accept other config options):
28221 Property Type Description
28222 ---------------- --------------- ----------------------------------------------------------------------------------
28223 url String The url for the action (defaults to the form's url)
28224 method String The form method to use (defaults to the form's method, or POST if not defined)
28225 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
28226 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
28227 validate the form on the client (defaults to false)
28229 * @return {BasicForm} this
28231 doAction : function(action, options){
28232 if(typeof action == 'string'){
28233 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
28235 if(this.fireEvent('beforeaction', this, action) !== false){
28236 this.beforeAction(action);
28237 action.run.defer(100, action);
28243 * Shortcut to do a submit action.
28244 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28245 * @return {BasicForm} this
28247 submit : function(options){
28248 this.doAction('submit', options);
28253 * Shortcut to do a load action.
28254 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28255 * @return {BasicForm} this
28257 load : function(options){
28258 this.doAction('load', options);
28263 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
28264 * @param {Record} record The record to edit
28265 * @return {BasicForm} this
28267 updateRecord : function(record){
28268 record.beginEdit();
28269 var fs = record.fields;
28270 fs.each(function(f){
28271 var field = this.findField(f.name);
28273 record.set(f.name, field.getValue());
28281 * Loads an Roo.data.Record into this form.
28282 * @param {Record} record The record to load
28283 * @return {BasicForm} this
28285 loadRecord : function(record){
28286 this.setValues(record.data);
28291 beforeAction : function(action){
28292 var o = action.options;
28295 if(this.waitMsgTarget === true){
28296 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
28297 }else if(this.waitMsgTarget){
28298 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
28299 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
28301 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
28307 afterAction : function(action, success){
28308 this.activeAction = null;
28309 var o = action.options;
28311 if(this.waitMsgTarget === true){
28313 }else if(this.waitMsgTarget){
28314 this.waitMsgTarget.unmask();
28316 Roo.MessageBox.updateProgress(1);
28317 Roo.MessageBox.hide();
28324 Roo.callback(o.success, o.scope, [this, action]);
28325 this.fireEvent('actioncomplete', this, action);
28329 // failure condition..
28330 // we have a scenario where updates need confirming.
28331 // eg. if a locking scenario exists..
28332 // we look for { errors : { needs_confirm : true }} in the response.
28334 (typeof(action.result) != 'undefined') &&
28335 (typeof(action.result.errors) != 'undefined') &&
28336 (typeof(action.result.errors.needs_confirm) != 'undefined')
28339 Roo.MessageBox.confirm(
28340 "Change requires confirmation",
28341 action.result.errorMsg,
28346 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
28356 Roo.callback(o.failure, o.scope, [this, action]);
28357 // show an error message if no failed handler is set..
28358 if (!this.hasListener('actionfailed')) {
28359 Roo.MessageBox.alert("Error",
28360 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
28361 action.result.errorMsg :
28362 "Saving Failed, please check your entries or try again"
28366 this.fireEvent('actionfailed', this, action);
28372 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
28373 * @param {String} id The value to search for
28376 findField : function(id){
28377 var field = this.items.get(id);
28379 this.items.each(function(f){
28380 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
28386 return field || null;
28390 * Add a secondary form to this one,
28391 * Used to provide tabbed forms. One form is primary, with hidden values
28392 * which mirror the elements from the other forms.
28394 * @param {Roo.form.Form} form to add.
28397 addForm : function(form)
28400 if (this.childForms.indexOf(form) > -1) {
28404 this.childForms.push(form);
28406 Roo.each(form.allItems, function (fe) {
28408 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
28409 if (this.findField(n)) { // already added..
28412 var add = new Roo.form.Hidden({
28415 add.render(this.el);
28422 * Mark fields in this form invalid in bulk.
28423 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
28424 * @return {BasicForm} this
28426 markInvalid : function(errors){
28427 if(errors instanceof Array){
28428 for(var i = 0, len = errors.length; i < len; i++){
28429 var fieldError = errors[i];
28430 var f = this.findField(fieldError.id);
28432 f.markInvalid(fieldError.msg);
28438 if(typeof errors[id] != 'function' && (field = this.findField(id))){
28439 field.markInvalid(errors[id]);
28443 Roo.each(this.childForms || [], function (f) {
28444 f.markInvalid(errors);
28451 * Set values for fields in this form in bulk.
28452 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
28453 * @return {BasicForm} this
28455 setValues : function(values){
28456 if(values instanceof Array){ // array of objects
28457 for(var i = 0, len = values.length; i < len; i++){
28459 var f = this.findField(v.id);
28461 f.setValue(v.value);
28462 if(this.trackResetOnLoad){
28463 f.originalValue = f.getValue();
28467 }else{ // object hash
28470 if(typeof values[id] != 'function' && (field = this.findField(id))){
28472 if (field.setFromData &&
28473 field.valueField &&
28474 field.displayField &&
28475 // combos' with local stores can
28476 // be queried via setValue()
28477 // to set their value..
28478 (field.store && !field.store.isLocal)
28482 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
28483 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
28484 field.setFromData(sd);
28487 field.setValue(values[id]);
28491 if(this.trackResetOnLoad){
28492 field.originalValue = field.getValue();
28498 Roo.each(this.childForms || [], function (f) {
28499 f.setValues(values);
28506 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
28507 * they are returned as an array.
28508 * @param {Boolean} asString
28511 getValues : function(asString){
28512 if (this.childForms) {
28513 // copy values from the child forms
28514 Roo.each(this.childForms, function (f) {
28515 this.setValues(f.getValues());
28521 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
28522 if(asString === true){
28525 return Roo.urlDecode(fs);
28529 * Returns the fields in this form as an object with key/value pairs.
28530 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
28533 getFieldValues : function(with_hidden)
28535 if (this.childForms) {
28536 // copy values from the child forms
28537 // should this call getFieldValues - probably not as we do not currently copy
28538 // hidden fields when we generate..
28539 Roo.each(this.childForms, function (f) {
28540 this.setValues(f.getValues());
28545 this.items.each(function(f){
28546 if (!f.getName()) {
28549 var v = f.getValue();
28550 if (f.inputType =='radio') {
28551 if (typeof(ret[f.getName()]) == 'undefined') {
28552 ret[f.getName()] = ''; // empty..
28555 if (!f.el.dom.checked) {
28559 v = f.el.dom.value;
28563 // not sure if this supported any more..
28564 if ((typeof(v) == 'object') && f.getRawValue) {
28565 v = f.getRawValue() ; // dates..
28567 // combo boxes where name != hiddenName...
28568 if (f.name != f.getName()) {
28569 ret[f.name] = f.getRawValue();
28571 ret[f.getName()] = v;
28578 * Clears all invalid messages in this form.
28579 * @return {BasicForm} this
28581 clearInvalid : function(){
28582 this.items.each(function(f){
28586 Roo.each(this.childForms || [], function (f) {
28595 * Resets this form.
28596 * @return {BasicForm} this
28598 reset : function(){
28599 this.items.each(function(f){
28603 Roo.each(this.childForms || [], function (f) {
28612 * Add Roo.form components to this form.
28613 * @param {Field} field1
28614 * @param {Field} field2 (optional)
28615 * @param {Field} etc (optional)
28616 * @return {BasicForm} this
28619 this.items.addAll(Array.prototype.slice.call(arguments, 0));
28625 * Removes a field from the items collection (does NOT remove its markup).
28626 * @param {Field} field
28627 * @return {BasicForm} this
28629 remove : function(field){
28630 this.items.remove(field);
28635 * Looks at the fields in this form, checks them for an id attribute,
28636 * and calls applyTo on the existing dom element with that id.
28637 * @return {BasicForm} this
28639 render : function(){
28640 this.items.each(function(f){
28641 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
28649 * Calls {@link Ext#apply} for all fields in this form with the passed object.
28650 * @param {Object} values
28651 * @return {BasicForm} this
28653 applyToFields : function(o){
28654 this.items.each(function(f){
28661 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
28662 * @param {Object} values
28663 * @return {BasicForm} this
28665 applyIfToFields : function(o){
28666 this.items.each(function(f){
28674 Roo.BasicForm = Roo.form.BasicForm;/*
28676 * Ext JS Library 1.1.1
28677 * Copyright(c) 2006-2007, Ext JS, LLC.
28679 * Originally Released Under LGPL - original licence link has changed is not relivant.
28682 * <script type="text/javascript">
28686 * @class Roo.form.Form
28687 * @extends Roo.form.BasicForm
28688 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
28690 * @param {Object} config Configuration options
28692 Roo.form.Form = function(config){
28694 if (config.items) {
28695 xitems = config.items;
28696 delete config.items;
28700 Roo.form.Form.superclass.constructor.call(this, null, config);
28701 this.url = this.url || this.action;
28703 this.root = new Roo.form.Layout(Roo.applyIf({
28707 this.active = this.root;
28709 * Array of all the buttons that have been added to this form via {@link addButton}
28713 this.allItems = [];
28716 * @event clientvalidation
28717 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
28718 * @param {Form} this
28719 * @param {Boolean} valid true if the form has passed client-side validation
28721 clientvalidation: true,
28724 * Fires when the form is rendered
28725 * @param {Roo.form.Form} form
28730 if (this.progressUrl) {
28731 // push a hidden field onto the list of fields..
28735 name : 'UPLOAD_IDENTIFIER'
28740 Roo.each(xitems, this.addxtype, this);
28746 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
28748 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
28751 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
28754 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
28756 buttonAlign:'center',
28759 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
28764 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
28765 * This property cascades to child containers if not set.
28770 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
28771 * fires a looping event with that state. This is required to bind buttons to the valid
28772 * state using the config value formBind:true on the button.
28774 monitorValid : false,
28777 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
28782 * @cfg {String} progressUrl - Url to return progress data
28785 progressUrl : false,
28788 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
28789 * fields are added and the column is closed. If no fields are passed the column remains open
28790 * until end() is called.
28791 * @param {Object} config The config to pass to the column
28792 * @param {Field} field1 (optional)
28793 * @param {Field} field2 (optional)
28794 * @param {Field} etc (optional)
28795 * @return Column The column container object
28797 column : function(c){
28798 var col = new Roo.form.Column(c);
28800 if(arguments.length > 1){ // duplicate code required because of Opera
28801 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28808 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
28809 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
28810 * until end() is called.
28811 * @param {Object} config The config to pass to the fieldset
28812 * @param {Field} field1 (optional)
28813 * @param {Field} field2 (optional)
28814 * @param {Field} etc (optional)
28815 * @return FieldSet The fieldset container object
28817 fieldset : function(c){
28818 var fs = new Roo.form.FieldSet(c);
28820 if(arguments.length > 1){ // duplicate code required because of Opera
28821 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28828 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
28829 * fields are added and the container is closed. If no fields are passed the container remains open
28830 * until end() is called.
28831 * @param {Object} config The config to pass to the Layout
28832 * @param {Field} field1 (optional)
28833 * @param {Field} field2 (optional)
28834 * @param {Field} etc (optional)
28835 * @return Layout The container object
28837 container : function(c){
28838 var l = new Roo.form.Layout(c);
28840 if(arguments.length > 1){ // duplicate code required because of Opera
28841 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28848 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
28849 * @param {Object} container A Roo.form.Layout or subclass of Layout
28850 * @return {Form} this
28852 start : function(c){
28853 // cascade label info
28854 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
28855 this.active.stack.push(c);
28856 c.ownerCt = this.active;
28862 * Closes the current open container
28863 * @return {Form} this
28866 if(this.active == this.root){
28869 this.active = this.active.ownerCt;
28874 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
28875 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
28876 * as the label of the field.
28877 * @param {Field} field1
28878 * @param {Field} field2 (optional)
28879 * @param {Field} etc. (optional)
28880 * @return {Form} this
28883 this.active.stack.push.apply(this.active.stack, arguments);
28884 this.allItems.push.apply(this.allItems,arguments);
28886 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
28887 if(a[i].isFormField){
28892 Roo.form.Form.superclass.add.apply(this, r);
28902 * Find any element that has been added to a form, using it's ID or name
28903 * This can include framesets, columns etc. along with regular fields..
28904 * @param {String} id - id or name to find.
28906 * @return {Element} e - or false if nothing found.
28908 findbyId : function(id)
28914 Roo.each(this.allItems, function(f){
28915 if (f.id == id || f.name == id ){
28926 * Render this form into the passed container. This should only be called once!
28927 * @param {String/HTMLElement/Element} container The element this component should be rendered into
28928 * @return {Form} this
28930 render : function(ct)
28936 var o = this.autoCreate || {
28938 method : this.method || 'POST',
28939 id : this.id || Roo.id()
28941 this.initEl(ct.createChild(o));
28943 this.root.render(this.el);
28947 this.items.each(function(f){
28948 f.render('x-form-el-'+f.id);
28951 if(this.buttons.length > 0){
28952 // tables are required to maintain order and for correct IE layout
28953 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
28954 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
28955 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28957 var tr = tb.getElementsByTagName('tr')[0];
28958 for(var i = 0, len = this.buttons.length; i < len; i++) {
28959 var b = this.buttons[i];
28960 var td = document.createElement('td');
28961 td.className = 'x-form-btn-td';
28962 b.render(tr.appendChild(td));
28965 if(this.monitorValid){ // initialize after render
28966 this.startMonitoring();
28968 this.fireEvent('rendered', this);
28973 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
28974 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28975 * object or a valid Roo.DomHelper element config
28976 * @param {Function} handler The function called when the button is clicked
28977 * @param {Object} scope (optional) The scope of the handler function
28978 * @return {Roo.Button}
28980 addButton : function(config, handler, scope){
28984 minWidth: this.minButtonWidth,
28987 if(typeof config == "string"){
28990 Roo.apply(bc, config);
28992 var btn = new Roo.Button(null, bc);
28993 this.buttons.push(btn);
28998 * Adds a series of form elements (using the xtype property as the factory method.
28999 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
29000 * @param {Object} config
29003 addxtype : function()
29005 var ar = Array.prototype.slice.call(arguments, 0);
29007 for(var i = 0; i < ar.length; i++) {
29009 continue; // skip -- if this happends something invalid got sent, we
29010 // should ignore it, as basically that interface element will not show up
29011 // and that should be pretty obvious!!
29014 if (Roo.form[ar[i].xtype]) {
29016 var fe = Roo.factory(ar[i], Roo.form);
29022 fe.store.form = this;
29027 this.allItems.push(fe);
29028 if (fe.items && fe.addxtype) {
29029 fe.addxtype.apply(fe, fe.items);
29039 // console.log('adding ' + ar[i].xtype);
29041 if (ar[i].xtype == 'Button') {
29042 //console.log('adding button');
29043 //console.log(ar[i]);
29044 this.addButton(ar[i]);
29045 this.allItems.push(fe);
29049 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
29050 alert('end is not supported on xtype any more, use items');
29052 // //console.log('adding end');
29060 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
29061 * option "monitorValid"
29063 startMonitoring : function(){
29066 Roo.TaskMgr.start({
29067 run : this.bindHandler,
29068 interval : this.monitorPoll || 200,
29075 * Stops monitoring of the valid state of this form
29077 stopMonitoring : function(){
29078 this.bound = false;
29082 bindHandler : function(){
29084 return false; // stops binding
29087 this.items.each(function(f){
29088 if(!f.isValid(true)){
29093 for(var i = 0, len = this.buttons.length; i < len; i++){
29094 var btn = this.buttons[i];
29095 if(btn.formBind === true && btn.disabled === valid){
29096 btn.setDisabled(!valid);
29099 this.fireEvent('clientvalidation', this, valid);
29113 Roo.Form = Roo.form.Form;
29116 * Ext JS Library 1.1.1
29117 * Copyright(c) 2006-2007, Ext JS, LLC.
29119 * Originally Released Under LGPL - original licence link has changed is not relivant.
29122 * <script type="text/javascript">
29126 * @class Roo.form.Action
29127 * Internal Class used to handle form actions
29129 * @param {Roo.form.BasicForm} el The form element or its id
29130 * @param {Object} config Configuration options
29134 // define the action interface
29135 Roo.form.Action = function(form, options){
29137 this.options = options || {};
29140 * Client Validation Failed
29143 Roo.form.Action.CLIENT_INVALID = 'client';
29145 * Server Validation Failed
29148 Roo.form.Action.SERVER_INVALID = 'server';
29150 * Connect to Server Failed
29153 Roo.form.Action.CONNECT_FAILURE = 'connect';
29155 * Reading Data from Server Failed
29158 Roo.form.Action.LOAD_FAILURE = 'load';
29160 Roo.form.Action.prototype = {
29162 failureType : undefined,
29163 response : undefined,
29164 result : undefined,
29166 // interface method
29167 run : function(options){
29171 // interface method
29172 success : function(response){
29176 // interface method
29177 handleResponse : function(response){
29181 // default connection failure
29182 failure : function(response){
29184 this.response = response;
29185 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29186 this.form.afterAction(this, false);
29189 processResponse : function(response){
29190 this.response = response;
29191 if(!response.responseText){
29194 this.result = this.handleResponse(response);
29195 return this.result;
29198 // utility functions used internally
29199 getUrl : function(appendParams){
29200 var url = this.options.url || this.form.url || this.form.el.dom.action;
29202 var p = this.getParams();
29204 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
29210 getMethod : function(){
29211 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
29214 getParams : function(){
29215 var bp = this.form.baseParams;
29216 var p = this.options.params;
29218 if(typeof p == "object"){
29219 p = Roo.urlEncode(Roo.applyIf(p, bp));
29220 }else if(typeof p == 'string' && bp){
29221 p += '&' + Roo.urlEncode(bp);
29224 p = Roo.urlEncode(bp);
29229 createCallback : function(){
29231 success: this.success,
29232 failure: this.failure,
29234 timeout: (this.form.timeout*1000),
29235 upload: this.form.fileUpload ? this.success : undefined
29240 Roo.form.Action.Submit = function(form, options){
29241 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
29244 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
29247 haveProgress : false,
29248 uploadComplete : false,
29250 // uploadProgress indicator.
29251 uploadProgress : function()
29253 if (!this.form.progressUrl) {
29257 if (!this.haveProgress) {
29258 Roo.MessageBox.progress("Uploading", "Uploading");
29260 if (this.uploadComplete) {
29261 Roo.MessageBox.hide();
29265 this.haveProgress = true;
29267 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
29269 var c = new Roo.data.Connection();
29271 url : this.form.progressUrl,
29276 success : function(req){
29277 //console.log(data);
29281 rdata = Roo.decode(req.responseText)
29283 Roo.log("Invalid data from server..");
29287 if (!rdata || !rdata.success) {
29289 Roo.MessageBox.alert(Roo.encode(rdata));
29292 var data = rdata.data;
29294 if (this.uploadComplete) {
29295 Roo.MessageBox.hide();
29300 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
29301 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
29304 this.uploadProgress.defer(2000,this);
29307 failure: function(data) {
29308 Roo.log('progress url failed ');
29319 // run get Values on the form, so it syncs any secondary forms.
29320 this.form.getValues();
29322 var o = this.options;
29323 var method = this.getMethod();
29324 var isPost = method == 'POST';
29325 if(o.clientValidation === false || this.form.isValid()){
29327 if (this.form.progressUrl) {
29328 this.form.findField('UPLOAD_IDENTIFIER').setValue(
29329 (new Date() * 1) + '' + Math.random());
29334 Roo.Ajax.request(Roo.apply(this.createCallback(), {
29335 form:this.form.el.dom,
29336 url:this.getUrl(!isPost),
29338 params:isPost ? this.getParams() : null,
29339 isUpload: this.form.fileUpload
29342 this.uploadProgress();
29344 }else if (o.clientValidation !== false){ // client validation failed
29345 this.failureType = Roo.form.Action.CLIENT_INVALID;
29346 this.form.afterAction(this, false);
29350 success : function(response)
29352 this.uploadComplete= true;
29353 if (this.haveProgress) {
29354 Roo.MessageBox.hide();
29358 var result = this.processResponse(response);
29359 if(result === true || result.success){
29360 this.form.afterAction(this, true);
29364 this.form.markInvalid(result.errors);
29365 this.failureType = Roo.form.Action.SERVER_INVALID;
29367 this.form.afterAction(this, false);
29369 failure : function(response)
29371 this.uploadComplete= true;
29372 if (this.haveProgress) {
29373 Roo.MessageBox.hide();
29376 this.response = response;
29377 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29378 this.form.afterAction(this, false);
29381 handleResponse : function(response){
29382 if(this.form.errorReader){
29383 var rs = this.form.errorReader.read(response);
29386 for(var i = 0, len = rs.records.length; i < len; i++) {
29387 var r = rs.records[i];
29388 errors[i] = r.data;
29391 if(errors.length < 1){
29395 success : rs.success,
29401 ret = Roo.decode(response.responseText);
29405 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
29415 Roo.form.Action.Load = function(form, options){
29416 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
29417 this.reader = this.form.reader;
29420 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
29425 Roo.Ajax.request(Roo.apply(
29426 this.createCallback(), {
29427 method:this.getMethod(),
29428 url:this.getUrl(false),
29429 params:this.getParams()
29433 success : function(response){
29435 var result = this.processResponse(response);
29436 if(result === true || !result.success || !result.data){
29437 this.failureType = Roo.form.Action.LOAD_FAILURE;
29438 this.form.afterAction(this, false);
29441 this.form.clearInvalid();
29442 this.form.setValues(result.data);
29443 this.form.afterAction(this, true);
29446 handleResponse : function(response){
29447 if(this.form.reader){
29448 var rs = this.form.reader.read(response);
29449 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
29451 success : rs.success,
29455 return Roo.decode(response.responseText);
29459 Roo.form.Action.ACTION_TYPES = {
29460 'load' : Roo.form.Action.Load,
29461 'submit' : Roo.form.Action.Submit
29464 * Ext JS Library 1.1.1
29465 * Copyright(c) 2006-2007, Ext JS, LLC.
29467 * Originally Released Under LGPL - original licence link has changed is not relivant.
29470 * <script type="text/javascript">
29474 * @class Roo.form.Layout
29475 * @extends Roo.Component
29476 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
29478 * @param {Object} config Configuration options
29480 Roo.form.Layout = function(config){
29482 if (config.items) {
29483 xitems = config.items;
29484 delete config.items;
29486 Roo.form.Layout.superclass.constructor.call(this, config);
29488 Roo.each(xitems, this.addxtype, this);
29492 Roo.extend(Roo.form.Layout, Roo.Component, {
29494 * @cfg {String/Object} autoCreate
29495 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
29498 * @cfg {String/Object/Function} style
29499 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
29500 * a function which returns such a specification.
29503 * @cfg {String} labelAlign
29504 * Valid values are "left," "top" and "right" (defaults to "left")
29507 * @cfg {Number} labelWidth
29508 * Fixed width in pixels of all field labels (defaults to undefined)
29511 * @cfg {Boolean} clear
29512 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
29516 * @cfg {String} labelSeparator
29517 * The separator to use after field labels (defaults to ':')
29519 labelSeparator : ':',
29521 * @cfg {Boolean} hideLabels
29522 * True to suppress the display of field labels in this layout (defaults to false)
29524 hideLabels : false,
29527 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
29532 onRender : function(ct, position){
29533 if(this.el){ // from markup
29534 this.el = Roo.get(this.el);
29535 }else { // generate
29536 var cfg = this.getAutoCreate();
29537 this.el = ct.createChild(cfg, position);
29540 this.el.applyStyles(this.style);
29542 if(this.labelAlign){
29543 this.el.addClass('x-form-label-'+this.labelAlign);
29545 if(this.hideLabels){
29546 this.labelStyle = "display:none";
29547 this.elementStyle = "padding-left:0;";
29549 if(typeof this.labelWidth == 'number'){
29550 this.labelStyle = "width:"+this.labelWidth+"px;";
29551 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
29553 if(this.labelAlign == 'top'){
29554 this.labelStyle = "width:auto;";
29555 this.elementStyle = "padding-left:0;";
29558 var stack = this.stack;
29559 var slen = stack.length;
29561 if(!this.fieldTpl){
29562 var t = new Roo.Template(
29563 '<div class="x-form-item {5}">',
29564 '<label for="{0}" style="{2}">{1}{4}</label>',
29565 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29567 '</div><div class="x-form-clear-left"></div>'
29569 t.disableFormats = true;
29571 Roo.form.Layout.prototype.fieldTpl = t;
29573 for(var i = 0; i < slen; i++) {
29574 if(stack[i].isFormField){
29575 this.renderField(stack[i]);
29577 this.renderComponent(stack[i]);
29582 this.el.createChild({cls:'x-form-clear'});
29587 renderField : function(f){
29588 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
29591 f.labelStyle||this.labelStyle||'', //2
29592 this.elementStyle||'', //3
29593 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
29594 f.itemCls||this.itemCls||'' //5
29595 ], true).getPrevSibling());
29599 renderComponent : function(c){
29600 c.render(c.isLayout ? this.el : this.el.createChild());
29603 * Adds a object form elements (using the xtype property as the factory method.)
29604 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
29605 * @param {Object} config
29607 addxtype : function(o)
29609 // create the lement.
29610 o.form = this.form;
29611 var fe = Roo.factory(o, Roo.form);
29612 this.form.allItems.push(fe);
29613 this.stack.push(fe);
29615 if (fe.isFormField) {
29616 this.form.items.add(fe);
29624 * @class Roo.form.Column
29625 * @extends Roo.form.Layout
29626 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
29628 * @param {Object} config Configuration options
29630 Roo.form.Column = function(config){
29631 Roo.form.Column.superclass.constructor.call(this, config);
29634 Roo.extend(Roo.form.Column, Roo.form.Layout, {
29636 * @cfg {Number/String} width
29637 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29640 * @cfg {String/Object} autoCreate
29641 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
29645 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
29648 onRender : function(ct, position){
29649 Roo.form.Column.superclass.onRender.call(this, ct, position);
29651 this.el.setWidth(this.width);
29658 * @class Roo.form.Row
29659 * @extends Roo.form.Layout
29660 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
29662 * @param {Object} config Configuration options
29666 Roo.form.Row = function(config){
29667 Roo.form.Row.superclass.constructor.call(this, config);
29670 Roo.extend(Roo.form.Row, Roo.form.Layout, {
29672 * @cfg {Number/String} width
29673 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29676 * @cfg {Number/String} height
29677 * The fixed height of the column in pixels or CSS value (defaults to "auto")
29679 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
29683 onRender : function(ct, position){
29684 //console.log('row render');
29686 var t = new Roo.Template(
29687 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
29688 '<label for="{0}" style="{2}">{1}{4}</label>',
29689 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29693 t.disableFormats = true;
29695 Roo.form.Layout.prototype.rowTpl = t;
29697 this.fieldTpl = this.rowTpl;
29699 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
29700 var labelWidth = 100;
29702 if ((this.labelAlign != 'top')) {
29703 if (typeof this.labelWidth == 'number') {
29704 labelWidth = this.labelWidth
29706 this.padWidth = 20 + labelWidth;
29710 Roo.form.Column.superclass.onRender.call(this, ct, position);
29712 this.el.setWidth(this.width);
29715 this.el.setHeight(this.height);
29720 renderField : function(f){
29721 f.fieldEl = this.fieldTpl.append(this.el, [
29722 f.id, f.fieldLabel,
29723 f.labelStyle||this.labelStyle||'',
29724 this.elementStyle||'',
29725 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
29726 f.itemCls||this.itemCls||'',
29727 f.width ? f.width + this.padWidth : 160 + this.padWidth
29734 * @class Roo.form.FieldSet
29735 * @extends Roo.form.Layout
29736 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
29738 * @param {Object} config Configuration options
29740 Roo.form.FieldSet = function(config){
29741 Roo.form.FieldSet.superclass.constructor.call(this, config);
29744 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
29746 * @cfg {String} legend
29747 * The text to display as the legend for the FieldSet (defaults to '')
29750 * @cfg {String/Object} autoCreate
29751 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
29755 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
29758 onRender : function(ct, position){
29759 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
29761 this.setLegend(this.legend);
29766 setLegend : function(text){
29768 this.el.child('legend').update(text);
29773 * Ext JS Library 1.1.1
29774 * Copyright(c) 2006-2007, Ext JS, LLC.
29776 * Originally Released Under LGPL - original licence link has changed is not relivant.
29779 * <script type="text/javascript">
29782 * @class Roo.form.VTypes
29783 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
29786 Roo.form.VTypes = function(){
29787 // closure these in so they are only created once.
29788 var alpha = /^[a-zA-Z_]+$/;
29789 var alphanum = /^[a-zA-Z0-9_]+$/;
29790 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
29791 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
29793 // All these messages and functions are configurable
29796 * The function used to validate email addresses
29797 * @param {String} value The email address
29799 'email' : function(v){
29800 return email.test(v);
29803 * The error text to display when the email validation function returns false
29806 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
29808 * The keystroke filter mask to be applied on email input
29811 'emailMask' : /[a-z0-9_\.\-@]/i,
29814 * The function used to validate URLs
29815 * @param {String} value The URL
29817 'url' : function(v){
29818 return url.test(v);
29821 * The error text to display when the url validation function returns false
29824 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
29827 * The function used to validate alpha values
29828 * @param {String} value The value
29830 'alpha' : function(v){
29831 return alpha.test(v);
29834 * The error text to display when the alpha validation function returns false
29837 'alphaText' : 'This field should only contain letters and _',
29839 * The keystroke filter mask to be applied on alpha input
29842 'alphaMask' : /[a-z_]/i,
29845 * The function used to validate alphanumeric values
29846 * @param {String} value The value
29848 'alphanum' : function(v){
29849 return alphanum.test(v);
29852 * The error text to display when the alphanumeric validation function returns false
29855 'alphanumText' : 'This field should only contain letters, numbers and _',
29857 * The keystroke filter mask to be applied on alphanumeric input
29860 'alphanumMask' : /[a-z0-9_]/i
29862 }();//<script type="text/javascript">
29865 * @class Roo.form.FCKeditor
29866 * @extends Roo.form.TextArea
29867 * Wrapper around the FCKEditor http://www.fckeditor.net
29869 * Creates a new FCKeditor
29870 * @param {Object} config Configuration options
29872 Roo.form.FCKeditor = function(config){
29873 Roo.form.FCKeditor.superclass.constructor.call(this, config);
29876 * @event editorinit
29877 * Fired when the editor is initialized - you can add extra handlers here..
29878 * @param {FCKeditor} this
29879 * @param {Object} the FCK object.
29886 Roo.form.FCKeditor.editors = { };
29887 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
29889 //defaultAutoCreate : {
29890 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
29894 * @cfg {Object} fck options - see fck manual for details.
29899 * @cfg {Object} fck toolbar set (Basic or Default)
29901 toolbarSet : 'Basic',
29903 * @cfg {Object} fck BasePath
29905 basePath : '/fckeditor/',
29913 onRender : function(ct, position)
29916 this.defaultAutoCreate = {
29918 style:"width:300px;height:60px;",
29919 autocomplete: "off"
29922 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
29925 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
29926 if(this.preventScrollbars){
29927 this.el.setStyle("overflow", "hidden");
29929 this.el.setHeight(this.growMin);
29932 //console.log('onrender' + this.getId() );
29933 Roo.form.FCKeditor.editors[this.getId()] = this;
29936 this.replaceTextarea() ;
29940 getEditor : function() {
29941 return this.fckEditor;
29944 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
29945 * @param {Mixed} value The value to set
29949 setValue : function(value)
29951 //console.log('setValue: ' + value);
29953 if(typeof(value) == 'undefined') { // not sure why this is happending...
29956 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29958 //if(!this.el || !this.getEditor()) {
29959 // this.value = value;
29960 //this.setValue.defer(100,this,[value]);
29964 if(!this.getEditor()) {
29968 this.getEditor().SetData(value);
29975 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
29976 * @return {Mixed} value The field value
29978 getValue : function()
29981 if (this.frame && this.frame.dom.style.display == 'none') {
29982 return Roo.form.FCKeditor.superclass.getValue.call(this);
29985 if(!this.el || !this.getEditor()) {
29987 // this.getValue.defer(100,this);
29992 var value=this.getEditor().GetData();
29993 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29994 return Roo.form.FCKeditor.superclass.getValue.call(this);
30000 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
30001 * @return {Mixed} value The field value
30003 getRawValue : function()
30005 if (this.frame && this.frame.dom.style.display == 'none') {
30006 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
30009 if(!this.el || !this.getEditor()) {
30010 //this.getRawValue.defer(100,this);
30017 var value=this.getEditor().GetData();
30018 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
30019 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
30023 setSize : function(w,h) {
30027 //if (this.frame && this.frame.dom.style.display == 'none') {
30028 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30031 //if(!this.el || !this.getEditor()) {
30032 // this.setSize.defer(100,this, [w,h]);
30038 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30040 this.frame.dom.setAttribute('width', w);
30041 this.frame.dom.setAttribute('height', h);
30042 this.frame.setSize(w,h);
30046 toggleSourceEdit : function(value) {
30050 this.el.dom.style.display = value ? '' : 'none';
30051 this.frame.dom.style.display = value ? 'none' : '';
30056 focus: function(tag)
30058 if (this.frame.dom.style.display == 'none') {
30059 return Roo.form.FCKeditor.superclass.focus.call(this);
30061 if(!this.el || !this.getEditor()) {
30062 this.focus.defer(100,this, [tag]);
30069 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
30070 this.getEditor().Focus();
30072 if (!this.getEditor().Selection.GetSelection()) {
30073 this.focus.defer(100,this, [tag]);
30078 var r = this.getEditor().EditorDocument.createRange();
30079 r.setStart(tgs[0],0);
30080 r.setEnd(tgs[0],0);
30081 this.getEditor().Selection.GetSelection().removeAllRanges();
30082 this.getEditor().Selection.GetSelection().addRange(r);
30083 this.getEditor().Focus();
30090 replaceTextarea : function()
30092 if ( document.getElementById( this.getId() + '___Frame' ) )
30094 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
30096 // We must check the elements firstly using the Id and then the name.
30097 var oTextarea = document.getElementById( this.getId() );
30099 var colElementsByName = document.getElementsByName( this.getId() ) ;
30101 oTextarea.style.display = 'none' ;
30103 if ( oTextarea.tabIndex ) {
30104 this.TabIndex = oTextarea.tabIndex ;
30107 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
30108 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
30109 this.frame = Roo.get(this.getId() + '___Frame')
30112 _getConfigHtml : function()
30116 for ( var o in this.fckconfig ) {
30117 sConfig += sConfig.length > 0 ? '&' : '';
30118 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
30121 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
30125 _getIFrameHtml : function()
30127 var sFile = 'fckeditor.html' ;
30128 /* no idea what this is about..
30131 if ( (/fcksource=true/i).test( window.top.location.search ) )
30132 sFile = 'fckeditor.original.html' ;
30137 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
30138 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
30141 var html = '<iframe id="' + this.getId() +
30142 '___Frame" src="' + sLink +
30143 '" width="' + this.width +
30144 '" height="' + this.height + '"' +
30145 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
30146 ' frameborder="0" scrolling="no"></iframe>' ;
30151 _insertHtmlBefore : function( html, element )
30153 if ( element.insertAdjacentHTML ) {
30155 element.insertAdjacentHTML( 'beforeBegin', html ) ;
30157 var oRange = document.createRange() ;
30158 oRange.setStartBefore( element ) ;
30159 var oFragment = oRange.createContextualFragment( html );
30160 element.parentNode.insertBefore( oFragment, element ) ;
30173 //Roo.reg('fckeditor', Roo.form.FCKeditor);
30175 function FCKeditor_OnComplete(editorInstance){
30176 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
30177 f.fckEditor = editorInstance;
30178 //console.log("loaded");
30179 f.fireEvent('editorinit', f, editorInstance);
30199 //<script type="text/javascript">
30201 * @class Roo.form.GridField
30202 * @extends Roo.form.Field
30203 * Embed a grid (or editable grid into a form)
30206 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
30208 * xgrid.store = Roo.data.Store
30209 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
30210 * xgrid.store.reader = Roo.data.JsonReader
30214 * Creates a new GridField
30215 * @param {Object} config Configuration options
30217 Roo.form.GridField = function(config){
30218 Roo.form.GridField.superclass.constructor.call(this, config);
30222 Roo.extend(Roo.form.GridField, Roo.form.Field, {
30224 * @cfg {Number} width - used to restrict width of grid..
30228 * @cfg {Number} height - used to restrict height of grid..
30232 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
30238 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30239 * {tag: "input", type: "checkbox", autocomplete: "off"})
30241 // defaultAutoCreate : { tag: 'div' },
30242 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30244 * @cfg {String} addTitle Text to include for adding a title.
30248 onResize : function(){
30249 Roo.form.Field.superclass.onResize.apply(this, arguments);
30252 initEvents : function(){
30253 // Roo.form.Checkbox.superclass.initEvents.call(this);
30254 // has no events...
30259 getResizeEl : function(){
30263 getPositionEl : function(){
30268 onRender : function(ct, position){
30270 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
30271 var style = this.style;
30274 Roo.form.GridField.superclass.onRender.call(this, ct, position);
30275 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
30276 this.viewEl = this.wrap.createChild({ tag: 'div' });
30278 this.viewEl.applyStyles(style);
30281 this.viewEl.setWidth(this.width);
30284 this.viewEl.setHeight(this.height);
30286 //if(this.inputValue !== undefined){
30287 //this.setValue(this.value);
30290 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
30293 this.grid.render();
30294 this.grid.getDataSource().on('remove', this.refreshValue, this);
30295 this.grid.getDataSource().on('update', this.refreshValue, this);
30296 this.grid.on('afteredit', this.refreshValue, this);
30302 * Sets the value of the item.
30303 * @param {String} either an object or a string..
30305 setValue : function(v){
30307 v = v || []; // empty set..
30308 // this does not seem smart - it really only affects memoryproxy grids..
30309 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
30310 var ds = this.grid.getDataSource();
30311 // assumes a json reader..
30313 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
30314 ds.loadData( data);
30316 // clear selection so it does not get stale.
30317 if (this.grid.sm) {
30318 this.grid.sm.clearSelections();
30321 Roo.form.GridField.superclass.setValue.call(this, v);
30322 this.refreshValue();
30323 // should load data in the grid really....
30327 refreshValue: function() {
30329 this.grid.getDataSource().each(function(r) {
30332 this.el.dom.value = Roo.encode(val);
30340 * Ext JS Library 1.1.1
30341 * Copyright(c) 2006-2007, Ext JS, LLC.
30343 * Originally Released Under LGPL - original licence link has changed is not relivant.
30346 * <script type="text/javascript">
30349 * @class Roo.form.DisplayField
30350 * @extends Roo.form.Field
30351 * A generic Field to display non-editable data.
30353 * Creates a new Display Field item.
30354 * @param {Object} config Configuration options
30356 Roo.form.DisplayField = function(config){
30357 Roo.form.DisplayField.superclass.constructor.call(this, config);
30361 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
30362 inputType: 'hidden',
30368 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30370 focusClass : undefined,
30372 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30374 fieldClass: 'x-form-field',
30377 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
30379 valueRenderer: undefined,
30383 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30384 * {tag: "input", type: "checkbox", autocomplete: "off"})
30387 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30389 onResize : function(){
30390 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
30394 initEvents : function(){
30395 // Roo.form.Checkbox.superclass.initEvents.call(this);
30396 // has no events...
30401 getResizeEl : function(){
30405 getPositionEl : function(){
30410 onRender : function(ct, position){
30412 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
30413 //if(this.inputValue !== undefined){
30414 this.wrap = this.el.wrap();
30416 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
30418 if (this.bodyStyle) {
30419 this.viewEl.applyStyles(this.bodyStyle);
30421 //this.viewEl.setStyle('padding', '2px');
30423 this.setValue(this.value);
30428 initValue : Roo.emptyFn,
30433 onClick : function(){
30438 * Sets the checked state of the checkbox.
30439 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
30441 setValue : function(v){
30443 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
30444 // this might be called before we have a dom element..
30445 if (!this.viewEl) {
30448 this.viewEl.dom.innerHTML = html;
30449 Roo.form.DisplayField.superclass.setValue.call(this, v);
30459 * @class Roo.form.DayPicker
30460 * @extends Roo.form.Field
30461 * A Day picker show [M] [T] [W] ....
30463 * Creates a new Day Picker
30464 * @param {Object} config Configuration options
30466 Roo.form.DayPicker= function(config){
30467 Roo.form.DayPicker.superclass.constructor.call(this, config);
30471 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
30473 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30475 focusClass : undefined,
30477 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30479 fieldClass: "x-form-field",
30482 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30483 * {tag: "input", type: "checkbox", autocomplete: "off"})
30485 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
30488 actionMode : 'viewEl',
30492 inputType : 'hidden',
30495 inputElement: false, // real input element?
30496 basedOn: false, // ????
30498 isFormField: true, // not sure where this is needed!!!!
30500 onResize : function(){
30501 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
30502 if(!this.boxLabel){
30503 this.el.alignTo(this.wrap, 'c-c');
30507 initEvents : function(){
30508 Roo.form.Checkbox.superclass.initEvents.call(this);
30509 this.el.on("click", this.onClick, this);
30510 this.el.on("change", this.onClick, this);
30514 getResizeEl : function(){
30518 getPositionEl : function(){
30524 onRender : function(ct, position){
30525 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
30527 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
30529 var r1 = '<table><tr>';
30530 var r2 = '<tr class="x-form-daypick-icons">';
30531 for (var i=0; i < 7; i++) {
30532 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
30533 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
30536 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
30537 viewEl.select('img').on('click', this.onClick, this);
30538 this.viewEl = viewEl;
30541 // this will not work on Chrome!!!
30542 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
30543 this.el.on('propertychange', this.setFromHidden, this); //ie
30551 initValue : Roo.emptyFn,
30554 * Returns the checked state of the checkbox.
30555 * @return {Boolean} True if checked, else false
30557 getValue : function(){
30558 return this.el.dom.value;
30563 onClick : function(e){
30564 //this.setChecked(!this.checked);
30565 Roo.get(e.target).toggleClass('x-menu-item-checked');
30566 this.refreshValue();
30567 //if(this.el.dom.checked != this.checked){
30568 // this.setValue(this.el.dom.checked);
30573 refreshValue : function()
30576 this.viewEl.select('img',true).each(function(e,i,n) {
30577 val += e.is(".x-menu-item-checked") ? String(n) : '';
30579 this.setValue(val, true);
30583 * Sets the checked state of the checkbox.
30584 * On is always based on a string comparison between inputValue and the param.
30585 * @param {Boolean/String} value - the value to set
30586 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
30588 setValue : function(v,suppressEvent){
30589 if (!this.el.dom) {
30592 var old = this.el.dom.value ;
30593 this.el.dom.value = v;
30594 if (suppressEvent) {
30598 // update display..
30599 this.viewEl.select('img',true).each(function(e,i,n) {
30601 var on = e.is(".x-menu-item-checked");
30602 var newv = v.indexOf(String(n)) > -1;
30604 e.toggleClass('x-menu-item-checked');
30610 this.fireEvent('change', this, v, old);
30615 // handle setting of hidden value by some other method!!?!?
30616 setFromHidden: function()
30621 //console.log("SET FROM HIDDEN");
30622 //alert('setFrom hidden');
30623 this.setValue(this.el.dom.value);
30626 onDestroy : function()
30629 Roo.get(this.viewEl).remove();
30632 Roo.form.DayPicker.superclass.onDestroy.call(this);
30636 * RooJS Library 1.1.1
30637 * Copyright(c) 2008-2011 Alan Knowles
30644 * @class Roo.form.ComboCheck
30645 * @extends Roo.form.ComboBox
30646 * A combobox for multiple select items.
30648 * FIXME - could do with a reset button..
30651 * Create a new ComboCheck
30652 * @param {Object} config Configuration options
30654 Roo.form.ComboCheck = function(config){
30655 Roo.form.ComboCheck.superclass.constructor.call(this, config);
30656 // should verify some data...
30658 // hiddenName = required..
30659 // displayField = required
30660 // valudField == required
30661 var req= [ 'hiddenName', 'displayField', 'valueField' ];
30663 Roo.each(req, function(e) {
30664 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
30665 throw "Roo.form.ComboCheck : missing value for: " + e;
30672 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
30677 selectedClass: 'x-menu-item-checked',
30680 onRender : function(ct, position){
30686 var cls = 'x-combo-list';
30689 this.tpl = new Roo.Template({
30690 html : '<div class="'+cls+'-item x-menu-check-item">' +
30691 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
30692 '<span>{' + this.displayField + '}</span>' +
30699 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
30700 this.view.singleSelect = false;
30701 this.view.multiSelect = true;
30702 this.view.toggleSelect = true;
30703 this.pageTb.add(new Roo.Toolbar.Fill(), {
30706 handler: function()
30713 onViewOver : function(e, t){
30719 onViewClick : function(doFocus,index){
30723 select: function () {
30724 //Roo.log("SELECT CALLED");
30727 selectByValue : function(xv, scrollIntoView){
30728 var ar = this.getValueArray();
30731 Roo.each(ar, function(v) {
30732 if(v === undefined || v === null){
30735 var r = this.findRecord(this.valueField, v);
30737 sels.push(this.store.indexOf(r))
30741 this.view.select(sels);
30747 onSelect : function(record, index){
30748 // Roo.log("onselect Called");
30749 // this is only called by the clear button now..
30750 this.view.clearSelections();
30751 this.setValue('[]');
30752 if (this.value != this.valueBefore) {
30753 this.fireEvent('change', this, this.value, this.valueBefore);
30754 this.valueBefore = this.value;
30757 getValueArray : function()
30762 //Roo.log(this.value);
30763 if (typeof(this.value) == 'undefined') {
30766 var ar = Roo.decode(this.value);
30767 return ar instanceof Array ? ar : []; //?? valid?
30770 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
30775 expand : function ()
30778 Roo.form.ComboCheck.superclass.expand.call(this);
30779 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
30780 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
30785 collapse : function(){
30786 Roo.form.ComboCheck.superclass.collapse.call(this);
30787 var sl = this.view.getSelectedIndexes();
30788 var st = this.store;
30792 Roo.each(sl, function(i) {
30794 nv.push(r.get(this.valueField));
30796 this.setValue(Roo.encode(nv));
30797 if (this.value != this.valueBefore) {
30799 this.fireEvent('change', this, this.value, this.valueBefore);
30800 this.valueBefore = this.value;
30805 setValue : function(v){
30809 var vals = this.getValueArray();
30811 Roo.each(vals, function(k) {
30812 var r = this.findRecord(this.valueField, k);
30814 tv.push(r.data[this.displayField]);
30815 }else if(this.valueNotFoundText !== undefined){
30816 tv.push( this.valueNotFoundText );
30821 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
30822 this.hiddenField.value = v;
30828 * Ext JS Library 1.1.1
30829 * Copyright(c) 2006-2007, Ext JS, LLC.
30831 * Originally Released Under LGPL - original licence link has changed is not relivant.
30834 * <script type="text/javascript">
30838 * @class Roo.form.Signature
30839 * @extends Roo.form.Field
30843 * @param {Object} config Configuration options
30846 Roo.form.Signature = function(config){
30847 Roo.form.Signature.superclass.constructor.call(this, config);
30849 this.addEvents({// not in used??
30852 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
30853 * @param {Roo.form.Signature} combo This combo box
30858 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
30859 * @param {Roo.form.ComboBox} combo This combo box
30860 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
30866 Roo.extend(Roo.form.Signature, Roo.form.Field, {
30868 * @cfg {Object} labels Label to use when rendering a form.
30872 * confirm : "Confirm"
30877 confirm : "Confirm"
30880 * @cfg {Number} width The signature panel width (defaults to 300)
30884 * @cfg {Number} height The signature panel height (defaults to 100)
30888 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
30890 allowBlank : false,
30893 // {Object} signPanel The signature SVG panel element (defaults to {})
30895 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
30896 isMouseDown : false,
30897 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
30898 isConfirmed : false,
30899 // {String} signatureTmp SVG mapping string (defaults to empty string)
30903 defaultAutoCreate : { // modified by initCompnoent..
30909 onRender : function(ct, position){
30911 Roo.form.Signature.superclass.onRender.call(this, ct, position);
30913 this.wrap = this.el.wrap({
30914 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
30917 this.createToolbar(this);
30918 this.signPanel = this.wrap.createChild({
30920 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
30924 this.svgID = Roo.id();
30925 this.svgEl = this.signPanel.createChild({
30926 xmlns : 'http://www.w3.org/2000/svg',
30928 id : this.svgID + "-svg",
30930 height: this.height,
30931 viewBox: '0 0 '+this.width+' '+this.height,
30935 id: this.svgID + "-svg-r",
30937 height: this.height,
30942 id: this.svgID + "-svg-l",
30944 y1: (this.height*0.8), // start set the line in 80% of height
30945 x2: this.width, // end
30946 y2: (this.height*0.8), // end set the line in 80% of height
30948 'stroke-width': "1",
30949 'stroke-dasharray': "3",
30950 'shape-rendering': "crispEdges",
30951 'pointer-events': "none"
30955 id: this.svgID + "-svg-p",
30957 'stroke-width': "3",
30959 'pointer-events': 'none'
30964 this.svgBox = this.svgEl.dom.getScreenCTM();
30966 createSVG : function(){
30967 var svg = this.signPanel;
30968 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
30971 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
30972 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
30973 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
30974 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
30975 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
30976 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
30977 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
30980 isTouchEvent : function(e){
30981 return e.type.match(/^touch/);
30983 getCoords : function (e) {
30984 var pt = this.svgEl.dom.createSVGPoint();
30987 if (this.isTouchEvent(e)) {
30988 pt.x = e.targetTouches[0].clientX
30989 pt.y = e.targetTouches[0].clientY;
30991 var a = this.svgEl.dom.getScreenCTM();
30992 var b = a.inverse();
30993 var mx = pt.matrixTransform(b);
30994 return mx.x + ',' + mx.y;
30996 //mouse event headler
30997 down : function (e) {
30998 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
30999 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
31001 this.isMouseDown = true;
31003 e.preventDefault();
31005 move : function (e) {
31006 if (this.isMouseDown) {
31007 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
31008 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
31011 e.preventDefault();
31013 up : function (e) {
31014 this.isMouseDown = false;
31015 var sp = this.signatureTmp.split(' ');
31018 if(!sp[sp.length-2].match(/^L/)){
31022 this.signatureTmp = sp.join(" ");
31025 if(this.getValue() != this.signatureTmp){
31026 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31027 this.isConfirmed = false;
31029 e.preventDefault();
31033 * Protected method that will not generally be called directly. It
31034 * is called when the editor creates its toolbar. Override this method if you need to
31035 * add custom toolbar buttons.
31036 * @param {HtmlEditor} editor
31038 createToolbar : function(editor){
31039 function btn(id, toggle, handler){
31040 var xid = fid + '-'+ id ;
31044 cls : 'x-btn-icon x-edit-'+id,
31045 enableToggle:toggle !== false,
31046 scope: editor, // was editor...
31047 handler:handler||editor.relayBtnCmd,
31048 clickEvent:'mousedown',
31049 tooltip: etb.buttonTips[id] || undefined, ///tips ???
31055 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
31059 cls : ' x-signature-btn x-signature-'+id,
31060 scope: editor, // was editor...
31061 handler: this.reset,
31062 clickEvent:'mousedown',
31063 text: this.labels.clear
31070 cls : ' x-signature-btn x-signature-'+id,
31071 scope: editor, // was editor...
31072 handler: this.confirmHandler,
31073 clickEvent:'mousedown',
31074 text: this.labels.confirm
31081 * when user is clicked confirm then show this image.....
31083 * @return {String} Image Data URI
31085 getImageDataURI : function(){
31086 var svg = this.svgEl.dom.parentNode.innerHTML;
31087 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
31092 * @return {Boolean} this.isConfirmed
31094 getConfirmed : function(){
31095 return this.isConfirmed;
31099 * @return {Number} this.width
31101 getWidth : function(){
31106 * @return {Number} this.height
31108 getHeight : function(){
31109 return this.height;
31112 getSignature : function(){
31113 return this.signatureTmp;
31116 reset : function(){
31117 this.signatureTmp = '';
31118 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31119 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
31120 this.isConfirmed = false;
31121 Roo.form.Signature.superclass.reset.call(this);
31123 setSignature : function(s){
31124 this.signatureTmp = s;
31125 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31126 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
31128 this.isConfirmed = false;
31129 Roo.form.Signature.superclass.reset.call(this);
31132 // Roo.log(this.signPanel.dom.contentWindow.up())
31135 setConfirmed : function(){
31139 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
31142 confirmHandler : function(){
31143 if(!this.getSignature()){
31147 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
31148 this.setValue(this.getSignature());
31149 this.isConfirmed = true;
31151 this.fireEvent('confirm', this);
31154 // Subclasses should provide the validation implementation by overriding this
31155 validateValue : function(value){
31156 if(this.allowBlank){
31160 if(this.isConfirmed){
31167 * Ext JS Library 1.1.1
31168 * Copyright(c) 2006-2007, Ext JS, LLC.
31170 * Originally Released Under LGPL - original licence link has changed is not relivant.
31173 * <script type="text/javascript">
31178 * @class Roo.form.ComboBox
31179 * @extends Roo.form.TriggerField
31180 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
31182 * Create a new ComboBox.
31183 * @param {Object} config Configuration options
31185 Roo.form.Select = function(config){
31186 Roo.form.Select.superclass.constructor.call(this, config);
31190 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
31192 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
31195 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
31196 * rendering into an Roo.Editor, defaults to false)
31199 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
31200 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
31203 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
31206 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
31207 * the dropdown list (defaults to undefined, with no header element)
31211 * @cfg {String/Roo.Template} tpl The template to use to render the output
31215 defaultAutoCreate : {tag: "select" },
31217 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
31219 listWidth: undefined,
31221 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
31222 * mode = 'remote' or 'text' if mode = 'local')
31224 displayField: undefined,
31226 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
31227 * mode = 'remote' or 'value' if mode = 'local').
31228 * Note: use of a valueField requires the user make a selection
31229 * in order for a value to be mapped.
31231 valueField: undefined,
31235 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
31236 * field's data value (defaults to the underlying DOM element's name)
31238 hiddenName: undefined,
31240 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
31244 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
31246 selectedClass: 'x-combo-selected',
31248 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
31249 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
31250 * which displays a downward arrow icon).
31252 triggerClass : 'x-form-arrow-trigger',
31254 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31258 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
31259 * anchor positions (defaults to 'tl-bl')
31261 listAlign: 'tl-bl?',
31263 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
31267 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
31268 * query specified by the allQuery config option (defaults to 'query')
31270 triggerAction: 'query',
31272 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
31273 * (defaults to 4, does not apply if editable = false)
31277 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
31278 * delay (typeAheadDelay) if it matches a known value (defaults to false)
31282 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
31283 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
31287 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
31288 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
31292 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
31293 * when editable = true (defaults to false)
31295 selectOnFocus:false,
31297 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
31299 queryParam: 'query',
31301 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
31302 * when mode = 'remote' (defaults to 'Loading...')
31304 loadingText: 'Loading...',
31306 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
31310 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
31314 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
31315 * traditional select (defaults to true)
31319 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
31323 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
31327 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
31328 * listWidth has a higher value)
31332 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
31333 * allow the user to set arbitrary text into the field (defaults to false)
31335 forceSelection:false,
31337 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
31338 * if typeAhead = true (defaults to 250)
31340 typeAheadDelay : 250,
31342 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
31343 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
31345 valueNotFoundText : undefined,
31348 * @cfg {String} defaultValue The value displayed after loading the store.
31353 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
31355 blockFocus : false,
31358 * @cfg {Boolean} disableClear Disable showing of clear button.
31360 disableClear : false,
31362 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
31364 alwaysQuery : false,
31370 // element that contains real text value.. (when hidden is used..)
31373 onRender : function(ct, position){
31374 Roo.form.Field.prototype.onRender.call(this, ct, position);
31377 this.store.on('beforeload', this.onBeforeLoad, this);
31378 this.store.on('load', this.onLoad, this);
31379 this.store.on('loadexception', this.onLoadException, this);
31380 this.store.load({});
31388 initEvents : function(){
31389 //Roo.form.ComboBox.superclass.initEvents.call(this);
31393 onDestroy : function(){
31396 this.store.un('beforeload', this.onBeforeLoad, this);
31397 this.store.un('load', this.onLoad, this);
31398 this.store.un('loadexception', this.onLoadException, this);
31400 //Roo.form.ComboBox.superclass.onDestroy.call(this);
31404 fireKey : function(e){
31405 if(e.isNavKeyPress() && !this.list.isVisible()){
31406 this.fireEvent("specialkey", this, e);
31411 onResize: function(w, h){
31419 * Allow or prevent the user from directly editing the field text. If false is passed,
31420 * the user will only be able to select from the items defined in the dropdown list. This method
31421 * is the runtime equivalent of setting the 'editable' config option at config time.
31422 * @param {Boolean} value True to allow the user to directly edit the field text
31424 setEditable : function(value){
31429 onBeforeLoad : function(){
31431 Roo.log("Select before load");
31434 this.innerList.update(this.loadingText ?
31435 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
31436 //this.restrictHeight();
31437 this.selectedIndex = -1;
31441 onLoad : function(){
31444 var dom = this.el.dom;
31445 dom.innerHTML = '';
31446 var od = dom.ownerDocument;
31448 if (this.emptyText) {
31449 var op = od.createElement('option');
31450 op.setAttribute('value', '');
31451 op.innerHTML = String.format('{0}', this.emptyText);
31452 dom.appendChild(op);
31454 if(this.store.getCount() > 0){
31456 var vf = this.valueField;
31457 var df = this.displayField;
31458 this.store.data.each(function(r) {
31459 // which colmsn to use... testing - cdoe / title..
31460 var op = od.createElement('option');
31461 op.setAttribute('value', r.data[vf]);
31462 op.innerHTML = String.format('{0}', r.data[df]);
31463 dom.appendChild(op);
31465 if (typeof(this.defaultValue != 'undefined')) {
31466 this.setValue(this.defaultValue);
31471 //this.onEmptyResults();
31476 onLoadException : function()
31478 dom.innerHTML = '';
31480 Roo.log("Select on load exception");
31484 Roo.log(this.store.reader.jsonData);
31485 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
31486 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
31492 onTypeAhead : function(){
31497 onSelect : function(record, index){
31498 Roo.log('on select?');
31500 if(this.fireEvent('beforeselect', this, record, index) !== false){
31501 this.setFromData(index > -1 ? record.data : false);
31503 this.fireEvent('select', this, record, index);
31508 * Returns the currently selected field value or empty string if no value is set.
31509 * @return {String} value The selected value
31511 getValue : function(){
31512 var dom = this.el.dom;
31513 this.value = dom.options[dom.selectedIndex].value;
31519 * Clears any text/value currently set in the field
31521 clearValue : function(){
31523 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
31528 * Sets the specified value into the field. If the value finds a match, the corresponding record text
31529 * will be displayed in the field. If the value does not match the data value of an existing item,
31530 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
31531 * Otherwise the field will be blank (although the value will still be set).
31532 * @param {String} value The value to match
31534 setValue : function(v){
31535 var d = this.el.dom;
31536 for (var i =0; i < d.options.length;i++) {
31537 if (v == d.options[i].value) {
31538 d.selectedIndex = i;
31546 * @property {Object} the last set data for the element
31551 * Sets the value of the field based on a object which is related to the record format for the store.
31552 * @param {Object} value the value to set as. or false on reset?
31554 setFromData : function(o){
31555 Roo.log('setfrom data?');
31561 reset : function(){
31565 findRecord : function(prop, value){
31570 if(this.store.getCount() > 0){
31571 this.store.each(function(r){
31572 if(r.data[prop] == value){
31582 getName: function()
31584 // returns hidden if it's set..
31585 if (!this.rendered) {return ''};
31586 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
31594 onEmptyResults : function(){
31595 Roo.log('empty results');
31600 * Returns true if the dropdown list is expanded, else false.
31602 isExpanded : function(){
31607 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
31608 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31609 * @param {String} value The data value of the item to select
31610 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31611 * selected item if it is not currently in view (defaults to true)
31612 * @return {Boolean} True if the value matched an item in the list, else false
31614 selectByValue : function(v, scrollIntoView){
31615 Roo.log('select By Value');
31618 if(v !== undefined && v !== null){
31619 var r = this.findRecord(this.valueField || this.displayField, v);
31621 this.select(this.store.indexOf(r), scrollIntoView);
31629 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
31630 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31631 * @param {Number} index The zero-based index of the list item to select
31632 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31633 * selected item if it is not currently in view (defaults to true)
31635 select : function(index, scrollIntoView){
31636 Roo.log('select ');
31639 this.selectedIndex = index;
31640 this.view.select(index);
31641 if(scrollIntoView !== false){
31642 var el = this.view.getNode(index);
31644 this.innerList.scrollChildIntoView(el, false);
31652 validateBlur : function(){
31659 initQuery : function(){
31660 this.doQuery(this.getRawValue());
31664 doForce : function(){
31665 if(this.el.dom.value.length > 0){
31666 this.el.dom.value =
31667 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
31673 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
31674 * query allowing the query action to be canceled if needed.
31675 * @param {String} query The SQL query to execute
31676 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
31677 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
31678 * saved in the current store (defaults to false)
31680 doQuery : function(q, forceAll){
31682 Roo.log('doQuery?');
31683 if(q === undefined || q === null){
31688 forceAll: forceAll,
31692 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
31696 forceAll = qe.forceAll;
31697 if(forceAll === true || (q.length >= this.minChars)){
31698 if(this.lastQuery != q || this.alwaysQuery){
31699 this.lastQuery = q;
31700 if(this.mode == 'local'){
31701 this.selectedIndex = -1;
31703 this.store.clearFilter();
31705 this.store.filter(this.displayField, q);
31709 this.store.baseParams[this.queryParam] = q;
31711 params: this.getParams(q)
31716 this.selectedIndex = -1;
31723 getParams : function(q){
31725 //p[this.queryParam] = q;
31728 p.limit = this.pageSize;
31734 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
31736 collapse : function(){
31741 collapseIf : function(e){
31746 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
31748 expand : function(){
31756 * @cfg {Boolean} grow
31760 * @cfg {Number} growMin
31764 * @cfg {Number} growMax
31772 setWidth : function()
31776 getResizeEl : function(){
31779 });//<script type="text/javasscript">
31783 * @class Roo.DDView
31784 * A DnD enabled version of Roo.View.
31785 * @param {Element/String} container The Element in which to create the View.
31786 * @param {String} tpl The template string used to create the markup for each element of the View
31787 * @param {Object} config The configuration properties. These include all the config options of
31788 * {@link Roo.View} plus some specific to this class.<br>
31790 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
31791 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
31793 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
31794 .x-view-drag-insert-above {
31795 border-top:1px dotted #3366cc;
31797 .x-view-drag-insert-below {
31798 border-bottom:1px dotted #3366cc;
31804 Roo.DDView = function(container, tpl, config) {
31805 Roo.DDView.superclass.constructor.apply(this, arguments);
31806 this.getEl().setStyle("outline", "0px none");
31807 this.getEl().unselectable();
31808 if (this.dragGroup) {
31809 this.setDraggable(this.dragGroup.split(","));
31811 if (this.dropGroup) {
31812 this.setDroppable(this.dropGroup.split(","));
31814 if (this.deletable) {
31815 this.setDeletable();
31817 this.isDirtyFlag = false;
31823 Roo.extend(Roo.DDView, Roo.View, {
31824 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
31825 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
31826 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
31827 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
31831 reset: Roo.emptyFn,
31833 clearInvalid: Roo.form.Field.prototype.clearInvalid,
31835 validate: function() {
31839 destroy: function() {
31840 this.purgeListeners();
31841 this.getEl.removeAllListeners();
31842 this.getEl().remove();
31843 if (this.dragZone) {
31844 if (this.dragZone.destroy) {
31845 this.dragZone.destroy();
31848 if (this.dropZone) {
31849 if (this.dropZone.destroy) {
31850 this.dropZone.destroy();
31855 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
31856 getName: function() {
31860 /** Loads the View from a JSON string representing the Records to put into the Store. */
31861 setValue: function(v) {
31863 throw "DDView.setValue(). DDView must be constructed with a valid Store";
31866 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
31867 this.store.proxy = new Roo.data.MemoryProxy(data);
31871 /** @return {String} a parenthesised list of the ids of the Records in the View. */
31872 getValue: function() {
31874 this.store.each(function(rec) {
31875 result += rec.id + ',';
31877 return result.substr(0, result.length - 1) + ')';
31880 getIds: function() {
31881 var i = 0, result = new Array(this.store.getCount());
31882 this.store.each(function(rec) {
31883 result[i++] = rec.id;
31888 isDirty: function() {
31889 return this.isDirtyFlag;
31893 * Part of the Roo.dd.DropZone interface. If no target node is found, the
31894 * whole Element becomes the target, and this causes the drop gesture to append.
31896 getTargetFromEvent : function(e) {
31897 var target = e.getTarget();
31898 while ((target !== null) && (target.parentNode != this.el.dom)) {
31899 target = target.parentNode;
31902 target = this.el.dom.lastChild || this.el.dom;
31908 * Create the drag data which consists of an object which has the property "ddel" as
31909 * the drag proxy element.
31911 getDragData : function(e) {
31912 var target = this.findItemFromChild(e.getTarget());
31914 this.handleSelection(e);
31915 var selNodes = this.getSelectedNodes();
31918 copy: this.copy || (this.allowCopy && e.ctrlKey),
31922 var selectedIndices = this.getSelectedIndexes();
31923 for (var i = 0; i < selectedIndices.length; i++) {
31924 dragData.records.push(this.store.getAt(selectedIndices[i]));
31926 if (selNodes.length == 1) {
31927 dragData.ddel = target.cloneNode(true); // the div element
31929 var div = document.createElement('div'); // create the multi element drag "ghost"
31930 div.className = 'multi-proxy';
31931 for (var i = 0, len = selNodes.length; i < len; i++) {
31932 div.appendChild(selNodes[i].cloneNode(true));
31934 dragData.ddel = div;
31936 //console.log(dragData)
31937 //console.log(dragData.ddel.innerHTML)
31940 //console.log('nodragData')
31944 /** Specify to which ddGroup items in this DDView may be dragged. */
31945 setDraggable: function(ddGroup) {
31946 if (ddGroup instanceof Array) {
31947 Roo.each(ddGroup, this.setDraggable, this);
31950 if (this.dragZone) {
31951 this.dragZone.addToGroup(ddGroup);
31953 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
31954 containerScroll: true,
31958 // Draggability implies selection. DragZone's mousedown selects the element.
31959 if (!this.multiSelect) { this.singleSelect = true; }
31961 // Wire the DragZone's handlers up to methods in *this*
31962 this.dragZone.getDragData = this.getDragData.createDelegate(this);
31966 /** Specify from which ddGroup this DDView accepts drops. */
31967 setDroppable: function(ddGroup) {
31968 if (ddGroup instanceof Array) {
31969 Roo.each(ddGroup, this.setDroppable, this);
31972 if (this.dropZone) {
31973 this.dropZone.addToGroup(ddGroup);
31975 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
31976 containerScroll: true,
31980 // Wire the DropZone's handlers up to methods in *this*
31981 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
31982 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
31983 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
31984 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
31985 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
31989 /** Decide whether to drop above or below a View node. */
31990 getDropPoint : function(e, n, dd){
31991 if (n == this.el.dom) { return "above"; }
31992 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
31993 var c = t + (b - t) / 2;
31994 var y = Roo.lib.Event.getPageY(e);
32002 onNodeEnter : function(n, dd, e, data){
32006 onNodeOver : function(n, dd, e, data){
32007 var pt = this.getDropPoint(e, n, dd);
32008 // set the insert point style on the target node
32009 var dragElClass = this.dropNotAllowed;
32012 if (pt == "above"){
32013 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
32014 targetElClass = "x-view-drag-insert-above";
32016 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
32017 targetElClass = "x-view-drag-insert-below";
32019 if (this.lastInsertClass != targetElClass){
32020 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
32021 this.lastInsertClass = targetElClass;
32024 return dragElClass;
32027 onNodeOut : function(n, dd, e, data){
32028 this.removeDropIndicators(n);
32031 onNodeDrop : function(n, dd, e, data){
32032 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
32035 var pt = this.getDropPoint(e, n, dd);
32036 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
32037 if (pt == "below") { insertAt++; }
32038 for (var i = 0; i < data.records.length; i++) {
32039 var r = data.records[i];
32040 var dup = this.store.getById(r.id);
32041 if (dup && (dd != this.dragZone)) {
32042 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
32045 this.store.insert(insertAt++, r.copy());
32047 data.source.isDirtyFlag = true;
32049 this.store.insert(insertAt++, r);
32051 this.isDirtyFlag = true;
32054 this.dragZone.cachedTarget = null;
32058 removeDropIndicators : function(n){
32060 Roo.fly(n).removeClass([
32061 "x-view-drag-insert-above",
32062 "x-view-drag-insert-below"]);
32063 this.lastInsertClass = "_noclass";
32068 * Utility method. Add a delete option to the DDView's context menu.
32069 * @param {String} imageUrl The URL of the "delete" icon image.
32071 setDeletable: function(imageUrl) {
32072 if (!this.singleSelect && !this.multiSelect) {
32073 this.singleSelect = true;
32075 var c = this.getContextMenu();
32076 this.contextMenu.on("itemclick", function(item) {
32079 this.remove(this.getSelectedIndexes());
32083 this.contextMenu.add({
32090 /** Return the context menu for this DDView. */
32091 getContextMenu: function() {
32092 if (!this.contextMenu) {
32093 // Create the View's context menu
32094 this.contextMenu = new Roo.menu.Menu({
32095 id: this.id + "-contextmenu"
32097 this.el.on("contextmenu", this.showContextMenu, this);
32099 return this.contextMenu;
32102 disableContextMenu: function() {
32103 if (this.contextMenu) {
32104 this.el.un("contextmenu", this.showContextMenu, this);
32108 showContextMenu: function(e, item) {
32109 item = this.findItemFromChild(e.getTarget());
32112 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
32113 this.contextMenu.showAt(e.getXY());
32118 * Remove {@link Roo.data.Record}s at the specified indices.
32119 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
32121 remove: function(selectedIndices) {
32122 selectedIndices = [].concat(selectedIndices);
32123 for (var i = 0; i < selectedIndices.length; i++) {
32124 var rec = this.store.getAt(selectedIndices[i]);
32125 this.store.remove(rec);
32130 * Double click fires the event, but also, if this is draggable, and there is only one other
32131 * related DropZone, it transfers the selected node.
32133 onDblClick : function(e){
32134 var item = this.findItemFromChild(e.getTarget());
32136 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
32139 if (this.dragGroup) {
32140 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
32141 while (targets.indexOf(this.dropZone) > -1) {
32142 targets.remove(this.dropZone);
32144 if (targets.length == 1) {
32145 this.dragZone.cachedTarget = null;
32146 var el = Roo.get(targets[0].getEl());
32147 var box = el.getBox(true);
32148 targets[0].onNodeDrop(el.dom, {
32150 xy: [box.x, box.y + box.height - 1]
32151 }, null, this.getDragData(e));
32157 handleSelection: function(e) {
32158 this.dragZone.cachedTarget = null;
32159 var item = this.findItemFromChild(e.getTarget());
32161 this.clearSelections(true);
32164 if (item && (this.multiSelect || this.singleSelect)){
32165 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
32166 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
32167 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
32168 this.unselect(item);
32170 this.select(item, this.multiSelect && e.ctrlKey);
32171 this.lastSelection = item;
32176 onItemClick : function(item, index, e){
32177 if(this.fireEvent("beforeclick", this, index, item, e) === false){
32183 unselect : function(nodeInfo, suppressEvent){
32184 var node = this.getNode(nodeInfo);
32185 if(node && this.isSelected(node)){
32186 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
32187 Roo.fly(node).removeClass(this.selectedClass);
32188 this.selections.remove(node);
32189 if(!suppressEvent){
32190 this.fireEvent("selectionchange", this, this.selections);
32198 * Ext JS Library 1.1.1
32199 * Copyright(c) 2006-2007, Ext JS, LLC.
32201 * Originally Released Under LGPL - original licence link has changed is not relivant.
32204 * <script type="text/javascript">
32208 * @class Roo.LayoutManager
32209 * @extends Roo.util.Observable
32210 * Base class for layout managers.
32212 Roo.LayoutManager = function(container, config){
32213 Roo.LayoutManager.superclass.constructor.call(this);
32214 this.el = Roo.get(container);
32215 // ie scrollbar fix
32216 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32217 document.body.scroll = "no";
32218 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32219 this.el.position('relative');
32221 this.id = this.el.id;
32222 this.el.addClass("x-layout-container");
32223 /** false to disable window resize monitoring @type Boolean */
32224 this.monitorWindowResize = true;
32229 * Fires when a layout is performed.
32230 * @param {Roo.LayoutManager} this
32234 * @event regionresized
32235 * Fires when the user resizes a region.
32236 * @param {Roo.LayoutRegion} region The resized region
32237 * @param {Number} newSize The new size (width for east/west, height for north/south)
32239 "regionresized" : true,
32241 * @event regioncollapsed
32242 * Fires when a region is collapsed.
32243 * @param {Roo.LayoutRegion} region The collapsed region
32245 "regioncollapsed" : true,
32247 * @event regionexpanded
32248 * Fires when a region is expanded.
32249 * @param {Roo.LayoutRegion} region The expanded region
32251 "regionexpanded" : true
32253 this.updating = false;
32254 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32257 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
32259 * Returns true if this layout is currently being updated
32260 * @return {Boolean}
32262 isUpdating : function(){
32263 return this.updating;
32267 * Suspend the LayoutManager from doing auto-layouts while
32268 * making multiple add or remove calls
32270 beginUpdate : function(){
32271 this.updating = true;
32275 * Restore auto-layouts and optionally disable the manager from performing a layout
32276 * @param {Boolean} noLayout true to disable a layout update
32278 endUpdate : function(noLayout){
32279 this.updating = false;
32285 layout: function(){
32289 onRegionResized : function(region, newSize){
32290 this.fireEvent("regionresized", region, newSize);
32294 onRegionCollapsed : function(region){
32295 this.fireEvent("regioncollapsed", region);
32298 onRegionExpanded : function(region){
32299 this.fireEvent("regionexpanded", region);
32303 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32304 * performs box-model adjustments.
32305 * @return {Object} The size as an object {width: (the width), height: (the height)}
32307 getViewSize : function(){
32309 if(this.el.dom != document.body){
32310 size = this.el.getSize();
32312 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32314 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32315 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32320 * Returns the Element this layout is bound to.
32321 * @return {Roo.Element}
32323 getEl : function(){
32328 * Returns the specified region.
32329 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32330 * @return {Roo.LayoutRegion}
32332 getRegion : function(target){
32333 return this.regions[target.toLowerCase()];
32336 onWindowResize : function(){
32337 if(this.monitorWindowResize){
32343 * Ext JS Library 1.1.1
32344 * Copyright(c) 2006-2007, Ext JS, LLC.
32346 * Originally Released Under LGPL - original licence link has changed is not relivant.
32349 * <script type="text/javascript">
32352 * @class Roo.BorderLayout
32353 * @extends Roo.LayoutManager
32354 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32355 * please see: <br><br>
32356 * <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>
32357 * <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>
32360 var layout = new Roo.BorderLayout(document.body, {
32394 preferredTabWidth: 150
32399 var CP = Roo.ContentPanel;
32401 layout.beginUpdate();
32402 layout.add("north", new CP("north", "North"));
32403 layout.add("south", new CP("south", {title: "South", closable: true}));
32404 layout.add("west", new CP("west", {title: "West"}));
32405 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
32406 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
32407 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
32408 layout.getRegion("center").showPanel("center1");
32409 layout.endUpdate();
32412 <b>The container the layout is rendered into can be either the body element or any other element.
32413 If it is not the body element, the container needs to either be an absolute positioned element,
32414 or you will need to add "position:relative" to the css of the container. You will also need to specify
32415 the container size if it is not the body element.</b>
32418 * Create a new BorderLayout
32419 * @param {String/HTMLElement/Element} container The container this layout is bound to
32420 * @param {Object} config Configuration options
32422 Roo.BorderLayout = function(container, config){
32423 config = config || {};
32424 Roo.BorderLayout.superclass.constructor.call(this, container, config);
32425 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
32426 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
32427 var target = this.factory.validRegions[i];
32428 if(config[target]){
32429 this.addRegion(target, config[target]);
32434 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
32436 * Creates and adds a new region if it doesn't already exist.
32437 * @param {String} target The target region key (north, south, east, west or center).
32438 * @param {Object} config The regions config object
32439 * @return {BorderLayoutRegion} The new region
32441 addRegion : function(target, config){
32442 if(!this.regions[target]){
32443 var r = this.factory.create(target, this, config);
32444 this.bindRegion(target, r);
32446 return this.regions[target];
32450 bindRegion : function(name, r){
32451 this.regions[name] = r;
32452 r.on("visibilitychange", this.layout, this);
32453 r.on("paneladded", this.layout, this);
32454 r.on("panelremoved", this.layout, this);
32455 r.on("invalidated", this.layout, this);
32456 r.on("resized", this.onRegionResized, this);
32457 r.on("collapsed", this.onRegionCollapsed, this);
32458 r.on("expanded", this.onRegionExpanded, this);
32462 * Performs a layout update.
32464 layout : function(){
32465 if(this.updating) return;
32466 var size = this.getViewSize();
32467 var w = size.width;
32468 var h = size.height;
32473 //var x = 0, y = 0;
32475 var rs = this.regions;
32476 var north = rs["north"];
32477 var south = rs["south"];
32478 var west = rs["west"];
32479 var east = rs["east"];
32480 var center = rs["center"];
32481 //if(this.hideOnLayout){ // not supported anymore
32482 //c.el.setStyle("display", "none");
32484 if(north && north.isVisible()){
32485 var b = north.getBox();
32486 var m = north.getMargins();
32487 b.width = w - (m.left+m.right);
32490 centerY = b.height + b.y + m.bottom;
32491 centerH -= centerY;
32492 north.updateBox(this.safeBox(b));
32494 if(south && south.isVisible()){
32495 var b = south.getBox();
32496 var m = south.getMargins();
32497 b.width = w - (m.left+m.right);
32499 var totalHeight = (b.height + m.top + m.bottom);
32500 b.y = h - totalHeight + m.top;
32501 centerH -= totalHeight;
32502 south.updateBox(this.safeBox(b));
32504 if(west && west.isVisible()){
32505 var b = west.getBox();
32506 var m = west.getMargins();
32507 b.height = centerH - (m.top+m.bottom);
32509 b.y = centerY + m.top;
32510 var totalWidth = (b.width + m.left + m.right);
32511 centerX += totalWidth;
32512 centerW -= totalWidth;
32513 west.updateBox(this.safeBox(b));
32515 if(east && east.isVisible()){
32516 var b = east.getBox();
32517 var m = east.getMargins();
32518 b.height = centerH - (m.top+m.bottom);
32519 var totalWidth = (b.width + m.left + m.right);
32520 b.x = w - totalWidth + m.left;
32521 b.y = centerY + m.top;
32522 centerW -= totalWidth;
32523 east.updateBox(this.safeBox(b));
32526 var m = center.getMargins();
32528 x: centerX + m.left,
32529 y: centerY + m.top,
32530 width: centerW - (m.left+m.right),
32531 height: centerH - (m.top+m.bottom)
32533 //if(this.hideOnLayout){
32534 //center.el.setStyle("display", "block");
32536 center.updateBox(this.safeBox(centerBox));
32539 this.fireEvent("layout", this);
32543 safeBox : function(box){
32544 box.width = Math.max(0, box.width);
32545 box.height = Math.max(0, box.height);
32550 * Adds a ContentPanel (or subclass) to this layout.
32551 * @param {String} target The target region key (north, south, east, west or center).
32552 * @param {Roo.ContentPanel} panel The panel to add
32553 * @return {Roo.ContentPanel} The added panel
32555 add : function(target, panel){
32557 target = target.toLowerCase();
32558 return this.regions[target].add(panel);
32562 * Remove a ContentPanel (or subclass) to this layout.
32563 * @param {String} target The target region key (north, south, east, west or center).
32564 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32565 * @return {Roo.ContentPanel} The removed panel
32567 remove : function(target, panel){
32568 target = target.toLowerCase();
32569 return this.regions[target].remove(panel);
32573 * Searches all regions for a panel with the specified id
32574 * @param {String} panelId
32575 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32577 findPanel : function(panelId){
32578 var rs = this.regions;
32579 for(var target in rs){
32580 if(typeof rs[target] != "function"){
32581 var p = rs[target].getPanel(panelId);
32591 * Searches all regions for a panel with the specified id and activates (shows) it.
32592 * @param {String/ContentPanel} panelId The panels id or the panel itself
32593 * @return {Roo.ContentPanel} The shown panel or null
32595 showPanel : function(panelId) {
32596 var rs = this.regions;
32597 for(var target in rs){
32598 var r = rs[target];
32599 if(typeof r != "function"){
32600 if(r.hasPanel(panelId)){
32601 return r.showPanel(panelId);
32609 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32610 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32612 restoreState : function(provider){
32614 provider = Roo.state.Manager;
32616 var sm = new Roo.LayoutStateManager();
32617 sm.init(this, provider);
32621 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
32622 * object should contain properties for each region to add ContentPanels to, and each property's value should be
32623 * a valid ContentPanel config object. Example:
32625 // Create the main layout
32626 var layout = new Roo.BorderLayout('main-ct', {
32637 // Create and add multiple ContentPanels at once via configs
32640 id: 'source-files',
32642 title:'Ext Source Files',
32655 * @param {Object} regions An object containing ContentPanel configs by region name
32657 batchAdd : function(regions){
32658 this.beginUpdate();
32659 for(var rname in regions){
32660 var lr = this.regions[rname];
32662 this.addTypedPanels(lr, regions[rname]);
32669 addTypedPanels : function(lr, ps){
32670 if(typeof ps == 'string'){
32671 lr.add(new Roo.ContentPanel(ps));
32673 else if(ps instanceof Array){
32674 for(var i =0, len = ps.length; i < len; i++){
32675 this.addTypedPanels(lr, ps[i]);
32678 else if(!ps.events){ // raw config?
32680 delete ps.el; // prevent conflict
32681 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
32683 else { // panel object assumed!
32688 * Adds a xtype elements to the layout.
32692 xtype : 'ContentPanel',
32699 xtype : 'NestedLayoutPanel',
32705 items : [ ... list of content panels or nested layout panels.. ]
32709 * @param {Object} cfg Xtype definition of item to add.
32711 addxtype : function(cfg)
32713 // basically accepts a pannel...
32714 // can accept a layout region..!?!?
32715 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32717 if (!cfg.xtype.match(/Panel$/)) {
32722 if (typeof(cfg.region) == 'undefined') {
32723 Roo.log("Failed to add Panel, region was not set");
32727 var region = cfg.region;
32733 xitems = cfg.items;
32740 case 'ContentPanel': // ContentPanel (el, cfg)
32741 case 'ScrollPanel': // ContentPanel (el, cfg)
32743 if(cfg.autoCreate) {
32744 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32746 var el = this.el.createChild();
32747 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32750 this.add(region, ret);
32754 case 'TreePanel': // our new panel!
32755 cfg.el = this.el.createChild();
32756 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32757 this.add(region, ret);
32760 case 'NestedLayoutPanel':
32761 // create a new Layout (which is a Border Layout...
32762 var el = this.el.createChild();
32763 var clayout = cfg.layout;
32765 clayout.items = clayout.items || [];
32766 // replace this exitems with the clayout ones..
32767 xitems = clayout.items;
32770 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32771 cfg.background = false;
32773 var layout = new Roo.BorderLayout(el, clayout);
32775 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
32776 //console.log('adding nested layout panel ' + cfg.toSource());
32777 this.add(region, ret);
32778 nb = {}; /// find first...
32783 // needs grid and region
32785 //var el = this.getRegion(region).el.createChild();
32786 var el = this.el.createChild();
32787 // create the grid first...
32789 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
32791 if (region == 'center' && this.active ) {
32792 cfg.background = false;
32794 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
32796 this.add(region, ret);
32797 if (cfg.background) {
32798 ret.on('activate', function(gp) {
32799 if (!gp.grid.rendered) {
32814 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
32816 // GridPanel (grid, cfg)
32819 this.beginUpdate();
32823 Roo.each(xitems, function(i) {
32824 region = nb && i.region ? i.region : false;
32826 var add = ret.addxtype(i);
32829 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32830 if (!i.background) {
32831 abn[region] = nb[region] ;
32838 // make the last non-background panel active..
32839 //if (nb) { Roo.log(abn); }
32842 for(var r in abn) {
32843 region = this.getRegion(r);
32845 // tried using nb[r], but it does not work..
32847 region.showPanel(abn[r]);
32858 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
32859 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
32860 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
32861 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
32864 var CP = Roo.ContentPanel;
32866 var layout = Roo.BorderLayout.create({
32870 panels: [new CP("north", "North")]
32879 panels: [new CP("west", {title: "West"})]
32888 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
32897 panels: [new CP("south", {title: "South", closable: true})]
32904 preferredTabWidth: 150,
32906 new CP("center1", {title: "Close Me", closable: true}),
32907 new CP("center2", {title: "Center Panel", closable: false})
32912 layout.getRegion("center").showPanel("center1");
32917 Roo.BorderLayout.create = function(config, targetEl){
32918 var layout = new Roo.BorderLayout(targetEl || document.body, config);
32919 layout.beginUpdate();
32920 var regions = Roo.BorderLayout.RegionFactory.validRegions;
32921 for(var j = 0, jlen = regions.length; j < jlen; j++){
32922 var lr = regions[j];
32923 if(layout.regions[lr] && config[lr].panels){
32924 var r = layout.regions[lr];
32925 var ps = config[lr].panels;
32926 layout.addTypedPanels(r, ps);
32929 layout.endUpdate();
32934 Roo.BorderLayout.RegionFactory = {
32936 validRegions : ["north","south","east","west","center"],
32939 create : function(target, mgr, config){
32940 target = target.toLowerCase();
32941 if(config.lightweight || config.basic){
32942 return new Roo.BasicLayoutRegion(mgr, config, target);
32946 return new Roo.NorthLayoutRegion(mgr, config);
32948 return new Roo.SouthLayoutRegion(mgr, config);
32950 return new Roo.EastLayoutRegion(mgr, config);
32952 return new Roo.WestLayoutRegion(mgr, config);
32954 return new Roo.CenterLayoutRegion(mgr, config);
32956 throw 'Layout region "'+target+'" not supported.';
32960 * Ext JS Library 1.1.1
32961 * Copyright(c) 2006-2007, Ext JS, LLC.
32963 * Originally Released Under LGPL - original licence link has changed is not relivant.
32966 * <script type="text/javascript">
32970 * @class Roo.BasicLayoutRegion
32971 * @extends Roo.util.Observable
32972 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32973 * and does not have a titlebar, tabs or any other features. All it does is size and position
32974 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32976 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
32978 this.position = pos;
32981 * @scope Roo.BasicLayoutRegion
32985 * @event beforeremove
32986 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32987 * @param {Roo.LayoutRegion} this
32988 * @param {Roo.ContentPanel} panel The panel
32989 * @param {Object} e The cancel event object
32991 "beforeremove" : true,
32993 * @event invalidated
32994 * Fires when the layout for this region is changed.
32995 * @param {Roo.LayoutRegion} this
32997 "invalidated" : true,
32999 * @event visibilitychange
33000 * Fires when this region is shown or hidden
33001 * @param {Roo.LayoutRegion} this
33002 * @param {Boolean} visibility true or false
33004 "visibilitychange" : true,
33006 * @event paneladded
33007 * Fires when a panel is added.
33008 * @param {Roo.LayoutRegion} this
33009 * @param {Roo.ContentPanel} panel The panel
33011 "paneladded" : true,
33013 * @event panelremoved
33014 * Fires when a panel is removed.
33015 * @param {Roo.LayoutRegion} this
33016 * @param {Roo.ContentPanel} panel The panel
33018 "panelremoved" : true,
33021 * Fires when this region is collapsed.
33022 * @param {Roo.LayoutRegion} this
33024 "collapsed" : true,
33027 * Fires when this region is expanded.
33028 * @param {Roo.LayoutRegion} this
33033 * Fires when this region is slid into view.
33034 * @param {Roo.LayoutRegion} this
33036 "slideshow" : true,
33039 * Fires when this region slides out of view.
33040 * @param {Roo.LayoutRegion} this
33042 "slidehide" : true,
33044 * @event panelactivated
33045 * Fires when a panel is activated.
33046 * @param {Roo.LayoutRegion} this
33047 * @param {Roo.ContentPanel} panel The activated panel
33049 "panelactivated" : true,
33052 * Fires when the user resizes this region.
33053 * @param {Roo.LayoutRegion} this
33054 * @param {Number} newSize The new size (width for east/west, height for north/south)
33058 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33059 this.panels = new Roo.util.MixedCollection();
33060 this.panels.getKey = this.getPanelId.createDelegate(this);
33062 this.activePanel = null;
33063 // ensure listeners are added...
33065 if (config.listeners || config.events) {
33066 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
33067 listeners : config.listeners || {},
33068 events : config.events || {}
33072 if(skipConfig !== true){
33073 this.applyConfig(config);
33077 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
33078 getPanelId : function(p){
33082 applyConfig : function(config){
33083 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33084 this.config = config;
33089 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33090 * the width, for horizontal (north, south) the height.
33091 * @param {Number} newSize The new width or height
33093 resizeTo : function(newSize){
33094 var el = this.el ? this.el :
33095 (this.activePanel ? this.activePanel.getEl() : null);
33097 switch(this.position){
33100 el.setWidth(newSize);
33101 this.fireEvent("resized", this, newSize);
33105 el.setHeight(newSize);
33106 this.fireEvent("resized", this, newSize);
33112 getBox : function(){
33113 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33116 getMargins : function(){
33117 return this.margins;
33120 updateBox : function(box){
33122 var el = this.activePanel.getEl();
33123 el.dom.style.left = box.x + "px";
33124 el.dom.style.top = box.y + "px";
33125 this.activePanel.setSize(box.width, box.height);
33129 * Returns the container element for this region.
33130 * @return {Roo.Element}
33132 getEl : function(){
33133 return this.activePanel;
33137 * Returns true if this region is currently visible.
33138 * @return {Boolean}
33140 isVisible : function(){
33141 return this.activePanel ? true : false;
33144 setActivePanel : function(panel){
33145 panel = this.getPanel(panel);
33146 if(this.activePanel && this.activePanel != panel){
33147 this.activePanel.setActiveState(false);
33148 this.activePanel.getEl().setLeftTop(-10000,-10000);
33150 this.activePanel = panel;
33151 panel.setActiveState(true);
33153 panel.setSize(this.box.width, this.box.height);
33155 this.fireEvent("panelactivated", this, panel);
33156 this.fireEvent("invalidated");
33160 * Show the specified panel.
33161 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33162 * @return {Roo.ContentPanel} The shown panel or null
33164 showPanel : function(panel){
33165 if(panel = this.getPanel(panel)){
33166 this.setActivePanel(panel);
33172 * Get the active panel for this region.
33173 * @return {Roo.ContentPanel} The active panel or null
33175 getActivePanel : function(){
33176 return this.activePanel;
33180 * Add the passed ContentPanel(s)
33181 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33182 * @return {Roo.ContentPanel} The panel added (if only one was added)
33184 add : function(panel){
33185 if(arguments.length > 1){
33186 for(var i = 0, len = arguments.length; i < len; i++) {
33187 this.add(arguments[i]);
33191 if(this.hasPanel(panel)){
33192 this.showPanel(panel);
33195 var el = panel.getEl();
33196 if(el.dom.parentNode != this.mgr.el.dom){
33197 this.mgr.el.dom.appendChild(el.dom);
33199 if(panel.setRegion){
33200 panel.setRegion(this);
33202 this.panels.add(panel);
33203 el.setStyle("position", "absolute");
33204 if(!panel.background){
33205 this.setActivePanel(panel);
33206 if(this.config.initialSize && this.panels.getCount()==1){
33207 this.resizeTo(this.config.initialSize);
33210 this.fireEvent("paneladded", this, panel);
33215 * Returns true if the panel is in this region.
33216 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33217 * @return {Boolean}
33219 hasPanel : function(panel){
33220 if(typeof panel == "object"){ // must be panel obj
33221 panel = panel.getId();
33223 return this.getPanel(panel) ? true : false;
33227 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33228 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33229 * @param {Boolean} preservePanel Overrides the config preservePanel option
33230 * @return {Roo.ContentPanel} The panel that was removed
33232 remove : function(panel, preservePanel){
33233 panel = this.getPanel(panel);
33238 this.fireEvent("beforeremove", this, panel, e);
33239 if(e.cancel === true){
33242 var panelId = panel.getId();
33243 this.panels.removeKey(panelId);
33248 * Returns the panel specified or null if it's not in this region.
33249 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33250 * @return {Roo.ContentPanel}
33252 getPanel : function(id){
33253 if(typeof id == "object"){ // must be panel obj
33256 return this.panels.get(id);
33260 * Returns this regions position (north/south/east/west/center).
33263 getPosition: function(){
33264 return this.position;
33268 * Ext JS Library 1.1.1
33269 * Copyright(c) 2006-2007, Ext JS, LLC.
33271 * Originally Released Under LGPL - original licence link has changed is not relivant.
33274 * <script type="text/javascript">
33278 * @class Roo.LayoutRegion
33279 * @extends Roo.BasicLayoutRegion
33280 * This class represents a region in a layout manager.
33281 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
33282 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
33283 * @cfg {Boolean} floatable False to disable floating (defaults to true)
33284 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33285 * @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})
33286 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
33287 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
33288 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33289 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33290 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33291 * @cfg {String} title The title for the region (overrides panel titles)
33292 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33293 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33294 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33295 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33296 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33297 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33298 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33299 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33300 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33301 * @cfg {Boolean} showPin True to show a pin button
33302 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33303 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33304 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33305 * @cfg {Number} width For East/West panels
33306 * @cfg {Number} height For North/South panels
33307 * @cfg {Boolean} split To show the splitter
33308 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33310 Roo.LayoutRegion = function(mgr, config, pos){
33311 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
33312 var dh = Roo.DomHelper;
33313 /** This region's container element
33314 * @type Roo.Element */
33315 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
33316 /** This region's title element
33317 * @type Roo.Element */
33319 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
33320 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
33321 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
33323 this.titleEl.enableDisplayMode();
33324 /** This region's title text element
33325 * @type HTMLElement */
33326 this.titleTextEl = this.titleEl.dom.firstChild;
33327 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33328 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
33329 this.closeBtn.enableDisplayMode();
33330 this.closeBtn.on("click", this.closeClicked, this);
33331 this.closeBtn.hide();
33333 this.createBody(config);
33334 this.visible = true;
33335 this.collapsed = false;
33337 if(config.hideWhenEmpty){
33339 this.on("paneladded", this.validateVisibility, this);
33340 this.on("panelremoved", this.validateVisibility, this);
33342 this.applyConfig(config);
33345 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
33347 createBody : function(){
33348 /** This region's body element
33349 * @type Roo.Element */
33350 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
33353 applyConfig : function(c){
33354 if(c.collapsible && this.position != "center" && !this.collapsedEl){
33355 var dh = Roo.DomHelper;
33356 if(c.titlebar !== false){
33357 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
33358 this.collapseBtn.on("click", this.collapse, this);
33359 this.collapseBtn.enableDisplayMode();
33361 if(c.showPin === true || this.showPin){
33362 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
33363 this.stickBtn.enableDisplayMode();
33364 this.stickBtn.on("click", this.expand, this);
33365 this.stickBtn.hide();
33368 /** This region's collapsed element
33369 * @type Roo.Element */
33370 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33371 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33373 if(c.floatable !== false){
33374 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33375 this.collapsedEl.on("click", this.collapseClick, this);
33378 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33379 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33380 id: "message", unselectable: "on", style:{"float":"left"}});
33381 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33383 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33384 this.expandBtn.on("click", this.expand, this);
33386 if(this.collapseBtn){
33387 this.collapseBtn.setVisible(c.collapsible == true);
33389 this.cmargins = c.cmargins || this.cmargins ||
33390 (this.position == "west" || this.position == "east" ?
33391 {top: 0, left: 2, right:2, bottom: 0} :
33392 {top: 2, left: 0, right:0, bottom: 2});
33393 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33394 this.bottomTabs = c.tabPosition != "top";
33395 this.autoScroll = c.autoScroll || false;
33396 if(this.autoScroll){
33397 this.bodyEl.setStyle("overflow", "auto");
33399 this.bodyEl.setStyle("overflow", "hidden");
33401 //if(c.titlebar !== false){
33402 if((!c.titlebar && !c.title) || c.titlebar === false){
33403 this.titleEl.hide();
33405 this.titleEl.show();
33407 this.titleTextEl.innerHTML = c.title;
33411 this.duration = c.duration || .30;
33412 this.slideDuration = c.slideDuration || .45;
33415 this.collapse(true);
33422 * Returns true if this region is currently visible.
33423 * @return {Boolean}
33425 isVisible : function(){
33426 return this.visible;
33430 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33431 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33433 setCollapsedTitle : function(title){
33434 title = title || " ";
33435 if(this.collapsedTitleTextEl){
33436 this.collapsedTitleTextEl.innerHTML = title;
33440 getBox : function(){
33442 if(!this.collapsed){
33443 b = this.el.getBox(false, true);
33445 b = this.collapsedEl.getBox(false, true);
33450 getMargins : function(){
33451 return this.collapsed ? this.cmargins : this.margins;
33454 highlight : function(){
33455 this.el.addClass("x-layout-panel-dragover");
33458 unhighlight : function(){
33459 this.el.removeClass("x-layout-panel-dragover");
33462 updateBox : function(box){
33464 if(!this.collapsed){
33465 this.el.dom.style.left = box.x + "px";
33466 this.el.dom.style.top = box.y + "px";
33467 this.updateBody(box.width, box.height);
33469 this.collapsedEl.dom.style.left = box.x + "px";
33470 this.collapsedEl.dom.style.top = box.y + "px";
33471 this.collapsedEl.setSize(box.width, box.height);
33474 this.tabs.autoSizeTabs();
33478 updateBody : function(w, h){
33480 this.el.setWidth(w);
33481 w -= this.el.getBorderWidth("rl");
33482 if(this.config.adjustments){
33483 w += this.config.adjustments[0];
33487 this.el.setHeight(h);
33488 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33489 h -= this.el.getBorderWidth("tb");
33490 if(this.config.adjustments){
33491 h += this.config.adjustments[1];
33493 this.bodyEl.setHeight(h);
33495 h = this.tabs.syncHeight(h);
33498 if(this.panelSize){
33499 w = w !== null ? w : this.panelSize.width;
33500 h = h !== null ? h : this.panelSize.height;
33502 if(this.activePanel){
33503 var el = this.activePanel.getEl();
33504 w = w !== null ? w : el.getWidth();
33505 h = h !== null ? h : el.getHeight();
33506 this.panelSize = {width: w, height: h};
33507 this.activePanel.setSize(w, h);
33509 if(Roo.isIE && this.tabs){
33510 this.tabs.el.repaint();
33515 * Returns the container element for this region.
33516 * @return {Roo.Element}
33518 getEl : function(){
33523 * Hides this region.
33526 if(!this.collapsed){
33527 this.el.dom.style.left = "-2000px";
33530 this.collapsedEl.dom.style.left = "-2000px";
33531 this.collapsedEl.hide();
33533 this.visible = false;
33534 this.fireEvent("visibilitychange", this, false);
33538 * Shows this region if it was previously hidden.
33541 if(!this.collapsed){
33544 this.collapsedEl.show();
33546 this.visible = true;
33547 this.fireEvent("visibilitychange", this, true);
33550 closeClicked : function(){
33551 if(this.activePanel){
33552 this.remove(this.activePanel);
33556 collapseClick : function(e){
33558 e.stopPropagation();
33561 e.stopPropagation();
33567 * Collapses this region.
33568 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33570 collapse : function(skipAnim){
33571 if(this.collapsed) return;
33572 this.collapsed = true;
33574 this.split.el.hide();
33576 if(this.config.animate && skipAnim !== true){
33577 this.fireEvent("invalidated", this);
33578 this.animateCollapse();
33580 this.el.setLocation(-20000,-20000);
33582 this.collapsedEl.show();
33583 this.fireEvent("collapsed", this);
33584 this.fireEvent("invalidated", this);
33588 animateCollapse : function(){
33593 * Expands this region if it was previously collapsed.
33594 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33595 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33597 expand : function(e, skipAnim){
33598 if(e) e.stopPropagation();
33599 if(!this.collapsed || this.el.hasActiveFx()) return;
33601 this.afterSlideIn();
33604 this.collapsed = false;
33605 if(this.config.animate && skipAnim !== true){
33606 this.animateExpand();
33610 this.split.el.show();
33612 this.collapsedEl.setLocation(-2000,-2000);
33613 this.collapsedEl.hide();
33614 this.fireEvent("invalidated", this);
33615 this.fireEvent("expanded", this);
33619 animateExpand : function(){
33623 initTabs : function()
33625 this.bodyEl.setStyle("overflow", "hidden");
33626 var ts = new Roo.TabPanel(
33629 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33630 disableTooltips: this.config.disableTabTips,
33631 toolbar : this.config.toolbar
33634 if(this.config.hideTabs){
33635 ts.stripWrap.setDisplayed(false);
33638 ts.resizeTabs = this.config.resizeTabs === true;
33639 ts.minTabWidth = this.config.minTabWidth || 40;
33640 ts.maxTabWidth = this.config.maxTabWidth || 250;
33641 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33642 ts.monitorResize = false;
33643 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33644 ts.bodyEl.addClass('x-layout-tabs-body');
33645 this.panels.each(this.initPanelAsTab, this);
33648 initPanelAsTab : function(panel){
33649 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
33650 this.config.closeOnTab && panel.isClosable());
33651 if(panel.tabTip !== undefined){
33652 ti.setTooltip(panel.tabTip);
33654 ti.on("activate", function(){
33655 this.setActivePanel(panel);
33657 if(this.config.closeOnTab){
33658 ti.on("beforeclose", function(t, e){
33660 this.remove(panel);
33666 updatePanelTitle : function(panel, title){
33667 if(this.activePanel == panel){
33668 this.updateTitle(title);
33671 var ti = this.tabs.getTab(panel.getEl().id);
33673 if(panel.tabTip !== undefined){
33674 ti.setTooltip(panel.tabTip);
33679 updateTitle : function(title){
33680 if(this.titleTextEl && !this.config.title){
33681 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33685 setActivePanel : function(panel){
33686 panel = this.getPanel(panel);
33687 if(this.activePanel && this.activePanel != panel){
33688 this.activePanel.setActiveState(false);
33690 this.activePanel = panel;
33691 panel.setActiveState(true);
33692 if(this.panelSize){
33693 panel.setSize(this.panelSize.width, this.panelSize.height);
33696 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33698 this.updateTitle(panel.getTitle());
33700 this.fireEvent("invalidated", this);
33702 this.fireEvent("panelactivated", this, panel);
33706 * Shows the specified panel.
33707 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33708 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33710 showPanel : function(panel){
33711 if(panel = this.getPanel(panel)){
33713 var tab = this.tabs.getTab(panel.getEl().id);
33714 if(tab.isHidden()){
33715 this.tabs.unhideTab(tab.id);
33719 this.setActivePanel(panel);
33726 * Get the active panel for this region.
33727 * @return {Roo.ContentPanel} The active panel or null
33729 getActivePanel : function(){
33730 return this.activePanel;
33733 validateVisibility : function(){
33734 if(this.panels.getCount() < 1){
33735 this.updateTitle(" ");
33736 this.closeBtn.hide();
33739 if(!this.isVisible()){
33746 * Adds the passed ContentPanel(s) to this region.
33747 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33748 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33750 add : function(panel){
33751 if(arguments.length > 1){
33752 for(var i = 0, len = arguments.length; i < len; i++) {
33753 this.add(arguments[i]);
33757 if(this.hasPanel(panel)){
33758 this.showPanel(panel);
33761 panel.setRegion(this);
33762 this.panels.add(panel);
33763 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33764 this.bodyEl.dom.appendChild(panel.getEl().dom);
33765 if(panel.background !== true){
33766 this.setActivePanel(panel);
33768 this.fireEvent("paneladded", this, panel);
33774 this.initPanelAsTab(panel);
33776 if(panel.background !== true){
33777 this.tabs.activate(panel.getEl().id);
33779 this.fireEvent("paneladded", this, panel);
33784 * Hides the tab for the specified panel.
33785 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33787 hidePanel : function(panel){
33788 if(this.tabs && (panel = this.getPanel(panel))){
33789 this.tabs.hideTab(panel.getEl().id);
33794 * Unhides the tab for a previously hidden panel.
33795 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33797 unhidePanel : function(panel){
33798 if(this.tabs && (panel = this.getPanel(panel))){
33799 this.tabs.unhideTab(panel.getEl().id);
33803 clearPanels : function(){
33804 while(this.panels.getCount() > 0){
33805 this.remove(this.panels.first());
33810 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33811 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33812 * @param {Boolean} preservePanel Overrides the config preservePanel option
33813 * @return {Roo.ContentPanel} The panel that was removed
33815 remove : function(panel, preservePanel){
33816 panel = this.getPanel(panel);
33821 this.fireEvent("beforeremove", this, panel, e);
33822 if(e.cancel === true){
33825 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33826 var panelId = panel.getId();
33827 this.panels.removeKey(panelId);
33829 document.body.appendChild(panel.getEl().dom);
33832 this.tabs.removeTab(panel.getEl().id);
33833 }else if (!preservePanel){
33834 this.bodyEl.dom.removeChild(panel.getEl().dom);
33836 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33837 var p = this.panels.first();
33838 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33839 tempEl.appendChild(p.getEl().dom);
33840 this.bodyEl.update("");
33841 this.bodyEl.dom.appendChild(p.getEl().dom);
33843 this.updateTitle(p.getTitle());
33845 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33846 this.setActivePanel(p);
33848 panel.setRegion(null);
33849 if(this.activePanel == panel){
33850 this.activePanel = null;
33852 if(this.config.autoDestroy !== false && preservePanel !== true){
33853 try{panel.destroy();}catch(e){}
33855 this.fireEvent("panelremoved", this, panel);
33860 * Returns the TabPanel component used by this region
33861 * @return {Roo.TabPanel}
33863 getTabs : function(){
33867 createTool : function(parentEl, className){
33868 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
33869 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
33870 btn.addClassOnOver("x-layout-tools-button-over");
33875 * Ext JS Library 1.1.1
33876 * Copyright(c) 2006-2007, Ext JS, LLC.
33878 * Originally Released Under LGPL - original licence link has changed is not relivant.
33881 * <script type="text/javascript">
33887 * @class Roo.SplitLayoutRegion
33888 * @extends Roo.LayoutRegion
33889 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33891 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
33892 this.cursor = cursor;
33893 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
33896 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
33897 splitTip : "Drag to resize.",
33898 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33899 useSplitTips : false,
33901 applyConfig : function(config){
33902 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
33905 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
33906 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
33907 /** The SplitBar for this region
33908 * @type Roo.SplitBar */
33909 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
33910 this.split.on("moved", this.onSplitMove, this);
33911 this.split.useShim = config.useShim === true;
33912 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33913 if(this.useSplitTips){
33914 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33916 if(config.collapsible){
33917 this.split.el.on("dblclick", this.collapse, this);
33920 if(typeof config.minSize != "undefined"){
33921 this.split.minSize = config.minSize;
33923 if(typeof config.maxSize != "undefined"){
33924 this.split.maxSize = config.maxSize;
33926 if(config.hideWhenEmpty || config.hidden || config.collapsed){
33927 this.hideSplitter();
33932 getHMaxSize : function(){
33933 var cmax = this.config.maxSize || 10000;
33934 var center = this.mgr.getRegion("center");
33935 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33938 getVMaxSize : function(){
33939 var cmax = this.config.maxSize || 10000;
33940 var center = this.mgr.getRegion("center");
33941 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33944 onSplitMove : function(split, newSize){
33945 this.fireEvent("resized", this, newSize);
33949 * Returns the {@link Roo.SplitBar} for this region.
33950 * @return {Roo.SplitBar}
33952 getSplitBar : function(){
33957 this.hideSplitter();
33958 Roo.SplitLayoutRegion.superclass.hide.call(this);
33961 hideSplitter : function(){
33963 this.split.el.setLocation(-2000,-2000);
33964 this.split.el.hide();
33970 this.split.el.show();
33972 Roo.SplitLayoutRegion.superclass.show.call(this);
33975 beforeSlide: function(){
33976 if(Roo.isGecko){// firefox overflow auto bug workaround
33977 this.bodyEl.clip();
33978 if(this.tabs) this.tabs.bodyEl.clip();
33979 if(this.activePanel){
33980 this.activePanel.getEl().clip();
33982 if(this.activePanel.beforeSlide){
33983 this.activePanel.beforeSlide();
33989 afterSlide : function(){
33990 if(Roo.isGecko){// firefox overflow auto bug workaround
33991 this.bodyEl.unclip();
33992 if(this.tabs) this.tabs.bodyEl.unclip();
33993 if(this.activePanel){
33994 this.activePanel.getEl().unclip();
33995 if(this.activePanel.afterSlide){
33996 this.activePanel.afterSlide();
34002 initAutoHide : function(){
34003 if(this.autoHide !== false){
34004 if(!this.autoHideHd){
34005 var st = new Roo.util.DelayedTask(this.slideIn, this);
34006 this.autoHideHd = {
34007 "mouseout": function(e){
34008 if(!e.within(this.el, true)){
34012 "mouseover" : function(e){
34018 this.el.on(this.autoHideHd);
34022 clearAutoHide : function(){
34023 if(this.autoHide !== false){
34024 this.el.un("mouseout", this.autoHideHd.mouseout);
34025 this.el.un("mouseover", this.autoHideHd.mouseover);
34029 clearMonitor : function(){
34030 Roo.get(document).un("click", this.slideInIf, this);
34033 // these names are backwards but not changed for compat
34034 slideOut : function(){
34035 if(this.isSlid || this.el.hasActiveFx()){
34038 this.isSlid = true;
34039 if(this.collapseBtn){
34040 this.collapseBtn.hide();
34042 this.closeBtnState = this.closeBtn.getStyle('display');
34043 this.closeBtn.hide();
34045 this.stickBtn.show();
34048 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
34049 this.beforeSlide();
34050 this.el.setStyle("z-index", 10001);
34051 this.el.slideIn(this.getSlideAnchor(), {
34052 callback: function(){
34054 this.initAutoHide();
34055 Roo.get(document).on("click", this.slideInIf, this);
34056 this.fireEvent("slideshow", this);
34063 afterSlideIn : function(){
34064 this.clearAutoHide();
34065 this.isSlid = false;
34066 this.clearMonitor();
34067 this.el.setStyle("z-index", "");
34068 if(this.collapseBtn){
34069 this.collapseBtn.show();
34071 this.closeBtn.setStyle('display', this.closeBtnState);
34073 this.stickBtn.hide();
34075 this.fireEvent("slidehide", this);
34078 slideIn : function(cb){
34079 if(!this.isSlid || this.el.hasActiveFx()){
34083 this.isSlid = false;
34084 this.beforeSlide();
34085 this.el.slideOut(this.getSlideAnchor(), {
34086 callback: function(){
34087 this.el.setLeftTop(-10000, -10000);
34089 this.afterSlideIn();
34097 slideInIf : function(e){
34098 if(!e.within(this.el)){
34103 animateCollapse : function(){
34104 this.beforeSlide();
34105 this.el.setStyle("z-index", 20000);
34106 var anchor = this.getSlideAnchor();
34107 this.el.slideOut(anchor, {
34108 callback : function(){
34109 this.el.setStyle("z-index", "");
34110 this.collapsedEl.slideIn(anchor, {duration:.3});
34112 this.el.setLocation(-10000,-10000);
34114 this.fireEvent("collapsed", this);
34121 animateExpand : function(){
34122 this.beforeSlide();
34123 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34124 this.el.setStyle("z-index", 20000);
34125 this.collapsedEl.hide({
34128 this.el.slideIn(this.getSlideAnchor(), {
34129 callback : function(){
34130 this.el.setStyle("z-index", "");
34133 this.split.el.show();
34135 this.fireEvent("invalidated", this);
34136 this.fireEvent("expanded", this);
34164 getAnchor : function(){
34165 return this.anchors[this.position];
34168 getCollapseAnchor : function(){
34169 return this.canchors[this.position];
34172 getSlideAnchor : function(){
34173 return this.sanchors[this.position];
34176 getAlignAdj : function(){
34177 var cm = this.cmargins;
34178 switch(this.position){
34194 getExpandAdj : function(){
34195 var c = this.collapsedEl, cm = this.cmargins;
34196 switch(this.position){
34198 return [-(cm.right+c.getWidth()+cm.left), 0];
34201 return [cm.right+c.getWidth()+cm.left, 0];
34204 return [0, -(cm.top+cm.bottom+c.getHeight())];
34207 return [0, cm.top+cm.bottom+c.getHeight()];
34213 * Ext JS Library 1.1.1
34214 * Copyright(c) 2006-2007, Ext JS, LLC.
34216 * Originally Released Under LGPL - original licence link has changed is not relivant.
34219 * <script type="text/javascript">
34222 * These classes are private internal classes
34224 Roo.CenterLayoutRegion = function(mgr, config){
34225 Roo.LayoutRegion.call(this, mgr, config, "center");
34226 this.visible = true;
34227 this.minWidth = config.minWidth || 20;
34228 this.minHeight = config.minHeight || 20;
34231 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
34233 // center panel can't be hidden
34237 // center panel can't be hidden
34240 getMinWidth: function(){
34241 return this.minWidth;
34244 getMinHeight: function(){
34245 return this.minHeight;
34250 Roo.NorthLayoutRegion = function(mgr, config){
34251 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
34253 this.split.placement = Roo.SplitBar.TOP;
34254 this.split.orientation = Roo.SplitBar.VERTICAL;
34255 this.split.el.addClass("x-layout-split-v");
34257 var size = config.initialSize || config.height;
34258 if(typeof size != "undefined"){
34259 this.el.setHeight(size);
34262 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
34263 orientation: Roo.SplitBar.VERTICAL,
34264 getBox : function(){
34265 if(this.collapsed){
34266 return this.collapsedEl.getBox();
34268 var box = this.el.getBox();
34270 box.height += this.split.el.getHeight();
34275 updateBox : function(box){
34276 if(this.split && !this.collapsed){
34277 box.height -= this.split.el.getHeight();
34278 this.split.el.setLeft(box.x);
34279 this.split.el.setTop(box.y+box.height);
34280 this.split.el.setWidth(box.width);
34282 if(this.collapsed){
34283 this.updateBody(box.width, null);
34285 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34289 Roo.SouthLayoutRegion = function(mgr, config){
34290 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
34292 this.split.placement = Roo.SplitBar.BOTTOM;
34293 this.split.orientation = Roo.SplitBar.VERTICAL;
34294 this.split.el.addClass("x-layout-split-v");
34296 var size = config.initialSize || config.height;
34297 if(typeof size != "undefined"){
34298 this.el.setHeight(size);
34301 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
34302 orientation: Roo.SplitBar.VERTICAL,
34303 getBox : function(){
34304 if(this.collapsed){
34305 return this.collapsedEl.getBox();
34307 var box = this.el.getBox();
34309 var sh = this.split.el.getHeight();
34316 updateBox : function(box){
34317 if(this.split && !this.collapsed){
34318 var sh = this.split.el.getHeight();
34321 this.split.el.setLeft(box.x);
34322 this.split.el.setTop(box.y-sh);
34323 this.split.el.setWidth(box.width);
34325 if(this.collapsed){
34326 this.updateBody(box.width, null);
34328 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34332 Roo.EastLayoutRegion = function(mgr, config){
34333 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
34335 this.split.placement = Roo.SplitBar.RIGHT;
34336 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34337 this.split.el.addClass("x-layout-split-h");
34339 var size = config.initialSize || config.width;
34340 if(typeof size != "undefined"){
34341 this.el.setWidth(size);
34344 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
34345 orientation: Roo.SplitBar.HORIZONTAL,
34346 getBox : function(){
34347 if(this.collapsed){
34348 return this.collapsedEl.getBox();
34350 var box = this.el.getBox();
34352 var sw = this.split.el.getWidth();
34359 updateBox : function(box){
34360 if(this.split && !this.collapsed){
34361 var sw = this.split.el.getWidth();
34363 this.split.el.setLeft(box.x);
34364 this.split.el.setTop(box.y);
34365 this.split.el.setHeight(box.height);
34368 if(this.collapsed){
34369 this.updateBody(null, box.height);
34371 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34375 Roo.WestLayoutRegion = function(mgr, config){
34376 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
34378 this.split.placement = Roo.SplitBar.LEFT;
34379 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34380 this.split.el.addClass("x-layout-split-h");
34382 var size = config.initialSize || config.width;
34383 if(typeof size != "undefined"){
34384 this.el.setWidth(size);
34387 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
34388 orientation: Roo.SplitBar.HORIZONTAL,
34389 getBox : function(){
34390 if(this.collapsed){
34391 return this.collapsedEl.getBox();
34393 var box = this.el.getBox();
34395 box.width += this.split.el.getWidth();
34400 updateBox : function(box){
34401 if(this.split && !this.collapsed){
34402 var sw = this.split.el.getWidth();
34404 this.split.el.setLeft(box.x+box.width);
34405 this.split.el.setTop(box.y);
34406 this.split.el.setHeight(box.height);
34408 if(this.collapsed){
34409 this.updateBody(null, box.height);
34411 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34416 * Ext JS Library 1.1.1
34417 * Copyright(c) 2006-2007, Ext JS, LLC.
34419 * Originally Released Under LGPL - original licence link has changed is not relivant.
34422 * <script type="text/javascript">
34427 * Private internal class for reading and applying state
34429 Roo.LayoutStateManager = function(layout){
34430 // default empty state
34439 Roo.LayoutStateManager.prototype = {
34440 init : function(layout, provider){
34441 this.provider = provider;
34442 var state = provider.get(layout.id+"-layout-state");
34444 var wasUpdating = layout.isUpdating();
34446 layout.beginUpdate();
34448 for(var key in state){
34449 if(typeof state[key] != "function"){
34450 var rstate = state[key];
34451 var r = layout.getRegion(key);
34454 r.resizeTo(rstate.size);
34456 if(rstate.collapsed == true){
34459 r.expand(null, true);
34465 layout.endUpdate();
34467 this.state = state;
34469 this.layout = layout;
34470 layout.on("regionresized", this.onRegionResized, this);
34471 layout.on("regioncollapsed", this.onRegionCollapsed, this);
34472 layout.on("regionexpanded", this.onRegionExpanded, this);
34475 storeState : function(){
34476 this.provider.set(this.layout.id+"-layout-state", this.state);
34479 onRegionResized : function(region, newSize){
34480 this.state[region.getPosition()].size = newSize;
34484 onRegionCollapsed : function(region){
34485 this.state[region.getPosition()].collapsed = true;
34489 onRegionExpanded : function(region){
34490 this.state[region.getPosition()].collapsed = false;
34495 * Ext JS Library 1.1.1
34496 * Copyright(c) 2006-2007, Ext JS, LLC.
34498 * Originally Released Under LGPL - original licence link has changed is not relivant.
34501 * <script type="text/javascript">
34504 * @class Roo.ContentPanel
34505 * @extends Roo.util.Observable
34506 * A basic ContentPanel element.
34507 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34508 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34509 * @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
34510 * @cfg {Boolean} closable True if the panel can be closed/removed
34511 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34512 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34513 * @cfg {Toolbar} toolbar A toolbar for this panel
34514 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34515 * @cfg {String} title The title for this panel
34516 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34517 * @cfg {String} url Calls {@link #setUrl} with this value
34518 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34519 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34520 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34521 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34524 * Create a new ContentPanel.
34525 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34526 * @param {String/Object} config A string to set only the title or a config object
34527 * @param {String} content (optional) Set the HTML content for this panel
34528 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34530 Roo.ContentPanel = function(el, config, content){
34534 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
34538 if (config && config.parentLayout) {
34539 el = config.parentLayout.el.createChild();
34542 if(el.autoCreate){ // xtype is available if this is called from factory
34546 this.el = Roo.get(el);
34547 if(!this.el && config && config.autoCreate){
34548 if(typeof config.autoCreate == "object"){
34549 if(!config.autoCreate.id){
34550 config.autoCreate.id = config.id||el;
34552 this.el = Roo.DomHelper.append(document.body,
34553 config.autoCreate, true);
34555 this.el = Roo.DomHelper.append(document.body,
34556 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
34559 this.closable = false;
34560 this.loaded = false;
34561 this.active = false;
34562 if(typeof config == "string"){
34563 this.title = config;
34565 Roo.apply(this, config);
34568 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
34569 this.wrapEl = this.el.wrap();
34570 this.toolbar.container = this.el.insertSibling(false, 'before');
34571 this.toolbar = new Roo.Toolbar(this.toolbar);
34574 // xtype created footer. - not sure if will work as we normally have to render first..
34575 if (this.footer && !this.footer.el && this.footer.xtype) {
34576 if (!this.wrapEl) {
34577 this.wrapEl = this.el.wrap();
34580 this.footer.container = this.wrapEl.createChild();
34582 this.footer = Roo.factory(this.footer, Roo);
34587 this.resizeEl = Roo.get(this.resizeEl, true);
34589 this.resizeEl = this.el;
34591 // handle view.xtype
34599 * Fires when this panel is activated.
34600 * @param {Roo.ContentPanel} this
34604 * @event deactivate
34605 * Fires when this panel is activated.
34606 * @param {Roo.ContentPanel} this
34608 "deactivate" : true,
34612 * Fires when this panel is resized if fitToFrame is true.
34613 * @param {Roo.ContentPanel} this
34614 * @param {Number} width The width after any component adjustments
34615 * @param {Number} height The height after any component adjustments
34621 * Fires when this tab is created
34622 * @param {Roo.ContentPanel} this
34633 if(this.autoScroll){
34634 this.resizeEl.setStyle("overflow", "auto");
34636 // fix randome scrolling
34637 this.el.on('scroll', function() {
34638 Roo.log('fix random scolling');
34639 this.scrollTo('top',0);
34642 content = content || this.content;
34644 this.setContent(content);
34646 if(config && config.url){
34647 this.setUrl(this.url, this.params, this.loadOnce);
34652 Roo.ContentPanel.superclass.constructor.call(this);
34654 if (this.view && typeof(this.view.xtype) != 'undefined') {
34655 this.view.el = this.el.appendChild(document.createElement("div"));
34656 this.view = Roo.factory(this.view);
34657 this.view.render && this.view.render(false, '');
34661 this.fireEvent('render', this);
34664 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
34666 setRegion : function(region){
34667 this.region = region;
34669 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
34671 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
34676 * Returns the toolbar for this Panel if one was configured.
34677 * @return {Roo.Toolbar}
34679 getToolbar : function(){
34680 return this.toolbar;
34683 setActiveState : function(active){
34684 this.active = active;
34686 this.fireEvent("deactivate", this);
34688 this.fireEvent("activate", this);
34692 * Updates this panel's element
34693 * @param {String} content The new content
34694 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34696 setContent : function(content, loadScripts){
34697 this.el.update(content, loadScripts);
34700 ignoreResize : function(w, h){
34701 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34704 this.lastSize = {width: w, height: h};
34709 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34710 * @return {Roo.UpdateManager} The UpdateManager
34712 getUpdateManager : function(){
34713 return this.el.getUpdateManager();
34716 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34717 * @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:
34720 url: "your-url.php",
34721 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34722 callback: yourFunction,
34723 scope: yourObject, //(optional scope)
34726 text: "Loading...",
34731 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34732 * 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.
34733 * @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}
34734 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34735 * @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.
34736 * @return {Roo.ContentPanel} this
34739 var um = this.el.getUpdateManager();
34740 um.update.apply(um, arguments);
34746 * 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.
34747 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34748 * @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)
34749 * @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)
34750 * @return {Roo.UpdateManager} The UpdateManager
34752 setUrl : function(url, params, loadOnce){
34753 if(this.refreshDelegate){
34754 this.removeListener("activate", this.refreshDelegate);
34756 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34757 this.on("activate", this.refreshDelegate);
34758 return this.el.getUpdateManager();
34761 _handleRefresh : function(url, params, loadOnce){
34762 if(!loadOnce || !this.loaded){
34763 var updater = this.el.getUpdateManager();
34764 updater.update(url, params, this._setLoaded.createDelegate(this));
34768 _setLoaded : function(){
34769 this.loaded = true;
34773 * Returns this panel's id
34776 getId : function(){
34781 * Returns this panel's element - used by regiosn to add.
34782 * @return {Roo.Element}
34784 getEl : function(){
34785 return this.wrapEl || this.el;
34788 adjustForComponents : function(width, height)
34790 //Roo.log('adjustForComponents ');
34791 if(this.resizeEl != this.el){
34792 width -= this.el.getFrameWidth('lr');
34793 height -= this.el.getFrameWidth('tb');
34796 var te = this.toolbar.getEl();
34797 height -= te.getHeight();
34798 te.setWidth(width);
34801 var te = this.footer.getEl();
34802 Roo.log("footer:" + te.getHeight());
34804 height -= te.getHeight();
34805 te.setWidth(width);
34809 if(this.adjustments){
34810 width += this.adjustments[0];
34811 height += this.adjustments[1];
34813 return {"width": width, "height": height};
34816 setSize : function(width, height){
34817 if(this.fitToFrame && !this.ignoreResize(width, height)){
34818 if(this.fitContainer && this.resizeEl != this.el){
34819 this.el.setSize(width, height);
34821 var size = this.adjustForComponents(width, height);
34822 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34823 this.fireEvent('resize', this, size.width, size.height);
34828 * Returns this panel's title
34831 getTitle : function(){
34836 * Set this panel's title
34837 * @param {String} title
34839 setTitle : function(title){
34840 this.title = title;
34842 this.region.updatePanelTitle(this, title);
34847 * Returns true is this panel was configured to be closable
34848 * @return {Boolean}
34850 isClosable : function(){
34851 return this.closable;
34854 beforeSlide : function(){
34856 this.resizeEl.clip();
34859 afterSlide : function(){
34861 this.resizeEl.unclip();
34865 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34866 * Will fail silently if the {@link #setUrl} method has not been called.
34867 * This does not activate the panel, just updates its content.
34869 refresh : function(){
34870 if(this.refreshDelegate){
34871 this.loaded = false;
34872 this.refreshDelegate();
34877 * Destroys this panel
34879 destroy : function(){
34880 this.el.removeAllListeners();
34881 var tempEl = document.createElement("span");
34882 tempEl.appendChild(this.el.dom);
34883 tempEl.innerHTML = "";
34889 * form - if the content panel contains a form - this is a reference to it.
34890 * @type {Roo.form.Form}
34894 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34895 * This contains a reference to it.
34901 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34911 * @param {Object} cfg Xtype definition of item to add.
34914 addxtype : function(cfg) {
34916 if (cfg.xtype.match(/^Form$/)) {
34919 //if (this.footer) {
34920 // el = this.footer.container.insertSibling(false, 'before');
34922 el = this.el.createChild();
34925 this.form = new Roo.form.Form(cfg);
34928 if ( this.form.allItems.length) this.form.render(el.dom);
34931 // should only have one of theses..
34932 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34933 // views.. should not be just added - used named prop 'view''
34935 cfg.el = this.el.appendChild(document.createElement("div"));
34938 var ret = new Roo.factory(cfg);
34940 ret.render && ret.render(false, ''); // render blank..
34949 * @class Roo.GridPanel
34950 * @extends Roo.ContentPanel
34952 * Create a new GridPanel.
34953 * @param {Roo.grid.Grid} grid The grid for this panel
34954 * @param {String/Object} config A string to set only the panel's title, or a config object
34956 Roo.GridPanel = function(grid, config){
34959 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34960 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
34962 this.wrapper.dom.appendChild(grid.getGridEl().dom);
34964 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
34967 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
34969 // xtype created footer. - not sure if will work as we normally have to render first..
34970 if (this.footer && !this.footer.el && this.footer.xtype) {
34972 this.footer.container = this.grid.getView().getFooterPanel(true);
34973 this.footer.dataSource = this.grid.dataSource;
34974 this.footer = Roo.factory(this.footer, Roo);
34978 grid.monitorWindowResize = false; // turn off autosizing
34979 grid.autoHeight = false;
34980 grid.autoWidth = false;
34982 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
34985 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
34986 getId : function(){
34987 return this.grid.id;
34991 * Returns the grid for this panel
34992 * @return {Roo.grid.Grid}
34994 getGrid : function(){
34998 setSize : function(width, height){
34999 if(!this.ignoreResize(width, height)){
35000 var grid = this.grid;
35001 var size = this.adjustForComponents(width, height);
35002 grid.getGridEl().setSize(size.width, size.height);
35007 beforeSlide : function(){
35008 this.grid.getView().scroller.clip();
35011 afterSlide : function(){
35012 this.grid.getView().scroller.unclip();
35015 destroy : function(){
35016 this.grid.destroy();
35018 Roo.GridPanel.superclass.destroy.call(this);
35024 * @class Roo.NestedLayoutPanel
35025 * @extends Roo.ContentPanel
35027 * Create a new NestedLayoutPanel.
35030 * @param {Roo.BorderLayout} layout The layout for this panel
35031 * @param {String/Object} config A string to set only the title or a config object
35033 Roo.NestedLayoutPanel = function(layout, config)
35035 // construct with only one argument..
35036 /* FIXME - implement nicer consturctors
35037 if (layout.layout) {
35039 layout = config.layout;
35040 delete config.layout;
35042 if (layout.xtype && !layout.getEl) {
35043 // then layout needs constructing..
35044 layout = Roo.factory(layout, Roo);
35049 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
35051 layout.monitorWindowResize = false; // turn off autosizing
35052 this.layout = layout;
35053 this.layout.getEl().addClass("x-layout-nested-layout");
35060 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
35062 setSize : function(width, height){
35063 if(!this.ignoreResize(width, height)){
35064 var size = this.adjustForComponents(width, height);
35065 var el = this.layout.getEl();
35066 el.setSize(size.width, size.height);
35067 var touch = el.dom.offsetWidth;
35068 this.layout.layout();
35069 // ie requires a double layout on the first pass
35070 if(Roo.isIE && !this.initialized){
35071 this.initialized = true;
35072 this.layout.layout();
35077 // activate all subpanels if not currently active..
35079 setActiveState : function(active){
35080 this.active = active;
35082 this.fireEvent("deactivate", this);
35086 this.fireEvent("activate", this);
35087 // not sure if this should happen before or after..
35088 if (!this.layout) {
35089 return; // should not happen..
35092 for (var r in this.layout.regions) {
35093 reg = this.layout.getRegion(r);
35094 if (reg.getActivePanel()) {
35095 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35096 reg.setActivePanel(reg.getActivePanel());
35099 if (!reg.panels.length) {
35102 reg.showPanel(reg.getPanel(0));
35111 * Returns the nested BorderLayout for this panel
35112 * @return {Roo.BorderLayout}
35114 getLayout : function(){
35115 return this.layout;
35119 * Adds a xtype elements to the layout of the nested panel
35123 xtype : 'ContentPanel',
35130 xtype : 'NestedLayoutPanel',
35136 items : [ ... list of content panels or nested layout panels.. ]
35140 * @param {Object} cfg Xtype definition of item to add.
35142 addxtype : function(cfg) {
35143 return this.layout.addxtype(cfg);
35148 Roo.ScrollPanel = function(el, config, content){
35149 config = config || {};
35150 config.fitToFrame = true;
35151 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
35153 this.el.dom.style.overflow = "hidden";
35154 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
35155 this.el.removeClass("x-layout-inactive-content");
35156 this.el.on("mousewheel", this.onWheel, this);
35158 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
35159 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
35160 up.unselectable(); down.unselectable();
35161 up.on("click", this.scrollUp, this);
35162 down.on("click", this.scrollDown, this);
35163 up.addClassOnOver("x-scroller-btn-over");
35164 down.addClassOnOver("x-scroller-btn-over");
35165 up.addClassOnClick("x-scroller-btn-click");
35166 down.addClassOnClick("x-scroller-btn-click");
35167 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
35169 this.resizeEl = this.el;
35170 this.el = wrap; this.up = up; this.down = down;
35173 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
35175 wheelIncrement : 5,
35176 scrollUp : function(){
35177 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
35180 scrollDown : function(){
35181 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
35184 afterScroll : function(){
35185 var el = this.resizeEl;
35186 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
35187 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35188 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35191 setSize : function(){
35192 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
35193 this.afterScroll();
35196 onWheel : function(e){
35197 var d = e.getWheelDelta();
35198 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
35199 this.afterScroll();
35203 setContent : function(content, loadScripts){
35204 this.resizeEl.update(content, loadScripts);
35218 * @class Roo.TreePanel
35219 * @extends Roo.ContentPanel
35221 * Create a new TreePanel. - defaults to fit/scoll contents.
35222 * @param {String/Object} config A string to set only the panel's title, or a config object
35223 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
35225 Roo.TreePanel = function(config){
35226 var el = config.el;
35227 var tree = config.tree;
35228 delete config.tree;
35229 delete config.el; // hopefull!
35231 // wrapper for IE7 strict & safari scroll issue
35233 var treeEl = el.createChild();
35234 config.resizeEl = treeEl;
35238 Roo.TreePanel.superclass.constructor.call(this, el, config);
35241 this.tree = new Roo.tree.TreePanel(treeEl , tree);
35242 //console.log(tree);
35243 this.on('activate', function()
35245 if (this.tree.rendered) {
35248 //console.log('render tree');
35249 this.tree.render();
35251 // this should not be needed.. - it's actually the 'el' that resizes?
35252 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
35254 //this.on('resize', function (cp, w, h) {
35255 // this.tree.innerCt.setWidth(w);
35256 // this.tree.innerCt.setHeight(h);
35257 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
35264 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
35281 * Ext JS Library 1.1.1
35282 * Copyright(c) 2006-2007, Ext JS, LLC.
35284 * Originally Released Under LGPL - original licence link has changed is not relivant.
35287 * <script type="text/javascript">
35292 * @class Roo.ReaderLayout
35293 * @extends Roo.BorderLayout
35294 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
35295 * center region containing two nested regions (a top one for a list view and one for item preview below),
35296 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
35297 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
35298 * expedites the setup of the overall layout and regions for this common application style.
35301 var reader = new Roo.ReaderLayout();
35302 var CP = Roo.ContentPanel; // shortcut for adding
35304 reader.beginUpdate();
35305 reader.add("north", new CP("north", "North"));
35306 reader.add("west", new CP("west", {title: "West"}));
35307 reader.add("east", new CP("east", {title: "East"}));
35309 reader.regions.listView.add(new CP("listView", "List"));
35310 reader.regions.preview.add(new CP("preview", "Preview"));
35311 reader.endUpdate();
35314 * Create a new ReaderLayout
35315 * @param {Object} config Configuration options
35316 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
35317 * document.body if omitted)
35319 Roo.ReaderLayout = function(config, renderTo){
35320 var c = config || {size:{}};
35321 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
35322 north: c.north !== false ? Roo.apply({
35326 }, c.north) : false,
35327 west: c.west !== false ? Roo.apply({
35335 margins:{left:5,right:0,bottom:5,top:5},
35336 cmargins:{left:5,right:5,bottom:5,top:5}
35337 }, c.west) : false,
35338 east: c.east !== false ? Roo.apply({
35346 margins:{left:0,right:5,bottom:5,top:5},
35347 cmargins:{left:5,right:5,bottom:5,top:5}
35348 }, c.east) : false,
35349 center: Roo.apply({
35350 tabPosition: 'top',
35354 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
35358 this.el.addClass('x-reader');
35360 this.beginUpdate();
35362 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
35363 south: c.preview !== false ? Roo.apply({
35370 cmargins:{top:5,left:0, right:0, bottom:0}
35371 }, c.preview) : false,
35372 center: Roo.apply({
35378 this.add('center', new Roo.NestedLayoutPanel(inner,
35379 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
35383 this.regions.preview = inner.getRegion('south');
35384 this.regions.listView = inner.getRegion('center');
35387 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
35389 * Ext JS Library 1.1.1
35390 * Copyright(c) 2006-2007, Ext JS, LLC.
35392 * Originally Released Under LGPL - original licence link has changed is not relivant.
35395 * <script type="text/javascript">
35399 * @class Roo.grid.Grid
35400 * @extends Roo.util.Observable
35401 * This class represents the primary interface of a component based grid control.
35402 * <br><br>Usage:<pre><code>
35403 var grid = new Roo.grid.Grid("my-container-id", {
35406 selModel: mySelectionModel,
35407 autoSizeColumns: true,
35408 monitorWindowResize: false,
35409 trackMouseOver: true
35414 * <b>Common Problems:</b><br/>
35415 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
35416 * element will correct this<br/>
35417 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
35418 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
35419 * are unpredictable.<br/>
35420 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
35421 * grid to calculate dimensions/offsets.<br/>
35423 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35424 * The container MUST have some type of size defined for the grid to fill. The container will be
35425 * automatically set to position relative if it isn't already.
35426 * @param {Object} config A config object that sets properties on this grid.
35428 Roo.grid.Grid = function(container, config){
35429 // initialize the container
35430 this.container = Roo.get(container);
35431 this.container.update("");
35432 this.container.setStyle("overflow", "hidden");
35433 this.container.addClass('x-grid-container');
35435 this.id = this.container.id;
35437 Roo.apply(this, config);
35438 // check and correct shorthanded configs
35440 this.dataSource = this.ds;
35444 this.colModel = this.cm;
35448 this.selModel = this.sm;
35452 if (this.selModel) {
35453 this.selModel = Roo.factory(this.selModel, Roo.grid);
35454 this.sm = this.selModel;
35455 this.sm.xmodule = this.xmodule || false;
35457 if (typeof(this.colModel.config) == 'undefined') {
35458 this.colModel = new Roo.grid.ColumnModel(this.colModel);
35459 this.cm = this.colModel;
35460 this.cm.xmodule = this.xmodule || false;
35462 if (this.dataSource) {
35463 this.dataSource= Roo.factory(this.dataSource, Roo.data);
35464 this.ds = this.dataSource;
35465 this.ds.xmodule = this.xmodule || false;
35472 this.container.setWidth(this.width);
35476 this.container.setHeight(this.height);
35483 * The raw click event for the entire grid.
35484 * @param {Roo.EventObject} e
35489 * The raw dblclick event for the entire grid.
35490 * @param {Roo.EventObject} e
35494 * @event contextmenu
35495 * The raw contextmenu event for the entire grid.
35496 * @param {Roo.EventObject} e
35498 "contextmenu" : true,
35501 * The raw mousedown event for the entire grid.
35502 * @param {Roo.EventObject} e
35504 "mousedown" : true,
35507 * The raw mouseup event for the entire grid.
35508 * @param {Roo.EventObject} e
35513 * The raw mouseover event for the entire grid.
35514 * @param {Roo.EventObject} e
35516 "mouseover" : true,
35519 * The raw mouseout event for the entire grid.
35520 * @param {Roo.EventObject} e
35525 * The raw keypress event for the entire grid.
35526 * @param {Roo.EventObject} e
35531 * The raw keydown event for the entire grid.
35532 * @param {Roo.EventObject} e
35540 * Fires when a cell is clicked
35541 * @param {Grid} this
35542 * @param {Number} rowIndex
35543 * @param {Number} columnIndex
35544 * @param {Roo.EventObject} e
35546 "cellclick" : true,
35548 * @event celldblclick
35549 * Fires when a cell is double clicked
35550 * @param {Grid} this
35551 * @param {Number} rowIndex
35552 * @param {Number} columnIndex
35553 * @param {Roo.EventObject} e
35555 "celldblclick" : true,
35558 * Fires when a row is clicked
35559 * @param {Grid} this
35560 * @param {Number} rowIndex
35561 * @param {Roo.EventObject} e
35565 * @event rowdblclick
35566 * Fires when a row is double clicked
35567 * @param {Grid} this
35568 * @param {Number} rowIndex
35569 * @param {Roo.EventObject} e
35571 "rowdblclick" : true,
35573 * @event headerclick
35574 * Fires when a header is clicked
35575 * @param {Grid} this
35576 * @param {Number} columnIndex
35577 * @param {Roo.EventObject} e
35579 "headerclick" : true,
35581 * @event headerdblclick
35582 * Fires when a header cell is double clicked
35583 * @param {Grid} this
35584 * @param {Number} columnIndex
35585 * @param {Roo.EventObject} e
35587 "headerdblclick" : true,
35589 * @event rowcontextmenu
35590 * Fires when a row is right clicked
35591 * @param {Grid} this
35592 * @param {Number} rowIndex
35593 * @param {Roo.EventObject} e
35595 "rowcontextmenu" : true,
35597 * @event cellcontextmenu
35598 * Fires when a cell is right clicked
35599 * @param {Grid} this
35600 * @param {Number} rowIndex
35601 * @param {Number} cellIndex
35602 * @param {Roo.EventObject} e
35604 "cellcontextmenu" : true,
35606 * @event headercontextmenu
35607 * Fires when a header is right clicked
35608 * @param {Grid} this
35609 * @param {Number} columnIndex
35610 * @param {Roo.EventObject} e
35612 "headercontextmenu" : true,
35614 * @event bodyscroll
35615 * Fires when the body element is scrolled
35616 * @param {Number} scrollLeft
35617 * @param {Number} scrollTop
35619 "bodyscroll" : true,
35621 * @event columnresize
35622 * Fires when the user resizes a column
35623 * @param {Number} columnIndex
35624 * @param {Number} newSize
35626 "columnresize" : true,
35628 * @event columnmove
35629 * Fires when the user moves a column
35630 * @param {Number} oldIndex
35631 * @param {Number} newIndex
35633 "columnmove" : true,
35636 * Fires when row(s) start being dragged
35637 * @param {Grid} this
35638 * @param {Roo.GridDD} dd The drag drop object
35639 * @param {event} e The raw browser event
35641 "startdrag" : true,
35644 * Fires when a drag operation is complete
35645 * @param {Grid} this
35646 * @param {Roo.GridDD} dd The drag drop object
35647 * @param {event} e The raw browser event
35652 * Fires when dragged row(s) are dropped on a valid DD target
35653 * @param {Grid} this
35654 * @param {Roo.GridDD} dd The drag drop object
35655 * @param {String} targetId The target drag drop object
35656 * @param {event} e The raw browser event
35661 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
35662 * @param {Grid} this
35663 * @param {Roo.GridDD} dd The drag drop object
35664 * @param {String} targetId The target drag drop object
35665 * @param {event} e The raw browser event
35670 * Fires when the dragged row(s) first cross another DD target while being dragged
35671 * @param {Grid} this
35672 * @param {Roo.GridDD} dd The drag drop object
35673 * @param {String} targetId The target drag drop object
35674 * @param {event} e The raw browser event
35676 "dragenter" : true,
35679 * Fires when the dragged row(s) leave another DD target while being dragged
35680 * @param {Grid} this
35681 * @param {Roo.GridDD} dd The drag drop object
35682 * @param {String} targetId The target drag drop object
35683 * @param {event} e The raw browser event
35688 * Fires when a row is rendered, so you can change add a style to it.
35689 * @param {GridView} gridview The grid view
35690 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
35696 * Fires when the grid is rendered
35697 * @param {Grid} grid
35702 Roo.grid.Grid.superclass.constructor.call(this);
35704 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
35707 * @cfg {String} ddGroup - drag drop group.
35711 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
35713 minColumnWidth : 25,
35716 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
35717 * <b>on initial render.</b> It is more efficient to explicitly size the columns
35718 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
35720 autoSizeColumns : false,
35723 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
35725 autoSizeHeaders : true,
35728 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
35730 monitorWindowResize : true,
35733 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
35734 * rows measured to get a columns size. Default is 0 (all rows).
35736 maxRowsToMeasure : 0,
35739 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
35741 trackMouseOver : true,
35744 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
35748 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
35750 enableDragDrop : false,
35753 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
35755 enableColumnMove : true,
35758 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
35760 enableColumnHide : true,
35763 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
35765 enableRowHeightSync : false,
35768 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
35773 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
35775 autoHeight : false,
35778 * @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.
35780 autoExpandColumn : false,
35783 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
35786 autoExpandMin : 50,
35789 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
35791 autoExpandMax : 1000,
35794 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
35799 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
35803 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
35813 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
35814 * of a fixed width. Default is false.
35817 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
35820 * Called once after all setup has been completed and the grid is ready to be rendered.
35821 * @return {Roo.grid.Grid} this
35823 render : function()
35825 var c = this.container;
35826 // try to detect autoHeight/width mode
35827 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
35828 this.autoHeight = true;
35830 var view = this.getView();
35833 c.on("click", this.onClick, this);
35834 c.on("dblclick", this.onDblClick, this);
35835 c.on("contextmenu", this.onContextMenu, this);
35836 c.on("keydown", this.onKeyDown, this);
35838 c.on("touchstart", this.onTouchStart, this);
35841 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
35843 this.getSelectionModel().init(this);
35848 this.loadMask = new Roo.LoadMask(this.container,
35849 Roo.apply({store:this.dataSource}, this.loadMask));
35853 if (this.toolbar && this.toolbar.xtype) {
35854 this.toolbar.container = this.getView().getHeaderPanel(true);
35855 this.toolbar = new Roo.Toolbar(this.toolbar);
35857 if (this.footer && this.footer.xtype) {
35858 this.footer.dataSource = this.getDataSource();
35859 this.footer.container = this.getView().getFooterPanel(true);
35860 this.footer = Roo.factory(this.footer, Roo);
35862 if (this.dropTarget && this.dropTarget.xtype) {
35863 delete this.dropTarget.xtype;
35864 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
35868 this.rendered = true;
35869 this.fireEvent('render', this);
35874 * Reconfigures the grid to use a different Store and Column Model.
35875 * The View will be bound to the new objects and refreshed.
35876 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
35877 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
35879 reconfigure : function(dataSource, colModel){
35881 this.loadMask.destroy();
35882 this.loadMask = new Roo.LoadMask(this.container,
35883 Roo.apply({store:dataSource}, this.loadMask));
35885 this.view.bind(dataSource, colModel);
35886 this.dataSource = dataSource;
35887 this.colModel = colModel;
35888 this.view.refresh(true);
35892 onKeyDown : function(e){
35893 this.fireEvent("keydown", e);
35897 * Destroy this grid.
35898 * @param {Boolean} removeEl True to remove the element
35900 destroy : function(removeEl, keepListeners){
35902 this.loadMask.destroy();
35904 var c = this.container;
35905 c.removeAllListeners();
35906 this.view.destroy();
35907 this.colModel.purgeListeners();
35908 if(!keepListeners){
35909 this.purgeListeners();
35912 if(removeEl === true){
35918 processEvent : function(name, e){
35919 // does this fire select???
35920 Roo.log('grid:processEvent ' + name);
35922 if (name != 'touchstart' ) {
35923 this.fireEvent(name, e);
35926 var t = e.getTarget();
35928 var header = v.findHeaderIndex(t);
35929 if(header !== false){
35930 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
35932 var row = v.findRowIndex(t);
35933 var cell = v.findCellIndex(t);
35934 if (name == 'touchstart') {
35935 // first touch is always a click.
35936 // hopefull this happens after selection is updated.?
35939 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
35940 var cs = this.selModel.getSelectedCell();
35941 if (row == cs[0] && cell == cs[1]){
35945 if (typeof(this.selModel.getSelections) != 'undefined') {
35946 var cs = this.selModel.getSelections();
35947 var ds = this.dataSource;
35948 if (cs.length == 1 && ds.getAt(row) == cs[0]){
35959 this.fireEvent("row" + name, this, row, e);
35960 if(cell !== false){
35961 this.fireEvent("cell" + name, this, row, cell, e);
35968 onClick : function(e){
35969 this.processEvent("click", e);
35972 onTouchStart : function(e){
35973 this.processEvent("touchstart", e);
35977 onContextMenu : function(e, t){
35978 this.processEvent("contextmenu", e);
35982 onDblClick : function(e){
35983 this.processEvent("dblclick", e);
35987 walkCells : function(row, col, step, fn, scope){
35988 var cm = this.colModel, clen = cm.getColumnCount();
35989 var ds = this.dataSource, rlen = ds.getCount(), first = true;
36001 if(fn.call(scope || this, row, col, cm) === true){
36019 if(fn.call(scope || this, row, col, cm) === true){
36031 getSelections : function(){
36032 return this.selModel.getSelections();
36036 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
36037 * but if manual update is required this method will initiate it.
36039 autoSize : function(){
36041 this.view.layout();
36042 if(this.view.adjustForScroll){
36043 this.view.adjustForScroll();
36049 * Returns the grid's underlying element.
36050 * @return {Element} The element
36052 getGridEl : function(){
36053 return this.container;
36056 // private for compatibility, overridden by editor grid
36057 stopEditing : function(){},
36060 * Returns the grid's SelectionModel.
36061 * @return {SelectionModel}
36063 getSelectionModel : function(){
36064 if(!this.selModel){
36065 this.selModel = new Roo.grid.RowSelectionModel();
36067 return this.selModel;
36071 * Returns the grid's DataSource.
36072 * @return {DataSource}
36074 getDataSource : function(){
36075 return this.dataSource;
36079 * Returns the grid's ColumnModel.
36080 * @return {ColumnModel}
36082 getColumnModel : function(){
36083 return this.colModel;
36087 * Returns the grid's GridView object.
36088 * @return {GridView}
36090 getView : function(){
36092 this.view = new Roo.grid.GridView(this.viewConfig);
36097 * Called to get grid's drag proxy text, by default returns this.ddText.
36100 getDragDropText : function(){
36101 var count = this.selModel.getCount();
36102 return String.format(this.ddText, count, count == 1 ? '' : 's');
36106 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
36107 * %0 is replaced with the number of selected rows.
36110 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
36112 * Ext JS Library 1.1.1
36113 * Copyright(c) 2006-2007, Ext JS, LLC.
36115 * Originally Released Under LGPL - original licence link has changed is not relivant.
36118 * <script type="text/javascript">
36121 Roo.grid.AbstractGridView = function(){
36125 "beforerowremoved" : true,
36126 "beforerowsinserted" : true,
36127 "beforerefresh" : true,
36128 "rowremoved" : true,
36129 "rowsinserted" : true,
36130 "rowupdated" : true,
36133 Roo.grid.AbstractGridView.superclass.constructor.call(this);
36136 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
36137 rowClass : "x-grid-row",
36138 cellClass : "x-grid-cell",
36139 tdClass : "x-grid-td",
36140 hdClass : "x-grid-hd",
36141 splitClass : "x-grid-hd-split",
36143 init: function(grid){
36145 var cid = this.grid.getGridEl().id;
36146 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
36147 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
36148 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
36149 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
36152 getColumnRenderers : function(){
36153 var renderers = [];
36154 var cm = this.grid.colModel;
36155 var colCount = cm.getColumnCount();
36156 for(var i = 0; i < colCount; i++){
36157 renderers[i] = cm.getRenderer(i);
36162 getColumnIds : function(){
36164 var cm = this.grid.colModel;
36165 var colCount = cm.getColumnCount();
36166 for(var i = 0; i < colCount; i++){
36167 ids[i] = cm.getColumnId(i);
36172 getDataIndexes : function(){
36173 if(!this.indexMap){
36174 this.indexMap = this.buildIndexMap();
36176 return this.indexMap.colToData;
36179 getColumnIndexByDataIndex : function(dataIndex){
36180 if(!this.indexMap){
36181 this.indexMap = this.buildIndexMap();
36183 return this.indexMap.dataToCol[dataIndex];
36187 * Set a css style for a column dynamically.
36188 * @param {Number} colIndex The index of the column
36189 * @param {String} name The css property name
36190 * @param {String} value The css value
36192 setCSSStyle : function(colIndex, name, value){
36193 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
36194 Roo.util.CSS.updateRule(selector, name, value);
36197 generateRules : function(cm){
36198 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
36199 Roo.util.CSS.removeStyleSheet(rulesId);
36200 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36201 var cid = cm.getColumnId(i);
36202 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
36203 this.tdSelector, cid, " {\n}\n",
36204 this.hdSelector, cid, " {\n}\n",
36205 this.splitSelector, cid, " {\n}\n");
36207 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
36211 * Ext JS Library 1.1.1
36212 * Copyright(c) 2006-2007, Ext JS, LLC.
36214 * Originally Released Under LGPL - original licence link has changed is not relivant.
36217 * <script type="text/javascript">
36221 // This is a support class used internally by the Grid components
36222 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
36224 this.view = grid.getView();
36225 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36226 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
36228 this.setHandleElId(Roo.id(hd));
36229 this.setOuterHandleElId(Roo.id(hd2));
36231 this.scroll = false;
36233 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
36235 getDragData : function(e){
36236 var t = Roo.lib.Event.getTarget(e);
36237 var h = this.view.findHeaderCell(t);
36239 return {ddel: h.firstChild, header:h};
36244 onInitDrag : function(e){
36245 this.view.headersDisabled = true;
36246 var clone = this.dragData.ddel.cloneNode(true);
36247 clone.id = Roo.id();
36248 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
36249 this.proxy.update(clone);
36253 afterValidDrop : function(){
36255 setTimeout(function(){
36256 v.headersDisabled = false;
36260 afterInvalidDrop : function(){
36262 setTimeout(function(){
36263 v.headersDisabled = false;
36269 * Ext JS Library 1.1.1
36270 * Copyright(c) 2006-2007, Ext JS, LLC.
36272 * Originally Released Under LGPL - original licence link has changed is not relivant.
36275 * <script type="text/javascript">
36278 // This is a support class used internally by the Grid components
36279 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
36281 this.view = grid.getView();
36282 // split the proxies so they don't interfere with mouse events
36283 this.proxyTop = Roo.DomHelper.append(document.body, {
36284 cls:"col-move-top", html:" "
36286 this.proxyBottom = Roo.DomHelper.append(document.body, {
36287 cls:"col-move-bottom", html:" "
36289 this.proxyTop.hide = this.proxyBottom.hide = function(){
36290 this.setLeftTop(-100,-100);
36291 this.setStyle("visibility", "hidden");
36293 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36294 // temporarily disabled
36295 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
36296 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
36298 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
36299 proxyOffsets : [-4, -9],
36300 fly: Roo.Element.fly,
36302 getTargetFromEvent : function(e){
36303 var t = Roo.lib.Event.getTarget(e);
36304 var cindex = this.view.findCellIndex(t);
36305 if(cindex !== false){
36306 return this.view.getHeaderCell(cindex);
36311 nextVisible : function(h){
36312 var v = this.view, cm = this.grid.colModel;
36315 if(!cm.isHidden(v.getCellIndex(h))){
36323 prevVisible : function(h){
36324 var v = this.view, cm = this.grid.colModel;
36327 if(!cm.isHidden(v.getCellIndex(h))){
36335 positionIndicator : function(h, n, e){
36336 var x = Roo.lib.Event.getPageX(e);
36337 var r = Roo.lib.Dom.getRegion(n.firstChild);
36338 var px, pt, py = r.top + this.proxyOffsets[1];
36339 if((r.right - x) <= (r.right-r.left)/2){
36340 px = r.right+this.view.borderWidth;
36346 var oldIndex = this.view.getCellIndex(h);
36347 var newIndex = this.view.getCellIndex(n);
36349 if(this.grid.colModel.isFixed(newIndex)){
36353 var locked = this.grid.colModel.isLocked(newIndex);
36358 if(oldIndex < newIndex){
36361 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
36364 px += this.proxyOffsets[0];
36365 this.proxyTop.setLeftTop(px, py);
36366 this.proxyTop.show();
36367 if(!this.bottomOffset){
36368 this.bottomOffset = this.view.mainHd.getHeight();
36370 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
36371 this.proxyBottom.show();
36375 onNodeEnter : function(n, dd, e, data){
36376 if(data.header != n){
36377 this.positionIndicator(data.header, n, e);
36381 onNodeOver : function(n, dd, e, data){
36382 var result = false;
36383 if(data.header != n){
36384 result = this.positionIndicator(data.header, n, e);
36387 this.proxyTop.hide();
36388 this.proxyBottom.hide();
36390 return result ? this.dropAllowed : this.dropNotAllowed;
36393 onNodeOut : function(n, dd, e, data){
36394 this.proxyTop.hide();
36395 this.proxyBottom.hide();
36398 onNodeDrop : function(n, dd, e, data){
36399 var h = data.header;
36401 var cm = this.grid.colModel;
36402 var x = Roo.lib.Event.getPageX(e);
36403 var r = Roo.lib.Dom.getRegion(n.firstChild);
36404 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
36405 var oldIndex = this.view.getCellIndex(h);
36406 var newIndex = this.view.getCellIndex(n);
36407 var locked = cm.isLocked(newIndex);
36411 if(oldIndex < newIndex){
36414 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
36417 cm.setLocked(oldIndex, locked, true);
36418 cm.moveColumn(oldIndex, newIndex);
36419 this.grid.fireEvent("columnmove", oldIndex, newIndex);
36427 * Ext JS Library 1.1.1
36428 * Copyright(c) 2006-2007, Ext JS, LLC.
36430 * Originally Released Under LGPL - original licence link has changed is not relivant.
36433 * <script type="text/javascript">
36437 * @class Roo.grid.GridView
36438 * @extends Roo.util.Observable
36441 * @param {Object} config
36443 Roo.grid.GridView = function(config){
36444 Roo.grid.GridView.superclass.constructor.call(this);
36447 Roo.apply(this, config);
36450 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
36452 unselectable : 'unselectable="on"',
36453 unselectableCls : 'x-unselectable',
36456 rowClass : "x-grid-row",
36458 cellClass : "x-grid-col",
36460 tdClass : "x-grid-td",
36462 hdClass : "x-grid-hd",
36464 splitClass : "x-grid-split",
36466 sortClasses : ["sort-asc", "sort-desc"],
36468 enableMoveAnim : false,
36472 dh : Roo.DomHelper,
36474 fly : Roo.Element.fly,
36476 css : Roo.util.CSS,
36482 scrollIncrement : 22,
36484 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
36486 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
36488 bind : function(ds, cm){
36490 this.ds.un("load", this.onLoad, this);
36491 this.ds.un("datachanged", this.onDataChange, this);
36492 this.ds.un("add", this.onAdd, this);
36493 this.ds.un("remove", this.onRemove, this);
36494 this.ds.un("update", this.onUpdate, this);
36495 this.ds.un("clear", this.onClear, this);
36498 ds.on("load", this.onLoad, this);
36499 ds.on("datachanged", this.onDataChange, this);
36500 ds.on("add", this.onAdd, this);
36501 ds.on("remove", this.onRemove, this);
36502 ds.on("update", this.onUpdate, this);
36503 ds.on("clear", this.onClear, this);
36508 this.cm.un("widthchange", this.onColWidthChange, this);
36509 this.cm.un("headerchange", this.onHeaderChange, this);
36510 this.cm.un("hiddenchange", this.onHiddenChange, this);
36511 this.cm.un("columnmoved", this.onColumnMove, this);
36512 this.cm.un("columnlockchange", this.onColumnLock, this);
36515 this.generateRules(cm);
36516 cm.on("widthchange", this.onColWidthChange, this);
36517 cm.on("headerchange", this.onHeaderChange, this);
36518 cm.on("hiddenchange", this.onHiddenChange, this);
36519 cm.on("columnmoved", this.onColumnMove, this);
36520 cm.on("columnlockchange", this.onColumnLock, this);
36525 init: function(grid){
36526 Roo.grid.GridView.superclass.init.call(this, grid);
36528 this.bind(grid.dataSource, grid.colModel);
36530 grid.on("headerclick", this.handleHeaderClick, this);
36532 if(grid.trackMouseOver){
36533 grid.on("mouseover", this.onRowOver, this);
36534 grid.on("mouseout", this.onRowOut, this);
36536 grid.cancelTextSelection = function(){};
36537 this.gridId = grid.id;
36539 var tpls = this.templates || {};
36542 tpls.master = new Roo.Template(
36543 '<div class="x-grid" hidefocus="true">',
36544 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
36545 '<div class="x-grid-topbar"></div>',
36546 '<div class="x-grid-scroller"><div></div></div>',
36547 '<div class="x-grid-locked">',
36548 '<div class="x-grid-header">{lockedHeader}</div>',
36549 '<div class="x-grid-body">{lockedBody}</div>',
36551 '<div class="x-grid-viewport">',
36552 '<div class="x-grid-header">{header}</div>',
36553 '<div class="x-grid-body">{body}</div>',
36555 '<div class="x-grid-bottombar"></div>',
36557 '<div class="x-grid-resize-proxy"> </div>',
36560 tpls.master.disableformats = true;
36564 tpls.header = new Roo.Template(
36565 '<table border="0" cellspacing="0" cellpadding="0">',
36566 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
36569 tpls.header.disableformats = true;
36571 tpls.header.compile();
36574 tpls.hcell = new Roo.Template(
36575 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
36576 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
36579 tpls.hcell.disableFormats = true;
36581 tpls.hcell.compile();
36584 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
36585 this.unselectableCls + '" ' + this.unselectable +'> </div>');
36586 tpls.hsplit.disableFormats = true;
36588 tpls.hsplit.compile();
36591 tpls.body = new Roo.Template(
36592 '<table border="0" cellspacing="0" cellpadding="0">',
36593 "<tbody>{rows}</tbody>",
36596 tpls.body.disableFormats = true;
36598 tpls.body.compile();
36601 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
36602 tpls.row.disableFormats = true;
36604 tpls.row.compile();
36607 tpls.cell = new Roo.Template(
36608 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
36609 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
36610 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
36613 tpls.cell.disableFormats = true;
36615 tpls.cell.compile();
36617 this.templates = tpls;
36620 // remap these for backwards compat
36621 onColWidthChange : function(){
36622 this.updateColumns.apply(this, arguments);
36624 onHeaderChange : function(){
36625 this.updateHeaders.apply(this, arguments);
36627 onHiddenChange : function(){
36628 this.handleHiddenChange.apply(this, arguments);
36630 onColumnMove : function(){
36631 this.handleColumnMove.apply(this, arguments);
36633 onColumnLock : function(){
36634 this.handleLockChange.apply(this, arguments);
36637 onDataChange : function(){
36639 this.updateHeaderSortState();
36642 onClear : function(){
36646 onUpdate : function(ds, record){
36647 this.refreshRow(record);
36650 refreshRow : function(record){
36651 var ds = this.ds, index;
36652 if(typeof record == 'number'){
36654 record = ds.getAt(index);
36656 index = ds.indexOf(record);
36658 this.insertRows(ds, index, index, true);
36659 this.onRemove(ds, record, index+1, true);
36660 this.syncRowHeights(index, index);
36662 this.fireEvent("rowupdated", this, index, record);
36665 onAdd : function(ds, records, index){
36666 this.insertRows(ds, index, index + (records.length-1));
36669 onRemove : function(ds, record, index, isUpdate){
36670 if(isUpdate !== true){
36671 this.fireEvent("beforerowremoved", this, index, record);
36673 var bt = this.getBodyTable(), lt = this.getLockedTable();
36674 if(bt.rows[index]){
36675 bt.firstChild.removeChild(bt.rows[index]);
36677 if(lt.rows[index]){
36678 lt.firstChild.removeChild(lt.rows[index]);
36680 if(isUpdate !== true){
36681 this.stripeRows(index);
36682 this.syncRowHeights(index, index);
36684 this.fireEvent("rowremoved", this, index, record);
36688 onLoad : function(){
36689 this.scrollToTop();
36693 * Scrolls the grid to the top
36695 scrollToTop : function(){
36697 this.scroller.dom.scrollTop = 0;
36703 * Gets a panel in the header of the grid that can be used for toolbars etc.
36704 * After modifying the contents of this panel a call to grid.autoSize() may be
36705 * required to register any changes in size.
36706 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
36707 * @return Roo.Element
36709 getHeaderPanel : function(doShow){
36711 this.headerPanel.show();
36713 return this.headerPanel;
36717 * Gets a panel in the footer of the grid that can be used for toolbars etc.
36718 * After modifying the contents of this panel a call to grid.autoSize() may be
36719 * required to register any changes in size.
36720 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
36721 * @return Roo.Element
36723 getFooterPanel : function(doShow){
36725 this.footerPanel.show();
36727 return this.footerPanel;
36730 initElements : function(){
36731 var E = Roo.Element;
36732 var el = this.grid.getGridEl().dom.firstChild;
36733 var cs = el.childNodes;
36735 this.el = new E(el);
36737 this.focusEl = new E(el.firstChild);
36738 this.focusEl.swallowEvent("click", true);
36740 this.headerPanel = new E(cs[1]);
36741 this.headerPanel.enableDisplayMode("block");
36743 this.scroller = new E(cs[2]);
36744 this.scrollSizer = new E(this.scroller.dom.firstChild);
36746 this.lockedWrap = new E(cs[3]);
36747 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
36748 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
36750 this.mainWrap = new E(cs[4]);
36751 this.mainHd = new E(this.mainWrap.dom.firstChild);
36752 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
36754 this.footerPanel = new E(cs[5]);
36755 this.footerPanel.enableDisplayMode("block");
36757 this.resizeProxy = new E(cs[6]);
36759 this.headerSelector = String.format(
36760 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
36761 this.lockedHd.id, this.mainHd.id
36764 this.splitterSelector = String.format(
36765 '#{0} div.x-grid-split, #{1} div.x-grid-split',
36766 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
36769 idToCssName : function(s)
36771 return s.replace(/[^a-z0-9]+/ig, '-');
36774 getHeaderCell : function(index){
36775 return Roo.DomQuery.select(this.headerSelector)[index];
36778 getHeaderCellMeasure : function(index){
36779 return this.getHeaderCell(index).firstChild;
36782 getHeaderCellText : function(index){
36783 return this.getHeaderCell(index).firstChild.firstChild;
36786 getLockedTable : function(){
36787 return this.lockedBody.dom.firstChild;
36790 getBodyTable : function(){
36791 return this.mainBody.dom.firstChild;
36794 getLockedRow : function(index){
36795 return this.getLockedTable().rows[index];
36798 getRow : function(index){
36799 return this.getBodyTable().rows[index];
36802 getRowComposite : function(index){
36804 this.rowEl = new Roo.CompositeElementLite();
36806 var els = [], lrow, mrow;
36807 if(lrow = this.getLockedRow(index)){
36810 if(mrow = this.getRow(index)){
36813 this.rowEl.elements = els;
36817 * Gets the 'td' of the cell
36819 * @param {Integer} rowIndex row to select
36820 * @param {Integer} colIndex column to select
36824 getCell : function(rowIndex, colIndex){
36825 var locked = this.cm.getLockedCount();
36827 if(colIndex < locked){
36828 source = this.lockedBody.dom.firstChild;
36830 source = this.mainBody.dom.firstChild;
36831 colIndex -= locked;
36833 return source.rows[rowIndex].childNodes[colIndex];
36836 getCellText : function(rowIndex, colIndex){
36837 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
36840 getCellBox : function(cell){
36841 var b = this.fly(cell).getBox();
36842 if(Roo.isOpera){ // opera fails to report the Y
36843 b.y = cell.offsetTop + this.mainBody.getY();
36848 getCellIndex : function(cell){
36849 var id = String(cell.className).match(this.cellRE);
36851 return parseInt(id[1], 10);
36856 findHeaderIndex : function(n){
36857 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36858 return r ? this.getCellIndex(r) : false;
36861 findHeaderCell : function(n){
36862 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36863 return r ? r : false;
36866 findRowIndex : function(n){
36870 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
36871 return r ? r.rowIndex : false;
36874 findCellIndex : function(node){
36875 var stop = this.el.dom;
36876 while(node && node != stop){
36877 if(this.findRE.test(node.className)){
36878 return this.getCellIndex(node);
36880 node = node.parentNode;
36885 getColumnId : function(index){
36886 return this.cm.getColumnId(index);
36889 getSplitters : function()
36891 if(this.splitterSelector){
36892 return Roo.DomQuery.select(this.splitterSelector);
36898 getSplitter : function(index){
36899 return this.getSplitters()[index];
36902 onRowOver : function(e, t){
36904 if((row = this.findRowIndex(t)) !== false){
36905 this.getRowComposite(row).addClass("x-grid-row-over");
36909 onRowOut : function(e, t){
36911 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
36912 this.getRowComposite(row).removeClass("x-grid-row-over");
36916 renderHeaders : function(){
36918 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
36919 var cb = [], lb = [], sb = [], lsb = [], p = {};
36920 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36921 p.cellId = "x-grid-hd-0-" + i;
36922 p.splitId = "x-grid-csplit-0-" + i;
36923 p.id = cm.getColumnId(i);
36924 p.title = cm.getColumnTooltip(i) || "";
36925 p.value = cm.getColumnHeader(i) || "";
36926 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
36927 if(!cm.isLocked(i)){
36928 cb[cb.length] = ct.apply(p);
36929 sb[sb.length] = st.apply(p);
36931 lb[lb.length] = ct.apply(p);
36932 lsb[lsb.length] = st.apply(p);
36935 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
36936 ht.apply({cells: cb.join(""), splits:sb.join("")})];
36939 updateHeaders : function(){
36940 var html = this.renderHeaders();
36941 this.lockedHd.update(html[0]);
36942 this.mainHd.update(html[1]);
36946 * Focuses the specified row.
36947 * @param {Number} row The row index
36949 focusRow : function(row)
36951 //Roo.log('GridView.focusRow');
36952 var x = this.scroller.dom.scrollLeft;
36953 this.focusCell(row, 0, false);
36954 this.scroller.dom.scrollLeft = x;
36958 * Focuses the specified cell.
36959 * @param {Number} row The row index
36960 * @param {Number} col The column index
36961 * @param {Boolean} hscroll false to disable horizontal scrolling
36963 focusCell : function(row, col, hscroll)
36965 //Roo.log('GridView.focusCell');
36966 var el = this.ensureVisible(row, col, hscroll);
36967 this.focusEl.alignTo(el, "tl-tl");
36969 this.focusEl.focus();
36971 this.focusEl.focus.defer(1, this.focusEl);
36976 * Scrolls the specified cell into view
36977 * @param {Number} row The row index
36978 * @param {Number} col The column index
36979 * @param {Boolean} hscroll false to disable horizontal scrolling
36981 ensureVisible : function(row, col, hscroll)
36983 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
36984 //return null; //disable for testing.
36985 if(typeof row != "number"){
36986 row = row.rowIndex;
36988 if(row < 0 && row >= this.ds.getCount()){
36991 col = (col !== undefined ? col : 0);
36992 var cm = this.grid.colModel;
36993 while(cm.isHidden(col)){
36997 var el = this.getCell(row, col);
37001 var c = this.scroller.dom;
37003 var ctop = parseInt(el.offsetTop, 10);
37004 var cleft = parseInt(el.offsetLeft, 10);
37005 var cbot = ctop + el.offsetHeight;
37006 var cright = cleft + el.offsetWidth;
37008 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
37009 var stop = parseInt(c.scrollTop, 10);
37010 var sleft = parseInt(c.scrollLeft, 10);
37011 var sbot = stop + ch;
37012 var sright = sleft + c.clientWidth;
37014 Roo.log('GridView.ensureVisible:' +
37016 ' c.clientHeight:' + c.clientHeight +
37017 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
37025 c.scrollTop = ctop;
37026 //Roo.log("set scrolltop to ctop DISABLE?");
37027 }else if(cbot > sbot){
37028 //Roo.log("set scrolltop to cbot-ch");
37029 c.scrollTop = cbot-ch;
37032 if(hscroll !== false){
37034 c.scrollLeft = cleft;
37035 }else if(cright > sright){
37036 c.scrollLeft = cright-c.clientWidth;
37043 updateColumns : function(){
37044 this.grid.stopEditing();
37045 var cm = this.grid.colModel, colIds = this.getColumnIds();
37046 //var totalWidth = cm.getTotalWidth();
37048 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37049 //if(cm.isHidden(i)) continue;
37050 var w = cm.getColumnWidth(i);
37051 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37052 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37054 this.updateSplitters();
37057 generateRules : function(cm){
37058 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
37059 Roo.util.CSS.removeStyleSheet(rulesId);
37060 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37061 var cid = cm.getColumnId(i);
37063 if(cm.config[i].align){
37064 align = 'text-align:'+cm.config[i].align+';';
37067 if(cm.isHidden(i)){
37068 hidden = 'display:none;';
37070 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
37072 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
37073 this.hdSelector, cid, " {\n", align, width, "}\n",
37074 this.tdSelector, cid, " {\n",hidden,"\n}\n",
37075 this.splitSelector, cid, " {\n", hidden , "\n}\n");
37077 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
37080 updateSplitters : function(){
37081 var cm = this.cm, s = this.getSplitters();
37082 if(s){ // splitters not created yet
37083 var pos = 0, locked = true;
37084 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37085 if(cm.isHidden(i)) continue;
37086 var w = cm.getColumnWidth(i); // make sure it's a number
37087 if(!cm.isLocked(i) && locked){
37092 s[i].style.left = (pos-this.splitOffset) + "px";
37097 handleHiddenChange : function(colModel, colIndex, hidden){
37099 this.hideColumn(colIndex);
37101 this.unhideColumn(colIndex);
37105 hideColumn : function(colIndex){
37106 var cid = this.getColumnId(colIndex);
37107 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
37108 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
37110 this.updateHeaders();
37112 this.updateSplitters();
37116 unhideColumn : function(colIndex){
37117 var cid = this.getColumnId(colIndex);
37118 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
37119 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
37122 this.updateHeaders();
37124 this.updateSplitters();
37128 insertRows : function(dm, firstRow, lastRow, isUpdate){
37129 if(firstRow == 0 && lastRow == dm.getCount()-1){
37133 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
37135 var s = this.getScrollState();
37136 var markup = this.renderRows(firstRow, lastRow);
37137 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
37138 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
37139 this.restoreScroll(s);
37141 this.fireEvent("rowsinserted", this, firstRow, lastRow);
37142 this.syncRowHeights(firstRow, lastRow);
37143 this.stripeRows(firstRow);
37149 bufferRows : function(markup, target, index){
37150 var before = null, trows = target.rows, tbody = target.tBodies[0];
37151 if(index < trows.length){
37152 before = trows[index];
37154 var b = document.createElement("div");
37155 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
37156 var rows = b.firstChild.rows;
37157 for(var i = 0, len = rows.length; i < len; i++){
37159 tbody.insertBefore(rows[0], before);
37161 tbody.appendChild(rows[0]);
37168 deleteRows : function(dm, firstRow, lastRow){
37169 if(dm.getRowCount()<1){
37170 this.fireEvent("beforerefresh", this);
37171 this.mainBody.update("");
37172 this.lockedBody.update("");
37173 this.fireEvent("refresh", this);
37175 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
37176 var bt = this.getBodyTable();
37177 var tbody = bt.firstChild;
37178 var rows = bt.rows;
37179 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
37180 tbody.removeChild(rows[firstRow]);
37182 this.stripeRows(firstRow);
37183 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
37187 updateRows : function(dataSource, firstRow, lastRow){
37188 var s = this.getScrollState();
37190 this.restoreScroll(s);
37193 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
37197 this.updateHeaderSortState();
37200 getScrollState : function(){
37202 var sb = this.scroller.dom;
37203 return {left: sb.scrollLeft, top: sb.scrollTop};
37206 stripeRows : function(startRow){
37207 if(!this.grid.stripeRows || this.ds.getCount() < 1){
37210 startRow = startRow || 0;
37211 var rows = this.getBodyTable().rows;
37212 var lrows = this.getLockedTable().rows;
37213 var cls = ' x-grid-row-alt ';
37214 for(var i = startRow, len = rows.length; i < len; i++){
37215 var row = rows[i], lrow = lrows[i];
37216 var isAlt = ((i+1) % 2 == 0);
37217 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
37218 if(isAlt == hasAlt){
37222 row.className += " x-grid-row-alt";
37224 row.className = row.className.replace("x-grid-row-alt", "");
37227 lrow.className = row.className;
37232 restoreScroll : function(state){
37233 //Roo.log('GridView.restoreScroll');
37234 var sb = this.scroller.dom;
37235 sb.scrollLeft = state.left;
37236 sb.scrollTop = state.top;
37240 syncScroll : function(){
37241 //Roo.log('GridView.syncScroll');
37242 var sb = this.scroller.dom;
37243 var sh = this.mainHd.dom;
37244 var bs = this.mainBody.dom;
37245 var lv = this.lockedBody.dom;
37246 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
37247 lv.scrollTop = bs.scrollTop = sb.scrollTop;
37250 handleScroll : function(e){
37252 var sb = this.scroller.dom;
37253 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
37257 handleWheel : function(e){
37258 var d = e.getWheelDelta();
37259 this.scroller.dom.scrollTop -= d*22;
37260 // set this here to prevent jumpy scrolling on large tables
37261 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
37265 renderRows : function(startRow, endRow){
37266 // pull in all the crap needed to render rows
37267 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
37268 var colCount = cm.getColumnCount();
37270 if(ds.getCount() < 1){
37274 // build a map for all the columns
37276 for(var i = 0; i < colCount; i++){
37277 var name = cm.getDataIndex(i);
37279 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
37280 renderer : cm.getRenderer(i),
37281 id : cm.getColumnId(i),
37282 locked : cm.isLocked(i)
37286 startRow = startRow || 0;
37287 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
37289 // records to render
37290 var rs = ds.getRange(startRow, endRow);
37292 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
37295 // As much as I hate to duplicate code, this was branched because FireFox really hates
37296 // [].join("") on strings. The performance difference was substantial enough to
37297 // branch this function
37298 doRender : Roo.isGecko ?
37299 function(cs, rs, ds, startRow, colCount, stripe){
37300 var ts = this.templates, ct = ts.cell, rt = ts.row;
37302 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37304 var hasListener = this.grid.hasListener('rowclass');
37306 for(var j = 0, len = rs.length; j < len; j++){
37307 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
37308 for(var i = 0; i < colCount; i++){
37310 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37312 p.css = p.attr = "";
37313 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37314 if(p.value == undefined || p.value === "") p.value = " ";
37315 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37316 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37318 var markup = ct.apply(p);
37326 if(stripe && ((rowIndex+1) % 2 == 0)){
37327 alt.push("x-grid-row-alt")
37330 alt.push( " x-grid-dirty-row");
37333 if(this.getRowClass){
37334 alt.push(this.getRowClass(r, rowIndex));
37340 rowIndex : rowIndex,
37343 this.grid.fireEvent('rowclass', this, rowcfg);
37344 alt.push(rowcfg.rowClass);
37346 rp.alt = alt.join(" ");
37347 lbuf+= rt.apply(rp);
37349 buf+= rt.apply(rp);
37351 return [lbuf, buf];
37353 function(cs, rs, ds, startRow, colCount, stripe){
37354 var ts = this.templates, ct = ts.cell, rt = ts.row;
37356 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37357 var hasListener = this.grid.hasListener('rowclass');
37360 for(var j = 0, len = rs.length; j < len; j++){
37361 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
37362 for(var i = 0; i < colCount; i++){
37364 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37366 p.css = p.attr = "";
37367 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37368 if(p.value == undefined || p.value === "") p.value = " ";
37369 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37370 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37373 var markup = ct.apply(p);
37375 cb[cb.length] = markup;
37377 lcb[lcb.length] = markup;
37381 if(stripe && ((rowIndex+1) % 2 == 0)){
37382 alt.push( "x-grid-row-alt");
37385 alt.push(" x-grid-dirty-row");
37388 if(this.getRowClass){
37389 alt.push( this.getRowClass(r, rowIndex));
37395 rowIndex : rowIndex,
37398 this.grid.fireEvent('rowclass', this, rowcfg);
37399 alt.push(rowcfg.rowClass);
37401 rp.alt = alt.join(" ");
37402 rp.cells = lcb.join("");
37403 lbuf[lbuf.length] = rt.apply(rp);
37404 rp.cells = cb.join("");
37405 buf[buf.length] = rt.apply(rp);
37407 return [lbuf.join(""), buf.join("")];
37410 renderBody : function(){
37411 var markup = this.renderRows();
37412 var bt = this.templates.body;
37413 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
37417 * Refreshes the grid
37418 * @param {Boolean} headersToo
37420 refresh : function(headersToo){
37421 this.fireEvent("beforerefresh", this);
37422 this.grid.stopEditing();
37423 var result = this.renderBody();
37424 this.lockedBody.update(result[0]);
37425 this.mainBody.update(result[1]);
37426 if(headersToo === true){
37427 this.updateHeaders();
37428 this.updateColumns();
37429 this.updateSplitters();
37430 this.updateHeaderSortState();
37432 this.syncRowHeights();
37434 this.fireEvent("refresh", this);
37437 handleColumnMove : function(cm, oldIndex, newIndex){
37438 this.indexMap = null;
37439 var s = this.getScrollState();
37440 this.refresh(true);
37441 this.restoreScroll(s);
37442 this.afterMove(newIndex);
37445 afterMove : function(colIndex){
37446 if(this.enableMoveAnim && Roo.enableFx){
37447 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
37449 // if multisort - fix sortOrder, and reload..
37450 if (this.grid.dataSource.multiSort) {
37451 // the we can call sort again..
37452 var dm = this.grid.dataSource;
37453 var cm = this.grid.colModel;
37455 for(var i = 0; i < cm.config.length; i++ ) {
37457 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
37458 continue; // dont' bother, it's not in sort list or being set.
37461 so.push(cm.config[i].dataIndex);
37464 dm.load(dm.lastOptions);
37471 updateCell : function(dm, rowIndex, dataIndex){
37472 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
37473 if(typeof colIndex == "undefined"){ // not present in grid
37476 var cm = this.grid.colModel;
37477 var cell = this.getCell(rowIndex, colIndex);
37478 var cellText = this.getCellText(rowIndex, colIndex);
37481 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
37482 id : cm.getColumnId(colIndex),
37483 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
37485 var renderer = cm.getRenderer(colIndex);
37486 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
37487 if(typeof val == "undefined" || val === "") val = " ";
37488 cellText.innerHTML = val;
37489 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
37490 this.syncRowHeights(rowIndex, rowIndex);
37493 calcColumnWidth : function(colIndex, maxRowsToMeasure){
37495 if(this.grid.autoSizeHeaders){
37496 var h = this.getHeaderCellMeasure(colIndex);
37497 maxWidth = Math.max(maxWidth, h.scrollWidth);
37500 if(this.cm.isLocked(colIndex)){
37501 tb = this.getLockedTable();
37504 tb = this.getBodyTable();
37505 index = colIndex - this.cm.getLockedCount();
37508 var rows = tb.rows;
37509 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
37510 for(var i = 0; i < stopIndex; i++){
37511 var cell = rows[i].childNodes[index].firstChild;
37512 maxWidth = Math.max(maxWidth, cell.scrollWidth);
37515 return maxWidth + /*margin for error in IE*/ 5;
37518 * Autofit a column to its content.
37519 * @param {Number} colIndex
37520 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
37522 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
37523 if(this.cm.isHidden(colIndex)){
37524 return; // can't calc a hidden column
37527 var cid = this.cm.getColumnId(colIndex);
37528 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
37529 if(this.grid.autoSizeHeaders){
37530 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
37533 var newWidth = this.calcColumnWidth(colIndex);
37534 this.cm.setColumnWidth(colIndex,
37535 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
37536 if(!suppressEvent){
37537 this.grid.fireEvent("columnresize", colIndex, newWidth);
37542 * Autofits all columns to their content and then expands to fit any extra space in the grid
37544 autoSizeColumns : function(){
37545 var cm = this.grid.colModel;
37546 var colCount = cm.getColumnCount();
37547 for(var i = 0; i < colCount; i++){
37548 this.autoSizeColumn(i, true, true);
37550 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
37553 this.updateColumns();
37559 * Autofits all columns to the grid's width proportionate with their current size
37560 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
37562 fitColumns : function(reserveScrollSpace){
37563 var cm = this.grid.colModel;
37564 var colCount = cm.getColumnCount();
37568 for (i = 0; i < colCount; i++){
37569 if(!cm.isHidden(i) && !cm.isFixed(i)){
37570 w = cm.getColumnWidth(i);
37576 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
37577 if(reserveScrollSpace){
37580 var frac = (avail - cm.getTotalWidth())/width;
37581 while (cols.length){
37584 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
37586 this.updateColumns();
37590 onRowSelect : function(rowIndex){
37591 var row = this.getRowComposite(rowIndex);
37592 row.addClass("x-grid-row-selected");
37595 onRowDeselect : function(rowIndex){
37596 var row = this.getRowComposite(rowIndex);
37597 row.removeClass("x-grid-row-selected");
37600 onCellSelect : function(row, col){
37601 var cell = this.getCell(row, col);
37603 Roo.fly(cell).addClass("x-grid-cell-selected");
37607 onCellDeselect : function(row, col){
37608 var cell = this.getCell(row, col);
37610 Roo.fly(cell).removeClass("x-grid-cell-selected");
37614 updateHeaderSortState : function(){
37616 // sort state can be single { field: xxx, direction : yyy}
37617 // or { xxx=>ASC , yyy : DESC ..... }
37620 if (!this.ds.multiSort) {
37621 var state = this.ds.getSortState();
37625 mstate[state.field] = state.direction;
37626 // FIXME... - this is not used here.. but might be elsewhere..
37627 this.sortState = state;
37630 mstate = this.ds.sortToggle;
37632 //remove existing sort classes..
37634 var sc = this.sortClasses;
37635 var hds = this.el.select(this.headerSelector).removeClass(sc);
37637 for(var f in mstate) {
37639 var sortColumn = this.cm.findColumnIndex(f);
37641 if(sortColumn != -1){
37642 var sortDir = mstate[f];
37643 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
37652 handleHeaderClick : function(g, index){
37653 if(this.headersDisabled){
37656 var dm = g.dataSource, cm = g.colModel;
37657 if(!cm.isSortable(index)){
37662 if (dm.multiSort) {
37663 // update the sortOrder
37665 for(var i = 0; i < cm.config.length; i++ ) {
37667 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
37668 continue; // dont' bother, it's not in sort list or being set.
37671 so.push(cm.config[i].dataIndex);
37677 dm.sort(cm.getDataIndex(index));
37681 destroy : function(){
37683 this.colMenu.removeAll();
37684 Roo.menu.MenuMgr.unregister(this.colMenu);
37685 this.colMenu.getEl().remove();
37686 delete this.colMenu;
37689 this.hmenu.removeAll();
37690 Roo.menu.MenuMgr.unregister(this.hmenu);
37691 this.hmenu.getEl().remove();
37694 if(this.grid.enableColumnMove){
37695 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37697 for(var dd in dds){
37698 if(!dds[dd].config.isTarget && dds[dd].dragElId){
37699 var elid = dds[dd].dragElId;
37701 Roo.get(elid).remove();
37702 } else if(dds[dd].config.isTarget){
37703 dds[dd].proxyTop.remove();
37704 dds[dd].proxyBottom.remove();
37707 if(Roo.dd.DDM.locationCache[dd]){
37708 delete Roo.dd.DDM.locationCache[dd];
37711 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37714 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
37715 this.bind(null, null);
37716 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
37719 handleLockChange : function(){
37720 this.refresh(true);
37723 onDenyColumnLock : function(){
37727 onDenyColumnHide : function(){
37731 handleHdMenuClick : function(item){
37732 var index = this.hdCtxIndex;
37733 var cm = this.cm, ds = this.ds;
37736 ds.sort(cm.getDataIndex(index), "ASC");
37739 ds.sort(cm.getDataIndex(index), "DESC");
37742 var lc = cm.getLockedCount();
37743 if(cm.getColumnCount(true) <= lc+1){
37744 this.onDenyColumnLock();
37748 cm.setLocked(index, true, true);
37749 cm.moveColumn(index, lc);
37750 this.grid.fireEvent("columnmove", index, lc);
37752 cm.setLocked(index, true);
37756 var lc = cm.getLockedCount();
37757 if((lc-1) != index){
37758 cm.setLocked(index, false, true);
37759 cm.moveColumn(index, lc-1);
37760 this.grid.fireEvent("columnmove", index, lc-1);
37762 cm.setLocked(index, false);
37766 index = cm.getIndexById(item.id.substr(4));
37768 if(item.checked && cm.getColumnCount(true) <= 1){
37769 this.onDenyColumnHide();
37772 cm.setHidden(index, item.checked);
37778 beforeColMenuShow : function(){
37779 var cm = this.cm, colCount = cm.getColumnCount();
37780 this.colMenu.removeAll();
37781 for(var i = 0; i < colCount; i++){
37782 this.colMenu.add(new Roo.menu.CheckItem({
37783 id: "col-"+cm.getColumnId(i),
37784 text: cm.getColumnHeader(i),
37785 checked: !cm.isHidden(i),
37791 handleHdCtx : function(g, index, e){
37793 var hd = this.getHeaderCell(index);
37794 this.hdCtxIndex = index;
37795 var ms = this.hmenu.items, cm = this.cm;
37796 ms.get("asc").setDisabled(!cm.isSortable(index));
37797 ms.get("desc").setDisabled(!cm.isSortable(index));
37798 if(this.grid.enableColLock !== false){
37799 ms.get("lock").setDisabled(cm.isLocked(index));
37800 ms.get("unlock").setDisabled(!cm.isLocked(index));
37802 this.hmenu.show(hd, "tl-bl");
37805 handleHdOver : function(e){
37806 var hd = this.findHeaderCell(e.getTarget());
37807 if(hd && !this.headersDisabled){
37808 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
37809 this.fly(hd).addClass("x-grid-hd-over");
37814 handleHdOut : function(e){
37815 var hd = this.findHeaderCell(e.getTarget());
37817 this.fly(hd).removeClass("x-grid-hd-over");
37821 handleSplitDblClick : function(e, t){
37822 var i = this.getCellIndex(t);
37823 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
37824 this.autoSizeColumn(i, true);
37829 render : function(){
37832 var colCount = cm.getColumnCount();
37834 if(this.grid.monitorWindowResize === true){
37835 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37837 var header = this.renderHeaders();
37838 var body = this.templates.body.apply({rows:""});
37839 var html = this.templates.master.apply({
37842 lockedHeader: header[0],
37846 //this.updateColumns();
37848 this.grid.getGridEl().dom.innerHTML = html;
37850 this.initElements();
37852 // a kludge to fix the random scolling effect in webkit
37853 this.el.on("scroll", function() {
37854 this.el.dom.scrollTop=0; // hopefully not recursive..
37857 this.scroller.on("scroll", this.handleScroll, this);
37858 this.lockedBody.on("mousewheel", this.handleWheel, this);
37859 this.mainBody.on("mousewheel", this.handleWheel, this);
37861 this.mainHd.on("mouseover", this.handleHdOver, this);
37862 this.mainHd.on("mouseout", this.handleHdOut, this);
37863 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
37864 {delegate: "."+this.splitClass});
37866 this.lockedHd.on("mouseover", this.handleHdOver, this);
37867 this.lockedHd.on("mouseout", this.handleHdOut, this);
37868 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
37869 {delegate: "."+this.splitClass});
37871 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
37872 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37875 this.updateSplitters();
37877 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
37878 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37879 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37882 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
37883 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
37885 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
37886 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
37888 if(this.grid.enableColLock !== false){
37889 this.hmenu.add('-',
37890 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
37891 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
37894 if(this.grid.enableColumnHide !== false){
37896 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
37897 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
37898 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
37900 this.hmenu.add('-',
37901 {id:"columns", text: this.columnsText, menu: this.colMenu}
37904 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
37906 this.grid.on("headercontextmenu", this.handleHdCtx, this);
37909 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
37910 this.dd = new Roo.grid.GridDragZone(this.grid, {
37911 ddGroup : this.grid.ddGroup || 'GridDD'
37917 for(var i = 0; i < colCount; i++){
37918 if(cm.isHidden(i)){
37919 this.hideColumn(i);
37921 if(cm.config[i].align){
37922 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
37923 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
37927 this.updateHeaderSortState();
37929 this.beforeInitialResize();
37932 // two part rendering gives faster view to the user
37933 this.renderPhase2.defer(1, this);
37936 renderPhase2 : function(){
37937 // render the rows now
37939 if(this.grid.autoSizeColumns){
37940 this.autoSizeColumns();
37944 beforeInitialResize : function(){
37948 onColumnSplitterMoved : function(i, w){
37949 this.userResized = true;
37950 var cm = this.grid.colModel;
37951 cm.setColumnWidth(i, w, true);
37952 var cid = cm.getColumnId(i);
37953 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37954 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37955 this.updateSplitters();
37957 this.grid.fireEvent("columnresize", i, w);
37960 syncRowHeights : function(startIndex, endIndex){
37961 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
37962 startIndex = startIndex || 0;
37963 var mrows = this.getBodyTable().rows;
37964 var lrows = this.getLockedTable().rows;
37965 var len = mrows.length-1;
37966 endIndex = Math.min(endIndex || len, len);
37967 for(var i = startIndex; i <= endIndex; i++){
37968 var m = mrows[i], l = lrows[i];
37969 var h = Math.max(m.offsetHeight, l.offsetHeight);
37970 m.style.height = l.style.height = h + "px";
37975 layout : function(initialRender, is2ndPass){
37977 var auto = g.autoHeight;
37978 var scrollOffset = 16;
37979 var c = g.getGridEl(), cm = this.cm,
37980 expandCol = g.autoExpandColumn,
37982 //c.beginMeasure();
37984 if(!c.dom.offsetWidth){ // display:none?
37986 this.lockedWrap.show();
37987 this.mainWrap.show();
37992 var hasLock = this.cm.isLocked(0);
37994 var tbh = this.headerPanel.getHeight();
37995 var bbh = this.footerPanel.getHeight();
37998 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
37999 var newHeight = ch + c.getBorderWidth("tb");
38001 newHeight = Math.min(g.maxHeight, newHeight);
38003 c.setHeight(newHeight);
38007 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
38010 var s = this.scroller;
38012 var csize = c.getSize(true);
38014 this.el.setSize(csize.width, csize.height);
38016 this.headerPanel.setWidth(csize.width);
38017 this.footerPanel.setWidth(csize.width);
38019 var hdHeight = this.mainHd.getHeight();
38020 var vw = csize.width;
38021 var vh = csize.height - (tbh + bbh);
38025 var bt = this.getBodyTable();
38026 var ltWidth = hasLock ?
38027 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
38029 var scrollHeight = bt.offsetHeight;
38030 var scrollWidth = ltWidth + bt.offsetWidth;
38031 var vscroll = false, hscroll = false;
38033 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
38035 var lw = this.lockedWrap, mw = this.mainWrap;
38036 var lb = this.lockedBody, mb = this.mainBody;
38038 setTimeout(function(){
38039 var t = s.dom.offsetTop;
38040 var w = s.dom.clientWidth,
38041 h = s.dom.clientHeight;
38044 lw.setSize(ltWidth, h);
38046 mw.setLeftTop(ltWidth, t);
38047 mw.setSize(w-ltWidth, h);
38049 lb.setHeight(h-hdHeight);
38050 mb.setHeight(h-hdHeight);
38052 if(is2ndPass !== true && !gv.userResized && expandCol){
38053 // high speed resize without full column calculation
38055 var ci = cm.getIndexById(expandCol);
38057 ci = cm.findColumnIndex(expandCol);
38059 ci = Math.max(0, ci); // make sure it's got at least the first col.
38060 var expandId = cm.getColumnId(ci);
38061 var tw = cm.getTotalWidth(false);
38062 var currentWidth = cm.getColumnWidth(ci);
38063 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
38064 if(currentWidth != cw){
38065 cm.setColumnWidth(ci, cw, true);
38066 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38067 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38068 gv.updateSplitters();
38069 gv.layout(false, true);
38081 onWindowResize : function(){
38082 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
38088 appendFooter : function(parentEl){
38092 sortAscText : "Sort Ascending",
38093 sortDescText : "Sort Descending",
38094 lockText : "Lock Column",
38095 unlockText : "Unlock Column",
38096 columnsText : "Columns"
38100 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
38101 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
38102 this.proxy.el.addClass('x-grid3-col-dd');
38105 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
38106 handleMouseDown : function(e){
38110 callHandleMouseDown : function(e){
38111 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
38116 * Ext JS Library 1.1.1
38117 * Copyright(c) 2006-2007, Ext JS, LLC.
38119 * Originally Released Under LGPL - original licence link has changed is not relivant.
38122 * <script type="text/javascript">
38126 // This is a support class used internally by the Grid components
38127 Roo.grid.SplitDragZone = function(grid, hd, hd2){
38129 this.view = grid.getView();
38130 this.proxy = this.view.resizeProxy;
38131 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
38132 "gridSplitters" + this.grid.getGridEl().id, {
38133 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
38135 this.setHandleElId(Roo.id(hd));
38136 this.setOuterHandleElId(Roo.id(hd2));
38137 this.scroll = false;
38139 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
38140 fly: Roo.Element.fly,
38142 b4StartDrag : function(x, y){
38143 this.view.headersDisabled = true;
38144 this.proxy.setHeight(this.view.mainWrap.getHeight());
38145 var w = this.cm.getColumnWidth(this.cellIndex);
38146 var minw = Math.max(w-this.grid.minColumnWidth, 0);
38147 this.resetConstraints();
38148 this.setXConstraint(minw, 1000);
38149 this.setYConstraint(0, 0);
38150 this.minX = x - minw;
38151 this.maxX = x + 1000;
38153 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
38157 handleMouseDown : function(e){
38158 ev = Roo.EventObject.setEvent(e);
38159 var t = this.fly(ev.getTarget());
38160 if(t.hasClass("x-grid-split")){
38161 this.cellIndex = this.view.getCellIndex(t.dom);
38162 this.split = t.dom;
38163 this.cm = this.grid.colModel;
38164 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
38165 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
38170 endDrag : function(e){
38171 this.view.headersDisabled = false;
38172 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
38173 var diff = endX - this.startPos;
38174 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
38177 autoOffset : function(){
38178 this.setDelta(0,0);
38182 * Ext JS Library 1.1.1
38183 * Copyright(c) 2006-2007, Ext JS, LLC.
38185 * Originally Released Under LGPL - original licence link has changed is not relivant.
38188 * <script type="text/javascript">
38192 // This is a support class used internally by the Grid components
38193 Roo.grid.GridDragZone = function(grid, config){
38194 this.view = grid.getView();
38195 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
38196 if(this.view.lockedBody){
38197 this.setHandleElId(Roo.id(this.view.mainBody.dom));
38198 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
38200 this.scroll = false;
38202 this.ddel = document.createElement('div');
38203 this.ddel.className = 'x-grid-dd-wrap';
38206 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
38207 ddGroup : "GridDD",
38209 getDragData : function(e){
38210 var t = Roo.lib.Event.getTarget(e);
38211 var rowIndex = this.view.findRowIndex(t);
38212 var sm = this.grid.selModel;
38214 //Roo.log(rowIndex);
38216 if (sm.getSelectedCell) {
38217 // cell selection..
38218 if (!sm.getSelectedCell()) {
38221 if (rowIndex != sm.getSelectedCell()[0]) {
38227 if(rowIndex !== false){
38232 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
38234 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
38237 if (e.hasModifier()){
38238 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
38241 Roo.log("getDragData");
38246 rowIndex: rowIndex,
38247 selections:sm.getSelections ? sm.getSelections() : (
38248 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
38255 onInitDrag : function(e){
38256 var data = this.dragData;
38257 this.ddel.innerHTML = this.grid.getDragDropText();
38258 this.proxy.update(this.ddel);
38259 // fire start drag?
38262 afterRepair : function(){
38263 this.dragging = false;
38266 getRepairXY : function(e, data){
38270 onEndDrag : function(data, e){
38274 onValidDrop : function(dd, e, id){
38279 beforeInvalidDrop : function(e, id){
38284 * Ext JS Library 1.1.1
38285 * Copyright(c) 2006-2007, Ext JS, LLC.
38287 * Originally Released Under LGPL - original licence link has changed is not relivant.
38290 * <script type="text/javascript">
38295 * @class Roo.grid.ColumnModel
38296 * @extends Roo.util.Observable
38297 * This is the default implementation of a ColumnModel used by the Grid. It defines
38298 * the columns in the grid.
38301 var colModel = new Roo.grid.ColumnModel([
38302 {header: "Ticker", width: 60, sortable: true, locked: true},
38303 {header: "Company Name", width: 150, sortable: true},
38304 {header: "Market Cap.", width: 100, sortable: true},
38305 {header: "$ Sales", width: 100, sortable: true, renderer: money},
38306 {header: "Employees", width: 100, sortable: true, resizable: false}
38311 * The config options listed for this class are options which may appear in each
38312 * individual column definition.
38313 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
38315 * @param {Object} config An Array of column config objects. See this class's
38316 * config objects for details.
38318 Roo.grid.ColumnModel = function(config){
38320 * The config passed into the constructor
38322 this.config = config;
38325 // if no id, create one
38326 // if the column does not have a dataIndex mapping,
38327 // map it to the order it is in the config
38328 for(var i = 0, len = config.length; i < len; i++){
38330 if(typeof c.dataIndex == "undefined"){
38333 if(typeof c.renderer == "string"){
38334 c.renderer = Roo.util.Format[c.renderer];
38336 if(typeof c.id == "undefined"){
38339 if(c.editor && c.editor.xtype){
38340 c.editor = Roo.factory(c.editor, Roo.grid);
38342 if(c.editor && c.editor.isFormField){
38343 c.editor = new Roo.grid.GridEditor(c.editor);
38345 this.lookup[c.id] = c;
38349 * The width of columns which have no width specified (defaults to 100)
38352 this.defaultWidth = 100;
38355 * Default sortable of columns which have no sortable specified (defaults to false)
38358 this.defaultSortable = false;
38362 * @event widthchange
38363 * Fires when the width of a column changes.
38364 * @param {ColumnModel} this
38365 * @param {Number} columnIndex The column index
38366 * @param {Number} newWidth The new width
38368 "widthchange": true,
38370 * @event headerchange
38371 * Fires when the text of a header changes.
38372 * @param {ColumnModel} this
38373 * @param {Number} columnIndex The column index
38374 * @param {Number} newText The new header text
38376 "headerchange": true,
38378 * @event hiddenchange
38379 * Fires when a column is hidden or "unhidden".
38380 * @param {ColumnModel} this
38381 * @param {Number} columnIndex The column index
38382 * @param {Boolean} hidden true if hidden, false otherwise
38384 "hiddenchange": true,
38386 * @event columnmoved
38387 * Fires when a column is moved.
38388 * @param {ColumnModel} this
38389 * @param {Number} oldIndex
38390 * @param {Number} newIndex
38392 "columnmoved" : true,
38394 * @event columlockchange
38395 * Fires when a column's locked state is changed
38396 * @param {ColumnModel} this
38397 * @param {Number} colIndex
38398 * @param {Boolean} locked true if locked
38400 "columnlockchange" : true
38402 Roo.grid.ColumnModel.superclass.constructor.call(this);
38404 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
38406 * @cfg {String} header The header text to display in the Grid view.
38409 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
38410 * {@link Roo.data.Record} definition from which to draw the column's value. If not
38411 * specified, the column's index is used as an index into the Record's data Array.
38414 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
38415 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
38418 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
38419 * Defaults to the value of the {@link #defaultSortable} property.
38420 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
38423 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
38426 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
38429 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
38432 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
38435 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
38436 * given the cell's data value. See {@link #setRenderer}. If not specified, the
38437 * default renderer uses the raw data value.
38440 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
38443 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
38447 * Returns the id of the column at the specified index.
38448 * @param {Number} index The column index
38449 * @return {String} the id
38451 getColumnId : function(index){
38452 return this.config[index].id;
38456 * Returns the column for a specified id.
38457 * @param {String} id The column id
38458 * @return {Object} the column
38460 getColumnById : function(id){
38461 return this.lookup[id];
38466 * Returns the column for a specified dataIndex.
38467 * @param {String} dataIndex The column dataIndex
38468 * @return {Object|Boolean} the column or false if not found
38470 getColumnByDataIndex: function(dataIndex){
38471 var index = this.findColumnIndex(dataIndex);
38472 return index > -1 ? this.config[index] : false;
38476 * Returns the index for a specified column id.
38477 * @param {String} id The column id
38478 * @return {Number} the index, or -1 if not found
38480 getIndexById : function(id){
38481 for(var i = 0, len = this.config.length; i < len; i++){
38482 if(this.config[i].id == id){
38490 * Returns the index for a specified column dataIndex.
38491 * @param {String} dataIndex The column dataIndex
38492 * @return {Number} the index, or -1 if not found
38495 findColumnIndex : function(dataIndex){
38496 for(var i = 0, len = this.config.length; i < len; i++){
38497 if(this.config[i].dataIndex == dataIndex){
38505 moveColumn : function(oldIndex, newIndex){
38506 var c = this.config[oldIndex];
38507 this.config.splice(oldIndex, 1);
38508 this.config.splice(newIndex, 0, c);
38509 this.dataMap = null;
38510 this.fireEvent("columnmoved", this, oldIndex, newIndex);
38513 isLocked : function(colIndex){
38514 return this.config[colIndex].locked === true;
38517 setLocked : function(colIndex, value, suppressEvent){
38518 if(this.isLocked(colIndex) == value){
38521 this.config[colIndex].locked = value;
38522 if(!suppressEvent){
38523 this.fireEvent("columnlockchange", this, colIndex, value);
38527 getTotalLockedWidth : function(){
38528 var totalWidth = 0;
38529 for(var i = 0; i < this.config.length; i++){
38530 if(this.isLocked(i) && !this.isHidden(i)){
38531 this.totalWidth += this.getColumnWidth(i);
38537 getLockedCount : function(){
38538 for(var i = 0, len = this.config.length; i < len; i++){
38539 if(!this.isLocked(i)){
38546 * Returns the number of columns.
38549 getColumnCount : function(visibleOnly){
38550 if(visibleOnly === true){
38552 for(var i = 0, len = this.config.length; i < len; i++){
38553 if(!this.isHidden(i)){
38559 return this.config.length;
38563 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
38564 * @param {Function} fn
38565 * @param {Object} scope (optional)
38566 * @return {Array} result
38568 getColumnsBy : function(fn, scope){
38570 for(var i = 0, len = this.config.length; i < len; i++){
38571 var c = this.config[i];
38572 if(fn.call(scope||this, c, i) === true){
38580 * Returns true if the specified column is sortable.
38581 * @param {Number} col The column index
38582 * @return {Boolean}
38584 isSortable : function(col){
38585 if(typeof this.config[col].sortable == "undefined"){
38586 return this.defaultSortable;
38588 return this.config[col].sortable;
38592 * Returns the rendering (formatting) function defined for the column.
38593 * @param {Number} col The column index.
38594 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
38596 getRenderer : function(col){
38597 if(!this.config[col].renderer){
38598 return Roo.grid.ColumnModel.defaultRenderer;
38600 return this.config[col].renderer;
38604 * Sets the rendering (formatting) function for a column.
38605 * @param {Number} col The column index
38606 * @param {Function} fn The function to use to process the cell's raw data
38607 * to return HTML markup for the grid view. The render function is called with
38608 * the following parameters:<ul>
38609 * <li>Data value.</li>
38610 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
38611 * <li>css A CSS style string to apply to the table cell.</li>
38612 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
38613 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
38614 * <li>Row index</li>
38615 * <li>Column index</li>
38616 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
38618 setRenderer : function(col, fn){
38619 this.config[col].renderer = fn;
38623 * Returns the width for the specified column.
38624 * @param {Number} col The column index
38627 getColumnWidth : function(col){
38628 return this.config[col].width * 1 || this.defaultWidth;
38632 * Sets the width for a column.
38633 * @param {Number} col The column index
38634 * @param {Number} width The new width
38636 setColumnWidth : function(col, width, suppressEvent){
38637 this.config[col].width = width;
38638 this.totalWidth = null;
38639 if(!suppressEvent){
38640 this.fireEvent("widthchange", this, col, width);
38645 * Returns the total width of all columns.
38646 * @param {Boolean} includeHidden True to include hidden column widths
38649 getTotalWidth : function(includeHidden){
38650 if(!this.totalWidth){
38651 this.totalWidth = 0;
38652 for(var i = 0, len = this.config.length; i < len; i++){
38653 if(includeHidden || !this.isHidden(i)){
38654 this.totalWidth += this.getColumnWidth(i);
38658 return this.totalWidth;
38662 * Returns the header for the specified column.
38663 * @param {Number} col The column index
38666 getColumnHeader : function(col){
38667 return this.config[col].header;
38671 * Sets the header for a column.
38672 * @param {Number} col The column index
38673 * @param {String} header The new header
38675 setColumnHeader : function(col, header){
38676 this.config[col].header = header;
38677 this.fireEvent("headerchange", this, col, header);
38681 * Returns the tooltip for the specified column.
38682 * @param {Number} col The column index
38685 getColumnTooltip : function(col){
38686 return this.config[col].tooltip;
38689 * Sets the tooltip for a column.
38690 * @param {Number} col The column index
38691 * @param {String} tooltip The new tooltip
38693 setColumnTooltip : function(col, tooltip){
38694 this.config[col].tooltip = tooltip;
38698 * Returns the dataIndex for the specified column.
38699 * @param {Number} col The column index
38702 getDataIndex : function(col){
38703 return this.config[col].dataIndex;
38707 * Sets the dataIndex for a column.
38708 * @param {Number} col The column index
38709 * @param {Number} dataIndex The new dataIndex
38711 setDataIndex : function(col, dataIndex){
38712 this.config[col].dataIndex = dataIndex;
38718 * Returns true if the cell is editable.
38719 * @param {Number} colIndex The column index
38720 * @param {Number} rowIndex The row index
38721 * @return {Boolean}
38723 isCellEditable : function(colIndex, rowIndex){
38724 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
38728 * Returns the editor defined for the cell/column.
38729 * return false or null to disable editing.
38730 * @param {Number} colIndex The column index
38731 * @param {Number} rowIndex The row index
38734 getCellEditor : function(colIndex, rowIndex){
38735 return this.config[colIndex].editor;
38739 * Sets if a column is editable.
38740 * @param {Number} col The column index
38741 * @param {Boolean} editable True if the column is editable
38743 setEditable : function(col, editable){
38744 this.config[col].editable = editable;
38749 * Returns true if the column is hidden.
38750 * @param {Number} colIndex The column index
38751 * @return {Boolean}
38753 isHidden : function(colIndex){
38754 return this.config[colIndex].hidden;
38759 * Returns true if the column width cannot be changed
38761 isFixed : function(colIndex){
38762 return this.config[colIndex].fixed;
38766 * Returns true if the column can be resized
38767 * @return {Boolean}
38769 isResizable : function(colIndex){
38770 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
38773 * Sets if a column is hidden.
38774 * @param {Number} colIndex The column index
38775 * @param {Boolean} hidden True if the column is hidden
38777 setHidden : function(colIndex, hidden){
38778 this.config[colIndex].hidden = hidden;
38779 this.totalWidth = null;
38780 this.fireEvent("hiddenchange", this, colIndex, hidden);
38784 * Sets the editor for a column.
38785 * @param {Number} col The column index
38786 * @param {Object} editor The editor object
38788 setEditor : function(col, editor){
38789 this.config[col].editor = editor;
38793 Roo.grid.ColumnModel.defaultRenderer = function(value){
38794 if(typeof value == "string" && value.length < 1){
38800 // Alias for backwards compatibility
38801 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
38804 * Ext JS Library 1.1.1
38805 * Copyright(c) 2006-2007, Ext JS, LLC.
38807 * Originally Released Under LGPL - original licence link has changed is not relivant.
38810 * <script type="text/javascript">
38814 * @class Roo.grid.AbstractSelectionModel
38815 * @extends Roo.util.Observable
38816 * Abstract base class for grid SelectionModels. It provides the interface that should be
38817 * implemented by descendant classes. This class should not be directly instantiated.
38820 Roo.grid.AbstractSelectionModel = function(){
38821 this.locked = false;
38822 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
38825 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
38826 /** @ignore Called by the grid automatically. Do not call directly. */
38827 init : function(grid){
38833 * Locks the selections.
38836 this.locked = true;
38840 * Unlocks the selections.
38842 unlock : function(){
38843 this.locked = false;
38847 * Returns true if the selections are locked.
38848 * @return {Boolean}
38850 isLocked : function(){
38851 return this.locked;
38855 * Ext JS Library 1.1.1
38856 * Copyright(c) 2006-2007, Ext JS, LLC.
38858 * Originally Released Under LGPL - original licence link has changed is not relivant.
38861 * <script type="text/javascript">
38864 * @extends Roo.grid.AbstractSelectionModel
38865 * @class Roo.grid.RowSelectionModel
38866 * The default SelectionModel used by {@link Roo.grid.Grid}.
38867 * It supports multiple selections and keyboard selection/navigation.
38869 * @param {Object} config
38871 Roo.grid.RowSelectionModel = function(config){
38872 Roo.apply(this, config);
38873 this.selections = new Roo.util.MixedCollection(false, function(o){
38878 this.lastActive = false;
38882 * @event selectionchange
38883 * Fires when the selection changes
38884 * @param {SelectionModel} this
38886 "selectionchange" : true,
38888 * @event afterselectionchange
38889 * Fires after the selection changes (eg. by key press or clicking)
38890 * @param {SelectionModel} this
38892 "afterselectionchange" : true,
38894 * @event beforerowselect
38895 * Fires when a row is selected being selected, return false to cancel.
38896 * @param {SelectionModel} this
38897 * @param {Number} rowIndex The selected index
38898 * @param {Boolean} keepExisting False if other selections will be cleared
38900 "beforerowselect" : true,
38903 * Fires when a row is selected.
38904 * @param {SelectionModel} this
38905 * @param {Number} rowIndex The selected index
38906 * @param {Roo.data.Record} r The record
38908 "rowselect" : true,
38910 * @event rowdeselect
38911 * Fires when a row is deselected.
38912 * @param {SelectionModel} this
38913 * @param {Number} rowIndex The selected index
38915 "rowdeselect" : true
38917 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
38918 this.locked = false;
38921 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
38923 * @cfg {Boolean} singleSelect
38924 * True to allow selection of only one row at a time (defaults to false)
38926 singleSelect : false,
38929 initEvents : function(){
38931 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
38932 this.grid.on("mousedown", this.handleMouseDown, this);
38933 }else{ // allow click to work like normal
38934 this.grid.on("rowclick", this.handleDragableRowClick, this);
38937 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
38938 "up" : function(e){
38940 this.selectPrevious(e.shiftKey);
38941 }else if(this.last !== false && this.lastActive !== false){
38942 var last = this.last;
38943 this.selectRange(this.last, this.lastActive-1);
38944 this.grid.getView().focusRow(this.lastActive);
38945 if(last !== false){
38949 this.selectFirstRow();
38951 this.fireEvent("afterselectionchange", this);
38953 "down" : function(e){
38955 this.selectNext(e.shiftKey);
38956 }else if(this.last !== false && this.lastActive !== false){
38957 var last = this.last;
38958 this.selectRange(this.last, this.lastActive+1);
38959 this.grid.getView().focusRow(this.lastActive);
38960 if(last !== false){
38964 this.selectFirstRow();
38966 this.fireEvent("afterselectionchange", this);
38971 var view = this.grid.view;
38972 view.on("refresh", this.onRefresh, this);
38973 view.on("rowupdated", this.onRowUpdated, this);
38974 view.on("rowremoved", this.onRemove, this);
38978 onRefresh : function(){
38979 var ds = this.grid.dataSource, i, v = this.grid.view;
38980 var s = this.selections;
38981 s.each(function(r){
38982 if((i = ds.indexOfId(r.id)) != -1){
38991 onRemove : function(v, index, r){
38992 this.selections.remove(r);
38996 onRowUpdated : function(v, index, r){
38997 if(this.isSelected(r)){
38998 v.onRowSelect(index);
39004 * @param {Array} records The records to select
39005 * @param {Boolean} keepExisting (optional) True to keep existing selections
39007 selectRecords : function(records, keepExisting){
39009 this.clearSelections();
39011 var ds = this.grid.dataSource;
39012 for(var i = 0, len = records.length; i < len; i++){
39013 this.selectRow(ds.indexOf(records[i]), true);
39018 * Gets the number of selected rows.
39021 getCount : function(){
39022 return this.selections.length;
39026 * Selects the first row in the grid.
39028 selectFirstRow : function(){
39033 * Select the last row.
39034 * @param {Boolean} keepExisting (optional) True to keep existing selections
39036 selectLastRow : function(keepExisting){
39037 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
39041 * Selects the row immediately following the last selected row.
39042 * @param {Boolean} keepExisting (optional) True to keep existing selections
39044 selectNext : function(keepExisting){
39045 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
39046 this.selectRow(this.last+1, keepExisting);
39047 this.grid.getView().focusRow(this.last);
39052 * Selects the row that precedes the last selected row.
39053 * @param {Boolean} keepExisting (optional) True to keep existing selections
39055 selectPrevious : function(keepExisting){
39057 this.selectRow(this.last-1, keepExisting);
39058 this.grid.getView().focusRow(this.last);
39063 * Returns the selected records
39064 * @return {Array} Array of selected records
39066 getSelections : function(){
39067 return [].concat(this.selections.items);
39071 * Returns the first selected record.
39074 getSelected : function(){
39075 return this.selections.itemAt(0);
39080 * Clears all selections.
39082 clearSelections : function(fast){
39083 if(this.locked) return;
39085 var ds = this.grid.dataSource;
39086 var s = this.selections;
39087 s.each(function(r){
39088 this.deselectRow(ds.indexOfId(r.id));
39092 this.selections.clear();
39099 * Selects all rows.
39101 selectAll : function(){
39102 if(this.locked) return;
39103 this.selections.clear();
39104 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
39105 this.selectRow(i, true);
39110 * Returns True if there is a selection.
39111 * @return {Boolean}
39113 hasSelection : function(){
39114 return this.selections.length > 0;
39118 * Returns True if the specified row is selected.
39119 * @param {Number/Record} record The record or index of the record to check
39120 * @return {Boolean}
39122 isSelected : function(index){
39123 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
39124 return (r && this.selections.key(r.id) ? true : false);
39128 * Returns True if the specified record id is selected.
39129 * @param {String} id The id of record to check
39130 * @return {Boolean}
39132 isIdSelected : function(id){
39133 return (this.selections.key(id) ? true : false);
39137 handleMouseDown : function(e, t){
39138 var view = this.grid.getView(), rowIndex;
39139 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
39142 if(e.shiftKey && this.last !== false){
39143 var last = this.last;
39144 this.selectRange(last, rowIndex, e.ctrlKey);
39145 this.last = last; // reset the last
39146 view.focusRow(rowIndex);
39148 var isSelected = this.isSelected(rowIndex);
39149 if(e.button !== 0 && isSelected){
39150 view.focusRow(rowIndex);
39151 }else if(e.ctrlKey && isSelected){
39152 this.deselectRow(rowIndex);
39153 }else if(!isSelected){
39154 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
39155 view.focusRow(rowIndex);
39158 this.fireEvent("afterselectionchange", this);
39161 handleDragableRowClick : function(grid, rowIndex, e)
39163 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
39164 this.selectRow(rowIndex, false);
39165 grid.view.focusRow(rowIndex);
39166 this.fireEvent("afterselectionchange", this);
39171 * Selects multiple rows.
39172 * @param {Array} rows Array of the indexes of the row to select
39173 * @param {Boolean} keepExisting (optional) True to keep existing selections
39175 selectRows : function(rows, keepExisting){
39177 this.clearSelections();
39179 for(var i = 0, len = rows.length; i < len; i++){
39180 this.selectRow(rows[i], true);
39185 * Selects a range of rows. All rows in between startRow and endRow are also selected.
39186 * @param {Number} startRow The index of the first row in the range
39187 * @param {Number} endRow The index of the last row in the range
39188 * @param {Boolean} keepExisting (optional) True to retain existing selections
39190 selectRange : function(startRow, endRow, keepExisting){
39191 if(this.locked) return;
39193 this.clearSelections();
39195 if(startRow <= endRow){
39196 for(var i = startRow; i <= endRow; i++){
39197 this.selectRow(i, true);
39200 for(var i = startRow; i >= endRow; i--){
39201 this.selectRow(i, true);
39207 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
39208 * @param {Number} startRow The index of the first row in the range
39209 * @param {Number} endRow The index of the last row in the range
39211 deselectRange : function(startRow, endRow, preventViewNotify){
39212 if(this.locked) return;
39213 for(var i = startRow; i <= endRow; i++){
39214 this.deselectRow(i, preventViewNotify);
39220 * @param {Number} row The index of the row to select
39221 * @param {Boolean} keepExisting (optional) True to keep existing selections
39223 selectRow : function(index, keepExisting, preventViewNotify){
39224 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
39225 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
39226 if(!keepExisting || this.singleSelect){
39227 this.clearSelections();
39229 var r = this.grid.dataSource.getAt(index);
39230 this.selections.add(r);
39231 this.last = this.lastActive = index;
39232 if(!preventViewNotify){
39233 this.grid.getView().onRowSelect(index);
39235 this.fireEvent("rowselect", this, index, r);
39236 this.fireEvent("selectionchange", this);
39242 * @param {Number} row The index of the row to deselect
39244 deselectRow : function(index, preventViewNotify){
39245 if(this.locked) return;
39246 if(this.last == index){
39249 if(this.lastActive == index){
39250 this.lastActive = false;
39252 var r = this.grid.dataSource.getAt(index);
39253 this.selections.remove(r);
39254 if(!preventViewNotify){
39255 this.grid.getView().onRowDeselect(index);
39257 this.fireEvent("rowdeselect", this, index);
39258 this.fireEvent("selectionchange", this);
39262 restoreLast : function(){
39264 this.last = this._last;
39269 acceptsNav : function(row, col, cm){
39270 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39274 onEditorKey : function(field, e){
39275 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
39280 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39282 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39284 }else if(k == e.ENTER && !e.ctrlKey){
39288 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
39290 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
39292 }else if(k == e.ESC){
39296 g.startEditing(newCell[0], newCell[1]);
39301 * Ext JS Library 1.1.1
39302 * Copyright(c) 2006-2007, Ext JS, LLC.
39304 * Originally Released Under LGPL - original licence link has changed is not relivant.
39307 * <script type="text/javascript">
39310 * @class Roo.grid.CellSelectionModel
39311 * @extends Roo.grid.AbstractSelectionModel
39312 * This class provides the basic implementation for cell selection in a grid.
39314 * @param {Object} config The object containing the configuration of this model.
39315 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
39317 Roo.grid.CellSelectionModel = function(config){
39318 Roo.apply(this, config);
39320 this.selection = null;
39324 * @event beforerowselect
39325 * Fires before a cell is selected.
39326 * @param {SelectionModel} this
39327 * @param {Number} rowIndex The selected row index
39328 * @param {Number} colIndex The selected cell index
39330 "beforecellselect" : true,
39332 * @event cellselect
39333 * Fires when a cell is selected.
39334 * @param {SelectionModel} this
39335 * @param {Number} rowIndex The selected row index
39336 * @param {Number} colIndex The selected cell index
39338 "cellselect" : true,
39340 * @event selectionchange
39341 * Fires when the active selection changes.
39342 * @param {SelectionModel} this
39343 * @param {Object} selection null for no selection or an object (o) with two properties
39345 <li>o.record: the record object for the row the selection is in</li>
39346 <li>o.cell: An array of [rowIndex, columnIndex]</li>
39349 "selectionchange" : true,
39352 * Fires when the tab (or enter) was pressed on the last editable cell
39353 * You can use this to trigger add new row.
39354 * @param {SelectionModel} this
39358 * @event beforeeditnext
39359 * Fires before the next editable sell is made active
39360 * You can use this to skip to another cell or fire the tabend
39361 * if you set cell to false
39362 * @param {Object} eventdata object : { cell : [ row, col ] }
39364 "beforeeditnext" : true
39366 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
39369 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
39371 enter_is_tab: false,
39374 initEvents : function(){
39375 this.grid.on("mousedown", this.handleMouseDown, this);
39376 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
39377 var view = this.grid.view;
39378 view.on("refresh", this.onViewChange, this);
39379 view.on("rowupdated", this.onRowUpdated, this);
39380 view.on("beforerowremoved", this.clearSelections, this);
39381 view.on("beforerowsinserted", this.clearSelections, this);
39382 if(this.grid.isEditor){
39383 this.grid.on("beforeedit", this.beforeEdit, this);
39388 beforeEdit : function(e){
39389 this.select(e.row, e.column, false, true, e.record);
39393 onRowUpdated : function(v, index, r){
39394 if(this.selection && this.selection.record == r){
39395 v.onCellSelect(index, this.selection.cell[1]);
39400 onViewChange : function(){
39401 this.clearSelections(true);
39405 * Returns the currently selected cell,.
39406 * @return {Array} The selected cell (row, column) or null if none selected.
39408 getSelectedCell : function(){
39409 return this.selection ? this.selection.cell : null;
39413 * Clears all selections.
39414 * @param {Boolean} true to prevent the gridview from being notified about the change.
39416 clearSelections : function(preventNotify){
39417 var s = this.selection;
39419 if(preventNotify !== true){
39420 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
39422 this.selection = null;
39423 this.fireEvent("selectionchange", this, null);
39428 * Returns true if there is a selection.
39429 * @return {Boolean}
39431 hasSelection : function(){
39432 return this.selection ? true : false;
39436 handleMouseDown : function(e, t){
39437 var v = this.grid.getView();
39438 if(this.isLocked()){
39441 var row = v.findRowIndex(t);
39442 var cell = v.findCellIndex(t);
39443 if(row !== false && cell !== false){
39444 this.select(row, cell);
39450 * @param {Number} rowIndex
39451 * @param {Number} collIndex
39453 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
39454 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
39455 this.clearSelections();
39456 r = r || this.grid.dataSource.getAt(rowIndex);
39459 cell : [rowIndex, colIndex]
39461 if(!preventViewNotify){
39462 var v = this.grid.getView();
39463 v.onCellSelect(rowIndex, colIndex);
39464 if(preventFocus !== true){
39465 v.focusCell(rowIndex, colIndex);
39468 this.fireEvent("cellselect", this, rowIndex, colIndex);
39469 this.fireEvent("selectionchange", this, this.selection);
39474 isSelectable : function(rowIndex, colIndex, cm){
39475 return !cm.isHidden(colIndex);
39479 handleKeyDown : function(e){
39480 //Roo.log('Cell Sel Model handleKeyDown');
39481 if(!e.isNavKeyPress()){
39484 var g = this.grid, s = this.selection;
39487 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
39489 this.select(cell[0], cell[1]);
39494 var walk = function(row, col, step){
39495 return g.walkCells(row, col, step, sm.isSelectable, sm);
39497 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
39504 // handled by onEditorKey
39505 if (g.isEditor && g.editing) {
39509 newCell = walk(r, c-1, -1);
39511 newCell = walk(r, c+1, 1);
39516 newCell = walk(r+1, c, 1);
39520 newCell = walk(r-1, c, -1);
39524 newCell = walk(r, c+1, 1);
39528 newCell = walk(r, c-1, -1);
39533 if(g.isEditor && !g.editing){
39534 g.startEditing(r, c);
39543 this.select(newCell[0], newCell[1]);
39549 acceptsNav : function(row, col, cm){
39550 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39554 * @param {Number} field (not used) - as it's normally used as a listener
39555 * @param {Number} e - event - fake it by using
39557 * var e = Roo.EventObjectImpl.prototype;
39558 * e.keyCode = e.TAB
39562 onEditorKey : function(field, e){
39564 var k = e.getKey(),
39567 ed = g.activeEditor,
39569 ///Roo.log('onEditorKey' + k);
39572 if (this.enter_is_tab && k == e.ENTER) {
39578 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39580 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39586 } else if(k == e.ENTER && !e.ctrlKey){
39589 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39591 } else if(k == e.ESC){
39596 var ecall = { cell : newCell, forward : forward };
39597 this.fireEvent('beforeeditnext', ecall );
39598 newCell = ecall.cell;
39599 forward = ecall.forward;
39603 //Roo.log('next cell after edit');
39604 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
39605 } else if (forward) {
39606 // tabbed past last
39607 this.fireEvent.defer(100, this, ['tabend',this]);
39612 * Ext JS Library 1.1.1
39613 * Copyright(c) 2006-2007, Ext JS, LLC.
39615 * Originally Released Under LGPL - original licence link has changed is not relivant.
39618 * <script type="text/javascript">
39622 * @class Roo.grid.EditorGrid
39623 * @extends Roo.grid.Grid
39624 * Class for creating and editable grid.
39625 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
39626 * The container MUST have some type of size defined for the grid to fill. The container will be
39627 * automatically set to position relative if it isn't already.
39628 * @param {Object} dataSource The data model to bind to
39629 * @param {Object} colModel The column model with info about this grid's columns
39631 Roo.grid.EditorGrid = function(container, config){
39632 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
39633 this.getGridEl().addClass("xedit-grid");
39635 if(!this.selModel){
39636 this.selModel = new Roo.grid.CellSelectionModel();
39639 this.activeEditor = null;
39643 * @event beforeedit
39644 * Fires before cell editing is triggered. The edit event object has the following properties <br />
39645 * <ul style="padding:5px;padding-left:16px;">
39646 * <li>grid - This grid</li>
39647 * <li>record - The record being edited</li>
39648 * <li>field - The field name being edited</li>
39649 * <li>value - The value for the field being edited.</li>
39650 * <li>row - The grid row index</li>
39651 * <li>column - The grid column index</li>
39652 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39654 * @param {Object} e An edit event (see above for description)
39656 "beforeedit" : true,
39659 * Fires after a cell is edited. <br />
39660 * <ul style="padding:5px;padding-left:16px;">
39661 * <li>grid - This grid</li>
39662 * <li>record - The record being edited</li>
39663 * <li>field - The field name being edited</li>
39664 * <li>value - The value being set</li>
39665 * <li>originalValue - The original value for the field, before the edit.</li>
39666 * <li>row - The grid row index</li>
39667 * <li>column - The grid column index</li>
39669 * @param {Object} e An edit event (see above for description)
39671 "afteredit" : true,
39673 * @event validateedit
39674 * Fires after a cell is edited, but before the value is set in the record.
39675 * You can use this to modify the value being set in the field, Return false
39676 * to cancel the change. The edit event object has the following properties <br />
39677 * <ul style="padding:5px;padding-left:16px;">
39678 * <li>editor - This editor</li>
39679 * <li>grid - This grid</li>
39680 * <li>record - The record being edited</li>
39681 * <li>field - The field name being edited</li>
39682 * <li>value - The value being set</li>
39683 * <li>originalValue - The original value for the field, before the edit.</li>
39684 * <li>row - The grid row index</li>
39685 * <li>column - The grid column index</li>
39686 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39688 * @param {Object} e An edit event (see above for description)
39690 "validateedit" : true
39692 this.on("bodyscroll", this.stopEditing, this);
39693 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
39696 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
39698 * @cfg {Number} clicksToEdit
39699 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
39706 trackMouseOver: false, // causes very odd FF errors
39708 onCellDblClick : function(g, row, col){
39709 this.startEditing(row, col);
39712 onEditComplete : function(ed, value, startValue){
39713 this.editing = false;
39714 this.activeEditor = null;
39715 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
39717 var field = this.colModel.getDataIndex(ed.col);
39722 originalValue: startValue,
39729 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
39732 if(String(value) !== String(startValue)){
39734 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
39735 r.set(field, e.value);
39736 // if we are dealing with a combo box..
39737 // then we also set the 'name' colum to be the displayField
39738 if (ed.field.displayField && ed.field.name) {
39739 r.set(ed.field.name, ed.field.el.dom.value);
39742 delete e.cancel; //?? why!!!
39743 this.fireEvent("afteredit", e);
39746 this.fireEvent("afteredit", e); // always fire it!
39748 this.view.focusCell(ed.row, ed.col);
39752 * Starts editing the specified for the specified row/column
39753 * @param {Number} rowIndex
39754 * @param {Number} colIndex
39756 startEditing : function(row, col){
39757 this.stopEditing();
39758 if(this.colModel.isCellEditable(col, row)){
39759 this.view.ensureVisible(row, col, true);
39761 var r = this.dataSource.getAt(row);
39762 var field = this.colModel.getDataIndex(col);
39763 var cell = Roo.get(this.view.getCell(row,col));
39768 value: r.data[field],
39773 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
39774 this.editing = true;
39775 var ed = this.colModel.getCellEditor(col, row);
39781 ed.render(ed.parentEl || document.body);
39787 (function(){ // complex but required for focus issues in safari, ie and opera
39791 ed.on("complete", this.onEditComplete, this, {single: true});
39792 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
39793 this.activeEditor = ed;
39794 var v = r.data[field];
39795 ed.startEdit(this.view.getCell(row, col), v);
39796 // combo's with 'displayField and name set
39797 if (ed.field.displayField && ed.field.name) {
39798 ed.field.el.dom.value = r.data[ed.field.name];
39802 }).defer(50, this);
39808 * Stops any active editing
39810 stopEditing : function(){
39811 if(this.activeEditor){
39812 this.activeEditor.completeEdit();
39814 this.activeEditor = null;
39818 * Called to get grid's drag proxy text, by default returns this.ddText.
39821 getDragDropText : function(){
39822 var count = this.selModel.getSelectedCell() ? 1 : 0;
39823 return String.format(this.ddText, count, count == 1 ? '' : 's');
39828 * Ext JS Library 1.1.1
39829 * Copyright(c) 2006-2007, Ext JS, LLC.
39831 * Originally Released Under LGPL - original licence link has changed is not relivant.
39834 * <script type="text/javascript">
39837 // private - not really -- you end up using it !
39838 // This is a support class used internally by the Grid components
39841 * @class Roo.grid.GridEditor
39842 * @extends Roo.Editor
39843 * Class for creating and editable grid elements.
39844 * @param {Object} config any settings (must include field)
39846 Roo.grid.GridEditor = function(field, config){
39847 if (!config && field.field) {
39849 field = Roo.factory(config.field, Roo.form);
39851 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
39852 field.monitorTab = false;
39855 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
39858 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
39861 alignment: "tl-tl",
39864 cls: "x-small-editor x-grid-editor",
39869 * Ext JS Library 1.1.1
39870 * Copyright(c) 2006-2007, Ext JS, LLC.
39872 * Originally Released Under LGPL - original licence link has changed is not relivant.
39875 * <script type="text/javascript">
39880 Roo.grid.PropertyRecord = Roo.data.Record.create([
39881 {name:'name',type:'string'}, 'value'
39885 Roo.grid.PropertyStore = function(grid, source){
39887 this.store = new Roo.data.Store({
39888 recordType : Roo.grid.PropertyRecord
39890 this.store.on('update', this.onUpdate, this);
39892 this.setSource(source);
39894 Roo.grid.PropertyStore.superclass.constructor.call(this);
39899 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
39900 setSource : function(o){
39902 this.store.removeAll();
39905 if(this.isEditableValue(o[k])){
39906 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
39909 this.store.loadRecords({records: data}, {}, true);
39912 onUpdate : function(ds, record, type){
39913 if(type == Roo.data.Record.EDIT){
39914 var v = record.data['value'];
39915 var oldValue = record.modified['value'];
39916 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
39917 this.source[record.id] = v;
39919 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
39926 getProperty : function(row){
39927 return this.store.getAt(row);
39930 isEditableValue: function(val){
39931 if(val && val instanceof Date){
39933 }else if(typeof val == 'object' || typeof val == 'function'){
39939 setValue : function(prop, value){
39940 this.source[prop] = value;
39941 this.store.getById(prop).set('value', value);
39944 getSource : function(){
39945 return this.source;
39949 Roo.grid.PropertyColumnModel = function(grid, store){
39952 g.PropertyColumnModel.superclass.constructor.call(this, [
39953 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
39954 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
39956 this.store = store;
39957 this.bselect = Roo.DomHelper.append(document.body, {
39958 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
39959 {tag: 'option', value: 'true', html: 'true'},
39960 {tag: 'option', value: 'false', html: 'false'}
39963 Roo.id(this.bselect);
39966 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
39967 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
39968 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
39969 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
39970 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
39972 this.renderCellDelegate = this.renderCell.createDelegate(this);
39973 this.renderPropDelegate = this.renderProp.createDelegate(this);
39976 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
39980 valueText : 'Value',
39982 dateFormat : 'm/j/Y',
39985 renderDate : function(dateVal){
39986 return dateVal.dateFormat(this.dateFormat);
39989 renderBool : function(bVal){
39990 return bVal ? 'true' : 'false';
39993 isCellEditable : function(colIndex, rowIndex){
39994 return colIndex == 1;
39997 getRenderer : function(col){
39999 this.renderCellDelegate : this.renderPropDelegate;
40002 renderProp : function(v){
40003 return this.getPropertyName(v);
40006 renderCell : function(val){
40008 if(val instanceof Date){
40009 rv = this.renderDate(val);
40010 }else if(typeof val == 'boolean'){
40011 rv = this.renderBool(val);
40013 return Roo.util.Format.htmlEncode(rv);
40016 getPropertyName : function(name){
40017 var pn = this.grid.propertyNames;
40018 return pn && pn[name] ? pn[name] : name;
40021 getCellEditor : function(colIndex, rowIndex){
40022 var p = this.store.getProperty(rowIndex);
40023 var n = p.data['name'], val = p.data['value'];
40025 if(typeof(this.grid.customEditors[n]) == 'string'){
40026 return this.editors[this.grid.customEditors[n]];
40028 if(typeof(this.grid.customEditors[n]) != 'undefined'){
40029 return this.grid.customEditors[n];
40031 if(val instanceof Date){
40032 return this.editors['date'];
40033 }else if(typeof val == 'number'){
40034 return this.editors['number'];
40035 }else if(typeof val == 'boolean'){
40036 return this.editors['boolean'];
40038 return this.editors['string'];
40044 * @class Roo.grid.PropertyGrid
40045 * @extends Roo.grid.EditorGrid
40046 * This class represents the interface of a component based property grid control.
40047 * <br><br>Usage:<pre><code>
40048 var grid = new Roo.grid.PropertyGrid("my-container-id", {
40056 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
40057 * The container MUST have some type of size defined for the grid to fill. The container will be
40058 * automatically set to position relative if it isn't already.
40059 * @param {Object} config A config object that sets properties on this grid.
40061 Roo.grid.PropertyGrid = function(container, config){
40062 config = config || {};
40063 var store = new Roo.grid.PropertyStore(this);
40064 this.store = store;
40065 var cm = new Roo.grid.PropertyColumnModel(this, store);
40066 store.store.sort('name', 'ASC');
40067 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
40070 enableColLock:false,
40071 enableColumnMove:false,
40073 trackMouseOver: false,
40076 this.getGridEl().addClass('x-props-grid');
40077 this.lastEditRow = null;
40078 this.on('columnresize', this.onColumnResize, this);
40081 * @event beforepropertychange
40082 * Fires before a property changes (return false to stop?)
40083 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40084 * @param {String} id Record Id
40085 * @param {String} newval New Value
40086 * @param {String} oldval Old Value
40088 "beforepropertychange": true,
40090 * @event propertychange
40091 * Fires after a property changes
40092 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40093 * @param {String} id Record Id
40094 * @param {String} newval New Value
40095 * @param {String} oldval Old Value
40097 "propertychange": true
40099 this.customEditors = this.customEditors || {};
40101 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
40104 * @cfg {Object} customEditors map of colnames=> custom editors.
40105 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
40106 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
40107 * false disables editing of the field.
40111 * @cfg {Object} propertyNames map of property Names to their displayed value
40114 render : function(){
40115 Roo.grid.PropertyGrid.superclass.render.call(this);
40116 this.autoSize.defer(100, this);
40119 autoSize : function(){
40120 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
40122 this.view.fitColumns();
40126 onColumnResize : function(){
40127 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
40131 * Sets the data for the Grid
40132 * accepts a Key => Value object of all the elements avaiable.
40133 * @param {Object} data to appear in grid.
40135 setSource : function(source){
40136 this.store.setSource(source);
40140 * Gets all the data from the grid.
40141 * @return {Object} data data stored in grid
40143 getSource : function(){
40144 return this.store.getSource();
40148 * Ext JS Library 1.1.1
40149 * Copyright(c) 2006-2007, Ext JS, LLC.
40151 * Originally Released Under LGPL - original licence link has changed is not relivant.
40154 * <script type="text/javascript">
40158 * @class Roo.LoadMask
40159 * A simple utility class for generically masking elements while loading data. If the element being masked has
40160 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
40161 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
40162 * element's UpdateManager load indicator and will be destroyed after the initial load.
40164 * Create a new LoadMask
40165 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
40166 * @param {Object} config The config object
40168 Roo.LoadMask = function(el, config){
40169 this.el = Roo.get(el);
40170 Roo.apply(this, config);
40172 this.store.on('beforeload', this.onBeforeLoad, this);
40173 this.store.on('load', this.onLoad, this);
40174 this.store.on('loadexception', this.onLoadException, this);
40175 this.removeMask = false;
40177 var um = this.el.getUpdateManager();
40178 um.showLoadIndicator = false; // disable the default indicator
40179 um.on('beforeupdate', this.onBeforeLoad, this);
40180 um.on('update', this.onLoad, this);
40181 um.on('failure', this.onLoad, this);
40182 this.removeMask = true;
40186 Roo.LoadMask.prototype = {
40188 * @cfg {Boolean} removeMask
40189 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
40190 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
40193 * @cfg {String} msg
40194 * The text to display in a centered loading message box (defaults to 'Loading...')
40196 msg : 'Loading...',
40198 * @cfg {String} msgCls
40199 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
40201 msgCls : 'x-mask-loading',
40204 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
40210 * Disables the mask to prevent it from being displayed
40212 disable : function(){
40213 this.disabled = true;
40217 * Enables the mask so that it can be displayed
40219 enable : function(){
40220 this.disabled = false;
40223 onLoadException : function()
40225 Roo.log(arguments);
40227 if (typeof(arguments[3]) != 'undefined') {
40228 Roo.MessageBox.alert("Error loading",arguments[3]);
40232 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
40233 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
40242 this.el.unmask(this.removeMask);
40245 onLoad : function()
40247 this.el.unmask(this.removeMask);
40251 onBeforeLoad : function(){
40252 if(!this.disabled){
40253 this.el.mask(this.msg, this.msgCls);
40258 destroy : function(){
40260 this.store.un('beforeload', this.onBeforeLoad, this);
40261 this.store.un('load', this.onLoad, this);
40262 this.store.un('loadexception', this.onLoadException, this);
40264 var um = this.el.getUpdateManager();
40265 um.un('beforeupdate', this.onBeforeLoad, this);
40266 um.un('update', this.onLoad, this);
40267 um.un('failure', this.onLoad, this);
40272 * Ext JS Library 1.1.1
40273 * Copyright(c) 2006-2007, Ext JS, LLC.
40275 * Originally Released Under LGPL - original licence link has changed is not relivant.
40278 * <script type="text/javascript">
40283 * @class Roo.XTemplate
40284 * @extends Roo.Template
40285 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
40287 var t = new Roo.XTemplate(
40288 '<select name="{name}">',
40289 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
40293 // then append, applying the master template values
40296 * Supported features:
40301 {a_variable} - output encoded.
40302 {a_variable.format:("Y-m-d")} - call a method on the variable
40303 {a_variable:raw} - unencoded output
40304 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
40305 {a_variable:this.method_on_template(...)} - call a method on the template object.
40310 <tpl for="a_variable or condition.."></tpl>
40311 <tpl if="a_variable or condition"></tpl>
40312 <tpl exec="some javascript"></tpl>
40313 <tpl name="named_template"></tpl> (experimental)
40315 <tpl for="."></tpl> - just iterate the property..
40316 <tpl for=".."></tpl> - iterates with the parent (probably the template)
40320 Roo.XTemplate = function()
40322 Roo.XTemplate.superclass.constructor.apply(this, arguments);
40329 Roo.extend(Roo.XTemplate, Roo.Template, {
40332 * The various sub templates
40337 * basic tag replacing syntax
40340 * // you can fake an object call by doing this
40344 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
40347 * compile the template
40349 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
40352 compile: function()
40356 s = ['<tpl>', s, '</tpl>'].join('');
40358 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
40359 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
40360 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
40361 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
40362 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
40367 while(true == !!(m = s.match(re))){
40368 var forMatch = m[0].match(nameRe),
40369 ifMatch = m[0].match(ifRe),
40370 execMatch = m[0].match(execRe),
40371 namedMatch = m[0].match(namedRe),
40376 name = forMatch && forMatch[1] ? forMatch[1] : '';
40379 // if - puts fn into test..
40380 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
40382 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
40387 // exec - calls a function... returns empty if true is returned.
40388 exp = execMatch && execMatch[1] ? execMatch[1] : null;
40390 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
40398 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
40399 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
40400 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
40403 var uid = namedMatch ? namedMatch[1] : id;
40407 id: namedMatch ? namedMatch[1] : id,
40414 s = s.replace(m[0], '');
40416 s = s.replace(m[0], '{xtpl'+ id + '}');
40421 for(var i = tpls.length-1; i >= 0; --i){
40422 this.compileTpl(tpls[i]);
40423 this.tpls[tpls[i].id] = tpls[i];
40425 this.master = tpls[tpls.length-1];
40429 * same as applyTemplate, except it's done to one of the subTemplates
40430 * when using named templates, you can do:
40432 * var str = pl.applySubTemplate('your-name', values);
40435 * @param {Number} id of the template
40436 * @param {Object} values to apply to template
40437 * @param {Object} parent (normaly the instance of this object)
40439 applySubTemplate : function(id, values, parent)
40443 var t = this.tpls[id];
40447 if(t.test && !t.test.call(this, values, parent)){
40451 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
40452 Roo.log(e.toString());
40458 if(t.exec && t.exec.call(this, values, parent)){
40462 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
40463 Roo.log(e.toString());
40468 var vs = t.target ? t.target.call(this, values, parent) : values;
40469 parent = t.target ? values : parent;
40470 if(t.target && vs instanceof Array){
40472 for(var i = 0, len = vs.length; i < len; i++){
40473 buf[buf.length] = t.compiled.call(this, vs[i], parent);
40475 return buf.join('');
40477 return t.compiled.call(this, vs, parent);
40479 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
40480 Roo.log(e.toString());
40481 Roo.log(t.compiled);
40486 compileTpl : function(tpl)
40488 var fm = Roo.util.Format;
40489 var useF = this.disableFormats !== true;
40490 var sep = Roo.isGecko ? "+" : ",";
40491 var undef = function(str) {
40492 Roo.log("Property not found :" + str);
40496 var fn = function(m, name, format, args)
40498 //Roo.log(arguments);
40499 args = args ? args.replace(/\\'/g,"'") : args;
40500 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
40501 if (typeof(format) == 'undefined') {
40502 format= 'htmlEncode';
40504 if (format == 'raw' ) {
40508 if(name.substr(0, 4) == 'xtpl'){
40509 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
40512 // build an array of options to determine if value is undefined..
40514 // basically get 'xxxx.yyyy' then do
40515 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
40516 // (function () { Roo.log("Property not found"); return ''; })() :
40521 Roo.each(name.split('.'), function(st) {
40522 lookfor += (lookfor.length ? '.': '') + st;
40523 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
40526 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
40529 if(format && useF){
40531 args = args ? ',' + args : "";
40533 if(format.substr(0, 5) != "this."){
40534 format = "fm." + format + '(';
40536 format = 'this.call("'+ format.substr(5) + '", ';
40540 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
40544 // called with xxyx.yuu:(test,test)
40546 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
40548 // raw.. - :raw modifier..
40549 return "'"+ sep + udef_st + name + ")"+sep+"'";
40553 // branched to use + in gecko and [].join() in others
40555 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
40556 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
40559 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
40560 body.push(tpl.body.replace(/(\r\n|\n)/g,
40561 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
40562 body.push("'].join('');};};");
40563 body = body.join('');
40566 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
40568 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
40574 applyTemplate : function(values){
40575 return this.master.compiled.call(this, values, {});
40576 //var s = this.subs;
40579 apply : function(){
40580 return this.applyTemplate.apply(this, arguments);
40585 Roo.XTemplate.from = function(el){
40586 el = Roo.getDom(el);
40587 return new Roo.XTemplate(el.value || el.innerHTML);
40589 * Original code for Roojs - LGPL
40590 * <script type="text/javascript">
40594 * @class Roo.XComponent
40595 * A delayed Element creator...
40596 * Or a way to group chunks of interface together.
40598 * Mypart.xyx = new Roo.XComponent({
40600 parent : 'Mypart.xyz', // empty == document.element.!!
40604 disabled : function() {}
40606 tree : function() { // return an tree of xtype declared components
40610 xtype : 'NestedLayoutPanel',
40617 * It can be used to build a big heiracy, with parent etc.
40618 * or you can just use this to render a single compoent to a dom element
40619 * MYPART.render(Roo.Element | String(id) | dom_element )
40621 * @extends Roo.util.Observable
40623 * @param cfg {Object} configuration of component
40626 Roo.XComponent = function(cfg) {
40627 Roo.apply(this, cfg);
40631 * Fires when this the componnt is built
40632 * @param {Roo.XComponent} c the component
40637 this.region = this.region || 'center'; // default..
40638 Roo.XComponent.register(this);
40639 this.modules = false;
40640 this.el = false; // where the layout goes..
40644 Roo.extend(Roo.XComponent, Roo.util.Observable, {
40647 * The created element (with Roo.factory())
40648 * @type {Roo.Layout}
40654 * for BC - use el in new code
40655 * @type {Roo.Layout}
40661 * for BC - use el in new code
40662 * @type {Roo.Layout}
40667 * @cfg {Function|boolean} disabled
40668 * If this module is disabled by some rule, return true from the funtion
40673 * @cfg {String} parent
40674 * Name of parent element which it get xtype added to..
40679 * @cfg {String} order
40680 * Used to set the order in which elements are created (usefull for multiple tabs)
40685 * @cfg {String} name
40686 * String to display while loading.
40690 * @cfg {String} region
40691 * Region to render component to (defaults to center)
40696 * @cfg {Array} items
40697 * A single item array - the first element is the root of the tree..
40698 * It's done this way to stay compatible with the Xtype system...
40704 * The method that retuns the tree of parts that make up this compoennt
40711 * render element to dom or tree
40712 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
40715 render : function(el)
40719 var hp = this.parent ? 1 : 0;
40721 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
40722 // if parent is a '#.....' string, then let's use that..
40723 var ename = this.parent.substr(1)
40724 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
40725 el = Roo.get(ename);
40726 if (!el && !this.parent) {
40727 Roo.log("Warning - element can not be found :#" + ename );
40733 if (!this.parent) {
40735 el = el ? Roo.get(el) : false;
40737 // it's a top level one..
40739 el : new Roo.BorderLayout(el || document.body, {
40745 tabPosition: 'top',
40746 //resizeTabs: true,
40747 alwaysShowTabs: el && hp? false : true,
40748 hideTabs: el || !hp ? true : false,
40755 if (!this.parent.el) {
40756 // probably an old style ctor, which has been disabled.
40760 // The 'tree' method is '_tree now'
40762 var tree = this._tree ? this._tree() : this.tree();
40763 tree.region = tree.region || this.region;
40764 this.el = this.parent.el.addxtype(tree);
40765 this.fireEvent('built', this);
40767 this.panel = this.el;
40768 this.layout = this.panel.layout;
40769 this.parentLayout = this.parent.layout || false;
40775 Roo.apply(Roo.XComponent, {
40777 * @property hideProgress
40778 * true to disable the building progress bar.. usefull on single page renders.
40781 hideProgress : false,
40783 * @property buildCompleted
40784 * True when the builder has completed building the interface.
40787 buildCompleted : false,
40790 * @property topModule
40791 * the upper most module - uses document.element as it's constructor.
40798 * @property modules
40799 * array of modules to be created by registration system.
40800 * @type {Array} of Roo.XComponent
40805 * @property elmodules
40806 * array of modules to be created by which use #ID
40807 * @type {Array} of Roo.XComponent
40814 * Register components to be built later.
40816 * This solves the following issues
40817 * - Building is not done on page load, but after an authentication process has occured.
40818 * - Interface elements are registered on page load
40819 * - Parent Interface elements may not be loaded before child, so this handles that..
40826 module : 'Pman.Tab.projectMgr',
40828 parent : 'Pman.layout',
40829 disabled : false, // or use a function..
40832 * * @param {Object} details about module
40834 register : function(obj) {
40836 Roo.XComponent.event.fireEvent('register', obj);
40837 switch(typeof(obj.disabled) ) {
40843 if ( obj.disabled() ) {
40849 if (obj.disabled) {
40855 this.modules.push(obj);
40859 * convert a string to an object..
40860 * eg. 'AAA.BBB' -> finds AAA.BBB
40864 toObject : function(str)
40866 if (!str || typeof(str) == 'object') {
40869 if (str.substring(0,1) == '#') {
40873 var ar = str.split('.');
40878 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
40880 throw "Module not found : " + str;
40884 throw "Module not found : " + str;
40886 Roo.each(ar, function(e) {
40887 if (typeof(o[e]) == 'undefined') {
40888 throw "Module not found : " + str;
40899 * move modules into their correct place in the tree..
40902 preBuild : function ()
40905 Roo.each(this.modules , function (obj)
40907 Roo.XComponent.event.fireEvent('beforebuild', obj);
40909 var opar = obj.parent;
40911 obj.parent = this.toObject(opar);
40913 Roo.log("parent:toObject failed: " + e.toString());
40918 Roo.debug && Roo.log("GOT top level module");
40919 Roo.debug && Roo.log(obj);
40920 obj.modules = new Roo.util.MixedCollection(false,
40921 function(o) { return o.order + '' }
40923 this.topModule = obj;
40926 // parent is a string (usually a dom element name..)
40927 if (typeof(obj.parent) == 'string') {
40928 this.elmodules.push(obj);
40931 if (obj.parent.constructor != Roo.XComponent) {
40932 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
40934 if (!obj.parent.modules) {
40935 obj.parent.modules = new Roo.util.MixedCollection(false,
40936 function(o) { return o.order + '' }
40939 if (obj.parent.disabled) {
40940 obj.disabled = true;
40942 obj.parent.modules.add(obj);
40947 * make a list of modules to build.
40948 * @return {Array} list of modules.
40951 buildOrder : function()
40954 var cmp = function(a,b) {
40955 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
40957 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
40958 throw "No top level modules to build";
40961 // make a flat list in order of modules to build.
40962 var mods = this.topModule ? [ this.topModule ] : [];
40965 // elmodules (is a list of DOM based modules )
40966 Roo.each(this.elmodules, function(e) {
40968 if (!this.topModule &&
40969 typeof(e.parent) == 'string' &&
40970 e.parent.substring(0,1) == '#' &&
40971 Roo.get(e.parent.substr(1))
40974 _this.topModule = e;
40980 // add modules to their parents..
40981 var addMod = function(m) {
40982 Roo.debug && Roo.log("build Order: add: " + m.name);
40985 if (m.modules && !m.disabled) {
40986 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
40987 m.modules.keySort('ASC', cmp );
40988 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
40990 m.modules.each(addMod);
40992 Roo.debug && Roo.log("build Order: no child modules");
40994 // not sure if this is used any more..
40996 m.finalize.name = m.name + " (clean up) ";
40997 mods.push(m.finalize);
41001 if (this.topModule && this.topModule.modules) {
41002 this.topModule.modules.keySort('ASC', cmp );
41003 this.topModule.modules.each(addMod);
41009 * Build the registered modules.
41010 * @param {Object} parent element.
41011 * @param {Function} optional method to call after module has been added.
41019 var mods = this.buildOrder();
41021 //this.allmods = mods;
41022 //Roo.debug && Roo.log(mods);
41024 if (!mods.length) { // should not happen
41025 throw "NO modules!!!";
41029 var msg = "Building Interface...";
41030 // flash it up as modal - so we store the mask!?
41031 if (!this.hideProgress) {
41032 Roo.MessageBox.show({ title: 'loading' });
41033 Roo.MessageBox.show({
41034 title: "Please wait...",
41043 var total = mods.length;
41046 var progressRun = function() {
41047 if (!mods.length) {
41048 Roo.debug && Roo.log('hide?');
41049 if (!this.hideProgress) {
41050 Roo.MessageBox.hide();
41052 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
41058 var m = mods.shift();
41061 Roo.debug && Roo.log(m);
41062 // not sure if this is supported any more.. - modules that are are just function
41063 if (typeof(m) == 'function') {
41065 return progressRun.defer(10, _this);
41069 msg = "Building Interface " + (total - mods.length) +
41071 (m.name ? (' - ' + m.name) : '');
41072 Roo.debug && Roo.log(msg);
41073 if (!this.hideProgress) {
41074 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
41078 // is the module disabled?
41079 var disabled = (typeof(m.disabled) == 'function') ?
41080 m.disabled.call(m.module.disabled) : m.disabled;
41084 return progressRun(); // we do not update the display!
41092 // it's 10 on top level, and 1 on others??? why...
41093 return progressRun.defer(10, _this);
41096 progressRun.defer(1, _this);
41110 * wrapper for event.on - aliased later..
41111 * Typically use to register a event handler for register:
41113 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
41122 Roo.XComponent.event = new Roo.util.Observable({
41126 * Fires when an Component is registered,
41127 * set the disable property on the Component to stop registration.
41128 * @param {Roo.XComponent} c the component being registerd.
41133 * @event beforebuild
41134 * Fires before each Component is built
41135 * can be used to apply permissions.
41136 * @param {Roo.XComponent} c the component being registerd.
41139 'beforebuild' : true,
41141 * @event buildcomplete
41142 * Fires on the top level element when all elements have been built
41143 * @param {Roo.XComponent} the top level component.
41145 'buildcomplete' : true
41150 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);