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({
26981 actiontype : this.cleanStyles[i],
26982 html: 'Remove ' + this.cleanStyles[i],
26983 handler: function(a,b) {
26986 var c = Roo.get(editor.doc.body);
26987 c.select('[style]').each(function(s) {
26988 s.dom.style.removeProperty(a.actiontype);
26999 if (!this.disable.specialElements) {
27002 cls: 'x-edit-none',
27007 for (var i =0; i < this.specialElements.length; i++) {
27008 semenu.menu.items.push(
27010 handler: function(a,b) {
27011 editor.insertAtCursor(this.ihtml);
27013 }, this.specialElements[i])
27025 for(var i =0; i< this.btns.length;i++) {
27026 var b = Roo.factory(this.btns[i],Roo.form);
27027 b.cls = 'x-edit-none';
27036 // disable everything...
27038 this.tb.items.each(function(item){
27039 if(item.id != editor.frameId+ '-sourceedit'){
27043 this.rendered = true;
27045 // the all the btns;
27046 editor.on('editorevent', this.updateToolbar, this);
27047 // other toolbars need to implement this..
27048 //editor.on('editmodechange', this.updateToolbar, this);
27054 * Protected method that will not generally be called directly. It triggers
27055 * a toolbar update by reading the markup state of the current selection in the editor.
27057 updateToolbar: function(){
27059 if(!this.editor.activated){
27060 this.editor.onFirstFocus();
27064 var btns = this.tb.items.map,
27065 doc = this.editor.doc,
27066 frameId = this.editor.frameId;
27068 if(!this.disable.font && !Roo.isSafari){
27070 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
27071 if(name != this.fontSelect.dom.value){
27072 this.fontSelect.dom.value = name;
27076 if(!this.disable.format){
27077 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
27078 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
27079 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
27081 if(!this.disable.alignments){
27082 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
27083 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
27084 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
27086 if(!Roo.isSafari && !this.disable.lists){
27087 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
27088 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
27091 var ans = this.editor.getAllAncestors();
27092 if (this.formatCombo) {
27095 var store = this.formatCombo.store;
27096 this.formatCombo.setValue("");
27097 for (var i =0; i < ans.length;i++) {
27098 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
27100 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
27108 // hides menus... - so this cant be on a menu...
27109 Roo.menu.MenuMgr.hideAll();
27111 //this.editorsyncValue();
27115 createFontOptions : function(){
27116 var buf = [], fs = this.fontFamilies, ff, lc;
27120 for(var i = 0, len = fs.length; i< len; i++){
27122 lc = ff.toLowerCase();
27124 '<option value="',lc,'" style="font-family:',ff,';"',
27125 (this.defaultFont == lc ? ' selected="true">' : '>'),
27130 return buf.join('');
27133 toggleSourceEdit : function(sourceEditMode){
27134 if(sourceEditMode === undefined){
27135 sourceEditMode = !this.sourceEditMode;
27137 this.sourceEditMode = sourceEditMode === true;
27138 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
27139 // just toggle the button?
27140 if(btn.pressed !== this.editor.sourceEditMode){
27141 btn.toggle(this.editor.sourceEditMode);
27145 if(this.sourceEditMode){
27146 this.tb.items.each(function(item){
27147 if(item.cmd != 'sourceedit'){
27153 if(this.initialized){
27154 this.tb.items.each(function(item){
27160 // tell the editor that it's been pressed..
27161 this.editor.toggleSourceEdit(sourceEditMode);
27165 * Object collection of toolbar tooltips for the buttons in the editor. The key
27166 * is the command id associated with that button and the value is a valid QuickTips object.
27171 title: 'Bold (Ctrl+B)',
27172 text: 'Make the selected text bold.',
27173 cls: 'x-html-editor-tip'
27176 title: 'Italic (Ctrl+I)',
27177 text: 'Make the selected text italic.',
27178 cls: 'x-html-editor-tip'
27186 title: 'Bold (Ctrl+B)',
27187 text: 'Make the selected text bold.',
27188 cls: 'x-html-editor-tip'
27191 title: 'Italic (Ctrl+I)',
27192 text: 'Make the selected text italic.',
27193 cls: 'x-html-editor-tip'
27196 title: 'Underline (Ctrl+U)',
27197 text: 'Underline the selected text.',
27198 cls: 'x-html-editor-tip'
27200 increasefontsize : {
27201 title: 'Grow Text',
27202 text: 'Increase the font size.',
27203 cls: 'x-html-editor-tip'
27205 decreasefontsize : {
27206 title: 'Shrink Text',
27207 text: 'Decrease the font size.',
27208 cls: 'x-html-editor-tip'
27211 title: 'Text Highlight Color',
27212 text: 'Change the background color of the selected text.',
27213 cls: 'x-html-editor-tip'
27216 title: 'Font Color',
27217 text: 'Change the color of the selected text.',
27218 cls: 'x-html-editor-tip'
27221 title: 'Align Text Left',
27222 text: 'Align text to the left.',
27223 cls: 'x-html-editor-tip'
27226 title: 'Center Text',
27227 text: 'Center text in the editor.',
27228 cls: 'x-html-editor-tip'
27231 title: 'Align Text Right',
27232 text: 'Align text to the right.',
27233 cls: 'x-html-editor-tip'
27235 insertunorderedlist : {
27236 title: 'Bullet List',
27237 text: 'Start a bulleted list.',
27238 cls: 'x-html-editor-tip'
27240 insertorderedlist : {
27241 title: 'Numbered List',
27242 text: 'Start a numbered list.',
27243 cls: 'x-html-editor-tip'
27246 title: 'Hyperlink',
27247 text: 'Make the selected text a hyperlink.',
27248 cls: 'x-html-editor-tip'
27251 title: 'Source Edit',
27252 text: 'Switch to source editing mode.',
27253 cls: 'x-html-editor-tip'
27257 onDestroy : function(){
27260 this.tb.items.each(function(item){
27262 item.menu.removeAll();
27264 item.menu.el.destroy();
27272 onFirstFocus: function() {
27273 this.tb.items.each(function(item){
27282 // <script type="text/javascript">
27285 * Ext JS Library 1.1.1
27286 * Copyright(c) 2006-2007, Ext JS, LLC.
27293 * @class Roo.form.HtmlEditor.ToolbarContext
27298 new Roo.form.HtmlEditor({
27301 { xtype: 'ToolbarStandard', styles : {} }
27302 { xtype: 'ToolbarContext', disable : {} }
27308 * @config : {Object} disable List of elements to disable.. (not done yet.)
27309 * @config : {Object} styles Map of styles available.
27313 Roo.form.HtmlEditor.ToolbarContext = function(config)
27316 Roo.apply(this, config);
27317 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
27318 // dont call parent... till later.
27319 this.styles = this.styles || {};
27324 Roo.form.HtmlEditor.ToolbarContext.types = {
27336 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
27398 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
27403 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
27413 style : 'fontFamily',
27414 displayField: 'display',
27415 optname : 'font-family',
27464 // should we really allow this??
27465 // should this just be
27476 style : 'fontFamily',
27477 displayField: 'display',
27478 optname : 'font-family',
27485 style : 'fontFamily',
27486 displayField: 'display',
27487 optname : 'font-family',
27494 style : 'fontFamily',
27495 displayField: 'display',
27496 optname : 'font-family',
27507 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
27508 Roo.form.HtmlEditor.ToolbarContext.stores = false;
27510 Roo.form.HtmlEditor.ToolbarContext.options = {
27512 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
27513 [ 'Courier New', 'Courier New'],
27514 [ 'Tahoma', 'Tahoma'],
27515 [ 'Times New Roman,serif', 'Times'],
27516 [ 'Verdana','Verdana' ]
27520 // fixme - these need to be configurable..
27523 Roo.form.HtmlEditor.ToolbarContext.types
27526 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
27534 * @cfg {Object} disable List of toolbar elements to disable
27539 * @cfg {Object} styles List of styles
27540 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
27542 * These must be defined in the page, so they get rendered correctly..
27553 init : function(editor)
27555 this.editor = editor;
27558 var fid = editor.frameId;
27560 function btn(id, toggle, handler){
27561 var xid = fid + '-'+ id ;
27565 cls : 'x-btn-icon x-edit-'+id,
27566 enableToggle:toggle !== false,
27567 scope: editor, // was editor...
27568 handler:handler||editor.relayBtnCmd,
27569 clickEvent:'mousedown',
27570 tooltip: etb.buttonTips[id] || undefined, ///tips ???
27574 // create a new element.
27575 var wdiv = editor.wrap.createChild({
27577 }, editor.wrap.dom.firstChild.nextSibling, true);
27579 // can we do this more than once??
27581 // stop form submits
27584 // disable everything...
27585 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27586 this.toolbars = {};
27588 for (var i in ty) {
27590 this.toolbars[i] = this.buildToolbar(ty[i],i);
27592 this.tb = this.toolbars.BODY;
27594 this.buildFooter();
27595 this.footer.show();
27596 editor.on('hide', function( ) { this.footer.hide() }, this);
27597 editor.on('show', function( ) { this.footer.show() }, this);
27600 this.rendered = true;
27602 // the all the btns;
27603 editor.on('editorevent', this.updateToolbar, this);
27604 // other toolbars need to implement this..
27605 //editor.on('editmodechange', this.updateToolbar, this);
27611 * Protected method that will not generally be called directly. It triggers
27612 * a toolbar update by reading the markup state of the current selection in the editor.
27614 updateToolbar: function(editor,ev,sel){
27617 // capture mouse up - this is handy for selecting images..
27618 // perhaps should go somewhere else...
27619 if(!this.editor.activated){
27620 this.editor.onFirstFocus();
27624 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
27625 // selectNode - might want to handle IE?
27627 (ev.type == 'mouseup' || ev.type == 'click' ) &&
27628 ev.target && ev.target.tagName == 'IMG') {
27629 // they have click on an image...
27630 // let's see if we can change the selection...
27633 var nodeRange = sel.ownerDocument.createRange();
27635 nodeRange.selectNode(sel);
27637 nodeRange.selectNodeContents(sel);
27639 //nodeRange.collapse(true);
27640 var s = editor.win.getSelection();
27641 s.removeAllRanges();
27642 s.addRange(nodeRange);
27646 var updateFooter = sel ? false : true;
27649 var ans = this.editor.getAllAncestors();
27652 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27655 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
27656 sel = sel ? sel : this.editor.doc.body;
27657 sel = sel.tagName.length ? sel : this.editor.doc.body;
27660 // pick a menu that exists..
27661 var tn = sel.tagName.toUpperCase();
27662 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
27664 tn = sel.tagName.toUpperCase();
27666 var lastSel = this.tb.selectedNode
27668 this.tb.selectedNode = sel;
27670 // if current menu does not match..
27671 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
27674 ///console.log("show: " + tn);
27675 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
27678 this.tb.items.first().el.innerHTML = tn + ': ';
27681 // update attributes
27682 if (this.tb.fields) {
27683 this.tb.fields.each(function(e) {
27685 e.setValue(sel.style[e.stylename]);
27688 e.setValue(sel.getAttribute(e.attrname));
27692 var hasStyles = false;
27693 for(var i in this.styles) {
27700 var st = this.tb.fields.item(0);
27702 st.store.removeAll();
27705 var cn = sel.className.split(/\s+/);
27708 if (this.styles['*']) {
27710 Roo.each(this.styles['*'], function(v) {
27711 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27714 if (this.styles[tn]) {
27715 Roo.each(this.styles[tn], function(v) {
27716 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27720 st.store.loadData(avs);
27724 // flag our selected Node.
27725 this.tb.selectedNode = sel;
27728 Roo.menu.MenuMgr.hideAll();
27732 if (!updateFooter) {
27733 //this.footDisp.dom.innerHTML = '';
27736 // update the footer
27740 this.footerEls = ans.reverse();
27741 Roo.each(this.footerEls, function(a,i) {
27742 if (!a) { return; }
27743 html += html.length ? ' > ' : '';
27745 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
27750 var sz = this.footDisp.up('td').getSize();
27751 this.footDisp.dom.style.width = (sz.width -10) + 'px';
27752 this.footDisp.dom.style.marginLeft = '5px';
27754 this.footDisp.dom.style.overflow = 'hidden';
27756 this.footDisp.dom.innerHTML = html;
27758 //this.editorsyncValue();
27765 onDestroy : function(){
27768 this.tb.items.each(function(item){
27770 item.menu.removeAll();
27772 item.menu.el.destroy();
27780 onFirstFocus: function() {
27781 // need to do this for all the toolbars..
27782 this.tb.items.each(function(item){
27786 buildToolbar: function(tlist, nm)
27788 var editor = this.editor;
27789 // create a new element.
27790 var wdiv = editor.wrap.createChild({
27792 }, editor.wrap.dom.firstChild.nextSibling, true);
27795 var tb = new Roo.Toolbar(wdiv);
27798 tb.add(nm+ ": ");
27801 for(var i in this.styles) {
27806 if (styles && styles.length) {
27808 // this needs a multi-select checkbox...
27809 tb.addField( new Roo.form.ComboBox({
27810 store: new Roo.data.SimpleStore({
27812 fields: ['val', 'selected'],
27815 name : '-roo-edit-className',
27816 attrname : 'className',
27817 displayField: 'val',
27821 triggerAction: 'all',
27822 emptyText:'Select Style',
27823 selectOnFocus:true,
27826 'select': function(c, r, i) {
27827 // initial support only for on class per el..
27828 tb.selectedNode.className = r ? r.get('val') : '';
27829 editor.syncValue();
27836 var tbc = Roo.form.HtmlEditor.ToolbarContext;
27837 var tbops = tbc.options;
27839 for (var i in tlist) {
27841 var item = tlist[i];
27842 tb.add(item.title + ": ");
27845 //optname == used so you can configure the options available..
27846 var opts = item.opts ? item.opts : false;
27847 if (item.optname) {
27848 opts = tbops[item.optname];
27853 // opts == pulldown..
27854 tb.addField( new Roo.form.ComboBox({
27855 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
27857 fields: ['val', 'display'],
27860 name : '-roo-edit-' + i,
27862 stylename : item.style ? item.style : false,
27863 displayField: item.displayField ? item.displayField : 'val',
27864 valueField : 'val',
27866 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
27868 triggerAction: 'all',
27869 emptyText:'Select',
27870 selectOnFocus:true,
27871 width: item.width ? item.width : 130,
27873 'select': function(c, r, i) {
27875 tb.selectedNode.style[c.stylename] = r.get('val');
27878 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
27887 tb.addField( new Roo.form.TextField({
27890 //allowBlank:false,
27895 tb.addField( new Roo.form.TextField({
27896 name: '-roo-edit-' + i,
27903 'change' : function(f, nv, ov) {
27904 tb.selectedNode.setAttribute(f.attrname, nv);
27913 text: 'Remove Tag',
27916 click : function ()
27919 // undo does not work.
27921 var sn = tb.selectedNode;
27923 var pn = sn.parentNode;
27925 var stn = sn.childNodes[0];
27926 var en = sn.childNodes[sn.childNodes.length - 1 ];
27927 while (sn.childNodes.length) {
27928 var node = sn.childNodes[0];
27929 sn.removeChild(node);
27931 pn.insertBefore(node, sn);
27934 pn.removeChild(sn);
27935 var range = editor.createRange();
27937 range.setStart(stn,0);
27938 range.setEnd(en,0); //????
27939 //range.selectNode(sel);
27942 var selection = editor.getSelection();
27943 selection.removeAllRanges();
27944 selection.addRange(range);
27948 //_this.updateToolbar(null, null, pn);
27949 _this.updateToolbar(null, null, null);
27950 _this.footDisp.dom.innerHTML = '';
27960 tb.el.on('click', function(e){
27961 e.preventDefault(); // what does this do?
27963 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
27966 // dont need to disable them... as they will get hidden
27971 buildFooter : function()
27974 var fel = this.editor.wrap.createChild();
27975 this.footer = new Roo.Toolbar(fel);
27976 // toolbar has scrolly on left / right?
27977 var footDisp= new Roo.Toolbar.Fill();
27983 handler : function() {
27984 _t.footDisp.scrollTo('left',0,true)
27988 this.footer.add( footDisp );
27993 handler : function() {
27995 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
27999 var fel = Roo.get(footDisp.el);
28000 fel.addClass('x-editor-context');
28001 this.footDispWrap = fel;
28002 this.footDispWrap.overflow = 'hidden';
28004 this.footDisp = fel.createChild();
28005 this.footDispWrap.on('click', this.onContextClick, this)
28009 onContextClick : function (ev,dom)
28011 ev.preventDefault();
28012 var cn = dom.className;
28014 if (!cn.match(/x-ed-loc-/)) {
28017 var n = cn.split('-').pop();
28018 var ans = this.footerEls;
28022 var range = this.editor.createRange();
28024 range.selectNodeContents(sel);
28025 //range.selectNode(sel);
28028 var selection = this.editor.getSelection();
28029 selection.removeAllRanges();
28030 selection.addRange(range);
28034 this.updateToolbar(null, null, sel);
28051 * Ext JS Library 1.1.1
28052 * Copyright(c) 2006-2007, Ext JS, LLC.
28054 * Originally Released Under LGPL - original licence link has changed is not relivant.
28057 * <script type="text/javascript">
28061 * @class Roo.form.BasicForm
28062 * @extends Roo.util.Observable
28063 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
28065 * @param {String/HTMLElement/Roo.Element} el The form element or its id
28066 * @param {Object} config Configuration options
28068 Roo.form.BasicForm = function(el, config){
28069 this.allItems = [];
28070 this.childForms = [];
28071 Roo.apply(this, config);
28073 * The Roo.form.Field items in this form.
28074 * @type MixedCollection
28078 this.items = new Roo.util.MixedCollection(false, function(o){
28079 return o.id || (o.id = Roo.id());
28083 * @event beforeaction
28084 * Fires before any action is performed. Return false to cancel the action.
28085 * @param {Form} this
28086 * @param {Action} action The action to be performed
28088 beforeaction: true,
28090 * @event actionfailed
28091 * Fires when an action fails.
28092 * @param {Form} this
28093 * @param {Action} action The action that failed
28095 actionfailed : true,
28097 * @event actioncomplete
28098 * Fires when an action is completed.
28099 * @param {Form} this
28100 * @param {Action} action The action that completed
28102 actioncomplete : true
28107 Roo.form.BasicForm.superclass.constructor.call(this);
28110 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
28112 * @cfg {String} method
28113 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
28116 * @cfg {DataReader} reader
28117 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
28118 * This is optional as there is built-in support for processing JSON.
28121 * @cfg {DataReader} errorReader
28122 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
28123 * This is completely optional as there is built-in support for processing JSON.
28126 * @cfg {String} url
28127 * The URL to use for form actions if one isn't supplied in the action options.
28130 * @cfg {Boolean} fileUpload
28131 * Set to true if this form is a file upload.
28135 * @cfg {Object} baseParams
28136 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
28141 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
28146 activeAction : null,
28149 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
28150 * or setValues() data instead of when the form was first created.
28152 trackResetOnLoad : false,
28156 * childForms - used for multi-tab forms
28159 childForms : false,
28162 * allItems - full list of fields.
28168 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
28169 * element by passing it or its id or mask the form itself by passing in true.
28172 waitMsgTarget : false,
28175 initEl : function(el){
28176 this.el = Roo.get(el);
28177 this.id = this.el.id || Roo.id();
28178 this.el.on('submit', this.onSubmit, this);
28179 this.el.addClass('x-form');
28183 onSubmit : function(e){
28188 * Returns true if client-side validation on the form is successful.
28191 isValid : function(){
28193 this.items.each(function(f){
28202 * Returns true if any fields in this form have changed since their original load.
28205 isDirty : function(){
28207 this.items.each(function(f){
28217 * Performs a predefined action (submit or load) or custom actions you define on this form.
28218 * @param {String} actionName The name of the action type
28219 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
28220 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
28221 * accept other config options):
28223 Property Type Description
28224 ---------------- --------------- ----------------------------------------------------------------------------------
28225 url String The url for the action (defaults to the form's url)
28226 method String The form method to use (defaults to the form's method, or POST if not defined)
28227 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
28228 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
28229 validate the form on the client (defaults to false)
28231 * @return {BasicForm} this
28233 doAction : function(action, options){
28234 if(typeof action == 'string'){
28235 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
28237 if(this.fireEvent('beforeaction', this, action) !== false){
28238 this.beforeAction(action);
28239 action.run.defer(100, action);
28245 * Shortcut to do a submit action.
28246 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28247 * @return {BasicForm} this
28249 submit : function(options){
28250 this.doAction('submit', options);
28255 * Shortcut to do a load action.
28256 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28257 * @return {BasicForm} this
28259 load : function(options){
28260 this.doAction('load', options);
28265 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
28266 * @param {Record} record The record to edit
28267 * @return {BasicForm} this
28269 updateRecord : function(record){
28270 record.beginEdit();
28271 var fs = record.fields;
28272 fs.each(function(f){
28273 var field = this.findField(f.name);
28275 record.set(f.name, field.getValue());
28283 * Loads an Roo.data.Record into this form.
28284 * @param {Record} record The record to load
28285 * @return {BasicForm} this
28287 loadRecord : function(record){
28288 this.setValues(record.data);
28293 beforeAction : function(action){
28294 var o = action.options;
28297 if(this.waitMsgTarget === true){
28298 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
28299 }else if(this.waitMsgTarget){
28300 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
28301 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
28303 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
28309 afterAction : function(action, success){
28310 this.activeAction = null;
28311 var o = action.options;
28313 if(this.waitMsgTarget === true){
28315 }else if(this.waitMsgTarget){
28316 this.waitMsgTarget.unmask();
28318 Roo.MessageBox.updateProgress(1);
28319 Roo.MessageBox.hide();
28326 Roo.callback(o.success, o.scope, [this, action]);
28327 this.fireEvent('actioncomplete', this, action);
28331 // failure condition..
28332 // we have a scenario where updates need confirming.
28333 // eg. if a locking scenario exists..
28334 // we look for { errors : { needs_confirm : true }} in the response.
28336 (typeof(action.result) != 'undefined') &&
28337 (typeof(action.result.errors) != 'undefined') &&
28338 (typeof(action.result.errors.needs_confirm) != 'undefined')
28341 Roo.MessageBox.confirm(
28342 "Change requires confirmation",
28343 action.result.errorMsg,
28348 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
28358 Roo.callback(o.failure, o.scope, [this, action]);
28359 // show an error message if no failed handler is set..
28360 if (!this.hasListener('actionfailed')) {
28361 Roo.MessageBox.alert("Error",
28362 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
28363 action.result.errorMsg :
28364 "Saving Failed, please check your entries or try again"
28368 this.fireEvent('actionfailed', this, action);
28374 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
28375 * @param {String} id The value to search for
28378 findField : function(id){
28379 var field = this.items.get(id);
28381 this.items.each(function(f){
28382 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
28388 return field || null;
28392 * Add a secondary form to this one,
28393 * Used to provide tabbed forms. One form is primary, with hidden values
28394 * which mirror the elements from the other forms.
28396 * @param {Roo.form.Form} form to add.
28399 addForm : function(form)
28402 if (this.childForms.indexOf(form) > -1) {
28406 this.childForms.push(form);
28408 Roo.each(form.allItems, function (fe) {
28410 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
28411 if (this.findField(n)) { // already added..
28414 var add = new Roo.form.Hidden({
28417 add.render(this.el);
28424 * Mark fields in this form invalid in bulk.
28425 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
28426 * @return {BasicForm} this
28428 markInvalid : function(errors){
28429 if(errors instanceof Array){
28430 for(var i = 0, len = errors.length; i < len; i++){
28431 var fieldError = errors[i];
28432 var f = this.findField(fieldError.id);
28434 f.markInvalid(fieldError.msg);
28440 if(typeof errors[id] != 'function' && (field = this.findField(id))){
28441 field.markInvalid(errors[id]);
28445 Roo.each(this.childForms || [], function (f) {
28446 f.markInvalid(errors);
28453 * Set values for fields in this form in bulk.
28454 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
28455 * @return {BasicForm} this
28457 setValues : function(values){
28458 if(values instanceof Array){ // array of objects
28459 for(var i = 0, len = values.length; i < len; i++){
28461 var f = this.findField(v.id);
28463 f.setValue(v.value);
28464 if(this.trackResetOnLoad){
28465 f.originalValue = f.getValue();
28469 }else{ // object hash
28472 if(typeof values[id] != 'function' && (field = this.findField(id))){
28474 if (field.setFromData &&
28475 field.valueField &&
28476 field.displayField &&
28477 // combos' with local stores can
28478 // be queried via setValue()
28479 // to set their value..
28480 (field.store && !field.store.isLocal)
28484 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
28485 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
28486 field.setFromData(sd);
28489 field.setValue(values[id]);
28493 if(this.trackResetOnLoad){
28494 field.originalValue = field.getValue();
28500 Roo.each(this.childForms || [], function (f) {
28501 f.setValues(values);
28508 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
28509 * they are returned as an array.
28510 * @param {Boolean} asString
28513 getValues : function(asString){
28514 if (this.childForms) {
28515 // copy values from the child forms
28516 Roo.each(this.childForms, function (f) {
28517 this.setValues(f.getValues());
28523 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
28524 if(asString === true){
28527 return Roo.urlDecode(fs);
28531 * Returns the fields in this form as an object with key/value pairs.
28532 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
28535 getFieldValues : function(with_hidden)
28537 if (this.childForms) {
28538 // copy values from the child forms
28539 // should this call getFieldValues - probably not as we do not currently copy
28540 // hidden fields when we generate..
28541 Roo.each(this.childForms, function (f) {
28542 this.setValues(f.getValues());
28547 this.items.each(function(f){
28548 if (!f.getName()) {
28551 var v = f.getValue();
28552 if (f.inputType =='radio') {
28553 if (typeof(ret[f.getName()]) == 'undefined') {
28554 ret[f.getName()] = ''; // empty..
28557 if (!f.el.dom.checked) {
28561 v = f.el.dom.value;
28565 // not sure if this supported any more..
28566 if ((typeof(v) == 'object') && f.getRawValue) {
28567 v = f.getRawValue() ; // dates..
28569 // combo boxes where name != hiddenName...
28570 if (f.name != f.getName()) {
28571 ret[f.name] = f.getRawValue();
28573 ret[f.getName()] = v;
28580 * Clears all invalid messages in this form.
28581 * @return {BasicForm} this
28583 clearInvalid : function(){
28584 this.items.each(function(f){
28588 Roo.each(this.childForms || [], function (f) {
28597 * Resets this form.
28598 * @return {BasicForm} this
28600 reset : function(){
28601 this.items.each(function(f){
28605 Roo.each(this.childForms || [], function (f) {
28614 * Add Roo.form components to this form.
28615 * @param {Field} field1
28616 * @param {Field} field2 (optional)
28617 * @param {Field} etc (optional)
28618 * @return {BasicForm} this
28621 this.items.addAll(Array.prototype.slice.call(arguments, 0));
28627 * Removes a field from the items collection (does NOT remove its markup).
28628 * @param {Field} field
28629 * @return {BasicForm} this
28631 remove : function(field){
28632 this.items.remove(field);
28637 * Looks at the fields in this form, checks them for an id attribute,
28638 * and calls applyTo on the existing dom element with that id.
28639 * @return {BasicForm} this
28641 render : function(){
28642 this.items.each(function(f){
28643 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
28651 * Calls {@link Ext#apply} for all fields in this form with the passed object.
28652 * @param {Object} values
28653 * @return {BasicForm} this
28655 applyToFields : function(o){
28656 this.items.each(function(f){
28663 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
28664 * @param {Object} values
28665 * @return {BasicForm} this
28667 applyIfToFields : function(o){
28668 this.items.each(function(f){
28676 Roo.BasicForm = Roo.form.BasicForm;/*
28678 * Ext JS Library 1.1.1
28679 * Copyright(c) 2006-2007, Ext JS, LLC.
28681 * Originally Released Under LGPL - original licence link has changed is not relivant.
28684 * <script type="text/javascript">
28688 * @class Roo.form.Form
28689 * @extends Roo.form.BasicForm
28690 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
28692 * @param {Object} config Configuration options
28694 Roo.form.Form = function(config){
28696 if (config.items) {
28697 xitems = config.items;
28698 delete config.items;
28702 Roo.form.Form.superclass.constructor.call(this, null, config);
28703 this.url = this.url || this.action;
28705 this.root = new Roo.form.Layout(Roo.applyIf({
28709 this.active = this.root;
28711 * Array of all the buttons that have been added to this form via {@link addButton}
28715 this.allItems = [];
28718 * @event clientvalidation
28719 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
28720 * @param {Form} this
28721 * @param {Boolean} valid true if the form has passed client-side validation
28723 clientvalidation: true,
28726 * Fires when the form is rendered
28727 * @param {Roo.form.Form} form
28732 if (this.progressUrl) {
28733 // push a hidden field onto the list of fields..
28737 name : 'UPLOAD_IDENTIFIER'
28742 Roo.each(xitems, this.addxtype, this);
28748 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
28750 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
28753 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
28756 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
28758 buttonAlign:'center',
28761 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
28766 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
28767 * This property cascades to child containers if not set.
28772 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
28773 * fires a looping event with that state. This is required to bind buttons to the valid
28774 * state using the config value formBind:true on the button.
28776 monitorValid : false,
28779 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
28784 * @cfg {String} progressUrl - Url to return progress data
28787 progressUrl : false,
28790 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
28791 * fields are added and the column is closed. If no fields are passed the column remains open
28792 * until end() is called.
28793 * @param {Object} config The config to pass to the column
28794 * @param {Field} field1 (optional)
28795 * @param {Field} field2 (optional)
28796 * @param {Field} etc (optional)
28797 * @return Column The column container object
28799 column : function(c){
28800 var col = new Roo.form.Column(c);
28802 if(arguments.length > 1){ // duplicate code required because of Opera
28803 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28810 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
28811 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
28812 * until end() is called.
28813 * @param {Object} config The config to pass to the fieldset
28814 * @param {Field} field1 (optional)
28815 * @param {Field} field2 (optional)
28816 * @param {Field} etc (optional)
28817 * @return FieldSet The fieldset container object
28819 fieldset : function(c){
28820 var fs = new Roo.form.FieldSet(c);
28822 if(arguments.length > 1){ // duplicate code required because of Opera
28823 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28830 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
28831 * fields are added and the container is closed. If no fields are passed the container remains open
28832 * until end() is called.
28833 * @param {Object} config The config to pass to the Layout
28834 * @param {Field} field1 (optional)
28835 * @param {Field} field2 (optional)
28836 * @param {Field} etc (optional)
28837 * @return Layout The container object
28839 container : function(c){
28840 var l = new Roo.form.Layout(c);
28842 if(arguments.length > 1){ // duplicate code required because of Opera
28843 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28850 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
28851 * @param {Object} container A Roo.form.Layout or subclass of Layout
28852 * @return {Form} this
28854 start : function(c){
28855 // cascade label info
28856 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
28857 this.active.stack.push(c);
28858 c.ownerCt = this.active;
28864 * Closes the current open container
28865 * @return {Form} this
28868 if(this.active == this.root){
28871 this.active = this.active.ownerCt;
28876 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
28877 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
28878 * as the label of the field.
28879 * @param {Field} field1
28880 * @param {Field} field2 (optional)
28881 * @param {Field} etc. (optional)
28882 * @return {Form} this
28885 this.active.stack.push.apply(this.active.stack, arguments);
28886 this.allItems.push.apply(this.allItems,arguments);
28888 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
28889 if(a[i].isFormField){
28894 Roo.form.Form.superclass.add.apply(this, r);
28904 * Find any element that has been added to a form, using it's ID or name
28905 * This can include framesets, columns etc. along with regular fields..
28906 * @param {String} id - id or name to find.
28908 * @return {Element} e - or false if nothing found.
28910 findbyId : function(id)
28916 Roo.each(this.allItems, function(f){
28917 if (f.id == id || f.name == id ){
28928 * Render this form into the passed container. This should only be called once!
28929 * @param {String/HTMLElement/Element} container The element this component should be rendered into
28930 * @return {Form} this
28932 render : function(ct)
28938 var o = this.autoCreate || {
28940 method : this.method || 'POST',
28941 id : this.id || Roo.id()
28943 this.initEl(ct.createChild(o));
28945 this.root.render(this.el);
28949 this.items.each(function(f){
28950 f.render('x-form-el-'+f.id);
28953 if(this.buttons.length > 0){
28954 // tables are required to maintain order and for correct IE layout
28955 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
28956 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
28957 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28959 var tr = tb.getElementsByTagName('tr')[0];
28960 for(var i = 0, len = this.buttons.length; i < len; i++) {
28961 var b = this.buttons[i];
28962 var td = document.createElement('td');
28963 td.className = 'x-form-btn-td';
28964 b.render(tr.appendChild(td));
28967 if(this.monitorValid){ // initialize after render
28968 this.startMonitoring();
28970 this.fireEvent('rendered', this);
28975 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
28976 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28977 * object or a valid Roo.DomHelper element config
28978 * @param {Function} handler The function called when the button is clicked
28979 * @param {Object} scope (optional) The scope of the handler function
28980 * @return {Roo.Button}
28982 addButton : function(config, handler, scope){
28986 minWidth: this.minButtonWidth,
28989 if(typeof config == "string"){
28992 Roo.apply(bc, config);
28994 var btn = new Roo.Button(null, bc);
28995 this.buttons.push(btn);
29000 * Adds a series of form elements (using the xtype property as the factory method.
29001 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
29002 * @param {Object} config
29005 addxtype : function()
29007 var ar = Array.prototype.slice.call(arguments, 0);
29009 for(var i = 0; i < ar.length; i++) {
29011 continue; // skip -- if this happends something invalid got sent, we
29012 // should ignore it, as basically that interface element will not show up
29013 // and that should be pretty obvious!!
29016 if (Roo.form[ar[i].xtype]) {
29018 var fe = Roo.factory(ar[i], Roo.form);
29024 fe.store.form = this;
29029 this.allItems.push(fe);
29030 if (fe.items && fe.addxtype) {
29031 fe.addxtype.apply(fe, fe.items);
29041 // console.log('adding ' + ar[i].xtype);
29043 if (ar[i].xtype == 'Button') {
29044 //console.log('adding button');
29045 //console.log(ar[i]);
29046 this.addButton(ar[i]);
29047 this.allItems.push(fe);
29051 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
29052 alert('end is not supported on xtype any more, use items');
29054 // //console.log('adding end');
29062 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
29063 * option "monitorValid"
29065 startMonitoring : function(){
29068 Roo.TaskMgr.start({
29069 run : this.bindHandler,
29070 interval : this.monitorPoll || 200,
29077 * Stops monitoring of the valid state of this form
29079 stopMonitoring : function(){
29080 this.bound = false;
29084 bindHandler : function(){
29086 return false; // stops binding
29089 this.items.each(function(f){
29090 if(!f.isValid(true)){
29095 for(var i = 0, len = this.buttons.length; i < len; i++){
29096 var btn = this.buttons[i];
29097 if(btn.formBind === true && btn.disabled === valid){
29098 btn.setDisabled(!valid);
29101 this.fireEvent('clientvalidation', this, valid);
29115 Roo.Form = Roo.form.Form;
29118 * Ext JS Library 1.1.1
29119 * Copyright(c) 2006-2007, Ext JS, LLC.
29121 * Originally Released Under LGPL - original licence link has changed is not relivant.
29124 * <script type="text/javascript">
29128 * @class Roo.form.Action
29129 * Internal Class used to handle form actions
29131 * @param {Roo.form.BasicForm} el The form element or its id
29132 * @param {Object} config Configuration options
29136 // define the action interface
29137 Roo.form.Action = function(form, options){
29139 this.options = options || {};
29142 * Client Validation Failed
29145 Roo.form.Action.CLIENT_INVALID = 'client';
29147 * Server Validation Failed
29150 Roo.form.Action.SERVER_INVALID = 'server';
29152 * Connect to Server Failed
29155 Roo.form.Action.CONNECT_FAILURE = 'connect';
29157 * Reading Data from Server Failed
29160 Roo.form.Action.LOAD_FAILURE = 'load';
29162 Roo.form.Action.prototype = {
29164 failureType : undefined,
29165 response : undefined,
29166 result : undefined,
29168 // interface method
29169 run : function(options){
29173 // interface method
29174 success : function(response){
29178 // interface method
29179 handleResponse : function(response){
29183 // default connection failure
29184 failure : function(response){
29186 this.response = response;
29187 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29188 this.form.afterAction(this, false);
29191 processResponse : function(response){
29192 this.response = response;
29193 if(!response.responseText){
29196 this.result = this.handleResponse(response);
29197 return this.result;
29200 // utility functions used internally
29201 getUrl : function(appendParams){
29202 var url = this.options.url || this.form.url || this.form.el.dom.action;
29204 var p = this.getParams();
29206 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
29212 getMethod : function(){
29213 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
29216 getParams : function(){
29217 var bp = this.form.baseParams;
29218 var p = this.options.params;
29220 if(typeof p == "object"){
29221 p = Roo.urlEncode(Roo.applyIf(p, bp));
29222 }else if(typeof p == 'string' && bp){
29223 p += '&' + Roo.urlEncode(bp);
29226 p = Roo.urlEncode(bp);
29231 createCallback : function(){
29233 success: this.success,
29234 failure: this.failure,
29236 timeout: (this.form.timeout*1000),
29237 upload: this.form.fileUpload ? this.success : undefined
29242 Roo.form.Action.Submit = function(form, options){
29243 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
29246 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
29249 haveProgress : false,
29250 uploadComplete : false,
29252 // uploadProgress indicator.
29253 uploadProgress : function()
29255 if (!this.form.progressUrl) {
29259 if (!this.haveProgress) {
29260 Roo.MessageBox.progress("Uploading", "Uploading");
29262 if (this.uploadComplete) {
29263 Roo.MessageBox.hide();
29267 this.haveProgress = true;
29269 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
29271 var c = new Roo.data.Connection();
29273 url : this.form.progressUrl,
29278 success : function(req){
29279 //console.log(data);
29283 rdata = Roo.decode(req.responseText)
29285 Roo.log("Invalid data from server..");
29289 if (!rdata || !rdata.success) {
29291 Roo.MessageBox.alert(Roo.encode(rdata));
29294 var data = rdata.data;
29296 if (this.uploadComplete) {
29297 Roo.MessageBox.hide();
29302 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
29303 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
29306 this.uploadProgress.defer(2000,this);
29309 failure: function(data) {
29310 Roo.log('progress url failed ');
29321 // run get Values on the form, so it syncs any secondary forms.
29322 this.form.getValues();
29324 var o = this.options;
29325 var method = this.getMethod();
29326 var isPost = method == 'POST';
29327 if(o.clientValidation === false || this.form.isValid()){
29329 if (this.form.progressUrl) {
29330 this.form.findField('UPLOAD_IDENTIFIER').setValue(
29331 (new Date() * 1) + '' + Math.random());
29336 Roo.Ajax.request(Roo.apply(this.createCallback(), {
29337 form:this.form.el.dom,
29338 url:this.getUrl(!isPost),
29340 params:isPost ? this.getParams() : null,
29341 isUpload: this.form.fileUpload
29344 this.uploadProgress();
29346 }else if (o.clientValidation !== false){ // client validation failed
29347 this.failureType = Roo.form.Action.CLIENT_INVALID;
29348 this.form.afterAction(this, false);
29352 success : function(response)
29354 this.uploadComplete= true;
29355 if (this.haveProgress) {
29356 Roo.MessageBox.hide();
29360 var result = this.processResponse(response);
29361 if(result === true || result.success){
29362 this.form.afterAction(this, true);
29366 this.form.markInvalid(result.errors);
29367 this.failureType = Roo.form.Action.SERVER_INVALID;
29369 this.form.afterAction(this, false);
29371 failure : function(response)
29373 this.uploadComplete= true;
29374 if (this.haveProgress) {
29375 Roo.MessageBox.hide();
29378 this.response = response;
29379 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29380 this.form.afterAction(this, false);
29383 handleResponse : function(response){
29384 if(this.form.errorReader){
29385 var rs = this.form.errorReader.read(response);
29388 for(var i = 0, len = rs.records.length; i < len; i++) {
29389 var r = rs.records[i];
29390 errors[i] = r.data;
29393 if(errors.length < 1){
29397 success : rs.success,
29403 ret = Roo.decode(response.responseText);
29407 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
29417 Roo.form.Action.Load = function(form, options){
29418 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
29419 this.reader = this.form.reader;
29422 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
29427 Roo.Ajax.request(Roo.apply(
29428 this.createCallback(), {
29429 method:this.getMethod(),
29430 url:this.getUrl(false),
29431 params:this.getParams()
29435 success : function(response){
29437 var result = this.processResponse(response);
29438 if(result === true || !result.success || !result.data){
29439 this.failureType = Roo.form.Action.LOAD_FAILURE;
29440 this.form.afterAction(this, false);
29443 this.form.clearInvalid();
29444 this.form.setValues(result.data);
29445 this.form.afterAction(this, true);
29448 handleResponse : function(response){
29449 if(this.form.reader){
29450 var rs = this.form.reader.read(response);
29451 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
29453 success : rs.success,
29457 return Roo.decode(response.responseText);
29461 Roo.form.Action.ACTION_TYPES = {
29462 'load' : Roo.form.Action.Load,
29463 'submit' : Roo.form.Action.Submit
29466 * Ext JS Library 1.1.1
29467 * Copyright(c) 2006-2007, Ext JS, LLC.
29469 * Originally Released Under LGPL - original licence link has changed is not relivant.
29472 * <script type="text/javascript">
29476 * @class Roo.form.Layout
29477 * @extends Roo.Component
29478 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
29480 * @param {Object} config Configuration options
29482 Roo.form.Layout = function(config){
29484 if (config.items) {
29485 xitems = config.items;
29486 delete config.items;
29488 Roo.form.Layout.superclass.constructor.call(this, config);
29490 Roo.each(xitems, this.addxtype, this);
29494 Roo.extend(Roo.form.Layout, Roo.Component, {
29496 * @cfg {String/Object} autoCreate
29497 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
29500 * @cfg {String/Object/Function} style
29501 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
29502 * a function which returns such a specification.
29505 * @cfg {String} labelAlign
29506 * Valid values are "left," "top" and "right" (defaults to "left")
29509 * @cfg {Number} labelWidth
29510 * Fixed width in pixels of all field labels (defaults to undefined)
29513 * @cfg {Boolean} clear
29514 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
29518 * @cfg {String} labelSeparator
29519 * The separator to use after field labels (defaults to ':')
29521 labelSeparator : ':',
29523 * @cfg {Boolean} hideLabels
29524 * True to suppress the display of field labels in this layout (defaults to false)
29526 hideLabels : false,
29529 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
29534 onRender : function(ct, position){
29535 if(this.el){ // from markup
29536 this.el = Roo.get(this.el);
29537 }else { // generate
29538 var cfg = this.getAutoCreate();
29539 this.el = ct.createChild(cfg, position);
29542 this.el.applyStyles(this.style);
29544 if(this.labelAlign){
29545 this.el.addClass('x-form-label-'+this.labelAlign);
29547 if(this.hideLabels){
29548 this.labelStyle = "display:none";
29549 this.elementStyle = "padding-left:0;";
29551 if(typeof this.labelWidth == 'number'){
29552 this.labelStyle = "width:"+this.labelWidth+"px;";
29553 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
29555 if(this.labelAlign == 'top'){
29556 this.labelStyle = "width:auto;";
29557 this.elementStyle = "padding-left:0;";
29560 var stack = this.stack;
29561 var slen = stack.length;
29563 if(!this.fieldTpl){
29564 var t = new Roo.Template(
29565 '<div class="x-form-item {5}">',
29566 '<label for="{0}" style="{2}">{1}{4}</label>',
29567 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29569 '</div><div class="x-form-clear-left"></div>'
29571 t.disableFormats = true;
29573 Roo.form.Layout.prototype.fieldTpl = t;
29575 for(var i = 0; i < slen; i++) {
29576 if(stack[i].isFormField){
29577 this.renderField(stack[i]);
29579 this.renderComponent(stack[i]);
29584 this.el.createChild({cls:'x-form-clear'});
29589 renderField : function(f){
29590 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
29593 f.labelStyle||this.labelStyle||'', //2
29594 this.elementStyle||'', //3
29595 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
29596 f.itemCls||this.itemCls||'' //5
29597 ], true).getPrevSibling());
29601 renderComponent : function(c){
29602 c.render(c.isLayout ? this.el : this.el.createChild());
29605 * Adds a object form elements (using the xtype property as the factory method.)
29606 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
29607 * @param {Object} config
29609 addxtype : function(o)
29611 // create the lement.
29612 o.form = this.form;
29613 var fe = Roo.factory(o, Roo.form);
29614 this.form.allItems.push(fe);
29615 this.stack.push(fe);
29617 if (fe.isFormField) {
29618 this.form.items.add(fe);
29626 * @class Roo.form.Column
29627 * @extends Roo.form.Layout
29628 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
29630 * @param {Object} config Configuration options
29632 Roo.form.Column = function(config){
29633 Roo.form.Column.superclass.constructor.call(this, config);
29636 Roo.extend(Roo.form.Column, Roo.form.Layout, {
29638 * @cfg {Number/String} width
29639 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29642 * @cfg {String/Object} autoCreate
29643 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
29647 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
29650 onRender : function(ct, position){
29651 Roo.form.Column.superclass.onRender.call(this, ct, position);
29653 this.el.setWidth(this.width);
29660 * @class Roo.form.Row
29661 * @extends Roo.form.Layout
29662 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
29664 * @param {Object} config Configuration options
29668 Roo.form.Row = function(config){
29669 Roo.form.Row.superclass.constructor.call(this, config);
29672 Roo.extend(Roo.form.Row, Roo.form.Layout, {
29674 * @cfg {Number/String} width
29675 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29678 * @cfg {Number/String} height
29679 * The fixed height of the column in pixels or CSS value (defaults to "auto")
29681 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
29685 onRender : function(ct, position){
29686 //console.log('row render');
29688 var t = new Roo.Template(
29689 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
29690 '<label for="{0}" style="{2}">{1}{4}</label>',
29691 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29695 t.disableFormats = true;
29697 Roo.form.Layout.prototype.rowTpl = t;
29699 this.fieldTpl = this.rowTpl;
29701 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
29702 var labelWidth = 100;
29704 if ((this.labelAlign != 'top')) {
29705 if (typeof this.labelWidth == 'number') {
29706 labelWidth = this.labelWidth
29708 this.padWidth = 20 + labelWidth;
29712 Roo.form.Column.superclass.onRender.call(this, ct, position);
29714 this.el.setWidth(this.width);
29717 this.el.setHeight(this.height);
29722 renderField : function(f){
29723 f.fieldEl = this.fieldTpl.append(this.el, [
29724 f.id, f.fieldLabel,
29725 f.labelStyle||this.labelStyle||'',
29726 this.elementStyle||'',
29727 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
29728 f.itemCls||this.itemCls||'',
29729 f.width ? f.width + this.padWidth : 160 + this.padWidth
29736 * @class Roo.form.FieldSet
29737 * @extends Roo.form.Layout
29738 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
29740 * @param {Object} config Configuration options
29742 Roo.form.FieldSet = function(config){
29743 Roo.form.FieldSet.superclass.constructor.call(this, config);
29746 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
29748 * @cfg {String} legend
29749 * The text to display as the legend for the FieldSet (defaults to '')
29752 * @cfg {String/Object} autoCreate
29753 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
29757 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
29760 onRender : function(ct, position){
29761 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
29763 this.setLegend(this.legend);
29768 setLegend : function(text){
29770 this.el.child('legend').update(text);
29775 * Ext JS Library 1.1.1
29776 * Copyright(c) 2006-2007, Ext JS, LLC.
29778 * Originally Released Under LGPL - original licence link has changed is not relivant.
29781 * <script type="text/javascript">
29784 * @class Roo.form.VTypes
29785 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
29788 Roo.form.VTypes = function(){
29789 // closure these in so they are only created once.
29790 var alpha = /^[a-zA-Z_]+$/;
29791 var alphanum = /^[a-zA-Z0-9_]+$/;
29792 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
29793 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
29795 // All these messages and functions are configurable
29798 * The function used to validate email addresses
29799 * @param {String} value The email address
29801 'email' : function(v){
29802 return email.test(v);
29805 * The error text to display when the email validation function returns false
29808 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
29810 * The keystroke filter mask to be applied on email input
29813 'emailMask' : /[a-z0-9_\.\-@]/i,
29816 * The function used to validate URLs
29817 * @param {String} value The URL
29819 'url' : function(v){
29820 return url.test(v);
29823 * The error text to display when the url validation function returns false
29826 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
29829 * The function used to validate alpha values
29830 * @param {String} value The value
29832 'alpha' : function(v){
29833 return alpha.test(v);
29836 * The error text to display when the alpha validation function returns false
29839 'alphaText' : 'This field should only contain letters and _',
29841 * The keystroke filter mask to be applied on alpha input
29844 'alphaMask' : /[a-z_]/i,
29847 * The function used to validate alphanumeric values
29848 * @param {String} value The value
29850 'alphanum' : function(v){
29851 return alphanum.test(v);
29854 * The error text to display when the alphanumeric validation function returns false
29857 'alphanumText' : 'This field should only contain letters, numbers and _',
29859 * The keystroke filter mask to be applied on alphanumeric input
29862 'alphanumMask' : /[a-z0-9_]/i
29864 }();//<script type="text/javascript">
29867 * @class Roo.form.FCKeditor
29868 * @extends Roo.form.TextArea
29869 * Wrapper around the FCKEditor http://www.fckeditor.net
29871 * Creates a new FCKeditor
29872 * @param {Object} config Configuration options
29874 Roo.form.FCKeditor = function(config){
29875 Roo.form.FCKeditor.superclass.constructor.call(this, config);
29878 * @event editorinit
29879 * Fired when the editor is initialized - you can add extra handlers here..
29880 * @param {FCKeditor} this
29881 * @param {Object} the FCK object.
29888 Roo.form.FCKeditor.editors = { };
29889 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
29891 //defaultAutoCreate : {
29892 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
29896 * @cfg {Object} fck options - see fck manual for details.
29901 * @cfg {Object} fck toolbar set (Basic or Default)
29903 toolbarSet : 'Basic',
29905 * @cfg {Object} fck BasePath
29907 basePath : '/fckeditor/',
29915 onRender : function(ct, position)
29918 this.defaultAutoCreate = {
29920 style:"width:300px;height:60px;",
29921 autocomplete: "off"
29924 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
29927 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
29928 if(this.preventScrollbars){
29929 this.el.setStyle("overflow", "hidden");
29931 this.el.setHeight(this.growMin);
29934 //console.log('onrender' + this.getId() );
29935 Roo.form.FCKeditor.editors[this.getId()] = this;
29938 this.replaceTextarea() ;
29942 getEditor : function() {
29943 return this.fckEditor;
29946 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
29947 * @param {Mixed} value The value to set
29951 setValue : function(value)
29953 //console.log('setValue: ' + value);
29955 if(typeof(value) == 'undefined') { // not sure why this is happending...
29958 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29960 //if(!this.el || !this.getEditor()) {
29961 // this.value = value;
29962 //this.setValue.defer(100,this,[value]);
29966 if(!this.getEditor()) {
29970 this.getEditor().SetData(value);
29977 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
29978 * @return {Mixed} value The field value
29980 getValue : function()
29983 if (this.frame && this.frame.dom.style.display == 'none') {
29984 return Roo.form.FCKeditor.superclass.getValue.call(this);
29987 if(!this.el || !this.getEditor()) {
29989 // this.getValue.defer(100,this);
29994 var value=this.getEditor().GetData();
29995 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29996 return Roo.form.FCKeditor.superclass.getValue.call(this);
30002 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
30003 * @return {Mixed} value The field value
30005 getRawValue : function()
30007 if (this.frame && this.frame.dom.style.display == 'none') {
30008 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
30011 if(!this.el || !this.getEditor()) {
30012 //this.getRawValue.defer(100,this);
30019 var value=this.getEditor().GetData();
30020 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
30021 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
30025 setSize : function(w,h) {
30029 //if (this.frame && this.frame.dom.style.display == 'none') {
30030 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30033 //if(!this.el || !this.getEditor()) {
30034 // this.setSize.defer(100,this, [w,h]);
30040 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30042 this.frame.dom.setAttribute('width', w);
30043 this.frame.dom.setAttribute('height', h);
30044 this.frame.setSize(w,h);
30048 toggleSourceEdit : function(value) {
30052 this.el.dom.style.display = value ? '' : 'none';
30053 this.frame.dom.style.display = value ? 'none' : '';
30058 focus: function(tag)
30060 if (this.frame.dom.style.display == 'none') {
30061 return Roo.form.FCKeditor.superclass.focus.call(this);
30063 if(!this.el || !this.getEditor()) {
30064 this.focus.defer(100,this, [tag]);
30071 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
30072 this.getEditor().Focus();
30074 if (!this.getEditor().Selection.GetSelection()) {
30075 this.focus.defer(100,this, [tag]);
30080 var r = this.getEditor().EditorDocument.createRange();
30081 r.setStart(tgs[0],0);
30082 r.setEnd(tgs[0],0);
30083 this.getEditor().Selection.GetSelection().removeAllRanges();
30084 this.getEditor().Selection.GetSelection().addRange(r);
30085 this.getEditor().Focus();
30092 replaceTextarea : function()
30094 if ( document.getElementById( this.getId() + '___Frame' ) )
30096 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
30098 // We must check the elements firstly using the Id and then the name.
30099 var oTextarea = document.getElementById( this.getId() );
30101 var colElementsByName = document.getElementsByName( this.getId() ) ;
30103 oTextarea.style.display = 'none' ;
30105 if ( oTextarea.tabIndex ) {
30106 this.TabIndex = oTextarea.tabIndex ;
30109 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
30110 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
30111 this.frame = Roo.get(this.getId() + '___Frame')
30114 _getConfigHtml : function()
30118 for ( var o in this.fckconfig ) {
30119 sConfig += sConfig.length > 0 ? '&' : '';
30120 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
30123 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
30127 _getIFrameHtml : function()
30129 var sFile = 'fckeditor.html' ;
30130 /* no idea what this is about..
30133 if ( (/fcksource=true/i).test( window.top.location.search ) )
30134 sFile = 'fckeditor.original.html' ;
30139 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
30140 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
30143 var html = '<iframe id="' + this.getId() +
30144 '___Frame" src="' + sLink +
30145 '" width="' + this.width +
30146 '" height="' + this.height + '"' +
30147 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
30148 ' frameborder="0" scrolling="no"></iframe>' ;
30153 _insertHtmlBefore : function( html, element )
30155 if ( element.insertAdjacentHTML ) {
30157 element.insertAdjacentHTML( 'beforeBegin', html ) ;
30159 var oRange = document.createRange() ;
30160 oRange.setStartBefore( element ) ;
30161 var oFragment = oRange.createContextualFragment( html );
30162 element.parentNode.insertBefore( oFragment, element ) ;
30175 //Roo.reg('fckeditor', Roo.form.FCKeditor);
30177 function FCKeditor_OnComplete(editorInstance){
30178 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
30179 f.fckEditor = editorInstance;
30180 //console.log("loaded");
30181 f.fireEvent('editorinit', f, editorInstance);
30201 //<script type="text/javascript">
30203 * @class Roo.form.GridField
30204 * @extends Roo.form.Field
30205 * Embed a grid (or editable grid into a form)
30208 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
30210 * xgrid.store = Roo.data.Store
30211 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
30212 * xgrid.store.reader = Roo.data.JsonReader
30216 * Creates a new GridField
30217 * @param {Object} config Configuration options
30219 Roo.form.GridField = function(config){
30220 Roo.form.GridField.superclass.constructor.call(this, config);
30224 Roo.extend(Roo.form.GridField, Roo.form.Field, {
30226 * @cfg {Number} width - used to restrict width of grid..
30230 * @cfg {Number} height - used to restrict height of grid..
30234 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
30240 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30241 * {tag: "input", type: "checkbox", autocomplete: "off"})
30243 // defaultAutoCreate : { tag: 'div' },
30244 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30246 * @cfg {String} addTitle Text to include for adding a title.
30250 onResize : function(){
30251 Roo.form.Field.superclass.onResize.apply(this, arguments);
30254 initEvents : function(){
30255 // Roo.form.Checkbox.superclass.initEvents.call(this);
30256 // has no events...
30261 getResizeEl : function(){
30265 getPositionEl : function(){
30270 onRender : function(ct, position){
30272 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
30273 var style = this.style;
30276 Roo.form.GridField.superclass.onRender.call(this, ct, position);
30277 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
30278 this.viewEl = this.wrap.createChild({ tag: 'div' });
30280 this.viewEl.applyStyles(style);
30283 this.viewEl.setWidth(this.width);
30286 this.viewEl.setHeight(this.height);
30288 //if(this.inputValue !== undefined){
30289 //this.setValue(this.value);
30292 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
30295 this.grid.render();
30296 this.grid.getDataSource().on('remove', this.refreshValue, this);
30297 this.grid.getDataSource().on('update', this.refreshValue, this);
30298 this.grid.on('afteredit', this.refreshValue, this);
30304 * Sets the value of the item.
30305 * @param {String} either an object or a string..
30307 setValue : function(v){
30309 v = v || []; // empty set..
30310 // this does not seem smart - it really only affects memoryproxy grids..
30311 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
30312 var ds = this.grid.getDataSource();
30313 // assumes a json reader..
30315 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
30316 ds.loadData( data);
30318 // clear selection so it does not get stale.
30319 if (this.grid.sm) {
30320 this.grid.sm.clearSelections();
30323 Roo.form.GridField.superclass.setValue.call(this, v);
30324 this.refreshValue();
30325 // should load data in the grid really....
30329 refreshValue: function() {
30331 this.grid.getDataSource().each(function(r) {
30334 this.el.dom.value = Roo.encode(val);
30342 * Ext JS Library 1.1.1
30343 * Copyright(c) 2006-2007, Ext JS, LLC.
30345 * Originally Released Under LGPL - original licence link has changed is not relivant.
30348 * <script type="text/javascript">
30351 * @class Roo.form.DisplayField
30352 * @extends Roo.form.Field
30353 * A generic Field to display non-editable data.
30355 * Creates a new Display Field item.
30356 * @param {Object} config Configuration options
30358 Roo.form.DisplayField = function(config){
30359 Roo.form.DisplayField.superclass.constructor.call(this, config);
30363 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
30364 inputType: 'hidden',
30370 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30372 focusClass : undefined,
30374 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30376 fieldClass: 'x-form-field',
30379 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
30381 valueRenderer: undefined,
30385 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30386 * {tag: "input", type: "checkbox", autocomplete: "off"})
30389 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30391 onResize : function(){
30392 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
30396 initEvents : function(){
30397 // Roo.form.Checkbox.superclass.initEvents.call(this);
30398 // has no events...
30403 getResizeEl : function(){
30407 getPositionEl : function(){
30412 onRender : function(ct, position){
30414 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
30415 //if(this.inputValue !== undefined){
30416 this.wrap = this.el.wrap();
30418 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
30420 if (this.bodyStyle) {
30421 this.viewEl.applyStyles(this.bodyStyle);
30423 //this.viewEl.setStyle('padding', '2px');
30425 this.setValue(this.value);
30430 initValue : Roo.emptyFn,
30435 onClick : function(){
30440 * Sets the checked state of the checkbox.
30441 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
30443 setValue : function(v){
30445 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
30446 // this might be called before we have a dom element..
30447 if (!this.viewEl) {
30450 this.viewEl.dom.innerHTML = html;
30451 Roo.form.DisplayField.superclass.setValue.call(this, v);
30461 * @class Roo.form.DayPicker
30462 * @extends Roo.form.Field
30463 * A Day picker show [M] [T] [W] ....
30465 * Creates a new Day Picker
30466 * @param {Object} config Configuration options
30468 Roo.form.DayPicker= function(config){
30469 Roo.form.DayPicker.superclass.constructor.call(this, config);
30473 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
30475 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30477 focusClass : undefined,
30479 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30481 fieldClass: "x-form-field",
30484 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30485 * {tag: "input", type: "checkbox", autocomplete: "off"})
30487 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
30490 actionMode : 'viewEl',
30494 inputType : 'hidden',
30497 inputElement: false, // real input element?
30498 basedOn: false, // ????
30500 isFormField: true, // not sure where this is needed!!!!
30502 onResize : function(){
30503 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
30504 if(!this.boxLabel){
30505 this.el.alignTo(this.wrap, 'c-c');
30509 initEvents : function(){
30510 Roo.form.Checkbox.superclass.initEvents.call(this);
30511 this.el.on("click", this.onClick, this);
30512 this.el.on("change", this.onClick, this);
30516 getResizeEl : function(){
30520 getPositionEl : function(){
30526 onRender : function(ct, position){
30527 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
30529 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
30531 var r1 = '<table><tr>';
30532 var r2 = '<tr class="x-form-daypick-icons">';
30533 for (var i=0; i < 7; i++) {
30534 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
30535 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
30538 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
30539 viewEl.select('img').on('click', this.onClick, this);
30540 this.viewEl = viewEl;
30543 // this will not work on Chrome!!!
30544 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
30545 this.el.on('propertychange', this.setFromHidden, this); //ie
30553 initValue : Roo.emptyFn,
30556 * Returns the checked state of the checkbox.
30557 * @return {Boolean} True if checked, else false
30559 getValue : function(){
30560 return this.el.dom.value;
30565 onClick : function(e){
30566 //this.setChecked(!this.checked);
30567 Roo.get(e.target).toggleClass('x-menu-item-checked');
30568 this.refreshValue();
30569 //if(this.el.dom.checked != this.checked){
30570 // this.setValue(this.el.dom.checked);
30575 refreshValue : function()
30578 this.viewEl.select('img',true).each(function(e,i,n) {
30579 val += e.is(".x-menu-item-checked") ? String(n) : '';
30581 this.setValue(val, true);
30585 * Sets the checked state of the checkbox.
30586 * On is always based on a string comparison between inputValue and the param.
30587 * @param {Boolean/String} value - the value to set
30588 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
30590 setValue : function(v,suppressEvent){
30591 if (!this.el.dom) {
30594 var old = this.el.dom.value ;
30595 this.el.dom.value = v;
30596 if (suppressEvent) {
30600 // update display..
30601 this.viewEl.select('img',true).each(function(e,i,n) {
30603 var on = e.is(".x-menu-item-checked");
30604 var newv = v.indexOf(String(n)) > -1;
30606 e.toggleClass('x-menu-item-checked');
30612 this.fireEvent('change', this, v, old);
30617 // handle setting of hidden value by some other method!!?!?
30618 setFromHidden: function()
30623 //console.log("SET FROM HIDDEN");
30624 //alert('setFrom hidden');
30625 this.setValue(this.el.dom.value);
30628 onDestroy : function()
30631 Roo.get(this.viewEl).remove();
30634 Roo.form.DayPicker.superclass.onDestroy.call(this);
30638 * RooJS Library 1.1.1
30639 * Copyright(c) 2008-2011 Alan Knowles
30646 * @class Roo.form.ComboCheck
30647 * @extends Roo.form.ComboBox
30648 * A combobox for multiple select items.
30650 * FIXME - could do with a reset button..
30653 * Create a new ComboCheck
30654 * @param {Object} config Configuration options
30656 Roo.form.ComboCheck = function(config){
30657 Roo.form.ComboCheck.superclass.constructor.call(this, config);
30658 // should verify some data...
30660 // hiddenName = required..
30661 // displayField = required
30662 // valudField == required
30663 var req= [ 'hiddenName', 'displayField', 'valueField' ];
30665 Roo.each(req, function(e) {
30666 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
30667 throw "Roo.form.ComboCheck : missing value for: " + e;
30674 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
30679 selectedClass: 'x-menu-item-checked',
30682 onRender : function(ct, position){
30688 var cls = 'x-combo-list';
30691 this.tpl = new Roo.Template({
30692 html : '<div class="'+cls+'-item x-menu-check-item">' +
30693 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
30694 '<span>{' + this.displayField + '}</span>' +
30701 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
30702 this.view.singleSelect = false;
30703 this.view.multiSelect = true;
30704 this.view.toggleSelect = true;
30705 this.pageTb.add(new Roo.Toolbar.Fill(), {
30708 handler: function()
30715 onViewOver : function(e, t){
30721 onViewClick : function(doFocus,index){
30725 select: function () {
30726 //Roo.log("SELECT CALLED");
30729 selectByValue : function(xv, scrollIntoView){
30730 var ar = this.getValueArray();
30733 Roo.each(ar, function(v) {
30734 if(v === undefined || v === null){
30737 var r = this.findRecord(this.valueField, v);
30739 sels.push(this.store.indexOf(r))
30743 this.view.select(sels);
30749 onSelect : function(record, index){
30750 // Roo.log("onselect Called");
30751 // this is only called by the clear button now..
30752 this.view.clearSelections();
30753 this.setValue('[]');
30754 if (this.value != this.valueBefore) {
30755 this.fireEvent('change', this, this.value, this.valueBefore);
30756 this.valueBefore = this.value;
30759 getValueArray : function()
30764 //Roo.log(this.value);
30765 if (typeof(this.value) == 'undefined') {
30768 var ar = Roo.decode(this.value);
30769 return ar instanceof Array ? ar : []; //?? valid?
30772 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
30777 expand : function ()
30780 Roo.form.ComboCheck.superclass.expand.call(this);
30781 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
30782 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
30787 collapse : function(){
30788 Roo.form.ComboCheck.superclass.collapse.call(this);
30789 var sl = this.view.getSelectedIndexes();
30790 var st = this.store;
30794 Roo.each(sl, function(i) {
30796 nv.push(r.get(this.valueField));
30798 this.setValue(Roo.encode(nv));
30799 if (this.value != this.valueBefore) {
30801 this.fireEvent('change', this, this.value, this.valueBefore);
30802 this.valueBefore = this.value;
30807 setValue : function(v){
30811 var vals = this.getValueArray();
30813 Roo.each(vals, function(k) {
30814 var r = this.findRecord(this.valueField, k);
30816 tv.push(r.data[this.displayField]);
30817 }else if(this.valueNotFoundText !== undefined){
30818 tv.push( this.valueNotFoundText );
30823 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
30824 this.hiddenField.value = v;
30830 * Ext JS Library 1.1.1
30831 * Copyright(c) 2006-2007, Ext JS, LLC.
30833 * Originally Released Under LGPL - original licence link has changed is not relivant.
30836 * <script type="text/javascript">
30840 * @class Roo.form.Signature
30841 * @extends Roo.form.Field
30845 * @param {Object} config Configuration options
30848 Roo.form.Signature = function(config){
30849 Roo.form.Signature.superclass.constructor.call(this, config);
30851 this.addEvents({// not in used??
30854 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
30855 * @param {Roo.form.Signature} combo This combo box
30860 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
30861 * @param {Roo.form.ComboBox} combo This combo box
30862 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
30868 Roo.extend(Roo.form.Signature, Roo.form.Field, {
30870 * @cfg {Object} labels Label to use when rendering a form.
30874 * confirm : "Confirm"
30879 confirm : "Confirm"
30882 * @cfg {Number} width The signature panel width (defaults to 300)
30886 * @cfg {Number} height The signature panel height (defaults to 100)
30890 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
30892 allowBlank : false,
30895 // {Object} signPanel The signature SVG panel element (defaults to {})
30897 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
30898 isMouseDown : false,
30899 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
30900 isConfirmed : false,
30901 // {String} signatureTmp SVG mapping string (defaults to empty string)
30905 defaultAutoCreate : { // modified by initCompnoent..
30911 onRender : function(ct, position){
30913 Roo.form.Signature.superclass.onRender.call(this, ct, position);
30915 this.wrap = this.el.wrap({
30916 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
30919 this.createToolbar(this);
30920 this.signPanel = this.wrap.createChild({
30922 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
30926 this.svgID = Roo.id();
30927 this.svgEl = this.signPanel.createChild({
30928 xmlns : 'http://www.w3.org/2000/svg',
30930 id : this.svgID + "-svg",
30932 height: this.height,
30933 viewBox: '0 0 '+this.width+' '+this.height,
30937 id: this.svgID + "-svg-r",
30939 height: this.height,
30944 id: this.svgID + "-svg-l",
30946 y1: (this.height*0.8), // start set the line in 80% of height
30947 x2: this.width, // end
30948 y2: (this.height*0.8), // end set the line in 80% of height
30950 'stroke-width': "1",
30951 'stroke-dasharray': "3",
30952 'shape-rendering': "crispEdges",
30953 'pointer-events': "none"
30957 id: this.svgID + "-svg-p",
30959 'stroke-width': "3",
30961 'pointer-events': 'none'
30966 this.svgBox = this.svgEl.dom.getScreenCTM();
30968 createSVG : function(){
30969 var svg = this.signPanel;
30970 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
30973 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
30974 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
30975 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
30976 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
30977 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
30978 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
30979 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
30982 isTouchEvent : function(e){
30983 return e.type.match(/^touch/);
30985 getCoords : function (e) {
30986 var pt = this.svgEl.dom.createSVGPoint();
30989 if (this.isTouchEvent(e)) {
30990 pt.x = e.targetTouches[0].clientX
30991 pt.y = e.targetTouches[0].clientY;
30993 var a = this.svgEl.dom.getScreenCTM();
30994 var b = a.inverse();
30995 var mx = pt.matrixTransform(b);
30996 return mx.x + ',' + mx.y;
30998 //mouse event headler
30999 down : function (e) {
31000 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
31001 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
31003 this.isMouseDown = true;
31005 e.preventDefault();
31007 move : function (e) {
31008 if (this.isMouseDown) {
31009 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
31010 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
31013 e.preventDefault();
31015 up : function (e) {
31016 this.isMouseDown = false;
31017 var sp = this.signatureTmp.split(' ');
31020 if(!sp[sp.length-2].match(/^L/)){
31024 this.signatureTmp = sp.join(" ");
31027 if(this.getValue() != this.signatureTmp){
31028 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31029 this.isConfirmed = false;
31031 e.preventDefault();
31035 * Protected method that will not generally be called directly. It
31036 * is called when the editor creates its toolbar. Override this method if you need to
31037 * add custom toolbar buttons.
31038 * @param {HtmlEditor} editor
31040 createToolbar : function(editor){
31041 function btn(id, toggle, handler){
31042 var xid = fid + '-'+ id ;
31046 cls : 'x-btn-icon x-edit-'+id,
31047 enableToggle:toggle !== false,
31048 scope: editor, // was editor...
31049 handler:handler||editor.relayBtnCmd,
31050 clickEvent:'mousedown',
31051 tooltip: etb.buttonTips[id] || undefined, ///tips ???
31057 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
31061 cls : ' x-signature-btn x-signature-'+id,
31062 scope: editor, // was editor...
31063 handler: this.reset,
31064 clickEvent:'mousedown',
31065 text: this.labels.clear
31072 cls : ' x-signature-btn x-signature-'+id,
31073 scope: editor, // was editor...
31074 handler: this.confirmHandler,
31075 clickEvent:'mousedown',
31076 text: this.labels.confirm
31083 * when user is clicked confirm then show this image.....
31085 * @return {String} Image Data URI
31087 getImageDataURI : function(){
31088 var svg = this.svgEl.dom.parentNode.innerHTML;
31089 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
31094 * @return {Boolean} this.isConfirmed
31096 getConfirmed : function(){
31097 return this.isConfirmed;
31101 * @return {Number} this.width
31103 getWidth : function(){
31108 * @return {Number} this.height
31110 getHeight : function(){
31111 return this.height;
31114 getSignature : function(){
31115 return this.signatureTmp;
31118 reset : function(){
31119 this.signatureTmp = '';
31120 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31121 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
31122 this.isConfirmed = false;
31123 Roo.form.Signature.superclass.reset.call(this);
31125 setSignature : function(s){
31126 this.signatureTmp = s;
31127 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31128 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
31130 this.isConfirmed = false;
31131 Roo.form.Signature.superclass.reset.call(this);
31134 // Roo.log(this.signPanel.dom.contentWindow.up())
31137 setConfirmed : function(){
31141 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
31144 confirmHandler : function(){
31145 if(!this.getSignature()){
31149 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
31150 this.setValue(this.getSignature());
31151 this.isConfirmed = true;
31153 this.fireEvent('confirm', this);
31156 // Subclasses should provide the validation implementation by overriding this
31157 validateValue : function(value){
31158 if(this.allowBlank){
31162 if(this.isConfirmed){
31169 * Ext JS Library 1.1.1
31170 * Copyright(c) 2006-2007, Ext JS, LLC.
31172 * Originally Released Under LGPL - original licence link has changed is not relivant.
31175 * <script type="text/javascript">
31180 * @class Roo.form.ComboBox
31181 * @extends Roo.form.TriggerField
31182 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
31184 * Create a new ComboBox.
31185 * @param {Object} config Configuration options
31187 Roo.form.Select = function(config){
31188 Roo.form.Select.superclass.constructor.call(this, config);
31192 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
31194 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
31197 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
31198 * rendering into an Roo.Editor, defaults to false)
31201 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
31202 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
31205 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
31208 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
31209 * the dropdown list (defaults to undefined, with no header element)
31213 * @cfg {String/Roo.Template} tpl The template to use to render the output
31217 defaultAutoCreate : {tag: "select" },
31219 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
31221 listWidth: undefined,
31223 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
31224 * mode = 'remote' or 'text' if mode = 'local')
31226 displayField: undefined,
31228 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
31229 * mode = 'remote' or 'value' if mode = 'local').
31230 * Note: use of a valueField requires the user make a selection
31231 * in order for a value to be mapped.
31233 valueField: undefined,
31237 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
31238 * field's data value (defaults to the underlying DOM element's name)
31240 hiddenName: undefined,
31242 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
31246 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
31248 selectedClass: 'x-combo-selected',
31250 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
31251 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
31252 * which displays a downward arrow icon).
31254 triggerClass : 'x-form-arrow-trigger',
31256 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31260 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
31261 * anchor positions (defaults to 'tl-bl')
31263 listAlign: 'tl-bl?',
31265 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
31269 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
31270 * query specified by the allQuery config option (defaults to 'query')
31272 triggerAction: 'query',
31274 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
31275 * (defaults to 4, does not apply if editable = false)
31279 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
31280 * delay (typeAheadDelay) if it matches a known value (defaults to false)
31284 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
31285 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
31289 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
31290 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
31294 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
31295 * when editable = true (defaults to false)
31297 selectOnFocus:false,
31299 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
31301 queryParam: 'query',
31303 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
31304 * when mode = 'remote' (defaults to 'Loading...')
31306 loadingText: 'Loading...',
31308 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
31312 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
31316 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
31317 * traditional select (defaults to true)
31321 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
31325 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
31329 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
31330 * listWidth has a higher value)
31334 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
31335 * allow the user to set arbitrary text into the field (defaults to false)
31337 forceSelection:false,
31339 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
31340 * if typeAhead = true (defaults to 250)
31342 typeAheadDelay : 250,
31344 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
31345 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
31347 valueNotFoundText : undefined,
31350 * @cfg {String} defaultValue The value displayed after loading the store.
31355 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
31357 blockFocus : false,
31360 * @cfg {Boolean} disableClear Disable showing of clear button.
31362 disableClear : false,
31364 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
31366 alwaysQuery : false,
31372 // element that contains real text value.. (when hidden is used..)
31375 onRender : function(ct, position){
31376 Roo.form.Field.prototype.onRender.call(this, ct, position);
31379 this.store.on('beforeload', this.onBeforeLoad, this);
31380 this.store.on('load', this.onLoad, this);
31381 this.store.on('loadexception', this.onLoadException, this);
31382 this.store.load({});
31390 initEvents : function(){
31391 //Roo.form.ComboBox.superclass.initEvents.call(this);
31395 onDestroy : function(){
31398 this.store.un('beforeload', this.onBeforeLoad, this);
31399 this.store.un('load', this.onLoad, this);
31400 this.store.un('loadexception', this.onLoadException, this);
31402 //Roo.form.ComboBox.superclass.onDestroy.call(this);
31406 fireKey : function(e){
31407 if(e.isNavKeyPress() && !this.list.isVisible()){
31408 this.fireEvent("specialkey", this, e);
31413 onResize: function(w, h){
31421 * Allow or prevent the user from directly editing the field text. If false is passed,
31422 * the user will only be able to select from the items defined in the dropdown list. This method
31423 * is the runtime equivalent of setting the 'editable' config option at config time.
31424 * @param {Boolean} value True to allow the user to directly edit the field text
31426 setEditable : function(value){
31431 onBeforeLoad : function(){
31433 Roo.log("Select before load");
31436 this.innerList.update(this.loadingText ?
31437 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
31438 //this.restrictHeight();
31439 this.selectedIndex = -1;
31443 onLoad : function(){
31446 var dom = this.el.dom;
31447 dom.innerHTML = '';
31448 var od = dom.ownerDocument;
31450 if (this.emptyText) {
31451 var op = od.createElement('option');
31452 op.setAttribute('value', '');
31453 op.innerHTML = String.format('{0}', this.emptyText);
31454 dom.appendChild(op);
31456 if(this.store.getCount() > 0){
31458 var vf = this.valueField;
31459 var df = this.displayField;
31460 this.store.data.each(function(r) {
31461 // which colmsn to use... testing - cdoe / title..
31462 var op = od.createElement('option');
31463 op.setAttribute('value', r.data[vf]);
31464 op.innerHTML = String.format('{0}', r.data[df]);
31465 dom.appendChild(op);
31467 if (typeof(this.defaultValue != 'undefined')) {
31468 this.setValue(this.defaultValue);
31473 //this.onEmptyResults();
31478 onLoadException : function()
31480 dom.innerHTML = '';
31482 Roo.log("Select on load exception");
31486 Roo.log(this.store.reader.jsonData);
31487 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
31488 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
31494 onTypeAhead : function(){
31499 onSelect : function(record, index){
31500 Roo.log('on select?');
31502 if(this.fireEvent('beforeselect', this, record, index) !== false){
31503 this.setFromData(index > -1 ? record.data : false);
31505 this.fireEvent('select', this, record, index);
31510 * Returns the currently selected field value or empty string if no value is set.
31511 * @return {String} value The selected value
31513 getValue : function(){
31514 var dom = this.el.dom;
31515 this.value = dom.options[dom.selectedIndex].value;
31521 * Clears any text/value currently set in the field
31523 clearValue : function(){
31525 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
31530 * Sets the specified value into the field. If the value finds a match, the corresponding record text
31531 * will be displayed in the field. If the value does not match the data value of an existing item,
31532 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
31533 * Otherwise the field will be blank (although the value will still be set).
31534 * @param {String} value The value to match
31536 setValue : function(v){
31537 var d = this.el.dom;
31538 for (var i =0; i < d.options.length;i++) {
31539 if (v == d.options[i].value) {
31540 d.selectedIndex = i;
31548 * @property {Object} the last set data for the element
31553 * Sets the value of the field based on a object which is related to the record format for the store.
31554 * @param {Object} value the value to set as. or false on reset?
31556 setFromData : function(o){
31557 Roo.log('setfrom data?');
31563 reset : function(){
31567 findRecord : function(prop, value){
31572 if(this.store.getCount() > 0){
31573 this.store.each(function(r){
31574 if(r.data[prop] == value){
31584 getName: function()
31586 // returns hidden if it's set..
31587 if (!this.rendered) {return ''};
31588 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
31596 onEmptyResults : function(){
31597 Roo.log('empty results');
31602 * Returns true if the dropdown list is expanded, else false.
31604 isExpanded : function(){
31609 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
31610 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31611 * @param {String} value The data value of the item to select
31612 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31613 * selected item if it is not currently in view (defaults to true)
31614 * @return {Boolean} True if the value matched an item in the list, else false
31616 selectByValue : function(v, scrollIntoView){
31617 Roo.log('select By Value');
31620 if(v !== undefined && v !== null){
31621 var r = this.findRecord(this.valueField || this.displayField, v);
31623 this.select(this.store.indexOf(r), scrollIntoView);
31631 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
31632 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31633 * @param {Number} index The zero-based index of the list item to select
31634 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31635 * selected item if it is not currently in view (defaults to true)
31637 select : function(index, scrollIntoView){
31638 Roo.log('select ');
31641 this.selectedIndex = index;
31642 this.view.select(index);
31643 if(scrollIntoView !== false){
31644 var el = this.view.getNode(index);
31646 this.innerList.scrollChildIntoView(el, false);
31654 validateBlur : function(){
31661 initQuery : function(){
31662 this.doQuery(this.getRawValue());
31666 doForce : function(){
31667 if(this.el.dom.value.length > 0){
31668 this.el.dom.value =
31669 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
31675 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
31676 * query allowing the query action to be canceled if needed.
31677 * @param {String} query The SQL query to execute
31678 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
31679 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
31680 * saved in the current store (defaults to false)
31682 doQuery : function(q, forceAll){
31684 Roo.log('doQuery?');
31685 if(q === undefined || q === null){
31690 forceAll: forceAll,
31694 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
31698 forceAll = qe.forceAll;
31699 if(forceAll === true || (q.length >= this.minChars)){
31700 if(this.lastQuery != q || this.alwaysQuery){
31701 this.lastQuery = q;
31702 if(this.mode == 'local'){
31703 this.selectedIndex = -1;
31705 this.store.clearFilter();
31707 this.store.filter(this.displayField, q);
31711 this.store.baseParams[this.queryParam] = q;
31713 params: this.getParams(q)
31718 this.selectedIndex = -1;
31725 getParams : function(q){
31727 //p[this.queryParam] = q;
31730 p.limit = this.pageSize;
31736 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
31738 collapse : function(){
31743 collapseIf : function(e){
31748 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
31750 expand : function(){
31758 * @cfg {Boolean} grow
31762 * @cfg {Number} growMin
31766 * @cfg {Number} growMax
31774 setWidth : function()
31778 getResizeEl : function(){
31781 });//<script type="text/javasscript">
31785 * @class Roo.DDView
31786 * A DnD enabled version of Roo.View.
31787 * @param {Element/String} container The Element in which to create the View.
31788 * @param {String} tpl The template string used to create the markup for each element of the View
31789 * @param {Object} config The configuration properties. These include all the config options of
31790 * {@link Roo.View} plus some specific to this class.<br>
31792 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
31793 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
31795 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
31796 .x-view-drag-insert-above {
31797 border-top:1px dotted #3366cc;
31799 .x-view-drag-insert-below {
31800 border-bottom:1px dotted #3366cc;
31806 Roo.DDView = function(container, tpl, config) {
31807 Roo.DDView.superclass.constructor.apply(this, arguments);
31808 this.getEl().setStyle("outline", "0px none");
31809 this.getEl().unselectable();
31810 if (this.dragGroup) {
31811 this.setDraggable(this.dragGroup.split(","));
31813 if (this.dropGroup) {
31814 this.setDroppable(this.dropGroup.split(","));
31816 if (this.deletable) {
31817 this.setDeletable();
31819 this.isDirtyFlag = false;
31825 Roo.extend(Roo.DDView, Roo.View, {
31826 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
31827 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
31828 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
31829 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
31833 reset: Roo.emptyFn,
31835 clearInvalid: Roo.form.Field.prototype.clearInvalid,
31837 validate: function() {
31841 destroy: function() {
31842 this.purgeListeners();
31843 this.getEl.removeAllListeners();
31844 this.getEl().remove();
31845 if (this.dragZone) {
31846 if (this.dragZone.destroy) {
31847 this.dragZone.destroy();
31850 if (this.dropZone) {
31851 if (this.dropZone.destroy) {
31852 this.dropZone.destroy();
31857 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
31858 getName: function() {
31862 /** Loads the View from a JSON string representing the Records to put into the Store. */
31863 setValue: function(v) {
31865 throw "DDView.setValue(). DDView must be constructed with a valid Store";
31868 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
31869 this.store.proxy = new Roo.data.MemoryProxy(data);
31873 /** @return {String} a parenthesised list of the ids of the Records in the View. */
31874 getValue: function() {
31876 this.store.each(function(rec) {
31877 result += rec.id + ',';
31879 return result.substr(0, result.length - 1) + ')';
31882 getIds: function() {
31883 var i = 0, result = new Array(this.store.getCount());
31884 this.store.each(function(rec) {
31885 result[i++] = rec.id;
31890 isDirty: function() {
31891 return this.isDirtyFlag;
31895 * Part of the Roo.dd.DropZone interface. If no target node is found, the
31896 * whole Element becomes the target, and this causes the drop gesture to append.
31898 getTargetFromEvent : function(e) {
31899 var target = e.getTarget();
31900 while ((target !== null) && (target.parentNode != this.el.dom)) {
31901 target = target.parentNode;
31904 target = this.el.dom.lastChild || this.el.dom;
31910 * Create the drag data which consists of an object which has the property "ddel" as
31911 * the drag proxy element.
31913 getDragData : function(e) {
31914 var target = this.findItemFromChild(e.getTarget());
31916 this.handleSelection(e);
31917 var selNodes = this.getSelectedNodes();
31920 copy: this.copy || (this.allowCopy && e.ctrlKey),
31924 var selectedIndices = this.getSelectedIndexes();
31925 for (var i = 0; i < selectedIndices.length; i++) {
31926 dragData.records.push(this.store.getAt(selectedIndices[i]));
31928 if (selNodes.length == 1) {
31929 dragData.ddel = target.cloneNode(true); // the div element
31931 var div = document.createElement('div'); // create the multi element drag "ghost"
31932 div.className = 'multi-proxy';
31933 for (var i = 0, len = selNodes.length; i < len; i++) {
31934 div.appendChild(selNodes[i].cloneNode(true));
31936 dragData.ddel = div;
31938 //console.log(dragData)
31939 //console.log(dragData.ddel.innerHTML)
31942 //console.log('nodragData')
31946 /** Specify to which ddGroup items in this DDView may be dragged. */
31947 setDraggable: function(ddGroup) {
31948 if (ddGroup instanceof Array) {
31949 Roo.each(ddGroup, this.setDraggable, this);
31952 if (this.dragZone) {
31953 this.dragZone.addToGroup(ddGroup);
31955 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
31956 containerScroll: true,
31960 // Draggability implies selection. DragZone's mousedown selects the element.
31961 if (!this.multiSelect) { this.singleSelect = true; }
31963 // Wire the DragZone's handlers up to methods in *this*
31964 this.dragZone.getDragData = this.getDragData.createDelegate(this);
31968 /** Specify from which ddGroup this DDView accepts drops. */
31969 setDroppable: function(ddGroup) {
31970 if (ddGroup instanceof Array) {
31971 Roo.each(ddGroup, this.setDroppable, this);
31974 if (this.dropZone) {
31975 this.dropZone.addToGroup(ddGroup);
31977 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
31978 containerScroll: true,
31982 // Wire the DropZone's handlers up to methods in *this*
31983 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
31984 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
31985 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
31986 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
31987 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
31991 /** Decide whether to drop above or below a View node. */
31992 getDropPoint : function(e, n, dd){
31993 if (n == this.el.dom) { return "above"; }
31994 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
31995 var c = t + (b - t) / 2;
31996 var y = Roo.lib.Event.getPageY(e);
32004 onNodeEnter : function(n, dd, e, data){
32008 onNodeOver : function(n, dd, e, data){
32009 var pt = this.getDropPoint(e, n, dd);
32010 // set the insert point style on the target node
32011 var dragElClass = this.dropNotAllowed;
32014 if (pt == "above"){
32015 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
32016 targetElClass = "x-view-drag-insert-above";
32018 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
32019 targetElClass = "x-view-drag-insert-below";
32021 if (this.lastInsertClass != targetElClass){
32022 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
32023 this.lastInsertClass = targetElClass;
32026 return dragElClass;
32029 onNodeOut : function(n, dd, e, data){
32030 this.removeDropIndicators(n);
32033 onNodeDrop : function(n, dd, e, data){
32034 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
32037 var pt = this.getDropPoint(e, n, dd);
32038 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
32039 if (pt == "below") { insertAt++; }
32040 for (var i = 0; i < data.records.length; i++) {
32041 var r = data.records[i];
32042 var dup = this.store.getById(r.id);
32043 if (dup && (dd != this.dragZone)) {
32044 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
32047 this.store.insert(insertAt++, r.copy());
32049 data.source.isDirtyFlag = true;
32051 this.store.insert(insertAt++, r);
32053 this.isDirtyFlag = true;
32056 this.dragZone.cachedTarget = null;
32060 removeDropIndicators : function(n){
32062 Roo.fly(n).removeClass([
32063 "x-view-drag-insert-above",
32064 "x-view-drag-insert-below"]);
32065 this.lastInsertClass = "_noclass";
32070 * Utility method. Add a delete option to the DDView's context menu.
32071 * @param {String} imageUrl The URL of the "delete" icon image.
32073 setDeletable: function(imageUrl) {
32074 if (!this.singleSelect && !this.multiSelect) {
32075 this.singleSelect = true;
32077 var c = this.getContextMenu();
32078 this.contextMenu.on("itemclick", function(item) {
32081 this.remove(this.getSelectedIndexes());
32085 this.contextMenu.add({
32092 /** Return the context menu for this DDView. */
32093 getContextMenu: function() {
32094 if (!this.contextMenu) {
32095 // Create the View's context menu
32096 this.contextMenu = new Roo.menu.Menu({
32097 id: this.id + "-contextmenu"
32099 this.el.on("contextmenu", this.showContextMenu, this);
32101 return this.contextMenu;
32104 disableContextMenu: function() {
32105 if (this.contextMenu) {
32106 this.el.un("contextmenu", this.showContextMenu, this);
32110 showContextMenu: function(e, item) {
32111 item = this.findItemFromChild(e.getTarget());
32114 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
32115 this.contextMenu.showAt(e.getXY());
32120 * Remove {@link Roo.data.Record}s at the specified indices.
32121 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
32123 remove: function(selectedIndices) {
32124 selectedIndices = [].concat(selectedIndices);
32125 for (var i = 0; i < selectedIndices.length; i++) {
32126 var rec = this.store.getAt(selectedIndices[i]);
32127 this.store.remove(rec);
32132 * Double click fires the event, but also, if this is draggable, and there is only one other
32133 * related DropZone, it transfers the selected node.
32135 onDblClick : function(e){
32136 var item = this.findItemFromChild(e.getTarget());
32138 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
32141 if (this.dragGroup) {
32142 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
32143 while (targets.indexOf(this.dropZone) > -1) {
32144 targets.remove(this.dropZone);
32146 if (targets.length == 1) {
32147 this.dragZone.cachedTarget = null;
32148 var el = Roo.get(targets[0].getEl());
32149 var box = el.getBox(true);
32150 targets[0].onNodeDrop(el.dom, {
32152 xy: [box.x, box.y + box.height - 1]
32153 }, null, this.getDragData(e));
32159 handleSelection: function(e) {
32160 this.dragZone.cachedTarget = null;
32161 var item = this.findItemFromChild(e.getTarget());
32163 this.clearSelections(true);
32166 if (item && (this.multiSelect || this.singleSelect)){
32167 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
32168 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
32169 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
32170 this.unselect(item);
32172 this.select(item, this.multiSelect && e.ctrlKey);
32173 this.lastSelection = item;
32178 onItemClick : function(item, index, e){
32179 if(this.fireEvent("beforeclick", this, index, item, e) === false){
32185 unselect : function(nodeInfo, suppressEvent){
32186 var node = this.getNode(nodeInfo);
32187 if(node && this.isSelected(node)){
32188 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
32189 Roo.fly(node).removeClass(this.selectedClass);
32190 this.selections.remove(node);
32191 if(!suppressEvent){
32192 this.fireEvent("selectionchange", this, this.selections);
32200 * Ext JS Library 1.1.1
32201 * Copyright(c) 2006-2007, Ext JS, LLC.
32203 * Originally Released Under LGPL - original licence link has changed is not relivant.
32206 * <script type="text/javascript">
32210 * @class Roo.LayoutManager
32211 * @extends Roo.util.Observable
32212 * Base class for layout managers.
32214 Roo.LayoutManager = function(container, config){
32215 Roo.LayoutManager.superclass.constructor.call(this);
32216 this.el = Roo.get(container);
32217 // ie scrollbar fix
32218 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32219 document.body.scroll = "no";
32220 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32221 this.el.position('relative');
32223 this.id = this.el.id;
32224 this.el.addClass("x-layout-container");
32225 /** false to disable window resize monitoring @type Boolean */
32226 this.monitorWindowResize = true;
32231 * Fires when a layout is performed.
32232 * @param {Roo.LayoutManager} this
32236 * @event regionresized
32237 * Fires when the user resizes a region.
32238 * @param {Roo.LayoutRegion} region The resized region
32239 * @param {Number} newSize The new size (width for east/west, height for north/south)
32241 "regionresized" : true,
32243 * @event regioncollapsed
32244 * Fires when a region is collapsed.
32245 * @param {Roo.LayoutRegion} region The collapsed region
32247 "regioncollapsed" : true,
32249 * @event regionexpanded
32250 * Fires when a region is expanded.
32251 * @param {Roo.LayoutRegion} region The expanded region
32253 "regionexpanded" : true
32255 this.updating = false;
32256 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32259 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
32261 * Returns true if this layout is currently being updated
32262 * @return {Boolean}
32264 isUpdating : function(){
32265 return this.updating;
32269 * Suspend the LayoutManager from doing auto-layouts while
32270 * making multiple add or remove calls
32272 beginUpdate : function(){
32273 this.updating = true;
32277 * Restore auto-layouts and optionally disable the manager from performing a layout
32278 * @param {Boolean} noLayout true to disable a layout update
32280 endUpdate : function(noLayout){
32281 this.updating = false;
32287 layout: function(){
32291 onRegionResized : function(region, newSize){
32292 this.fireEvent("regionresized", region, newSize);
32296 onRegionCollapsed : function(region){
32297 this.fireEvent("regioncollapsed", region);
32300 onRegionExpanded : function(region){
32301 this.fireEvent("regionexpanded", region);
32305 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32306 * performs box-model adjustments.
32307 * @return {Object} The size as an object {width: (the width), height: (the height)}
32309 getViewSize : function(){
32311 if(this.el.dom != document.body){
32312 size = this.el.getSize();
32314 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32316 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32317 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32322 * Returns the Element this layout is bound to.
32323 * @return {Roo.Element}
32325 getEl : function(){
32330 * Returns the specified region.
32331 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32332 * @return {Roo.LayoutRegion}
32334 getRegion : function(target){
32335 return this.regions[target.toLowerCase()];
32338 onWindowResize : function(){
32339 if(this.monitorWindowResize){
32345 * Ext JS Library 1.1.1
32346 * Copyright(c) 2006-2007, Ext JS, LLC.
32348 * Originally Released Under LGPL - original licence link has changed is not relivant.
32351 * <script type="text/javascript">
32354 * @class Roo.BorderLayout
32355 * @extends Roo.LayoutManager
32356 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32357 * please see: <br><br>
32358 * <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>
32359 * <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>
32362 var layout = new Roo.BorderLayout(document.body, {
32396 preferredTabWidth: 150
32401 var CP = Roo.ContentPanel;
32403 layout.beginUpdate();
32404 layout.add("north", new CP("north", "North"));
32405 layout.add("south", new CP("south", {title: "South", closable: true}));
32406 layout.add("west", new CP("west", {title: "West"}));
32407 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
32408 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
32409 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
32410 layout.getRegion("center").showPanel("center1");
32411 layout.endUpdate();
32414 <b>The container the layout is rendered into can be either the body element or any other element.
32415 If it is not the body element, the container needs to either be an absolute positioned element,
32416 or you will need to add "position:relative" to the css of the container. You will also need to specify
32417 the container size if it is not the body element.</b>
32420 * Create a new BorderLayout
32421 * @param {String/HTMLElement/Element} container The container this layout is bound to
32422 * @param {Object} config Configuration options
32424 Roo.BorderLayout = function(container, config){
32425 config = config || {};
32426 Roo.BorderLayout.superclass.constructor.call(this, container, config);
32427 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
32428 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
32429 var target = this.factory.validRegions[i];
32430 if(config[target]){
32431 this.addRegion(target, config[target]);
32436 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
32438 * Creates and adds a new region if it doesn't already exist.
32439 * @param {String} target The target region key (north, south, east, west or center).
32440 * @param {Object} config The regions config object
32441 * @return {BorderLayoutRegion} The new region
32443 addRegion : function(target, config){
32444 if(!this.regions[target]){
32445 var r = this.factory.create(target, this, config);
32446 this.bindRegion(target, r);
32448 return this.regions[target];
32452 bindRegion : function(name, r){
32453 this.regions[name] = r;
32454 r.on("visibilitychange", this.layout, this);
32455 r.on("paneladded", this.layout, this);
32456 r.on("panelremoved", this.layout, this);
32457 r.on("invalidated", this.layout, this);
32458 r.on("resized", this.onRegionResized, this);
32459 r.on("collapsed", this.onRegionCollapsed, this);
32460 r.on("expanded", this.onRegionExpanded, this);
32464 * Performs a layout update.
32466 layout : function(){
32467 if(this.updating) return;
32468 var size = this.getViewSize();
32469 var w = size.width;
32470 var h = size.height;
32475 //var x = 0, y = 0;
32477 var rs = this.regions;
32478 var north = rs["north"];
32479 var south = rs["south"];
32480 var west = rs["west"];
32481 var east = rs["east"];
32482 var center = rs["center"];
32483 //if(this.hideOnLayout){ // not supported anymore
32484 //c.el.setStyle("display", "none");
32486 if(north && north.isVisible()){
32487 var b = north.getBox();
32488 var m = north.getMargins();
32489 b.width = w - (m.left+m.right);
32492 centerY = b.height + b.y + m.bottom;
32493 centerH -= centerY;
32494 north.updateBox(this.safeBox(b));
32496 if(south && south.isVisible()){
32497 var b = south.getBox();
32498 var m = south.getMargins();
32499 b.width = w - (m.left+m.right);
32501 var totalHeight = (b.height + m.top + m.bottom);
32502 b.y = h - totalHeight + m.top;
32503 centerH -= totalHeight;
32504 south.updateBox(this.safeBox(b));
32506 if(west && west.isVisible()){
32507 var b = west.getBox();
32508 var m = west.getMargins();
32509 b.height = centerH - (m.top+m.bottom);
32511 b.y = centerY + m.top;
32512 var totalWidth = (b.width + m.left + m.right);
32513 centerX += totalWidth;
32514 centerW -= totalWidth;
32515 west.updateBox(this.safeBox(b));
32517 if(east && east.isVisible()){
32518 var b = east.getBox();
32519 var m = east.getMargins();
32520 b.height = centerH - (m.top+m.bottom);
32521 var totalWidth = (b.width + m.left + m.right);
32522 b.x = w - totalWidth + m.left;
32523 b.y = centerY + m.top;
32524 centerW -= totalWidth;
32525 east.updateBox(this.safeBox(b));
32528 var m = center.getMargins();
32530 x: centerX + m.left,
32531 y: centerY + m.top,
32532 width: centerW - (m.left+m.right),
32533 height: centerH - (m.top+m.bottom)
32535 //if(this.hideOnLayout){
32536 //center.el.setStyle("display", "block");
32538 center.updateBox(this.safeBox(centerBox));
32541 this.fireEvent("layout", this);
32545 safeBox : function(box){
32546 box.width = Math.max(0, box.width);
32547 box.height = Math.max(0, box.height);
32552 * Adds a ContentPanel (or subclass) to this layout.
32553 * @param {String} target The target region key (north, south, east, west or center).
32554 * @param {Roo.ContentPanel} panel The panel to add
32555 * @return {Roo.ContentPanel} The added panel
32557 add : function(target, panel){
32559 target = target.toLowerCase();
32560 return this.regions[target].add(panel);
32564 * Remove a ContentPanel (or subclass) to this layout.
32565 * @param {String} target The target region key (north, south, east, west or center).
32566 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32567 * @return {Roo.ContentPanel} The removed panel
32569 remove : function(target, panel){
32570 target = target.toLowerCase();
32571 return this.regions[target].remove(panel);
32575 * Searches all regions for a panel with the specified id
32576 * @param {String} panelId
32577 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32579 findPanel : function(panelId){
32580 var rs = this.regions;
32581 for(var target in rs){
32582 if(typeof rs[target] != "function"){
32583 var p = rs[target].getPanel(panelId);
32593 * Searches all regions for a panel with the specified id and activates (shows) it.
32594 * @param {String/ContentPanel} panelId The panels id or the panel itself
32595 * @return {Roo.ContentPanel} The shown panel or null
32597 showPanel : function(panelId) {
32598 var rs = this.regions;
32599 for(var target in rs){
32600 var r = rs[target];
32601 if(typeof r != "function"){
32602 if(r.hasPanel(panelId)){
32603 return r.showPanel(panelId);
32611 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32612 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32614 restoreState : function(provider){
32616 provider = Roo.state.Manager;
32618 var sm = new Roo.LayoutStateManager();
32619 sm.init(this, provider);
32623 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
32624 * object should contain properties for each region to add ContentPanels to, and each property's value should be
32625 * a valid ContentPanel config object. Example:
32627 // Create the main layout
32628 var layout = new Roo.BorderLayout('main-ct', {
32639 // Create and add multiple ContentPanels at once via configs
32642 id: 'source-files',
32644 title:'Ext Source Files',
32657 * @param {Object} regions An object containing ContentPanel configs by region name
32659 batchAdd : function(regions){
32660 this.beginUpdate();
32661 for(var rname in regions){
32662 var lr = this.regions[rname];
32664 this.addTypedPanels(lr, regions[rname]);
32671 addTypedPanels : function(lr, ps){
32672 if(typeof ps == 'string'){
32673 lr.add(new Roo.ContentPanel(ps));
32675 else if(ps instanceof Array){
32676 for(var i =0, len = ps.length; i < len; i++){
32677 this.addTypedPanels(lr, ps[i]);
32680 else if(!ps.events){ // raw config?
32682 delete ps.el; // prevent conflict
32683 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
32685 else { // panel object assumed!
32690 * Adds a xtype elements to the layout.
32694 xtype : 'ContentPanel',
32701 xtype : 'NestedLayoutPanel',
32707 items : [ ... list of content panels or nested layout panels.. ]
32711 * @param {Object} cfg Xtype definition of item to add.
32713 addxtype : function(cfg)
32715 // basically accepts a pannel...
32716 // can accept a layout region..!?!?
32717 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32719 if (!cfg.xtype.match(/Panel$/)) {
32724 if (typeof(cfg.region) == 'undefined') {
32725 Roo.log("Failed to add Panel, region was not set");
32729 var region = cfg.region;
32735 xitems = cfg.items;
32742 case 'ContentPanel': // ContentPanel (el, cfg)
32743 case 'ScrollPanel': // ContentPanel (el, cfg)
32745 if(cfg.autoCreate) {
32746 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32748 var el = this.el.createChild();
32749 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32752 this.add(region, ret);
32756 case 'TreePanel': // our new panel!
32757 cfg.el = this.el.createChild();
32758 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32759 this.add(region, ret);
32762 case 'NestedLayoutPanel':
32763 // create a new Layout (which is a Border Layout...
32764 var el = this.el.createChild();
32765 var clayout = cfg.layout;
32767 clayout.items = clayout.items || [];
32768 // replace this exitems with the clayout ones..
32769 xitems = clayout.items;
32772 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32773 cfg.background = false;
32775 var layout = new Roo.BorderLayout(el, clayout);
32777 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
32778 //console.log('adding nested layout panel ' + cfg.toSource());
32779 this.add(region, ret);
32780 nb = {}; /// find first...
32785 // needs grid and region
32787 //var el = this.getRegion(region).el.createChild();
32788 var el = this.el.createChild();
32789 // create the grid first...
32791 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
32793 if (region == 'center' && this.active ) {
32794 cfg.background = false;
32796 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
32798 this.add(region, ret);
32799 if (cfg.background) {
32800 ret.on('activate', function(gp) {
32801 if (!gp.grid.rendered) {
32816 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
32818 // GridPanel (grid, cfg)
32821 this.beginUpdate();
32825 Roo.each(xitems, function(i) {
32826 region = nb && i.region ? i.region : false;
32828 var add = ret.addxtype(i);
32831 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32832 if (!i.background) {
32833 abn[region] = nb[region] ;
32840 // make the last non-background panel active..
32841 //if (nb) { Roo.log(abn); }
32844 for(var r in abn) {
32845 region = this.getRegion(r);
32847 // tried using nb[r], but it does not work..
32849 region.showPanel(abn[r]);
32860 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
32861 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
32862 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
32863 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
32866 var CP = Roo.ContentPanel;
32868 var layout = Roo.BorderLayout.create({
32872 panels: [new CP("north", "North")]
32881 panels: [new CP("west", {title: "West"})]
32890 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
32899 panels: [new CP("south", {title: "South", closable: true})]
32906 preferredTabWidth: 150,
32908 new CP("center1", {title: "Close Me", closable: true}),
32909 new CP("center2", {title: "Center Panel", closable: false})
32914 layout.getRegion("center").showPanel("center1");
32919 Roo.BorderLayout.create = function(config, targetEl){
32920 var layout = new Roo.BorderLayout(targetEl || document.body, config);
32921 layout.beginUpdate();
32922 var regions = Roo.BorderLayout.RegionFactory.validRegions;
32923 for(var j = 0, jlen = regions.length; j < jlen; j++){
32924 var lr = regions[j];
32925 if(layout.regions[lr] && config[lr].panels){
32926 var r = layout.regions[lr];
32927 var ps = config[lr].panels;
32928 layout.addTypedPanels(r, ps);
32931 layout.endUpdate();
32936 Roo.BorderLayout.RegionFactory = {
32938 validRegions : ["north","south","east","west","center"],
32941 create : function(target, mgr, config){
32942 target = target.toLowerCase();
32943 if(config.lightweight || config.basic){
32944 return new Roo.BasicLayoutRegion(mgr, config, target);
32948 return new Roo.NorthLayoutRegion(mgr, config);
32950 return new Roo.SouthLayoutRegion(mgr, config);
32952 return new Roo.EastLayoutRegion(mgr, config);
32954 return new Roo.WestLayoutRegion(mgr, config);
32956 return new Roo.CenterLayoutRegion(mgr, config);
32958 throw 'Layout region "'+target+'" not supported.';
32962 * Ext JS Library 1.1.1
32963 * Copyright(c) 2006-2007, Ext JS, LLC.
32965 * Originally Released Under LGPL - original licence link has changed is not relivant.
32968 * <script type="text/javascript">
32972 * @class Roo.BasicLayoutRegion
32973 * @extends Roo.util.Observable
32974 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32975 * and does not have a titlebar, tabs or any other features. All it does is size and position
32976 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32978 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
32980 this.position = pos;
32983 * @scope Roo.BasicLayoutRegion
32987 * @event beforeremove
32988 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32989 * @param {Roo.LayoutRegion} this
32990 * @param {Roo.ContentPanel} panel The panel
32991 * @param {Object} e The cancel event object
32993 "beforeremove" : true,
32995 * @event invalidated
32996 * Fires when the layout for this region is changed.
32997 * @param {Roo.LayoutRegion} this
32999 "invalidated" : true,
33001 * @event visibilitychange
33002 * Fires when this region is shown or hidden
33003 * @param {Roo.LayoutRegion} this
33004 * @param {Boolean} visibility true or false
33006 "visibilitychange" : true,
33008 * @event paneladded
33009 * Fires when a panel is added.
33010 * @param {Roo.LayoutRegion} this
33011 * @param {Roo.ContentPanel} panel The panel
33013 "paneladded" : true,
33015 * @event panelremoved
33016 * Fires when a panel is removed.
33017 * @param {Roo.LayoutRegion} this
33018 * @param {Roo.ContentPanel} panel The panel
33020 "panelremoved" : true,
33023 * Fires when this region is collapsed.
33024 * @param {Roo.LayoutRegion} this
33026 "collapsed" : true,
33029 * Fires when this region is expanded.
33030 * @param {Roo.LayoutRegion} this
33035 * Fires when this region is slid into view.
33036 * @param {Roo.LayoutRegion} this
33038 "slideshow" : true,
33041 * Fires when this region slides out of view.
33042 * @param {Roo.LayoutRegion} this
33044 "slidehide" : true,
33046 * @event panelactivated
33047 * Fires when a panel is activated.
33048 * @param {Roo.LayoutRegion} this
33049 * @param {Roo.ContentPanel} panel The activated panel
33051 "panelactivated" : true,
33054 * Fires when the user resizes this region.
33055 * @param {Roo.LayoutRegion} this
33056 * @param {Number} newSize The new size (width for east/west, height for north/south)
33060 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33061 this.panels = new Roo.util.MixedCollection();
33062 this.panels.getKey = this.getPanelId.createDelegate(this);
33064 this.activePanel = null;
33065 // ensure listeners are added...
33067 if (config.listeners || config.events) {
33068 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
33069 listeners : config.listeners || {},
33070 events : config.events || {}
33074 if(skipConfig !== true){
33075 this.applyConfig(config);
33079 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
33080 getPanelId : function(p){
33084 applyConfig : function(config){
33085 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33086 this.config = config;
33091 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33092 * the width, for horizontal (north, south) the height.
33093 * @param {Number} newSize The new width or height
33095 resizeTo : function(newSize){
33096 var el = this.el ? this.el :
33097 (this.activePanel ? this.activePanel.getEl() : null);
33099 switch(this.position){
33102 el.setWidth(newSize);
33103 this.fireEvent("resized", this, newSize);
33107 el.setHeight(newSize);
33108 this.fireEvent("resized", this, newSize);
33114 getBox : function(){
33115 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33118 getMargins : function(){
33119 return this.margins;
33122 updateBox : function(box){
33124 var el = this.activePanel.getEl();
33125 el.dom.style.left = box.x + "px";
33126 el.dom.style.top = box.y + "px";
33127 this.activePanel.setSize(box.width, box.height);
33131 * Returns the container element for this region.
33132 * @return {Roo.Element}
33134 getEl : function(){
33135 return this.activePanel;
33139 * Returns true if this region is currently visible.
33140 * @return {Boolean}
33142 isVisible : function(){
33143 return this.activePanel ? true : false;
33146 setActivePanel : function(panel){
33147 panel = this.getPanel(panel);
33148 if(this.activePanel && this.activePanel != panel){
33149 this.activePanel.setActiveState(false);
33150 this.activePanel.getEl().setLeftTop(-10000,-10000);
33152 this.activePanel = panel;
33153 panel.setActiveState(true);
33155 panel.setSize(this.box.width, this.box.height);
33157 this.fireEvent("panelactivated", this, panel);
33158 this.fireEvent("invalidated");
33162 * Show the specified panel.
33163 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33164 * @return {Roo.ContentPanel} The shown panel or null
33166 showPanel : function(panel){
33167 if(panel = this.getPanel(panel)){
33168 this.setActivePanel(panel);
33174 * Get the active panel for this region.
33175 * @return {Roo.ContentPanel} The active panel or null
33177 getActivePanel : function(){
33178 return this.activePanel;
33182 * Add the passed ContentPanel(s)
33183 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33184 * @return {Roo.ContentPanel} The panel added (if only one was added)
33186 add : function(panel){
33187 if(arguments.length > 1){
33188 for(var i = 0, len = arguments.length; i < len; i++) {
33189 this.add(arguments[i]);
33193 if(this.hasPanel(panel)){
33194 this.showPanel(panel);
33197 var el = panel.getEl();
33198 if(el.dom.parentNode != this.mgr.el.dom){
33199 this.mgr.el.dom.appendChild(el.dom);
33201 if(panel.setRegion){
33202 panel.setRegion(this);
33204 this.panels.add(panel);
33205 el.setStyle("position", "absolute");
33206 if(!panel.background){
33207 this.setActivePanel(panel);
33208 if(this.config.initialSize && this.panels.getCount()==1){
33209 this.resizeTo(this.config.initialSize);
33212 this.fireEvent("paneladded", this, panel);
33217 * Returns true if the panel is in this region.
33218 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33219 * @return {Boolean}
33221 hasPanel : function(panel){
33222 if(typeof panel == "object"){ // must be panel obj
33223 panel = panel.getId();
33225 return this.getPanel(panel) ? true : false;
33229 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33230 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33231 * @param {Boolean} preservePanel Overrides the config preservePanel option
33232 * @return {Roo.ContentPanel} The panel that was removed
33234 remove : function(panel, preservePanel){
33235 panel = this.getPanel(panel);
33240 this.fireEvent("beforeremove", this, panel, e);
33241 if(e.cancel === true){
33244 var panelId = panel.getId();
33245 this.panels.removeKey(panelId);
33250 * Returns the panel specified or null if it's not in this region.
33251 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33252 * @return {Roo.ContentPanel}
33254 getPanel : function(id){
33255 if(typeof id == "object"){ // must be panel obj
33258 return this.panels.get(id);
33262 * Returns this regions position (north/south/east/west/center).
33265 getPosition: function(){
33266 return this.position;
33270 * Ext JS Library 1.1.1
33271 * Copyright(c) 2006-2007, Ext JS, LLC.
33273 * Originally Released Under LGPL - original licence link has changed is not relivant.
33276 * <script type="text/javascript">
33280 * @class Roo.LayoutRegion
33281 * @extends Roo.BasicLayoutRegion
33282 * This class represents a region in a layout manager.
33283 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
33284 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
33285 * @cfg {Boolean} floatable False to disable floating (defaults to true)
33286 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33287 * @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})
33288 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
33289 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
33290 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33291 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33292 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33293 * @cfg {String} title The title for the region (overrides panel titles)
33294 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33295 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33296 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33297 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33298 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33299 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33300 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33301 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33302 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33303 * @cfg {Boolean} showPin True to show a pin button
33304 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33305 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33306 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33307 * @cfg {Number} width For East/West panels
33308 * @cfg {Number} height For North/South panels
33309 * @cfg {Boolean} split To show the splitter
33310 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33312 Roo.LayoutRegion = function(mgr, config, pos){
33313 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
33314 var dh = Roo.DomHelper;
33315 /** This region's container element
33316 * @type Roo.Element */
33317 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
33318 /** This region's title element
33319 * @type Roo.Element */
33321 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
33322 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
33323 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
33325 this.titleEl.enableDisplayMode();
33326 /** This region's title text element
33327 * @type HTMLElement */
33328 this.titleTextEl = this.titleEl.dom.firstChild;
33329 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33330 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
33331 this.closeBtn.enableDisplayMode();
33332 this.closeBtn.on("click", this.closeClicked, this);
33333 this.closeBtn.hide();
33335 this.createBody(config);
33336 this.visible = true;
33337 this.collapsed = false;
33339 if(config.hideWhenEmpty){
33341 this.on("paneladded", this.validateVisibility, this);
33342 this.on("panelremoved", this.validateVisibility, this);
33344 this.applyConfig(config);
33347 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
33349 createBody : function(){
33350 /** This region's body element
33351 * @type Roo.Element */
33352 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
33355 applyConfig : function(c){
33356 if(c.collapsible && this.position != "center" && !this.collapsedEl){
33357 var dh = Roo.DomHelper;
33358 if(c.titlebar !== false){
33359 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
33360 this.collapseBtn.on("click", this.collapse, this);
33361 this.collapseBtn.enableDisplayMode();
33363 if(c.showPin === true || this.showPin){
33364 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
33365 this.stickBtn.enableDisplayMode();
33366 this.stickBtn.on("click", this.expand, this);
33367 this.stickBtn.hide();
33370 /** This region's collapsed element
33371 * @type Roo.Element */
33372 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33373 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33375 if(c.floatable !== false){
33376 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33377 this.collapsedEl.on("click", this.collapseClick, this);
33380 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33381 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33382 id: "message", unselectable: "on", style:{"float":"left"}});
33383 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33385 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33386 this.expandBtn.on("click", this.expand, this);
33388 if(this.collapseBtn){
33389 this.collapseBtn.setVisible(c.collapsible == true);
33391 this.cmargins = c.cmargins || this.cmargins ||
33392 (this.position == "west" || this.position == "east" ?
33393 {top: 0, left: 2, right:2, bottom: 0} :
33394 {top: 2, left: 0, right:0, bottom: 2});
33395 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33396 this.bottomTabs = c.tabPosition != "top";
33397 this.autoScroll = c.autoScroll || false;
33398 if(this.autoScroll){
33399 this.bodyEl.setStyle("overflow", "auto");
33401 this.bodyEl.setStyle("overflow", "hidden");
33403 //if(c.titlebar !== false){
33404 if((!c.titlebar && !c.title) || c.titlebar === false){
33405 this.titleEl.hide();
33407 this.titleEl.show();
33409 this.titleTextEl.innerHTML = c.title;
33413 this.duration = c.duration || .30;
33414 this.slideDuration = c.slideDuration || .45;
33417 this.collapse(true);
33424 * Returns true if this region is currently visible.
33425 * @return {Boolean}
33427 isVisible : function(){
33428 return this.visible;
33432 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33433 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33435 setCollapsedTitle : function(title){
33436 title = title || " ";
33437 if(this.collapsedTitleTextEl){
33438 this.collapsedTitleTextEl.innerHTML = title;
33442 getBox : function(){
33444 if(!this.collapsed){
33445 b = this.el.getBox(false, true);
33447 b = this.collapsedEl.getBox(false, true);
33452 getMargins : function(){
33453 return this.collapsed ? this.cmargins : this.margins;
33456 highlight : function(){
33457 this.el.addClass("x-layout-panel-dragover");
33460 unhighlight : function(){
33461 this.el.removeClass("x-layout-panel-dragover");
33464 updateBox : function(box){
33466 if(!this.collapsed){
33467 this.el.dom.style.left = box.x + "px";
33468 this.el.dom.style.top = box.y + "px";
33469 this.updateBody(box.width, box.height);
33471 this.collapsedEl.dom.style.left = box.x + "px";
33472 this.collapsedEl.dom.style.top = box.y + "px";
33473 this.collapsedEl.setSize(box.width, box.height);
33476 this.tabs.autoSizeTabs();
33480 updateBody : function(w, h){
33482 this.el.setWidth(w);
33483 w -= this.el.getBorderWidth("rl");
33484 if(this.config.adjustments){
33485 w += this.config.adjustments[0];
33489 this.el.setHeight(h);
33490 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33491 h -= this.el.getBorderWidth("tb");
33492 if(this.config.adjustments){
33493 h += this.config.adjustments[1];
33495 this.bodyEl.setHeight(h);
33497 h = this.tabs.syncHeight(h);
33500 if(this.panelSize){
33501 w = w !== null ? w : this.panelSize.width;
33502 h = h !== null ? h : this.panelSize.height;
33504 if(this.activePanel){
33505 var el = this.activePanel.getEl();
33506 w = w !== null ? w : el.getWidth();
33507 h = h !== null ? h : el.getHeight();
33508 this.panelSize = {width: w, height: h};
33509 this.activePanel.setSize(w, h);
33511 if(Roo.isIE && this.tabs){
33512 this.tabs.el.repaint();
33517 * Returns the container element for this region.
33518 * @return {Roo.Element}
33520 getEl : function(){
33525 * Hides this region.
33528 if(!this.collapsed){
33529 this.el.dom.style.left = "-2000px";
33532 this.collapsedEl.dom.style.left = "-2000px";
33533 this.collapsedEl.hide();
33535 this.visible = false;
33536 this.fireEvent("visibilitychange", this, false);
33540 * Shows this region if it was previously hidden.
33543 if(!this.collapsed){
33546 this.collapsedEl.show();
33548 this.visible = true;
33549 this.fireEvent("visibilitychange", this, true);
33552 closeClicked : function(){
33553 if(this.activePanel){
33554 this.remove(this.activePanel);
33558 collapseClick : function(e){
33560 e.stopPropagation();
33563 e.stopPropagation();
33569 * Collapses this region.
33570 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33572 collapse : function(skipAnim){
33573 if(this.collapsed) return;
33574 this.collapsed = true;
33576 this.split.el.hide();
33578 if(this.config.animate && skipAnim !== true){
33579 this.fireEvent("invalidated", this);
33580 this.animateCollapse();
33582 this.el.setLocation(-20000,-20000);
33584 this.collapsedEl.show();
33585 this.fireEvent("collapsed", this);
33586 this.fireEvent("invalidated", this);
33590 animateCollapse : function(){
33595 * Expands this region if it was previously collapsed.
33596 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33597 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33599 expand : function(e, skipAnim){
33600 if(e) e.stopPropagation();
33601 if(!this.collapsed || this.el.hasActiveFx()) return;
33603 this.afterSlideIn();
33606 this.collapsed = false;
33607 if(this.config.animate && skipAnim !== true){
33608 this.animateExpand();
33612 this.split.el.show();
33614 this.collapsedEl.setLocation(-2000,-2000);
33615 this.collapsedEl.hide();
33616 this.fireEvent("invalidated", this);
33617 this.fireEvent("expanded", this);
33621 animateExpand : function(){
33625 initTabs : function()
33627 this.bodyEl.setStyle("overflow", "hidden");
33628 var ts = new Roo.TabPanel(
33631 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33632 disableTooltips: this.config.disableTabTips,
33633 toolbar : this.config.toolbar
33636 if(this.config.hideTabs){
33637 ts.stripWrap.setDisplayed(false);
33640 ts.resizeTabs = this.config.resizeTabs === true;
33641 ts.minTabWidth = this.config.minTabWidth || 40;
33642 ts.maxTabWidth = this.config.maxTabWidth || 250;
33643 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33644 ts.monitorResize = false;
33645 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33646 ts.bodyEl.addClass('x-layout-tabs-body');
33647 this.panels.each(this.initPanelAsTab, this);
33650 initPanelAsTab : function(panel){
33651 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
33652 this.config.closeOnTab && panel.isClosable());
33653 if(panel.tabTip !== undefined){
33654 ti.setTooltip(panel.tabTip);
33656 ti.on("activate", function(){
33657 this.setActivePanel(panel);
33659 if(this.config.closeOnTab){
33660 ti.on("beforeclose", function(t, e){
33662 this.remove(panel);
33668 updatePanelTitle : function(panel, title){
33669 if(this.activePanel == panel){
33670 this.updateTitle(title);
33673 var ti = this.tabs.getTab(panel.getEl().id);
33675 if(panel.tabTip !== undefined){
33676 ti.setTooltip(panel.tabTip);
33681 updateTitle : function(title){
33682 if(this.titleTextEl && !this.config.title){
33683 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33687 setActivePanel : function(panel){
33688 panel = this.getPanel(panel);
33689 if(this.activePanel && this.activePanel != panel){
33690 this.activePanel.setActiveState(false);
33692 this.activePanel = panel;
33693 panel.setActiveState(true);
33694 if(this.panelSize){
33695 panel.setSize(this.panelSize.width, this.panelSize.height);
33698 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33700 this.updateTitle(panel.getTitle());
33702 this.fireEvent("invalidated", this);
33704 this.fireEvent("panelactivated", this, panel);
33708 * Shows the specified panel.
33709 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33710 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33712 showPanel : function(panel){
33713 if(panel = this.getPanel(panel)){
33715 var tab = this.tabs.getTab(panel.getEl().id);
33716 if(tab.isHidden()){
33717 this.tabs.unhideTab(tab.id);
33721 this.setActivePanel(panel);
33728 * Get the active panel for this region.
33729 * @return {Roo.ContentPanel} The active panel or null
33731 getActivePanel : function(){
33732 return this.activePanel;
33735 validateVisibility : function(){
33736 if(this.panels.getCount() < 1){
33737 this.updateTitle(" ");
33738 this.closeBtn.hide();
33741 if(!this.isVisible()){
33748 * Adds the passed ContentPanel(s) to this region.
33749 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33750 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33752 add : function(panel){
33753 if(arguments.length > 1){
33754 for(var i = 0, len = arguments.length; i < len; i++) {
33755 this.add(arguments[i]);
33759 if(this.hasPanel(panel)){
33760 this.showPanel(panel);
33763 panel.setRegion(this);
33764 this.panels.add(panel);
33765 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33766 this.bodyEl.dom.appendChild(panel.getEl().dom);
33767 if(panel.background !== true){
33768 this.setActivePanel(panel);
33770 this.fireEvent("paneladded", this, panel);
33776 this.initPanelAsTab(panel);
33778 if(panel.background !== true){
33779 this.tabs.activate(panel.getEl().id);
33781 this.fireEvent("paneladded", this, panel);
33786 * Hides the tab for the specified panel.
33787 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33789 hidePanel : function(panel){
33790 if(this.tabs && (panel = this.getPanel(panel))){
33791 this.tabs.hideTab(panel.getEl().id);
33796 * Unhides the tab for a previously hidden panel.
33797 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33799 unhidePanel : function(panel){
33800 if(this.tabs && (panel = this.getPanel(panel))){
33801 this.tabs.unhideTab(panel.getEl().id);
33805 clearPanels : function(){
33806 while(this.panels.getCount() > 0){
33807 this.remove(this.panels.first());
33812 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33813 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33814 * @param {Boolean} preservePanel Overrides the config preservePanel option
33815 * @return {Roo.ContentPanel} The panel that was removed
33817 remove : function(panel, preservePanel){
33818 panel = this.getPanel(panel);
33823 this.fireEvent("beforeremove", this, panel, e);
33824 if(e.cancel === true){
33827 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33828 var panelId = panel.getId();
33829 this.panels.removeKey(panelId);
33831 document.body.appendChild(panel.getEl().dom);
33834 this.tabs.removeTab(panel.getEl().id);
33835 }else if (!preservePanel){
33836 this.bodyEl.dom.removeChild(panel.getEl().dom);
33838 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33839 var p = this.panels.first();
33840 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33841 tempEl.appendChild(p.getEl().dom);
33842 this.bodyEl.update("");
33843 this.bodyEl.dom.appendChild(p.getEl().dom);
33845 this.updateTitle(p.getTitle());
33847 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33848 this.setActivePanel(p);
33850 panel.setRegion(null);
33851 if(this.activePanel == panel){
33852 this.activePanel = null;
33854 if(this.config.autoDestroy !== false && preservePanel !== true){
33855 try{panel.destroy();}catch(e){}
33857 this.fireEvent("panelremoved", this, panel);
33862 * Returns the TabPanel component used by this region
33863 * @return {Roo.TabPanel}
33865 getTabs : function(){
33869 createTool : function(parentEl, className){
33870 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
33871 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
33872 btn.addClassOnOver("x-layout-tools-button-over");
33877 * Ext JS Library 1.1.1
33878 * Copyright(c) 2006-2007, Ext JS, LLC.
33880 * Originally Released Under LGPL - original licence link has changed is not relivant.
33883 * <script type="text/javascript">
33889 * @class Roo.SplitLayoutRegion
33890 * @extends Roo.LayoutRegion
33891 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33893 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
33894 this.cursor = cursor;
33895 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
33898 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
33899 splitTip : "Drag to resize.",
33900 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33901 useSplitTips : false,
33903 applyConfig : function(config){
33904 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
33907 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
33908 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
33909 /** The SplitBar for this region
33910 * @type Roo.SplitBar */
33911 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
33912 this.split.on("moved", this.onSplitMove, this);
33913 this.split.useShim = config.useShim === true;
33914 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33915 if(this.useSplitTips){
33916 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33918 if(config.collapsible){
33919 this.split.el.on("dblclick", this.collapse, this);
33922 if(typeof config.minSize != "undefined"){
33923 this.split.minSize = config.minSize;
33925 if(typeof config.maxSize != "undefined"){
33926 this.split.maxSize = config.maxSize;
33928 if(config.hideWhenEmpty || config.hidden || config.collapsed){
33929 this.hideSplitter();
33934 getHMaxSize : function(){
33935 var cmax = this.config.maxSize || 10000;
33936 var center = this.mgr.getRegion("center");
33937 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33940 getVMaxSize : function(){
33941 var cmax = this.config.maxSize || 10000;
33942 var center = this.mgr.getRegion("center");
33943 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33946 onSplitMove : function(split, newSize){
33947 this.fireEvent("resized", this, newSize);
33951 * Returns the {@link Roo.SplitBar} for this region.
33952 * @return {Roo.SplitBar}
33954 getSplitBar : function(){
33959 this.hideSplitter();
33960 Roo.SplitLayoutRegion.superclass.hide.call(this);
33963 hideSplitter : function(){
33965 this.split.el.setLocation(-2000,-2000);
33966 this.split.el.hide();
33972 this.split.el.show();
33974 Roo.SplitLayoutRegion.superclass.show.call(this);
33977 beforeSlide: function(){
33978 if(Roo.isGecko){// firefox overflow auto bug workaround
33979 this.bodyEl.clip();
33980 if(this.tabs) this.tabs.bodyEl.clip();
33981 if(this.activePanel){
33982 this.activePanel.getEl().clip();
33984 if(this.activePanel.beforeSlide){
33985 this.activePanel.beforeSlide();
33991 afterSlide : function(){
33992 if(Roo.isGecko){// firefox overflow auto bug workaround
33993 this.bodyEl.unclip();
33994 if(this.tabs) this.tabs.bodyEl.unclip();
33995 if(this.activePanel){
33996 this.activePanel.getEl().unclip();
33997 if(this.activePanel.afterSlide){
33998 this.activePanel.afterSlide();
34004 initAutoHide : function(){
34005 if(this.autoHide !== false){
34006 if(!this.autoHideHd){
34007 var st = new Roo.util.DelayedTask(this.slideIn, this);
34008 this.autoHideHd = {
34009 "mouseout": function(e){
34010 if(!e.within(this.el, true)){
34014 "mouseover" : function(e){
34020 this.el.on(this.autoHideHd);
34024 clearAutoHide : function(){
34025 if(this.autoHide !== false){
34026 this.el.un("mouseout", this.autoHideHd.mouseout);
34027 this.el.un("mouseover", this.autoHideHd.mouseover);
34031 clearMonitor : function(){
34032 Roo.get(document).un("click", this.slideInIf, this);
34035 // these names are backwards but not changed for compat
34036 slideOut : function(){
34037 if(this.isSlid || this.el.hasActiveFx()){
34040 this.isSlid = true;
34041 if(this.collapseBtn){
34042 this.collapseBtn.hide();
34044 this.closeBtnState = this.closeBtn.getStyle('display');
34045 this.closeBtn.hide();
34047 this.stickBtn.show();
34050 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
34051 this.beforeSlide();
34052 this.el.setStyle("z-index", 10001);
34053 this.el.slideIn(this.getSlideAnchor(), {
34054 callback: function(){
34056 this.initAutoHide();
34057 Roo.get(document).on("click", this.slideInIf, this);
34058 this.fireEvent("slideshow", this);
34065 afterSlideIn : function(){
34066 this.clearAutoHide();
34067 this.isSlid = false;
34068 this.clearMonitor();
34069 this.el.setStyle("z-index", "");
34070 if(this.collapseBtn){
34071 this.collapseBtn.show();
34073 this.closeBtn.setStyle('display', this.closeBtnState);
34075 this.stickBtn.hide();
34077 this.fireEvent("slidehide", this);
34080 slideIn : function(cb){
34081 if(!this.isSlid || this.el.hasActiveFx()){
34085 this.isSlid = false;
34086 this.beforeSlide();
34087 this.el.slideOut(this.getSlideAnchor(), {
34088 callback: function(){
34089 this.el.setLeftTop(-10000, -10000);
34091 this.afterSlideIn();
34099 slideInIf : function(e){
34100 if(!e.within(this.el)){
34105 animateCollapse : function(){
34106 this.beforeSlide();
34107 this.el.setStyle("z-index", 20000);
34108 var anchor = this.getSlideAnchor();
34109 this.el.slideOut(anchor, {
34110 callback : function(){
34111 this.el.setStyle("z-index", "");
34112 this.collapsedEl.slideIn(anchor, {duration:.3});
34114 this.el.setLocation(-10000,-10000);
34116 this.fireEvent("collapsed", this);
34123 animateExpand : function(){
34124 this.beforeSlide();
34125 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34126 this.el.setStyle("z-index", 20000);
34127 this.collapsedEl.hide({
34130 this.el.slideIn(this.getSlideAnchor(), {
34131 callback : function(){
34132 this.el.setStyle("z-index", "");
34135 this.split.el.show();
34137 this.fireEvent("invalidated", this);
34138 this.fireEvent("expanded", this);
34166 getAnchor : function(){
34167 return this.anchors[this.position];
34170 getCollapseAnchor : function(){
34171 return this.canchors[this.position];
34174 getSlideAnchor : function(){
34175 return this.sanchors[this.position];
34178 getAlignAdj : function(){
34179 var cm = this.cmargins;
34180 switch(this.position){
34196 getExpandAdj : function(){
34197 var c = this.collapsedEl, cm = this.cmargins;
34198 switch(this.position){
34200 return [-(cm.right+c.getWidth()+cm.left), 0];
34203 return [cm.right+c.getWidth()+cm.left, 0];
34206 return [0, -(cm.top+cm.bottom+c.getHeight())];
34209 return [0, cm.top+cm.bottom+c.getHeight()];
34215 * Ext JS Library 1.1.1
34216 * Copyright(c) 2006-2007, Ext JS, LLC.
34218 * Originally Released Under LGPL - original licence link has changed is not relivant.
34221 * <script type="text/javascript">
34224 * These classes are private internal classes
34226 Roo.CenterLayoutRegion = function(mgr, config){
34227 Roo.LayoutRegion.call(this, mgr, config, "center");
34228 this.visible = true;
34229 this.minWidth = config.minWidth || 20;
34230 this.minHeight = config.minHeight || 20;
34233 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
34235 // center panel can't be hidden
34239 // center panel can't be hidden
34242 getMinWidth: function(){
34243 return this.minWidth;
34246 getMinHeight: function(){
34247 return this.minHeight;
34252 Roo.NorthLayoutRegion = function(mgr, config){
34253 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
34255 this.split.placement = Roo.SplitBar.TOP;
34256 this.split.orientation = Roo.SplitBar.VERTICAL;
34257 this.split.el.addClass("x-layout-split-v");
34259 var size = config.initialSize || config.height;
34260 if(typeof size != "undefined"){
34261 this.el.setHeight(size);
34264 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
34265 orientation: Roo.SplitBar.VERTICAL,
34266 getBox : function(){
34267 if(this.collapsed){
34268 return this.collapsedEl.getBox();
34270 var box = this.el.getBox();
34272 box.height += this.split.el.getHeight();
34277 updateBox : function(box){
34278 if(this.split && !this.collapsed){
34279 box.height -= this.split.el.getHeight();
34280 this.split.el.setLeft(box.x);
34281 this.split.el.setTop(box.y+box.height);
34282 this.split.el.setWidth(box.width);
34284 if(this.collapsed){
34285 this.updateBody(box.width, null);
34287 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34291 Roo.SouthLayoutRegion = function(mgr, config){
34292 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
34294 this.split.placement = Roo.SplitBar.BOTTOM;
34295 this.split.orientation = Roo.SplitBar.VERTICAL;
34296 this.split.el.addClass("x-layout-split-v");
34298 var size = config.initialSize || config.height;
34299 if(typeof size != "undefined"){
34300 this.el.setHeight(size);
34303 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
34304 orientation: Roo.SplitBar.VERTICAL,
34305 getBox : function(){
34306 if(this.collapsed){
34307 return this.collapsedEl.getBox();
34309 var box = this.el.getBox();
34311 var sh = this.split.el.getHeight();
34318 updateBox : function(box){
34319 if(this.split && !this.collapsed){
34320 var sh = this.split.el.getHeight();
34323 this.split.el.setLeft(box.x);
34324 this.split.el.setTop(box.y-sh);
34325 this.split.el.setWidth(box.width);
34327 if(this.collapsed){
34328 this.updateBody(box.width, null);
34330 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34334 Roo.EastLayoutRegion = function(mgr, config){
34335 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
34337 this.split.placement = Roo.SplitBar.RIGHT;
34338 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34339 this.split.el.addClass("x-layout-split-h");
34341 var size = config.initialSize || config.width;
34342 if(typeof size != "undefined"){
34343 this.el.setWidth(size);
34346 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
34347 orientation: Roo.SplitBar.HORIZONTAL,
34348 getBox : function(){
34349 if(this.collapsed){
34350 return this.collapsedEl.getBox();
34352 var box = this.el.getBox();
34354 var sw = this.split.el.getWidth();
34361 updateBox : function(box){
34362 if(this.split && !this.collapsed){
34363 var sw = this.split.el.getWidth();
34365 this.split.el.setLeft(box.x);
34366 this.split.el.setTop(box.y);
34367 this.split.el.setHeight(box.height);
34370 if(this.collapsed){
34371 this.updateBody(null, box.height);
34373 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34377 Roo.WestLayoutRegion = function(mgr, config){
34378 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
34380 this.split.placement = Roo.SplitBar.LEFT;
34381 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34382 this.split.el.addClass("x-layout-split-h");
34384 var size = config.initialSize || config.width;
34385 if(typeof size != "undefined"){
34386 this.el.setWidth(size);
34389 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
34390 orientation: Roo.SplitBar.HORIZONTAL,
34391 getBox : function(){
34392 if(this.collapsed){
34393 return this.collapsedEl.getBox();
34395 var box = this.el.getBox();
34397 box.width += this.split.el.getWidth();
34402 updateBox : function(box){
34403 if(this.split && !this.collapsed){
34404 var sw = this.split.el.getWidth();
34406 this.split.el.setLeft(box.x+box.width);
34407 this.split.el.setTop(box.y);
34408 this.split.el.setHeight(box.height);
34410 if(this.collapsed){
34411 this.updateBody(null, box.height);
34413 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34418 * Ext JS Library 1.1.1
34419 * Copyright(c) 2006-2007, Ext JS, LLC.
34421 * Originally Released Under LGPL - original licence link has changed is not relivant.
34424 * <script type="text/javascript">
34429 * Private internal class for reading and applying state
34431 Roo.LayoutStateManager = function(layout){
34432 // default empty state
34441 Roo.LayoutStateManager.prototype = {
34442 init : function(layout, provider){
34443 this.provider = provider;
34444 var state = provider.get(layout.id+"-layout-state");
34446 var wasUpdating = layout.isUpdating();
34448 layout.beginUpdate();
34450 for(var key in state){
34451 if(typeof state[key] != "function"){
34452 var rstate = state[key];
34453 var r = layout.getRegion(key);
34456 r.resizeTo(rstate.size);
34458 if(rstate.collapsed == true){
34461 r.expand(null, true);
34467 layout.endUpdate();
34469 this.state = state;
34471 this.layout = layout;
34472 layout.on("regionresized", this.onRegionResized, this);
34473 layout.on("regioncollapsed", this.onRegionCollapsed, this);
34474 layout.on("regionexpanded", this.onRegionExpanded, this);
34477 storeState : function(){
34478 this.provider.set(this.layout.id+"-layout-state", this.state);
34481 onRegionResized : function(region, newSize){
34482 this.state[region.getPosition()].size = newSize;
34486 onRegionCollapsed : function(region){
34487 this.state[region.getPosition()].collapsed = true;
34491 onRegionExpanded : function(region){
34492 this.state[region.getPosition()].collapsed = false;
34497 * Ext JS Library 1.1.1
34498 * Copyright(c) 2006-2007, Ext JS, LLC.
34500 * Originally Released Under LGPL - original licence link has changed is not relivant.
34503 * <script type="text/javascript">
34506 * @class Roo.ContentPanel
34507 * @extends Roo.util.Observable
34508 * A basic ContentPanel element.
34509 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34510 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34511 * @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
34512 * @cfg {Boolean} closable True if the panel can be closed/removed
34513 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34514 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34515 * @cfg {Toolbar} toolbar A toolbar for this panel
34516 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34517 * @cfg {String} title The title for this panel
34518 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34519 * @cfg {String} url Calls {@link #setUrl} with this value
34520 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34521 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34522 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34523 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34526 * Create a new ContentPanel.
34527 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34528 * @param {String/Object} config A string to set only the title or a config object
34529 * @param {String} content (optional) Set the HTML content for this panel
34530 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34532 Roo.ContentPanel = function(el, config, content){
34536 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
34540 if (config && config.parentLayout) {
34541 el = config.parentLayout.el.createChild();
34544 if(el.autoCreate){ // xtype is available if this is called from factory
34548 this.el = Roo.get(el);
34549 if(!this.el && config && config.autoCreate){
34550 if(typeof config.autoCreate == "object"){
34551 if(!config.autoCreate.id){
34552 config.autoCreate.id = config.id||el;
34554 this.el = Roo.DomHelper.append(document.body,
34555 config.autoCreate, true);
34557 this.el = Roo.DomHelper.append(document.body,
34558 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
34561 this.closable = false;
34562 this.loaded = false;
34563 this.active = false;
34564 if(typeof config == "string"){
34565 this.title = config;
34567 Roo.apply(this, config);
34570 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
34571 this.wrapEl = this.el.wrap();
34572 this.toolbar.container = this.el.insertSibling(false, 'before');
34573 this.toolbar = new Roo.Toolbar(this.toolbar);
34576 // xtype created footer. - not sure if will work as we normally have to render first..
34577 if (this.footer && !this.footer.el && this.footer.xtype) {
34578 if (!this.wrapEl) {
34579 this.wrapEl = this.el.wrap();
34582 this.footer.container = this.wrapEl.createChild();
34584 this.footer = Roo.factory(this.footer, Roo);
34589 this.resizeEl = Roo.get(this.resizeEl, true);
34591 this.resizeEl = this.el;
34593 // handle view.xtype
34601 * Fires when this panel is activated.
34602 * @param {Roo.ContentPanel} this
34606 * @event deactivate
34607 * Fires when this panel is activated.
34608 * @param {Roo.ContentPanel} this
34610 "deactivate" : true,
34614 * Fires when this panel is resized if fitToFrame is true.
34615 * @param {Roo.ContentPanel} this
34616 * @param {Number} width The width after any component adjustments
34617 * @param {Number} height The height after any component adjustments
34623 * Fires when this tab is created
34624 * @param {Roo.ContentPanel} this
34635 if(this.autoScroll){
34636 this.resizeEl.setStyle("overflow", "auto");
34638 // fix randome scrolling
34639 this.el.on('scroll', function() {
34640 Roo.log('fix random scolling');
34641 this.scrollTo('top',0);
34644 content = content || this.content;
34646 this.setContent(content);
34648 if(config && config.url){
34649 this.setUrl(this.url, this.params, this.loadOnce);
34654 Roo.ContentPanel.superclass.constructor.call(this);
34656 if (this.view && typeof(this.view.xtype) != 'undefined') {
34657 this.view.el = this.el.appendChild(document.createElement("div"));
34658 this.view = Roo.factory(this.view);
34659 this.view.render && this.view.render(false, '');
34663 this.fireEvent('render', this);
34666 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
34668 setRegion : function(region){
34669 this.region = region;
34671 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
34673 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
34678 * Returns the toolbar for this Panel if one was configured.
34679 * @return {Roo.Toolbar}
34681 getToolbar : function(){
34682 return this.toolbar;
34685 setActiveState : function(active){
34686 this.active = active;
34688 this.fireEvent("deactivate", this);
34690 this.fireEvent("activate", this);
34694 * Updates this panel's element
34695 * @param {String} content The new content
34696 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34698 setContent : function(content, loadScripts){
34699 this.el.update(content, loadScripts);
34702 ignoreResize : function(w, h){
34703 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34706 this.lastSize = {width: w, height: h};
34711 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34712 * @return {Roo.UpdateManager} The UpdateManager
34714 getUpdateManager : function(){
34715 return this.el.getUpdateManager();
34718 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34719 * @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:
34722 url: "your-url.php",
34723 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34724 callback: yourFunction,
34725 scope: yourObject, //(optional scope)
34728 text: "Loading...",
34733 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34734 * 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.
34735 * @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}
34736 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34737 * @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.
34738 * @return {Roo.ContentPanel} this
34741 var um = this.el.getUpdateManager();
34742 um.update.apply(um, arguments);
34748 * 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.
34749 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34750 * @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)
34751 * @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)
34752 * @return {Roo.UpdateManager} The UpdateManager
34754 setUrl : function(url, params, loadOnce){
34755 if(this.refreshDelegate){
34756 this.removeListener("activate", this.refreshDelegate);
34758 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34759 this.on("activate", this.refreshDelegate);
34760 return this.el.getUpdateManager();
34763 _handleRefresh : function(url, params, loadOnce){
34764 if(!loadOnce || !this.loaded){
34765 var updater = this.el.getUpdateManager();
34766 updater.update(url, params, this._setLoaded.createDelegate(this));
34770 _setLoaded : function(){
34771 this.loaded = true;
34775 * Returns this panel's id
34778 getId : function(){
34783 * Returns this panel's element - used by regiosn to add.
34784 * @return {Roo.Element}
34786 getEl : function(){
34787 return this.wrapEl || this.el;
34790 adjustForComponents : function(width, height)
34792 //Roo.log('adjustForComponents ');
34793 if(this.resizeEl != this.el){
34794 width -= this.el.getFrameWidth('lr');
34795 height -= this.el.getFrameWidth('tb');
34798 var te = this.toolbar.getEl();
34799 height -= te.getHeight();
34800 te.setWidth(width);
34803 var te = this.footer.getEl();
34804 Roo.log("footer:" + te.getHeight());
34806 height -= te.getHeight();
34807 te.setWidth(width);
34811 if(this.adjustments){
34812 width += this.adjustments[0];
34813 height += this.adjustments[1];
34815 return {"width": width, "height": height};
34818 setSize : function(width, height){
34819 if(this.fitToFrame && !this.ignoreResize(width, height)){
34820 if(this.fitContainer && this.resizeEl != this.el){
34821 this.el.setSize(width, height);
34823 var size = this.adjustForComponents(width, height);
34824 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34825 this.fireEvent('resize', this, size.width, size.height);
34830 * Returns this panel's title
34833 getTitle : function(){
34838 * Set this panel's title
34839 * @param {String} title
34841 setTitle : function(title){
34842 this.title = title;
34844 this.region.updatePanelTitle(this, title);
34849 * Returns true is this panel was configured to be closable
34850 * @return {Boolean}
34852 isClosable : function(){
34853 return this.closable;
34856 beforeSlide : function(){
34858 this.resizeEl.clip();
34861 afterSlide : function(){
34863 this.resizeEl.unclip();
34867 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34868 * Will fail silently if the {@link #setUrl} method has not been called.
34869 * This does not activate the panel, just updates its content.
34871 refresh : function(){
34872 if(this.refreshDelegate){
34873 this.loaded = false;
34874 this.refreshDelegate();
34879 * Destroys this panel
34881 destroy : function(){
34882 this.el.removeAllListeners();
34883 var tempEl = document.createElement("span");
34884 tempEl.appendChild(this.el.dom);
34885 tempEl.innerHTML = "";
34891 * form - if the content panel contains a form - this is a reference to it.
34892 * @type {Roo.form.Form}
34896 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34897 * This contains a reference to it.
34903 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34913 * @param {Object} cfg Xtype definition of item to add.
34916 addxtype : function(cfg) {
34918 if (cfg.xtype.match(/^Form$/)) {
34921 //if (this.footer) {
34922 // el = this.footer.container.insertSibling(false, 'before');
34924 el = this.el.createChild();
34927 this.form = new Roo.form.Form(cfg);
34930 if ( this.form.allItems.length) this.form.render(el.dom);
34933 // should only have one of theses..
34934 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34935 // views.. should not be just added - used named prop 'view''
34937 cfg.el = this.el.appendChild(document.createElement("div"));
34940 var ret = new Roo.factory(cfg);
34942 ret.render && ret.render(false, ''); // render blank..
34951 * @class Roo.GridPanel
34952 * @extends Roo.ContentPanel
34954 * Create a new GridPanel.
34955 * @param {Roo.grid.Grid} grid The grid for this panel
34956 * @param {String/Object} config A string to set only the panel's title, or a config object
34958 Roo.GridPanel = function(grid, config){
34961 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34962 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
34964 this.wrapper.dom.appendChild(grid.getGridEl().dom);
34966 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
34969 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
34971 // xtype created footer. - not sure if will work as we normally have to render first..
34972 if (this.footer && !this.footer.el && this.footer.xtype) {
34974 this.footer.container = this.grid.getView().getFooterPanel(true);
34975 this.footer.dataSource = this.grid.dataSource;
34976 this.footer = Roo.factory(this.footer, Roo);
34980 grid.monitorWindowResize = false; // turn off autosizing
34981 grid.autoHeight = false;
34982 grid.autoWidth = false;
34984 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
34987 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
34988 getId : function(){
34989 return this.grid.id;
34993 * Returns the grid for this panel
34994 * @return {Roo.grid.Grid}
34996 getGrid : function(){
35000 setSize : function(width, height){
35001 if(!this.ignoreResize(width, height)){
35002 var grid = this.grid;
35003 var size = this.adjustForComponents(width, height);
35004 grid.getGridEl().setSize(size.width, size.height);
35009 beforeSlide : function(){
35010 this.grid.getView().scroller.clip();
35013 afterSlide : function(){
35014 this.grid.getView().scroller.unclip();
35017 destroy : function(){
35018 this.grid.destroy();
35020 Roo.GridPanel.superclass.destroy.call(this);
35026 * @class Roo.NestedLayoutPanel
35027 * @extends Roo.ContentPanel
35029 * Create a new NestedLayoutPanel.
35032 * @param {Roo.BorderLayout} layout The layout for this panel
35033 * @param {String/Object} config A string to set only the title or a config object
35035 Roo.NestedLayoutPanel = function(layout, config)
35037 // construct with only one argument..
35038 /* FIXME - implement nicer consturctors
35039 if (layout.layout) {
35041 layout = config.layout;
35042 delete config.layout;
35044 if (layout.xtype && !layout.getEl) {
35045 // then layout needs constructing..
35046 layout = Roo.factory(layout, Roo);
35051 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
35053 layout.monitorWindowResize = false; // turn off autosizing
35054 this.layout = layout;
35055 this.layout.getEl().addClass("x-layout-nested-layout");
35062 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
35064 setSize : function(width, height){
35065 if(!this.ignoreResize(width, height)){
35066 var size = this.adjustForComponents(width, height);
35067 var el = this.layout.getEl();
35068 el.setSize(size.width, size.height);
35069 var touch = el.dom.offsetWidth;
35070 this.layout.layout();
35071 // ie requires a double layout on the first pass
35072 if(Roo.isIE && !this.initialized){
35073 this.initialized = true;
35074 this.layout.layout();
35079 // activate all subpanels if not currently active..
35081 setActiveState : function(active){
35082 this.active = active;
35084 this.fireEvent("deactivate", this);
35088 this.fireEvent("activate", this);
35089 // not sure if this should happen before or after..
35090 if (!this.layout) {
35091 return; // should not happen..
35094 for (var r in this.layout.regions) {
35095 reg = this.layout.getRegion(r);
35096 if (reg.getActivePanel()) {
35097 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35098 reg.setActivePanel(reg.getActivePanel());
35101 if (!reg.panels.length) {
35104 reg.showPanel(reg.getPanel(0));
35113 * Returns the nested BorderLayout for this panel
35114 * @return {Roo.BorderLayout}
35116 getLayout : function(){
35117 return this.layout;
35121 * Adds a xtype elements to the layout of the nested panel
35125 xtype : 'ContentPanel',
35132 xtype : 'NestedLayoutPanel',
35138 items : [ ... list of content panels or nested layout panels.. ]
35142 * @param {Object} cfg Xtype definition of item to add.
35144 addxtype : function(cfg) {
35145 return this.layout.addxtype(cfg);
35150 Roo.ScrollPanel = function(el, config, content){
35151 config = config || {};
35152 config.fitToFrame = true;
35153 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
35155 this.el.dom.style.overflow = "hidden";
35156 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
35157 this.el.removeClass("x-layout-inactive-content");
35158 this.el.on("mousewheel", this.onWheel, this);
35160 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
35161 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
35162 up.unselectable(); down.unselectable();
35163 up.on("click", this.scrollUp, this);
35164 down.on("click", this.scrollDown, this);
35165 up.addClassOnOver("x-scroller-btn-over");
35166 down.addClassOnOver("x-scroller-btn-over");
35167 up.addClassOnClick("x-scroller-btn-click");
35168 down.addClassOnClick("x-scroller-btn-click");
35169 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
35171 this.resizeEl = this.el;
35172 this.el = wrap; this.up = up; this.down = down;
35175 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
35177 wheelIncrement : 5,
35178 scrollUp : function(){
35179 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
35182 scrollDown : function(){
35183 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
35186 afterScroll : function(){
35187 var el = this.resizeEl;
35188 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
35189 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35190 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35193 setSize : function(){
35194 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
35195 this.afterScroll();
35198 onWheel : function(e){
35199 var d = e.getWheelDelta();
35200 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
35201 this.afterScroll();
35205 setContent : function(content, loadScripts){
35206 this.resizeEl.update(content, loadScripts);
35220 * @class Roo.TreePanel
35221 * @extends Roo.ContentPanel
35223 * Create a new TreePanel. - defaults to fit/scoll contents.
35224 * @param {String/Object} config A string to set only the panel's title, or a config object
35225 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
35227 Roo.TreePanel = function(config){
35228 var el = config.el;
35229 var tree = config.tree;
35230 delete config.tree;
35231 delete config.el; // hopefull!
35233 // wrapper for IE7 strict & safari scroll issue
35235 var treeEl = el.createChild();
35236 config.resizeEl = treeEl;
35240 Roo.TreePanel.superclass.constructor.call(this, el, config);
35243 this.tree = new Roo.tree.TreePanel(treeEl , tree);
35244 //console.log(tree);
35245 this.on('activate', function()
35247 if (this.tree.rendered) {
35250 //console.log('render tree');
35251 this.tree.render();
35253 // this should not be needed.. - it's actually the 'el' that resizes?
35254 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
35256 //this.on('resize', function (cp, w, h) {
35257 // this.tree.innerCt.setWidth(w);
35258 // this.tree.innerCt.setHeight(h);
35259 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
35266 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
35283 * Ext JS Library 1.1.1
35284 * Copyright(c) 2006-2007, Ext JS, LLC.
35286 * Originally Released Under LGPL - original licence link has changed is not relivant.
35289 * <script type="text/javascript">
35294 * @class Roo.ReaderLayout
35295 * @extends Roo.BorderLayout
35296 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
35297 * center region containing two nested regions (a top one for a list view and one for item preview below),
35298 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
35299 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
35300 * expedites the setup of the overall layout and regions for this common application style.
35303 var reader = new Roo.ReaderLayout();
35304 var CP = Roo.ContentPanel; // shortcut for adding
35306 reader.beginUpdate();
35307 reader.add("north", new CP("north", "North"));
35308 reader.add("west", new CP("west", {title: "West"}));
35309 reader.add("east", new CP("east", {title: "East"}));
35311 reader.regions.listView.add(new CP("listView", "List"));
35312 reader.regions.preview.add(new CP("preview", "Preview"));
35313 reader.endUpdate();
35316 * Create a new ReaderLayout
35317 * @param {Object} config Configuration options
35318 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
35319 * document.body if omitted)
35321 Roo.ReaderLayout = function(config, renderTo){
35322 var c = config || {size:{}};
35323 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
35324 north: c.north !== false ? Roo.apply({
35328 }, c.north) : false,
35329 west: c.west !== false ? Roo.apply({
35337 margins:{left:5,right:0,bottom:5,top:5},
35338 cmargins:{left:5,right:5,bottom:5,top:5}
35339 }, c.west) : false,
35340 east: c.east !== false ? Roo.apply({
35348 margins:{left:0,right:5,bottom:5,top:5},
35349 cmargins:{left:5,right:5,bottom:5,top:5}
35350 }, c.east) : false,
35351 center: Roo.apply({
35352 tabPosition: 'top',
35356 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
35360 this.el.addClass('x-reader');
35362 this.beginUpdate();
35364 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
35365 south: c.preview !== false ? Roo.apply({
35372 cmargins:{top:5,left:0, right:0, bottom:0}
35373 }, c.preview) : false,
35374 center: Roo.apply({
35380 this.add('center', new Roo.NestedLayoutPanel(inner,
35381 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
35385 this.regions.preview = inner.getRegion('south');
35386 this.regions.listView = inner.getRegion('center');
35389 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
35391 * Ext JS Library 1.1.1
35392 * Copyright(c) 2006-2007, Ext JS, LLC.
35394 * Originally Released Under LGPL - original licence link has changed is not relivant.
35397 * <script type="text/javascript">
35401 * @class Roo.grid.Grid
35402 * @extends Roo.util.Observable
35403 * This class represents the primary interface of a component based grid control.
35404 * <br><br>Usage:<pre><code>
35405 var grid = new Roo.grid.Grid("my-container-id", {
35408 selModel: mySelectionModel,
35409 autoSizeColumns: true,
35410 monitorWindowResize: false,
35411 trackMouseOver: true
35416 * <b>Common Problems:</b><br/>
35417 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
35418 * element will correct this<br/>
35419 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
35420 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
35421 * are unpredictable.<br/>
35422 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
35423 * grid to calculate dimensions/offsets.<br/>
35425 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35426 * The container MUST have some type of size defined for the grid to fill. The container will be
35427 * automatically set to position relative if it isn't already.
35428 * @param {Object} config A config object that sets properties on this grid.
35430 Roo.grid.Grid = function(container, config){
35431 // initialize the container
35432 this.container = Roo.get(container);
35433 this.container.update("");
35434 this.container.setStyle("overflow", "hidden");
35435 this.container.addClass('x-grid-container');
35437 this.id = this.container.id;
35439 Roo.apply(this, config);
35440 // check and correct shorthanded configs
35442 this.dataSource = this.ds;
35446 this.colModel = this.cm;
35450 this.selModel = this.sm;
35454 if (this.selModel) {
35455 this.selModel = Roo.factory(this.selModel, Roo.grid);
35456 this.sm = this.selModel;
35457 this.sm.xmodule = this.xmodule || false;
35459 if (typeof(this.colModel.config) == 'undefined') {
35460 this.colModel = new Roo.grid.ColumnModel(this.colModel);
35461 this.cm = this.colModel;
35462 this.cm.xmodule = this.xmodule || false;
35464 if (this.dataSource) {
35465 this.dataSource= Roo.factory(this.dataSource, Roo.data);
35466 this.ds = this.dataSource;
35467 this.ds.xmodule = this.xmodule || false;
35474 this.container.setWidth(this.width);
35478 this.container.setHeight(this.height);
35485 * The raw click event for the entire grid.
35486 * @param {Roo.EventObject} e
35491 * The raw dblclick event for the entire grid.
35492 * @param {Roo.EventObject} e
35496 * @event contextmenu
35497 * The raw contextmenu event for the entire grid.
35498 * @param {Roo.EventObject} e
35500 "contextmenu" : true,
35503 * The raw mousedown event for the entire grid.
35504 * @param {Roo.EventObject} e
35506 "mousedown" : true,
35509 * The raw mouseup event for the entire grid.
35510 * @param {Roo.EventObject} e
35515 * The raw mouseover event for the entire grid.
35516 * @param {Roo.EventObject} e
35518 "mouseover" : true,
35521 * The raw mouseout event for the entire grid.
35522 * @param {Roo.EventObject} e
35527 * The raw keypress event for the entire grid.
35528 * @param {Roo.EventObject} e
35533 * The raw keydown event for the entire grid.
35534 * @param {Roo.EventObject} e
35542 * Fires when a cell is clicked
35543 * @param {Grid} this
35544 * @param {Number} rowIndex
35545 * @param {Number} columnIndex
35546 * @param {Roo.EventObject} e
35548 "cellclick" : true,
35550 * @event celldblclick
35551 * Fires when a cell is double clicked
35552 * @param {Grid} this
35553 * @param {Number} rowIndex
35554 * @param {Number} columnIndex
35555 * @param {Roo.EventObject} e
35557 "celldblclick" : true,
35560 * Fires when a row is clicked
35561 * @param {Grid} this
35562 * @param {Number} rowIndex
35563 * @param {Roo.EventObject} e
35567 * @event rowdblclick
35568 * Fires when a row is double clicked
35569 * @param {Grid} this
35570 * @param {Number} rowIndex
35571 * @param {Roo.EventObject} e
35573 "rowdblclick" : true,
35575 * @event headerclick
35576 * Fires when a header is clicked
35577 * @param {Grid} this
35578 * @param {Number} columnIndex
35579 * @param {Roo.EventObject} e
35581 "headerclick" : true,
35583 * @event headerdblclick
35584 * Fires when a header cell is double clicked
35585 * @param {Grid} this
35586 * @param {Number} columnIndex
35587 * @param {Roo.EventObject} e
35589 "headerdblclick" : true,
35591 * @event rowcontextmenu
35592 * Fires when a row is right clicked
35593 * @param {Grid} this
35594 * @param {Number} rowIndex
35595 * @param {Roo.EventObject} e
35597 "rowcontextmenu" : true,
35599 * @event cellcontextmenu
35600 * Fires when a cell is right clicked
35601 * @param {Grid} this
35602 * @param {Number} rowIndex
35603 * @param {Number} cellIndex
35604 * @param {Roo.EventObject} e
35606 "cellcontextmenu" : true,
35608 * @event headercontextmenu
35609 * Fires when a header is right clicked
35610 * @param {Grid} this
35611 * @param {Number} columnIndex
35612 * @param {Roo.EventObject} e
35614 "headercontextmenu" : true,
35616 * @event bodyscroll
35617 * Fires when the body element is scrolled
35618 * @param {Number} scrollLeft
35619 * @param {Number} scrollTop
35621 "bodyscroll" : true,
35623 * @event columnresize
35624 * Fires when the user resizes a column
35625 * @param {Number} columnIndex
35626 * @param {Number} newSize
35628 "columnresize" : true,
35630 * @event columnmove
35631 * Fires when the user moves a column
35632 * @param {Number} oldIndex
35633 * @param {Number} newIndex
35635 "columnmove" : true,
35638 * Fires when row(s) start being dragged
35639 * @param {Grid} this
35640 * @param {Roo.GridDD} dd The drag drop object
35641 * @param {event} e The raw browser event
35643 "startdrag" : true,
35646 * Fires when a drag operation is complete
35647 * @param {Grid} this
35648 * @param {Roo.GridDD} dd The drag drop object
35649 * @param {event} e The raw browser event
35654 * Fires when dragged row(s) are dropped on a valid DD target
35655 * @param {Grid} this
35656 * @param {Roo.GridDD} dd The drag drop object
35657 * @param {String} targetId The target drag drop object
35658 * @param {event} e The raw browser event
35663 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
35664 * @param {Grid} this
35665 * @param {Roo.GridDD} dd The drag drop object
35666 * @param {String} targetId The target drag drop object
35667 * @param {event} e The raw browser event
35672 * Fires when the dragged row(s) first cross another DD target while being dragged
35673 * @param {Grid} this
35674 * @param {Roo.GridDD} dd The drag drop object
35675 * @param {String} targetId The target drag drop object
35676 * @param {event} e The raw browser event
35678 "dragenter" : true,
35681 * Fires when the dragged row(s) leave another DD target while being dragged
35682 * @param {Grid} this
35683 * @param {Roo.GridDD} dd The drag drop object
35684 * @param {String} targetId The target drag drop object
35685 * @param {event} e The raw browser event
35690 * Fires when a row is rendered, so you can change add a style to it.
35691 * @param {GridView} gridview The grid view
35692 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
35698 * Fires when the grid is rendered
35699 * @param {Grid} grid
35704 Roo.grid.Grid.superclass.constructor.call(this);
35706 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
35709 * @cfg {String} ddGroup - drag drop group.
35713 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
35715 minColumnWidth : 25,
35718 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
35719 * <b>on initial render.</b> It is more efficient to explicitly size the columns
35720 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
35722 autoSizeColumns : false,
35725 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
35727 autoSizeHeaders : true,
35730 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
35732 monitorWindowResize : true,
35735 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
35736 * rows measured to get a columns size. Default is 0 (all rows).
35738 maxRowsToMeasure : 0,
35741 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
35743 trackMouseOver : true,
35746 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
35750 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
35752 enableDragDrop : false,
35755 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
35757 enableColumnMove : true,
35760 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
35762 enableColumnHide : true,
35765 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
35767 enableRowHeightSync : false,
35770 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
35775 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
35777 autoHeight : false,
35780 * @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.
35782 autoExpandColumn : false,
35785 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
35788 autoExpandMin : 50,
35791 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
35793 autoExpandMax : 1000,
35796 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
35801 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
35805 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
35815 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
35816 * of a fixed width. Default is false.
35819 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
35822 * Called once after all setup has been completed and the grid is ready to be rendered.
35823 * @return {Roo.grid.Grid} this
35825 render : function()
35827 var c = this.container;
35828 // try to detect autoHeight/width mode
35829 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
35830 this.autoHeight = true;
35832 var view = this.getView();
35835 c.on("click", this.onClick, this);
35836 c.on("dblclick", this.onDblClick, this);
35837 c.on("contextmenu", this.onContextMenu, this);
35838 c.on("keydown", this.onKeyDown, this);
35840 c.on("touchstart", this.onTouchStart, this);
35843 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
35845 this.getSelectionModel().init(this);
35850 this.loadMask = new Roo.LoadMask(this.container,
35851 Roo.apply({store:this.dataSource}, this.loadMask));
35855 if (this.toolbar && this.toolbar.xtype) {
35856 this.toolbar.container = this.getView().getHeaderPanel(true);
35857 this.toolbar = new Roo.Toolbar(this.toolbar);
35859 if (this.footer && this.footer.xtype) {
35860 this.footer.dataSource = this.getDataSource();
35861 this.footer.container = this.getView().getFooterPanel(true);
35862 this.footer = Roo.factory(this.footer, Roo);
35864 if (this.dropTarget && this.dropTarget.xtype) {
35865 delete this.dropTarget.xtype;
35866 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
35870 this.rendered = true;
35871 this.fireEvent('render', this);
35876 * Reconfigures the grid to use a different Store and Column Model.
35877 * The View will be bound to the new objects and refreshed.
35878 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
35879 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
35881 reconfigure : function(dataSource, colModel){
35883 this.loadMask.destroy();
35884 this.loadMask = new Roo.LoadMask(this.container,
35885 Roo.apply({store:dataSource}, this.loadMask));
35887 this.view.bind(dataSource, colModel);
35888 this.dataSource = dataSource;
35889 this.colModel = colModel;
35890 this.view.refresh(true);
35894 onKeyDown : function(e){
35895 this.fireEvent("keydown", e);
35899 * Destroy this grid.
35900 * @param {Boolean} removeEl True to remove the element
35902 destroy : function(removeEl, keepListeners){
35904 this.loadMask.destroy();
35906 var c = this.container;
35907 c.removeAllListeners();
35908 this.view.destroy();
35909 this.colModel.purgeListeners();
35910 if(!keepListeners){
35911 this.purgeListeners();
35914 if(removeEl === true){
35920 processEvent : function(name, e){
35921 // does this fire select???
35922 Roo.log('grid:processEvent ' + name);
35924 if (name != 'touchstart' ) {
35925 this.fireEvent(name, e);
35928 var t = e.getTarget();
35930 var header = v.findHeaderIndex(t);
35931 if(header !== false){
35932 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
35934 var row = v.findRowIndex(t);
35935 var cell = v.findCellIndex(t);
35936 if (name == 'touchstart') {
35937 // first touch is always a click.
35938 // hopefull this happens after selection is updated.?
35941 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
35942 var cs = this.selModel.getSelectedCell();
35943 if (row == cs[0] && cell == cs[1]){
35947 if (typeof(this.selModel.getSelections) != 'undefined') {
35948 var cs = this.selModel.getSelections();
35949 var ds = this.dataSource;
35950 if (cs.length == 1 && ds.getAt(row) == cs[0]){
35961 this.fireEvent("row" + name, this, row, e);
35962 if(cell !== false){
35963 this.fireEvent("cell" + name, this, row, cell, e);
35970 onClick : function(e){
35971 this.processEvent("click", e);
35974 onTouchStart : function(e){
35975 this.processEvent("touchstart", e);
35979 onContextMenu : function(e, t){
35980 this.processEvent("contextmenu", e);
35984 onDblClick : function(e){
35985 this.processEvent("dblclick", e);
35989 walkCells : function(row, col, step, fn, scope){
35990 var cm = this.colModel, clen = cm.getColumnCount();
35991 var ds = this.dataSource, rlen = ds.getCount(), first = true;
36003 if(fn.call(scope || this, row, col, cm) === true){
36021 if(fn.call(scope || this, row, col, cm) === true){
36033 getSelections : function(){
36034 return this.selModel.getSelections();
36038 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
36039 * but if manual update is required this method will initiate it.
36041 autoSize : function(){
36043 this.view.layout();
36044 if(this.view.adjustForScroll){
36045 this.view.adjustForScroll();
36051 * Returns the grid's underlying element.
36052 * @return {Element} The element
36054 getGridEl : function(){
36055 return this.container;
36058 // private for compatibility, overridden by editor grid
36059 stopEditing : function(){},
36062 * Returns the grid's SelectionModel.
36063 * @return {SelectionModel}
36065 getSelectionModel : function(){
36066 if(!this.selModel){
36067 this.selModel = new Roo.grid.RowSelectionModel();
36069 return this.selModel;
36073 * Returns the grid's DataSource.
36074 * @return {DataSource}
36076 getDataSource : function(){
36077 return this.dataSource;
36081 * Returns the grid's ColumnModel.
36082 * @return {ColumnModel}
36084 getColumnModel : function(){
36085 return this.colModel;
36089 * Returns the grid's GridView object.
36090 * @return {GridView}
36092 getView : function(){
36094 this.view = new Roo.grid.GridView(this.viewConfig);
36099 * Called to get grid's drag proxy text, by default returns this.ddText.
36102 getDragDropText : function(){
36103 var count = this.selModel.getCount();
36104 return String.format(this.ddText, count, count == 1 ? '' : 's');
36108 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
36109 * %0 is replaced with the number of selected rows.
36112 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
36114 * Ext JS Library 1.1.1
36115 * Copyright(c) 2006-2007, Ext JS, LLC.
36117 * Originally Released Under LGPL - original licence link has changed is not relivant.
36120 * <script type="text/javascript">
36123 Roo.grid.AbstractGridView = function(){
36127 "beforerowremoved" : true,
36128 "beforerowsinserted" : true,
36129 "beforerefresh" : true,
36130 "rowremoved" : true,
36131 "rowsinserted" : true,
36132 "rowupdated" : true,
36135 Roo.grid.AbstractGridView.superclass.constructor.call(this);
36138 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
36139 rowClass : "x-grid-row",
36140 cellClass : "x-grid-cell",
36141 tdClass : "x-grid-td",
36142 hdClass : "x-grid-hd",
36143 splitClass : "x-grid-hd-split",
36145 init: function(grid){
36147 var cid = this.grid.getGridEl().id;
36148 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
36149 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
36150 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
36151 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
36154 getColumnRenderers : function(){
36155 var renderers = [];
36156 var cm = this.grid.colModel;
36157 var colCount = cm.getColumnCount();
36158 for(var i = 0; i < colCount; i++){
36159 renderers[i] = cm.getRenderer(i);
36164 getColumnIds : function(){
36166 var cm = this.grid.colModel;
36167 var colCount = cm.getColumnCount();
36168 for(var i = 0; i < colCount; i++){
36169 ids[i] = cm.getColumnId(i);
36174 getDataIndexes : function(){
36175 if(!this.indexMap){
36176 this.indexMap = this.buildIndexMap();
36178 return this.indexMap.colToData;
36181 getColumnIndexByDataIndex : function(dataIndex){
36182 if(!this.indexMap){
36183 this.indexMap = this.buildIndexMap();
36185 return this.indexMap.dataToCol[dataIndex];
36189 * Set a css style for a column dynamically.
36190 * @param {Number} colIndex The index of the column
36191 * @param {String} name The css property name
36192 * @param {String} value The css value
36194 setCSSStyle : function(colIndex, name, value){
36195 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
36196 Roo.util.CSS.updateRule(selector, name, value);
36199 generateRules : function(cm){
36200 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
36201 Roo.util.CSS.removeStyleSheet(rulesId);
36202 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36203 var cid = cm.getColumnId(i);
36204 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
36205 this.tdSelector, cid, " {\n}\n",
36206 this.hdSelector, cid, " {\n}\n",
36207 this.splitSelector, cid, " {\n}\n");
36209 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
36213 * Ext JS Library 1.1.1
36214 * Copyright(c) 2006-2007, Ext JS, LLC.
36216 * Originally Released Under LGPL - original licence link has changed is not relivant.
36219 * <script type="text/javascript">
36223 // This is a support class used internally by the Grid components
36224 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
36226 this.view = grid.getView();
36227 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36228 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
36230 this.setHandleElId(Roo.id(hd));
36231 this.setOuterHandleElId(Roo.id(hd2));
36233 this.scroll = false;
36235 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
36237 getDragData : function(e){
36238 var t = Roo.lib.Event.getTarget(e);
36239 var h = this.view.findHeaderCell(t);
36241 return {ddel: h.firstChild, header:h};
36246 onInitDrag : function(e){
36247 this.view.headersDisabled = true;
36248 var clone = this.dragData.ddel.cloneNode(true);
36249 clone.id = Roo.id();
36250 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
36251 this.proxy.update(clone);
36255 afterValidDrop : function(){
36257 setTimeout(function(){
36258 v.headersDisabled = false;
36262 afterInvalidDrop : function(){
36264 setTimeout(function(){
36265 v.headersDisabled = false;
36271 * Ext JS Library 1.1.1
36272 * Copyright(c) 2006-2007, Ext JS, LLC.
36274 * Originally Released Under LGPL - original licence link has changed is not relivant.
36277 * <script type="text/javascript">
36280 // This is a support class used internally by the Grid components
36281 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
36283 this.view = grid.getView();
36284 // split the proxies so they don't interfere with mouse events
36285 this.proxyTop = Roo.DomHelper.append(document.body, {
36286 cls:"col-move-top", html:" "
36288 this.proxyBottom = Roo.DomHelper.append(document.body, {
36289 cls:"col-move-bottom", html:" "
36291 this.proxyTop.hide = this.proxyBottom.hide = function(){
36292 this.setLeftTop(-100,-100);
36293 this.setStyle("visibility", "hidden");
36295 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36296 // temporarily disabled
36297 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
36298 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
36300 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
36301 proxyOffsets : [-4, -9],
36302 fly: Roo.Element.fly,
36304 getTargetFromEvent : function(e){
36305 var t = Roo.lib.Event.getTarget(e);
36306 var cindex = this.view.findCellIndex(t);
36307 if(cindex !== false){
36308 return this.view.getHeaderCell(cindex);
36313 nextVisible : function(h){
36314 var v = this.view, cm = this.grid.colModel;
36317 if(!cm.isHidden(v.getCellIndex(h))){
36325 prevVisible : function(h){
36326 var v = this.view, cm = this.grid.colModel;
36329 if(!cm.isHidden(v.getCellIndex(h))){
36337 positionIndicator : function(h, n, e){
36338 var x = Roo.lib.Event.getPageX(e);
36339 var r = Roo.lib.Dom.getRegion(n.firstChild);
36340 var px, pt, py = r.top + this.proxyOffsets[1];
36341 if((r.right - x) <= (r.right-r.left)/2){
36342 px = r.right+this.view.borderWidth;
36348 var oldIndex = this.view.getCellIndex(h);
36349 var newIndex = this.view.getCellIndex(n);
36351 if(this.grid.colModel.isFixed(newIndex)){
36355 var locked = this.grid.colModel.isLocked(newIndex);
36360 if(oldIndex < newIndex){
36363 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
36366 px += this.proxyOffsets[0];
36367 this.proxyTop.setLeftTop(px, py);
36368 this.proxyTop.show();
36369 if(!this.bottomOffset){
36370 this.bottomOffset = this.view.mainHd.getHeight();
36372 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
36373 this.proxyBottom.show();
36377 onNodeEnter : function(n, dd, e, data){
36378 if(data.header != n){
36379 this.positionIndicator(data.header, n, e);
36383 onNodeOver : function(n, dd, e, data){
36384 var result = false;
36385 if(data.header != n){
36386 result = this.positionIndicator(data.header, n, e);
36389 this.proxyTop.hide();
36390 this.proxyBottom.hide();
36392 return result ? this.dropAllowed : this.dropNotAllowed;
36395 onNodeOut : function(n, dd, e, data){
36396 this.proxyTop.hide();
36397 this.proxyBottom.hide();
36400 onNodeDrop : function(n, dd, e, data){
36401 var h = data.header;
36403 var cm = this.grid.colModel;
36404 var x = Roo.lib.Event.getPageX(e);
36405 var r = Roo.lib.Dom.getRegion(n.firstChild);
36406 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
36407 var oldIndex = this.view.getCellIndex(h);
36408 var newIndex = this.view.getCellIndex(n);
36409 var locked = cm.isLocked(newIndex);
36413 if(oldIndex < newIndex){
36416 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
36419 cm.setLocked(oldIndex, locked, true);
36420 cm.moveColumn(oldIndex, newIndex);
36421 this.grid.fireEvent("columnmove", oldIndex, newIndex);
36429 * Ext JS Library 1.1.1
36430 * Copyright(c) 2006-2007, Ext JS, LLC.
36432 * Originally Released Under LGPL - original licence link has changed is not relivant.
36435 * <script type="text/javascript">
36439 * @class Roo.grid.GridView
36440 * @extends Roo.util.Observable
36443 * @param {Object} config
36445 Roo.grid.GridView = function(config){
36446 Roo.grid.GridView.superclass.constructor.call(this);
36449 Roo.apply(this, config);
36452 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
36454 unselectable : 'unselectable="on"',
36455 unselectableCls : 'x-unselectable',
36458 rowClass : "x-grid-row",
36460 cellClass : "x-grid-col",
36462 tdClass : "x-grid-td",
36464 hdClass : "x-grid-hd",
36466 splitClass : "x-grid-split",
36468 sortClasses : ["sort-asc", "sort-desc"],
36470 enableMoveAnim : false,
36474 dh : Roo.DomHelper,
36476 fly : Roo.Element.fly,
36478 css : Roo.util.CSS,
36484 scrollIncrement : 22,
36486 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
36488 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
36490 bind : function(ds, cm){
36492 this.ds.un("load", this.onLoad, this);
36493 this.ds.un("datachanged", this.onDataChange, this);
36494 this.ds.un("add", this.onAdd, this);
36495 this.ds.un("remove", this.onRemove, this);
36496 this.ds.un("update", this.onUpdate, this);
36497 this.ds.un("clear", this.onClear, this);
36500 ds.on("load", this.onLoad, this);
36501 ds.on("datachanged", this.onDataChange, this);
36502 ds.on("add", this.onAdd, this);
36503 ds.on("remove", this.onRemove, this);
36504 ds.on("update", this.onUpdate, this);
36505 ds.on("clear", this.onClear, this);
36510 this.cm.un("widthchange", this.onColWidthChange, this);
36511 this.cm.un("headerchange", this.onHeaderChange, this);
36512 this.cm.un("hiddenchange", this.onHiddenChange, this);
36513 this.cm.un("columnmoved", this.onColumnMove, this);
36514 this.cm.un("columnlockchange", this.onColumnLock, this);
36517 this.generateRules(cm);
36518 cm.on("widthchange", this.onColWidthChange, this);
36519 cm.on("headerchange", this.onHeaderChange, this);
36520 cm.on("hiddenchange", this.onHiddenChange, this);
36521 cm.on("columnmoved", this.onColumnMove, this);
36522 cm.on("columnlockchange", this.onColumnLock, this);
36527 init: function(grid){
36528 Roo.grid.GridView.superclass.init.call(this, grid);
36530 this.bind(grid.dataSource, grid.colModel);
36532 grid.on("headerclick", this.handleHeaderClick, this);
36534 if(grid.trackMouseOver){
36535 grid.on("mouseover", this.onRowOver, this);
36536 grid.on("mouseout", this.onRowOut, this);
36538 grid.cancelTextSelection = function(){};
36539 this.gridId = grid.id;
36541 var tpls = this.templates || {};
36544 tpls.master = new Roo.Template(
36545 '<div class="x-grid" hidefocus="true">',
36546 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
36547 '<div class="x-grid-topbar"></div>',
36548 '<div class="x-grid-scroller"><div></div></div>',
36549 '<div class="x-grid-locked">',
36550 '<div class="x-grid-header">{lockedHeader}</div>',
36551 '<div class="x-grid-body">{lockedBody}</div>',
36553 '<div class="x-grid-viewport">',
36554 '<div class="x-grid-header">{header}</div>',
36555 '<div class="x-grid-body">{body}</div>',
36557 '<div class="x-grid-bottombar"></div>',
36559 '<div class="x-grid-resize-proxy"> </div>',
36562 tpls.master.disableformats = true;
36566 tpls.header = new Roo.Template(
36567 '<table border="0" cellspacing="0" cellpadding="0">',
36568 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
36571 tpls.header.disableformats = true;
36573 tpls.header.compile();
36576 tpls.hcell = new Roo.Template(
36577 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
36578 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
36581 tpls.hcell.disableFormats = true;
36583 tpls.hcell.compile();
36586 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
36587 this.unselectableCls + '" ' + this.unselectable +'> </div>');
36588 tpls.hsplit.disableFormats = true;
36590 tpls.hsplit.compile();
36593 tpls.body = new Roo.Template(
36594 '<table border="0" cellspacing="0" cellpadding="0">',
36595 "<tbody>{rows}</tbody>",
36598 tpls.body.disableFormats = true;
36600 tpls.body.compile();
36603 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
36604 tpls.row.disableFormats = true;
36606 tpls.row.compile();
36609 tpls.cell = new Roo.Template(
36610 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
36611 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
36612 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
36615 tpls.cell.disableFormats = true;
36617 tpls.cell.compile();
36619 this.templates = tpls;
36622 // remap these for backwards compat
36623 onColWidthChange : function(){
36624 this.updateColumns.apply(this, arguments);
36626 onHeaderChange : function(){
36627 this.updateHeaders.apply(this, arguments);
36629 onHiddenChange : function(){
36630 this.handleHiddenChange.apply(this, arguments);
36632 onColumnMove : function(){
36633 this.handleColumnMove.apply(this, arguments);
36635 onColumnLock : function(){
36636 this.handleLockChange.apply(this, arguments);
36639 onDataChange : function(){
36641 this.updateHeaderSortState();
36644 onClear : function(){
36648 onUpdate : function(ds, record){
36649 this.refreshRow(record);
36652 refreshRow : function(record){
36653 var ds = this.ds, index;
36654 if(typeof record == 'number'){
36656 record = ds.getAt(index);
36658 index = ds.indexOf(record);
36660 this.insertRows(ds, index, index, true);
36661 this.onRemove(ds, record, index+1, true);
36662 this.syncRowHeights(index, index);
36664 this.fireEvent("rowupdated", this, index, record);
36667 onAdd : function(ds, records, index){
36668 this.insertRows(ds, index, index + (records.length-1));
36671 onRemove : function(ds, record, index, isUpdate){
36672 if(isUpdate !== true){
36673 this.fireEvent("beforerowremoved", this, index, record);
36675 var bt = this.getBodyTable(), lt = this.getLockedTable();
36676 if(bt.rows[index]){
36677 bt.firstChild.removeChild(bt.rows[index]);
36679 if(lt.rows[index]){
36680 lt.firstChild.removeChild(lt.rows[index]);
36682 if(isUpdate !== true){
36683 this.stripeRows(index);
36684 this.syncRowHeights(index, index);
36686 this.fireEvent("rowremoved", this, index, record);
36690 onLoad : function(){
36691 this.scrollToTop();
36695 * Scrolls the grid to the top
36697 scrollToTop : function(){
36699 this.scroller.dom.scrollTop = 0;
36705 * Gets a panel in the header of the grid that can be used for toolbars etc.
36706 * After modifying the contents of this panel a call to grid.autoSize() may be
36707 * required to register any changes in size.
36708 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
36709 * @return Roo.Element
36711 getHeaderPanel : function(doShow){
36713 this.headerPanel.show();
36715 return this.headerPanel;
36719 * Gets a panel in the footer of the grid that can be used for toolbars etc.
36720 * After modifying the contents of this panel a call to grid.autoSize() may be
36721 * required to register any changes in size.
36722 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
36723 * @return Roo.Element
36725 getFooterPanel : function(doShow){
36727 this.footerPanel.show();
36729 return this.footerPanel;
36732 initElements : function(){
36733 var E = Roo.Element;
36734 var el = this.grid.getGridEl().dom.firstChild;
36735 var cs = el.childNodes;
36737 this.el = new E(el);
36739 this.focusEl = new E(el.firstChild);
36740 this.focusEl.swallowEvent("click", true);
36742 this.headerPanel = new E(cs[1]);
36743 this.headerPanel.enableDisplayMode("block");
36745 this.scroller = new E(cs[2]);
36746 this.scrollSizer = new E(this.scroller.dom.firstChild);
36748 this.lockedWrap = new E(cs[3]);
36749 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
36750 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
36752 this.mainWrap = new E(cs[4]);
36753 this.mainHd = new E(this.mainWrap.dom.firstChild);
36754 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
36756 this.footerPanel = new E(cs[5]);
36757 this.footerPanel.enableDisplayMode("block");
36759 this.resizeProxy = new E(cs[6]);
36761 this.headerSelector = String.format(
36762 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
36763 this.lockedHd.id, this.mainHd.id
36766 this.splitterSelector = String.format(
36767 '#{0} div.x-grid-split, #{1} div.x-grid-split',
36768 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
36771 idToCssName : function(s)
36773 return s.replace(/[^a-z0-9]+/ig, '-');
36776 getHeaderCell : function(index){
36777 return Roo.DomQuery.select(this.headerSelector)[index];
36780 getHeaderCellMeasure : function(index){
36781 return this.getHeaderCell(index).firstChild;
36784 getHeaderCellText : function(index){
36785 return this.getHeaderCell(index).firstChild.firstChild;
36788 getLockedTable : function(){
36789 return this.lockedBody.dom.firstChild;
36792 getBodyTable : function(){
36793 return this.mainBody.dom.firstChild;
36796 getLockedRow : function(index){
36797 return this.getLockedTable().rows[index];
36800 getRow : function(index){
36801 return this.getBodyTable().rows[index];
36804 getRowComposite : function(index){
36806 this.rowEl = new Roo.CompositeElementLite();
36808 var els = [], lrow, mrow;
36809 if(lrow = this.getLockedRow(index)){
36812 if(mrow = this.getRow(index)){
36815 this.rowEl.elements = els;
36819 * Gets the 'td' of the cell
36821 * @param {Integer} rowIndex row to select
36822 * @param {Integer} colIndex column to select
36826 getCell : function(rowIndex, colIndex){
36827 var locked = this.cm.getLockedCount();
36829 if(colIndex < locked){
36830 source = this.lockedBody.dom.firstChild;
36832 source = this.mainBody.dom.firstChild;
36833 colIndex -= locked;
36835 return source.rows[rowIndex].childNodes[colIndex];
36838 getCellText : function(rowIndex, colIndex){
36839 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
36842 getCellBox : function(cell){
36843 var b = this.fly(cell).getBox();
36844 if(Roo.isOpera){ // opera fails to report the Y
36845 b.y = cell.offsetTop + this.mainBody.getY();
36850 getCellIndex : function(cell){
36851 var id = String(cell.className).match(this.cellRE);
36853 return parseInt(id[1], 10);
36858 findHeaderIndex : function(n){
36859 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36860 return r ? this.getCellIndex(r) : false;
36863 findHeaderCell : function(n){
36864 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36865 return r ? r : false;
36868 findRowIndex : function(n){
36872 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
36873 return r ? r.rowIndex : false;
36876 findCellIndex : function(node){
36877 var stop = this.el.dom;
36878 while(node && node != stop){
36879 if(this.findRE.test(node.className)){
36880 return this.getCellIndex(node);
36882 node = node.parentNode;
36887 getColumnId : function(index){
36888 return this.cm.getColumnId(index);
36891 getSplitters : function()
36893 if(this.splitterSelector){
36894 return Roo.DomQuery.select(this.splitterSelector);
36900 getSplitter : function(index){
36901 return this.getSplitters()[index];
36904 onRowOver : function(e, t){
36906 if((row = this.findRowIndex(t)) !== false){
36907 this.getRowComposite(row).addClass("x-grid-row-over");
36911 onRowOut : function(e, t){
36913 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
36914 this.getRowComposite(row).removeClass("x-grid-row-over");
36918 renderHeaders : function(){
36920 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
36921 var cb = [], lb = [], sb = [], lsb = [], p = {};
36922 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36923 p.cellId = "x-grid-hd-0-" + i;
36924 p.splitId = "x-grid-csplit-0-" + i;
36925 p.id = cm.getColumnId(i);
36926 p.title = cm.getColumnTooltip(i) || "";
36927 p.value = cm.getColumnHeader(i) || "";
36928 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
36929 if(!cm.isLocked(i)){
36930 cb[cb.length] = ct.apply(p);
36931 sb[sb.length] = st.apply(p);
36933 lb[lb.length] = ct.apply(p);
36934 lsb[lsb.length] = st.apply(p);
36937 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
36938 ht.apply({cells: cb.join(""), splits:sb.join("")})];
36941 updateHeaders : function(){
36942 var html = this.renderHeaders();
36943 this.lockedHd.update(html[0]);
36944 this.mainHd.update(html[1]);
36948 * Focuses the specified row.
36949 * @param {Number} row The row index
36951 focusRow : function(row)
36953 //Roo.log('GridView.focusRow');
36954 var x = this.scroller.dom.scrollLeft;
36955 this.focusCell(row, 0, false);
36956 this.scroller.dom.scrollLeft = x;
36960 * Focuses the specified cell.
36961 * @param {Number} row The row index
36962 * @param {Number} col The column index
36963 * @param {Boolean} hscroll false to disable horizontal scrolling
36965 focusCell : function(row, col, hscroll)
36967 //Roo.log('GridView.focusCell');
36968 var el = this.ensureVisible(row, col, hscroll);
36969 this.focusEl.alignTo(el, "tl-tl");
36971 this.focusEl.focus();
36973 this.focusEl.focus.defer(1, this.focusEl);
36978 * Scrolls the specified cell into view
36979 * @param {Number} row The row index
36980 * @param {Number} col The column index
36981 * @param {Boolean} hscroll false to disable horizontal scrolling
36983 ensureVisible : function(row, col, hscroll)
36985 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
36986 //return null; //disable for testing.
36987 if(typeof row != "number"){
36988 row = row.rowIndex;
36990 if(row < 0 && row >= this.ds.getCount()){
36993 col = (col !== undefined ? col : 0);
36994 var cm = this.grid.colModel;
36995 while(cm.isHidden(col)){
36999 var el = this.getCell(row, col);
37003 var c = this.scroller.dom;
37005 var ctop = parseInt(el.offsetTop, 10);
37006 var cleft = parseInt(el.offsetLeft, 10);
37007 var cbot = ctop + el.offsetHeight;
37008 var cright = cleft + el.offsetWidth;
37010 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
37011 var stop = parseInt(c.scrollTop, 10);
37012 var sleft = parseInt(c.scrollLeft, 10);
37013 var sbot = stop + ch;
37014 var sright = sleft + c.clientWidth;
37016 Roo.log('GridView.ensureVisible:' +
37018 ' c.clientHeight:' + c.clientHeight +
37019 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
37027 c.scrollTop = ctop;
37028 //Roo.log("set scrolltop to ctop DISABLE?");
37029 }else if(cbot > sbot){
37030 //Roo.log("set scrolltop to cbot-ch");
37031 c.scrollTop = cbot-ch;
37034 if(hscroll !== false){
37036 c.scrollLeft = cleft;
37037 }else if(cright > sright){
37038 c.scrollLeft = cright-c.clientWidth;
37045 updateColumns : function(){
37046 this.grid.stopEditing();
37047 var cm = this.grid.colModel, colIds = this.getColumnIds();
37048 //var totalWidth = cm.getTotalWidth();
37050 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37051 //if(cm.isHidden(i)) continue;
37052 var w = cm.getColumnWidth(i);
37053 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37054 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37056 this.updateSplitters();
37059 generateRules : function(cm){
37060 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
37061 Roo.util.CSS.removeStyleSheet(rulesId);
37062 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37063 var cid = cm.getColumnId(i);
37065 if(cm.config[i].align){
37066 align = 'text-align:'+cm.config[i].align+';';
37069 if(cm.isHidden(i)){
37070 hidden = 'display:none;';
37072 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
37074 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
37075 this.hdSelector, cid, " {\n", align, width, "}\n",
37076 this.tdSelector, cid, " {\n",hidden,"\n}\n",
37077 this.splitSelector, cid, " {\n", hidden , "\n}\n");
37079 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
37082 updateSplitters : function(){
37083 var cm = this.cm, s = this.getSplitters();
37084 if(s){ // splitters not created yet
37085 var pos = 0, locked = true;
37086 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37087 if(cm.isHidden(i)) continue;
37088 var w = cm.getColumnWidth(i); // make sure it's a number
37089 if(!cm.isLocked(i) && locked){
37094 s[i].style.left = (pos-this.splitOffset) + "px";
37099 handleHiddenChange : function(colModel, colIndex, hidden){
37101 this.hideColumn(colIndex);
37103 this.unhideColumn(colIndex);
37107 hideColumn : function(colIndex){
37108 var cid = this.getColumnId(colIndex);
37109 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
37110 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
37112 this.updateHeaders();
37114 this.updateSplitters();
37118 unhideColumn : function(colIndex){
37119 var cid = this.getColumnId(colIndex);
37120 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
37121 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
37124 this.updateHeaders();
37126 this.updateSplitters();
37130 insertRows : function(dm, firstRow, lastRow, isUpdate){
37131 if(firstRow == 0 && lastRow == dm.getCount()-1){
37135 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
37137 var s = this.getScrollState();
37138 var markup = this.renderRows(firstRow, lastRow);
37139 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
37140 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
37141 this.restoreScroll(s);
37143 this.fireEvent("rowsinserted", this, firstRow, lastRow);
37144 this.syncRowHeights(firstRow, lastRow);
37145 this.stripeRows(firstRow);
37151 bufferRows : function(markup, target, index){
37152 var before = null, trows = target.rows, tbody = target.tBodies[0];
37153 if(index < trows.length){
37154 before = trows[index];
37156 var b = document.createElement("div");
37157 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
37158 var rows = b.firstChild.rows;
37159 for(var i = 0, len = rows.length; i < len; i++){
37161 tbody.insertBefore(rows[0], before);
37163 tbody.appendChild(rows[0]);
37170 deleteRows : function(dm, firstRow, lastRow){
37171 if(dm.getRowCount()<1){
37172 this.fireEvent("beforerefresh", this);
37173 this.mainBody.update("");
37174 this.lockedBody.update("");
37175 this.fireEvent("refresh", this);
37177 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
37178 var bt = this.getBodyTable();
37179 var tbody = bt.firstChild;
37180 var rows = bt.rows;
37181 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
37182 tbody.removeChild(rows[firstRow]);
37184 this.stripeRows(firstRow);
37185 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
37189 updateRows : function(dataSource, firstRow, lastRow){
37190 var s = this.getScrollState();
37192 this.restoreScroll(s);
37195 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
37199 this.updateHeaderSortState();
37202 getScrollState : function(){
37204 var sb = this.scroller.dom;
37205 return {left: sb.scrollLeft, top: sb.scrollTop};
37208 stripeRows : function(startRow){
37209 if(!this.grid.stripeRows || this.ds.getCount() < 1){
37212 startRow = startRow || 0;
37213 var rows = this.getBodyTable().rows;
37214 var lrows = this.getLockedTable().rows;
37215 var cls = ' x-grid-row-alt ';
37216 for(var i = startRow, len = rows.length; i < len; i++){
37217 var row = rows[i], lrow = lrows[i];
37218 var isAlt = ((i+1) % 2 == 0);
37219 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
37220 if(isAlt == hasAlt){
37224 row.className += " x-grid-row-alt";
37226 row.className = row.className.replace("x-grid-row-alt", "");
37229 lrow.className = row.className;
37234 restoreScroll : function(state){
37235 //Roo.log('GridView.restoreScroll');
37236 var sb = this.scroller.dom;
37237 sb.scrollLeft = state.left;
37238 sb.scrollTop = state.top;
37242 syncScroll : function(){
37243 //Roo.log('GridView.syncScroll');
37244 var sb = this.scroller.dom;
37245 var sh = this.mainHd.dom;
37246 var bs = this.mainBody.dom;
37247 var lv = this.lockedBody.dom;
37248 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
37249 lv.scrollTop = bs.scrollTop = sb.scrollTop;
37252 handleScroll : function(e){
37254 var sb = this.scroller.dom;
37255 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
37259 handleWheel : function(e){
37260 var d = e.getWheelDelta();
37261 this.scroller.dom.scrollTop -= d*22;
37262 // set this here to prevent jumpy scrolling on large tables
37263 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
37267 renderRows : function(startRow, endRow){
37268 // pull in all the crap needed to render rows
37269 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
37270 var colCount = cm.getColumnCount();
37272 if(ds.getCount() < 1){
37276 // build a map for all the columns
37278 for(var i = 0; i < colCount; i++){
37279 var name = cm.getDataIndex(i);
37281 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
37282 renderer : cm.getRenderer(i),
37283 id : cm.getColumnId(i),
37284 locked : cm.isLocked(i)
37288 startRow = startRow || 0;
37289 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
37291 // records to render
37292 var rs = ds.getRange(startRow, endRow);
37294 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
37297 // As much as I hate to duplicate code, this was branched because FireFox really hates
37298 // [].join("") on strings. The performance difference was substantial enough to
37299 // branch this function
37300 doRender : Roo.isGecko ?
37301 function(cs, rs, ds, startRow, colCount, stripe){
37302 var ts = this.templates, ct = ts.cell, rt = ts.row;
37304 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37306 var hasListener = this.grid.hasListener('rowclass');
37308 for(var j = 0, len = rs.length; j < len; j++){
37309 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
37310 for(var i = 0; i < colCount; i++){
37312 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37314 p.css = p.attr = "";
37315 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37316 if(p.value == undefined || p.value === "") p.value = " ";
37317 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37318 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37320 var markup = ct.apply(p);
37328 if(stripe && ((rowIndex+1) % 2 == 0)){
37329 alt.push("x-grid-row-alt")
37332 alt.push( " x-grid-dirty-row");
37335 if(this.getRowClass){
37336 alt.push(this.getRowClass(r, rowIndex));
37342 rowIndex : rowIndex,
37345 this.grid.fireEvent('rowclass', this, rowcfg);
37346 alt.push(rowcfg.rowClass);
37348 rp.alt = alt.join(" ");
37349 lbuf+= rt.apply(rp);
37351 buf+= rt.apply(rp);
37353 return [lbuf, buf];
37355 function(cs, rs, ds, startRow, colCount, stripe){
37356 var ts = this.templates, ct = ts.cell, rt = ts.row;
37358 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37359 var hasListener = this.grid.hasListener('rowclass');
37362 for(var j = 0, len = rs.length; j < len; j++){
37363 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
37364 for(var i = 0; i < colCount; i++){
37366 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37368 p.css = p.attr = "";
37369 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37370 if(p.value == undefined || p.value === "") p.value = " ";
37371 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37372 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37375 var markup = ct.apply(p);
37377 cb[cb.length] = markup;
37379 lcb[lcb.length] = markup;
37383 if(stripe && ((rowIndex+1) % 2 == 0)){
37384 alt.push( "x-grid-row-alt");
37387 alt.push(" x-grid-dirty-row");
37390 if(this.getRowClass){
37391 alt.push( this.getRowClass(r, rowIndex));
37397 rowIndex : rowIndex,
37400 this.grid.fireEvent('rowclass', this, rowcfg);
37401 alt.push(rowcfg.rowClass);
37403 rp.alt = alt.join(" ");
37404 rp.cells = lcb.join("");
37405 lbuf[lbuf.length] = rt.apply(rp);
37406 rp.cells = cb.join("");
37407 buf[buf.length] = rt.apply(rp);
37409 return [lbuf.join(""), buf.join("")];
37412 renderBody : function(){
37413 var markup = this.renderRows();
37414 var bt = this.templates.body;
37415 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
37419 * Refreshes the grid
37420 * @param {Boolean} headersToo
37422 refresh : function(headersToo){
37423 this.fireEvent("beforerefresh", this);
37424 this.grid.stopEditing();
37425 var result = this.renderBody();
37426 this.lockedBody.update(result[0]);
37427 this.mainBody.update(result[1]);
37428 if(headersToo === true){
37429 this.updateHeaders();
37430 this.updateColumns();
37431 this.updateSplitters();
37432 this.updateHeaderSortState();
37434 this.syncRowHeights();
37436 this.fireEvent("refresh", this);
37439 handleColumnMove : function(cm, oldIndex, newIndex){
37440 this.indexMap = null;
37441 var s = this.getScrollState();
37442 this.refresh(true);
37443 this.restoreScroll(s);
37444 this.afterMove(newIndex);
37447 afterMove : function(colIndex){
37448 if(this.enableMoveAnim && Roo.enableFx){
37449 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
37451 // if multisort - fix sortOrder, and reload..
37452 if (this.grid.dataSource.multiSort) {
37453 // the we can call sort again..
37454 var dm = this.grid.dataSource;
37455 var cm = this.grid.colModel;
37457 for(var i = 0; i < cm.config.length; i++ ) {
37459 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
37460 continue; // dont' bother, it's not in sort list or being set.
37463 so.push(cm.config[i].dataIndex);
37466 dm.load(dm.lastOptions);
37473 updateCell : function(dm, rowIndex, dataIndex){
37474 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
37475 if(typeof colIndex == "undefined"){ // not present in grid
37478 var cm = this.grid.colModel;
37479 var cell = this.getCell(rowIndex, colIndex);
37480 var cellText = this.getCellText(rowIndex, colIndex);
37483 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
37484 id : cm.getColumnId(colIndex),
37485 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
37487 var renderer = cm.getRenderer(colIndex);
37488 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
37489 if(typeof val == "undefined" || val === "") val = " ";
37490 cellText.innerHTML = val;
37491 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
37492 this.syncRowHeights(rowIndex, rowIndex);
37495 calcColumnWidth : function(colIndex, maxRowsToMeasure){
37497 if(this.grid.autoSizeHeaders){
37498 var h = this.getHeaderCellMeasure(colIndex);
37499 maxWidth = Math.max(maxWidth, h.scrollWidth);
37502 if(this.cm.isLocked(colIndex)){
37503 tb = this.getLockedTable();
37506 tb = this.getBodyTable();
37507 index = colIndex - this.cm.getLockedCount();
37510 var rows = tb.rows;
37511 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
37512 for(var i = 0; i < stopIndex; i++){
37513 var cell = rows[i].childNodes[index].firstChild;
37514 maxWidth = Math.max(maxWidth, cell.scrollWidth);
37517 return maxWidth + /*margin for error in IE*/ 5;
37520 * Autofit a column to its content.
37521 * @param {Number} colIndex
37522 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
37524 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
37525 if(this.cm.isHidden(colIndex)){
37526 return; // can't calc a hidden column
37529 var cid = this.cm.getColumnId(colIndex);
37530 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
37531 if(this.grid.autoSizeHeaders){
37532 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
37535 var newWidth = this.calcColumnWidth(colIndex);
37536 this.cm.setColumnWidth(colIndex,
37537 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
37538 if(!suppressEvent){
37539 this.grid.fireEvent("columnresize", colIndex, newWidth);
37544 * Autofits all columns to their content and then expands to fit any extra space in the grid
37546 autoSizeColumns : function(){
37547 var cm = this.grid.colModel;
37548 var colCount = cm.getColumnCount();
37549 for(var i = 0; i < colCount; i++){
37550 this.autoSizeColumn(i, true, true);
37552 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
37555 this.updateColumns();
37561 * Autofits all columns to the grid's width proportionate with their current size
37562 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
37564 fitColumns : function(reserveScrollSpace){
37565 var cm = this.grid.colModel;
37566 var colCount = cm.getColumnCount();
37570 for (i = 0; i < colCount; i++){
37571 if(!cm.isHidden(i) && !cm.isFixed(i)){
37572 w = cm.getColumnWidth(i);
37578 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
37579 if(reserveScrollSpace){
37582 var frac = (avail - cm.getTotalWidth())/width;
37583 while (cols.length){
37586 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
37588 this.updateColumns();
37592 onRowSelect : function(rowIndex){
37593 var row = this.getRowComposite(rowIndex);
37594 row.addClass("x-grid-row-selected");
37597 onRowDeselect : function(rowIndex){
37598 var row = this.getRowComposite(rowIndex);
37599 row.removeClass("x-grid-row-selected");
37602 onCellSelect : function(row, col){
37603 var cell = this.getCell(row, col);
37605 Roo.fly(cell).addClass("x-grid-cell-selected");
37609 onCellDeselect : function(row, col){
37610 var cell = this.getCell(row, col);
37612 Roo.fly(cell).removeClass("x-grid-cell-selected");
37616 updateHeaderSortState : function(){
37618 // sort state can be single { field: xxx, direction : yyy}
37619 // or { xxx=>ASC , yyy : DESC ..... }
37622 if (!this.ds.multiSort) {
37623 var state = this.ds.getSortState();
37627 mstate[state.field] = state.direction;
37628 // FIXME... - this is not used here.. but might be elsewhere..
37629 this.sortState = state;
37632 mstate = this.ds.sortToggle;
37634 //remove existing sort classes..
37636 var sc = this.sortClasses;
37637 var hds = this.el.select(this.headerSelector).removeClass(sc);
37639 for(var f in mstate) {
37641 var sortColumn = this.cm.findColumnIndex(f);
37643 if(sortColumn != -1){
37644 var sortDir = mstate[f];
37645 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
37654 handleHeaderClick : function(g, index){
37655 if(this.headersDisabled){
37658 var dm = g.dataSource, cm = g.colModel;
37659 if(!cm.isSortable(index)){
37664 if (dm.multiSort) {
37665 // update the sortOrder
37667 for(var i = 0; i < cm.config.length; i++ ) {
37669 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
37670 continue; // dont' bother, it's not in sort list or being set.
37673 so.push(cm.config[i].dataIndex);
37679 dm.sort(cm.getDataIndex(index));
37683 destroy : function(){
37685 this.colMenu.removeAll();
37686 Roo.menu.MenuMgr.unregister(this.colMenu);
37687 this.colMenu.getEl().remove();
37688 delete this.colMenu;
37691 this.hmenu.removeAll();
37692 Roo.menu.MenuMgr.unregister(this.hmenu);
37693 this.hmenu.getEl().remove();
37696 if(this.grid.enableColumnMove){
37697 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37699 for(var dd in dds){
37700 if(!dds[dd].config.isTarget && dds[dd].dragElId){
37701 var elid = dds[dd].dragElId;
37703 Roo.get(elid).remove();
37704 } else if(dds[dd].config.isTarget){
37705 dds[dd].proxyTop.remove();
37706 dds[dd].proxyBottom.remove();
37709 if(Roo.dd.DDM.locationCache[dd]){
37710 delete Roo.dd.DDM.locationCache[dd];
37713 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37716 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
37717 this.bind(null, null);
37718 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
37721 handleLockChange : function(){
37722 this.refresh(true);
37725 onDenyColumnLock : function(){
37729 onDenyColumnHide : function(){
37733 handleHdMenuClick : function(item){
37734 var index = this.hdCtxIndex;
37735 var cm = this.cm, ds = this.ds;
37738 ds.sort(cm.getDataIndex(index), "ASC");
37741 ds.sort(cm.getDataIndex(index), "DESC");
37744 var lc = cm.getLockedCount();
37745 if(cm.getColumnCount(true) <= lc+1){
37746 this.onDenyColumnLock();
37750 cm.setLocked(index, true, true);
37751 cm.moveColumn(index, lc);
37752 this.grid.fireEvent("columnmove", index, lc);
37754 cm.setLocked(index, true);
37758 var lc = cm.getLockedCount();
37759 if((lc-1) != index){
37760 cm.setLocked(index, false, true);
37761 cm.moveColumn(index, lc-1);
37762 this.grid.fireEvent("columnmove", index, lc-1);
37764 cm.setLocked(index, false);
37768 index = cm.getIndexById(item.id.substr(4));
37770 if(item.checked && cm.getColumnCount(true) <= 1){
37771 this.onDenyColumnHide();
37774 cm.setHidden(index, item.checked);
37780 beforeColMenuShow : function(){
37781 var cm = this.cm, colCount = cm.getColumnCount();
37782 this.colMenu.removeAll();
37783 for(var i = 0; i < colCount; i++){
37784 this.colMenu.add(new Roo.menu.CheckItem({
37785 id: "col-"+cm.getColumnId(i),
37786 text: cm.getColumnHeader(i),
37787 checked: !cm.isHidden(i),
37793 handleHdCtx : function(g, index, e){
37795 var hd = this.getHeaderCell(index);
37796 this.hdCtxIndex = index;
37797 var ms = this.hmenu.items, cm = this.cm;
37798 ms.get("asc").setDisabled(!cm.isSortable(index));
37799 ms.get("desc").setDisabled(!cm.isSortable(index));
37800 if(this.grid.enableColLock !== false){
37801 ms.get("lock").setDisabled(cm.isLocked(index));
37802 ms.get("unlock").setDisabled(!cm.isLocked(index));
37804 this.hmenu.show(hd, "tl-bl");
37807 handleHdOver : function(e){
37808 var hd = this.findHeaderCell(e.getTarget());
37809 if(hd && !this.headersDisabled){
37810 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
37811 this.fly(hd).addClass("x-grid-hd-over");
37816 handleHdOut : function(e){
37817 var hd = this.findHeaderCell(e.getTarget());
37819 this.fly(hd).removeClass("x-grid-hd-over");
37823 handleSplitDblClick : function(e, t){
37824 var i = this.getCellIndex(t);
37825 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
37826 this.autoSizeColumn(i, true);
37831 render : function(){
37834 var colCount = cm.getColumnCount();
37836 if(this.grid.monitorWindowResize === true){
37837 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37839 var header = this.renderHeaders();
37840 var body = this.templates.body.apply({rows:""});
37841 var html = this.templates.master.apply({
37844 lockedHeader: header[0],
37848 //this.updateColumns();
37850 this.grid.getGridEl().dom.innerHTML = html;
37852 this.initElements();
37854 // a kludge to fix the random scolling effect in webkit
37855 this.el.on("scroll", function() {
37856 this.el.dom.scrollTop=0; // hopefully not recursive..
37859 this.scroller.on("scroll", this.handleScroll, this);
37860 this.lockedBody.on("mousewheel", this.handleWheel, this);
37861 this.mainBody.on("mousewheel", this.handleWheel, this);
37863 this.mainHd.on("mouseover", this.handleHdOver, this);
37864 this.mainHd.on("mouseout", this.handleHdOut, this);
37865 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
37866 {delegate: "."+this.splitClass});
37868 this.lockedHd.on("mouseover", this.handleHdOver, this);
37869 this.lockedHd.on("mouseout", this.handleHdOut, this);
37870 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
37871 {delegate: "."+this.splitClass});
37873 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
37874 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37877 this.updateSplitters();
37879 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
37880 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37881 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37884 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
37885 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
37887 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
37888 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
37890 if(this.grid.enableColLock !== false){
37891 this.hmenu.add('-',
37892 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
37893 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
37896 if(this.grid.enableColumnHide !== false){
37898 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
37899 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
37900 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
37902 this.hmenu.add('-',
37903 {id:"columns", text: this.columnsText, menu: this.colMenu}
37906 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
37908 this.grid.on("headercontextmenu", this.handleHdCtx, this);
37911 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
37912 this.dd = new Roo.grid.GridDragZone(this.grid, {
37913 ddGroup : this.grid.ddGroup || 'GridDD'
37919 for(var i = 0; i < colCount; i++){
37920 if(cm.isHidden(i)){
37921 this.hideColumn(i);
37923 if(cm.config[i].align){
37924 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
37925 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
37929 this.updateHeaderSortState();
37931 this.beforeInitialResize();
37934 // two part rendering gives faster view to the user
37935 this.renderPhase2.defer(1, this);
37938 renderPhase2 : function(){
37939 // render the rows now
37941 if(this.grid.autoSizeColumns){
37942 this.autoSizeColumns();
37946 beforeInitialResize : function(){
37950 onColumnSplitterMoved : function(i, w){
37951 this.userResized = true;
37952 var cm = this.grid.colModel;
37953 cm.setColumnWidth(i, w, true);
37954 var cid = cm.getColumnId(i);
37955 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37956 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37957 this.updateSplitters();
37959 this.grid.fireEvent("columnresize", i, w);
37962 syncRowHeights : function(startIndex, endIndex){
37963 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
37964 startIndex = startIndex || 0;
37965 var mrows = this.getBodyTable().rows;
37966 var lrows = this.getLockedTable().rows;
37967 var len = mrows.length-1;
37968 endIndex = Math.min(endIndex || len, len);
37969 for(var i = startIndex; i <= endIndex; i++){
37970 var m = mrows[i], l = lrows[i];
37971 var h = Math.max(m.offsetHeight, l.offsetHeight);
37972 m.style.height = l.style.height = h + "px";
37977 layout : function(initialRender, is2ndPass){
37979 var auto = g.autoHeight;
37980 var scrollOffset = 16;
37981 var c = g.getGridEl(), cm = this.cm,
37982 expandCol = g.autoExpandColumn,
37984 //c.beginMeasure();
37986 if(!c.dom.offsetWidth){ // display:none?
37988 this.lockedWrap.show();
37989 this.mainWrap.show();
37994 var hasLock = this.cm.isLocked(0);
37996 var tbh = this.headerPanel.getHeight();
37997 var bbh = this.footerPanel.getHeight();
38000 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
38001 var newHeight = ch + c.getBorderWidth("tb");
38003 newHeight = Math.min(g.maxHeight, newHeight);
38005 c.setHeight(newHeight);
38009 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
38012 var s = this.scroller;
38014 var csize = c.getSize(true);
38016 this.el.setSize(csize.width, csize.height);
38018 this.headerPanel.setWidth(csize.width);
38019 this.footerPanel.setWidth(csize.width);
38021 var hdHeight = this.mainHd.getHeight();
38022 var vw = csize.width;
38023 var vh = csize.height - (tbh + bbh);
38027 var bt = this.getBodyTable();
38028 var ltWidth = hasLock ?
38029 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
38031 var scrollHeight = bt.offsetHeight;
38032 var scrollWidth = ltWidth + bt.offsetWidth;
38033 var vscroll = false, hscroll = false;
38035 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
38037 var lw = this.lockedWrap, mw = this.mainWrap;
38038 var lb = this.lockedBody, mb = this.mainBody;
38040 setTimeout(function(){
38041 var t = s.dom.offsetTop;
38042 var w = s.dom.clientWidth,
38043 h = s.dom.clientHeight;
38046 lw.setSize(ltWidth, h);
38048 mw.setLeftTop(ltWidth, t);
38049 mw.setSize(w-ltWidth, h);
38051 lb.setHeight(h-hdHeight);
38052 mb.setHeight(h-hdHeight);
38054 if(is2ndPass !== true && !gv.userResized && expandCol){
38055 // high speed resize without full column calculation
38057 var ci = cm.getIndexById(expandCol);
38059 ci = cm.findColumnIndex(expandCol);
38061 ci = Math.max(0, ci); // make sure it's got at least the first col.
38062 var expandId = cm.getColumnId(ci);
38063 var tw = cm.getTotalWidth(false);
38064 var currentWidth = cm.getColumnWidth(ci);
38065 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
38066 if(currentWidth != cw){
38067 cm.setColumnWidth(ci, cw, true);
38068 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38069 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38070 gv.updateSplitters();
38071 gv.layout(false, true);
38083 onWindowResize : function(){
38084 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
38090 appendFooter : function(parentEl){
38094 sortAscText : "Sort Ascending",
38095 sortDescText : "Sort Descending",
38096 lockText : "Lock Column",
38097 unlockText : "Unlock Column",
38098 columnsText : "Columns"
38102 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
38103 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
38104 this.proxy.el.addClass('x-grid3-col-dd');
38107 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
38108 handleMouseDown : function(e){
38112 callHandleMouseDown : function(e){
38113 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
38118 * Ext JS Library 1.1.1
38119 * Copyright(c) 2006-2007, Ext JS, LLC.
38121 * Originally Released Under LGPL - original licence link has changed is not relivant.
38124 * <script type="text/javascript">
38128 // This is a support class used internally by the Grid components
38129 Roo.grid.SplitDragZone = function(grid, hd, hd2){
38131 this.view = grid.getView();
38132 this.proxy = this.view.resizeProxy;
38133 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
38134 "gridSplitters" + this.grid.getGridEl().id, {
38135 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
38137 this.setHandleElId(Roo.id(hd));
38138 this.setOuterHandleElId(Roo.id(hd2));
38139 this.scroll = false;
38141 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
38142 fly: Roo.Element.fly,
38144 b4StartDrag : function(x, y){
38145 this.view.headersDisabled = true;
38146 this.proxy.setHeight(this.view.mainWrap.getHeight());
38147 var w = this.cm.getColumnWidth(this.cellIndex);
38148 var minw = Math.max(w-this.grid.minColumnWidth, 0);
38149 this.resetConstraints();
38150 this.setXConstraint(minw, 1000);
38151 this.setYConstraint(0, 0);
38152 this.minX = x - minw;
38153 this.maxX = x + 1000;
38155 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
38159 handleMouseDown : function(e){
38160 ev = Roo.EventObject.setEvent(e);
38161 var t = this.fly(ev.getTarget());
38162 if(t.hasClass("x-grid-split")){
38163 this.cellIndex = this.view.getCellIndex(t.dom);
38164 this.split = t.dom;
38165 this.cm = this.grid.colModel;
38166 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
38167 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
38172 endDrag : function(e){
38173 this.view.headersDisabled = false;
38174 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
38175 var diff = endX - this.startPos;
38176 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
38179 autoOffset : function(){
38180 this.setDelta(0,0);
38184 * Ext JS Library 1.1.1
38185 * Copyright(c) 2006-2007, Ext JS, LLC.
38187 * Originally Released Under LGPL - original licence link has changed is not relivant.
38190 * <script type="text/javascript">
38194 // This is a support class used internally by the Grid components
38195 Roo.grid.GridDragZone = function(grid, config){
38196 this.view = grid.getView();
38197 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
38198 if(this.view.lockedBody){
38199 this.setHandleElId(Roo.id(this.view.mainBody.dom));
38200 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
38202 this.scroll = false;
38204 this.ddel = document.createElement('div');
38205 this.ddel.className = 'x-grid-dd-wrap';
38208 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
38209 ddGroup : "GridDD",
38211 getDragData : function(e){
38212 var t = Roo.lib.Event.getTarget(e);
38213 var rowIndex = this.view.findRowIndex(t);
38214 var sm = this.grid.selModel;
38216 //Roo.log(rowIndex);
38218 if (sm.getSelectedCell) {
38219 // cell selection..
38220 if (!sm.getSelectedCell()) {
38223 if (rowIndex != sm.getSelectedCell()[0]) {
38229 if(rowIndex !== false){
38234 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
38236 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
38239 if (e.hasModifier()){
38240 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
38243 Roo.log("getDragData");
38248 rowIndex: rowIndex,
38249 selections:sm.getSelections ? sm.getSelections() : (
38250 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
38257 onInitDrag : function(e){
38258 var data = this.dragData;
38259 this.ddel.innerHTML = this.grid.getDragDropText();
38260 this.proxy.update(this.ddel);
38261 // fire start drag?
38264 afterRepair : function(){
38265 this.dragging = false;
38268 getRepairXY : function(e, data){
38272 onEndDrag : function(data, e){
38276 onValidDrop : function(dd, e, id){
38281 beforeInvalidDrop : function(e, id){
38286 * Ext JS Library 1.1.1
38287 * Copyright(c) 2006-2007, Ext JS, LLC.
38289 * Originally Released Under LGPL - original licence link has changed is not relivant.
38292 * <script type="text/javascript">
38297 * @class Roo.grid.ColumnModel
38298 * @extends Roo.util.Observable
38299 * This is the default implementation of a ColumnModel used by the Grid. It defines
38300 * the columns in the grid.
38303 var colModel = new Roo.grid.ColumnModel([
38304 {header: "Ticker", width: 60, sortable: true, locked: true},
38305 {header: "Company Name", width: 150, sortable: true},
38306 {header: "Market Cap.", width: 100, sortable: true},
38307 {header: "$ Sales", width: 100, sortable: true, renderer: money},
38308 {header: "Employees", width: 100, sortable: true, resizable: false}
38313 * The config options listed for this class are options which may appear in each
38314 * individual column definition.
38315 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
38317 * @param {Object} config An Array of column config objects. See this class's
38318 * config objects for details.
38320 Roo.grid.ColumnModel = function(config){
38322 * The config passed into the constructor
38324 this.config = config;
38327 // if no id, create one
38328 // if the column does not have a dataIndex mapping,
38329 // map it to the order it is in the config
38330 for(var i = 0, len = config.length; i < len; i++){
38332 if(typeof c.dataIndex == "undefined"){
38335 if(typeof c.renderer == "string"){
38336 c.renderer = Roo.util.Format[c.renderer];
38338 if(typeof c.id == "undefined"){
38341 if(c.editor && c.editor.xtype){
38342 c.editor = Roo.factory(c.editor, Roo.grid);
38344 if(c.editor && c.editor.isFormField){
38345 c.editor = new Roo.grid.GridEditor(c.editor);
38347 this.lookup[c.id] = c;
38351 * The width of columns which have no width specified (defaults to 100)
38354 this.defaultWidth = 100;
38357 * Default sortable of columns which have no sortable specified (defaults to false)
38360 this.defaultSortable = false;
38364 * @event widthchange
38365 * Fires when the width of a column changes.
38366 * @param {ColumnModel} this
38367 * @param {Number} columnIndex The column index
38368 * @param {Number} newWidth The new width
38370 "widthchange": true,
38372 * @event headerchange
38373 * Fires when the text of a header changes.
38374 * @param {ColumnModel} this
38375 * @param {Number} columnIndex The column index
38376 * @param {Number} newText The new header text
38378 "headerchange": true,
38380 * @event hiddenchange
38381 * Fires when a column is hidden or "unhidden".
38382 * @param {ColumnModel} this
38383 * @param {Number} columnIndex The column index
38384 * @param {Boolean} hidden true if hidden, false otherwise
38386 "hiddenchange": true,
38388 * @event columnmoved
38389 * Fires when a column is moved.
38390 * @param {ColumnModel} this
38391 * @param {Number} oldIndex
38392 * @param {Number} newIndex
38394 "columnmoved" : true,
38396 * @event columlockchange
38397 * Fires when a column's locked state is changed
38398 * @param {ColumnModel} this
38399 * @param {Number} colIndex
38400 * @param {Boolean} locked true if locked
38402 "columnlockchange" : true
38404 Roo.grid.ColumnModel.superclass.constructor.call(this);
38406 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
38408 * @cfg {String} header The header text to display in the Grid view.
38411 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
38412 * {@link Roo.data.Record} definition from which to draw the column's value. If not
38413 * specified, the column's index is used as an index into the Record's data Array.
38416 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
38417 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
38420 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
38421 * Defaults to the value of the {@link #defaultSortable} property.
38422 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
38425 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
38428 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
38431 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
38434 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
38437 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
38438 * given the cell's data value. See {@link #setRenderer}. If not specified, the
38439 * default renderer uses the raw data value.
38442 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
38445 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
38449 * Returns the id of the column at the specified index.
38450 * @param {Number} index The column index
38451 * @return {String} the id
38453 getColumnId : function(index){
38454 return this.config[index].id;
38458 * Returns the column for a specified id.
38459 * @param {String} id The column id
38460 * @return {Object} the column
38462 getColumnById : function(id){
38463 return this.lookup[id];
38468 * Returns the column for a specified dataIndex.
38469 * @param {String} dataIndex The column dataIndex
38470 * @return {Object|Boolean} the column or false if not found
38472 getColumnByDataIndex: function(dataIndex){
38473 var index = this.findColumnIndex(dataIndex);
38474 return index > -1 ? this.config[index] : false;
38478 * Returns the index for a specified column id.
38479 * @param {String} id The column id
38480 * @return {Number} the index, or -1 if not found
38482 getIndexById : function(id){
38483 for(var i = 0, len = this.config.length; i < len; i++){
38484 if(this.config[i].id == id){
38492 * Returns the index for a specified column dataIndex.
38493 * @param {String} dataIndex The column dataIndex
38494 * @return {Number} the index, or -1 if not found
38497 findColumnIndex : function(dataIndex){
38498 for(var i = 0, len = this.config.length; i < len; i++){
38499 if(this.config[i].dataIndex == dataIndex){
38507 moveColumn : function(oldIndex, newIndex){
38508 var c = this.config[oldIndex];
38509 this.config.splice(oldIndex, 1);
38510 this.config.splice(newIndex, 0, c);
38511 this.dataMap = null;
38512 this.fireEvent("columnmoved", this, oldIndex, newIndex);
38515 isLocked : function(colIndex){
38516 return this.config[colIndex].locked === true;
38519 setLocked : function(colIndex, value, suppressEvent){
38520 if(this.isLocked(colIndex) == value){
38523 this.config[colIndex].locked = value;
38524 if(!suppressEvent){
38525 this.fireEvent("columnlockchange", this, colIndex, value);
38529 getTotalLockedWidth : function(){
38530 var totalWidth = 0;
38531 for(var i = 0; i < this.config.length; i++){
38532 if(this.isLocked(i) && !this.isHidden(i)){
38533 this.totalWidth += this.getColumnWidth(i);
38539 getLockedCount : function(){
38540 for(var i = 0, len = this.config.length; i < len; i++){
38541 if(!this.isLocked(i)){
38548 * Returns the number of columns.
38551 getColumnCount : function(visibleOnly){
38552 if(visibleOnly === true){
38554 for(var i = 0, len = this.config.length; i < len; i++){
38555 if(!this.isHidden(i)){
38561 return this.config.length;
38565 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
38566 * @param {Function} fn
38567 * @param {Object} scope (optional)
38568 * @return {Array} result
38570 getColumnsBy : function(fn, scope){
38572 for(var i = 0, len = this.config.length; i < len; i++){
38573 var c = this.config[i];
38574 if(fn.call(scope||this, c, i) === true){
38582 * Returns true if the specified column is sortable.
38583 * @param {Number} col The column index
38584 * @return {Boolean}
38586 isSortable : function(col){
38587 if(typeof this.config[col].sortable == "undefined"){
38588 return this.defaultSortable;
38590 return this.config[col].sortable;
38594 * Returns the rendering (formatting) function defined for the column.
38595 * @param {Number} col The column index.
38596 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
38598 getRenderer : function(col){
38599 if(!this.config[col].renderer){
38600 return Roo.grid.ColumnModel.defaultRenderer;
38602 return this.config[col].renderer;
38606 * Sets the rendering (formatting) function for a column.
38607 * @param {Number} col The column index
38608 * @param {Function} fn The function to use to process the cell's raw data
38609 * to return HTML markup for the grid view. The render function is called with
38610 * the following parameters:<ul>
38611 * <li>Data value.</li>
38612 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
38613 * <li>css A CSS style string to apply to the table cell.</li>
38614 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
38615 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
38616 * <li>Row index</li>
38617 * <li>Column index</li>
38618 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
38620 setRenderer : function(col, fn){
38621 this.config[col].renderer = fn;
38625 * Returns the width for the specified column.
38626 * @param {Number} col The column index
38629 getColumnWidth : function(col){
38630 return this.config[col].width * 1 || this.defaultWidth;
38634 * Sets the width for a column.
38635 * @param {Number} col The column index
38636 * @param {Number} width The new width
38638 setColumnWidth : function(col, width, suppressEvent){
38639 this.config[col].width = width;
38640 this.totalWidth = null;
38641 if(!suppressEvent){
38642 this.fireEvent("widthchange", this, col, width);
38647 * Returns the total width of all columns.
38648 * @param {Boolean} includeHidden True to include hidden column widths
38651 getTotalWidth : function(includeHidden){
38652 if(!this.totalWidth){
38653 this.totalWidth = 0;
38654 for(var i = 0, len = this.config.length; i < len; i++){
38655 if(includeHidden || !this.isHidden(i)){
38656 this.totalWidth += this.getColumnWidth(i);
38660 return this.totalWidth;
38664 * Returns the header for the specified column.
38665 * @param {Number} col The column index
38668 getColumnHeader : function(col){
38669 return this.config[col].header;
38673 * Sets the header for a column.
38674 * @param {Number} col The column index
38675 * @param {String} header The new header
38677 setColumnHeader : function(col, header){
38678 this.config[col].header = header;
38679 this.fireEvent("headerchange", this, col, header);
38683 * Returns the tooltip for the specified column.
38684 * @param {Number} col The column index
38687 getColumnTooltip : function(col){
38688 return this.config[col].tooltip;
38691 * Sets the tooltip for a column.
38692 * @param {Number} col The column index
38693 * @param {String} tooltip The new tooltip
38695 setColumnTooltip : function(col, tooltip){
38696 this.config[col].tooltip = tooltip;
38700 * Returns the dataIndex for the specified column.
38701 * @param {Number} col The column index
38704 getDataIndex : function(col){
38705 return this.config[col].dataIndex;
38709 * Sets the dataIndex for a column.
38710 * @param {Number} col The column index
38711 * @param {Number} dataIndex The new dataIndex
38713 setDataIndex : function(col, dataIndex){
38714 this.config[col].dataIndex = dataIndex;
38720 * Returns true if the cell is editable.
38721 * @param {Number} colIndex The column index
38722 * @param {Number} rowIndex The row index
38723 * @return {Boolean}
38725 isCellEditable : function(colIndex, rowIndex){
38726 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
38730 * Returns the editor defined for the cell/column.
38731 * return false or null to disable editing.
38732 * @param {Number} colIndex The column index
38733 * @param {Number} rowIndex The row index
38736 getCellEditor : function(colIndex, rowIndex){
38737 return this.config[colIndex].editor;
38741 * Sets if a column is editable.
38742 * @param {Number} col The column index
38743 * @param {Boolean} editable True if the column is editable
38745 setEditable : function(col, editable){
38746 this.config[col].editable = editable;
38751 * Returns true if the column is hidden.
38752 * @param {Number} colIndex The column index
38753 * @return {Boolean}
38755 isHidden : function(colIndex){
38756 return this.config[colIndex].hidden;
38761 * Returns true if the column width cannot be changed
38763 isFixed : function(colIndex){
38764 return this.config[colIndex].fixed;
38768 * Returns true if the column can be resized
38769 * @return {Boolean}
38771 isResizable : function(colIndex){
38772 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
38775 * Sets if a column is hidden.
38776 * @param {Number} colIndex The column index
38777 * @param {Boolean} hidden True if the column is hidden
38779 setHidden : function(colIndex, hidden){
38780 this.config[colIndex].hidden = hidden;
38781 this.totalWidth = null;
38782 this.fireEvent("hiddenchange", this, colIndex, hidden);
38786 * Sets the editor for a column.
38787 * @param {Number} col The column index
38788 * @param {Object} editor The editor object
38790 setEditor : function(col, editor){
38791 this.config[col].editor = editor;
38795 Roo.grid.ColumnModel.defaultRenderer = function(value){
38796 if(typeof value == "string" && value.length < 1){
38802 // Alias for backwards compatibility
38803 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
38806 * Ext JS Library 1.1.1
38807 * Copyright(c) 2006-2007, Ext JS, LLC.
38809 * Originally Released Under LGPL - original licence link has changed is not relivant.
38812 * <script type="text/javascript">
38816 * @class Roo.grid.AbstractSelectionModel
38817 * @extends Roo.util.Observable
38818 * Abstract base class for grid SelectionModels. It provides the interface that should be
38819 * implemented by descendant classes. This class should not be directly instantiated.
38822 Roo.grid.AbstractSelectionModel = function(){
38823 this.locked = false;
38824 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
38827 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
38828 /** @ignore Called by the grid automatically. Do not call directly. */
38829 init : function(grid){
38835 * Locks the selections.
38838 this.locked = true;
38842 * Unlocks the selections.
38844 unlock : function(){
38845 this.locked = false;
38849 * Returns true if the selections are locked.
38850 * @return {Boolean}
38852 isLocked : function(){
38853 return this.locked;
38857 * Ext JS Library 1.1.1
38858 * Copyright(c) 2006-2007, Ext JS, LLC.
38860 * Originally Released Under LGPL - original licence link has changed is not relivant.
38863 * <script type="text/javascript">
38866 * @extends Roo.grid.AbstractSelectionModel
38867 * @class Roo.grid.RowSelectionModel
38868 * The default SelectionModel used by {@link Roo.grid.Grid}.
38869 * It supports multiple selections and keyboard selection/navigation.
38871 * @param {Object} config
38873 Roo.grid.RowSelectionModel = function(config){
38874 Roo.apply(this, config);
38875 this.selections = new Roo.util.MixedCollection(false, function(o){
38880 this.lastActive = false;
38884 * @event selectionchange
38885 * Fires when the selection changes
38886 * @param {SelectionModel} this
38888 "selectionchange" : true,
38890 * @event afterselectionchange
38891 * Fires after the selection changes (eg. by key press or clicking)
38892 * @param {SelectionModel} this
38894 "afterselectionchange" : true,
38896 * @event beforerowselect
38897 * Fires when a row is selected being selected, return false to cancel.
38898 * @param {SelectionModel} this
38899 * @param {Number} rowIndex The selected index
38900 * @param {Boolean} keepExisting False if other selections will be cleared
38902 "beforerowselect" : true,
38905 * Fires when a row is selected.
38906 * @param {SelectionModel} this
38907 * @param {Number} rowIndex The selected index
38908 * @param {Roo.data.Record} r The record
38910 "rowselect" : true,
38912 * @event rowdeselect
38913 * Fires when a row is deselected.
38914 * @param {SelectionModel} this
38915 * @param {Number} rowIndex The selected index
38917 "rowdeselect" : true
38919 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
38920 this.locked = false;
38923 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
38925 * @cfg {Boolean} singleSelect
38926 * True to allow selection of only one row at a time (defaults to false)
38928 singleSelect : false,
38931 initEvents : function(){
38933 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
38934 this.grid.on("mousedown", this.handleMouseDown, this);
38935 }else{ // allow click to work like normal
38936 this.grid.on("rowclick", this.handleDragableRowClick, this);
38939 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
38940 "up" : function(e){
38942 this.selectPrevious(e.shiftKey);
38943 }else if(this.last !== false && this.lastActive !== false){
38944 var last = this.last;
38945 this.selectRange(this.last, this.lastActive-1);
38946 this.grid.getView().focusRow(this.lastActive);
38947 if(last !== false){
38951 this.selectFirstRow();
38953 this.fireEvent("afterselectionchange", this);
38955 "down" : function(e){
38957 this.selectNext(e.shiftKey);
38958 }else if(this.last !== false && this.lastActive !== false){
38959 var last = this.last;
38960 this.selectRange(this.last, this.lastActive+1);
38961 this.grid.getView().focusRow(this.lastActive);
38962 if(last !== false){
38966 this.selectFirstRow();
38968 this.fireEvent("afterselectionchange", this);
38973 var view = this.grid.view;
38974 view.on("refresh", this.onRefresh, this);
38975 view.on("rowupdated", this.onRowUpdated, this);
38976 view.on("rowremoved", this.onRemove, this);
38980 onRefresh : function(){
38981 var ds = this.grid.dataSource, i, v = this.grid.view;
38982 var s = this.selections;
38983 s.each(function(r){
38984 if((i = ds.indexOfId(r.id)) != -1){
38993 onRemove : function(v, index, r){
38994 this.selections.remove(r);
38998 onRowUpdated : function(v, index, r){
38999 if(this.isSelected(r)){
39000 v.onRowSelect(index);
39006 * @param {Array} records The records to select
39007 * @param {Boolean} keepExisting (optional) True to keep existing selections
39009 selectRecords : function(records, keepExisting){
39011 this.clearSelections();
39013 var ds = this.grid.dataSource;
39014 for(var i = 0, len = records.length; i < len; i++){
39015 this.selectRow(ds.indexOf(records[i]), true);
39020 * Gets the number of selected rows.
39023 getCount : function(){
39024 return this.selections.length;
39028 * Selects the first row in the grid.
39030 selectFirstRow : function(){
39035 * Select the last row.
39036 * @param {Boolean} keepExisting (optional) True to keep existing selections
39038 selectLastRow : function(keepExisting){
39039 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
39043 * Selects the row immediately following the last selected row.
39044 * @param {Boolean} keepExisting (optional) True to keep existing selections
39046 selectNext : function(keepExisting){
39047 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
39048 this.selectRow(this.last+1, keepExisting);
39049 this.grid.getView().focusRow(this.last);
39054 * Selects the row that precedes the last selected row.
39055 * @param {Boolean} keepExisting (optional) True to keep existing selections
39057 selectPrevious : function(keepExisting){
39059 this.selectRow(this.last-1, keepExisting);
39060 this.grid.getView().focusRow(this.last);
39065 * Returns the selected records
39066 * @return {Array} Array of selected records
39068 getSelections : function(){
39069 return [].concat(this.selections.items);
39073 * Returns the first selected record.
39076 getSelected : function(){
39077 return this.selections.itemAt(0);
39082 * Clears all selections.
39084 clearSelections : function(fast){
39085 if(this.locked) return;
39087 var ds = this.grid.dataSource;
39088 var s = this.selections;
39089 s.each(function(r){
39090 this.deselectRow(ds.indexOfId(r.id));
39094 this.selections.clear();
39101 * Selects all rows.
39103 selectAll : function(){
39104 if(this.locked) return;
39105 this.selections.clear();
39106 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
39107 this.selectRow(i, true);
39112 * Returns True if there is a selection.
39113 * @return {Boolean}
39115 hasSelection : function(){
39116 return this.selections.length > 0;
39120 * Returns True if the specified row is selected.
39121 * @param {Number/Record} record The record or index of the record to check
39122 * @return {Boolean}
39124 isSelected : function(index){
39125 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
39126 return (r && this.selections.key(r.id) ? true : false);
39130 * Returns True if the specified record id is selected.
39131 * @param {String} id The id of record to check
39132 * @return {Boolean}
39134 isIdSelected : function(id){
39135 return (this.selections.key(id) ? true : false);
39139 handleMouseDown : function(e, t){
39140 var view = this.grid.getView(), rowIndex;
39141 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
39144 if(e.shiftKey && this.last !== false){
39145 var last = this.last;
39146 this.selectRange(last, rowIndex, e.ctrlKey);
39147 this.last = last; // reset the last
39148 view.focusRow(rowIndex);
39150 var isSelected = this.isSelected(rowIndex);
39151 if(e.button !== 0 && isSelected){
39152 view.focusRow(rowIndex);
39153 }else if(e.ctrlKey && isSelected){
39154 this.deselectRow(rowIndex);
39155 }else if(!isSelected){
39156 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
39157 view.focusRow(rowIndex);
39160 this.fireEvent("afterselectionchange", this);
39163 handleDragableRowClick : function(grid, rowIndex, e)
39165 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
39166 this.selectRow(rowIndex, false);
39167 grid.view.focusRow(rowIndex);
39168 this.fireEvent("afterselectionchange", this);
39173 * Selects multiple rows.
39174 * @param {Array} rows Array of the indexes of the row to select
39175 * @param {Boolean} keepExisting (optional) True to keep existing selections
39177 selectRows : function(rows, keepExisting){
39179 this.clearSelections();
39181 for(var i = 0, len = rows.length; i < len; i++){
39182 this.selectRow(rows[i], true);
39187 * Selects a range of rows. All rows in between startRow and endRow are also selected.
39188 * @param {Number} startRow The index of the first row in the range
39189 * @param {Number} endRow The index of the last row in the range
39190 * @param {Boolean} keepExisting (optional) True to retain existing selections
39192 selectRange : function(startRow, endRow, keepExisting){
39193 if(this.locked) return;
39195 this.clearSelections();
39197 if(startRow <= endRow){
39198 for(var i = startRow; i <= endRow; i++){
39199 this.selectRow(i, true);
39202 for(var i = startRow; i >= endRow; i--){
39203 this.selectRow(i, true);
39209 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
39210 * @param {Number} startRow The index of the first row in the range
39211 * @param {Number} endRow The index of the last row in the range
39213 deselectRange : function(startRow, endRow, preventViewNotify){
39214 if(this.locked) return;
39215 for(var i = startRow; i <= endRow; i++){
39216 this.deselectRow(i, preventViewNotify);
39222 * @param {Number} row The index of the row to select
39223 * @param {Boolean} keepExisting (optional) True to keep existing selections
39225 selectRow : function(index, keepExisting, preventViewNotify){
39226 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
39227 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
39228 if(!keepExisting || this.singleSelect){
39229 this.clearSelections();
39231 var r = this.grid.dataSource.getAt(index);
39232 this.selections.add(r);
39233 this.last = this.lastActive = index;
39234 if(!preventViewNotify){
39235 this.grid.getView().onRowSelect(index);
39237 this.fireEvent("rowselect", this, index, r);
39238 this.fireEvent("selectionchange", this);
39244 * @param {Number} row The index of the row to deselect
39246 deselectRow : function(index, preventViewNotify){
39247 if(this.locked) return;
39248 if(this.last == index){
39251 if(this.lastActive == index){
39252 this.lastActive = false;
39254 var r = this.grid.dataSource.getAt(index);
39255 this.selections.remove(r);
39256 if(!preventViewNotify){
39257 this.grid.getView().onRowDeselect(index);
39259 this.fireEvent("rowdeselect", this, index);
39260 this.fireEvent("selectionchange", this);
39264 restoreLast : function(){
39266 this.last = this._last;
39271 acceptsNav : function(row, col, cm){
39272 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39276 onEditorKey : function(field, e){
39277 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
39282 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39284 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39286 }else if(k == e.ENTER && !e.ctrlKey){
39290 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
39292 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
39294 }else if(k == e.ESC){
39298 g.startEditing(newCell[0], newCell[1]);
39303 * Ext JS Library 1.1.1
39304 * Copyright(c) 2006-2007, Ext JS, LLC.
39306 * Originally Released Under LGPL - original licence link has changed is not relivant.
39309 * <script type="text/javascript">
39312 * @class Roo.grid.CellSelectionModel
39313 * @extends Roo.grid.AbstractSelectionModel
39314 * This class provides the basic implementation for cell selection in a grid.
39316 * @param {Object} config The object containing the configuration of this model.
39317 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
39319 Roo.grid.CellSelectionModel = function(config){
39320 Roo.apply(this, config);
39322 this.selection = null;
39326 * @event beforerowselect
39327 * Fires before a cell is selected.
39328 * @param {SelectionModel} this
39329 * @param {Number} rowIndex The selected row index
39330 * @param {Number} colIndex The selected cell index
39332 "beforecellselect" : true,
39334 * @event cellselect
39335 * Fires when a cell is selected.
39336 * @param {SelectionModel} this
39337 * @param {Number} rowIndex The selected row index
39338 * @param {Number} colIndex The selected cell index
39340 "cellselect" : true,
39342 * @event selectionchange
39343 * Fires when the active selection changes.
39344 * @param {SelectionModel} this
39345 * @param {Object} selection null for no selection or an object (o) with two properties
39347 <li>o.record: the record object for the row the selection is in</li>
39348 <li>o.cell: An array of [rowIndex, columnIndex]</li>
39351 "selectionchange" : true,
39354 * Fires when the tab (or enter) was pressed on the last editable cell
39355 * You can use this to trigger add new row.
39356 * @param {SelectionModel} this
39360 * @event beforeeditnext
39361 * Fires before the next editable sell is made active
39362 * You can use this to skip to another cell or fire the tabend
39363 * if you set cell to false
39364 * @param {Object} eventdata object : { cell : [ row, col ] }
39366 "beforeeditnext" : true
39368 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
39371 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
39373 enter_is_tab: false,
39376 initEvents : function(){
39377 this.grid.on("mousedown", this.handleMouseDown, this);
39378 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
39379 var view = this.grid.view;
39380 view.on("refresh", this.onViewChange, this);
39381 view.on("rowupdated", this.onRowUpdated, this);
39382 view.on("beforerowremoved", this.clearSelections, this);
39383 view.on("beforerowsinserted", this.clearSelections, this);
39384 if(this.grid.isEditor){
39385 this.grid.on("beforeedit", this.beforeEdit, this);
39390 beforeEdit : function(e){
39391 this.select(e.row, e.column, false, true, e.record);
39395 onRowUpdated : function(v, index, r){
39396 if(this.selection && this.selection.record == r){
39397 v.onCellSelect(index, this.selection.cell[1]);
39402 onViewChange : function(){
39403 this.clearSelections(true);
39407 * Returns the currently selected cell,.
39408 * @return {Array} The selected cell (row, column) or null if none selected.
39410 getSelectedCell : function(){
39411 return this.selection ? this.selection.cell : null;
39415 * Clears all selections.
39416 * @param {Boolean} true to prevent the gridview from being notified about the change.
39418 clearSelections : function(preventNotify){
39419 var s = this.selection;
39421 if(preventNotify !== true){
39422 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
39424 this.selection = null;
39425 this.fireEvent("selectionchange", this, null);
39430 * Returns true if there is a selection.
39431 * @return {Boolean}
39433 hasSelection : function(){
39434 return this.selection ? true : false;
39438 handleMouseDown : function(e, t){
39439 var v = this.grid.getView();
39440 if(this.isLocked()){
39443 var row = v.findRowIndex(t);
39444 var cell = v.findCellIndex(t);
39445 if(row !== false && cell !== false){
39446 this.select(row, cell);
39452 * @param {Number} rowIndex
39453 * @param {Number} collIndex
39455 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
39456 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
39457 this.clearSelections();
39458 r = r || this.grid.dataSource.getAt(rowIndex);
39461 cell : [rowIndex, colIndex]
39463 if(!preventViewNotify){
39464 var v = this.grid.getView();
39465 v.onCellSelect(rowIndex, colIndex);
39466 if(preventFocus !== true){
39467 v.focusCell(rowIndex, colIndex);
39470 this.fireEvent("cellselect", this, rowIndex, colIndex);
39471 this.fireEvent("selectionchange", this, this.selection);
39476 isSelectable : function(rowIndex, colIndex, cm){
39477 return !cm.isHidden(colIndex);
39481 handleKeyDown : function(e){
39482 //Roo.log('Cell Sel Model handleKeyDown');
39483 if(!e.isNavKeyPress()){
39486 var g = this.grid, s = this.selection;
39489 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
39491 this.select(cell[0], cell[1]);
39496 var walk = function(row, col, step){
39497 return g.walkCells(row, col, step, sm.isSelectable, sm);
39499 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
39506 // handled by onEditorKey
39507 if (g.isEditor && g.editing) {
39511 newCell = walk(r, c-1, -1);
39513 newCell = walk(r, c+1, 1);
39518 newCell = walk(r+1, c, 1);
39522 newCell = walk(r-1, c, -1);
39526 newCell = walk(r, c+1, 1);
39530 newCell = walk(r, c-1, -1);
39535 if(g.isEditor && !g.editing){
39536 g.startEditing(r, c);
39545 this.select(newCell[0], newCell[1]);
39551 acceptsNav : function(row, col, cm){
39552 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39556 * @param {Number} field (not used) - as it's normally used as a listener
39557 * @param {Number} e - event - fake it by using
39559 * var e = Roo.EventObjectImpl.prototype;
39560 * e.keyCode = e.TAB
39564 onEditorKey : function(field, e){
39566 var k = e.getKey(),
39569 ed = g.activeEditor,
39571 ///Roo.log('onEditorKey' + k);
39574 if (this.enter_is_tab && k == e.ENTER) {
39580 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39582 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39588 } else if(k == e.ENTER && !e.ctrlKey){
39591 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39593 } else if(k == e.ESC){
39598 var ecall = { cell : newCell, forward : forward };
39599 this.fireEvent('beforeeditnext', ecall );
39600 newCell = ecall.cell;
39601 forward = ecall.forward;
39605 //Roo.log('next cell after edit');
39606 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
39607 } else if (forward) {
39608 // tabbed past last
39609 this.fireEvent.defer(100, this, ['tabend',this]);
39614 * Ext JS Library 1.1.1
39615 * Copyright(c) 2006-2007, Ext JS, LLC.
39617 * Originally Released Under LGPL - original licence link has changed is not relivant.
39620 * <script type="text/javascript">
39624 * @class Roo.grid.EditorGrid
39625 * @extends Roo.grid.Grid
39626 * Class for creating and editable grid.
39627 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
39628 * The container MUST have some type of size defined for the grid to fill. The container will be
39629 * automatically set to position relative if it isn't already.
39630 * @param {Object} dataSource The data model to bind to
39631 * @param {Object} colModel The column model with info about this grid's columns
39633 Roo.grid.EditorGrid = function(container, config){
39634 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
39635 this.getGridEl().addClass("xedit-grid");
39637 if(!this.selModel){
39638 this.selModel = new Roo.grid.CellSelectionModel();
39641 this.activeEditor = null;
39645 * @event beforeedit
39646 * Fires before cell editing is triggered. The edit event object has the following properties <br />
39647 * <ul style="padding:5px;padding-left:16px;">
39648 * <li>grid - This grid</li>
39649 * <li>record - The record being edited</li>
39650 * <li>field - The field name being edited</li>
39651 * <li>value - The value for the field being edited.</li>
39652 * <li>row - The grid row index</li>
39653 * <li>column - The grid column index</li>
39654 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39656 * @param {Object} e An edit event (see above for description)
39658 "beforeedit" : true,
39661 * Fires after a cell is edited. <br />
39662 * <ul style="padding:5px;padding-left:16px;">
39663 * <li>grid - This grid</li>
39664 * <li>record - The record being edited</li>
39665 * <li>field - The field name being edited</li>
39666 * <li>value - The value being set</li>
39667 * <li>originalValue - The original value for the field, before the edit.</li>
39668 * <li>row - The grid row index</li>
39669 * <li>column - The grid column index</li>
39671 * @param {Object} e An edit event (see above for description)
39673 "afteredit" : true,
39675 * @event validateedit
39676 * Fires after a cell is edited, but before the value is set in the record.
39677 * You can use this to modify the value being set in the field, Return false
39678 * to cancel the change. The edit event object has the following properties <br />
39679 * <ul style="padding:5px;padding-left:16px;">
39680 * <li>editor - This editor</li>
39681 * <li>grid - This grid</li>
39682 * <li>record - The record being edited</li>
39683 * <li>field - The field name being edited</li>
39684 * <li>value - The value being set</li>
39685 * <li>originalValue - The original value for the field, before the edit.</li>
39686 * <li>row - The grid row index</li>
39687 * <li>column - The grid column index</li>
39688 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39690 * @param {Object} e An edit event (see above for description)
39692 "validateedit" : true
39694 this.on("bodyscroll", this.stopEditing, this);
39695 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
39698 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
39700 * @cfg {Number} clicksToEdit
39701 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
39708 trackMouseOver: false, // causes very odd FF errors
39710 onCellDblClick : function(g, row, col){
39711 this.startEditing(row, col);
39714 onEditComplete : function(ed, value, startValue){
39715 this.editing = false;
39716 this.activeEditor = null;
39717 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
39719 var field = this.colModel.getDataIndex(ed.col);
39724 originalValue: startValue,
39731 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
39734 if(String(value) !== String(startValue)){
39736 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
39737 r.set(field, e.value);
39738 // if we are dealing with a combo box..
39739 // then we also set the 'name' colum to be the displayField
39740 if (ed.field.displayField && ed.field.name) {
39741 r.set(ed.field.name, ed.field.el.dom.value);
39744 delete e.cancel; //?? why!!!
39745 this.fireEvent("afteredit", e);
39748 this.fireEvent("afteredit", e); // always fire it!
39750 this.view.focusCell(ed.row, ed.col);
39754 * Starts editing the specified for the specified row/column
39755 * @param {Number} rowIndex
39756 * @param {Number} colIndex
39758 startEditing : function(row, col){
39759 this.stopEditing();
39760 if(this.colModel.isCellEditable(col, row)){
39761 this.view.ensureVisible(row, col, true);
39763 var r = this.dataSource.getAt(row);
39764 var field = this.colModel.getDataIndex(col);
39765 var cell = Roo.get(this.view.getCell(row,col));
39770 value: r.data[field],
39775 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
39776 this.editing = true;
39777 var ed = this.colModel.getCellEditor(col, row);
39783 ed.render(ed.parentEl || document.body);
39789 (function(){ // complex but required for focus issues in safari, ie and opera
39793 ed.on("complete", this.onEditComplete, this, {single: true});
39794 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
39795 this.activeEditor = ed;
39796 var v = r.data[field];
39797 ed.startEdit(this.view.getCell(row, col), v);
39798 // combo's with 'displayField and name set
39799 if (ed.field.displayField && ed.field.name) {
39800 ed.field.el.dom.value = r.data[ed.field.name];
39804 }).defer(50, this);
39810 * Stops any active editing
39812 stopEditing : function(){
39813 if(this.activeEditor){
39814 this.activeEditor.completeEdit();
39816 this.activeEditor = null;
39820 * Called to get grid's drag proxy text, by default returns this.ddText.
39823 getDragDropText : function(){
39824 var count = this.selModel.getSelectedCell() ? 1 : 0;
39825 return String.format(this.ddText, count, count == 1 ? '' : 's');
39830 * Ext JS Library 1.1.1
39831 * Copyright(c) 2006-2007, Ext JS, LLC.
39833 * Originally Released Under LGPL - original licence link has changed is not relivant.
39836 * <script type="text/javascript">
39839 // private - not really -- you end up using it !
39840 // This is a support class used internally by the Grid components
39843 * @class Roo.grid.GridEditor
39844 * @extends Roo.Editor
39845 * Class for creating and editable grid elements.
39846 * @param {Object} config any settings (must include field)
39848 Roo.grid.GridEditor = function(field, config){
39849 if (!config && field.field) {
39851 field = Roo.factory(config.field, Roo.form);
39853 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
39854 field.monitorTab = false;
39857 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
39860 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
39863 alignment: "tl-tl",
39866 cls: "x-small-editor x-grid-editor",
39871 * Ext JS Library 1.1.1
39872 * Copyright(c) 2006-2007, Ext JS, LLC.
39874 * Originally Released Under LGPL - original licence link has changed is not relivant.
39877 * <script type="text/javascript">
39882 Roo.grid.PropertyRecord = Roo.data.Record.create([
39883 {name:'name',type:'string'}, 'value'
39887 Roo.grid.PropertyStore = function(grid, source){
39889 this.store = new Roo.data.Store({
39890 recordType : Roo.grid.PropertyRecord
39892 this.store.on('update', this.onUpdate, this);
39894 this.setSource(source);
39896 Roo.grid.PropertyStore.superclass.constructor.call(this);
39901 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
39902 setSource : function(o){
39904 this.store.removeAll();
39907 if(this.isEditableValue(o[k])){
39908 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
39911 this.store.loadRecords({records: data}, {}, true);
39914 onUpdate : function(ds, record, type){
39915 if(type == Roo.data.Record.EDIT){
39916 var v = record.data['value'];
39917 var oldValue = record.modified['value'];
39918 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
39919 this.source[record.id] = v;
39921 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
39928 getProperty : function(row){
39929 return this.store.getAt(row);
39932 isEditableValue: function(val){
39933 if(val && val instanceof Date){
39935 }else if(typeof val == 'object' || typeof val == 'function'){
39941 setValue : function(prop, value){
39942 this.source[prop] = value;
39943 this.store.getById(prop).set('value', value);
39946 getSource : function(){
39947 return this.source;
39951 Roo.grid.PropertyColumnModel = function(grid, store){
39954 g.PropertyColumnModel.superclass.constructor.call(this, [
39955 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
39956 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
39958 this.store = store;
39959 this.bselect = Roo.DomHelper.append(document.body, {
39960 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
39961 {tag: 'option', value: 'true', html: 'true'},
39962 {tag: 'option', value: 'false', html: 'false'}
39965 Roo.id(this.bselect);
39968 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
39969 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
39970 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
39971 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
39972 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
39974 this.renderCellDelegate = this.renderCell.createDelegate(this);
39975 this.renderPropDelegate = this.renderProp.createDelegate(this);
39978 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
39982 valueText : 'Value',
39984 dateFormat : 'm/j/Y',
39987 renderDate : function(dateVal){
39988 return dateVal.dateFormat(this.dateFormat);
39991 renderBool : function(bVal){
39992 return bVal ? 'true' : 'false';
39995 isCellEditable : function(colIndex, rowIndex){
39996 return colIndex == 1;
39999 getRenderer : function(col){
40001 this.renderCellDelegate : this.renderPropDelegate;
40004 renderProp : function(v){
40005 return this.getPropertyName(v);
40008 renderCell : function(val){
40010 if(val instanceof Date){
40011 rv = this.renderDate(val);
40012 }else if(typeof val == 'boolean'){
40013 rv = this.renderBool(val);
40015 return Roo.util.Format.htmlEncode(rv);
40018 getPropertyName : function(name){
40019 var pn = this.grid.propertyNames;
40020 return pn && pn[name] ? pn[name] : name;
40023 getCellEditor : function(colIndex, rowIndex){
40024 var p = this.store.getProperty(rowIndex);
40025 var n = p.data['name'], val = p.data['value'];
40027 if(typeof(this.grid.customEditors[n]) == 'string'){
40028 return this.editors[this.grid.customEditors[n]];
40030 if(typeof(this.grid.customEditors[n]) != 'undefined'){
40031 return this.grid.customEditors[n];
40033 if(val instanceof Date){
40034 return this.editors['date'];
40035 }else if(typeof val == 'number'){
40036 return this.editors['number'];
40037 }else if(typeof val == 'boolean'){
40038 return this.editors['boolean'];
40040 return this.editors['string'];
40046 * @class Roo.grid.PropertyGrid
40047 * @extends Roo.grid.EditorGrid
40048 * This class represents the interface of a component based property grid control.
40049 * <br><br>Usage:<pre><code>
40050 var grid = new Roo.grid.PropertyGrid("my-container-id", {
40058 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
40059 * The container MUST have some type of size defined for the grid to fill. The container will be
40060 * automatically set to position relative if it isn't already.
40061 * @param {Object} config A config object that sets properties on this grid.
40063 Roo.grid.PropertyGrid = function(container, config){
40064 config = config || {};
40065 var store = new Roo.grid.PropertyStore(this);
40066 this.store = store;
40067 var cm = new Roo.grid.PropertyColumnModel(this, store);
40068 store.store.sort('name', 'ASC');
40069 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
40072 enableColLock:false,
40073 enableColumnMove:false,
40075 trackMouseOver: false,
40078 this.getGridEl().addClass('x-props-grid');
40079 this.lastEditRow = null;
40080 this.on('columnresize', this.onColumnResize, this);
40083 * @event beforepropertychange
40084 * Fires before a property changes (return false to stop?)
40085 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40086 * @param {String} id Record Id
40087 * @param {String} newval New Value
40088 * @param {String} oldval Old Value
40090 "beforepropertychange": true,
40092 * @event propertychange
40093 * Fires after a property changes
40094 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40095 * @param {String} id Record Id
40096 * @param {String} newval New Value
40097 * @param {String} oldval Old Value
40099 "propertychange": true
40101 this.customEditors = this.customEditors || {};
40103 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
40106 * @cfg {Object} customEditors map of colnames=> custom editors.
40107 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
40108 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
40109 * false disables editing of the field.
40113 * @cfg {Object} propertyNames map of property Names to their displayed value
40116 render : function(){
40117 Roo.grid.PropertyGrid.superclass.render.call(this);
40118 this.autoSize.defer(100, this);
40121 autoSize : function(){
40122 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
40124 this.view.fitColumns();
40128 onColumnResize : function(){
40129 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
40133 * Sets the data for the Grid
40134 * accepts a Key => Value object of all the elements avaiable.
40135 * @param {Object} data to appear in grid.
40137 setSource : function(source){
40138 this.store.setSource(source);
40142 * Gets all the data from the grid.
40143 * @return {Object} data data stored in grid
40145 getSource : function(){
40146 return this.store.getSource();
40150 * Ext JS Library 1.1.1
40151 * Copyright(c) 2006-2007, Ext JS, LLC.
40153 * Originally Released Under LGPL - original licence link has changed is not relivant.
40156 * <script type="text/javascript">
40160 * @class Roo.LoadMask
40161 * A simple utility class for generically masking elements while loading data. If the element being masked has
40162 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
40163 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
40164 * element's UpdateManager load indicator and will be destroyed after the initial load.
40166 * Create a new LoadMask
40167 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
40168 * @param {Object} config The config object
40170 Roo.LoadMask = function(el, config){
40171 this.el = Roo.get(el);
40172 Roo.apply(this, config);
40174 this.store.on('beforeload', this.onBeforeLoad, this);
40175 this.store.on('load', this.onLoad, this);
40176 this.store.on('loadexception', this.onLoadException, this);
40177 this.removeMask = false;
40179 var um = this.el.getUpdateManager();
40180 um.showLoadIndicator = false; // disable the default indicator
40181 um.on('beforeupdate', this.onBeforeLoad, this);
40182 um.on('update', this.onLoad, this);
40183 um.on('failure', this.onLoad, this);
40184 this.removeMask = true;
40188 Roo.LoadMask.prototype = {
40190 * @cfg {Boolean} removeMask
40191 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
40192 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
40195 * @cfg {String} msg
40196 * The text to display in a centered loading message box (defaults to 'Loading...')
40198 msg : 'Loading...',
40200 * @cfg {String} msgCls
40201 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
40203 msgCls : 'x-mask-loading',
40206 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
40212 * Disables the mask to prevent it from being displayed
40214 disable : function(){
40215 this.disabled = true;
40219 * Enables the mask so that it can be displayed
40221 enable : function(){
40222 this.disabled = false;
40225 onLoadException : function()
40227 Roo.log(arguments);
40229 if (typeof(arguments[3]) != 'undefined') {
40230 Roo.MessageBox.alert("Error loading",arguments[3]);
40234 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
40235 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
40244 this.el.unmask(this.removeMask);
40247 onLoad : function()
40249 this.el.unmask(this.removeMask);
40253 onBeforeLoad : function(){
40254 if(!this.disabled){
40255 this.el.mask(this.msg, this.msgCls);
40260 destroy : function(){
40262 this.store.un('beforeload', this.onBeforeLoad, this);
40263 this.store.un('load', this.onLoad, this);
40264 this.store.un('loadexception', this.onLoadException, this);
40266 var um = this.el.getUpdateManager();
40267 um.un('beforeupdate', this.onBeforeLoad, this);
40268 um.un('update', this.onLoad, this);
40269 um.un('failure', this.onLoad, this);
40274 * Ext JS Library 1.1.1
40275 * Copyright(c) 2006-2007, Ext JS, LLC.
40277 * Originally Released Under LGPL - original licence link has changed is not relivant.
40280 * <script type="text/javascript">
40285 * @class Roo.XTemplate
40286 * @extends Roo.Template
40287 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
40289 var t = new Roo.XTemplate(
40290 '<select name="{name}">',
40291 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
40295 // then append, applying the master template values
40298 * Supported features:
40303 {a_variable} - output encoded.
40304 {a_variable.format:("Y-m-d")} - call a method on the variable
40305 {a_variable:raw} - unencoded output
40306 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
40307 {a_variable:this.method_on_template(...)} - call a method on the template object.
40312 <tpl for="a_variable or condition.."></tpl>
40313 <tpl if="a_variable or condition"></tpl>
40314 <tpl exec="some javascript"></tpl>
40315 <tpl name="named_template"></tpl> (experimental)
40317 <tpl for="."></tpl> - just iterate the property..
40318 <tpl for=".."></tpl> - iterates with the parent (probably the template)
40322 Roo.XTemplate = function()
40324 Roo.XTemplate.superclass.constructor.apply(this, arguments);
40331 Roo.extend(Roo.XTemplate, Roo.Template, {
40334 * The various sub templates
40339 * basic tag replacing syntax
40342 * // you can fake an object call by doing this
40346 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
40349 * compile the template
40351 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
40354 compile: function()
40358 s = ['<tpl>', s, '</tpl>'].join('');
40360 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
40361 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
40362 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
40363 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
40364 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
40369 while(true == !!(m = s.match(re))){
40370 var forMatch = m[0].match(nameRe),
40371 ifMatch = m[0].match(ifRe),
40372 execMatch = m[0].match(execRe),
40373 namedMatch = m[0].match(namedRe),
40378 name = forMatch && forMatch[1] ? forMatch[1] : '';
40381 // if - puts fn into test..
40382 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
40384 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
40389 // exec - calls a function... returns empty if true is returned.
40390 exp = execMatch && execMatch[1] ? execMatch[1] : null;
40392 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
40400 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
40401 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
40402 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
40405 var uid = namedMatch ? namedMatch[1] : id;
40409 id: namedMatch ? namedMatch[1] : id,
40416 s = s.replace(m[0], '');
40418 s = s.replace(m[0], '{xtpl'+ id + '}');
40423 for(var i = tpls.length-1; i >= 0; --i){
40424 this.compileTpl(tpls[i]);
40425 this.tpls[tpls[i].id] = tpls[i];
40427 this.master = tpls[tpls.length-1];
40431 * same as applyTemplate, except it's done to one of the subTemplates
40432 * when using named templates, you can do:
40434 * var str = pl.applySubTemplate('your-name', values);
40437 * @param {Number} id of the template
40438 * @param {Object} values to apply to template
40439 * @param {Object} parent (normaly the instance of this object)
40441 applySubTemplate : function(id, values, parent)
40445 var t = this.tpls[id];
40449 if(t.test && !t.test.call(this, values, parent)){
40453 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
40454 Roo.log(e.toString());
40460 if(t.exec && t.exec.call(this, values, parent)){
40464 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
40465 Roo.log(e.toString());
40470 var vs = t.target ? t.target.call(this, values, parent) : values;
40471 parent = t.target ? values : parent;
40472 if(t.target && vs instanceof Array){
40474 for(var i = 0, len = vs.length; i < len; i++){
40475 buf[buf.length] = t.compiled.call(this, vs[i], parent);
40477 return buf.join('');
40479 return t.compiled.call(this, vs, parent);
40481 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
40482 Roo.log(e.toString());
40483 Roo.log(t.compiled);
40488 compileTpl : function(tpl)
40490 var fm = Roo.util.Format;
40491 var useF = this.disableFormats !== true;
40492 var sep = Roo.isGecko ? "+" : ",";
40493 var undef = function(str) {
40494 Roo.log("Property not found :" + str);
40498 var fn = function(m, name, format, args)
40500 //Roo.log(arguments);
40501 args = args ? args.replace(/\\'/g,"'") : args;
40502 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
40503 if (typeof(format) == 'undefined') {
40504 format= 'htmlEncode';
40506 if (format == 'raw' ) {
40510 if(name.substr(0, 4) == 'xtpl'){
40511 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
40514 // build an array of options to determine if value is undefined..
40516 // basically get 'xxxx.yyyy' then do
40517 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
40518 // (function () { Roo.log("Property not found"); return ''; })() :
40523 Roo.each(name.split('.'), function(st) {
40524 lookfor += (lookfor.length ? '.': '') + st;
40525 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
40528 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
40531 if(format && useF){
40533 args = args ? ',' + args : "";
40535 if(format.substr(0, 5) != "this."){
40536 format = "fm." + format + '(';
40538 format = 'this.call("'+ format.substr(5) + '", ';
40542 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
40546 // called with xxyx.yuu:(test,test)
40548 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
40550 // raw.. - :raw modifier..
40551 return "'"+ sep + udef_st + name + ")"+sep+"'";
40555 // branched to use + in gecko and [].join() in others
40557 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
40558 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
40561 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
40562 body.push(tpl.body.replace(/(\r\n|\n)/g,
40563 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
40564 body.push("'].join('');};};");
40565 body = body.join('');
40568 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
40570 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
40576 applyTemplate : function(values){
40577 return this.master.compiled.call(this, values, {});
40578 //var s = this.subs;
40581 apply : function(){
40582 return this.applyTemplate.apply(this, arguments);
40587 Roo.XTemplate.from = function(el){
40588 el = Roo.getDom(el);
40589 return new Roo.XTemplate(el.value || el.innerHTML);
40591 * Original code for Roojs - LGPL
40592 * <script type="text/javascript">
40596 * @class Roo.XComponent
40597 * A delayed Element creator...
40598 * Or a way to group chunks of interface together.
40600 * Mypart.xyx = new Roo.XComponent({
40602 parent : 'Mypart.xyz', // empty == document.element.!!
40606 disabled : function() {}
40608 tree : function() { // return an tree of xtype declared components
40612 xtype : 'NestedLayoutPanel',
40619 * It can be used to build a big heiracy, with parent etc.
40620 * or you can just use this to render a single compoent to a dom element
40621 * MYPART.render(Roo.Element | String(id) | dom_element )
40623 * @extends Roo.util.Observable
40625 * @param cfg {Object} configuration of component
40628 Roo.XComponent = function(cfg) {
40629 Roo.apply(this, cfg);
40633 * Fires when this the componnt is built
40634 * @param {Roo.XComponent} c the component
40639 this.region = this.region || 'center'; // default..
40640 Roo.XComponent.register(this);
40641 this.modules = false;
40642 this.el = false; // where the layout goes..
40646 Roo.extend(Roo.XComponent, Roo.util.Observable, {
40649 * The created element (with Roo.factory())
40650 * @type {Roo.Layout}
40656 * for BC - use el in new code
40657 * @type {Roo.Layout}
40663 * for BC - use el in new code
40664 * @type {Roo.Layout}
40669 * @cfg {Function|boolean} disabled
40670 * If this module is disabled by some rule, return true from the funtion
40675 * @cfg {String} parent
40676 * Name of parent element which it get xtype added to..
40681 * @cfg {String} order
40682 * Used to set the order in which elements are created (usefull for multiple tabs)
40687 * @cfg {String} name
40688 * String to display while loading.
40692 * @cfg {String} region
40693 * Region to render component to (defaults to center)
40698 * @cfg {Array} items
40699 * A single item array - the first element is the root of the tree..
40700 * It's done this way to stay compatible with the Xtype system...
40706 * The method that retuns the tree of parts that make up this compoennt
40713 * render element to dom or tree
40714 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
40717 render : function(el)
40721 var hp = this.parent ? 1 : 0;
40723 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
40724 // if parent is a '#.....' string, then let's use that..
40725 var ename = this.parent.substr(1)
40726 this.parent = (this.parent == '#bootstrap') ? { el : true} : false; // flags it as a top module...
40727 el = Roo.get(ename);
40728 if (!el && !this.parent) {
40729 Roo.log("Warning - element can not be found :#" + ename );
40735 if (!this.parent) {
40737 el = el ? Roo.get(el) : false;
40739 // it's a top level one..
40741 el : new Roo.BorderLayout(el || document.body, {
40747 tabPosition: 'top',
40748 //resizeTabs: true,
40749 alwaysShowTabs: el && hp? false : true,
40750 hideTabs: el || !hp ? true : false,
40757 if (!this.parent.el) {
40758 // probably an old style ctor, which has been disabled.
40762 // The 'tree' method is '_tree now'
40764 var tree = this._tree ? this._tree() : this.tree();
40765 tree.region = tree.region || this.region;
40766 this.el = this.parent.el.addxtype(tree);
40767 this.fireEvent('built', this);
40769 this.panel = this.el;
40770 this.layout = this.panel.layout;
40771 this.parentLayout = this.parent.layout || false;
40777 Roo.apply(Roo.XComponent, {
40779 * @property hideProgress
40780 * true to disable the building progress bar.. usefull on single page renders.
40783 hideProgress : false,
40785 * @property buildCompleted
40786 * True when the builder has completed building the interface.
40789 buildCompleted : false,
40792 * @property topModule
40793 * the upper most module - uses document.element as it's constructor.
40800 * @property modules
40801 * array of modules to be created by registration system.
40802 * @type {Array} of Roo.XComponent
40807 * @property elmodules
40808 * array of modules to be created by which use #ID
40809 * @type {Array} of Roo.XComponent
40816 * Register components to be built later.
40818 * This solves the following issues
40819 * - Building is not done on page load, but after an authentication process has occured.
40820 * - Interface elements are registered on page load
40821 * - Parent Interface elements may not be loaded before child, so this handles that..
40828 module : 'Pman.Tab.projectMgr',
40830 parent : 'Pman.layout',
40831 disabled : false, // or use a function..
40834 * * @param {Object} details about module
40836 register : function(obj) {
40838 Roo.XComponent.event.fireEvent('register', obj);
40839 switch(typeof(obj.disabled) ) {
40845 if ( obj.disabled() ) {
40851 if (obj.disabled) {
40857 this.modules.push(obj);
40861 * convert a string to an object..
40862 * eg. 'AAA.BBB' -> finds AAA.BBB
40866 toObject : function(str)
40868 if (!str || typeof(str) == 'object') {
40871 if (str.substring(0,1) == '#') {
40875 var ar = str.split('.');
40880 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
40882 throw "Module not found : " + str;
40886 throw "Module not found : " + str;
40888 Roo.each(ar, function(e) {
40889 if (typeof(o[e]) == 'undefined') {
40890 throw "Module not found : " + str;
40901 * move modules into their correct place in the tree..
40904 preBuild : function ()
40907 Roo.each(this.modules , function (obj)
40909 Roo.XComponent.event.fireEvent('beforebuild', obj);
40911 var opar = obj.parent;
40913 obj.parent = this.toObject(opar);
40915 Roo.log("parent:toObject failed: " + e.toString());
40920 Roo.debug && Roo.log("GOT top level module");
40921 Roo.debug && Roo.log(obj);
40922 obj.modules = new Roo.util.MixedCollection(false,
40923 function(o) { return o.order + '' }
40925 this.topModule = obj;
40928 // parent is a string (usually a dom element name..)
40929 if (typeof(obj.parent) == 'string') {
40930 this.elmodules.push(obj);
40933 if (obj.parent.constructor != Roo.XComponent) {
40934 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
40936 if (!obj.parent.modules) {
40937 obj.parent.modules = new Roo.util.MixedCollection(false,
40938 function(o) { return o.order + '' }
40941 if (obj.parent.disabled) {
40942 obj.disabled = true;
40944 obj.parent.modules.add(obj);
40949 * make a list of modules to build.
40950 * @return {Array} list of modules.
40953 buildOrder : function()
40956 var cmp = function(a,b) {
40957 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
40959 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
40960 throw "No top level modules to build";
40963 // make a flat list in order of modules to build.
40964 var mods = this.topModule ? [ this.topModule ] : [];
40967 // elmodules (is a list of DOM based modules )
40968 Roo.each(this.elmodules, function(e) {
40970 if (!this.topModule &&
40971 typeof(e.parent) == 'string' &&
40972 e.parent.substring(0,1) == '#' &&
40973 Roo.get(e.parent.substr(1))
40976 _this.topModule = e;
40982 // add modules to their parents..
40983 var addMod = function(m) {
40984 Roo.debug && Roo.log("build Order: add: " + m.name);
40987 if (m.modules && !m.disabled) {
40988 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
40989 m.modules.keySort('ASC', cmp );
40990 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
40992 m.modules.each(addMod);
40994 Roo.debug && Roo.log("build Order: no child modules");
40996 // not sure if this is used any more..
40998 m.finalize.name = m.name + " (clean up) ";
40999 mods.push(m.finalize);
41003 if (this.topModule && this.topModule.modules) {
41004 this.topModule.modules.keySort('ASC', cmp );
41005 this.topModule.modules.each(addMod);
41011 * Build the registered modules.
41012 * @param {Object} parent element.
41013 * @param {Function} optional method to call after module has been added.
41021 var mods = this.buildOrder();
41023 //this.allmods = mods;
41024 //Roo.debug && Roo.log(mods);
41026 if (!mods.length) { // should not happen
41027 throw "NO modules!!!";
41031 var msg = "Building Interface...";
41032 // flash it up as modal - so we store the mask!?
41033 if (!this.hideProgress) {
41034 Roo.MessageBox.show({ title: 'loading' });
41035 Roo.MessageBox.show({
41036 title: "Please wait...",
41045 var total = mods.length;
41048 var progressRun = function() {
41049 if (!mods.length) {
41050 Roo.debug && Roo.log('hide?');
41051 if (!this.hideProgress) {
41052 Roo.MessageBox.hide();
41054 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
41060 var m = mods.shift();
41063 Roo.debug && Roo.log(m);
41064 // not sure if this is supported any more.. - modules that are are just function
41065 if (typeof(m) == 'function') {
41067 return progressRun.defer(10, _this);
41071 msg = "Building Interface " + (total - mods.length) +
41073 (m.name ? (' - ' + m.name) : '');
41074 Roo.debug && Roo.log(msg);
41075 if (!this.hideProgress) {
41076 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
41080 // is the module disabled?
41081 var disabled = (typeof(m.disabled) == 'function') ?
41082 m.disabled.call(m.module.disabled) : m.disabled;
41086 return progressRun(); // we do not update the display!
41094 // it's 10 on top level, and 1 on others??? why...
41095 return progressRun.defer(10, _this);
41098 progressRun.defer(1, _this);
41112 * wrapper for event.on - aliased later..
41113 * Typically use to register a event handler for register:
41115 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
41124 Roo.XComponent.event = new Roo.util.Observable({
41128 * Fires when an Component is registered,
41129 * set the disable property on the Component to stop registration.
41130 * @param {Roo.XComponent} c the component being registerd.
41135 * @event beforebuild
41136 * Fires before each Component is built
41137 * can be used to apply permissions.
41138 * @param {Roo.XComponent} c the component being registerd.
41141 'beforebuild' : true,
41143 * @event buildcomplete
41144 * Fires on the top level element when all elements have been built
41145 * @param {Roo.XComponent} the top level component.
41147 'buildcomplete' : true
41152 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);