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"],
26740 * @cfg {String} defaultFont default font to use.
26742 defaultFont: 'tahoma',
26744 fontSelect : false,
26747 formatCombo : false,
26749 init : function(editor)
26751 this.editor = editor;
26754 var fid = editor.frameId;
26756 function btn(id, toggle, handler){
26757 var xid = fid + '-'+ id ;
26761 cls : 'x-btn-icon x-edit-'+id,
26762 enableToggle:toggle !== false,
26763 scope: editor, // was editor...
26764 handler:handler||editor.relayBtnCmd,
26765 clickEvent:'mousedown',
26766 tooltip: etb.buttonTips[id] || undefined, ///tips ???
26773 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
26775 // stop form submits
26776 tb.el.on('click', function(e){
26777 e.preventDefault(); // what does this do?
26780 if(!this.disable.font) { // && !Roo.isSafari){
26781 /* why no safari for fonts
26782 editor.fontSelect = tb.el.createChild({
26785 cls:'x-font-select',
26786 html: this.createFontOptions()
26789 editor.fontSelect.on('change', function(){
26790 var font = editor.fontSelect.dom.value;
26791 editor.relayCmd('fontname', font);
26792 editor.deferFocus();
26796 editor.fontSelect.dom,
26802 if(!this.disable.formats){
26803 this.formatCombo = new Roo.form.ComboBox({
26804 store: new Roo.data.SimpleStore({
26807 data : this.formats // from states.js
26811 //autoCreate : {tag: "div", size: "20"},
26812 displayField:'tag',
26816 triggerAction: 'all',
26817 emptyText:'Add tag',
26818 selectOnFocus:true,
26821 'select': function(c, r, i) {
26822 editor.insertTag(r.get('tag'));
26828 tb.addField(this.formatCombo);
26832 if(!this.disable.format){
26839 if(!this.disable.fontSize){
26844 btn('increasefontsize', false, editor.adjustFont),
26845 btn('decreasefontsize', false, editor.adjustFont)
26850 if(!this.disable.colors){
26853 id:editor.frameId +'-forecolor',
26854 cls:'x-btn-icon x-edit-forecolor',
26855 clickEvent:'mousedown',
26856 tooltip: this.buttonTips['forecolor'] || undefined,
26858 menu : new Roo.menu.ColorMenu({
26859 allowReselect: true,
26860 focus: Roo.emptyFn,
26863 selectHandler: function(cp, color){
26864 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
26865 editor.deferFocus();
26868 clickEvent:'mousedown'
26871 id:editor.frameId +'backcolor',
26872 cls:'x-btn-icon x-edit-backcolor',
26873 clickEvent:'mousedown',
26874 tooltip: this.buttonTips['backcolor'] || undefined,
26876 menu : new Roo.menu.ColorMenu({
26877 focus: Roo.emptyFn,
26880 allowReselect: true,
26881 selectHandler: function(cp, color){
26883 editor.execCmd('useCSS', false);
26884 editor.execCmd('hilitecolor', color);
26885 editor.execCmd('useCSS', true);
26886 editor.deferFocus();
26888 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
26889 Roo.isSafari || Roo.isIE ? '#'+color : color);
26890 editor.deferFocus();
26894 clickEvent:'mousedown'
26899 // now add all the items...
26902 if(!this.disable.alignments){
26905 btn('justifyleft'),
26906 btn('justifycenter'),
26907 btn('justifyright')
26911 //if(!Roo.isSafari){
26912 if(!this.disable.links){
26915 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
26919 if(!this.disable.lists){
26922 btn('insertorderedlist'),
26923 btn('insertunorderedlist')
26926 if(!this.disable.sourceEdit){
26929 btn('sourceedit', true, function(btn){
26930 this.toggleSourceEdit(btn.pressed);
26937 // special menu.. - needs to be tidied up..
26938 if (!this.disable.special) {
26941 cls: 'x-edit-none',
26947 for (var i =0; i < this.specialChars.length; i++) {
26948 smenu.menu.items.push({
26950 html: this.specialChars[i],
26951 handler: function(a,b) {
26952 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
26953 //editor.insertAtCursor(a.html);
26966 if (!this.disable.specialElements) {
26969 cls: 'x-edit-none',
26974 for (var i =0; i < this.specialElements.length; i++) {
26975 semenu.menu.items.push(
26977 handler: function(a,b) {
26978 editor.insertAtCursor(this.ihtml);
26980 }, this.specialElements[i])
26992 for(var i =0; i< this.btns.length;i++) {
26993 var b = Roo.factory(this.btns[i],Roo.form);
26994 b.cls = 'x-edit-none';
27003 // disable everything...
27005 this.tb.items.each(function(item){
27006 if(item.id != editor.frameId+ '-sourceedit'){
27010 this.rendered = true;
27012 // the all the btns;
27013 editor.on('editorevent', this.updateToolbar, this);
27014 // other toolbars need to implement this..
27015 //editor.on('editmodechange', this.updateToolbar, this);
27021 * Protected method that will not generally be called directly. It triggers
27022 * a toolbar update by reading the markup state of the current selection in the editor.
27024 updateToolbar: function(){
27026 if(!this.editor.activated){
27027 this.editor.onFirstFocus();
27031 var btns = this.tb.items.map,
27032 doc = this.editor.doc,
27033 frameId = this.editor.frameId;
27035 if(!this.disable.font && !Roo.isSafari){
27037 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
27038 if(name != this.fontSelect.dom.value){
27039 this.fontSelect.dom.value = name;
27043 if(!this.disable.format){
27044 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
27045 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
27046 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
27048 if(!this.disable.alignments){
27049 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
27050 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
27051 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
27053 if(!Roo.isSafari && !this.disable.lists){
27054 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
27055 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
27058 var ans = this.editor.getAllAncestors();
27059 if (this.formatCombo) {
27062 var store = this.formatCombo.store;
27063 this.formatCombo.setValue("");
27064 for (var i =0; i < ans.length;i++) {
27065 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
27067 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
27075 // hides menus... - so this cant be on a menu...
27076 Roo.menu.MenuMgr.hideAll();
27078 //this.editorsyncValue();
27082 createFontOptions : function(){
27083 var buf = [], fs = this.fontFamilies, ff, lc;
27087 for(var i = 0, len = fs.length; i< len; i++){
27089 lc = ff.toLowerCase();
27091 '<option value="',lc,'" style="font-family:',ff,';"',
27092 (this.defaultFont == lc ? ' selected="true">' : '>'),
27097 return buf.join('');
27100 toggleSourceEdit : function(sourceEditMode){
27101 if(sourceEditMode === undefined){
27102 sourceEditMode = !this.sourceEditMode;
27104 this.sourceEditMode = sourceEditMode === true;
27105 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
27106 // just toggle the button?
27107 if(btn.pressed !== this.editor.sourceEditMode){
27108 btn.toggle(this.editor.sourceEditMode);
27112 if(this.sourceEditMode){
27113 this.tb.items.each(function(item){
27114 if(item.cmd != 'sourceedit'){
27120 if(this.initialized){
27121 this.tb.items.each(function(item){
27127 // tell the editor that it's been pressed..
27128 this.editor.toggleSourceEdit(sourceEditMode);
27132 * Object collection of toolbar tooltips for the buttons in the editor. The key
27133 * is the command id associated with that button and the value is a valid QuickTips object.
27138 title: 'Bold (Ctrl+B)',
27139 text: 'Make the selected text bold.',
27140 cls: 'x-html-editor-tip'
27143 title: 'Italic (Ctrl+I)',
27144 text: 'Make the selected text italic.',
27145 cls: 'x-html-editor-tip'
27153 title: 'Bold (Ctrl+B)',
27154 text: 'Make the selected text bold.',
27155 cls: 'x-html-editor-tip'
27158 title: 'Italic (Ctrl+I)',
27159 text: 'Make the selected text italic.',
27160 cls: 'x-html-editor-tip'
27163 title: 'Underline (Ctrl+U)',
27164 text: 'Underline the selected text.',
27165 cls: 'x-html-editor-tip'
27167 increasefontsize : {
27168 title: 'Grow Text',
27169 text: 'Increase the font size.',
27170 cls: 'x-html-editor-tip'
27172 decreasefontsize : {
27173 title: 'Shrink Text',
27174 text: 'Decrease the font size.',
27175 cls: 'x-html-editor-tip'
27178 title: 'Text Highlight Color',
27179 text: 'Change the background color of the selected text.',
27180 cls: 'x-html-editor-tip'
27183 title: 'Font Color',
27184 text: 'Change the color of the selected text.',
27185 cls: 'x-html-editor-tip'
27188 title: 'Align Text Left',
27189 text: 'Align text to the left.',
27190 cls: 'x-html-editor-tip'
27193 title: 'Center Text',
27194 text: 'Center text in the editor.',
27195 cls: 'x-html-editor-tip'
27198 title: 'Align Text Right',
27199 text: 'Align text to the right.',
27200 cls: 'x-html-editor-tip'
27202 insertunorderedlist : {
27203 title: 'Bullet List',
27204 text: 'Start a bulleted list.',
27205 cls: 'x-html-editor-tip'
27207 insertorderedlist : {
27208 title: 'Numbered List',
27209 text: 'Start a numbered list.',
27210 cls: 'x-html-editor-tip'
27213 title: 'Hyperlink',
27214 text: 'Make the selected text a hyperlink.',
27215 cls: 'x-html-editor-tip'
27218 title: 'Source Edit',
27219 text: 'Switch to source editing mode.',
27220 cls: 'x-html-editor-tip'
27224 onDestroy : function(){
27227 this.tb.items.each(function(item){
27229 item.menu.removeAll();
27231 item.menu.el.destroy();
27239 onFirstFocus: function() {
27240 this.tb.items.each(function(item){
27249 // <script type="text/javascript">
27252 * Ext JS Library 1.1.1
27253 * Copyright(c) 2006-2007, Ext JS, LLC.
27260 * @class Roo.form.HtmlEditor.ToolbarContext
27265 new Roo.form.HtmlEditor({
27268 { xtype: 'ToolbarStandard', styles : {} }
27269 { xtype: 'ToolbarContext', disable : {} }
27275 * @config : {Object} disable List of elements to disable.. (not done yet.)
27276 * @config : {Object} styles Map of styles available.
27280 Roo.form.HtmlEditor.ToolbarContext = function(config)
27283 Roo.apply(this, config);
27284 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
27285 // dont call parent... till later.
27286 this.styles = this.styles || {};
27291 Roo.form.HtmlEditor.ToolbarContext.types = {
27303 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
27365 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
27370 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
27380 style : 'fontFamily',
27381 displayField: 'display',
27382 optname : 'font-family',
27431 // should we really allow this??
27432 // should this just be
27443 style : 'fontFamily',
27444 displayField: 'display',
27445 optname : 'font-family',
27452 style : 'fontFamily',
27453 displayField: 'display',
27454 optname : 'font-family',
27461 style : 'fontFamily',
27462 displayField: 'display',
27463 optname : 'font-family',
27474 // this should be configurable.. - you can either set it up using stores, or modify options somehwere..
27475 Roo.form.HtmlEditor.ToolbarContext.stores = false;
27477 Roo.form.HtmlEditor.ToolbarContext.options = {
27479 [ 'Helvetica,Arial,sans-serif', 'Helvetica'],
27480 [ 'Courier New', 'Courier New'],
27481 [ 'Tahoma', 'Tahoma'],
27482 [ 'Times New Roman,serif', 'Times'],
27483 [ 'Verdana','Verdana' ]
27487 // fixme - these need to be configurable..
27490 Roo.form.HtmlEditor.ToolbarContext.types
27493 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
27501 * @cfg {Object} disable List of toolbar elements to disable
27506 * @cfg {Object} styles List of styles
27507 * eg. { '*' : [ 'headline' ] , 'TD' : [ 'underline', 'double-underline' ] }
27509 * These must be defined in the page, so they get rendered correctly..
27520 init : function(editor)
27522 this.editor = editor;
27525 var fid = editor.frameId;
27527 function btn(id, toggle, handler){
27528 var xid = fid + '-'+ id ;
27532 cls : 'x-btn-icon x-edit-'+id,
27533 enableToggle:toggle !== false,
27534 scope: editor, // was editor...
27535 handler:handler||editor.relayBtnCmd,
27536 clickEvent:'mousedown',
27537 tooltip: etb.buttonTips[id] || undefined, ///tips ???
27541 // create a new element.
27542 var wdiv = editor.wrap.createChild({
27544 }, editor.wrap.dom.firstChild.nextSibling, true);
27546 // can we do this more than once??
27548 // stop form submits
27551 // disable everything...
27552 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27553 this.toolbars = {};
27555 for (var i in ty) {
27557 this.toolbars[i] = this.buildToolbar(ty[i],i);
27559 this.tb = this.toolbars.BODY;
27561 this.buildFooter();
27562 this.footer.show();
27563 editor.on('hide', function( ) { this.footer.hide() }, this);
27564 editor.on('show', function( ) { this.footer.show() }, this);
27567 this.rendered = true;
27569 // the all the btns;
27570 editor.on('editorevent', this.updateToolbar, this);
27571 // other toolbars need to implement this..
27572 //editor.on('editmodechange', this.updateToolbar, this);
27578 * Protected method that will not generally be called directly. It triggers
27579 * a toolbar update by reading the markup state of the current selection in the editor.
27581 updateToolbar: function(editor,ev,sel){
27584 // capture mouse up - this is handy for selecting images..
27585 // perhaps should go somewhere else...
27586 if(!this.editor.activated){
27587 this.editor.onFirstFocus();
27591 // http://developer.yahoo.com/yui/docs/simple-editor.js.html
27592 // selectNode - might want to handle IE?
27594 (ev.type == 'mouseup' || ev.type == 'click' ) &&
27595 ev.target && ev.target.tagName == 'IMG') {
27596 // they have click on an image...
27597 // let's see if we can change the selection...
27600 var nodeRange = sel.ownerDocument.createRange();
27602 nodeRange.selectNode(sel);
27604 nodeRange.selectNodeContents(sel);
27606 //nodeRange.collapse(true);
27607 var s = editor.win.getSelection();
27608 s.removeAllRanges();
27609 s.addRange(nodeRange);
27613 var updateFooter = sel ? false : true;
27616 var ans = this.editor.getAllAncestors();
27619 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
27622 sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
27623 sel = sel ? sel : this.editor.doc.body;
27624 sel = sel.tagName.length ? sel : this.editor.doc.body;
27627 // pick a menu that exists..
27628 var tn = sel.tagName.toUpperCase();
27629 //sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
27631 tn = sel.tagName.toUpperCase();
27633 var lastSel = this.tb.selectedNode
27635 this.tb.selectedNode = sel;
27637 // if current menu does not match..
27638 if ((this.tb.name != tn) || (lastSel != this.tb.selectedNode)) {
27641 ///console.log("show: " + tn);
27642 this.tb = typeof(ty[tn]) != 'undefined' ? this.toolbars[tn] : this.toolbars['*'];
27645 this.tb.items.first().el.innerHTML = tn + ': ';
27648 // update attributes
27649 if (this.tb.fields) {
27650 this.tb.fields.each(function(e) {
27652 e.setValue(sel.style[e.stylename]);
27655 e.setValue(sel.getAttribute(e.attrname));
27659 var hasStyles = false;
27660 for(var i in this.styles) {
27667 var st = this.tb.fields.item(0);
27669 st.store.removeAll();
27672 var cn = sel.className.split(/\s+/);
27675 if (this.styles['*']) {
27677 Roo.each(this.styles['*'], function(v) {
27678 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27681 if (this.styles[tn]) {
27682 Roo.each(this.styles[tn], function(v) {
27683 avs.push( [ v , cn.indexOf(v) > -1 ? 1 : 0 ] );
27687 st.store.loadData(avs);
27691 // flag our selected Node.
27692 this.tb.selectedNode = sel;
27695 Roo.menu.MenuMgr.hideAll();
27699 if (!updateFooter) {
27700 //this.footDisp.dom.innerHTML = '';
27703 // update the footer
27707 this.footerEls = ans.reverse();
27708 Roo.each(this.footerEls, function(a,i) {
27709 if (!a) { return; }
27710 html += html.length ? ' > ' : '';
27712 html += '<span class="x-ed-loc-' + i + '">' + a.tagName + '</span>';
27717 var sz = this.footDisp.up('td').getSize();
27718 this.footDisp.dom.style.width = (sz.width -10) + 'px';
27719 this.footDisp.dom.style.marginLeft = '5px';
27721 this.footDisp.dom.style.overflow = 'hidden';
27723 this.footDisp.dom.innerHTML = html;
27725 //this.editorsyncValue();
27732 onDestroy : function(){
27735 this.tb.items.each(function(item){
27737 item.menu.removeAll();
27739 item.menu.el.destroy();
27747 onFirstFocus: function() {
27748 // need to do this for all the toolbars..
27749 this.tb.items.each(function(item){
27753 buildToolbar: function(tlist, nm)
27755 var editor = this.editor;
27756 // create a new element.
27757 var wdiv = editor.wrap.createChild({
27759 }, editor.wrap.dom.firstChild.nextSibling, true);
27762 var tb = new Roo.Toolbar(wdiv);
27765 tb.add(nm+ ": ");
27768 for(var i in this.styles) {
27773 if (styles && styles.length) {
27775 // this needs a multi-select checkbox...
27776 tb.addField( new Roo.form.ComboBox({
27777 store: new Roo.data.SimpleStore({
27779 fields: ['val', 'selected'],
27782 name : '-roo-edit-className',
27783 attrname : 'className',
27784 displayField: 'val',
27788 triggerAction: 'all',
27789 emptyText:'Select Style',
27790 selectOnFocus:true,
27793 'select': function(c, r, i) {
27794 // initial support only for on class per el..
27795 tb.selectedNode.className = r ? r.get('val') : '';
27796 editor.syncValue();
27803 var tbc = Roo.form.HtmlEditor.ToolbarContext;
27804 var tbops = tbc.options;
27806 for (var i in tlist) {
27808 var item = tlist[i];
27809 tb.add(item.title + ": ");
27812 //optname == used so you can configure the options available..
27813 var opts = item.opts ? item.opts : false;
27814 if (item.optname) {
27815 opts = tbops[item.optname];
27820 // opts == pulldown..
27821 tb.addField( new Roo.form.ComboBox({
27822 store: typeof(tbc.stores[i]) != 'undefined' ? Roo.factory(tbc.stores[i],Roo.data) : new Roo.data.SimpleStore({
27824 fields: ['val', 'display'],
27827 name : '-roo-edit-' + i,
27829 stylename : item.style ? item.style : false,
27830 displayField: item.displayField ? item.displayField : 'val',
27831 valueField : 'val',
27833 mode: typeof(tbc.stores[i]) != 'undefined' ? 'remote' : 'local',
27835 triggerAction: 'all',
27836 emptyText:'Select',
27837 selectOnFocus:true,
27838 width: item.width ? item.width : 130,
27840 'select': function(c, r, i) {
27842 tb.selectedNode.style[c.stylename] = r.get('val');
27845 tb.selectedNode.setAttribute(c.attrname, r.get('val'));
27854 tb.addField( new Roo.form.TextField({
27857 //allowBlank:false,
27862 tb.addField( new Roo.form.TextField({
27863 name: '-roo-edit-' + i,
27870 'change' : function(f, nv, ov) {
27871 tb.selectedNode.setAttribute(f.attrname, nv);
27880 text: 'Remove Tag',
27883 click : function ()
27886 // undo does not work.
27888 var sn = tb.selectedNode;
27890 var pn = sn.parentNode;
27892 var stn = sn.childNodes[0];
27893 var en = sn.childNodes[sn.childNodes.length - 1 ];
27894 while (sn.childNodes.length) {
27895 var node = sn.childNodes[0];
27896 sn.removeChild(node);
27898 pn.insertBefore(node, sn);
27901 pn.removeChild(sn);
27902 var range = editor.createRange();
27904 range.setStart(stn,0);
27905 range.setEnd(en,0); //????
27906 //range.selectNode(sel);
27909 var selection = editor.getSelection();
27910 selection.removeAllRanges();
27911 selection.addRange(range);
27915 //_this.updateToolbar(null, null, pn);
27916 _this.updateToolbar(null, null, null);
27917 _this.footDisp.dom.innerHTML = '';
27927 tb.el.on('click', function(e){
27928 e.preventDefault(); // what does this do?
27930 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
27933 // dont need to disable them... as they will get hidden
27938 buildFooter : function()
27941 var fel = this.editor.wrap.createChild();
27942 this.footer = new Roo.Toolbar(fel);
27943 // toolbar has scrolly on left / right?
27944 var footDisp= new Roo.Toolbar.Fill();
27950 handler : function() {
27951 _t.footDisp.scrollTo('left',0,true)
27955 this.footer.add( footDisp );
27960 handler : function() {
27962 _t.footDisp.select('span').last().scrollIntoView(_t.footDisp,true);
27966 var fel = Roo.get(footDisp.el);
27967 fel.addClass('x-editor-context');
27968 this.footDispWrap = fel;
27969 this.footDispWrap.overflow = 'hidden';
27971 this.footDisp = fel.createChild();
27972 this.footDispWrap.on('click', this.onContextClick, this)
27976 onContextClick : function (ev,dom)
27978 ev.preventDefault();
27979 var cn = dom.className;
27981 if (!cn.match(/x-ed-loc-/)) {
27984 var n = cn.split('-').pop();
27985 var ans = this.footerEls;
27989 var range = this.editor.createRange();
27991 range.selectNodeContents(sel);
27992 //range.selectNode(sel);
27995 var selection = this.editor.getSelection();
27996 selection.removeAllRanges();
27997 selection.addRange(range);
28001 this.updateToolbar(null, null, sel);
28018 * Ext JS Library 1.1.1
28019 * Copyright(c) 2006-2007, Ext JS, LLC.
28021 * Originally Released Under LGPL - original licence link has changed is not relivant.
28024 * <script type="text/javascript">
28028 * @class Roo.form.BasicForm
28029 * @extends Roo.util.Observable
28030 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
28032 * @param {String/HTMLElement/Roo.Element} el The form element or its id
28033 * @param {Object} config Configuration options
28035 Roo.form.BasicForm = function(el, config){
28036 this.allItems = [];
28037 this.childForms = [];
28038 Roo.apply(this, config);
28040 * The Roo.form.Field items in this form.
28041 * @type MixedCollection
28045 this.items = new Roo.util.MixedCollection(false, function(o){
28046 return o.id || (o.id = Roo.id());
28050 * @event beforeaction
28051 * Fires before any action is performed. Return false to cancel the action.
28052 * @param {Form} this
28053 * @param {Action} action The action to be performed
28055 beforeaction: true,
28057 * @event actionfailed
28058 * Fires when an action fails.
28059 * @param {Form} this
28060 * @param {Action} action The action that failed
28062 actionfailed : true,
28064 * @event actioncomplete
28065 * Fires when an action is completed.
28066 * @param {Form} this
28067 * @param {Action} action The action that completed
28069 actioncomplete : true
28074 Roo.form.BasicForm.superclass.constructor.call(this);
28077 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
28079 * @cfg {String} method
28080 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
28083 * @cfg {DataReader} reader
28084 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
28085 * This is optional as there is built-in support for processing JSON.
28088 * @cfg {DataReader} errorReader
28089 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
28090 * This is completely optional as there is built-in support for processing JSON.
28093 * @cfg {String} url
28094 * The URL to use for form actions if one isn't supplied in the action options.
28097 * @cfg {Boolean} fileUpload
28098 * Set to true if this form is a file upload.
28102 * @cfg {Object} baseParams
28103 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
28108 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
28113 activeAction : null,
28116 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
28117 * or setValues() data instead of when the form was first created.
28119 trackResetOnLoad : false,
28123 * childForms - used for multi-tab forms
28126 childForms : false,
28129 * allItems - full list of fields.
28135 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
28136 * element by passing it or its id or mask the form itself by passing in true.
28139 waitMsgTarget : false,
28142 initEl : function(el){
28143 this.el = Roo.get(el);
28144 this.id = this.el.id || Roo.id();
28145 this.el.on('submit', this.onSubmit, this);
28146 this.el.addClass('x-form');
28150 onSubmit : function(e){
28155 * Returns true if client-side validation on the form is successful.
28158 isValid : function(){
28160 this.items.each(function(f){
28169 * Returns true if any fields in this form have changed since their original load.
28172 isDirty : function(){
28174 this.items.each(function(f){
28184 * Performs a predefined action (submit or load) or custom actions you define on this form.
28185 * @param {String} actionName The name of the action type
28186 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
28187 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
28188 * accept other config options):
28190 Property Type Description
28191 ---------------- --------------- ----------------------------------------------------------------------------------
28192 url String The url for the action (defaults to the form's url)
28193 method String The form method to use (defaults to the form's method, or POST if not defined)
28194 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
28195 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
28196 validate the form on the client (defaults to false)
28198 * @return {BasicForm} this
28200 doAction : function(action, options){
28201 if(typeof action == 'string'){
28202 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
28204 if(this.fireEvent('beforeaction', this, action) !== false){
28205 this.beforeAction(action);
28206 action.run.defer(100, action);
28212 * Shortcut to do a submit action.
28213 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28214 * @return {BasicForm} this
28216 submit : function(options){
28217 this.doAction('submit', options);
28222 * Shortcut to do a load action.
28223 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
28224 * @return {BasicForm} this
28226 load : function(options){
28227 this.doAction('load', options);
28232 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
28233 * @param {Record} record The record to edit
28234 * @return {BasicForm} this
28236 updateRecord : function(record){
28237 record.beginEdit();
28238 var fs = record.fields;
28239 fs.each(function(f){
28240 var field = this.findField(f.name);
28242 record.set(f.name, field.getValue());
28250 * Loads an Roo.data.Record into this form.
28251 * @param {Record} record The record to load
28252 * @return {BasicForm} this
28254 loadRecord : function(record){
28255 this.setValues(record.data);
28260 beforeAction : function(action){
28261 var o = action.options;
28264 if(this.waitMsgTarget === true){
28265 this.el.mask(o.waitMsg || "Sending", 'x-mask-loading');
28266 }else if(this.waitMsgTarget){
28267 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
28268 this.waitMsgTarget.mask(o.waitMsg || "Sending", 'x-mask-loading');
28270 Roo.MessageBox.wait(o.waitMsg || "Sending", o.waitTitle || this.waitTitle || 'Please Wait...');
28276 afterAction : function(action, success){
28277 this.activeAction = null;
28278 var o = action.options;
28280 if(this.waitMsgTarget === true){
28282 }else if(this.waitMsgTarget){
28283 this.waitMsgTarget.unmask();
28285 Roo.MessageBox.updateProgress(1);
28286 Roo.MessageBox.hide();
28293 Roo.callback(o.success, o.scope, [this, action]);
28294 this.fireEvent('actioncomplete', this, action);
28298 // failure condition..
28299 // we have a scenario where updates need confirming.
28300 // eg. if a locking scenario exists..
28301 // we look for { errors : { needs_confirm : true }} in the response.
28303 (typeof(action.result) != 'undefined') &&
28304 (typeof(action.result.errors) != 'undefined') &&
28305 (typeof(action.result.errors.needs_confirm) != 'undefined')
28308 Roo.MessageBox.confirm(
28309 "Change requires confirmation",
28310 action.result.errorMsg,
28315 _t.doAction('submit', { params : { _submit_confirmed : 1 } } );
28325 Roo.callback(o.failure, o.scope, [this, action]);
28326 // show an error message if no failed handler is set..
28327 if (!this.hasListener('actionfailed')) {
28328 Roo.MessageBox.alert("Error",
28329 (typeof(action.result) != 'undefined' && typeof(action.result.errorMsg) != 'undefined') ?
28330 action.result.errorMsg :
28331 "Saving Failed, please check your entries or try again"
28335 this.fireEvent('actionfailed', this, action);
28341 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
28342 * @param {String} id The value to search for
28345 findField : function(id){
28346 var field = this.items.get(id);
28348 this.items.each(function(f){
28349 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
28355 return field || null;
28359 * Add a secondary form to this one,
28360 * Used to provide tabbed forms. One form is primary, with hidden values
28361 * which mirror the elements from the other forms.
28363 * @param {Roo.form.Form} form to add.
28366 addForm : function(form)
28369 if (this.childForms.indexOf(form) > -1) {
28373 this.childForms.push(form);
28375 Roo.each(form.allItems, function (fe) {
28377 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
28378 if (this.findField(n)) { // already added..
28381 var add = new Roo.form.Hidden({
28384 add.render(this.el);
28391 * Mark fields in this form invalid in bulk.
28392 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
28393 * @return {BasicForm} this
28395 markInvalid : function(errors){
28396 if(errors instanceof Array){
28397 for(var i = 0, len = errors.length; i < len; i++){
28398 var fieldError = errors[i];
28399 var f = this.findField(fieldError.id);
28401 f.markInvalid(fieldError.msg);
28407 if(typeof errors[id] != 'function' && (field = this.findField(id))){
28408 field.markInvalid(errors[id]);
28412 Roo.each(this.childForms || [], function (f) {
28413 f.markInvalid(errors);
28420 * Set values for fields in this form in bulk.
28421 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
28422 * @return {BasicForm} this
28424 setValues : function(values){
28425 if(values instanceof Array){ // array of objects
28426 for(var i = 0, len = values.length; i < len; i++){
28428 var f = this.findField(v.id);
28430 f.setValue(v.value);
28431 if(this.trackResetOnLoad){
28432 f.originalValue = f.getValue();
28436 }else{ // object hash
28439 if(typeof values[id] != 'function' && (field = this.findField(id))){
28441 if (field.setFromData &&
28442 field.valueField &&
28443 field.displayField &&
28444 // combos' with local stores can
28445 // be queried via setValue()
28446 // to set their value..
28447 (field.store && !field.store.isLocal)
28451 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
28452 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
28453 field.setFromData(sd);
28456 field.setValue(values[id]);
28460 if(this.trackResetOnLoad){
28461 field.originalValue = field.getValue();
28467 Roo.each(this.childForms || [], function (f) {
28468 f.setValues(values);
28475 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
28476 * they are returned as an array.
28477 * @param {Boolean} asString
28480 getValues : function(asString){
28481 if (this.childForms) {
28482 // copy values from the child forms
28483 Roo.each(this.childForms, function (f) {
28484 this.setValues(f.getValues());
28490 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
28491 if(asString === true){
28494 return Roo.urlDecode(fs);
28498 * Returns the fields in this form as an object with key/value pairs.
28499 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
28502 getFieldValues : function(with_hidden)
28504 if (this.childForms) {
28505 // copy values from the child forms
28506 // should this call getFieldValues - probably not as we do not currently copy
28507 // hidden fields when we generate..
28508 Roo.each(this.childForms, function (f) {
28509 this.setValues(f.getValues());
28514 this.items.each(function(f){
28515 if (!f.getName()) {
28518 var v = f.getValue();
28519 if (f.inputType =='radio') {
28520 if (typeof(ret[f.getName()]) == 'undefined') {
28521 ret[f.getName()] = ''; // empty..
28524 if (!f.el.dom.checked) {
28528 v = f.el.dom.value;
28532 // not sure if this supported any more..
28533 if ((typeof(v) == 'object') && f.getRawValue) {
28534 v = f.getRawValue() ; // dates..
28536 // combo boxes where name != hiddenName...
28537 if (f.name != f.getName()) {
28538 ret[f.name] = f.getRawValue();
28540 ret[f.getName()] = v;
28547 * Clears all invalid messages in this form.
28548 * @return {BasicForm} this
28550 clearInvalid : function(){
28551 this.items.each(function(f){
28555 Roo.each(this.childForms || [], function (f) {
28564 * Resets this form.
28565 * @return {BasicForm} this
28567 reset : function(){
28568 this.items.each(function(f){
28572 Roo.each(this.childForms || [], function (f) {
28581 * Add Roo.form components to this form.
28582 * @param {Field} field1
28583 * @param {Field} field2 (optional)
28584 * @param {Field} etc (optional)
28585 * @return {BasicForm} this
28588 this.items.addAll(Array.prototype.slice.call(arguments, 0));
28594 * Removes a field from the items collection (does NOT remove its markup).
28595 * @param {Field} field
28596 * @return {BasicForm} this
28598 remove : function(field){
28599 this.items.remove(field);
28604 * Looks at the fields in this form, checks them for an id attribute,
28605 * and calls applyTo on the existing dom element with that id.
28606 * @return {BasicForm} this
28608 render : function(){
28609 this.items.each(function(f){
28610 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
28618 * Calls {@link Ext#apply} for all fields in this form with the passed object.
28619 * @param {Object} values
28620 * @return {BasicForm} this
28622 applyToFields : function(o){
28623 this.items.each(function(f){
28630 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
28631 * @param {Object} values
28632 * @return {BasicForm} this
28634 applyIfToFields : function(o){
28635 this.items.each(function(f){
28643 Roo.BasicForm = Roo.form.BasicForm;/*
28645 * Ext JS Library 1.1.1
28646 * Copyright(c) 2006-2007, Ext JS, LLC.
28648 * Originally Released Under LGPL - original licence link has changed is not relivant.
28651 * <script type="text/javascript">
28655 * @class Roo.form.Form
28656 * @extends Roo.form.BasicForm
28657 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
28659 * @param {Object} config Configuration options
28661 Roo.form.Form = function(config){
28663 if (config.items) {
28664 xitems = config.items;
28665 delete config.items;
28669 Roo.form.Form.superclass.constructor.call(this, null, config);
28670 this.url = this.url || this.action;
28672 this.root = new Roo.form.Layout(Roo.applyIf({
28676 this.active = this.root;
28678 * Array of all the buttons that have been added to this form via {@link addButton}
28682 this.allItems = [];
28685 * @event clientvalidation
28686 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
28687 * @param {Form} this
28688 * @param {Boolean} valid true if the form has passed client-side validation
28690 clientvalidation: true,
28693 * Fires when the form is rendered
28694 * @param {Roo.form.Form} form
28699 if (this.progressUrl) {
28700 // push a hidden field onto the list of fields..
28704 name : 'UPLOAD_IDENTIFIER'
28709 Roo.each(xitems, this.addxtype, this);
28715 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
28717 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
28720 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
28723 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
28725 buttonAlign:'center',
28728 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
28733 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
28734 * This property cascades to child containers if not set.
28739 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
28740 * fires a looping event with that state. This is required to bind buttons to the valid
28741 * state using the config value formBind:true on the button.
28743 monitorValid : false,
28746 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
28751 * @cfg {String} progressUrl - Url to return progress data
28754 progressUrl : false,
28757 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
28758 * fields are added and the column is closed. If no fields are passed the column remains open
28759 * until end() is called.
28760 * @param {Object} config The config to pass to the column
28761 * @param {Field} field1 (optional)
28762 * @param {Field} field2 (optional)
28763 * @param {Field} etc (optional)
28764 * @return Column The column container object
28766 column : function(c){
28767 var col = new Roo.form.Column(c);
28769 if(arguments.length > 1){ // duplicate code required because of Opera
28770 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28777 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
28778 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
28779 * until end() is called.
28780 * @param {Object} config The config to pass to the fieldset
28781 * @param {Field} field1 (optional)
28782 * @param {Field} field2 (optional)
28783 * @param {Field} etc (optional)
28784 * @return FieldSet The fieldset container object
28786 fieldset : function(c){
28787 var fs = new Roo.form.FieldSet(c);
28789 if(arguments.length > 1){ // duplicate code required because of Opera
28790 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28797 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
28798 * fields are added and the container is closed. If no fields are passed the container remains open
28799 * until end() is called.
28800 * @param {Object} config The config to pass to the Layout
28801 * @param {Field} field1 (optional)
28802 * @param {Field} field2 (optional)
28803 * @param {Field} etc (optional)
28804 * @return Layout The container object
28806 container : function(c){
28807 var l = new Roo.form.Layout(c);
28809 if(arguments.length > 1){ // duplicate code required because of Opera
28810 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
28817 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
28818 * @param {Object} container A Roo.form.Layout or subclass of Layout
28819 * @return {Form} this
28821 start : function(c){
28822 // cascade label info
28823 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
28824 this.active.stack.push(c);
28825 c.ownerCt = this.active;
28831 * Closes the current open container
28832 * @return {Form} this
28835 if(this.active == this.root){
28838 this.active = this.active.ownerCt;
28843 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
28844 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
28845 * as the label of the field.
28846 * @param {Field} field1
28847 * @param {Field} field2 (optional)
28848 * @param {Field} etc. (optional)
28849 * @return {Form} this
28852 this.active.stack.push.apply(this.active.stack, arguments);
28853 this.allItems.push.apply(this.allItems,arguments);
28855 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
28856 if(a[i].isFormField){
28861 Roo.form.Form.superclass.add.apply(this, r);
28871 * Find any element that has been added to a form, using it's ID or name
28872 * This can include framesets, columns etc. along with regular fields..
28873 * @param {String} id - id or name to find.
28875 * @return {Element} e - or false if nothing found.
28877 findbyId : function(id)
28883 Roo.each(this.allItems, function(f){
28884 if (f.id == id || f.name == id ){
28895 * Render this form into the passed container. This should only be called once!
28896 * @param {String/HTMLElement/Element} container The element this component should be rendered into
28897 * @return {Form} this
28899 render : function(ct)
28905 var o = this.autoCreate || {
28907 method : this.method || 'POST',
28908 id : this.id || Roo.id()
28910 this.initEl(ct.createChild(o));
28912 this.root.render(this.el);
28916 this.items.each(function(f){
28917 f.render('x-form-el-'+f.id);
28920 if(this.buttons.length > 0){
28921 // tables are required to maintain order and for correct IE layout
28922 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
28923 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
28924 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
28926 var tr = tb.getElementsByTagName('tr')[0];
28927 for(var i = 0, len = this.buttons.length; i < len; i++) {
28928 var b = this.buttons[i];
28929 var td = document.createElement('td');
28930 td.className = 'x-form-btn-td';
28931 b.render(tr.appendChild(td));
28934 if(this.monitorValid){ // initialize after render
28935 this.startMonitoring();
28937 this.fireEvent('rendered', this);
28942 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
28943 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
28944 * object or a valid Roo.DomHelper element config
28945 * @param {Function} handler The function called when the button is clicked
28946 * @param {Object} scope (optional) The scope of the handler function
28947 * @return {Roo.Button}
28949 addButton : function(config, handler, scope){
28953 minWidth: this.minButtonWidth,
28956 if(typeof config == "string"){
28959 Roo.apply(bc, config);
28961 var btn = new Roo.Button(null, bc);
28962 this.buttons.push(btn);
28967 * Adds a series of form elements (using the xtype property as the factory method.
28968 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
28969 * @param {Object} config
28972 addxtype : function()
28974 var ar = Array.prototype.slice.call(arguments, 0);
28976 for(var i = 0; i < ar.length; i++) {
28978 continue; // skip -- if this happends something invalid got sent, we
28979 // should ignore it, as basically that interface element will not show up
28980 // and that should be pretty obvious!!
28983 if (Roo.form[ar[i].xtype]) {
28985 var fe = Roo.factory(ar[i], Roo.form);
28991 fe.store.form = this;
28996 this.allItems.push(fe);
28997 if (fe.items && fe.addxtype) {
28998 fe.addxtype.apply(fe, fe.items);
29008 // console.log('adding ' + ar[i].xtype);
29010 if (ar[i].xtype == 'Button') {
29011 //console.log('adding button');
29012 //console.log(ar[i]);
29013 this.addButton(ar[i]);
29014 this.allItems.push(fe);
29018 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
29019 alert('end is not supported on xtype any more, use items');
29021 // //console.log('adding end');
29029 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
29030 * option "monitorValid"
29032 startMonitoring : function(){
29035 Roo.TaskMgr.start({
29036 run : this.bindHandler,
29037 interval : this.monitorPoll || 200,
29044 * Stops monitoring of the valid state of this form
29046 stopMonitoring : function(){
29047 this.bound = false;
29051 bindHandler : function(){
29053 return false; // stops binding
29056 this.items.each(function(f){
29057 if(!f.isValid(true)){
29062 for(var i = 0, len = this.buttons.length; i < len; i++){
29063 var btn = this.buttons[i];
29064 if(btn.formBind === true && btn.disabled === valid){
29065 btn.setDisabled(!valid);
29068 this.fireEvent('clientvalidation', this, valid);
29082 Roo.Form = Roo.form.Form;
29085 * Ext JS Library 1.1.1
29086 * Copyright(c) 2006-2007, Ext JS, LLC.
29088 * Originally Released Under LGPL - original licence link has changed is not relivant.
29091 * <script type="text/javascript">
29095 * @class Roo.form.Action
29096 * Internal Class used to handle form actions
29098 * @param {Roo.form.BasicForm} el The form element or its id
29099 * @param {Object} config Configuration options
29103 // define the action interface
29104 Roo.form.Action = function(form, options){
29106 this.options = options || {};
29109 * Client Validation Failed
29112 Roo.form.Action.CLIENT_INVALID = 'client';
29114 * Server Validation Failed
29117 Roo.form.Action.SERVER_INVALID = 'server';
29119 * Connect to Server Failed
29122 Roo.form.Action.CONNECT_FAILURE = 'connect';
29124 * Reading Data from Server Failed
29127 Roo.form.Action.LOAD_FAILURE = 'load';
29129 Roo.form.Action.prototype = {
29131 failureType : undefined,
29132 response : undefined,
29133 result : undefined,
29135 // interface method
29136 run : function(options){
29140 // interface method
29141 success : function(response){
29145 // interface method
29146 handleResponse : function(response){
29150 // default connection failure
29151 failure : function(response){
29153 this.response = response;
29154 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29155 this.form.afterAction(this, false);
29158 processResponse : function(response){
29159 this.response = response;
29160 if(!response.responseText){
29163 this.result = this.handleResponse(response);
29164 return this.result;
29167 // utility functions used internally
29168 getUrl : function(appendParams){
29169 var url = this.options.url || this.form.url || this.form.el.dom.action;
29171 var p = this.getParams();
29173 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
29179 getMethod : function(){
29180 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
29183 getParams : function(){
29184 var bp = this.form.baseParams;
29185 var p = this.options.params;
29187 if(typeof p == "object"){
29188 p = Roo.urlEncode(Roo.applyIf(p, bp));
29189 }else if(typeof p == 'string' && bp){
29190 p += '&' + Roo.urlEncode(bp);
29193 p = Roo.urlEncode(bp);
29198 createCallback : function(){
29200 success: this.success,
29201 failure: this.failure,
29203 timeout: (this.form.timeout*1000),
29204 upload: this.form.fileUpload ? this.success : undefined
29209 Roo.form.Action.Submit = function(form, options){
29210 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
29213 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
29216 haveProgress : false,
29217 uploadComplete : false,
29219 // uploadProgress indicator.
29220 uploadProgress : function()
29222 if (!this.form.progressUrl) {
29226 if (!this.haveProgress) {
29227 Roo.MessageBox.progress("Uploading", "Uploading");
29229 if (this.uploadComplete) {
29230 Roo.MessageBox.hide();
29234 this.haveProgress = true;
29236 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
29238 var c = new Roo.data.Connection();
29240 url : this.form.progressUrl,
29245 success : function(req){
29246 //console.log(data);
29250 rdata = Roo.decode(req.responseText)
29252 Roo.log("Invalid data from server..");
29256 if (!rdata || !rdata.success) {
29258 Roo.MessageBox.alert(Roo.encode(rdata));
29261 var data = rdata.data;
29263 if (this.uploadComplete) {
29264 Roo.MessageBox.hide();
29269 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
29270 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
29273 this.uploadProgress.defer(2000,this);
29276 failure: function(data) {
29277 Roo.log('progress url failed ');
29288 // run get Values on the form, so it syncs any secondary forms.
29289 this.form.getValues();
29291 var o = this.options;
29292 var method = this.getMethod();
29293 var isPost = method == 'POST';
29294 if(o.clientValidation === false || this.form.isValid()){
29296 if (this.form.progressUrl) {
29297 this.form.findField('UPLOAD_IDENTIFIER').setValue(
29298 (new Date() * 1) + '' + Math.random());
29303 Roo.Ajax.request(Roo.apply(this.createCallback(), {
29304 form:this.form.el.dom,
29305 url:this.getUrl(!isPost),
29307 params:isPost ? this.getParams() : null,
29308 isUpload: this.form.fileUpload
29311 this.uploadProgress();
29313 }else if (o.clientValidation !== false){ // client validation failed
29314 this.failureType = Roo.form.Action.CLIENT_INVALID;
29315 this.form.afterAction(this, false);
29319 success : function(response)
29321 this.uploadComplete= true;
29322 if (this.haveProgress) {
29323 Roo.MessageBox.hide();
29327 var result = this.processResponse(response);
29328 if(result === true || result.success){
29329 this.form.afterAction(this, true);
29333 this.form.markInvalid(result.errors);
29334 this.failureType = Roo.form.Action.SERVER_INVALID;
29336 this.form.afterAction(this, false);
29338 failure : function(response)
29340 this.uploadComplete= true;
29341 if (this.haveProgress) {
29342 Roo.MessageBox.hide();
29345 this.response = response;
29346 this.failureType = Roo.form.Action.CONNECT_FAILURE;
29347 this.form.afterAction(this, false);
29350 handleResponse : function(response){
29351 if(this.form.errorReader){
29352 var rs = this.form.errorReader.read(response);
29355 for(var i = 0, len = rs.records.length; i < len; i++) {
29356 var r = rs.records[i];
29357 errors[i] = r.data;
29360 if(errors.length < 1){
29364 success : rs.success,
29370 ret = Roo.decode(response.responseText);
29374 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
29384 Roo.form.Action.Load = function(form, options){
29385 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
29386 this.reader = this.form.reader;
29389 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
29394 Roo.Ajax.request(Roo.apply(
29395 this.createCallback(), {
29396 method:this.getMethod(),
29397 url:this.getUrl(false),
29398 params:this.getParams()
29402 success : function(response){
29404 var result = this.processResponse(response);
29405 if(result === true || !result.success || !result.data){
29406 this.failureType = Roo.form.Action.LOAD_FAILURE;
29407 this.form.afterAction(this, false);
29410 this.form.clearInvalid();
29411 this.form.setValues(result.data);
29412 this.form.afterAction(this, true);
29415 handleResponse : function(response){
29416 if(this.form.reader){
29417 var rs = this.form.reader.read(response);
29418 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
29420 success : rs.success,
29424 return Roo.decode(response.responseText);
29428 Roo.form.Action.ACTION_TYPES = {
29429 'load' : Roo.form.Action.Load,
29430 'submit' : Roo.form.Action.Submit
29433 * Ext JS Library 1.1.1
29434 * Copyright(c) 2006-2007, Ext JS, LLC.
29436 * Originally Released Under LGPL - original licence link has changed is not relivant.
29439 * <script type="text/javascript">
29443 * @class Roo.form.Layout
29444 * @extends Roo.Component
29445 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
29447 * @param {Object} config Configuration options
29449 Roo.form.Layout = function(config){
29451 if (config.items) {
29452 xitems = config.items;
29453 delete config.items;
29455 Roo.form.Layout.superclass.constructor.call(this, config);
29457 Roo.each(xitems, this.addxtype, this);
29461 Roo.extend(Roo.form.Layout, Roo.Component, {
29463 * @cfg {String/Object} autoCreate
29464 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
29467 * @cfg {String/Object/Function} style
29468 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
29469 * a function which returns such a specification.
29472 * @cfg {String} labelAlign
29473 * Valid values are "left," "top" and "right" (defaults to "left")
29476 * @cfg {Number} labelWidth
29477 * Fixed width in pixels of all field labels (defaults to undefined)
29480 * @cfg {Boolean} clear
29481 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
29485 * @cfg {String} labelSeparator
29486 * The separator to use after field labels (defaults to ':')
29488 labelSeparator : ':',
29490 * @cfg {Boolean} hideLabels
29491 * True to suppress the display of field labels in this layout (defaults to false)
29493 hideLabels : false,
29496 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
29501 onRender : function(ct, position){
29502 if(this.el){ // from markup
29503 this.el = Roo.get(this.el);
29504 }else { // generate
29505 var cfg = this.getAutoCreate();
29506 this.el = ct.createChild(cfg, position);
29509 this.el.applyStyles(this.style);
29511 if(this.labelAlign){
29512 this.el.addClass('x-form-label-'+this.labelAlign);
29514 if(this.hideLabels){
29515 this.labelStyle = "display:none";
29516 this.elementStyle = "padding-left:0;";
29518 if(typeof this.labelWidth == 'number'){
29519 this.labelStyle = "width:"+this.labelWidth+"px;";
29520 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
29522 if(this.labelAlign == 'top'){
29523 this.labelStyle = "width:auto;";
29524 this.elementStyle = "padding-left:0;";
29527 var stack = this.stack;
29528 var slen = stack.length;
29530 if(!this.fieldTpl){
29531 var t = new Roo.Template(
29532 '<div class="x-form-item {5}">',
29533 '<label for="{0}" style="{2}">{1}{4}</label>',
29534 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29536 '</div><div class="x-form-clear-left"></div>'
29538 t.disableFormats = true;
29540 Roo.form.Layout.prototype.fieldTpl = t;
29542 for(var i = 0; i < slen; i++) {
29543 if(stack[i].isFormField){
29544 this.renderField(stack[i]);
29546 this.renderComponent(stack[i]);
29551 this.el.createChild({cls:'x-form-clear'});
29556 renderField : function(f){
29557 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
29560 f.labelStyle||this.labelStyle||'', //2
29561 this.elementStyle||'', //3
29562 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
29563 f.itemCls||this.itemCls||'' //5
29564 ], true).getPrevSibling());
29568 renderComponent : function(c){
29569 c.render(c.isLayout ? this.el : this.el.createChild());
29572 * Adds a object form elements (using the xtype property as the factory method.)
29573 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
29574 * @param {Object} config
29576 addxtype : function(o)
29578 // create the lement.
29579 o.form = this.form;
29580 var fe = Roo.factory(o, Roo.form);
29581 this.form.allItems.push(fe);
29582 this.stack.push(fe);
29584 if (fe.isFormField) {
29585 this.form.items.add(fe);
29593 * @class Roo.form.Column
29594 * @extends Roo.form.Layout
29595 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
29597 * @param {Object} config Configuration options
29599 Roo.form.Column = function(config){
29600 Roo.form.Column.superclass.constructor.call(this, config);
29603 Roo.extend(Roo.form.Column, Roo.form.Layout, {
29605 * @cfg {Number/String} width
29606 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29609 * @cfg {String/Object} autoCreate
29610 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
29614 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
29617 onRender : function(ct, position){
29618 Roo.form.Column.superclass.onRender.call(this, ct, position);
29620 this.el.setWidth(this.width);
29627 * @class Roo.form.Row
29628 * @extends Roo.form.Layout
29629 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
29631 * @param {Object} config Configuration options
29635 Roo.form.Row = function(config){
29636 Roo.form.Row.superclass.constructor.call(this, config);
29639 Roo.extend(Roo.form.Row, Roo.form.Layout, {
29641 * @cfg {Number/String} width
29642 * The fixed width of the column in pixels or CSS value (defaults to "auto")
29645 * @cfg {Number/String} height
29646 * The fixed height of the column in pixels or CSS value (defaults to "auto")
29648 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
29652 onRender : function(ct, position){
29653 //console.log('row render');
29655 var t = new Roo.Template(
29656 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
29657 '<label for="{0}" style="{2}">{1}{4}</label>',
29658 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
29662 t.disableFormats = true;
29664 Roo.form.Layout.prototype.rowTpl = t;
29666 this.fieldTpl = this.rowTpl;
29668 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
29669 var labelWidth = 100;
29671 if ((this.labelAlign != 'top')) {
29672 if (typeof this.labelWidth == 'number') {
29673 labelWidth = this.labelWidth
29675 this.padWidth = 20 + labelWidth;
29679 Roo.form.Column.superclass.onRender.call(this, ct, position);
29681 this.el.setWidth(this.width);
29684 this.el.setHeight(this.height);
29689 renderField : function(f){
29690 f.fieldEl = this.fieldTpl.append(this.el, [
29691 f.id, f.fieldLabel,
29692 f.labelStyle||this.labelStyle||'',
29693 this.elementStyle||'',
29694 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
29695 f.itemCls||this.itemCls||'',
29696 f.width ? f.width + this.padWidth : 160 + this.padWidth
29703 * @class Roo.form.FieldSet
29704 * @extends Roo.form.Layout
29705 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
29707 * @param {Object} config Configuration options
29709 Roo.form.FieldSet = function(config){
29710 Roo.form.FieldSet.superclass.constructor.call(this, config);
29713 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
29715 * @cfg {String} legend
29716 * The text to display as the legend for the FieldSet (defaults to '')
29719 * @cfg {String/Object} autoCreate
29720 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
29724 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
29727 onRender : function(ct, position){
29728 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
29730 this.setLegend(this.legend);
29735 setLegend : function(text){
29737 this.el.child('legend').update(text);
29742 * Ext JS Library 1.1.1
29743 * Copyright(c) 2006-2007, Ext JS, LLC.
29745 * Originally Released Under LGPL - original licence link has changed is not relivant.
29748 * <script type="text/javascript">
29751 * @class Roo.form.VTypes
29752 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
29755 Roo.form.VTypes = function(){
29756 // closure these in so they are only created once.
29757 var alpha = /^[a-zA-Z_]+$/;
29758 var alphanum = /^[a-zA-Z0-9_]+$/;
29759 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
29760 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
29762 // All these messages and functions are configurable
29765 * The function used to validate email addresses
29766 * @param {String} value The email address
29768 'email' : function(v){
29769 return email.test(v);
29772 * The error text to display when the email validation function returns false
29775 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
29777 * The keystroke filter mask to be applied on email input
29780 'emailMask' : /[a-z0-9_\.\-@]/i,
29783 * The function used to validate URLs
29784 * @param {String} value The URL
29786 'url' : function(v){
29787 return url.test(v);
29790 * The error text to display when the url validation function returns false
29793 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
29796 * The function used to validate alpha values
29797 * @param {String} value The value
29799 'alpha' : function(v){
29800 return alpha.test(v);
29803 * The error text to display when the alpha validation function returns false
29806 'alphaText' : 'This field should only contain letters and _',
29808 * The keystroke filter mask to be applied on alpha input
29811 'alphaMask' : /[a-z_]/i,
29814 * The function used to validate alphanumeric values
29815 * @param {String} value The value
29817 'alphanum' : function(v){
29818 return alphanum.test(v);
29821 * The error text to display when the alphanumeric validation function returns false
29824 'alphanumText' : 'This field should only contain letters, numbers and _',
29826 * The keystroke filter mask to be applied on alphanumeric input
29829 'alphanumMask' : /[a-z0-9_]/i
29831 }();//<script type="text/javascript">
29834 * @class Roo.form.FCKeditor
29835 * @extends Roo.form.TextArea
29836 * Wrapper around the FCKEditor http://www.fckeditor.net
29838 * Creates a new FCKeditor
29839 * @param {Object} config Configuration options
29841 Roo.form.FCKeditor = function(config){
29842 Roo.form.FCKeditor.superclass.constructor.call(this, config);
29845 * @event editorinit
29846 * Fired when the editor is initialized - you can add extra handlers here..
29847 * @param {FCKeditor} this
29848 * @param {Object} the FCK object.
29855 Roo.form.FCKeditor.editors = { };
29856 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
29858 //defaultAutoCreate : {
29859 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
29863 * @cfg {Object} fck options - see fck manual for details.
29868 * @cfg {Object} fck toolbar set (Basic or Default)
29870 toolbarSet : 'Basic',
29872 * @cfg {Object} fck BasePath
29874 basePath : '/fckeditor/',
29882 onRender : function(ct, position)
29885 this.defaultAutoCreate = {
29887 style:"width:300px;height:60px;",
29888 autocomplete: "off"
29891 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
29894 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
29895 if(this.preventScrollbars){
29896 this.el.setStyle("overflow", "hidden");
29898 this.el.setHeight(this.growMin);
29901 //console.log('onrender' + this.getId() );
29902 Roo.form.FCKeditor.editors[this.getId()] = this;
29905 this.replaceTextarea() ;
29909 getEditor : function() {
29910 return this.fckEditor;
29913 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
29914 * @param {Mixed} value The value to set
29918 setValue : function(value)
29920 //console.log('setValue: ' + value);
29922 if(typeof(value) == 'undefined') { // not sure why this is happending...
29925 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29927 //if(!this.el || !this.getEditor()) {
29928 // this.value = value;
29929 //this.setValue.defer(100,this,[value]);
29933 if(!this.getEditor()) {
29937 this.getEditor().SetData(value);
29944 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
29945 * @return {Mixed} value The field value
29947 getValue : function()
29950 if (this.frame && this.frame.dom.style.display == 'none') {
29951 return Roo.form.FCKeditor.superclass.getValue.call(this);
29954 if(!this.el || !this.getEditor()) {
29956 // this.getValue.defer(100,this);
29961 var value=this.getEditor().GetData();
29962 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
29963 return Roo.form.FCKeditor.superclass.getValue.call(this);
29969 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
29970 * @return {Mixed} value The field value
29972 getRawValue : function()
29974 if (this.frame && this.frame.dom.style.display == 'none') {
29975 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
29978 if(!this.el || !this.getEditor()) {
29979 //this.getRawValue.defer(100,this);
29986 var value=this.getEditor().GetData();
29987 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
29988 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
29992 setSize : function(w,h) {
29996 //if (this.frame && this.frame.dom.style.display == 'none') {
29997 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30000 //if(!this.el || !this.getEditor()) {
30001 // this.setSize.defer(100,this, [w,h]);
30007 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
30009 this.frame.dom.setAttribute('width', w);
30010 this.frame.dom.setAttribute('height', h);
30011 this.frame.setSize(w,h);
30015 toggleSourceEdit : function(value) {
30019 this.el.dom.style.display = value ? '' : 'none';
30020 this.frame.dom.style.display = value ? 'none' : '';
30025 focus: function(tag)
30027 if (this.frame.dom.style.display == 'none') {
30028 return Roo.form.FCKeditor.superclass.focus.call(this);
30030 if(!this.el || !this.getEditor()) {
30031 this.focus.defer(100,this, [tag]);
30038 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
30039 this.getEditor().Focus();
30041 if (!this.getEditor().Selection.GetSelection()) {
30042 this.focus.defer(100,this, [tag]);
30047 var r = this.getEditor().EditorDocument.createRange();
30048 r.setStart(tgs[0],0);
30049 r.setEnd(tgs[0],0);
30050 this.getEditor().Selection.GetSelection().removeAllRanges();
30051 this.getEditor().Selection.GetSelection().addRange(r);
30052 this.getEditor().Focus();
30059 replaceTextarea : function()
30061 if ( document.getElementById( this.getId() + '___Frame' ) )
30063 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
30065 // We must check the elements firstly using the Id and then the name.
30066 var oTextarea = document.getElementById( this.getId() );
30068 var colElementsByName = document.getElementsByName( this.getId() ) ;
30070 oTextarea.style.display = 'none' ;
30072 if ( oTextarea.tabIndex ) {
30073 this.TabIndex = oTextarea.tabIndex ;
30076 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
30077 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
30078 this.frame = Roo.get(this.getId() + '___Frame')
30081 _getConfigHtml : function()
30085 for ( var o in this.fckconfig ) {
30086 sConfig += sConfig.length > 0 ? '&' : '';
30087 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
30090 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
30094 _getIFrameHtml : function()
30096 var sFile = 'fckeditor.html' ;
30097 /* no idea what this is about..
30100 if ( (/fcksource=true/i).test( window.top.location.search ) )
30101 sFile = 'fckeditor.original.html' ;
30106 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
30107 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
30110 var html = '<iframe id="' + this.getId() +
30111 '___Frame" src="' + sLink +
30112 '" width="' + this.width +
30113 '" height="' + this.height + '"' +
30114 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
30115 ' frameborder="0" scrolling="no"></iframe>' ;
30120 _insertHtmlBefore : function( html, element )
30122 if ( element.insertAdjacentHTML ) {
30124 element.insertAdjacentHTML( 'beforeBegin', html ) ;
30126 var oRange = document.createRange() ;
30127 oRange.setStartBefore( element ) ;
30128 var oFragment = oRange.createContextualFragment( html );
30129 element.parentNode.insertBefore( oFragment, element ) ;
30142 //Roo.reg('fckeditor', Roo.form.FCKeditor);
30144 function FCKeditor_OnComplete(editorInstance){
30145 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
30146 f.fckEditor = editorInstance;
30147 //console.log("loaded");
30148 f.fireEvent('editorinit', f, editorInstance);
30168 //<script type="text/javascript">
30170 * @class Roo.form.GridField
30171 * @extends Roo.form.Field
30172 * Embed a grid (or editable grid into a form)
30175 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
30177 * xgrid.store = Roo.data.Store
30178 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
30179 * xgrid.store.reader = Roo.data.JsonReader
30183 * Creates a new GridField
30184 * @param {Object} config Configuration options
30186 Roo.form.GridField = function(config){
30187 Roo.form.GridField.superclass.constructor.call(this, config);
30191 Roo.extend(Roo.form.GridField, Roo.form.Field, {
30193 * @cfg {Number} width - used to restrict width of grid..
30197 * @cfg {Number} height - used to restrict height of grid..
30201 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
30207 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30208 * {tag: "input", type: "checkbox", autocomplete: "off"})
30210 // defaultAutoCreate : { tag: 'div' },
30211 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30213 * @cfg {String} addTitle Text to include for adding a title.
30217 onResize : function(){
30218 Roo.form.Field.superclass.onResize.apply(this, arguments);
30221 initEvents : function(){
30222 // Roo.form.Checkbox.superclass.initEvents.call(this);
30223 // has no events...
30228 getResizeEl : function(){
30232 getPositionEl : function(){
30237 onRender : function(ct, position){
30239 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
30240 var style = this.style;
30243 Roo.form.GridField.superclass.onRender.call(this, ct, position);
30244 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
30245 this.viewEl = this.wrap.createChild({ tag: 'div' });
30247 this.viewEl.applyStyles(style);
30250 this.viewEl.setWidth(this.width);
30253 this.viewEl.setHeight(this.height);
30255 //if(this.inputValue !== undefined){
30256 //this.setValue(this.value);
30259 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
30262 this.grid.render();
30263 this.grid.getDataSource().on('remove', this.refreshValue, this);
30264 this.grid.getDataSource().on('update', this.refreshValue, this);
30265 this.grid.on('afteredit', this.refreshValue, this);
30271 * Sets the value of the item.
30272 * @param {String} either an object or a string..
30274 setValue : function(v){
30276 v = v || []; // empty set..
30277 // this does not seem smart - it really only affects memoryproxy grids..
30278 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
30279 var ds = this.grid.getDataSource();
30280 // assumes a json reader..
30282 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
30283 ds.loadData( data);
30285 // clear selection so it does not get stale.
30286 if (this.grid.sm) {
30287 this.grid.sm.clearSelections();
30290 Roo.form.GridField.superclass.setValue.call(this, v);
30291 this.refreshValue();
30292 // should load data in the grid really....
30296 refreshValue: function() {
30298 this.grid.getDataSource().each(function(r) {
30301 this.el.dom.value = Roo.encode(val);
30309 * Ext JS Library 1.1.1
30310 * Copyright(c) 2006-2007, Ext JS, LLC.
30312 * Originally Released Under LGPL - original licence link has changed is not relivant.
30315 * <script type="text/javascript">
30318 * @class Roo.form.DisplayField
30319 * @extends Roo.form.Field
30320 * A generic Field to display non-editable data.
30322 * Creates a new Display Field item.
30323 * @param {Object} config Configuration options
30325 Roo.form.DisplayField = function(config){
30326 Roo.form.DisplayField.superclass.constructor.call(this, config);
30330 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
30331 inputType: 'hidden',
30337 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30339 focusClass : undefined,
30341 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30343 fieldClass: 'x-form-field',
30346 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
30348 valueRenderer: undefined,
30352 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30353 * {tag: "input", type: "checkbox", autocomplete: "off"})
30356 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
30358 onResize : function(){
30359 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
30363 initEvents : function(){
30364 // Roo.form.Checkbox.superclass.initEvents.call(this);
30365 // has no events...
30370 getResizeEl : function(){
30374 getPositionEl : function(){
30379 onRender : function(ct, position){
30381 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
30382 //if(this.inputValue !== undefined){
30383 this.wrap = this.el.wrap();
30385 this.viewEl = this.wrap.createChild({ tag: 'div', cls: 'x-form-displayfield'});
30387 if (this.bodyStyle) {
30388 this.viewEl.applyStyles(this.bodyStyle);
30390 //this.viewEl.setStyle('padding', '2px');
30392 this.setValue(this.value);
30397 initValue : Roo.emptyFn,
30402 onClick : function(){
30407 * Sets the checked state of the checkbox.
30408 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
30410 setValue : function(v){
30412 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
30413 // this might be called before we have a dom element..
30414 if (!this.viewEl) {
30417 this.viewEl.dom.innerHTML = html;
30418 Roo.form.DisplayField.superclass.setValue.call(this, v);
30428 * @class Roo.form.DayPicker
30429 * @extends Roo.form.Field
30430 * A Day picker show [M] [T] [W] ....
30432 * Creates a new Day Picker
30433 * @param {Object} config Configuration options
30435 Roo.form.DayPicker= function(config){
30436 Roo.form.DayPicker.superclass.constructor.call(this, config);
30440 Roo.extend(Roo.form.DayPicker, Roo.form.Field, {
30442 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
30444 focusClass : undefined,
30446 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
30448 fieldClass: "x-form-field",
30451 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
30452 * {tag: "input", type: "checkbox", autocomplete: "off"})
30454 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
30457 actionMode : 'viewEl',
30461 inputType : 'hidden',
30464 inputElement: false, // real input element?
30465 basedOn: false, // ????
30467 isFormField: true, // not sure where this is needed!!!!
30469 onResize : function(){
30470 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
30471 if(!this.boxLabel){
30472 this.el.alignTo(this.wrap, 'c-c');
30476 initEvents : function(){
30477 Roo.form.Checkbox.superclass.initEvents.call(this);
30478 this.el.on("click", this.onClick, this);
30479 this.el.on("change", this.onClick, this);
30483 getResizeEl : function(){
30487 getPositionEl : function(){
30493 onRender : function(ct, position){
30494 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
30496 this.wrap = this.el.wrap({cls: 'x-form-daypick-item '});
30498 var r1 = '<table><tr>';
30499 var r2 = '<tr class="x-form-daypick-icons">';
30500 for (var i=0; i < 7; i++) {
30501 r1+= '<td><div>' + Date.dayNames[i].substring(0,3) + '</div></td>';
30502 r2+= '<td><img class="x-menu-item-icon" src="' + Roo.BLANK_IMAGE_URL +'"></td>';
30505 var viewEl = this.wrap.createChild( r1 + '</tr>' + r2 + '</tr></table>');
30506 viewEl.select('img').on('click', this.onClick, this);
30507 this.viewEl = viewEl;
30510 // this will not work on Chrome!!!
30511 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
30512 this.el.on('propertychange', this.setFromHidden, this); //ie
30520 initValue : Roo.emptyFn,
30523 * Returns the checked state of the checkbox.
30524 * @return {Boolean} True if checked, else false
30526 getValue : function(){
30527 return this.el.dom.value;
30532 onClick : function(e){
30533 //this.setChecked(!this.checked);
30534 Roo.get(e.target).toggleClass('x-menu-item-checked');
30535 this.refreshValue();
30536 //if(this.el.dom.checked != this.checked){
30537 // this.setValue(this.el.dom.checked);
30542 refreshValue : function()
30545 this.viewEl.select('img',true).each(function(e,i,n) {
30546 val += e.is(".x-menu-item-checked") ? String(n) : '';
30548 this.setValue(val, true);
30552 * Sets the checked state of the checkbox.
30553 * On is always based on a string comparison between inputValue and the param.
30554 * @param {Boolean/String} value - the value to set
30555 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
30557 setValue : function(v,suppressEvent){
30558 if (!this.el.dom) {
30561 var old = this.el.dom.value ;
30562 this.el.dom.value = v;
30563 if (suppressEvent) {
30567 // update display..
30568 this.viewEl.select('img',true).each(function(e,i,n) {
30570 var on = e.is(".x-menu-item-checked");
30571 var newv = v.indexOf(String(n)) > -1;
30573 e.toggleClass('x-menu-item-checked');
30579 this.fireEvent('change', this, v, old);
30584 // handle setting of hidden value by some other method!!?!?
30585 setFromHidden: function()
30590 //console.log("SET FROM HIDDEN");
30591 //alert('setFrom hidden');
30592 this.setValue(this.el.dom.value);
30595 onDestroy : function()
30598 Roo.get(this.viewEl).remove();
30601 Roo.form.DayPicker.superclass.onDestroy.call(this);
30605 * RooJS Library 1.1.1
30606 * Copyright(c) 2008-2011 Alan Knowles
30613 * @class Roo.form.ComboCheck
30614 * @extends Roo.form.ComboBox
30615 * A combobox for multiple select items.
30617 * FIXME - could do with a reset button..
30620 * Create a new ComboCheck
30621 * @param {Object} config Configuration options
30623 Roo.form.ComboCheck = function(config){
30624 Roo.form.ComboCheck.superclass.constructor.call(this, config);
30625 // should verify some data...
30627 // hiddenName = required..
30628 // displayField = required
30629 // valudField == required
30630 var req= [ 'hiddenName', 'displayField', 'valueField' ];
30632 Roo.each(req, function(e) {
30633 if ((typeof(_t[e]) == 'undefined' ) || !_t[e].length) {
30634 throw "Roo.form.ComboCheck : missing value for: " + e;
30641 Roo.extend(Roo.form.ComboCheck, Roo.form.ComboBox, {
30646 selectedClass: 'x-menu-item-checked',
30649 onRender : function(ct, position){
30655 var cls = 'x-combo-list';
30658 this.tpl = new Roo.Template({
30659 html : '<div class="'+cls+'-item x-menu-check-item">' +
30660 '<img class="x-menu-item-icon" style="margin: 0px;" src="' + Roo.BLANK_IMAGE_URL + '">' +
30661 '<span>{' + this.displayField + '}</span>' +
30668 Roo.form.ComboCheck.superclass.onRender.call(this, ct, position);
30669 this.view.singleSelect = false;
30670 this.view.multiSelect = true;
30671 this.view.toggleSelect = true;
30672 this.pageTb.add(new Roo.Toolbar.Fill(), {
30675 handler: function()
30682 onViewOver : function(e, t){
30688 onViewClick : function(doFocus,index){
30692 select: function () {
30693 //Roo.log("SELECT CALLED");
30696 selectByValue : function(xv, scrollIntoView){
30697 var ar = this.getValueArray();
30700 Roo.each(ar, function(v) {
30701 if(v === undefined || v === null){
30704 var r = this.findRecord(this.valueField, v);
30706 sels.push(this.store.indexOf(r))
30710 this.view.select(sels);
30716 onSelect : function(record, index){
30717 // Roo.log("onselect Called");
30718 // this is only called by the clear button now..
30719 this.view.clearSelections();
30720 this.setValue('[]');
30721 if (this.value != this.valueBefore) {
30722 this.fireEvent('change', this, this.value, this.valueBefore);
30723 this.valueBefore = this.value;
30726 getValueArray : function()
30731 //Roo.log(this.value);
30732 if (typeof(this.value) == 'undefined') {
30735 var ar = Roo.decode(this.value);
30736 return ar instanceof Array ? ar : []; //?? valid?
30739 Roo.log(e + "\nRoo.form.ComboCheck:getValueArray invalid data:" + this.getValue());
30744 expand : function ()
30747 Roo.form.ComboCheck.superclass.expand.call(this);
30748 this.valueBefore = typeof(this.value) == 'undefined' ? '' : this.value;
30749 //this.valueBefore = typeof(this.valueBefore) == 'undefined' ? '' : this.valueBefore;
30754 collapse : function(){
30755 Roo.form.ComboCheck.superclass.collapse.call(this);
30756 var sl = this.view.getSelectedIndexes();
30757 var st = this.store;
30761 Roo.each(sl, function(i) {
30763 nv.push(r.get(this.valueField));
30765 this.setValue(Roo.encode(nv));
30766 if (this.value != this.valueBefore) {
30768 this.fireEvent('change', this, this.value, this.valueBefore);
30769 this.valueBefore = this.value;
30774 setValue : function(v){
30778 var vals = this.getValueArray();
30780 Roo.each(vals, function(k) {
30781 var r = this.findRecord(this.valueField, k);
30783 tv.push(r.data[this.displayField]);
30784 }else if(this.valueNotFoundText !== undefined){
30785 tv.push( this.valueNotFoundText );
30790 Roo.form.ComboBox.superclass.setValue.call(this, tv.join(', '));
30791 this.hiddenField.value = v;
30797 * Ext JS Library 1.1.1
30798 * Copyright(c) 2006-2007, Ext JS, LLC.
30800 * Originally Released Under LGPL - original licence link has changed is not relivant.
30803 * <script type="text/javascript">
30807 * @class Roo.form.Signature
30808 * @extends Roo.form.Field
30812 * @param {Object} config Configuration options
30815 Roo.form.Signature = function(config){
30816 Roo.form.Signature.superclass.constructor.call(this, config);
30818 this.addEvents({// not in used??
30821 * Fires when the 'confirm' icon is pressed (add a listener to enable add button)
30822 * @param {Roo.form.Signature} combo This combo box
30827 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
30828 * @param {Roo.form.ComboBox} combo This combo box
30829 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
30835 Roo.extend(Roo.form.Signature, Roo.form.Field, {
30837 * @cfg {Object} labels Label to use when rendering a form.
30841 * confirm : "Confirm"
30846 confirm : "Confirm"
30849 * @cfg {Number} width The signature panel width (defaults to 300)
30853 * @cfg {Number} height The signature panel height (defaults to 100)
30857 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to false)
30859 allowBlank : false,
30862 // {Object} signPanel The signature SVG panel element (defaults to {})
30864 // {Boolean} isMouseDown False to validate that the mouse down event (defaults to false)
30865 isMouseDown : false,
30866 // {Boolean} isConfirmed validate the signature is confirmed or not for submitting form (defaults to false)
30867 isConfirmed : false,
30868 // {String} signatureTmp SVG mapping string (defaults to empty string)
30872 defaultAutoCreate : { // modified by initCompnoent..
30878 onRender : function(ct, position){
30880 Roo.form.Signature.superclass.onRender.call(this, ct, position);
30882 this.wrap = this.el.wrap({
30883 cls:'x-form-signature-wrap', style : 'width: ' + this.width + 'px', cn:{cls:'x-form-signature'}
30886 this.createToolbar(this);
30887 this.signPanel = this.wrap.createChild({
30889 style: 'width: ' + this.width + 'px; height: ' + this.height + 'px; border: 0;'
30893 this.svgID = Roo.id();
30894 this.svgEl = this.signPanel.createChild({
30895 xmlns : 'http://www.w3.org/2000/svg',
30897 id : this.svgID + "-svg",
30899 height: this.height,
30900 viewBox: '0 0 '+this.width+' '+this.height,
30904 id: this.svgID + "-svg-r",
30906 height: this.height,
30911 id: this.svgID + "-svg-l",
30913 y1: (this.height*0.8), // start set the line in 80% of height
30914 x2: this.width, // end
30915 y2: (this.height*0.8), // end set the line in 80% of height
30917 'stroke-width': "1",
30918 'stroke-dasharray': "3",
30919 'shape-rendering': "crispEdges",
30920 'pointer-events': "none"
30924 id: this.svgID + "-svg-p",
30926 'stroke-width': "3",
30928 'pointer-events': 'none'
30933 this.svgBox = this.svgEl.dom.getScreenCTM();
30935 createSVG : function(){
30936 var svg = this.signPanel;
30937 var r = svg.select('#'+ this.svgID + '-svg-r', true).first().dom;
30940 r.addEventListener('mousedown', function(e) { return t.down(e); }, false);
30941 r.addEventListener('mousemove', function(e) { return t.move(e); }, false);
30942 r.addEventListener('mouseup', function(e) { return t.up(e); }, false);
30943 r.addEventListener('mouseout', function(e) { return t.up(e); }, false);
30944 r.addEventListener('touchstart', function(e) { return t.down(e); }, false);
30945 r.addEventListener('touchmove', function(e) { return t.move(e); }, false);
30946 r.addEventListener('touchend', function(e) { return t.up(e); }, false);
30949 isTouchEvent : function(e){
30950 return e.type.match(/^touch/);
30952 getCoords : function (e) {
30953 var pt = this.svgEl.dom.createSVGPoint();
30956 if (this.isTouchEvent(e)) {
30957 pt.x = e.targetTouches[0].clientX
30958 pt.y = e.targetTouches[0].clientY;
30960 var a = this.svgEl.dom.getScreenCTM();
30961 var b = a.inverse();
30962 var mx = pt.matrixTransform(b);
30963 return mx.x + ',' + mx.y;
30965 //mouse event headler
30966 down : function (e) {
30967 this.signatureTmp += 'M' + this.getCoords(e) + ' ';
30968 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr('d', this.signatureTmp);
30970 this.isMouseDown = true;
30972 e.preventDefault();
30974 move : function (e) {
30975 if (this.isMouseDown) {
30976 this.signatureTmp += 'L' + this.getCoords(e) + ' ';
30977 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', this.signatureTmp);
30980 e.preventDefault();
30982 up : function (e) {
30983 this.isMouseDown = false;
30984 var sp = this.signatureTmp.split(' ');
30987 if(!sp[sp.length-2].match(/^L/)){
30991 this.signatureTmp = sp.join(" ");
30994 if(this.getValue() != this.signatureTmp){
30995 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
30996 this.isConfirmed = false;
30998 e.preventDefault();
31002 * Protected method that will not generally be called directly. It
31003 * is called when the editor creates its toolbar. Override this method if you need to
31004 * add custom toolbar buttons.
31005 * @param {HtmlEditor} editor
31007 createToolbar : function(editor){
31008 function btn(id, toggle, handler){
31009 var xid = fid + '-'+ id ;
31013 cls : 'x-btn-icon x-edit-'+id,
31014 enableToggle:toggle !== false,
31015 scope: editor, // was editor...
31016 handler:handler||editor.relayBtnCmd,
31017 clickEvent:'mousedown',
31018 tooltip: etb.buttonTips[id] || undefined, ///tips ???
31024 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
31028 cls : ' x-signature-btn x-signature-'+id,
31029 scope: editor, // was editor...
31030 handler: this.reset,
31031 clickEvent:'mousedown',
31032 text: this.labels.clear
31039 cls : ' x-signature-btn x-signature-'+id,
31040 scope: editor, // was editor...
31041 handler: this.confirmHandler,
31042 clickEvent:'mousedown',
31043 text: this.labels.confirm
31050 * when user is clicked confirm then show this image.....
31052 * @return {String} Image Data URI
31054 getImageDataURI : function(){
31055 var svg = this.svgEl.dom.parentNode.innerHTML;
31056 var src = 'data:image/svg+xml;base64,'+window.btoa(svg);
31061 * @return {Boolean} this.isConfirmed
31063 getConfirmed : function(){
31064 return this.isConfirmed;
31068 * @return {Number} this.width
31070 getWidth : function(){
31075 * @return {Number} this.height
31077 getHeight : function(){
31078 return this.height;
31081 getSignature : function(){
31082 return this.signatureTmp;
31085 reset : function(){
31086 this.signatureTmp = '';
31087 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31088 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', '');
31089 this.isConfirmed = false;
31090 Roo.form.Signature.superclass.reset.call(this);
31092 setSignature : function(s){
31093 this.signatureTmp = s;
31094 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#ffa');
31095 this.signPanel.select('#'+ this.svgID + '-svg-p', true).first().attr( 'd', s);
31097 this.isConfirmed = false;
31098 Roo.form.Signature.superclass.reset.call(this);
31101 // Roo.log(this.signPanel.dom.contentWindow.up())
31104 setConfirmed : function(){
31108 // Roo.log(Roo.get(this.signPanel.dom.contentWindow.r).attr('fill', '#cfc'));
31111 confirmHandler : function(){
31112 if(!this.getSignature()){
31116 this.signPanel.select('#'+ this.svgID + '-svg-r', true).first().attr('fill', '#cfc');
31117 this.setValue(this.getSignature());
31118 this.isConfirmed = true;
31120 this.fireEvent('confirm', this);
31123 // Subclasses should provide the validation implementation by overriding this
31124 validateValue : function(value){
31125 if(this.allowBlank){
31129 if(this.isConfirmed){
31136 * Ext JS Library 1.1.1
31137 * Copyright(c) 2006-2007, Ext JS, LLC.
31139 * Originally Released Under LGPL - original licence link has changed is not relivant.
31142 * <script type="text/javascript">
31147 * @class Roo.form.ComboBox
31148 * @extends Roo.form.TriggerField
31149 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
31151 * Create a new ComboBox.
31152 * @param {Object} config Configuration options
31154 Roo.form.Select = function(config){
31155 Roo.form.Select.superclass.constructor.call(this, config);
31159 Roo.extend(Roo.form.Select , Roo.form.ComboBox, {
31161 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
31164 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
31165 * rendering into an Roo.Editor, defaults to false)
31168 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
31169 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
31172 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
31175 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
31176 * the dropdown list (defaults to undefined, with no header element)
31180 * @cfg {String/Roo.Template} tpl The template to use to render the output
31184 defaultAutoCreate : {tag: "select" },
31186 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
31188 listWidth: undefined,
31190 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
31191 * mode = 'remote' or 'text' if mode = 'local')
31193 displayField: undefined,
31195 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
31196 * mode = 'remote' or 'value' if mode = 'local').
31197 * Note: use of a valueField requires the user make a selection
31198 * in order for a value to be mapped.
31200 valueField: undefined,
31204 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
31205 * field's data value (defaults to the underlying DOM element's name)
31207 hiddenName: undefined,
31209 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
31213 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
31215 selectedClass: 'x-combo-selected',
31217 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
31218 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
31219 * which displays a downward arrow icon).
31221 triggerClass : 'x-form-arrow-trigger',
31223 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
31227 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
31228 * anchor positions (defaults to 'tl-bl')
31230 listAlign: 'tl-bl?',
31232 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
31236 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
31237 * query specified by the allQuery config option (defaults to 'query')
31239 triggerAction: 'query',
31241 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
31242 * (defaults to 4, does not apply if editable = false)
31246 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
31247 * delay (typeAheadDelay) if it matches a known value (defaults to false)
31251 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
31252 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
31256 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
31257 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
31261 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
31262 * when editable = true (defaults to false)
31264 selectOnFocus:false,
31266 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
31268 queryParam: 'query',
31270 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
31271 * when mode = 'remote' (defaults to 'Loading...')
31273 loadingText: 'Loading...',
31275 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
31279 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
31283 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
31284 * traditional select (defaults to true)
31288 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
31292 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
31296 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
31297 * listWidth has a higher value)
31301 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
31302 * allow the user to set arbitrary text into the field (defaults to false)
31304 forceSelection:false,
31306 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
31307 * if typeAhead = true (defaults to 250)
31309 typeAheadDelay : 250,
31311 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
31312 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
31314 valueNotFoundText : undefined,
31317 * @cfg {String} defaultValue The value displayed after loading the store.
31322 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
31324 blockFocus : false,
31327 * @cfg {Boolean} disableClear Disable showing of clear button.
31329 disableClear : false,
31331 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
31333 alwaysQuery : false,
31339 // element that contains real text value.. (when hidden is used..)
31342 onRender : function(ct, position){
31343 Roo.form.Field.prototype.onRender.call(this, ct, position);
31346 this.store.on('beforeload', this.onBeforeLoad, this);
31347 this.store.on('load', this.onLoad, this);
31348 this.store.on('loadexception', this.onLoadException, this);
31349 this.store.load({});
31357 initEvents : function(){
31358 //Roo.form.ComboBox.superclass.initEvents.call(this);
31362 onDestroy : function(){
31365 this.store.un('beforeload', this.onBeforeLoad, this);
31366 this.store.un('load', this.onLoad, this);
31367 this.store.un('loadexception', this.onLoadException, this);
31369 //Roo.form.ComboBox.superclass.onDestroy.call(this);
31373 fireKey : function(e){
31374 if(e.isNavKeyPress() && !this.list.isVisible()){
31375 this.fireEvent("specialkey", this, e);
31380 onResize: function(w, h){
31388 * Allow or prevent the user from directly editing the field text. If false is passed,
31389 * the user will only be able to select from the items defined in the dropdown list. This method
31390 * is the runtime equivalent of setting the 'editable' config option at config time.
31391 * @param {Boolean} value True to allow the user to directly edit the field text
31393 setEditable : function(value){
31398 onBeforeLoad : function(){
31400 Roo.log("Select before load");
31403 this.innerList.update(this.loadingText ?
31404 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
31405 //this.restrictHeight();
31406 this.selectedIndex = -1;
31410 onLoad : function(){
31413 var dom = this.el.dom;
31414 dom.innerHTML = '';
31415 var od = dom.ownerDocument;
31417 if (this.emptyText) {
31418 var op = od.createElement('option');
31419 op.setAttribute('value', '');
31420 op.innerHTML = String.format('{0}', this.emptyText);
31421 dom.appendChild(op);
31423 if(this.store.getCount() > 0){
31425 var vf = this.valueField;
31426 var df = this.displayField;
31427 this.store.data.each(function(r) {
31428 // which colmsn to use... testing - cdoe / title..
31429 var op = od.createElement('option');
31430 op.setAttribute('value', r.data[vf]);
31431 op.innerHTML = String.format('{0}', r.data[df]);
31432 dom.appendChild(op);
31434 if (typeof(this.defaultValue != 'undefined')) {
31435 this.setValue(this.defaultValue);
31440 //this.onEmptyResults();
31445 onLoadException : function()
31447 dom.innerHTML = '';
31449 Roo.log("Select on load exception");
31453 Roo.log(this.store.reader.jsonData);
31454 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
31455 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
31461 onTypeAhead : function(){
31466 onSelect : function(record, index){
31467 Roo.log('on select?');
31469 if(this.fireEvent('beforeselect', this, record, index) !== false){
31470 this.setFromData(index > -1 ? record.data : false);
31472 this.fireEvent('select', this, record, index);
31477 * Returns the currently selected field value or empty string if no value is set.
31478 * @return {String} value The selected value
31480 getValue : function(){
31481 var dom = this.el.dom;
31482 this.value = dom.options[dom.selectedIndex].value;
31488 * Clears any text/value currently set in the field
31490 clearValue : function(){
31492 this.el.dom.selectedIndex = this.emptyText ? 0 : -1;
31497 * Sets the specified value into the field. If the value finds a match, the corresponding record text
31498 * will be displayed in the field. If the value does not match the data value of an existing item,
31499 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
31500 * Otherwise the field will be blank (although the value will still be set).
31501 * @param {String} value The value to match
31503 setValue : function(v){
31504 var d = this.el.dom;
31505 for (var i =0; i < d.options.length;i++) {
31506 if (v == d.options[i].value) {
31507 d.selectedIndex = i;
31515 * @property {Object} the last set data for the element
31520 * Sets the value of the field based on a object which is related to the record format for the store.
31521 * @param {Object} value the value to set as. or false on reset?
31523 setFromData : function(o){
31524 Roo.log('setfrom data?');
31530 reset : function(){
31534 findRecord : function(prop, value){
31539 if(this.store.getCount() > 0){
31540 this.store.each(function(r){
31541 if(r.data[prop] == value){
31551 getName: function()
31553 // returns hidden if it's set..
31554 if (!this.rendered) {return ''};
31555 return !this.hiddenName && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
31563 onEmptyResults : function(){
31564 Roo.log('empty results');
31569 * Returns true if the dropdown list is expanded, else false.
31571 isExpanded : function(){
31576 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
31577 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31578 * @param {String} value The data value of the item to select
31579 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31580 * selected item if it is not currently in view (defaults to true)
31581 * @return {Boolean} True if the value matched an item in the list, else false
31583 selectByValue : function(v, scrollIntoView){
31584 Roo.log('select By Value');
31587 if(v !== undefined && v !== null){
31588 var r = this.findRecord(this.valueField || this.displayField, v);
31590 this.select(this.store.indexOf(r), scrollIntoView);
31598 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
31599 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
31600 * @param {Number} index The zero-based index of the list item to select
31601 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
31602 * selected item if it is not currently in view (defaults to true)
31604 select : function(index, scrollIntoView){
31605 Roo.log('select ');
31608 this.selectedIndex = index;
31609 this.view.select(index);
31610 if(scrollIntoView !== false){
31611 var el = this.view.getNode(index);
31613 this.innerList.scrollChildIntoView(el, false);
31621 validateBlur : function(){
31628 initQuery : function(){
31629 this.doQuery(this.getRawValue());
31633 doForce : function(){
31634 if(this.el.dom.value.length > 0){
31635 this.el.dom.value =
31636 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
31642 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
31643 * query allowing the query action to be canceled if needed.
31644 * @param {String} query The SQL query to execute
31645 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
31646 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
31647 * saved in the current store (defaults to false)
31649 doQuery : function(q, forceAll){
31651 Roo.log('doQuery?');
31652 if(q === undefined || q === null){
31657 forceAll: forceAll,
31661 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
31665 forceAll = qe.forceAll;
31666 if(forceAll === true || (q.length >= this.minChars)){
31667 if(this.lastQuery != q || this.alwaysQuery){
31668 this.lastQuery = q;
31669 if(this.mode == 'local'){
31670 this.selectedIndex = -1;
31672 this.store.clearFilter();
31674 this.store.filter(this.displayField, q);
31678 this.store.baseParams[this.queryParam] = q;
31680 params: this.getParams(q)
31685 this.selectedIndex = -1;
31692 getParams : function(q){
31694 //p[this.queryParam] = q;
31697 p.limit = this.pageSize;
31703 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
31705 collapse : function(){
31710 collapseIf : function(e){
31715 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
31717 expand : function(){
31725 * @cfg {Boolean} grow
31729 * @cfg {Number} growMin
31733 * @cfg {Number} growMax
31741 setWidth : function()
31745 getResizeEl : function(){
31748 });//<script type="text/javasscript">
31752 * @class Roo.DDView
31753 * A DnD enabled version of Roo.View.
31754 * @param {Element/String} container The Element in which to create the View.
31755 * @param {String} tpl The template string used to create the markup for each element of the View
31756 * @param {Object} config The configuration properties. These include all the config options of
31757 * {@link Roo.View} plus some specific to this class.<br>
31759 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
31760 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
31762 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
31763 .x-view-drag-insert-above {
31764 border-top:1px dotted #3366cc;
31766 .x-view-drag-insert-below {
31767 border-bottom:1px dotted #3366cc;
31773 Roo.DDView = function(container, tpl, config) {
31774 Roo.DDView.superclass.constructor.apply(this, arguments);
31775 this.getEl().setStyle("outline", "0px none");
31776 this.getEl().unselectable();
31777 if (this.dragGroup) {
31778 this.setDraggable(this.dragGroup.split(","));
31780 if (this.dropGroup) {
31781 this.setDroppable(this.dropGroup.split(","));
31783 if (this.deletable) {
31784 this.setDeletable();
31786 this.isDirtyFlag = false;
31792 Roo.extend(Roo.DDView, Roo.View, {
31793 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
31794 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
31795 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
31796 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
31800 reset: Roo.emptyFn,
31802 clearInvalid: Roo.form.Field.prototype.clearInvalid,
31804 validate: function() {
31808 destroy: function() {
31809 this.purgeListeners();
31810 this.getEl.removeAllListeners();
31811 this.getEl().remove();
31812 if (this.dragZone) {
31813 if (this.dragZone.destroy) {
31814 this.dragZone.destroy();
31817 if (this.dropZone) {
31818 if (this.dropZone.destroy) {
31819 this.dropZone.destroy();
31824 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
31825 getName: function() {
31829 /** Loads the View from a JSON string representing the Records to put into the Store. */
31830 setValue: function(v) {
31832 throw "DDView.setValue(). DDView must be constructed with a valid Store";
31835 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
31836 this.store.proxy = new Roo.data.MemoryProxy(data);
31840 /** @return {String} a parenthesised list of the ids of the Records in the View. */
31841 getValue: function() {
31843 this.store.each(function(rec) {
31844 result += rec.id + ',';
31846 return result.substr(0, result.length - 1) + ')';
31849 getIds: function() {
31850 var i = 0, result = new Array(this.store.getCount());
31851 this.store.each(function(rec) {
31852 result[i++] = rec.id;
31857 isDirty: function() {
31858 return this.isDirtyFlag;
31862 * Part of the Roo.dd.DropZone interface. If no target node is found, the
31863 * whole Element becomes the target, and this causes the drop gesture to append.
31865 getTargetFromEvent : function(e) {
31866 var target = e.getTarget();
31867 while ((target !== null) && (target.parentNode != this.el.dom)) {
31868 target = target.parentNode;
31871 target = this.el.dom.lastChild || this.el.dom;
31877 * Create the drag data which consists of an object which has the property "ddel" as
31878 * the drag proxy element.
31880 getDragData : function(e) {
31881 var target = this.findItemFromChild(e.getTarget());
31883 this.handleSelection(e);
31884 var selNodes = this.getSelectedNodes();
31887 copy: this.copy || (this.allowCopy && e.ctrlKey),
31891 var selectedIndices = this.getSelectedIndexes();
31892 for (var i = 0; i < selectedIndices.length; i++) {
31893 dragData.records.push(this.store.getAt(selectedIndices[i]));
31895 if (selNodes.length == 1) {
31896 dragData.ddel = target.cloneNode(true); // the div element
31898 var div = document.createElement('div'); // create the multi element drag "ghost"
31899 div.className = 'multi-proxy';
31900 for (var i = 0, len = selNodes.length; i < len; i++) {
31901 div.appendChild(selNodes[i].cloneNode(true));
31903 dragData.ddel = div;
31905 //console.log(dragData)
31906 //console.log(dragData.ddel.innerHTML)
31909 //console.log('nodragData')
31913 /** Specify to which ddGroup items in this DDView may be dragged. */
31914 setDraggable: function(ddGroup) {
31915 if (ddGroup instanceof Array) {
31916 Roo.each(ddGroup, this.setDraggable, this);
31919 if (this.dragZone) {
31920 this.dragZone.addToGroup(ddGroup);
31922 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
31923 containerScroll: true,
31927 // Draggability implies selection. DragZone's mousedown selects the element.
31928 if (!this.multiSelect) { this.singleSelect = true; }
31930 // Wire the DragZone's handlers up to methods in *this*
31931 this.dragZone.getDragData = this.getDragData.createDelegate(this);
31935 /** Specify from which ddGroup this DDView accepts drops. */
31936 setDroppable: function(ddGroup) {
31937 if (ddGroup instanceof Array) {
31938 Roo.each(ddGroup, this.setDroppable, this);
31941 if (this.dropZone) {
31942 this.dropZone.addToGroup(ddGroup);
31944 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
31945 containerScroll: true,
31949 // Wire the DropZone's handlers up to methods in *this*
31950 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
31951 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
31952 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
31953 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
31954 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
31958 /** Decide whether to drop above or below a View node. */
31959 getDropPoint : function(e, n, dd){
31960 if (n == this.el.dom) { return "above"; }
31961 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
31962 var c = t + (b - t) / 2;
31963 var y = Roo.lib.Event.getPageY(e);
31971 onNodeEnter : function(n, dd, e, data){
31975 onNodeOver : function(n, dd, e, data){
31976 var pt = this.getDropPoint(e, n, dd);
31977 // set the insert point style on the target node
31978 var dragElClass = this.dropNotAllowed;
31981 if (pt == "above"){
31982 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
31983 targetElClass = "x-view-drag-insert-above";
31985 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
31986 targetElClass = "x-view-drag-insert-below";
31988 if (this.lastInsertClass != targetElClass){
31989 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
31990 this.lastInsertClass = targetElClass;
31993 return dragElClass;
31996 onNodeOut : function(n, dd, e, data){
31997 this.removeDropIndicators(n);
32000 onNodeDrop : function(n, dd, e, data){
32001 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
32004 var pt = this.getDropPoint(e, n, dd);
32005 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
32006 if (pt == "below") { insertAt++; }
32007 for (var i = 0; i < data.records.length; i++) {
32008 var r = data.records[i];
32009 var dup = this.store.getById(r.id);
32010 if (dup && (dd != this.dragZone)) {
32011 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
32014 this.store.insert(insertAt++, r.copy());
32016 data.source.isDirtyFlag = true;
32018 this.store.insert(insertAt++, r);
32020 this.isDirtyFlag = true;
32023 this.dragZone.cachedTarget = null;
32027 removeDropIndicators : function(n){
32029 Roo.fly(n).removeClass([
32030 "x-view-drag-insert-above",
32031 "x-view-drag-insert-below"]);
32032 this.lastInsertClass = "_noclass";
32037 * Utility method. Add a delete option to the DDView's context menu.
32038 * @param {String} imageUrl The URL of the "delete" icon image.
32040 setDeletable: function(imageUrl) {
32041 if (!this.singleSelect && !this.multiSelect) {
32042 this.singleSelect = true;
32044 var c = this.getContextMenu();
32045 this.contextMenu.on("itemclick", function(item) {
32048 this.remove(this.getSelectedIndexes());
32052 this.contextMenu.add({
32059 /** Return the context menu for this DDView. */
32060 getContextMenu: function() {
32061 if (!this.contextMenu) {
32062 // Create the View's context menu
32063 this.contextMenu = new Roo.menu.Menu({
32064 id: this.id + "-contextmenu"
32066 this.el.on("contextmenu", this.showContextMenu, this);
32068 return this.contextMenu;
32071 disableContextMenu: function() {
32072 if (this.contextMenu) {
32073 this.el.un("contextmenu", this.showContextMenu, this);
32077 showContextMenu: function(e, item) {
32078 item = this.findItemFromChild(e.getTarget());
32081 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
32082 this.contextMenu.showAt(e.getXY());
32087 * Remove {@link Roo.data.Record}s at the specified indices.
32088 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
32090 remove: function(selectedIndices) {
32091 selectedIndices = [].concat(selectedIndices);
32092 for (var i = 0; i < selectedIndices.length; i++) {
32093 var rec = this.store.getAt(selectedIndices[i]);
32094 this.store.remove(rec);
32099 * Double click fires the event, but also, if this is draggable, and there is only one other
32100 * related DropZone, it transfers the selected node.
32102 onDblClick : function(e){
32103 var item = this.findItemFromChild(e.getTarget());
32105 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
32108 if (this.dragGroup) {
32109 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
32110 while (targets.indexOf(this.dropZone) > -1) {
32111 targets.remove(this.dropZone);
32113 if (targets.length == 1) {
32114 this.dragZone.cachedTarget = null;
32115 var el = Roo.get(targets[0].getEl());
32116 var box = el.getBox(true);
32117 targets[0].onNodeDrop(el.dom, {
32119 xy: [box.x, box.y + box.height - 1]
32120 }, null, this.getDragData(e));
32126 handleSelection: function(e) {
32127 this.dragZone.cachedTarget = null;
32128 var item = this.findItemFromChild(e.getTarget());
32130 this.clearSelections(true);
32133 if (item && (this.multiSelect || this.singleSelect)){
32134 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
32135 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
32136 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
32137 this.unselect(item);
32139 this.select(item, this.multiSelect && e.ctrlKey);
32140 this.lastSelection = item;
32145 onItemClick : function(item, index, e){
32146 if(this.fireEvent("beforeclick", this, index, item, e) === false){
32152 unselect : function(nodeInfo, suppressEvent){
32153 var node = this.getNode(nodeInfo);
32154 if(node && this.isSelected(node)){
32155 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
32156 Roo.fly(node).removeClass(this.selectedClass);
32157 this.selections.remove(node);
32158 if(!suppressEvent){
32159 this.fireEvent("selectionchange", this, this.selections);
32167 * Ext JS Library 1.1.1
32168 * Copyright(c) 2006-2007, Ext JS, LLC.
32170 * Originally Released Under LGPL - original licence link has changed is not relivant.
32173 * <script type="text/javascript">
32177 * @class Roo.LayoutManager
32178 * @extends Roo.util.Observable
32179 * Base class for layout managers.
32181 Roo.LayoutManager = function(container, config){
32182 Roo.LayoutManager.superclass.constructor.call(this);
32183 this.el = Roo.get(container);
32184 // ie scrollbar fix
32185 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
32186 document.body.scroll = "no";
32187 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
32188 this.el.position('relative');
32190 this.id = this.el.id;
32191 this.el.addClass("x-layout-container");
32192 /** false to disable window resize monitoring @type Boolean */
32193 this.monitorWindowResize = true;
32198 * Fires when a layout is performed.
32199 * @param {Roo.LayoutManager} this
32203 * @event regionresized
32204 * Fires when the user resizes a region.
32205 * @param {Roo.LayoutRegion} region The resized region
32206 * @param {Number} newSize The new size (width for east/west, height for north/south)
32208 "regionresized" : true,
32210 * @event regioncollapsed
32211 * Fires when a region is collapsed.
32212 * @param {Roo.LayoutRegion} region The collapsed region
32214 "regioncollapsed" : true,
32216 * @event regionexpanded
32217 * Fires when a region is expanded.
32218 * @param {Roo.LayoutRegion} region The expanded region
32220 "regionexpanded" : true
32222 this.updating = false;
32223 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
32226 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
32228 * Returns true if this layout is currently being updated
32229 * @return {Boolean}
32231 isUpdating : function(){
32232 return this.updating;
32236 * Suspend the LayoutManager from doing auto-layouts while
32237 * making multiple add or remove calls
32239 beginUpdate : function(){
32240 this.updating = true;
32244 * Restore auto-layouts and optionally disable the manager from performing a layout
32245 * @param {Boolean} noLayout true to disable a layout update
32247 endUpdate : function(noLayout){
32248 this.updating = false;
32254 layout: function(){
32258 onRegionResized : function(region, newSize){
32259 this.fireEvent("regionresized", region, newSize);
32263 onRegionCollapsed : function(region){
32264 this.fireEvent("regioncollapsed", region);
32267 onRegionExpanded : function(region){
32268 this.fireEvent("regionexpanded", region);
32272 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
32273 * performs box-model adjustments.
32274 * @return {Object} The size as an object {width: (the width), height: (the height)}
32276 getViewSize : function(){
32278 if(this.el.dom != document.body){
32279 size = this.el.getSize();
32281 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
32283 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
32284 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
32289 * Returns the Element this layout is bound to.
32290 * @return {Roo.Element}
32292 getEl : function(){
32297 * Returns the specified region.
32298 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
32299 * @return {Roo.LayoutRegion}
32301 getRegion : function(target){
32302 return this.regions[target.toLowerCase()];
32305 onWindowResize : function(){
32306 if(this.monitorWindowResize){
32312 * Ext JS Library 1.1.1
32313 * Copyright(c) 2006-2007, Ext JS, LLC.
32315 * Originally Released Under LGPL - original licence link has changed is not relivant.
32318 * <script type="text/javascript">
32321 * @class Roo.BorderLayout
32322 * @extends Roo.LayoutManager
32323 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
32324 * please see: <br><br>
32325 * <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>
32326 * <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>
32329 var layout = new Roo.BorderLayout(document.body, {
32363 preferredTabWidth: 150
32368 var CP = Roo.ContentPanel;
32370 layout.beginUpdate();
32371 layout.add("north", new CP("north", "North"));
32372 layout.add("south", new CP("south", {title: "South", closable: true}));
32373 layout.add("west", new CP("west", {title: "West"}));
32374 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
32375 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
32376 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
32377 layout.getRegion("center").showPanel("center1");
32378 layout.endUpdate();
32381 <b>The container the layout is rendered into can be either the body element or any other element.
32382 If it is not the body element, the container needs to either be an absolute positioned element,
32383 or you will need to add "position:relative" to the css of the container. You will also need to specify
32384 the container size if it is not the body element.</b>
32387 * Create a new BorderLayout
32388 * @param {String/HTMLElement/Element} container The container this layout is bound to
32389 * @param {Object} config Configuration options
32391 Roo.BorderLayout = function(container, config){
32392 config = config || {};
32393 Roo.BorderLayout.superclass.constructor.call(this, container, config);
32394 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
32395 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
32396 var target = this.factory.validRegions[i];
32397 if(config[target]){
32398 this.addRegion(target, config[target]);
32403 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
32405 * Creates and adds a new region if it doesn't already exist.
32406 * @param {String} target The target region key (north, south, east, west or center).
32407 * @param {Object} config The regions config object
32408 * @return {BorderLayoutRegion} The new region
32410 addRegion : function(target, config){
32411 if(!this.regions[target]){
32412 var r = this.factory.create(target, this, config);
32413 this.bindRegion(target, r);
32415 return this.regions[target];
32419 bindRegion : function(name, r){
32420 this.regions[name] = r;
32421 r.on("visibilitychange", this.layout, this);
32422 r.on("paneladded", this.layout, this);
32423 r.on("panelremoved", this.layout, this);
32424 r.on("invalidated", this.layout, this);
32425 r.on("resized", this.onRegionResized, this);
32426 r.on("collapsed", this.onRegionCollapsed, this);
32427 r.on("expanded", this.onRegionExpanded, this);
32431 * Performs a layout update.
32433 layout : function(){
32434 if(this.updating) return;
32435 var size = this.getViewSize();
32436 var w = size.width;
32437 var h = size.height;
32442 //var x = 0, y = 0;
32444 var rs = this.regions;
32445 var north = rs["north"];
32446 var south = rs["south"];
32447 var west = rs["west"];
32448 var east = rs["east"];
32449 var center = rs["center"];
32450 //if(this.hideOnLayout){ // not supported anymore
32451 //c.el.setStyle("display", "none");
32453 if(north && north.isVisible()){
32454 var b = north.getBox();
32455 var m = north.getMargins();
32456 b.width = w - (m.left+m.right);
32459 centerY = b.height + b.y + m.bottom;
32460 centerH -= centerY;
32461 north.updateBox(this.safeBox(b));
32463 if(south && south.isVisible()){
32464 var b = south.getBox();
32465 var m = south.getMargins();
32466 b.width = w - (m.left+m.right);
32468 var totalHeight = (b.height + m.top + m.bottom);
32469 b.y = h - totalHeight + m.top;
32470 centerH -= totalHeight;
32471 south.updateBox(this.safeBox(b));
32473 if(west && west.isVisible()){
32474 var b = west.getBox();
32475 var m = west.getMargins();
32476 b.height = centerH - (m.top+m.bottom);
32478 b.y = centerY + m.top;
32479 var totalWidth = (b.width + m.left + m.right);
32480 centerX += totalWidth;
32481 centerW -= totalWidth;
32482 west.updateBox(this.safeBox(b));
32484 if(east && east.isVisible()){
32485 var b = east.getBox();
32486 var m = east.getMargins();
32487 b.height = centerH - (m.top+m.bottom);
32488 var totalWidth = (b.width + m.left + m.right);
32489 b.x = w - totalWidth + m.left;
32490 b.y = centerY + m.top;
32491 centerW -= totalWidth;
32492 east.updateBox(this.safeBox(b));
32495 var m = center.getMargins();
32497 x: centerX + m.left,
32498 y: centerY + m.top,
32499 width: centerW - (m.left+m.right),
32500 height: centerH - (m.top+m.bottom)
32502 //if(this.hideOnLayout){
32503 //center.el.setStyle("display", "block");
32505 center.updateBox(this.safeBox(centerBox));
32508 this.fireEvent("layout", this);
32512 safeBox : function(box){
32513 box.width = Math.max(0, box.width);
32514 box.height = Math.max(0, box.height);
32519 * Adds a ContentPanel (or subclass) to this layout.
32520 * @param {String} target The target region key (north, south, east, west or center).
32521 * @param {Roo.ContentPanel} panel The panel to add
32522 * @return {Roo.ContentPanel} The added panel
32524 add : function(target, panel){
32526 target = target.toLowerCase();
32527 return this.regions[target].add(panel);
32531 * Remove a ContentPanel (or subclass) to this layout.
32532 * @param {String} target The target region key (north, south, east, west or center).
32533 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
32534 * @return {Roo.ContentPanel} The removed panel
32536 remove : function(target, panel){
32537 target = target.toLowerCase();
32538 return this.regions[target].remove(panel);
32542 * Searches all regions for a panel with the specified id
32543 * @param {String} panelId
32544 * @return {Roo.ContentPanel} The panel or null if it wasn't found
32546 findPanel : function(panelId){
32547 var rs = this.regions;
32548 for(var target in rs){
32549 if(typeof rs[target] != "function"){
32550 var p = rs[target].getPanel(panelId);
32560 * Searches all regions for a panel with the specified id and activates (shows) it.
32561 * @param {String/ContentPanel} panelId The panels id or the panel itself
32562 * @return {Roo.ContentPanel} The shown panel or null
32564 showPanel : function(panelId) {
32565 var rs = this.regions;
32566 for(var target in rs){
32567 var r = rs[target];
32568 if(typeof r != "function"){
32569 if(r.hasPanel(panelId)){
32570 return r.showPanel(panelId);
32578 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
32579 * @param {Roo.state.Provider} provider (optional) An alternate state provider
32581 restoreState : function(provider){
32583 provider = Roo.state.Manager;
32585 var sm = new Roo.LayoutStateManager();
32586 sm.init(this, provider);
32590 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
32591 * object should contain properties for each region to add ContentPanels to, and each property's value should be
32592 * a valid ContentPanel config object. Example:
32594 // Create the main layout
32595 var layout = new Roo.BorderLayout('main-ct', {
32606 // Create and add multiple ContentPanels at once via configs
32609 id: 'source-files',
32611 title:'Ext Source Files',
32624 * @param {Object} regions An object containing ContentPanel configs by region name
32626 batchAdd : function(regions){
32627 this.beginUpdate();
32628 for(var rname in regions){
32629 var lr = this.regions[rname];
32631 this.addTypedPanels(lr, regions[rname]);
32638 addTypedPanels : function(lr, ps){
32639 if(typeof ps == 'string'){
32640 lr.add(new Roo.ContentPanel(ps));
32642 else if(ps instanceof Array){
32643 for(var i =0, len = ps.length; i < len; i++){
32644 this.addTypedPanels(lr, ps[i]);
32647 else if(!ps.events){ // raw config?
32649 delete ps.el; // prevent conflict
32650 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
32652 else { // panel object assumed!
32657 * Adds a xtype elements to the layout.
32661 xtype : 'ContentPanel',
32668 xtype : 'NestedLayoutPanel',
32674 items : [ ... list of content panels or nested layout panels.. ]
32678 * @param {Object} cfg Xtype definition of item to add.
32680 addxtype : function(cfg)
32682 // basically accepts a pannel...
32683 // can accept a layout region..!?!?
32684 //Roo.log('Roo.BorderLayout add ' + cfg.xtype)
32686 if (!cfg.xtype.match(/Panel$/)) {
32691 if (typeof(cfg.region) == 'undefined') {
32692 Roo.log("Failed to add Panel, region was not set");
32696 var region = cfg.region;
32702 xitems = cfg.items;
32709 case 'ContentPanel': // ContentPanel (el, cfg)
32710 case 'ScrollPanel': // ContentPanel (el, cfg)
32712 if(cfg.autoCreate) {
32713 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32715 var el = this.el.createChild();
32716 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
32719 this.add(region, ret);
32723 case 'TreePanel': // our new panel!
32724 cfg.el = this.el.createChild();
32725 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
32726 this.add(region, ret);
32729 case 'NestedLayoutPanel':
32730 // create a new Layout (which is a Border Layout...
32731 var el = this.el.createChild();
32732 var clayout = cfg.layout;
32734 clayout.items = clayout.items || [];
32735 // replace this exitems with the clayout ones..
32736 xitems = clayout.items;
32739 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
32740 cfg.background = false;
32742 var layout = new Roo.BorderLayout(el, clayout);
32744 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
32745 //console.log('adding nested layout panel ' + cfg.toSource());
32746 this.add(region, ret);
32747 nb = {}; /// find first...
32752 // needs grid and region
32754 //var el = this.getRegion(region).el.createChild();
32755 var el = this.el.createChild();
32756 // create the grid first...
32758 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
32760 if (region == 'center' && this.active ) {
32761 cfg.background = false;
32763 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
32765 this.add(region, ret);
32766 if (cfg.background) {
32767 ret.on('activate', function(gp) {
32768 if (!gp.grid.rendered) {
32783 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
32785 // GridPanel (grid, cfg)
32788 this.beginUpdate();
32792 Roo.each(xitems, function(i) {
32793 region = nb && i.region ? i.region : false;
32795 var add = ret.addxtype(i);
32798 nb[region] = nb[region] == undefined ? 0 : nb[region]+1;
32799 if (!i.background) {
32800 abn[region] = nb[region] ;
32807 // make the last non-background panel active..
32808 //if (nb) { Roo.log(abn); }
32811 for(var r in abn) {
32812 region = this.getRegion(r);
32814 // tried using nb[r], but it does not work..
32816 region.showPanel(abn[r]);
32827 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
32828 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
32829 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
32830 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
32833 var CP = Roo.ContentPanel;
32835 var layout = Roo.BorderLayout.create({
32839 panels: [new CP("north", "North")]
32848 panels: [new CP("west", {title: "West"})]
32857 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
32866 panels: [new CP("south", {title: "South", closable: true})]
32873 preferredTabWidth: 150,
32875 new CP("center1", {title: "Close Me", closable: true}),
32876 new CP("center2", {title: "Center Panel", closable: false})
32881 layout.getRegion("center").showPanel("center1");
32886 Roo.BorderLayout.create = function(config, targetEl){
32887 var layout = new Roo.BorderLayout(targetEl || document.body, config);
32888 layout.beginUpdate();
32889 var regions = Roo.BorderLayout.RegionFactory.validRegions;
32890 for(var j = 0, jlen = regions.length; j < jlen; j++){
32891 var lr = regions[j];
32892 if(layout.regions[lr] && config[lr].panels){
32893 var r = layout.regions[lr];
32894 var ps = config[lr].panels;
32895 layout.addTypedPanels(r, ps);
32898 layout.endUpdate();
32903 Roo.BorderLayout.RegionFactory = {
32905 validRegions : ["north","south","east","west","center"],
32908 create : function(target, mgr, config){
32909 target = target.toLowerCase();
32910 if(config.lightweight || config.basic){
32911 return new Roo.BasicLayoutRegion(mgr, config, target);
32915 return new Roo.NorthLayoutRegion(mgr, config);
32917 return new Roo.SouthLayoutRegion(mgr, config);
32919 return new Roo.EastLayoutRegion(mgr, config);
32921 return new Roo.WestLayoutRegion(mgr, config);
32923 return new Roo.CenterLayoutRegion(mgr, config);
32925 throw 'Layout region "'+target+'" not supported.';
32929 * Ext JS Library 1.1.1
32930 * Copyright(c) 2006-2007, Ext JS, LLC.
32932 * Originally Released Under LGPL - original licence link has changed is not relivant.
32935 * <script type="text/javascript">
32939 * @class Roo.BasicLayoutRegion
32940 * @extends Roo.util.Observable
32941 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
32942 * and does not have a titlebar, tabs or any other features. All it does is size and position
32943 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
32945 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
32947 this.position = pos;
32950 * @scope Roo.BasicLayoutRegion
32954 * @event beforeremove
32955 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
32956 * @param {Roo.LayoutRegion} this
32957 * @param {Roo.ContentPanel} panel The panel
32958 * @param {Object} e The cancel event object
32960 "beforeremove" : true,
32962 * @event invalidated
32963 * Fires when the layout for this region is changed.
32964 * @param {Roo.LayoutRegion} this
32966 "invalidated" : true,
32968 * @event visibilitychange
32969 * Fires when this region is shown or hidden
32970 * @param {Roo.LayoutRegion} this
32971 * @param {Boolean} visibility true or false
32973 "visibilitychange" : true,
32975 * @event paneladded
32976 * Fires when a panel is added.
32977 * @param {Roo.LayoutRegion} this
32978 * @param {Roo.ContentPanel} panel The panel
32980 "paneladded" : true,
32982 * @event panelremoved
32983 * Fires when a panel is removed.
32984 * @param {Roo.LayoutRegion} this
32985 * @param {Roo.ContentPanel} panel The panel
32987 "panelremoved" : true,
32990 * Fires when this region is collapsed.
32991 * @param {Roo.LayoutRegion} this
32993 "collapsed" : true,
32996 * Fires when this region is expanded.
32997 * @param {Roo.LayoutRegion} this
33002 * Fires when this region is slid into view.
33003 * @param {Roo.LayoutRegion} this
33005 "slideshow" : true,
33008 * Fires when this region slides out of view.
33009 * @param {Roo.LayoutRegion} this
33011 "slidehide" : true,
33013 * @event panelactivated
33014 * Fires when a panel is activated.
33015 * @param {Roo.LayoutRegion} this
33016 * @param {Roo.ContentPanel} panel The activated panel
33018 "panelactivated" : true,
33021 * Fires when the user resizes this region.
33022 * @param {Roo.LayoutRegion} this
33023 * @param {Number} newSize The new size (width for east/west, height for north/south)
33027 /** A collection of panels in this region. @type Roo.util.MixedCollection */
33028 this.panels = new Roo.util.MixedCollection();
33029 this.panels.getKey = this.getPanelId.createDelegate(this);
33031 this.activePanel = null;
33032 // ensure listeners are added...
33034 if (config.listeners || config.events) {
33035 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
33036 listeners : config.listeners || {},
33037 events : config.events || {}
33041 if(skipConfig !== true){
33042 this.applyConfig(config);
33046 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
33047 getPanelId : function(p){
33051 applyConfig : function(config){
33052 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33053 this.config = config;
33058 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
33059 * the width, for horizontal (north, south) the height.
33060 * @param {Number} newSize The new width or height
33062 resizeTo : function(newSize){
33063 var el = this.el ? this.el :
33064 (this.activePanel ? this.activePanel.getEl() : null);
33066 switch(this.position){
33069 el.setWidth(newSize);
33070 this.fireEvent("resized", this, newSize);
33074 el.setHeight(newSize);
33075 this.fireEvent("resized", this, newSize);
33081 getBox : function(){
33082 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
33085 getMargins : function(){
33086 return this.margins;
33089 updateBox : function(box){
33091 var el = this.activePanel.getEl();
33092 el.dom.style.left = box.x + "px";
33093 el.dom.style.top = box.y + "px";
33094 this.activePanel.setSize(box.width, box.height);
33098 * Returns the container element for this region.
33099 * @return {Roo.Element}
33101 getEl : function(){
33102 return this.activePanel;
33106 * Returns true if this region is currently visible.
33107 * @return {Boolean}
33109 isVisible : function(){
33110 return this.activePanel ? true : false;
33113 setActivePanel : function(panel){
33114 panel = this.getPanel(panel);
33115 if(this.activePanel && this.activePanel != panel){
33116 this.activePanel.setActiveState(false);
33117 this.activePanel.getEl().setLeftTop(-10000,-10000);
33119 this.activePanel = panel;
33120 panel.setActiveState(true);
33122 panel.setSize(this.box.width, this.box.height);
33124 this.fireEvent("panelactivated", this, panel);
33125 this.fireEvent("invalidated");
33129 * Show the specified panel.
33130 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
33131 * @return {Roo.ContentPanel} The shown panel or null
33133 showPanel : function(panel){
33134 if(panel = this.getPanel(panel)){
33135 this.setActivePanel(panel);
33141 * Get the active panel for this region.
33142 * @return {Roo.ContentPanel} The active panel or null
33144 getActivePanel : function(){
33145 return this.activePanel;
33149 * Add the passed ContentPanel(s)
33150 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33151 * @return {Roo.ContentPanel} The panel added (if only one was added)
33153 add : function(panel){
33154 if(arguments.length > 1){
33155 for(var i = 0, len = arguments.length; i < len; i++) {
33156 this.add(arguments[i]);
33160 if(this.hasPanel(panel)){
33161 this.showPanel(panel);
33164 var el = panel.getEl();
33165 if(el.dom.parentNode != this.mgr.el.dom){
33166 this.mgr.el.dom.appendChild(el.dom);
33168 if(panel.setRegion){
33169 panel.setRegion(this);
33171 this.panels.add(panel);
33172 el.setStyle("position", "absolute");
33173 if(!panel.background){
33174 this.setActivePanel(panel);
33175 if(this.config.initialSize && this.panels.getCount()==1){
33176 this.resizeTo(this.config.initialSize);
33179 this.fireEvent("paneladded", this, panel);
33184 * Returns true if the panel is in this region.
33185 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33186 * @return {Boolean}
33188 hasPanel : function(panel){
33189 if(typeof panel == "object"){ // must be panel obj
33190 panel = panel.getId();
33192 return this.getPanel(panel) ? true : false;
33196 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33197 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33198 * @param {Boolean} preservePanel Overrides the config preservePanel option
33199 * @return {Roo.ContentPanel} The panel that was removed
33201 remove : function(panel, preservePanel){
33202 panel = this.getPanel(panel);
33207 this.fireEvent("beforeremove", this, panel, e);
33208 if(e.cancel === true){
33211 var panelId = panel.getId();
33212 this.panels.removeKey(panelId);
33217 * Returns the panel specified or null if it's not in this region.
33218 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
33219 * @return {Roo.ContentPanel}
33221 getPanel : function(id){
33222 if(typeof id == "object"){ // must be panel obj
33225 return this.panels.get(id);
33229 * Returns this regions position (north/south/east/west/center).
33232 getPosition: function(){
33233 return this.position;
33237 * Ext JS Library 1.1.1
33238 * Copyright(c) 2006-2007, Ext JS, LLC.
33240 * Originally Released Under LGPL - original licence link has changed is not relivant.
33243 * <script type="text/javascript">
33247 * @class Roo.LayoutRegion
33248 * @extends Roo.BasicLayoutRegion
33249 * This class represents a region in a layout manager.
33250 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
33251 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
33252 * @cfg {Boolean} floatable False to disable floating (defaults to true)
33253 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
33254 * @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})
33255 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
33256 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
33257 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
33258 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
33259 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
33260 * @cfg {String} title The title for the region (overrides panel titles)
33261 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
33262 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
33263 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
33264 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
33265 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
33266 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
33267 * the space available, similar to FireFox 1.5 tabs (defaults to false)
33268 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
33269 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
33270 * @cfg {Boolean} showPin True to show a pin button
33271 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
33272 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
33273 * @cfg {Boolean} disableTabTips True to disable tab tooltips
33274 * @cfg {Number} width For East/West panels
33275 * @cfg {Number} height For North/South panels
33276 * @cfg {Boolean} split To show the splitter
33277 * @cfg {Boolean} toolbar xtype configuration for a toolbar - shows on right of tabbar
33279 Roo.LayoutRegion = function(mgr, config, pos){
33280 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
33281 var dh = Roo.DomHelper;
33282 /** This region's container element
33283 * @type Roo.Element */
33284 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
33285 /** This region's title element
33286 * @type Roo.Element */
33288 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
33289 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
33290 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
33292 this.titleEl.enableDisplayMode();
33293 /** This region's title text element
33294 * @type HTMLElement */
33295 this.titleTextEl = this.titleEl.dom.firstChild;
33296 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
33297 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
33298 this.closeBtn.enableDisplayMode();
33299 this.closeBtn.on("click", this.closeClicked, this);
33300 this.closeBtn.hide();
33302 this.createBody(config);
33303 this.visible = true;
33304 this.collapsed = false;
33306 if(config.hideWhenEmpty){
33308 this.on("paneladded", this.validateVisibility, this);
33309 this.on("panelremoved", this.validateVisibility, this);
33311 this.applyConfig(config);
33314 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
33316 createBody : function(){
33317 /** This region's body element
33318 * @type Roo.Element */
33319 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
33322 applyConfig : function(c){
33323 if(c.collapsible && this.position != "center" && !this.collapsedEl){
33324 var dh = Roo.DomHelper;
33325 if(c.titlebar !== false){
33326 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
33327 this.collapseBtn.on("click", this.collapse, this);
33328 this.collapseBtn.enableDisplayMode();
33330 if(c.showPin === true || this.showPin){
33331 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
33332 this.stickBtn.enableDisplayMode();
33333 this.stickBtn.on("click", this.expand, this);
33334 this.stickBtn.hide();
33337 /** This region's collapsed element
33338 * @type Roo.Element */
33339 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
33340 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
33342 if(c.floatable !== false){
33343 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
33344 this.collapsedEl.on("click", this.collapseClick, this);
33347 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
33348 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
33349 id: "message", unselectable: "on", style:{"float":"left"}});
33350 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
33352 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
33353 this.expandBtn.on("click", this.expand, this);
33355 if(this.collapseBtn){
33356 this.collapseBtn.setVisible(c.collapsible == true);
33358 this.cmargins = c.cmargins || this.cmargins ||
33359 (this.position == "west" || this.position == "east" ?
33360 {top: 0, left: 2, right:2, bottom: 0} :
33361 {top: 2, left: 0, right:0, bottom: 2});
33362 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
33363 this.bottomTabs = c.tabPosition != "top";
33364 this.autoScroll = c.autoScroll || false;
33365 if(this.autoScroll){
33366 this.bodyEl.setStyle("overflow", "auto");
33368 this.bodyEl.setStyle("overflow", "hidden");
33370 //if(c.titlebar !== false){
33371 if((!c.titlebar && !c.title) || c.titlebar === false){
33372 this.titleEl.hide();
33374 this.titleEl.show();
33376 this.titleTextEl.innerHTML = c.title;
33380 this.duration = c.duration || .30;
33381 this.slideDuration = c.slideDuration || .45;
33384 this.collapse(true);
33391 * Returns true if this region is currently visible.
33392 * @return {Boolean}
33394 isVisible : function(){
33395 return this.visible;
33399 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
33400 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
33402 setCollapsedTitle : function(title){
33403 title = title || " ";
33404 if(this.collapsedTitleTextEl){
33405 this.collapsedTitleTextEl.innerHTML = title;
33409 getBox : function(){
33411 if(!this.collapsed){
33412 b = this.el.getBox(false, true);
33414 b = this.collapsedEl.getBox(false, true);
33419 getMargins : function(){
33420 return this.collapsed ? this.cmargins : this.margins;
33423 highlight : function(){
33424 this.el.addClass("x-layout-panel-dragover");
33427 unhighlight : function(){
33428 this.el.removeClass("x-layout-panel-dragover");
33431 updateBox : function(box){
33433 if(!this.collapsed){
33434 this.el.dom.style.left = box.x + "px";
33435 this.el.dom.style.top = box.y + "px";
33436 this.updateBody(box.width, box.height);
33438 this.collapsedEl.dom.style.left = box.x + "px";
33439 this.collapsedEl.dom.style.top = box.y + "px";
33440 this.collapsedEl.setSize(box.width, box.height);
33443 this.tabs.autoSizeTabs();
33447 updateBody : function(w, h){
33449 this.el.setWidth(w);
33450 w -= this.el.getBorderWidth("rl");
33451 if(this.config.adjustments){
33452 w += this.config.adjustments[0];
33456 this.el.setHeight(h);
33457 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
33458 h -= this.el.getBorderWidth("tb");
33459 if(this.config.adjustments){
33460 h += this.config.adjustments[1];
33462 this.bodyEl.setHeight(h);
33464 h = this.tabs.syncHeight(h);
33467 if(this.panelSize){
33468 w = w !== null ? w : this.panelSize.width;
33469 h = h !== null ? h : this.panelSize.height;
33471 if(this.activePanel){
33472 var el = this.activePanel.getEl();
33473 w = w !== null ? w : el.getWidth();
33474 h = h !== null ? h : el.getHeight();
33475 this.panelSize = {width: w, height: h};
33476 this.activePanel.setSize(w, h);
33478 if(Roo.isIE && this.tabs){
33479 this.tabs.el.repaint();
33484 * Returns the container element for this region.
33485 * @return {Roo.Element}
33487 getEl : function(){
33492 * Hides this region.
33495 if(!this.collapsed){
33496 this.el.dom.style.left = "-2000px";
33499 this.collapsedEl.dom.style.left = "-2000px";
33500 this.collapsedEl.hide();
33502 this.visible = false;
33503 this.fireEvent("visibilitychange", this, false);
33507 * Shows this region if it was previously hidden.
33510 if(!this.collapsed){
33513 this.collapsedEl.show();
33515 this.visible = true;
33516 this.fireEvent("visibilitychange", this, true);
33519 closeClicked : function(){
33520 if(this.activePanel){
33521 this.remove(this.activePanel);
33525 collapseClick : function(e){
33527 e.stopPropagation();
33530 e.stopPropagation();
33536 * Collapses this region.
33537 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
33539 collapse : function(skipAnim){
33540 if(this.collapsed) return;
33541 this.collapsed = true;
33543 this.split.el.hide();
33545 if(this.config.animate && skipAnim !== true){
33546 this.fireEvent("invalidated", this);
33547 this.animateCollapse();
33549 this.el.setLocation(-20000,-20000);
33551 this.collapsedEl.show();
33552 this.fireEvent("collapsed", this);
33553 this.fireEvent("invalidated", this);
33557 animateCollapse : function(){
33562 * Expands this region if it was previously collapsed.
33563 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
33564 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
33566 expand : function(e, skipAnim){
33567 if(e) e.stopPropagation();
33568 if(!this.collapsed || this.el.hasActiveFx()) return;
33570 this.afterSlideIn();
33573 this.collapsed = false;
33574 if(this.config.animate && skipAnim !== true){
33575 this.animateExpand();
33579 this.split.el.show();
33581 this.collapsedEl.setLocation(-2000,-2000);
33582 this.collapsedEl.hide();
33583 this.fireEvent("invalidated", this);
33584 this.fireEvent("expanded", this);
33588 animateExpand : function(){
33592 initTabs : function()
33594 this.bodyEl.setStyle("overflow", "hidden");
33595 var ts = new Roo.TabPanel(
33598 tabPosition: this.bottomTabs ? 'bottom' : 'top',
33599 disableTooltips: this.config.disableTabTips,
33600 toolbar : this.config.toolbar
33603 if(this.config.hideTabs){
33604 ts.stripWrap.setDisplayed(false);
33607 ts.resizeTabs = this.config.resizeTabs === true;
33608 ts.minTabWidth = this.config.minTabWidth || 40;
33609 ts.maxTabWidth = this.config.maxTabWidth || 250;
33610 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
33611 ts.monitorResize = false;
33612 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33613 ts.bodyEl.addClass('x-layout-tabs-body');
33614 this.panels.each(this.initPanelAsTab, this);
33617 initPanelAsTab : function(panel){
33618 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
33619 this.config.closeOnTab && panel.isClosable());
33620 if(panel.tabTip !== undefined){
33621 ti.setTooltip(panel.tabTip);
33623 ti.on("activate", function(){
33624 this.setActivePanel(panel);
33626 if(this.config.closeOnTab){
33627 ti.on("beforeclose", function(t, e){
33629 this.remove(panel);
33635 updatePanelTitle : function(panel, title){
33636 if(this.activePanel == panel){
33637 this.updateTitle(title);
33640 var ti = this.tabs.getTab(panel.getEl().id);
33642 if(panel.tabTip !== undefined){
33643 ti.setTooltip(panel.tabTip);
33648 updateTitle : function(title){
33649 if(this.titleTextEl && !this.config.title){
33650 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
33654 setActivePanel : function(panel){
33655 panel = this.getPanel(panel);
33656 if(this.activePanel && this.activePanel != panel){
33657 this.activePanel.setActiveState(false);
33659 this.activePanel = panel;
33660 panel.setActiveState(true);
33661 if(this.panelSize){
33662 panel.setSize(this.panelSize.width, this.panelSize.height);
33665 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
33667 this.updateTitle(panel.getTitle());
33669 this.fireEvent("invalidated", this);
33671 this.fireEvent("panelactivated", this, panel);
33675 * Shows the specified panel.
33676 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
33677 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
33679 showPanel : function(panel){
33680 if(panel = this.getPanel(panel)){
33682 var tab = this.tabs.getTab(panel.getEl().id);
33683 if(tab.isHidden()){
33684 this.tabs.unhideTab(tab.id);
33688 this.setActivePanel(panel);
33695 * Get the active panel for this region.
33696 * @return {Roo.ContentPanel} The active panel or null
33698 getActivePanel : function(){
33699 return this.activePanel;
33702 validateVisibility : function(){
33703 if(this.panels.getCount() < 1){
33704 this.updateTitle(" ");
33705 this.closeBtn.hide();
33708 if(!this.isVisible()){
33715 * Adds the passed ContentPanel(s) to this region.
33716 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
33717 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
33719 add : function(panel){
33720 if(arguments.length > 1){
33721 for(var i = 0, len = arguments.length; i < len; i++) {
33722 this.add(arguments[i]);
33726 if(this.hasPanel(panel)){
33727 this.showPanel(panel);
33730 panel.setRegion(this);
33731 this.panels.add(panel);
33732 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
33733 this.bodyEl.dom.appendChild(panel.getEl().dom);
33734 if(panel.background !== true){
33735 this.setActivePanel(panel);
33737 this.fireEvent("paneladded", this, panel);
33743 this.initPanelAsTab(panel);
33745 if(panel.background !== true){
33746 this.tabs.activate(panel.getEl().id);
33748 this.fireEvent("paneladded", this, panel);
33753 * Hides the tab for the specified panel.
33754 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33756 hidePanel : function(panel){
33757 if(this.tabs && (panel = this.getPanel(panel))){
33758 this.tabs.hideTab(panel.getEl().id);
33763 * Unhides the tab for a previously hidden panel.
33764 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33766 unhidePanel : function(panel){
33767 if(this.tabs && (panel = this.getPanel(panel))){
33768 this.tabs.unhideTab(panel.getEl().id);
33772 clearPanels : function(){
33773 while(this.panels.getCount() > 0){
33774 this.remove(this.panels.first());
33779 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
33780 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
33781 * @param {Boolean} preservePanel Overrides the config preservePanel option
33782 * @return {Roo.ContentPanel} The panel that was removed
33784 remove : function(panel, preservePanel){
33785 panel = this.getPanel(panel);
33790 this.fireEvent("beforeremove", this, panel, e);
33791 if(e.cancel === true){
33794 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
33795 var panelId = panel.getId();
33796 this.panels.removeKey(panelId);
33798 document.body.appendChild(panel.getEl().dom);
33801 this.tabs.removeTab(panel.getEl().id);
33802 }else if (!preservePanel){
33803 this.bodyEl.dom.removeChild(panel.getEl().dom);
33805 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
33806 var p = this.panels.first();
33807 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
33808 tempEl.appendChild(p.getEl().dom);
33809 this.bodyEl.update("");
33810 this.bodyEl.dom.appendChild(p.getEl().dom);
33812 this.updateTitle(p.getTitle());
33814 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
33815 this.setActivePanel(p);
33817 panel.setRegion(null);
33818 if(this.activePanel == panel){
33819 this.activePanel = null;
33821 if(this.config.autoDestroy !== false && preservePanel !== true){
33822 try{panel.destroy();}catch(e){}
33824 this.fireEvent("panelremoved", this, panel);
33829 * Returns the TabPanel component used by this region
33830 * @return {Roo.TabPanel}
33832 getTabs : function(){
33836 createTool : function(parentEl, className){
33837 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
33838 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
33839 btn.addClassOnOver("x-layout-tools-button-over");
33844 * Ext JS Library 1.1.1
33845 * Copyright(c) 2006-2007, Ext JS, LLC.
33847 * Originally Released Under LGPL - original licence link has changed is not relivant.
33850 * <script type="text/javascript">
33856 * @class Roo.SplitLayoutRegion
33857 * @extends Roo.LayoutRegion
33858 * Adds a splitbar and other (private) useful functionality to a {@link Roo.LayoutRegion}.
33860 Roo.SplitLayoutRegion = function(mgr, config, pos, cursor){
33861 this.cursor = cursor;
33862 Roo.SplitLayoutRegion.superclass.constructor.call(this, mgr, config, pos);
33865 Roo.extend(Roo.SplitLayoutRegion, Roo.LayoutRegion, {
33866 splitTip : "Drag to resize.",
33867 collapsibleSplitTip : "Drag to resize. Double click to hide.",
33868 useSplitTips : false,
33870 applyConfig : function(config){
33871 Roo.SplitLayoutRegion.superclass.applyConfig.call(this, config);
33874 var splitEl = Roo.DomHelper.append(this.mgr.el.dom,
33875 {tag: "div", id: this.el.id + "-split", cls: "x-layout-split x-layout-split-"+this.position, html: " "});
33876 /** The SplitBar for this region
33877 * @type Roo.SplitBar */
33878 this.split = new Roo.SplitBar(splitEl, this.el, this.orientation);
33879 this.split.on("moved", this.onSplitMove, this);
33880 this.split.useShim = config.useShim === true;
33881 this.split.getMaximumSize = this[this.position == 'north' || this.position == 'south' ? 'getVMaxSize' : 'getHMaxSize'].createDelegate(this);
33882 if(this.useSplitTips){
33883 this.split.el.dom.title = config.collapsible ? this.collapsibleSplitTip : this.splitTip;
33885 if(config.collapsible){
33886 this.split.el.on("dblclick", this.collapse, this);
33889 if(typeof config.minSize != "undefined"){
33890 this.split.minSize = config.minSize;
33892 if(typeof config.maxSize != "undefined"){
33893 this.split.maxSize = config.maxSize;
33895 if(config.hideWhenEmpty || config.hidden || config.collapsed){
33896 this.hideSplitter();
33901 getHMaxSize : function(){
33902 var cmax = this.config.maxSize || 10000;
33903 var center = this.mgr.getRegion("center");
33904 return Math.min(cmax, (this.el.getWidth()+center.getEl().getWidth())-center.getMinWidth());
33907 getVMaxSize : function(){
33908 var cmax = this.config.maxSize || 10000;
33909 var center = this.mgr.getRegion("center");
33910 return Math.min(cmax, (this.el.getHeight()+center.getEl().getHeight())-center.getMinHeight());
33913 onSplitMove : function(split, newSize){
33914 this.fireEvent("resized", this, newSize);
33918 * Returns the {@link Roo.SplitBar} for this region.
33919 * @return {Roo.SplitBar}
33921 getSplitBar : function(){
33926 this.hideSplitter();
33927 Roo.SplitLayoutRegion.superclass.hide.call(this);
33930 hideSplitter : function(){
33932 this.split.el.setLocation(-2000,-2000);
33933 this.split.el.hide();
33939 this.split.el.show();
33941 Roo.SplitLayoutRegion.superclass.show.call(this);
33944 beforeSlide: function(){
33945 if(Roo.isGecko){// firefox overflow auto bug workaround
33946 this.bodyEl.clip();
33947 if(this.tabs) this.tabs.bodyEl.clip();
33948 if(this.activePanel){
33949 this.activePanel.getEl().clip();
33951 if(this.activePanel.beforeSlide){
33952 this.activePanel.beforeSlide();
33958 afterSlide : function(){
33959 if(Roo.isGecko){// firefox overflow auto bug workaround
33960 this.bodyEl.unclip();
33961 if(this.tabs) this.tabs.bodyEl.unclip();
33962 if(this.activePanel){
33963 this.activePanel.getEl().unclip();
33964 if(this.activePanel.afterSlide){
33965 this.activePanel.afterSlide();
33971 initAutoHide : function(){
33972 if(this.autoHide !== false){
33973 if(!this.autoHideHd){
33974 var st = new Roo.util.DelayedTask(this.slideIn, this);
33975 this.autoHideHd = {
33976 "mouseout": function(e){
33977 if(!e.within(this.el, true)){
33981 "mouseover" : function(e){
33987 this.el.on(this.autoHideHd);
33991 clearAutoHide : function(){
33992 if(this.autoHide !== false){
33993 this.el.un("mouseout", this.autoHideHd.mouseout);
33994 this.el.un("mouseover", this.autoHideHd.mouseover);
33998 clearMonitor : function(){
33999 Roo.get(document).un("click", this.slideInIf, this);
34002 // these names are backwards but not changed for compat
34003 slideOut : function(){
34004 if(this.isSlid || this.el.hasActiveFx()){
34007 this.isSlid = true;
34008 if(this.collapseBtn){
34009 this.collapseBtn.hide();
34011 this.closeBtnState = this.closeBtn.getStyle('display');
34012 this.closeBtn.hide();
34014 this.stickBtn.show();
34017 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor());
34018 this.beforeSlide();
34019 this.el.setStyle("z-index", 10001);
34020 this.el.slideIn(this.getSlideAnchor(), {
34021 callback: function(){
34023 this.initAutoHide();
34024 Roo.get(document).on("click", this.slideInIf, this);
34025 this.fireEvent("slideshow", this);
34032 afterSlideIn : function(){
34033 this.clearAutoHide();
34034 this.isSlid = false;
34035 this.clearMonitor();
34036 this.el.setStyle("z-index", "");
34037 if(this.collapseBtn){
34038 this.collapseBtn.show();
34040 this.closeBtn.setStyle('display', this.closeBtnState);
34042 this.stickBtn.hide();
34044 this.fireEvent("slidehide", this);
34047 slideIn : function(cb){
34048 if(!this.isSlid || this.el.hasActiveFx()){
34052 this.isSlid = false;
34053 this.beforeSlide();
34054 this.el.slideOut(this.getSlideAnchor(), {
34055 callback: function(){
34056 this.el.setLeftTop(-10000, -10000);
34058 this.afterSlideIn();
34066 slideInIf : function(e){
34067 if(!e.within(this.el)){
34072 animateCollapse : function(){
34073 this.beforeSlide();
34074 this.el.setStyle("z-index", 20000);
34075 var anchor = this.getSlideAnchor();
34076 this.el.slideOut(anchor, {
34077 callback : function(){
34078 this.el.setStyle("z-index", "");
34079 this.collapsedEl.slideIn(anchor, {duration:.3});
34081 this.el.setLocation(-10000,-10000);
34083 this.fireEvent("collapsed", this);
34090 animateExpand : function(){
34091 this.beforeSlide();
34092 this.el.alignTo(this.collapsedEl, this.getCollapseAnchor(), this.getExpandAdj());
34093 this.el.setStyle("z-index", 20000);
34094 this.collapsedEl.hide({
34097 this.el.slideIn(this.getSlideAnchor(), {
34098 callback : function(){
34099 this.el.setStyle("z-index", "");
34102 this.split.el.show();
34104 this.fireEvent("invalidated", this);
34105 this.fireEvent("expanded", this);
34133 getAnchor : function(){
34134 return this.anchors[this.position];
34137 getCollapseAnchor : function(){
34138 return this.canchors[this.position];
34141 getSlideAnchor : function(){
34142 return this.sanchors[this.position];
34145 getAlignAdj : function(){
34146 var cm = this.cmargins;
34147 switch(this.position){
34163 getExpandAdj : function(){
34164 var c = this.collapsedEl, cm = this.cmargins;
34165 switch(this.position){
34167 return [-(cm.right+c.getWidth()+cm.left), 0];
34170 return [cm.right+c.getWidth()+cm.left, 0];
34173 return [0, -(cm.top+cm.bottom+c.getHeight())];
34176 return [0, cm.top+cm.bottom+c.getHeight()];
34182 * Ext JS Library 1.1.1
34183 * Copyright(c) 2006-2007, Ext JS, LLC.
34185 * Originally Released Under LGPL - original licence link has changed is not relivant.
34188 * <script type="text/javascript">
34191 * These classes are private internal classes
34193 Roo.CenterLayoutRegion = function(mgr, config){
34194 Roo.LayoutRegion.call(this, mgr, config, "center");
34195 this.visible = true;
34196 this.minWidth = config.minWidth || 20;
34197 this.minHeight = config.minHeight || 20;
34200 Roo.extend(Roo.CenterLayoutRegion, Roo.LayoutRegion, {
34202 // center panel can't be hidden
34206 // center panel can't be hidden
34209 getMinWidth: function(){
34210 return this.minWidth;
34213 getMinHeight: function(){
34214 return this.minHeight;
34219 Roo.NorthLayoutRegion = function(mgr, config){
34220 Roo.LayoutRegion.call(this, mgr, config, "north", "n-resize");
34222 this.split.placement = Roo.SplitBar.TOP;
34223 this.split.orientation = Roo.SplitBar.VERTICAL;
34224 this.split.el.addClass("x-layout-split-v");
34226 var size = config.initialSize || config.height;
34227 if(typeof size != "undefined"){
34228 this.el.setHeight(size);
34231 Roo.extend(Roo.NorthLayoutRegion, Roo.SplitLayoutRegion, {
34232 orientation: Roo.SplitBar.VERTICAL,
34233 getBox : function(){
34234 if(this.collapsed){
34235 return this.collapsedEl.getBox();
34237 var box = this.el.getBox();
34239 box.height += this.split.el.getHeight();
34244 updateBox : function(box){
34245 if(this.split && !this.collapsed){
34246 box.height -= this.split.el.getHeight();
34247 this.split.el.setLeft(box.x);
34248 this.split.el.setTop(box.y+box.height);
34249 this.split.el.setWidth(box.width);
34251 if(this.collapsed){
34252 this.updateBody(box.width, null);
34254 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34258 Roo.SouthLayoutRegion = function(mgr, config){
34259 Roo.SplitLayoutRegion.call(this, mgr, config, "south", "s-resize");
34261 this.split.placement = Roo.SplitBar.BOTTOM;
34262 this.split.orientation = Roo.SplitBar.VERTICAL;
34263 this.split.el.addClass("x-layout-split-v");
34265 var size = config.initialSize || config.height;
34266 if(typeof size != "undefined"){
34267 this.el.setHeight(size);
34270 Roo.extend(Roo.SouthLayoutRegion, Roo.SplitLayoutRegion, {
34271 orientation: Roo.SplitBar.VERTICAL,
34272 getBox : function(){
34273 if(this.collapsed){
34274 return this.collapsedEl.getBox();
34276 var box = this.el.getBox();
34278 var sh = this.split.el.getHeight();
34285 updateBox : function(box){
34286 if(this.split && !this.collapsed){
34287 var sh = this.split.el.getHeight();
34290 this.split.el.setLeft(box.x);
34291 this.split.el.setTop(box.y-sh);
34292 this.split.el.setWidth(box.width);
34294 if(this.collapsed){
34295 this.updateBody(box.width, null);
34297 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34301 Roo.EastLayoutRegion = function(mgr, config){
34302 Roo.SplitLayoutRegion.call(this, mgr, config, "east", "e-resize");
34304 this.split.placement = Roo.SplitBar.RIGHT;
34305 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34306 this.split.el.addClass("x-layout-split-h");
34308 var size = config.initialSize || config.width;
34309 if(typeof size != "undefined"){
34310 this.el.setWidth(size);
34313 Roo.extend(Roo.EastLayoutRegion, Roo.SplitLayoutRegion, {
34314 orientation: Roo.SplitBar.HORIZONTAL,
34315 getBox : function(){
34316 if(this.collapsed){
34317 return this.collapsedEl.getBox();
34319 var box = this.el.getBox();
34321 var sw = this.split.el.getWidth();
34328 updateBox : function(box){
34329 if(this.split && !this.collapsed){
34330 var sw = this.split.el.getWidth();
34332 this.split.el.setLeft(box.x);
34333 this.split.el.setTop(box.y);
34334 this.split.el.setHeight(box.height);
34337 if(this.collapsed){
34338 this.updateBody(null, box.height);
34340 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34344 Roo.WestLayoutRegion = function(mgr, config){
34345 Roo.SplitLayoutRegion.call(this, mgr, config, "west", "w-resize");
34347 this.split.placement = Roo.SplitBar.LEFT;
34348 this.split.orientation = Roo.SplitBar.HORIZONTAL;
34349 this.split.el.addClass("x-layout-split-h");
34351 var size = config.initialSize || config.width;
34352 if(typeof size != "undefined"){
34353 this.el.setWidth(size);
34356 Roo.extend(Roo.WestLayoutRegion, Roo.SplitLayoutRegion, {
34357 orientation: Roo.SplitBar.HORIZONTAL,
34358 getBox : function(){
34359 if(this.collapsed){
34360 return this.collapsedEl.getBox();
34362 var box = this.el.getBox();
34364 box.width += this.split.el.getWidth();
34369 updateBox : function(box){
34370 if(this.split && !this.collapsed){
34371 var sw = this.split.el.getWidth();
34373 this.split.el.setLeft(box.x+box.width);
34374 this.split.el.setTop(box.y);
34375 this.split.el.setHeight(box.height);
34377 if(this.collapsed){
34378 this.updateBody(null, box.height);
34380 Roo.LayoutRegion.prototype.updateBox.call(this, box);
34385 * Ext JS Library 1.1.1
34386 * Copyright(c) 2006-2007, Ext JS, LLC.
34388 * Originally Released Under LGPL - original licence link has changed is not relivant.
34391 * <script type="text/javascript">
34396 * Private internal class for reading and applying state
34398 Roo.LayoutStateManager = function(layout){
34399 // default empty state
34408 Roo.LayoutStateManager.prototype = {
34409 init : function(layout, provider){
34410 this.provider = provider;
34411 var state = provider.get(layout.id+"-layout-state");
34413 var wasUpdating = layout.isUpdating();
34415 layout.beginUpdate();
34417 for(var key in state){
34418 if(typeof state[key] != "function"){
34419 var rstate = state[key];
34420 var r = layout.getRegion(key);
34423 r.resizeTo(rstate.size);
34425 if(rstate.collapsed == true){
34428 r.expand(null, true);
34434 layout.endUpdate();
34436 this.state = state;
34438 this.layout = layout;
34439 layout.on("regionresized", this.onRegionResized, this);
34440 layout.on("regioncollapsed", this.onRegionCollapsed, this);
34441 layout.on("regionexpanded", this.onRegionExpanded, this);
34444 storeState : function(){
34445 this.provider.set(this.layout.id+"-layout-state", this.state);
34448 onRegionResized : function(region, newSize){
34449 this.state[region.getPosition()].size = newSize;
34453 onRegionCollapsed : function(region){
34454 this.state[region.getPosition()].collapsed = true;
34458 onRegionExpanded : function(region){
34459 this.state[region.getPosition()].collapsed = false;
34464 * Ext JS Library 1.1.1
34465 * Copyright(c) 2006-2007, Ext JS, LLC.
34467 * Originally Released Under LGPL - original licence link has changed is not relivant.
34470 * <script type="text/javascript">
34473 * @class Roo.ContentPanel
34474 * @extends Roo.util.Observable
34475 * A basic ContentPanel element.
34476 * @cfg {Boolean} fitToFrame True for this panel to adjust its size to fit when the region resizes (defaults to false)
34477 * @cfg {Boolean} fitContainer When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container (defaults to false)
34478 * @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
34479 * @cfg {Boolean} closable True if the panel can be closed/removed
34480 * @cfg {Boolean} background True if the panel should not be activated when it is added (defaults to false)
34481 * @cfg {String/HTMLElement/Element} resizeEl An element to resize if {@link #fitToFrame} is true (instead of this panel's element)
34482 * @cfg {Toolbar} toolbar A toolbar for this panel
34483 * @cfg {Boolean} autoScroll True to scroll overflow in this panel (use with {@link #fitToFrame})
34484 * @cfg {String} title The title for this panel
34485 * @cfg {Array} adjustments Values to <b>add</b> to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
34486 * @cfg {String} url Calls {@link #setUrl} with this value
34487 * @cfg {String} region (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
34488 * @cfg {String/Object} params When used with {@link #url}, calls {@link #setUrl} with this value
34489 * @cfg {Boolean} loadOnce When used with {@link #url}, calls {@link #setUrl} with this value
34490 * @cfg {String} content Raw content to fill content panel with (uses setContent on construction.)
34493 * Create a new ContentPanel.
34494 * @param {String/HTMLElement/Roo.Element} el The container element for this panel
34495 * @param {String/Object} config A string to set only the title or a config object
34496 * @param {String} content (optional) Set the HTML content for this panel
34497 * @param {String} region (optional) Used by xtype constructors to add to regions. (values center,east,west,south,north)
34499 Roo.ContentPanel = function(el, config, content){
34503 if(el.autoCreate || el.xtype){ // xtype is available if this is called from factory
34507 if (config && config.parentLayout) {
34508 el = config.parentLayout.el.createChild();
34511 if(el.autoCreate){ // xtype is available if this is called from factory
34515 this.el = Roo.get(el);
34516 if(!this.el && config && config.autoCreate){
34517 if(typeof config.autoCreate == "object"){
34518 if(!config.autoCreate.id){
34519 config.autoCreate.id = config.id||el;
34521 this.el = Roo.DomHelper.append(document.body,
34522 config.autoCreate, true);
34524 this.el = Roo.DomHelper.append(document.body,
34525 {tag: "div", cls: "x-layout-inactive-content", id: config.id||el}, true);
34528 this.closable = false;
34529 this.loaded = false;
34530 this.active = false;
34531 if(typeof config == "string"){
34532 this.title = config;
34534 Roo.apply(this, config);
34537 if (this.toolbar && !this.toolbar.el && this.toolbar.xtype) {
34538 this.wrapEl = this.el.wrap();
34539 this.toolbar.container = this.el.insertSibling(false, 'before');
34540 this.toolbar = new Roo.Toolbar(this.toolbar);
34543 // xtype created footer. - not sure if will work as we normally have to render first..
34544 if (this.footer && !this.footer.el && this.footer.xtype) {
34545 if (!this.wrapEl) {
34546 this.wrapEl = this.el.wrap();
34549 this.footer.container = this.wrapEl.createChild();
34551 this.footer = Roo.factory(this.footer, Roo);
34556 this.resizeEl = Roo.get(this.resizeEl, true);
34558 this.resizeEl = this.el;
34560 // handle view.xtype
34568 * Fires when this panel is activated.
34569 * @param {Roo.ContentPanel} this
34573 * @event deactivate
34574 * Fires when this panel is activated.
34575 * @param {Roo.ContentPanel} this
34577 "deactivate" : true,
34581 * Fires when this panel is resized if fitToFrame is true.
34582 * @param {Roo.ContentPanel} this
34583 * @param {Number} width The width after any component adjustments
34584 * @param {Number} height The height after any component adjustments
34590 * Fires when this tab is created
34591 * @param {Roo.ContentPanel} this
34602 if(this.autoScroll){
34603 this.resizeEl.setStyle("overflow", "auto");
34605 // fix randome scrolling
34606 this.el.on('scroll', function() {
34607 Roo.log('fix random scolling');
34608 this.scrollTo('top',0);
34611 content = content || this.content;
34613 this.setContent(content);
34615 if(config && config.url){
34616 this.setUrl(this.url, this.params, this.loadOnce);
34621 Roo.ContentPanel.superclass.constructor.call(this);
34623 if (this.view && typeof(this.view.xtype) != 'undefined') {
34624 this.view.el = this.el.appendChild(document.createElement("div"));
34625 this.view = Roo.factory(this.view);
34626 this.view.render && this.view.render(false, '');
34630 this.fireEvent('render', this);
34633 Roo.extend(Roo.ContentPanel, Roo.util.Observable, {
34635 setRegion : function(region){
34636 this.region = region;
34638 this.el.replaceClass("x-layout-inactive-content", "x-layout-active-content");
34640 this.el.replaceClass("x-layout-active-content", "x-layout-inactive-content");
34645 * Returns the toolbar for this Panel if one was configured.
34646 * @return {Roo.Toolbar}
34648 getToolbar : function(){
34649 return this.toolbar;
34652 setActiveState : function(active){
34653 this.active = active;
34655 this.fireEvent("deactivate", this);
34657 this.fireEvent("activate", this);
34661 * Updates this panel's element
34662 * @param {String} content The new content
34663 * @param {Boolean} loadScripts (optional) true to look for and process scripts
34665 setContent : function(content, loadScripts){
34666 this.el.update(content, loadScripts);
34669 ignoreResize : function(w, h){
34670 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
34673 this.lastSize = {width: w, height: h};
34678 * Get the {@link Roo.UpdateManager} for this panel. Enables you to perform Ajax updates.
34679 * @return {Roo.UpdateManager} The UpdateManager
34681 getUpdateManager : function(){
34682 return this.el.getUpdateManager();
34685 * Loads this content panel immediately with content from XHR. Note: to delay loading until the panel is activated, use {@link #setUrl}.
34686 * @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:
34689 url: "your-url.php",
34690 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
34691 callback: yourFunction,
34692 scope: yourObject, //(optional scope)
34695 text: "Loading...",
34700 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
34701 * 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.
34702 * @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}
34703 * @param {Function} callback (optional) Callback when transaction is complete -- called with signature (oElement, bSuccess, oResponse)
34704 * @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.
34705 * @return {Roo.ContentPanel} this
34708 var um = this.el.getUpdateManager();
34709 um.update.apply(um, arguments);
34715 * 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.
34716 * @param {String/Function} url The URL to load the content from or a function to call to get the URL
34717 * @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)
34718 * @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)
34719 * @return {Roo.UpdateManager} The UpdateManager
34721 setUrl : function(url, params, loadOnce){
34722 if(this.refreshDelegate){
34723 this.removeListener("activate", this.refreshDelegate);
34725 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
34726 this.on("activate", this.refreshDelegate);
34727 return this.el.getUpdateManager();
34730 _handleRefresh : function(url, params, loadOnce){
34731 if(!loadOnce || !this.loaded){
34732 var updater = this.el.getUpdateManager();
34733 updater.update(url, params, this._setLoaded.createDelegate(this));
34737 _setLoaded : function(){
34738 this.loaded = true;
34742 * Returns this panel's id
34745 getId : function(){
34750 * Returns this panel's element - used by regiosn to add.
34751 * @return {Roo.Element}
34753 getEl : function(){
34754 return this.wrapEl || this.el;
34757 adjustForComponents : function(width, height)
34759 //Roo.log('adjustForComponents ');
34760 if(this.resizeEl != this.el){
34761 width -= this.el.getFrameWidth('lr');
34762 height -= this.el.getFrameWidth('tb');
34765 var te = this.toolbar.getEl();
34766 height -= te.getHeight();
34767 te.setWidth(width);
34770 var te = this.footer.getEl();
34771 Roo.log("footer:" + te.getHeight());
34773 height -= te.getHeight();
34774 te.setWidth(width);
34778 if(this.adjustments){
34779 width += this.adjustments[0];
34780 height += this.adjustments[1];
34782 return {"width": width, "height": height};
34785 setSize : function(width, height){
34786 if(this.fitToFrame && !this.ignoreResize(width, height)){
34787 if(this.fitContainer && this.resizeEl != this.el){
34788 this.el.setSize(width, height);
34790 var size = this.adjustForComponents(width, height);
34791 this.resizeEl.setSize(this.autoWidth ? "auto" : size.width, this.autoHeight ? "auto" : size.height);
34792 this.fireEvent('resize', this, size.width, size.height);
34797 * Returns this panel's title
34800 getTitle : function(){
34805 * Set this panel's title
34806 * @param {String} title
34808 setTitle : function(title){
34809 this.title = title;
34811 this.region.updatePanelTitle(this, title);
34816 * Returns true is this panel was configured to be closable
34817 * @return {Boolean}
34819 isClosable : function(){
34820 return this.closable;
34823 beforeSlide : function(){
34825 this.resizeEl.clip();
34828 afterSlide : function(){
34830 this.resizeEl.unclip();
34834 * Force a content refresh from the URL specified in the {@link #setUrl} method.
34835 * Will fail silently if the {@link #setUrl} method has not been called.
34836 * This does not activate the panel, just updates its content.
34838 refresh : function(){
34839 if(this.refreshDelegate){
34840 this.loaded = false;
34841 this.refreshDelegate();
34846 * Destroys this panel
34848 destroy : function(){
34849 this.el.removeAllListeners();
34850 var tempEl = document.createElement("span");
34851 tempEl.appendChild(this.el.dom);
34852 tempEl.innerHTML = "";
34858 * form - if the content panel contains a form - this is a reference to it.
34859 * @type {Roo.form.Form}
34863 * view - if the content panel contains a view (Roo.DatePicker / Roo.View / Roo.JsonView)
34864 * This contains a reference to it.
34870 * Adds a xtype elements to the panel - currently only supports Forms, View, JsonView.
34880 * @param {Object} cfg Xtype definition of item to add.
34883 addxtype : function(cfg) {
34885 if (cfg.xtype.match(/^Form$/)) {
34888 //if (this.footer) {
34889 // el = this.footer.container.insertSibling(false, 'before');
34891 el = this.el.createChild();
34894 this.form = new Roo.form.Form(cfg);
34897 if ( this.form.allItems.length) this.form.render(el.dom);
34900 // should only have one of theses..
34901 if ([ 'View', 'JsonView', 'DatePicker'].indexOf(cfg.xtype) > -1) {
34902 // views.. should not be just added - used named prop 'view''
34904 cfg.el = this.el.appendChild(document.createElement("div"));
34907 var ret = new Roo.factory(cfg);
34909 ret.render && ret.render(false, ''); // render blank..
34918 * @class Roo.GridPanel
34919 * @extends Roo.ContentPanel
34921 * Create a new GridPanel.
34922 * @param {Roo.grid.Grid} grid The grid for this panel
34923 * @param {String/Object} config A string to set only the panel's title, or a config object
34925 Roo.GridPanel = function(grid, config){
34928 this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
34929 {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
34931 this.wrapper.dom.appendChild(grid.getGridEl().dom);
34933 Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
34936 this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
34938 // xtype created footer. - not sure if will work as we normally have to render first..
34939 if (this.footer && !this.footer.el && this.footer.xtype) {
34941 this.footer.container = this.grid.getView().getFooterPanel(true);
34942 this.footer.dataSource = this.grid.dataSource;
34943 this.footer = Roo.factory(this.footer, Roo);
34947 grid.monitorWindowResize = false; // turn off autosizing
34948 grid.autoHeight = false;
34949 grid.autoWidth = false;
34951 this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
34954 Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
34955 getId : function(){
34956 return this.grid.id;
34960 * Returns the grid for this panel
34961 * @return {Roo.grid.Grid}
34963 getGrid : function(){
34967 setSize : function(width, height){
34968 if(!this.ignoreResize(width, height)){
34969 var grid = this.grid;
34970 var size = this.adjustForComponents(width, height);
34971 grid.getGridEl().setSize(size.width, size.height);
34976 beforeSlide : function(){
34977 this.grid.getView().scroller.clip();
34980 afterSlide : function(){
34981 this.grid.getView().scroller.unclip();
34984 destroy : function(){
34985 this.grid.destroy();
34987 Roo.GridPanel.superclass.destroy.call(this);
34993 * @class Roo.NestedLayoutPanel
34994 * @extends Roo.ContentPanel
34996 * Create a new NestedLayoutPanel.
34999 * @param {Roo.BorderLayout} layout The layout for this panel
35000 * @param {String/Object} config A string to set only the title or a config object
35002 Roo.NestedLayoutPanel = function(layout, config)
35004 // construct with only one argument..
35005 /* FIXME - implement nicer consturctors
35006 if (layout.layout) {
35008 layout = config.layout;
35009 delete config.layout;
35011 if (layout.xtype && !layout.getEl) {
35012 // then layout needs constructing..
35013 layout = Roo.factory(layout, Roo);
35018 Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
35020 layout.monitorWindowResize = false; // turn off autosizing
35021 this.layout = layout;
35022 this.layout.getEl().addClass("x-layout-nested-layout");
35029 Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
35031 setSize : function(width, height){
35032 if(!this.ignoreResize(width, height)){
35033 var size = this.adjustForComponents(width, height);
35034 var el = this.layout.getEl();
35035 el.setSize(size.width, size.height);
35036 var touch = el.dom.offsetWidth;
35037 this.layout.layout();
35038 // ie requires a double layout on the first pass
35039 if(Roo.isIE && !this.initialized){
35040 this.initialized = true;
35041 this.layout.layout();
35046 // activate all subpanels if not currently active..
35048 setActiveState : function(active){
35049 this.active = active;
35051 this.fireEvent("deactivate", this);
35055 this.fireEvent("activate", this);
35056 // not sure if this should happen before or after..
35057 if (!this.layout) {
35058 return; // should not happen..
35061 for (var r in this.layout.regions) {
35062 reg = this.layout.getRegion(r);
35063 if (reg.getActivePanel()) {
35064 //reg.showPanel(reg.getActivePanel()); // force it to activate..
35065 reg.setActivePanel(reg.getActivePanel());
35068 if (!reg.panels.length) {
35071 reg.showPanel(reg.getPanel(0));
35080 * Returns the nested BorderLayout for this panel
35081 * @return {Roo.BorderLayout}
35083 getLayout : function(){
35084 return this.layout;
35088 * Adds a xtype elements to the layout of the nested panel
35092 xtype : 'ContentPanel',
35099 xtype : 'NestedLayoutPanel',
35105 items : [ ... list of content panels or nested layout panels.. ]
35109 * @param {Object} cfg Xtype definition of item to add.
35111 addxtype : function(cfg) {
35112 return this.layout.addxtype(cfg);
35117 Roo.ScrollPanel = function(el, config, content){
35118 config = config || {};
35119 config.fitToFrame = true;
35120 Roo.ScrollPanel.superclass.constructor.call(this, el, config, content);
35122 this.el.dom.style.overflow = "hidden";
35123 var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"});
35124 this.el.removeClass("x-layout-inactive-content");
35125 this.el.on("mousewheel", this.onWheel, this);
35127 var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom);
35128 var down = wrap.createChild({cls: "x-scroller-down", html: " "});
35129 up.unselectable(); down.unselectable();
35130 up.on("click", this.scrollUp, this);
35131 down.on("click", this.scrollDown, this);
35132 up.addClassOnOver("x-scroller-btn-over");
35133 down.addClassOnOver("x-scroller-btn-over");
35134 up.addClassOnClick("x-scroller-btn-click");
35135 down.addClassOnClick("x-scroller-btn-click");
35136 this.adjustments = [0, -(up.getHeight() + down.getHeight())];
35138 this.resizeEl = this.el;
35139 this.el = wrap; this.up = up; this.down = down;
35142 Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, {
35144 wheelIncrement : 5,
35145 scrollUp : function(){
35146 this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this});
35149 scrollDown : function(){
35150 this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this});
35153 afterScroll : function(){
35154 var el = this.resizeEl;
35155 var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight;
35156 this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35157 this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled");
35160 setSize : function(){
35161 Roo.ScrollPanel.superclass.setSize.apply(this, arguments);
35162 this.afterScroll();
35165 onWheel : function(e){
35166 var d = e.getWheelDelta();
35167 this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement);
35168 this.afterScroll();
35172 setContent : function(content, loadScripts){
35173 this.resizeEl.update(content, loadScripts);
35187 * @class Roo.TreePanel
35188 * @extends Roo.ContentPanel
35190 * Create a new TreePanel. - defaults to fit/scoll contents.
35191 * @param {String/Object} config A string to set only the panel's title, or a config object
35192 * @cfg {Roo.tree.TreePanel} tree The tree TreePanel, with config etc.
35194 Roo.TreePanel = function(config){
35195 var el = config.el;
35196 var tree = config.tree;
35197 delete config.tree;
35198 delete config.el; // hopefull!
35200 // wrapper for IE7 strict & safari scroll issue
35202 var treeEl = el.createChild();
35203 config.resizeEl = treeEl;
35207 Roo.TreePanel.superclass.constructor.call(this, el, config);
35210 this.tree = new Roo.tree.TreePanel(treeEl , tree);
35211 //console.log(tree);
35212 this.on('activate', function()
35214 if (this.tree.rendered) {
35217 //console.log('render tree');
35218 this.tree.render();
35220 // this should not be needed.. - it's actually the 'el' that resizes?
35221 // actuall it breaks the containerScroll - dragging nodes auto scroll at top
35223 //this.on('resize', function (cp, w, h) {
35224 // this.tree.innerCt.setWidth(w);
35225 // this.tree.innerCt.setHeight(h);
35226 // //this.tree.innerCt.setStyle('overflow-y', 'auto');
35233 Roo.extend(Roo.TreePanel, Roo.ContentPanel, {
35250 * Ext JS Library 1.1.1
35251 * Copyright(c) 2006-2007, Ext JS, LLC.
35253 * Originally Released Under LGPL - original licence link has changed is not relivant.
35256 * <script type="text/javascript">
35261 * @class Roo.ReaderLayout
35262 * @extends Roo.BorderLayout
35263 * This is a pre-built layout that represents a classic, 5-pane application. It consists of a header, a primary
35264 * center region containing two nested regions (a top one for a list view and one for item preview below),
35265 * and regions on either side that can be used for navigation, application commands, informational displays, etc.
35266 * The setup and configuration work exactly the same as it does for a {@link Roo.BorderLayout} - this class simply
35267 * expedites the setup of the overall layout and regions for this common application style.
35270 var reader = new Roo.ReaderLayout();
35271 var CP = Roo.ContentPanel; // shortcut for adding
35273 reader.beginUpdate();
35274 reader.add("north", new CP("north", "North"));
35275 reader.add("west", new CP("west", {title: "West"}));
35276 reader.add("east", new CP("east", {title: "East"}));
35278 reader.regions.listView.add(new CP("listView", "List"));
35279 reader.regions.preview.add(new CP("preview", "Preview"));
35280 reader.endUpdate();
35283 * Create a new ReaderLayout
35284 * @param {Object} config Configuration options
35285 * @param {String/HTMLElement/Element} container (optional) The container this layout is bound to (defaults to
35286 * document.body if omitted)
35288 Roo.ReaderLayout = function(config, renderTo){
35289 var c = config || {size:{}};
35290 Roo.ReaderLayout.superclass.constructor.call(this, renderTo || document.body, {
35291 north: c.north !== false ? Roo.apply({
35295 }, c.north) : false,
35296 west: c.west !== false ? Roo.apply({
35304 margins:{left:5,right:0,bottom:5,top:5},
35305 cmargins:{left:5,right:5,bottom:5,top:5}
35306 }, c.west) : false,
35307 east: c.east !== false ? Roo.apply({
35315 margins:{left:0,right:5,bottom:5,top:5},
35316 cmargins:{left:5,right:5,bottom:5,top:5}
35317 }, c.east) : false,
35318 center: Roo.apply({
35319 tabPosition: 'top',
35323 margins:{left:c.west!==false ? 0 : 5,right:c.east!==false ? 0 : 5,bottom:5,top:2}
35327 this.el.addClass('x-reader');
35329 this.beginUpdate();
35331 var inner = new Roo.BorderLayout(Roo.get(document.body).createChild(), {
35332 south: c.preview !== false ? Roo.apply({
35339 cmargins:{top:5,left:0, right:0, bottom:0}
35340 }, c.preview) : false,
35341 center: Roo.apply({
35347 this.add('center', new Roo.NestedLayoutPanel(inner,
35348 Roo.apply({title: c.mainTitle || '',tabTip:''},c.innerPanelCfg)));
35352 this.regions.preview = inner.getRegion('south');
35353 this.regions.listView = inner.getRegion('center');
35356 Roo.extend(Roo.ReaderLayout, Roo.BorderLayout);/*
35358 * Ext JS Library 1.1.1
35359 * Copyright(c) 2006-2007, Ext JS, LLC.
35361 * Originally Released Under LGPL - original licence link has changed is not relivant.
35364 * <script type="text/javascript">
35368 * @class Roo.grid.Grid
35369 * @extends Roo.util.Observable
35370 * This class represents the primary interface of a component based grid control.
35371 * <br><br>Usage:<pre><code>
35372 var grid = new Roo.grid.Grid("my-container-id", {
35375 selModel: mySelectionModel,
35376 autoSizeColumns: true,
35377 monitorWindowResize: false,
35378 trackMouseOver: true
35383 * <b>Common Problems:</b><br/>
35384 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
35385 * element will correct this<br/>
35386 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
35387 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
35388 * are unpredictable.<br/>
35389 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
35390 * grid to calculate dimensions/offsets.<br/>
35392 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
35393 * The container MUST have some type of size defined for the grid to fill. The container will be
35394 * automatically set to position relative if it isn't already.
35395 * @param {Object} config A config object that sets properties on this grid.
35397 Roo.grid.Grid = function(container, config){
35398 // initialize the container
35399 this.container = Roo.get(container);
35400 this.container.update("");
35401 this.container.setStyle("overflow", "hidden");
35402 this.container.addClass('x-grid-container');
35404 this.id = this.container.id;
35406 Roo.apply(this, config);
35407 // check and correct shorthanded configs
35409 this.dataSource = this.ds;
35413 this.colModel = this.cm;
35417 this.selModel = this.sm;
35421 if (this.selModel) {
35422 this.selModel = Roo.factory(this.selModel, Roo.grid);
35423 this.sm = this.selModel;
35424 this.sm.xmodule = this.xmodule || false;
35426 if (typeof(this.colModel.config) == 'undefined') {
35427 this.colModel = new Roo.grid.ColumnModel(this.colModel);
35428 this.cm = this.colModel;
35429 this.cm.xmodule = this.xmodule || false;
35431 if (this.dataSource) {
35432 this.dataSource= Roo.factory(this.dataSource, Roo.data);
35433 this.ds = this.dataSource;
35434 this.ds.xmodule = this.xmodule || false;
35441 this.container.setWidth(this.width);
35445 this.container.setHeight(this.height);
35452 * The raw click event for the entire grid.
35453 * @param {Roo.EventObject} e
35458 * The raw dblclick event for the entire grid.
35459 * @param {Roo.EventObject} e
35463 * @event contextmenu
35464 * The raw contextmenu event for the entire grid.
35465 * @param {Roo.EventObject} e
35467 "contextmenu" : true,
35470 * The raw mousedown event for the entire grid.
35471 * @param {Roo.EventObject} e
35473 "mousedown" : true,
35476 * The raw mouseup event for the entire grid.
35477 * @param {Roo.EventObject} e
35482 * The raw mouseover event for the entire grid.
35483 * @param {Roo.EventObject} e
35485 "mouseover" : true,
35488 * The raw mouseout event for the entire grid.
35489 * @param {Roo.EventObject} e
35494 * The raw keypress event for the entire grid.
35495 * @param {Roo.EventObject} e
35500 * The raw keydown event for the entire grid.
35501 * @param {Roo.EventObject} e
35509 * Fires when a cell is clicked
35510 * @param {Grid} this
35511 * @param {Number} rowIndex
35512 * @param {Number} columnIndex
35513 * @param {Roo.EventObject} e
35515 "cellclick" : true,
35517 * @event celldblclick
35518 * Fires when a cell is double clicked
35519 * @param {Grid} this
35520 * @param {Number} rowIndex
35521 * @param {Number} columnIndex
35522 * @param {Roo.EventObject} e
35524 "celldblclick" : true,
35527 * Fires when a row is clicked
35528 * @param {Grid} this
35529 * @param {Number} rowIndex
35530 * @param {Roo.EventObject} e
35534 * @event rowdblclick
35535 * Fires when a row is double clicked
35536 * @param {Grid} this
35537 * @param {Number} rowIndex
35538 * @param {Roo.EventObject} e
35540 "rowdblclick" : true,
35542 * @event headerclick
35543 * Fires when a header is clicked
35544 * @param {Grid} this
35545 * @param {Number} columnIndex
35546 * @param {Roo.EventObject} e
35548 "headerclick" : true,
35550 * @event headerdblclick
35551 * Fires when a header cell is double clicked
35552 * @param {Grid} this
35553 * @param {Number} columnIndex
35554 * @param {Roo.EventObject} e
35556 "headerdblclick" : true,
35558 * @event rowcontextmenu
35559 * Fires when a row is right clicked
35560 * @param {Grid} this
35561 * @param {Number} rowIndex
35562 * @param {Roo.EventObject} e
35564 "rowcontextmenu" : true,
35566 * @event cellcontextmenu
35567 * Fires when a cell is right clicked
35568 * @param {Grid} this
35569 * @param {Number} rowIndex
35570 * @param {Number} cellIndex
35571 * @param {Roo.EventObject} e
35573 "cellcontextmenu" : true,
35575 * @event headercontextmenu
35576 * Fires when a header is right clicked
35577 * @param {Grid} this
35578 * @param {Number} columnIndex
35579 * @param {Roo.EventObject} e
35581 "headercontextmenu" : true,
35583 * @event bodyscroll
35584 * Fires when the body element is scrolled
35585 * @param {Number} scrollLeft
35586 * @param {Number} scrollTop
35588 "bodyscroll" : true,
35590 * @event columnresize
35591 * Fires when the user resizes a column
35592 * @param {Number} columnIndex
35593 * @param {Number} newSize
35595 "columnresize" : true,
35597 * @event columnmove
35598 * Fires when the user moves a column
35599 * @param {Number} oldIndex
35600 * @param {Number} newIndex
35602 "columnmove" : true,
35605 * Fires when row(s) start being dragged
35606 * @param {Grid} this
35607 * @param {Roo.GridDD} dd The drag drop object
35608 * @param {event} e The raw browser event
35610 "startdrag" : true,
35613 * Fires when a drag operation is complete
35614 * @param {Grid} this
35615 * @param {Roo.GridDD} dd The drag drop object
35616 * @param {event} e The raw browser event
35621 * Fires when dragged row(s) are dropped on a valid DD target
35622 * @param {Grid} this
35623 * @param {Roo.GridDD} dd The drag drop object
35624 * @param {String} targetId The target drag drop object
35625 * @param {event} e The raw browser event
35630 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
35631 * @param {Grid} this
35632 * @param {Roo.GridDD} dd The drag drop object
35633 * @param {String} targetId The target drag drop object
35634 * @param {event} e The raw browser event
35639 * Fires when the dragged row(s) first cross another DD target while being dragged
35640 * @param {Grid} this
35641 * @param {Roo.GridDD} dd The drag drop object
35642 * @param {String} targetId The target drag drop object
35643 * @param {event} e The raw browser event
35645 "dragenter" : true,
35648 * Fires when the dragged row(s) leave another DD target while being dragged
35649 * @param {Grid} this
35650 * @param {Roo.GridDD} dd The drag drop object
35651 * @param {String} targetId The target drag drop object
35652 * @param {event} e The raw browser event
35657 * Fires when a row is rendered, so you can change add a style to it.
35658 * @param {GridView} gridview The grid view
35659 * @param {Object} rowcfg contains record rowIndex and rowClass - set rowClass to add a style.
35665 * Fires when the grid is rendered
35666 * @param {Grid} grid
35671 Roo.grid.Grid.superclass.constructor.call(this);
35673 Roo.extend(Roo.grid.Grid, Roo.util.Observable, {
35676 * @cfg {String} ddGroup - drag drop group.
35680 * @cfg {Number} minColumnWidth The minimum width a column can be resized to. Default is 25.
35682 minColumnWidth : 25,
35685 * @cfg {Boolean} autoSizeColumns True to automatically resize the columns to fit their content
35686 * <b>on initial render.</b> It is more efficient to explicitly size the columns
35687 * through the ColumnModel's {@link Roo.grid.ColumnModel#width} config option. Default is false.
35689 autoSizeColumns : false,
35692 * @cfg {Boolean} autoSizeHeaders True to measure headers with column data when auto sizing columns. Default is true.
35694 autoSizeHeaders : true,
35697 * @cfg {Boolean} monitorWindowResize True to autoSize the grid when the window resizes. Default is true.
35699 monitorWindowResize : true,
35702 * @cfg {Boolean} maxRowsToMeasure If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
35703 * rows measured to get a columns size. Default is 0 (all rows).
35705 maxRowsToMeasure : 0,
35708 * @cfg {Boolean} trackMouseOver True to highlight rows when the mouse is over. Default is true.
35710 trackMouseOver : true,
35713 * @cfg {Boolean} enableDrag True to enable drag of rows. Default is false. (double check if this is needed?)
35717 * @cfg {Boolean} enableDragDrop True to enable drag and drop of rows. Default is false.
35719 enableDragDrop : false,
35722 * @cfg {Boolean} enableColumnMove True to enable drag and drop reorder of columns. Default is true.
35724 enableColumnMove : true,
35727 * @cfg {Boolean} enableColumnHide True to enable hiding of columns with the header context menu. Default is true.
35729 enableColumnHide : true,
35732 * @cfg {Boolean} enableRowHeightSync True to manually sync row heights across locked and not locked rows. Default is false.
35734 enableRowHeightSync : false,
35737 * @cfg {Boolean} stripeRows True to stripe the rows. Default is true.
35742 * @cfg {Boolean} autoHeight True to fit the height of the grid container to the height of the data. Default is false.
35744 autoHeight : false,
35747 * @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.
35749 autoExpandColumn : false,
35752 * @cfg {Number} autoExpandMin The minimum width the autoExpandColumn can have (if enabled).
35755 autoExpandMin : 50,
35758 * @cfg {Number} autoExpandMax The maximum width the autoExpandColumn can have (if enabled). Default is 1000.
35760 autoExpandMax : 1000,
35763 * @cfg {Object} view The {@link Roo.grid.GridView} used by the grid. This can be set before a call to render().
35768 * @cfg {Object} loadMask An {@link Roo.LoadMask} config or true to mask the grid while loading. Default is false.
35772 * @cfg {Roo.dd.DropTarget} dropTarget An {@link Roo.dd.DropTarget} config
35782 * @cfg {Boolean} autoWidth True to set the grid's width to the default total width of the grid's columns instead
35783 * of a fixed width. Default is false.
35786 * @cfg {Number} maxHeight Sets the maximum height of the grid - ignored if autoHeight is not on.
35789 * Called once after all setup has been completed and the grid is ready to be rendered.
35790 * @return {Roo.grid.Grid} this
35792 render : function()
35794 var c = this.container;
35795 // try to detect autoHeight/width mode
35796 if((!c.dom.offsetHeight || c.dom.offsetHeight < 20) || c.getStyle("height") == "auto"){
35797 this.autoHeight = true;
35799 var view = this.getView();
35802 c.on("click", this.onClick, this);
35803 c.on("dblclick", this.onDblClick, this);
35804 c.on("contextmenu", this.onContextMenu, this);
35805 c.on("keydown", this.onKeyDown, this);
35807 c.on("touchstart", this.onTouchStart, this);
35810 this.relayEvents(c, ["mousedown","mouseup","mouseover","mouseout","keypress"]);
35812 this.getSelectionModel().init(this);
35817 this.loadMask = new Roo.LoadMask(this.container,
35818 Roo.apply({store:this.dataSource}, this.loadMask));
35822 if (this.toolbar && this.toolbar.xtype) {
35823 this.toolbar.container = this.getView().getHeaderPanel(true);
35824 this.toolbar = new Roo.Toolbar(this.toolbar);
35826 if (this.footer && this.footer.xtype) {
35827 this.footer.dataSource = this.getDataSource();
35828 this.footer.container = this.getView().getFooterPanel(true);
35829 this.footer = Roo.factory(this.footer, Roo);
35831 if (this.dropTarget && this.dropTarget.xtype) {
35832 delete this.dropTarget.xtype;
35833 this.dropTarget = new Roo.dd.DropTarget(this.getView().mainBody, this.dropTarget);
35837 this.rendered = true;
35838 this.fireEvent('render', this);
35843 * Reconfigures the grid to use a different Store and Column Model.
35844 * The View will be bound to the new objects and refreshed.
35845 * @param {Roo.data.Store} dataSource The new {@link Roo.data.Store} object
35846 * @param {Roo.grid.ColumnModel} The new {@link Roo.grid.ColumnModel} object
35848 reconfigure : function(dataSource, colModel){
35850 this.loadMask.destroy();
35851 this.loadMask = new Roo.LoadMask(this.container,
35852 Roo.apply({store:dataSource}, this.loadMask));
35854 this.view.bind(dataSource, colModel);
35855 this.dataSource = dataSource;
35856 this.colModel = colModel;
35857 this.view.refresh(true);
35861 onKeyDown : function(e){
35862 this.fireEvent("keydown", e);
35866 * Destroy this grid.
35867 * @param {Boolean} removeEl True to remove the element
35869 destroy : function(removeEl, keepListeners){
35871 this.loadMask.destroy();
35873 var c = this.container;
35874 c.removeAllListeners();
35875 this.view.destroy();
35876 this.colModel.purgeListeners();
35877 if(!keepListeners){
35878 this.purgeListeners();
35881 if(removeEl === true){
35887 processEvent : function(name, e){
35888 // does this fire select???
35889 Roo.log('grid:processEvent ' + name);
35891 if (name != 'touchstart' ) {
35892 this.fireEvent(name, e);
35895 var t = e.getTarget();
35897 var header = v.findHeaderIndex(t);
35898 if(header !== false){
35899 this.fireEvent("header" + (name == 'touchstart' ? 'click' : name), this, header, e);
35901 var row = v.findRowIndex(t);
35902 var cell = v.findCellIndex(t);
35903 if (name == 'touchstart') {
35904 // first touch is always a click.
35905 // hopefull this happens after selection is updated.?
35908 if (typeof(this.selModel.getSelectedCell) != 'undefined') {
35909 var cs = this.selModel.getSelectedCell();
35910 if (row == cs[0] && cell == cs[1]){
35914 if (typeof(this.selModel.getSelections) != 'undefined') {
35915 var cs = this.selModel.getSelections();
35916 var ds = this.dataSource;
35917 if (cs.length == 1 && ds.getAt(row) == cs[0]){
35928 this.fireEvent("row" + name, this, row, e);
35929 if(cell !== false){
35930 this.fireEvent("cell" + name, this, row, cell, e);
35937 onClick : function(e){
35938 this.processEvent("click", e);
35941 onTouchStart : function(e){
35942 this.processEvent("touchstart", e);
35946 onContextMenu : function(e, t){
35947 this.processEvent("contextmenu", e);
35951 onDblClick : function(e){
35952 this.processEvent("dblclick", e);
35956 walkCells : function(row, col, step, fn, scope){
35957 var cm = this.colModel, clen = cm.getColumnCount();
35958 var ds = this.dataSource, rlen = ds.getCount(), first = true;
35970 if(fn.call(scope || this, row, col, cm) === true){
35988 if(fn.call(scope || this, row, col, cm) === true){
36000 getSelections : function(){
36001 return this.selModel.getSelections();
36005 * Causes the grid to manually recalculate its dimensions. Generally this is done automatically,
36006 * but if manual update is required this method will initiate it.
36008 autoSize : function(){
36010 this.view.layout();
36011 if(this.view.adjustForScroll){
36012 this.view.adjustForScroll();
36018 * Returns the grid's underlying element.
36019 * @return {Element} The element
36021 getGridEl : function(){
36022 return this.container;
36025 // private for compatibility, overridden by editor grid
36026 stopEditing : function(){},
36029 * Returns the grid's SelectionModel.
36030 * @return {SelectionModel}
36032 getSelectionModel : function(){
36033 if(!this.selModel){
36034 this.selModel = new Roo.grid.RowSelectionModel();
36036 return this.selModel;
36040 * Returns the grid's DataSource.
36041 * @return {DataSource}
36043 getDataSource : function(){
36044 return this.dataSource;
36048 * Returns the grid's ColumnModel.
36049 * @return {ColumnModel}
36051 getColumnModel : function(){
36052 return this.colModel;
36056 * Returns the grid's GridView object.
36057 * @return {GridView}
36059 getView : function(){
36061 this.view = new Roo.grid.GridView(this.viewConfig);
36066 * Called to get grid's drag proxy text, by default returns this.ddText.
36069 getDragDropText : function(){
36070 var count = this.selModel.getCount();
36071 return String.format(this.ddText, count, count == 1 ? '' : 's');
36075 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
36076 * %0 is replaced with the number of selected rows.
36079 Roo.grid.Grid.prototype.ddText = "{0} selected row{1}";/*
36081 * Ext JS Library 1.1.1
36082 * Copyright(c) 2006-2007, Ext JS, LLC.
36084 * Originally Released Under LGPL - original licence link has changed is not relivant.
36087 * <script type="text/javascript">
36090 Roo.grid.AbstractGridView = function(){
36094 "beforerowremoved" : true,
36095 "beforerowsinserted" : true,
36096 "beforerefresh" : true,
36097 "rowremoved" : true,
36098 "rowsinserted" : true,
36099 "rowupdated" : true,
36102 Roo.grid.AbstractGridView.superclass.constructor.call(this);
36105 Roo.extend(Roo.grid.AbstractGridView, Roo.util.Observable, {
36106 rowClass : "x-grid-row",
36107 cellClass : "x-grid-cell",
36108 tdClass : "x-grid-td",
36109 hdClass : "x-grid-hd",
36110 splitClass : "x-grid-hd-split",
36112 init: function(grid){
36114 var cid = this.grid.getGridEl().id;
36115 this.colSelector = "#" + cid + " ." + this.cellClass + "-";
36116 this.tdSelector = "#" + cid + " ." + this.tdClass + "-";
36117 this.hdSelector = "#" + cid + " ." + this.hdClass + "-";
36118 this.splitSelector = "#" + cid + " ." + this.splitClass + "-";
36121 getColumnRenderers : function(){
36122 var renderers = [];
36123 var cm = this.grid.colModel;
36124 var colCount = cm.getColumnCount();
36125 for(var i = 0; i < colCount; i++){
36126 renderers[i] = cm.getRenderer(i);
36131 getColumnIds : function(){
36133 var cm = this.grid.colModel;
36134 var colCount = cm.getColumnCount();
36135 for(var i = 0; i < colCount; i++){
36136 ids[i] = cm.getColumnId(i);
36141 getDataIndexes : function(){
36142 if(!this.indexMap){
36143 this.indexMap = this.buildIndexMap();
36145 return this.indexMap.colToData;
36148 getColumnIndexByDataIndex : function(dataIndex){
36149 if(!this.indexMap){
36150 this.indexMap = this.buildIndexMap();
36152 return this.indexMap.dataToCol[dataIndex];
36156 * Set a css style for a column dynamically.
36157 * @param {Number} colIndex The index of the column
36158 * @param {String} name The css property name
36159 * @param {String} value The css value
36161 setCSSStyle : function(colIndex, name, value){
36162 var selector = "#" + this.grid.id + " .x-grid-col-" + colIndex;
36163 Roo.util.CSS.updateRule(selector, name, value);
36166 generateRules : function(cm){
36167 var ruleBuf = [], rulesId = this.grid.id + '-cssrules';
36168 Roo.util.CSS.removeStyleSheet(rulesId);
36169 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36170 var cid = cm.getColumnId(i);
36171 ruleBuf.push(this.colSelector, cid, " {\n", cm.config[i].css, "}\n",
36172 this.tdSelector, cid, " {\n}\n",
36173 this.hdSelector, cid, " {\n}\n",
36174 this.splitSelector, cid, " {\n}\n");
36176 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
36180 * Ext JS Library 1.1.1
36181 * Copyright(c) 2006-2007, Ext JS, LLC.
36183 * Originally Released Under LGPL - original licence link has changed is not relivant.
36186 * <script type="text/javascript">
36190 // This is a support class used internally by the Grid components
36191 Roo.grid.HeaderDragZone = function(grid, hd, hd2){
36193 this.view = grid.getView();
36194 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36195 Roo.grid.HeaderDragZone.superclass.constructor.call(this, hd);
36197 this.setHandleElId(Roo.id(hd));
36198 this.setOuterHandleElId(Roo.id(hd2));
36200 this.scroll = false;
36202 Roo.extend(Roo.grid.HeaderDragZone, Roo.dd.DragZone, {
36204 getDragData : function(e){
36205 var t = Roo.lib.Event.getTarget(e);
36206 var h = this.view.findHeaderCell(t);
36208 return {ddel: h.firstChild, header:h};
36213 onInitDrag : function(e){
36214 this.view.headersDisabled = true;
36215 var clone = this.dragData.ddel.cloneNode(true);
36216 clone.id = Roo.id();
36217 clone.style.width = Math.min(this.dragData.header.offsetWidth,this.maxDragWidth) + "px";
36218 this.proxy.update(clone);
36222 afterValidDrop : function(){
36224 setTimeout(function(){
36225 v.headersDisabled = false;
36229 afterInvalidDrop : function(){
36231 setTimeout(function(){
36232 v.headersDisabled = false;
36238 * Ext JS Library 1.1.1
36239 * Copyright(c) 2006-2007, Ext JS, LLC.
36241 * Originally Released Under LGPL - original licence link has changed is not relivant.
36244 * <script type="text/javascript">
36247 // This is a support class used internally by the Grid components
36248 Roo.grid.HeaderDropZone = function(grid, hd, hd2){
36250 this.view = grid.getView();
36251 // split the proxies so they don't interfere with mouse events
36252 this.proxyTop = Roo.DomHelper.append(document.body, {
36253 cls:"col-move-top", html:" "
36255 this.proxyBottom = Roo.DomHelper.append(document.body, {
36256 cls:"col-move-bottom", html:" "
36258 this.proxyTop.hide = this.proxyBottom.hide = function(){
36259 this.setLeftTop(-100,-100);
36260 this.setStyle("visibility", "hidden");
36262 this.ddGroup = "gridHeader" + this.grid.getGridEl().id;
36263 // temporarily disabled
36264 //Roo.dd.ScrollManager.register(this.view.scroller.dom);
36265 Roo.grid.HeaderDropZone.superclass.constructor.call(this, grid.getGridEl().dom);
36267 Roo.extend(Roo.grid.HeaderDropZone, Roo.dd.DropZone, {
36268 proxyOffsets : [-4, -9],
36269 fly: Roo.Element.fly,
36271 getTargetFromEvent : function(e){
36272 var t = Roo.lib.Event.getTarget(e);
36273 var cindex = this.view.findCellIndex(t);
36274 if(cindex !== false){
36275 return this.view.getHeaderCell(cindex);
36280 nextVisible : function(h){
36281 var v = this.view, cm = this.grid.colModel;
36284 if(!cm.isHidden(v.getCellIndex(h))){
36292 prevVisible : function(h){
36293 var v = this.view, cm = this.grid.colModel;
36296 if(!cm.isHidden(v.getCellIndex(h))){
36304 positionIndicator : function(h, n, e){
36305 var x = Roo.lib.Event.getPageX(e);
36306 var r = Roo.lib.Dom.getRegion(n.firstChild);
36307 var px, pt, py = r.top + this.proxyOffsets[1];
36308 if((r.right - x) <= (r.right-r.left)/2){
36309 px = r.right+this.view.borderWidth;
36315 var oldIndex = this.view.getCellIndex(h);
36316 var newIndex = this.view.getCellIndex(n);
36318 if(this.grid.colModel.isFixed(newIndex)){
36322 var locked = this.grid.colModel.isLocked(newIndex);
36327 if(oldIndex < newIndex){
36330 if(oldIndex == newIndex && (locked == this.grid.colModel.isLocked(oldIndex))){
36333 px += this.proxyOffsets[0];
36334 this.proxyTop.setLeftTop(px, py);
36335 this.proxyTop.show();
36336 if(!this.bottomOffset){
36337 this.bottomOffset = this.view.mainHd.getHeight();
36339 this.proxyBottom.setLeftTop(px, py+this.proxyTop.dom.offsetHeight+this.bottomOffset);
36340 this.proxyBottom.show();
36344 onNodeEnter : function(n, dd, e, data){
36345 if(data.header != n){
36346 this.positionIndicator(data.header, n, e);
36350 onNodeOver : function(n, dd, e, data){
36351 var result = false;
36352 if(data.header != n){
36353 result = this.positionIndicator(data.header, n, e);
36356 this.proxyTop.hide();
36357 this.proxyBottom.hide();
36359 return result ? this.dropAllowed : this.dropNotAllowed;
36362 onNodeOut : function(n, dd, e, data){
36363 this.proxyTop.hide();
36364 this.proxyBottom.hide();
36367 onNodeDrop : function(n, dd, e, data){
36368 var h = data.header;
36370 var cm = this.grid.colModel;
36371 var x = Roo.lib.Event.getPageX(e);
36372 var r = Roo.lib.Dom.getRegion(n.firstChild);
36373 var pt = (r.right - x) <= ((r.right-r.left)/2) ? "after" : "before";
36374 var oldIndex = this.view.getCellIndex(h);
36375 var newIndex = this.view.getCellIndex(n);
36376 var locked = cm.isLocked(newIndex);
36380 if(oldIndex < newIndex){
36383 if(oldIndex == newIndex && (locked == cm.isLocked(oldIndex))){
36386 cm.setLocked(oldIndex, locked, true);
36387 cm.moveColumn(oldIndex, newIndex);
36388 this.grid.fireEvent("columnmove", oldIndex, newIndex);
36396 * Ext JS Library 1.1.1
36397 * Copyright(c) 2006-2007, Ext JS, LLC.
36399 * Originally Released Under LGPL - original licence link has changed is not relivant.
36402 * <script type="text/javascript">
36406 * @class Roo.grid.GridView
36407 * @extends Roo.util.Observable
36410 * @param {Object} config
36412 Roo.grid.GridView = function(config){
36413 Roo.grid.GridView.superclass.constructor.call(this);
36416 Roo.apply(this, config);
36419 Roo.extend(Roo.grid.GridView, Roo.grid.AbstractGridView, {
36421 unselectable : 'unselectable="on"',
36422 unselectableCls : 'x-unselectable',
36425 rowClass : "x-grid-row",
36427 cellClass : "x-grid-col",
36429 tdClass : "x-grid-td",
36431 hdClass : "x-grid-hd",
36433 splitClass : "x-grid-split",
36435 sortClasses : ["sort-asc", "sort-desc"],
36437 enableMoveAnim : false,
36441 dh : Roo.DomHelper,
36443 fly : Roo.Element.fly,
36445 css : Roo.util.CSS,
36451 scrollIncrement : 22,
36453 cellRE: /(?:.*?)x-grid-(?:hd|cell|csplit)-(?:[\d]+)-([\d]+)(?:.*?)/,
36455 findRE: /\s?(?:x-grid-hd|x-grid-col|x-grid-csplit)\s/,
36457 bind : function(ds, cm){
36459 this.ds.un("load", this.onLoad, this);
36460 this.ds.un("datachanged", this.onDataChange, this);
36461 this.ds.un("add", this.onAdd, this);
36462 this.ds.un("remove", this.onRemove, this);
36463 this.ds.un("update", this.onUpdate, this);
36464 this.ds.un("clear", this.onClear, this);
36467 ds.on("load", this.onLoad, this);
36468 ds.on("datachanged", this.onDataChange, this);
36469 ds.on("add", this.onAdd, this);
36470 ds.on("remove", this.onRemove, this);
36471 ds.on("update", this.onUpdate, this);
36472 ds.on("clear", this.onClear, this);
36477 this.cm.un("widthchange", this.onColWidthChange, this);
36478 this.cm.un("headerchange", this.onHeaderChange, this);
36479 this.cm.un("hiddenchange", this.onHiddenChange, this);
36480 this.cm.un("columnmoved", this.onColumnMove, this);
36481 this.cm.un("columnlockchange", this.onColumnLock, this);
36484 this.generateRules(cm);
36485 cm.on("widthchange", this.onColWidthChange, this);
36486 cm.on("headerchange", this.onHeaderChange, this);
36487 cm.on("hiddenchange", this.onHiddenChange, this);
36488 cm.on("columnmoved", this.onColumnMove, this);
36489 cm.on("columnlockchange", this.onColumnLock, this);
36494 init: function(grid){
36495 Roo.grid.GridView.superclass.init.call(this, grid);
36497 this.bind(grid.dataSource, grid.colModel);
36499 grid.on("headerclick", this.handleHeaderClick, this);
36501 if(grid.trackMouseOver){
36502 grid.on("mouseover", this.onRowOver, this);
36503 grid.on("mouseout", this.onRowOut, this);
36505 grid.cancelTextSelection = function(){};
36506 this.gridId = grid.id;
36508 var tpls = this.templates || {};
36511 tpls.master = new Roo.Template(
36512 '<div class="x-grid" hidefocus="true">',
36513 '<a href="#" class="x-grid-focus" tabIndex="-1"></a>',
36514 '<div class="x-grid-topbar"></div>',
36515 '<div class="x-grid-scroller"><div></div></div>',
36516 '<div class="x-grid-locked">',
36517 '<div class="x-grid-header">{lockedHeader}</div>',
36518 '<div class="x-grid-body">{lockedBody}</div>',
36520 '<div class="x-grid-viewport">',
36521 '<div class="x-grid-header">{header}</div>',
36522 '<div class="x-grid-body">{body}</div>',
36524 '<div class="x-grid-bottombar"></div>',
36526 '<div class="x-grid-resize-proxy"> </div>',
36529 tpls.master.disableformats = true;
36533 tpls.header = new Roo.Template(
36534 '<table border="0" cellspacing="0" cellpadding="0">',
36535 '<tbody><tr class="x-grid-hd-row">{cells}</tr></tbody>',
36538 tpls.header.disableformats = true;
36540 tpls.header.compile();
36543 tpls.hcell = new Roo.Template(
36544 '<td class="x-grid-hd x-grid-td-{id} {cellId}"><div title="{title}" class="x-grid-hd-inner x-grid-hd-{id}">',
36545 '<div class="x-grid-hd-text ' + this.unselectableCls + '" ' + this.unselectable +'>{value}<img class="x-grid-sort-icon" src="', Roo.BLANK_IMAGE_URL, '" /></div>',
36548 tpls.hcell.disableFormats = true;
36550 tpls.hcell.compile();
36553 tpls.hsplit = new Roo.Template('<div class="x-grid-split {splitId} x-grid-split-{id}" style="{style} ' +
36554 this.unselectableCls + '" ' + this.unselectable +'> </div>');
36555 tpls.hsplit.disableFormats = true;
36557 tpls.hsplit.compile();
36560 tpls.body = new Roo.Template(
36561 '<table border="0" cellspacing="0" cellpadding="0">',
36562 "<tbody>{rows}</tbody>",
36565 tpls.body.disableFormats = true;
36567 tpls.body.compile();
36570 tpls.row = new Roo.Template('<tr class="x-grid-row {alt}">{cells}</tr>');
36571 tpls.row.disableFormats = true;
36573 tpls.row.compile();
36576 tpls.cell = new Roo.Template(
36577 '<td class="x-grid-col x-grid-td-{id} {cellId} {css}" tabIndex="0">',
36578 '<div class="x-grid-col-{id} x-grid-cell-inner"><div class="x-grid-cell-text ' +
36579 this.unselectableCls + '" ' + this.unselectable +'" {attr}>{value}</div></div>',
36582 tpls.cell.disableFormats = true;
36584 tpls.cell.compile();
36586 this.templates = tpls;
36589 // remap these for backwards compat
36590 onColWidthChange : function(){
36591 this.updateColumns.apply(this, arguments);
36593 onHeaderChange : function(){
36594 this.updateHeaders.apply(this, arguments);
36596 onHiddenChange : function(){
36597 this.handleHiddenChange.apply(this, arguments);
36599 onColumnMove : function(){
36600 this.handleColumnMove.apply(this, arguments);
36602 onColumnLock : function(){
36603 this.handleLockChange.apply(this, arguments);
36606 onDataChange : function(){
36608 this.updateHeaderSortState();
36611 onClear : function(){
36615 onUpdate : function(ds, record){
36616 this.refreshRow(record);
36619 refreshRow : function(record){
36620 var ds = this.ds, index;
36621 if(typeof record == 'number'){
36623 record = ds.getAt(index);
36625 index = ds.indexOf(record);
36627 this.insertRows(ds, index, index, true);
36628 this.onRemove(ds, record, index+1, true);
36629 this.syncRowHeights(index, index);
36631 this.fireEvent("rowupdated", this, index, record);
36634 onAdd : function(ds, records, index){
36635 this.insertRows(ds, index, index + (records.length-1));
36638 onRemove : function(ds, record, index, isUpdate){
36639 if(isUpdate !== true){
36640 this.fireEvent("beforerowremoved", this, index, record);
36642 var bt = this.getBodyTable(), lt = this.getLockedTable();
36643 if(bt.rows[index]){
36644 bt.firstChild.removeChild(bt.rows[index]);
36646 if(lt.rows[index]){
36647 lt.firstChild.removeChild(lt.rows[index]);
36649 if(isUpdate !== true){
36650 this.stripeRows(index);
36651 this.syncRowHeights(index, index);
36653 this.fireEvent("rowremoved", this, index, record);
36657 onLoad : function(){
36658 this.scrollToTop();
36662 * Scrolls the grid to the top
36664 scrollToTop : function(){
36666 this.scroller.dom.scrollTop = 0;
36672 * Gets a panel in the header of the grid that can be used for toolbars etc.
36673 * After modifying the contents of this panel a call to grid.autoSize() may be
36674 * required to register any changes in size.
36675 * @param {Boolean} doShow By default the header is hidden. Pass true to show the panel
36676 * @return Roo.Element
36678 getHeaderPanel : function(doShow){
36680 this.headerPanel.show();
36682 return this.headerPanel;
36686 * Gets a panel in the footer of the grid that can be used for toolbars etc.
36687 * After modifying the contents of this panel a call to grid.autoSize() may be
36688 * required to register any changes in size.
36689 * @param {Boolean} doShow By default the footer is hidden. Pass true to show the panel
36690 * @return Roo.Element
36692 getFooterPanel : function(doShow){
36694 this.footerPanel.show();
36696 return this.footerPanel;
36699 initElements : function(){
36700 var E = Roo.Element;
36701 var el = this.grid.getGridEl().dom.firstChild;
36702 var cs = el.childNodes;
36704 this.el = new E(el);
36706 this.focusEl = new E(el.firstChild);
36707 this.focusEl.swallowEvent("click", true);
36709 this.headerPanel = new E(cs[1]);
36710 this.headerPanel.enableDisplayMode("block");
36712 this.scroller = new E(cs[2]);
36713 this.scrollSizer = new E(this.scroller.dom.firstChild);
36715 this.lockedWrap = new E(cs[3]);
36716 this.lockedHd = new E(this.lockedWrap.dom.firstChild);
36717 this.lockedBody = new E(this.lockedWrap.dom.childNodes[1]);
36719 this.mainWrap = new E(cs[4]);
36720 this.mainHd = new E(this.mainWrap.dom.firstChild);
36721 this.mainBody = new E(this.mainWrap.dom.childNodes[1]);
36723 this.footerPanel = new E(cs[5]);
36724 this.footerPanel.enableDisplayMode("block");
36726 this.resizeProxy = new E(cs[6]);
36728 this.headerSelector = String.format(
36729 '#{0} td.x-grid-hd, #{1} td.x-grid-hd',
36730 this.lockedHd.id, this.mainHd.id
36733 this.splitterSelector = String.format(
36734 '#{0} div.x-grid-split, #{1} div.x-grid-split',
36735 this.idToCssName(this.lockedHd.id), this.idToCssName(this.mainHd.id)
36738 idToCssName : function(s)
36740 return s.replace(/[^a-z0-9]+/ig, '-');
36743 getHeaderCell : function(index){
36744 return Roo.DomQuery.select(this.headerSelector)[index];
36747 getHeaderCellMeasure : function(index){
36748 return this.getHeaderCell(index).firstChild;
36751 getHeaderCellText : function(index){
36752 return this.getHeaderCell(index).firstChild.firstChild;
36755 getLockedTable : function(){
36756 return this.lockedBody.dom.firstChild;
36759 getBodyTable : function(){
36760 return this.mainBody.dom.firstChild;
36763 getLockedRow : function(index){
36764 return this.getLockedTable().rows[index];
36767 getRow : function(index){
36768 return this.getBodyTable().rows[index];
36771 getRowComposite : function(index){
36773 this.rowEl = new Roo.CompositeElementLite();
36775 var els = [], lrow, mrow;
36776 if(lrow = this.getLockedRow(index)){
36779 if(mrow = this.getRow(index)){
36782 this.rowEl.elements = els;
36786 * Gets the 'td' of the cell
36788 * @param {Integer} rowIndex row to select
36789 * @param {Integer} colIndex column to select
36793 getCell : function(rowIndex, colIndex){
36794 var locked = this.cm.getLockedCount();
36796 if(colIndex < locked){
36797 source = this.lockedBody.dom.firstChild;
36799 source = this.mainBody.dom.firstChild;
36800 colIndex -= locked;
36802 return source.rows[rowIndex].childNodes[colIndex];
36805 getCellText : function(rowIndex, colIndex){
36806 return this.getCell(rowIndex, colIndex).firstChild.firstChild;
36809 getCellBox : function(cell){
36810 var b = this.fly(cell).getBox();
36811 if(Roo.isOpera){ // opera fails to report the Y
36812 b.y = cell.offsetTop + this.mainBody.getY();
36817 getCellIndex : function(cell){
36818 var id = String(cell.className).match(this.cellRE);
36820 return parseInt(id[1], 10);
36825 findHeaderIndex : function(n){
36826 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36827 return r ? this.getCellIndex(r) : false;
36830 findHeaderCell : function(n){
36831 var r = Roo.fly(n).findParent("td." + this.hdClass, 6);
36832 return r ? r : false;
36835 findRowIndex : function(n){
36839 var r = Roo.fly(n).findParent("tr." + this.rowClass, 6);
36840 return r ? r.rowIndex : false;
36843 findCellIndex : function(node){
36844 var stop = this.el.dom;
36845 while(node && node != stop){
36846 if(this.findRE.test(node.className)){
36847 return this.getCellIndex(node);
36849 node = node.parentNode;
36854 getColumnId : function(index){
36855 return this.cm.getColumnId(index);
36858 getSplitters : function()
36860 if(this.splitterSelector){
36861 return Roo.DomQuery.select(this.splitterSelector);
36867 getSplitter : function(index){
36868 return this.getSplitters()[index];
36871 onRowOver : function(e, t){
36873 if((row = this.findRowIndex(t)) !== false){
36874 this.getRowComposite(row).addClass("x-grid-row-over");
36878 onRowOut : function(e, t){
36880 if((row = this.findRowIndex(t)) !== false && row !== this.findRowIndex(e.getRelatedTarget())){
36881 this.getRowComposite(row).removeClass("x-grid-row-over");
36885 renderHeaders : function(){
36887 var ct = this.templates.hcell, ht = this.templates.header, st = this.templates.hsplit;
36888 var cb = [], lb = [], sb = [], lsb = [], p = {};
36889 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
36890 p.cellId = "x-grid-hd-0-" + i;
36891 p.splitId = "x-grid-csplit-0-" + i;
36892 p.id = cm.getColumnId(i);
36893 p.title = cm.getColumnTooltip(i) || "";
36894 p.value = cm.getColumnHeader(i) || "";
36895 p.style = (this.grid.enableColumnResize === false || !cm.isResizable(i) || cm.isFixed(i)) ? 'cursor:default' : '';
36896 if(!cm.isLocked(i)){
36897 cb[cb.length] = ct.apply(p);
36898 sb[sb.length] = st.apply(p);
36900 lb[lb.length] = ct.apply(p);
36901 lsb[lsb.length] = st.apply(p);
36904 return [ht.apply({cells: lb.join(""), splits:lsb.join("")}),
36905 ht.apply({cells: cb.join(""), splits:sb.join("")})];
36908 updateHeaders : function(){
36909 var html = this.renderHeaders();
36910 this.lockedHd.update(html[0]);
36911 this.mainHd.update(html[1]);
36915 * Focuses the specified row.
36916 * @param {Number} row The row index
36918 focusRow : function(row)
36920 //Roo.log('GridView.focusRow');
36921 var x = this.scroller.dom.scrollLeft;
36922 this.focusCell(row, 0, false);
36923 this.scroller.dom.scrollLeft = x;
36927 * Focuses the specified cell.
36928 * @param {Number} row The row index
36929 * @param {Number} col The column index
36930 * @param {Boolean} hscroll false to disable horizontal scrolling
36932 focusCell : function(row, col, hscroll)
36934 //Roo.log('GridView.focusCell');
36935 var el = this.ensureVisible(row, col, hscroll);
36936 this.focusEl.alignTo(el, "tl-tl");
36938 this.focusEl.focus();
36940 this.focusEl.focus.defer(1, this.focusEl);
36945 * Scrolls the specified cell into view
36946 * @param {Number} row The row index
36947 * @param {Number} col The column index
36948 * @param {Boolean} hscroll false to disable horizontal scrolling
36950 ensureVisible : function(row, col, hscroll)
36952 //Roo.log('GridView.ensureVisible,' + row + ',' + col);
36953 //return null; //disable for testing.
36954 if(typeof row != "number"){
36955 row = row.rowIndex;
36957 if(row < 0 && row >= this.ds.getCount()){
36960 col = (col !== undefined ? col : 0);
36961 var cm = this.grid.colModel;
36962 while(cm.isHidden(col)){
36966 var el = this.getCell(row, col);
36970 var c = this.scroller.dom;
36972 var ctop = parseInt(el.offsetTop, 10);
36973 var cleft = parseInt(el.offsetLeft, 10);
36974 var cbot = ctop + el.offsetHeight;
36975 var cright = cleft + el.offsetWidth;
36977 var ch = c.clientHeight - this.mainHd.dom.offsetHeight;
36978 var stop = parseInt(c.scrollTop, 10);
36979 var sleft = parseInt(c.scrollLeft, 10);
36980 var sbot = stop + ch;
36981 var sright = sleft + c.clientWidth;
36983 Roo.log('GridView.ensureVisible:' +
36985 ' c.clientHeight:' + c.clientHeight +
36986 ' this.mainHd.dom.offsetHeight:' + this.mainHd.dom.offsetHeight +
36994 c.scrollTop = ctop;
36995 //Roo.log("set scrolltop to ctop DISABLE?");
36996 }else if(cbot > sbot){
36997 //Roo.log("set scrolltop to cbot-ch");
36998 c.scrollTop = cbot-ch;
37001 if(hscroll !== false){
37003 c.scrollLeft = cleft;
37004 }else if(cright > sright){
37005 c.scrollLeft = cright-c.clientWidth;
37012 updateColumns : function(){
37013 this.grid.stopEditing();
37014 var cm = this.grid.colModel, colIds = this.getColumnIds();
37015 //var totalWidth = cm.getTotalWidth();
37017 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37018 //if(cm.isHidden(i)) continue;
37019 var w = cm.getColumnWidth(i);
37020 this.css.updateRule(this.colSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37021 this.css.updateRule(this.hdSelector+this.idToCssName(colIds[i]), "width", (w - this.borderWidth) + "px");
37023 this.updateSplitters();
37026 generateRules : function(cm){
37027 var ruleBuf = [], rulesId = this.idToCssName(this.grid.id)+ '-cssrules';
37028 Roo.util.CSS.removeStyleSheet(rulesId);
37029 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37030 var cid = cm.getColumnId(i);
37032 if(cm.config[i].align){
37033 align = 'text-align:'+cm.config[i].align+';';
37036 if(cm.isHidden(i)){
37037 hidden = 'display:none;';
37039 var width = "width:" + (cm.getColumnWidth(i) - this.borderWidth) + "px;";
37041 this.colSelector, cid, " {\n", cm.config[i].css, align, width, "\n}\n",
37042 this.hdSelector, cid, " {\n", align, width, "}\n",
37043 this.tdSelector, cid, " {\n",hidden,"\n}\n",
37044 this.splitSelector, cid, " {\n", hidden , "\n}\n");
37046 return Roo.util.CSS.createStyleSheet(ruleBuf.join(""), rulesId);
37049 updateSplitters : function(){
37050 var cm = this.cm, s = this.getSplitters();
37051 if(s){ // splitters not created yet
37052 var pos = 0, locked = true;
37053 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
37054 if(cm.isHidden(i)) continue;
37055 var w = cm.getColumnWidth(i); // make sure it's a number
37056 if(!cm.isLocked(i) && locked){
37061 s[i].style.left = (pos-this.splitOffset) + "px";
37066 handleHiddenChange : function(colModel, colIndex, hidden){
37068 this.hideColumn(colIndex);
37070 this.unhideColumn(colIndex);
37074 hideColumn : function(colIndex){
37075 var cid = this.getColumnId(colIndex);
37076 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "none");
37077 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "none");
37079 this.updateHeaders();
37081 this.updateSplitters();
37085 unhideColumn : function(colIndex){
37086 var cid = this.getColumnId(colIndex);
37087 this.css.updateRule(this.tdSelector+this.idToCssName(cid), "display", "");
37088 this.css.updateRule(this.splitSelector+this.idToCssName(cid), "display", "");
37091 this.updateHeaders();
37093 this.updateSplitters();
37097 insertRows : function(dm, firstRow, lastRow, isUpdate){
37098 if(firstRow == 0 && lastRow == dm.getCount()-1){
37102 this.fireEvent("beforerowsinserted", this, firstRow, lastRow);
37104 var s = this.getScrollState();
37105 var markup = this.renderRows(firstRow, lastRow);
37106 this.bufferRows(markup[0], this.getLockedTable(), firstRow);
37107 this.bufferRows(markup[1], this.getBodyTable(), firstRow);
37108 this.restoreScroll(s);
37110 this.fireEvent("rowsinserted", this, firstRow, lastRow);
37111 this.syncRowHeights(firstRow, lastRow);
37112 this.stripeRows(firstRow);
37118 bufferRows : function(markup, target, index){
37119 var before = null, trows = target.rows, tbody = target.tBodies[0];
37120 if(index < trows.length){
37121 before = trows[index];
37123 var b = document.createElement("div");
37124 b.innerHTML = "<table><tbody>"+markup+"</tbody></table>";
37125 var rows = b.firstChild.rows;
37126 for(var i = 0, len = rows.length; i < len; i++){
37128 tbody.insertBefore(rows[0], before);
37130 tbody.appendChild(rows[0]);
37137 deleteRows : function(dm, firstRow, lastRow){
37138 if(dm.getRowCount()<1){
37139 this.fireEvent("beforerefresh", this);
37140 this.mainBody.update("");
37141 this.lockedBody.update("");
37142 this.fireEvent("refresh", this);
37144 this.fireEvent("beforerowsdeleted", this, firstRow, lastRow);
37145 var bt = this.getBodyTable();
37146 var tbody = bt.firstChild;
37147 var rows = bt.rows;
37148 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
37149 tbody.removeChild(rows[firstRow]);
37151 this.stripeRows(firstRow);
37152 this.fireEvent("rowsdeleted", this, firstRow, lastRow);
37156 updateRows : function(dataSource, firstRow, lastRow){
37157 var s = this.getScrollState();
37159 this.restoreScroll(s);
37162 handleSort : function(dataSource, sortColumnIndex, sortDir, noRefresh){
37166 this.updateHeaderSortState();
37169 getScrollState : function(){
37171 var sb = this.scroller.dom;
37172 return {left: sb.scrollLeft, top: sb.scrollTop};
37175 stripeRows : function(startRow){
37176 if(!this.grid.stripeRows || this.ds.getCount() < 1){
37179 startRow = startRow || 0;
37180 var rows = this.getBodyTable().rows;
37181 var lrows = this.getLockedTable().rows;
37182 var cls = ' x-grid-row-alt ';
37183 for(var i = startRow, len = rows.length; i < len; i++){
37184 var row = rows[i], lrow = lrows[i];
37185 var isAlt = ((i+1) % 2 == 0);
37186 var hasAlt = (' '+row.className + ' ').indexOf(cls) != -1;
37187 if(isAlt == hasAlt){
37191 row.className += " x-grid-row-alt";
37193 row.className = row.className.replace("x-grid-row-alt", "");
37196 lrow.className = row.className;
37201 restoreScroll : function(state){
37202 //Roo.log('GridView.restoreScroll');
37203 var sb = this.scroller.dom;
37204 sb.scrollLeft = state.left;
37205 sb.scrollTop = state.top;
37209 syncScroll : function(){
37210 //Roo.log('GridView.syncScroll');
37211 var sb = this.scroller.dom;
37212 var sh = this.mainHd.dom;
37213 var bs = this.mainBody.dom;
37214 var lv = this.lockedBody.dom;
37215 sh.scrollLeft = bs.scrollLeft = sb.scrollLeft;
37216 lv.scrollTop = bs.scrollTop = sb.scrollTop;
37219 handleScroll : function(e){
37221 var sb = this.scroller.dom;
37222 this.grid.fireEvent("bodyscroll", sb.scrollLeft, sb.scrollTop);
37226 handleWheel : function(e){
37227 var d = e.getWheelDelta();
37228 this.scroller.dom.scrollTop -= d*22;
37229 // set this here to prevent jumpy scrolling on large tables
37230 this.lockedBody.dom.scrollTop = this.mainBody.dom.scrollTop = this.scroller.dom.scrollTop;
37234 renderRows : function(startRow, endRow){
37235 // pull in all the crap needed to render rows
37236 var g = this.grid, cm = g.colModel, ds = g.dataSource, stripe = g.stripeRows;
37237 var colCount = cm.getColumnCount();
37239 if(ds.getCount() < 1){
37243 // build a map for all the columns
37245 for(var i = 0; i < colCount; i++){
37246 var name = cm.getDataIndex(i);
37248 name : typeof name == 'undefined' ? ds.fields.get(i).name : name,
37249 renderer : cm.getRenderer(i),
37250 id : cm.getColumnId(i),
37251 locked : cm.isLocked(i)
37255 startRow = startRow || 0;
37256 endRow = typeof endRow == "undefined"? ds.getCount()-1 : endRow;
37258 // records to render
37259 var rs = ds.getRange(startRow, endRow);
37261 return this.doRender(cs, rs, ds, startRow, colCount, stripe);
37264 // As much as I hate to duplicate code, this was branched because FireFox really hates
37265 // [].join("") on strings. The performance difference was substantial enough to
37266 // branch this function
37267 doRender : Roo.isGecko ?
37268 function(cs, rs, ds, startRow, colCount, stripe){
37269 var ts = this.templates, ct = ts.cell, rt = ts.row;
37271 var buf = "", lbuf = "", cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37273 var hasListener = this.grid.hasListener('rowclass');
37275 for(var j = 0, len = rs.length; j < len; j++){
37276 r = rs[j]; cb = ""; lcb = ""; rowIndex = (j+startRow);
37277 for(var i = 0; i < colCount; i++){
37279 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37281 p.css = p.attr = "";
37282 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37283 if(p.value == undefined || p.value === "") p.value = " ";
37284 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37285 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37287 var markup = ct.apply(p);
37295 if(stripe && ((rowIndex+1) % 2 == 0)){
37296 alt.push("x-grid-row-alt")
37299 alt.push( " x-grid-dirty-row");
37302 if(this.getRowClass){
37303 alt.push(this.getRowClass(r, rowIndex));
37309 rowIndex : rowIndex,
37312 this.grid.fireEvent('rowclass', this, rowcfg);
37313 alt.push(rowcfg.rowClass);
37315 rp.alt = alt.join(" ");
37316 lbuf+= rt.apply(rp);
37318 buf+= rt.apply(rp);
37320 return [lbuf, buf];
37322 function(cs, rs, ds, startRow, colCount, stripe){
37323 var ts = this.templates, ct = ts.cell, rt = ts.row;
37325 var buf = [], lbuf = [], cb, lcb, c, p = {}, rp = {}, r, rowIndex;
37326 var hasListener = this.grid.hasListener('rowclass');
37329 for(var j = 0, len = rs.length; j < len; j++){
37330 r = rs[j]; cb = []; lcb = []; rowIndex = (j+startRow);
37331 for(var i = 0; i < colCount; i++){
37333 p.cellId = "x-grid-cell-" + rowIndex + "-" + i;
37335 p.css = p.attr = "";
37336 p.value = c.renderer(r.data[c.name], p, r, rowIndex, i, ds);
37337 if(p.value == undefined || p.value === "") p.value = " ";
37338 if(r.dirty && typeof r.modified[c.name] !== 'undefined'){
37339 p.css += p.css ? ' x-grid-dirty-cell' : 'x-grid-dirty-cell';
37342 var markup = ct.apply(p);
37344 cb[cb.length] = markup;
37346 lcb[lcb.length] = markup;
37350 if(stripe && ((rowIndex+1) % 2 == 0)){
37351 alt.push( "x-grid-row-alt");
37354 alt.push(" x-grid-dirty-row");
37357 if(this.getRowClass){
37358 alt.push( this.getRowClass(r, rowIndex));
37364 rowIndex : rowIndex,
37367 this.grid.fireEvent('rowclass', this, rowcfg);
37368 alt.push(rowcfg.rowClass);
37370 rp.alt = alt.join(" ");
37371 rp.cells = lcb.join("");
37372 lbuf[lbuf.length] = rt.apply(rp);
37373 rp.cells = cb.join("");
37374 buf[buf.length] = rt.apply(rp);
37376 return [lbuf.join(""), buf.join("")];
37379 renderBody : function(){
37380 var markup = this.renderRows();
37381 var bt = this.templates.body;
37382 return [bt.apply({rows: markup[0]}), bt.apply({rows: markup[1]})];
37386 * Refreshes the grid
37387 * @param {Boolean} headersToo
37389 refresh : function(headersToo){
37390 this.fireEvent("beforerefresh", this);
37391 this.grid.stopEditing();
37392 var result = this.renderBody();
37393 this.lockedBody.update(result[0]);
37394 this.mainBody.update(result[1]);
37395 if(headersToo === true){
37396 this.updateHeaders();
37397 this.updateColumns();
37398 this.updateSplitters();
37399 this.updateHeaderSortState();
37401 this.syncRowHeights();
37403 this.fireEvent("refresh", this);
37406 handleColumnMove : function(cm, oldIndex, newIndex){
37407 this.indexMap = null;
37408 var s = this.getScrollState();
37409 this.refresh(true);
37410 this.restoreScroll(s);
37411 this.afterMove(newIndex);
37414 afterMove : function(colIndex){
37415 if(this.enableMoveAnim && Roo.enableFx){
37416 this.fly(this.getHeaderCell(colIndex).firstChild).highlight(this.hlColor);
37418 // if multisort - fix sortOrder, and reload..
37419 if (this.grid.dataSource.multiSort) {
37420 // the we can call sort again..
37421 var dm = this.grid.dataSource;
37422 var cm = this.grid.colModel;
37424 for(var i = 0; i < cm.config.length; i++ ) {
37426 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined')) {
37427 continue; // dont' bother, it's not in sort list or being set.
37430 so.push(cm.config[i].dataIndex);
37433 dm.load(dm.lastOptions);
37440 updateCell : function(dm, rowIndex, dataIndex){
37441 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
37442 if(typeof colIndex == "undefined"){ // not present in grid
37445 var cm = this.grid.colModel;
37446 var cell = this.getCell(rowIndex, colIndex);
37447 var cellText = this.getCellText(rowIndex, colIndex);
37450 cellId : "x-grid-cell-" + rowIndex + "-" + colIndex,
37451 id : cm.getColumnId(colIndex),
37452 css: colIndex == cm.getColumnCount()-1 ? "x-grid-col-last" : ""
37454 var renderer = cm.getRenderer(colIndex);
37455 var val = renderer(dm.getValueAt(rowIndex, dataIndex), p, rowIndex, colIndex, dm);
37456 if(typeof val == "undefined" || val === "") val = " ";
37457 cellText.innerHTML = val;
37458 cell.className = this.cellClass + " " + this.idToCssName(p.cellId) + " " + p.css;
37459 this.syncRowHeights(rowIndex, rowIndex);
37462 calcColumnWidth : function(colIndex, maxRowsToMeasure){
37464 if(this.grid.autoSizeHeaders){
37465 var h = this.getHeaderCellMeasure(colIndex);
37466 maxWidth = Math.max(maxWidth, h.scrollWidth);
37469 if(this.cm.isLocked(colIndex)){
37470 tb = this.getLockedTable();
37473 tb = this.getBodyTable();
37474 index = colIndex - this.cm.getLockedCount();
37477 var rows = tb.rows;
37478 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
37479 for(var i = 0; i < stopIndex; i++){
37480 var cell = rows[i].childNodes[index].firstChild;
37481 maxWidth = Math.max(maxWidth, cell.scrollWidth);
37484 return maxWidth + /*margin for error in IE*/ 5;
37487 * Autofit a column to its content.
37488 * @param {Number} colIndex
37489 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
37491 autoSizeColumn : function(colIndex, forceMinSize, suppressEvent){
37492 if(this.cm.isHidden(colIndex)){
37493 return; // can't calc a hidden column
37496 var cid = this.cm.getColumnId(colIndex);
37497 this.css.updateRule(this.colSelector +this.idToCssName( cid), "width", this.grid.minColumnWidth + "px");
37498 if(this.grid.autoSizeHeaders){
37499 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", this.grid.minColumnWidth + "px");
37502 var newWidth = this.calcColumnWidth(colIndex);
37503 this.cm.setColumnWidth(colIndex,
37504 Math.max(this.grid.minColumnWidth, newWidth), suppressEvent);
37505 if(!suppressEvent){
37506 this.grid.fireEvent("columnresize", colIndex, newWidth);
37511 * Autofits all columns to their content and then expands to fit any extra space in the grid
37513 autoSizeColumns : function(){
37514 var cm = this.grid.colModel;
37515 var colCount = cm.getColumnCount();
37516 for(var i = 0; i < colCount; i++){
37517 this.autoSizeColumn(i, true, true);
37519 if(cm.getTotalWidth() < this.scroller.dom.clientWidth){
37522 this.updateColumns();
37528 * Autofits all columns to the grid's width proportionate with their current size
37529 * @param {Boolean} reserveScrollSpace Reserve space for a scrollbar
37531 fitColumns : function(reserveScrollSpace){
37532 var cm = this.grid.colModel;
37533 var colCount = cm.getColumnCount();
37537 for (i = 0; i < colCount; i++){
37538 if(!cm.isHidden(i) && !cm.isFixed(i)){
37539 w = cm.getColumnWidth(i);
37545 var avail = Math.min(this.scroller.dom.clientWidth, this.el.getWidth());
37546 if(reserveScrollSpace){
37549 var frac = (avail - cm.getTotalWidth())/width;
37550 while (cols.length){
37553 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
37555 this.updateColumns();
37559 onRowSelect : function(rowIndex){
37560 var row = this.getRowComposite(rowIndex);
37561 row.addClass("x-grid-row-selected");
37564 onRowDeselect : function(rowIndex){
37565 var row = this.getRowComposite(rowIndex);
37566 row.removeClass("x-grid-row-selected");
37569 onCellSelect : function(row, col){
37570 var cell = this.getCell(row, col);
37572 Roo.fly(cell).addClass("x-grid-cell-selected");
37576 onCellDeselect : function(row, col){
37577 var cell = this.getCell(row, col);
37579 Roo.fly(cell).removeClass("x-grid-cell-selected");
37583 updateHeaderSortState : function(){
37585 // sort state can be single { field: xxx, direction : yyy}
37586 // or { xxx=>ASC , yyy : DESC ..... }
37589 if (!this.ds.multiSort) {
37590 var state = this.ds.getSortState();
37594 mstate[state.field] = state.direction;
37595 // FIXME... - this is not used here.. but might be elsewhere..
37596 this.sortState = state;
37599 mstate = this.ds.sortToggle;
37601 //remove existing sort classes..
37603 var sc = this.sortClasses;
37604 var hds = this.el.select(this.headerSelector).removeClass(sc);
37606 for(var f in mstate) {
37608 var sortColumn = this.cm.findColumnIndex(f);
37610 if(sortColumn != -1){
37611 var sortDir = mstate[f];
37612 hds.item(sortColumn).addClass(sc[sortDir == "DESC" ? 1 : 0]);
37621 handleHeaderClick : function(g, index){
37622 if(this.headersDisabled){
37625 var dm = g.dataSource, cm = g.colModel;
37626 if(!cm.isSortable(index)){
37631 if (dm.multiSort) {
37632 // update the sortOrder
37634 for(var i = 0; i < cm.config.length; i++ ) {
37636 if ((typeof(dm.sortToggle[cm.config[i].dataIndex]) == 'undefined') && (index != i)) {
37637 continue; // dont' bother, it's not in sort list or being set.
37640 so.push(cm.config[i].dataIndex);
37646 dm.sort(cm.getDataIndex(index));
37650 destroy : function(){
37652 this.colMenu.removeAll();
37653 Roo.menu.MenuMgr.unregister(this.colMenu);
37654 this.colMenu.getEl().remove();
37655 delete this.colMenu;
37658 this.hmenu.removeAll();
37659 Roo.menu.MenuMgr.unregister(this.hmenu);
37660 this.hmenu.getEl().remove();
37663 if(this.grid.enableColumnMove){
37664 var dds = Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37666 for(var dd in dds){
37667 if(!dds[dd].config.isTarget && dds[dd].dragElId){
37668 var elid = dds[dd].dragElId;
37670 Roo.get(elid).remove();
37671 } else if(dds[dd].config.isTarget){
37672 dds[dd].proxyTop.remove();
37673 dds[dd].proxyBottom.remove();
37676 if(Roo.dd.DDM.locationCache[dd]){
37677 delete Roo.dd.DDM.locationCache[dd];
37680 delete Roo.dd.DDM.ids['gridHeader' + this.grid.getGridEl().id];
37683 Roo.util.CSS.removeStyleSheet(this.idToCssName(this.grid.id) + '-cssrules');
37684 this.bind(null, null);
37685 Roo.EventManager.removeResizeListener(this.onWindowResize, this);
37688 handleLockChange : function(){
37689 this.refresh(true);
37692 onDenyColumnLock : function(){
37696 onDenyColumnHide : function(){
37700 handleHdMenuClick : function(item){
37701 var index = this.hdCtxIndex;
37702 var cm = this.cm, ds = this.ds;
37705 ds.sort(cm.getDataIndex(index), "ASC");
37708 ds.sort(cm.getDataIndex(index), "DESC");
37711 var lc = cm.getLockedCount();
37712 if(cm.getColumnCount(true) <= lc+1){
37713 this.onDenyColumnLock();
37717 cm.setLocked(index, true, true);
37718 cm.moveColumn(index, lc);
37719 this.grid.fireEvent("columnmove", index, lc);
37721 cm.setLocked(index, true);
37725 var lc = cm.getLockedCount();
37726 if((lc-1) != index){
37727 cm.setLocked(index, false, true);
37728 cm.moveColumn(index, lc-1);
37729 this.grid.fireEvent("columnmove", index, lc-1);
37731 cm.setLocked(index, false);
37735 index = cm.getIndexById(item.id.substr(4));
37737 if(item.checked && cm.getColumnCount(true) <= 1){
37738 this.onDenyColumnHide();
37741 cm.setHidden(index, item.checked);
37747 beforeColMenuShow : function(){
37748 var cm = this.cm, colCount = cm.getColumnCount();
37749 this.colMenu.removeAll();
37750 for(var i = 0; i < colCount; i++){
37751 this.colMenu.add(new Roo.menu.CheckItem({
37752 id: "col-"+cm.getColumnId(i),
37753 text: cm.getColumnHeader(i),
37754 checked: !cm.isHidden(i),
37760 handleHdCtx : function(g, index, e){
37762 var hd = this.getHeaderCell(index);
37763 this.hdCtxIndex = index;
37764 var ms = this.hmenu.items, cm = this.cm;
37765 ms.get("asc").setDisabled(!cm.isSortable(index));
37766 ms.get("desc").setDisabled(!cm.isSortable(index));
37767 if(this.grid.enableColLock !== false){
37768 ms.get("lock").setDisabled(cm.isLocked(index));
37769 ms.get("unlock").setDisabled(!cm.isLocked(index));
37771 this.hmenu.show(hd, "tl-bl");
37774 handleHdOver : function(e){
37775 var hd = this.findHeaderCell(e.getTarget());
37776 if(hd && !this.headersDisabled){
37777 if(this.grid.colModel.isSortable(this.getCellIndex(hd))){
37778 this.fly(hd).addClass("x-grid-hd-over");
37783 handleHdOut : function(e){
37784 var hd = this.findHeaderCell(e.getTarget());
37786 this.fly(hd).removeClass("x-grid-hd-over");
37790 handleSplitDblClick : function(e, t){
37791 var i = this.getCellIndex(t);
37792 if(this.grid.enableColumnResize !== false && this.cm.isResizable(i) && !this.cm.isFixed(i)){
37793 this.autoSizeColumn(i, true);
37798 render : function(){
37801 var colCount = cm.getColumnCount();
37803 if(this.grid.monitorWindowResize === true){
37804 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
37806 var header = this.renderHeaders();
37807 var body = this.templates.body.apply({rows:""});
37808 var html = this.templates.master.apply({
37811 lockedHeader: header[0],
37815 //this.updateColumns();
37817 this.grid.getGridEl().dom.innerHTML = html;
37819 this.initElements();
37821 // a kludge to fix the random scolling effect in webkit
37822 this.el.on("scroll", function() {
37823 this.el.dom.scrollTop=0; // hopefully not recursive..
37826 this.scroller.on("scroll", this.handleScroll, this);
37827 this.lockedBody.on("mousewheel", this.handleWheel, this);
37828 this.mainBody.on("mousewheel", this.handleWheel, this);
37830 this.mainHd.on("mouseover", this.handleHdOver, this);
37831 this.mainHd.on("mouseout", this.handleHdOut, this);
37832 this.mainHd.on("dblclick", this.handleSplitDblClick, this,
37833 {delegate: "."+this.splitClass});
37835 this.lockedHd.on("mouseover", this.handleHdOver, this);
37836 this.lockedHd.on("mouseout", this.handleHdOut, this);
37837 this.lockedHd.on("dblclick", this.handleSplitDblClick, this,
37838 {delegate: "."+this.splitClass});
37840 if(this.grid.enableColumnResize !== false && Roo.grid.SplitDragZone){
37841 new Roo.grid.SplitDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37844 this.updateSplitters();
37846 if(this.grid.enableColumnMove && Roo.grid.HeaderDragZone){
37847 new Roo.grid.HeaderDragZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37848 new Roo.grid.HeaderDropZone(this.grid, this.lockedHd.dom, this.mainHd.dom);
37851 if(this.grid.enableCtxMenu !== false && Roo.menu.Menu){
37852 this.hmenu = new Roo.menu.Menu({id: this.grid.id + "-hctx"});
37854 {id:"asc", text: this.sortAscText, cls: "xg-hmenu-sort-asc"},
37855 {id:"desc", text: this.sortDescText, cls: "xg-hmenu-sort-desc"}
37857 if(this.grid.enableColLock !== false){
37858 this.hmenu.add('-',
37859 {id:"lock", text: this.lockText, cls: "xg-hmenu-lock"},
37860 {id:"unlock", text: this.unlockText, cls: "xg-hmenu-unlock"}
37863 if(this.grid.enableColumnHide !== false){
37865 this.colMenu = new Roo.menu.Menu({id:this.grid.id + "-hcols-menu"});
37866 this.colMenu.on("beforeshow", this.beforeColMenuShow, this);
37867 this.colMenu.on("itemclick", this.handleHdMenuClick, this);
37869 this.hmenu.add('-',
37870 {id:"columns", text: this.columnsText, menu: this.colMenu}
37873 this.hmenu.on("itemclick", this.handleHdMenuClick, this);
37875 this.grid.on("headercontextmenu", this.handleHdCtx, this);
37878 if((this.grid.enableDragDrop || this.grid.enableDrag) && Roo.grid.GridDragZone){
37879 this.dd = new Roo.grid.GridDragZone(this.grid, {
37880 ddGroup : this.grid.ddGroup || 'GridDD'
37886 for(var i = 0; i < colCount; i++){
37887 if(cm.isHidden(i)){
37888 this.hideColumn(i);
37890 if(cm.config[i].align){
37891 this.css.updateRule(this.colSelector + i, "textAlign", cm.config[i].align);
37892 this.css.updateRule(this.hdSelector + i, "textAlign", cm.config[i].align);
37896 this.updateHeaderSortState();
37898 this.beforeInitialResize();
37901 // two part rendering gives faster view to the user
37902 this.renderPhase2.defer(1, this);
37905 renderPhase2 : function(){
37906 // render the rows now
37908 if(this.grid.autoSizeColumns){
37909 this.autoSizeColumns();
37913 beforeInitialResize : function(){
37917 onColumnSplitterMoved : function(i, w){
37918 this.userResized = true;
37919 var cm = this.grid.colModel;
37920 cm.setColumnWidth(i, w, true);
37921 var cid = cm.getColumnId(i);
37922 this.css.updateRule(this.colSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37923 this.css.updateRule(this.hdSelector + this.idToCssName(cid), "width", (w-this.borderWidth) + "px");
37924 this.updateSplitters();
37926 this.grid.fireEvent("columnresize", i, w);
37929 syncRowHeights : function(startIndex, endIndex){
37930 if(this.grid.enableRowHeightSync === true && this.cm.getLockedCount() > 0){
37931 startIndex = startIndex || 0;
37932 var mrows = this.getBodyTable().rows;
37933 var lrows = this.getLockedTable().rows;
37934 var len = mrows.length-1;
37935 endIndex = Math.min(endIndex || len, len);
37936 for(var i = startIndex; i <= endIndex; i++){
37937 var m = mrows[i], l = lrows[i];
37938 var h = Math.max(m.offsetHeight, l.offsetHeight);
37939 m.style.height = l.style.height = h + "px";
37944 layout : function(initialRender, is2ndPass){
37946 var auto = g.autoHeight;
37947 var scrollOffset = 16;
37948 var c = g.getGridEl(), cm = this.cm,
37949 expandCol = g.autoExpandColumn,
37951 //c.beginMeasure();
37953 if(!c.dom.offsetWidth){ // display:none?
37955 this.lockedWrap.show();
37956 this.mainWrap.show();
37961 var hasLock = this.cm.isLocked(0);
37963 var tbh = this.headerPanel.getHeight();
37964 var bbh = this.footerPanel.getHeight();
37967 var ch = this.getBodyTable().offsetHeight + tbh + bbh + this.mainHd.getHeight();
37968 var newHeight = ch + c.getBorderWidth("tb");
37970 newHeight = Math.min(g.maxHeight, newHeight);
37972 c.setHeight(newHeight);
37976 c.setWidth(cm.getTotalWidth()+c.getBorderWidth('lr'));
37979 var s = this.scroller;
37981 var csize = c.getSize(true);
37983 this.el.setSize(csize.width, csize.height);
37985 this.headerPanel.setWidth(csize.width);
37986 this.footerPanel.setWidth(csize.width);
37988 var hdHeight = this.mainHd.getHeight();
37989 var vw = csize.width;
37990 var vh = csize.height - (tbh + bbh);
37994 var bt = this.getBodyTable();
37995 var ltWidth = hasLock ?
37996 Math.max(this.getLockedTable().offsetWidth, this.lockedHd.dom.firstChild.offsetWidth) : 0;
37998 var scrollHeight = bt.offsetHeight;
37999 var scrollWidth = ltWidth + bt.offsetWidth;
38000 var vscroll = false, hscroll = false;
38002 this.scrollSizer.setSize(scrollWidth, scrollHeight+hdHeight);
38004 var lw = this.lockedWrap, mw = this.mainWrap;
38005 var lb = this.lockedBody, mb = this.mainBody;
38007 setTimeout(function(){
38008 var t = s.dom.offsetTop;
38009 var w = s.dom.clientWidth,
38010 h = s.dom.clientHeight;
38013 lw.setSize(ltWidth, h);
38015 mw.setLeftTop(ltWidth, t);
38016 mw.setSize(w-ltWidth, h);
38018 lb.setHeight(h-hdHeight);
38019 mb.setHeight(h-hdHeight);
38021 if(is2ndPass !== true && !gv.userResized && expandCol){
38022 // high speed resize without full column calculation
38024 var ci = cm.getIndexById(expandCol);
38026 ci = cm.findColumnIndex(expandCol);
38028 ci = Math.max(0, ci); // make sure it's got at least the first col.
38029 var expandId = cm.getColumnId(ci);
38030 var tw = cm.getTotalWidth(false);
38031 var currentWidth = cm.getColumnWidth(ci);
38032 var cw = Math.min(Math.max(((w-tw)+currentWidth-2)-/*scrollbar*/(w <= s.dom.offsetWidth ? 0 : 18), g.autoExpandMin), g.autoExpandMax);
38033 if(currentWidth != cw){
38034 cm.setColumnWidth(ci, cw, true);
38035 gv.css.updateRule(gv.colSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38036 gv.css.updateRule(gv.hdSelector+gv.idToCssName(expandId), "width", (cw - gv.borderWidth) + "px");
38037 gv.updateSplitters();
38038 gv.layout(false, true);
38050 onWindowResize : function(){
38051 if(!this.grid.monitorWindowResize || this.grid.autoHeight){
38057 appendFooter : function(parentEl){
38061 sortAscText : "Sort Ascending",
38062 sortDescText : "Sort Descending",
38063 lockText : "Lock Column",
38064 unlockText : "Unlock Column",
38065 columnsText : "Columns"
38069 Roo.grid.GridView.ColumnDragZone = function(grid, hd){
38070 Roo.grid.GridView.ColumnDragZone.superclass.constructor.call(this, grid, hd, null);
38071 this.proxy.el.addClass('x-grid3-col-dd');
38074 Roo.extend(Roo.grid.GridView.ColumnDragZone, Roo.grid.HeaderDragZone, {
38075 handleMouseDown : function(e){
38079 callHandleMouseDown : function(e){
38080 Roo.grid.GridView.ColumnDragZone.superclass.handleMouseDown.call(this, e);
38085 * Ext JS Library 1.1.1
38086 * Copyright(c) 2006-2007, Ext JS, LLC.
38088 * Originally Released Under LGPL - original licence link has changed is not relivant.
38091 * <script type="text/javascript">
38095 // This is a support class used internally by the Grid components
38096 Roo.grid.SplitDragZone = function(grid, hd, hd2){
38098 this.view = grid.getView();
38099 this.proxy = this.view.resizeProxy;
38100 Roo.grid.SplitDragZone.superclass.constructor.call(this, hd,
38101 "gridSplitters" + this.grid.getGridEl().id, {
38102 dragElId : Roo.id(this.proxy.dom), resizeFrame:false
38104 this.setHandleElId(Roo.id(hd));
38105 this.setOuterHandleElId(Roo.id(hd2));
38106 this.scroll = false;
38108 Roo.extend(Roo.grid.SplitDragZone, Roo.dd.DDProxy, {
38109 fly: Roo.Element.fly,
38111 b4StartDrag : function(x, y){
38112 this.view.headersDisabled = true;
38113 this.proxy.setHeight(this.view.mainWrap.getHeight());
38114 var w = this.cm.getColumnWidth(this.cellIndex);
38115 var minw = Math.max(w-this.grid.minColumnWidth, 0);
38116 this.resetConstraints();
38117 this.setXConstraint(minw, 1000);
38118 this.setYConstraint(0, 0);
38119 this.minX = x - minw;
38120 this.maxX = x + 1000;
38122 Roo.dd.DDProxy.prototype.b4StartDrag.call(this, x, y);
38126 handleMouseDown : function(e){
38127 ev = Roo.EventObject.setEvent(e);
38128 var t = this.fly(ev.getTarget());
38129 if(t.hasClass("x-grid-split")){
38130 this.cellIndex = this.view.getCellIndex(t.dom);
38131 this.split = t.dom;
38132 this.cm = this.grid.colModel;
38133 if(this.cm.isResizable(this.cellIndex) && !this.cm.isFixed(this.cellIndex)){
38134 Roo.grid.SplitDragZone.superclass.handleMouseDown.apply(this, arguments);
38139 endDrag : function(e){
38140 this.view.headersDisabled = false;
38141 var endX = Math.max(this.minX, Roo.lib.Event.getPageX(e));
38142 var diff = endX - this.startPos;
38143 this.view.onColumnSplitterMoved(this.cellIndex, this.cm.getColumnWidth(this.cellIndex)+diff);
38146 autoOffset : function(){
38147 this.setDelta(0,0);
38151 * Ext JS Library 1.1.1
38152 * Copyright(c) 2006-2007, Ext JS, LLC.
38154 * Originally Released Under LGPL - original licence link has changed is not relivant.
38157 * <script type="text/javascript">
38161 // This is a support class used internally by the Grid components
38162 Roo.grid.GridDragZone = function(grid, config){
38163 this.view = grid.getView();
38164 Roo.grid.GridDragZone.superclass.constructor.call(this, this.view.mainBody.dom, config);
38165 if(this.view.lockedBody){
38166 this.setHandleElId(Roo.id(this.view.mainBody.dom));
38167 this.setOuterHandleElId(Roo.id(this.view.lockedBody.dom));
38169 this.scroll = false;
38171 this.ddel = document.createElement('div');
38172 this.ddel.className = 'x-grid-dd-wrap';
38175 Roo.extend(Roo.grid.GridDragZone, Roo.dd.DragZone, {
38176 ddGroup : "GridDD",
38178 getDragData : function(e){
38179 var t = Roo.lib.Event.getTarget(e);
38180 var rowIndex = this.view.findRowIndex(t);
38181 var sm = this.grid.selModel;
38183 //Roo.log(rowIndex);
38185 if (sm.getSelectedCell) {
38186 // cell selection..
38187 if (!sm.getSelectedCell()) {
38190 if (rowIndex != sm.getSelectedCell()[0]) {
38196 if(rowIndex !== false){
38201 //Roo.log([ sm.getSelectedCell() ? sm.getSelectedCell()[0] : 'NO' , rowIndex ]);
38203 //if(!sm.isSelected(rowIndex) || e.hasModifier()){
38206 if (e.hasModifier()){
38207 sm.handleMouseDown(e, t); // non modifier buttons are handled by row select.
38210 Roo.log("getDragData");
38215 rowIndex: rowIndex,
38216 selections:sm.getSelections ? sm.getSelections() : (
38217 sm.getSelectedCell() ? [ this.grid.ds.getAt(sm.getSelectedCell()[0]) ] : []
38224 onInitDrag : function(e){
38225 var data = this.dragData;
38226 this.ddel.innerHTML = this.grid.getDragDropText();
38227 this.proxy.update(this.ddel);
38228 // fire start drag?
38231 afterRepair : function(){
38232 this.dragging = false;
38235 getRepairXY : function(e, data){
38239 onEndDrag : function(data, e){
38243 onValidDrop : function(dd, e, id){
38248 beforeInvalidDrop : function(e, id){
38253 * Ext JS Library 1.1.1
38254 * Copyright(c) 2006-2007, Ext JS, LLC.
38256 * Originally Released Under LGPL - original licence link has changed is not relivant.
38259 * <script type="text/javascript">
38264 * @class Roo.grid.ColumnModel
38265 * @extends Roo.util.Observable
38266 * This is the default implementation of a ColumnModel used by the Grid. It defines
38267 * the columns in the grid.
38270 var colModel = new Roo.grid.ColumnModel([
38271 {header: "Ticker", width: 60, sortable: true, locked: true},
38272 {header: "Company Name", width: 150, sortable: true},
38273 {header: "Market Cap.", width: 100, sortable: true},
38274 {header: "$ Sales", width: 100, sortable: true, renderer: money},
38275 {header: "Employees", width: 100, sortable: true, resizable: false}
38280 * The config options listed for this class are options which may appear in each
38281 * individual column definition.
38282 * <br/>RooJS Fix - column id's are not sequential but use Roo.id() - fixes bugs with layouts.
38284 * @param {Object} config An Array of column config objects. See this class's
38285 * config objects for details.
38287 Roo.grid.ColumnModel = function(config){
38289 * The config passed into the constructor
38291 this.config = config;
38294 // if no id, create one
38295 // if the column does not have a dataIndex mapping,
38296 // map it to the order it is in the config
38297 for(var i = 0, len = config.length; i < len; i++){
38299 if(typeof c.dataIndex == "undefined"){
38302 if(typeof c.renderer == "string"){
38303 c.renderer = Roo.util.Format[c.renderer];
38305 if(typeof c.id == "undefined"){
38308 if(c.editor && c.editor.xtype){
38309 c.editor = Roo.factory(c.editor, Roo.grid);
38311 if(c.editor && c.editor.isFormField){
38312 c.editor = new Roo.grid.GridEditor(c.editor);
38314 this.lookup[c.id] = c;
38318 * The width of columns which have no width specified (defaults to 100)
38321 this.defaultWidth = 100;
38324 * Default sortable of columns which have no sortable specified (defaults to false)
38327 this.defaultSortable = false;
38331 * @event widthchange
38332 * Fires when the width of a column changes.
38333 * @param {ColumnModel} this
38334 * @param {Number} columnIndex The column index
38335 * @param {Number} newWidth The new width
38337 "widthchange": true,
38339 * @event headerchange
38340 * Fires when the text of a header changes.
38341 * @param {ColumnModel} this
38342 * @param {Number} columnIndex The column index
38343 * @param {Number} newText The new header text
38345 "headerchange": true,
38347 * @event hiddenchange
38348 * Fires when a column is hidden or "unhidden".
38349 * @param {ColumnModel} this
38350 * @param {Number} columnIndex The column index
38351 * @param {Boolean} hidden true if hidden, false otherwise
38353 "hiddenchange": true,
38355 * @event columnmoved
38356 * Fires when a column is moved.
38357 * @param {ColumnModel} this
38358 * @param {Number} oldIndex
38359 * @param {Number} newIndex
38361 "columnmoved" : true,
38363 * @event columlockchange
38364 * Fires when a column's locked state is changed
38365 * @param {ColumnModel} this
38366 * @param {Number} colIndex
38367 * @param {Boolean} locked true if locked
38369 "columnlockchange" : true
38371 Roo.grid.ColumnModel.superclass.constructor.call(this);
38373 Roo.extend(Roo.grid.ColumnModel, Roo.util.Observable, {
38375 * @cfg {String} header The header text to display in the Grid view.
38378 * @cfg {String} dataIndex (Optional) The name of the field in the grid's {@link Roo.data.Store}'s
38379 * {@link Roo.data.Record} definition from which to draw the column's value. If not
38380 * specified, the column's index is used as an index into the Record's data Array.
38383 * @cfg {Number} width (Optional) The initial width in pixels of the column. Using this
38384 * instead of {@link Roo.grid.Grid#autoSizeColumns} is more efficient.
38387 * @cfg {Boolean} sortable (Optional) True if sorting is to be allowed on this column.
38388 * Defaults to the value of the {@link #defaultSortable} property.
38389 * Whether local/remote sorting is used is specified in {@link Roo.data.Store#remoteSort}.
38392 * @cfg {Boolean} locked (Optional) True to lock the column in place while scrolling the Grid. Defaults to false.
38395 * @cfg {Boolean} fixed (Optional) True if the column width cannot be changed. Defaults to false.
38398 * @cfg {Boolean} resizable (Optional) False to disable column resizing. Defaults to true.
38401 * @cfg {Boolean} hidden (Optional) True to hide the column. Defaults to false.
38404 * @cfg {Function} renderer (Optional) A function used to generate HTML markup for a cell
38405 * given the cell's data value. See {@link #setRenderer}. If not specified, the
38406 * default renderer uses the raw data value.
38409 * @cfg {Roo.grid.GridEditor} editor (Optional) For grid editors - returns the grid editor
38412 * @cfg {String} align (Optional) Set the CSS text-align property of the column. Defaults to undefined.
38416 * Returns the id of the column at the specified index.
38417 * @param {Number} index The column index
38418 * @return {String} the id
38420 getColumnId : function(index){
38421 return this.config[index].id;
38425 * Returns the column for a specified id.
38426 * @param {String} id The column id
38427 * @return {Object} the column
38429 getColumnById : function(id){
38430 return this.lookup[id];
38435 * Returns the column for a specified dataIndex.
38436 * @param {String} dataIndex The column dataIndex
38437 * @return {Object|Boolean} the column or false if not found
38439 getColumnByDataIndex: function(dataIndex){
38440 var index = this.findColumnIndex(dataIndex);
38441 return index > -1 ? this.config[index] : false;
38445 * Returns the index for a specified column id.
38446 * @param {String} id The column id
38447 * @return {Number} the index, or -1 if not found
38449 getIndexById : function(id){
38450 for(var i = 0, len = this.config.length; i < len; i++){
38451 if(this.config[i].id == id){
38459 * Returns the index for a specified column dataIndex.
38460 * @param {String} dataIndex The column dataIndex
38461 * @return {Number} the index, or -1 if not found
38464 findColumnIndex : function(dataIndex){
38465 for(var i = 0, len = this.config.length; i < len; i++){
38466 if(this.config[i].dataIndex == dataIndex){
38474 moveColumn : function(oldIndex, newIndex){
38475 var c = this.config[oldIndex];
38476 this.config.splice(oldIndex, 1);
38477 this.config.splice(newIndex, 0, c);
38478 this.dataMap = null;
38479 this.fireEvent("columnmoved", this, oldIndex, newIndex);
38482 isLocked : function(colIndex){
38483 return this.config[colIndex].locked === true;
38486 setLocked : function(colIndex, value, suppressEvent){
38487 if(this.isLocked(colIndex) == value){
38490 this.config[colIndex].locked = value;
38491 if(!suppressEvent){
38492 this.fireEvent("columnlockchange", this, colIndex, value);
38496 getTotalLockedWidth : function(){
38497 var totalWidth = 0;
38498 for(var i = 0; i < this.config.length; i++){
38499 if(this.isLocked(i) && !this.isHidden(i)){
38500 this.totalWidth += this.getColumnWidth(i);
38506 getLockedCount : function(){
38507 for(var i = 0, len = this.config.length; i < len; i++){
38508 if(!this.isLocked(i)){
38515 * Returns the number of columns.
38518 getColumnCount : function(visibleOnly){
38519 if(visibleOnly === true){
38521 for(var i = 0, len = this.config.length; i < len; i++){
38522 if(!this.isHidden(i)){
38528 return this.config.length;
38532 * Returns the column configs that return true by the passed function that is called with (columnConfig, index)
38533 * @param {Function} fn
38534 * @param {Object} scope (optional)
38535 * @return {Array} result
38537 getColumnsBy : function(fn, scope){
38539 for(var i = 0, len = this.config.length; i < len; i++){
38540 var c = this.config[i];
38541 if(fn.call(scope||this, c, i) === true){
38549 * Returns true if the specified column is sortable.
38550 * @param {Number} col The column index
38551 * @return {Boolean}
38553 isSortable : function(col){
38554 if(typeof this.config[col].sortable == "undefined"){
38555 return this.defaultSortable;
38557 return this.config[col].sortable;
38561 * Returns the rendering (formatting) function defined for the column.
38562 * @param {Number} col The column index.
38563 * @return {Function} The function used to render the cell. See {@link #setRenderer}.
38565 getRenderer : function(col){
38566 if(!this.config[col].renderer){
38567 return Roo.grid.ColumnModel.defaultRenderer;
38569 return this.config[col].renderer;
38573 * Sets the rendering (formatting) function for a column.
38574 * @param {Number} col The column index
38575 * @param {Function} fn The function to use to process the cell's raw data
38576 * to return HTML markup for the grid view. The render function is called with
38577 * the following parameters:<ul>
38578 * <li>Data value.</li>
38579 * <li>Cell metadata. An object in which you may set the following attributes:<ul>
38580 * <li>css A CSS style string to apply to the table cell.</li>
38581 * <li>attr An HTML attribute definition string to apply to the data container element <i>within</i> the table cell.</li></ul>
38582 * <li>The {@link Roo.data.Record} from which the data was extracted.</li>
38583 * <li>Row index</li>
38584 * <li>Column index</li>
38585 * <li>The {@link Roo.data.Store} object from which the Record was extracted</li></ul>
38587 setRenderer : function(col, fn){
38588 this.config[col].renderer = fn;
38592 * Returns the width for the specified column.
38593 * @param {Number} col The column index
38596 getColumnWidth : function(col){
38597 return this.config[col].width * 1 || this.defaultWidth;
38601 * Sets the width for a column.
38602 * @param {Number} col The column index
38603 * @param {Number} width The new width
38605 setColumnWidth : function(col, width, suppressEvent){
38606 this.config[col].width = width;
38607 this.totalWidth = null;
38608 if(!suppressEvent){
38609 this.fireEvent("widthchange", this, col, width);
38614 * Returns the total width of all columns.
38615 * @param {Boolean} includeHidden True to include hidden column widths
38618 getTotalWidth : function(includeHidden){
38619 if(!this.totalWidth){
38620 this.totalWidth = 0;
38621 for(var i = 0, len = this.config.length; i < len; i++){
38622 if(includeHidden || !this.isHidden(i)){
38623 this.totalWidth += this.getColumnWidth(i);
38627 return this.totalWidth;
38631 * Returns the header for the specified column.
38632 * @param {Number} col The column index
38635 getColumnHeader : function(col){
38636 return this.config[col].header;
38640 * Sets the header for a column.
38641 * @param {Number} col The column index
38642 * @param {String} header The new header
38644 setColumnHeader : function(col, header){
38645 this.config[col].header = header;
38646 this.fireEvent("headerchange", this, col, header);
38650 * Returns the tooltip for the specified column.
38651 * @param {Number} col The column index
38654 getColumnTooltip : function(col){
38655 return this.config[col].tooltip;
38658 * Sets the tooltip for a column.
38659 * @param {Number} col The column index
38660 * @param {String} tooltip The new tooltip
38662 setColumnTooltip : function(col, tooltip){
38663 this.config[col].tooltip = tooltip;
38667 * Returns the dataIndex for the specified column.
38668 * @param {Number} col The column index
38671 getDataIndex : function(col){
38672 return this.config[col].dataIndex;
38676 * Sets the dataIndex for a column.
38677 * @param {Number} col The column index
38678 * @param {Number} dataIndex The new dataIndex
38680 setDataIndex : function(col, dataIndex){
38681 this.config[col].dataIndex = dataIndex;
38687 * Returns true if the cell is editable.
38688 * @param {Number} colIndex The column index
38689 * @param {Number} rowIndex The row index
38690 * @return {Boolean}
38692 isCellEditable : function(colIndex, rowIndex){
38693 return (this.config[colIndex].editable || (typeof this.config[colIndex].editable == "undefined" && this.config[colIndex].editor)) ? true : false;
38697 * Returns the editor defined for the cell/column.
38698 * return false or null to disable editing.
38699 * @param {Number} colIndex The column index
38700 * @param {Number} rowIndex The row index
38703 getCellEditor : function(colIndex, rowIndex){
38704 return this.config[colIndex].editor;
38708 * Sets if a column is editable.
38709 * @param {Number} col The column index
38710 * @param {Boolean} editable True if the column is editable
38712 setEditable : function(col, editable){
38713 this.config[col].editable = editable;
38718 * Returns true if the column is hidden.
38719 * @param {Number} colIndex The column index
38720 * @return {Boolean}
38722 isHidden : function(colIndex){
38723 return this.config[colIndex].hidden;
38728 * Returns true if the column width cannot be changed
38730 isFixed : function(colIndex){
38731 return this.config[colIndex].fixed;
38735 * Returns true if the column can be resized
38736 * @return {Boolean}
38738 isResizable : function(colIndex){
38739 return colIndex >= 0 && this.config[colIndex].resizable !== false && this.config[colIndex].fixed !== true;
38742 * Sets if a column is hidden.
38743 * @param {Number} colIndex The column index
38744 * @param {Boolean} hidden True if the column is hidden
38746 setHidden : function(colIndex, hidden){
38747 this.config[colIndex].hidden = hidden;
38748 this.totalWidth = null;
38749 this.fireEvent("hiddenchange", this, colIndex, hidden);
38753 * Sets the editor for a column.
38754 * @param {Number} col The column index
38755 * @param {Object} editor The editor object
38757 setEditor : function(col, editor){
38758 this.config[col].editor = editor;
38762 Roo.grid.ColumnModel.defaultRenderer = function(value){
38763 if(typeof value == "string" && value.length < 1){
38769 // Alias for backwards compatibility
38770 Roo.grid.DefaultColumnModel = Roo.grid.ColumnModel;
38773 * Ext JS Library 1.1.1
38774 * Copyright(c) 2006-2007, Ext JS, LLC.
38776 * Originally Released Under LGPL - original licence link has changed is not relivant.
38779 * <script type="text/javascript">
38783 * @class Roo.grid.AbstractSelectionModel
38784 * @extends Roo.util.Observable
38785 * Abstract base class for grid SelectionModels. It provides the interface that should be
38786 * implemented by descendant classes. This class should not be directly instantiated.
38789 Roo.grid.AbstractSelectionModel = function(){
38790 this.locked = false;
38791 Roo.grid.AbstractSelectionModel.superclass.constructor.call(this);
38794 Roo.extend(Roo.grid.AbstractSelectionModel, Roo.util.Observable, {
38795 /** @ignore Called by the grid automatically. Do not call directly. */
38796 init : function(grid){
38802 * Locks the selections.
38805 this.locked = true;
38809 * Unlocks the selections.
38811 unlock : function(){
38812 this.locked = false;
38816 * Returns true if the selections are locked.
38817 * @return {Boolean}
38819 isLocked : function(){
38820 return this.locked;
38824 * Ext JS Library 1.1.1
38825 * Copyright(c) 2006-2007, Ext JS, LLC.
38827 * Originally Released Under LGPL - original licence link has changed is not relivant.
38830 * <script type="text/javascript">
38833 * @extends Roo.grid.AbstractSelectionModel
38834 * @class Roo.grid.RowSelectionModel
38835 * The default SelectionModel used by {@link Roo.grid.Grid}.
38836 * It supports multiple selections and keyboard selection/navigation.
38838 * @param {Object} config
38840 Roo.grid.RowSelectionModel = function(config){
38841 Roo.apply(this, config);
38842 this.selections = new Roo.util.MixedCollection(false, function(o){
38847 this.lastActive = false;
38851 * @event selectionchange
38852 * Fires when the selection changes
38853 * @param {SelectionModel} this
38855 "selectionchange" : true,
38857 * @event afterselectionchange
38858 * Fires after the selection changes (eg. by key press or clicking)
38859 * @param {SelectionModel} this
38861 "afterselectionchange" : true,
38863 * @event beforerowselect
38864 * Fires when a row is selected being selected, return false to cancel.
38865 * @param {SelectionModel} this
38866 * @param {Number} rowIndex The selected index
38867 * @param {Boolean} keepExisting False if other selections will be cleared
38869 "beforerowselect" : true,
38872 * Fires when a row is selected.
38873 * @param {SelectionModel} this
38874 * @param {Number} rowIndex The selected index
38875 * @param {Roo.data.Record} r The record
38877 "rowselect" : true,
38879 * @event rowdeselect
38880 * Fires when a row is deselected.
38881 * @param {SelectionModel} this
38882 * @param {Number} rowIndex The selected index
38884 "rowdeselect" : true
38886 Roo.grid.RowSelectionModel.superclass.constructor.call(this);
38887 this.locked = false;
38890 Roo.extend(Roo.grid.RowSelectionModel, Roo.grid.AbstractSelectionModel, {
38892 * @cfg {Boolean} singleSelect
38893 * True to allow selection of only one row at a time (defaults to false)
38895 singleSelect : false,
38898 initEvents : function(){
38900 if(!this.grid.enableDragDrop && !this.grid.enableDrag){
38901 this.grid.on("mousedown", this.handleMouseDown, this);
38902 }else{ // allow click to work like normal
38903 this.grid.on("rowclick", this.handleDragableRowClick, this);
38906 this.rowNav = new Roo.KeyNav(this.grid.getGridEl(), {
38907 "up" : function(e){
38909 this.selectPrevious(e.shiftKey);
38910 }else if(this.last !== false && this.lastActive !== false){
38911 var last = this.last;
38912 this.selectRange(this.last, this.lastActive-1);
38913 this.grid.getView().focusRow(this.lastActive);
38914 if(last !== false){
38918 this.selectFirstRow();
38920 this.fireEvent("afterselectionchange", this);
38922 "down" : function(e){
38924 this.selectNext(e.shiftKey);
38925 }else if(this.last !== false && this.lastActive !== false){
38926 var last = this.last;
38927 this.selectRange(this.last, this.lastActive+1);
38928 this.grid.getView().focusRow(this.lastActive);
38929 if(last !== false){
38933 this.selectFirstRow();
38935 this.fireEvent("afterselectionchange", this);
38940 var view = this.grid.view;
38941 view.on("refresh", this.onRefresh, this);
38942 view.on("rowupdated", this.onRowUpdated, this);
38943 view.on("rowremoved", this.onRemove, this);
38947 onRefresh : function(){
38948 var ds = this.grid.dataSource, i, v = this.grid.view;
38949 var s = this.selections;
38950 s.each(function(r){
38951 if((i = ds.indexOfId(r.id)) != -1){
38960 onRemove : function(v, index, r){
38961 this.selections.remove(r);
38965 onRowUpdated : function(v, index, r){
38966 if(this.isSelected(r)){
38967 v.onRowSelect(index);
38973 * @param {Array} records The records to select
38974 * @param {Boolean} keepExisting (optional) True to keep existing selections
38976 selectRecords : function(records, keepExisting){
38978 this.clearSelections();
38980 var ds = this.grid.dataSource;
38981 for(var i = 0, len = records.length; i < len; i++){
38982 this.selectRow(ds.indexOf(records[i]), true);
38987 * Gets the number of selected rows.
38990 getCount : function(){
38991 return this.selections.length;
38995 * Selects the first row in the grid.
38997 selectFirstRow : function(){
39002 * Select the last row.
39003 * @param {Boolean} keepExisting (optional) True to keep existing selections
39005 selectLastRow : function(keepExisting){
39006 this.selectRow(this.grid.dataSource.getCount() - 1, keepExisting);
39010 * Selects the row immediately following the last selected row.
39011 * @param {Boolean} keepExisting (optional) True to keep existing selections
39013 selectNext : function(keepExisting){
39014 if(this.last !== false && (this.last+1) < this.grid.dataSource.getCount()){
39015 this.selectRow(this.last+1, keepExisting);
39016 this.grid.getView().focusRow(this.last);
39021 * Selects the row that precedes the last selected row.
39022 * @param {Boolean} keepExisting (optional) True to keep existing selections
39024 selectPrevious : function(keepExisting){
39026 this.selectRow(this.last-1, keepExisting);
39027 this.grid.getView().focusRow(this.last);
39032 * Returns the selected records
39033 * @return {Array} Array of selected records
39035 getSelections : function(){
39036 return [].concat(this.selections.items);
39040 * Returns the first selected record.
39043 getSelected : function(){
39044 return this.selections.itemAt(0);
39049 * Clears all selections.
39051 clearSelections : function(fast){
39052 if(this.locked) return;
39054 var ds = this.grid.dataSource;
39055 var s = this.selections;
39056 s.each(function(r){
39057 this.deselectRow(ds.indexOfId(r.id));
39061 this.selections.clear();
39068 * Selects all rows.
39070 selectAll : function(){
39071 if(this.locked) return;
39072 this.selections.clear();
39073 for(var i = 0, len = this.grid.dataSource.getCount(); i < len; i++){
39074 this.selectRow(i, true);
39079 * Returns True if there is a selection.
39080 * @return {Boolean}
39082 hasSelection : function(){
39083 return this.selections.length > 0;
39087 * Returns True if the specified row is selected.
39088 * @param {Number/Record} record The record or index of the record to check
39089 * @return {Boolean}
39091 isSelected : function(index){
39092 var r = typeof index == "number" ? this.grid.dataSource.getAt(index) : index;
39093 return (r && this.selections.key(r.id) ? true : false);
39097 * Returns True if the specified record id is selected.
39098 * @param {String} id The id of record to check
39099 * @return {Boolean}
39101 isIdSelected : function(id){
39102 return (this.selections.key(id) ? true : false);
39106 handleMouseDown : function(e, t){
39107 var view = this.grid.getView(), rowIndex;
39108 if(this.isLocked() || (rowIndex = view.findRowIndex(t)) === false){
39111 if(e.shiftKey && this.last !== false){
39112 var last = this.last;
39113 this.selectRange(last, rowIndex, e.ctrlKey);
39114 this.last = last; // reset the last
39115 view.focusRow(rowIndex);
39117 var isSelected = this.isSelected(rowIndex);
39118 if(e.button !== 0 && isSelected){
39119 view.focusRow(rowIndex);
39120 }else if(e.ctrlKey && isSelected){
39121 this.deselectRow(rowIndex);
39122 }else if(!isSelected){
39123 this.selectRow(rowIndex, e.button === 0 && (e.ctrlKey || e.shiftKey));
39124 view.focusRow(rowIndex);
39127 this.fireEvent("afterselectionchange", this);
39130 handleDragableRowClick : function(grid, rowIndex, e)
39132 if(e.button === 0 && !e.shiftKey && !e.ctrlKey) {
39133 this.selectRow(rowIndex, false);
39134 grid.view.focusRow(rowIndex);
39135 this.fireEvent("afterselectionchange", this);
39140 * Selects multiple rows.
39141 * @param {Array} rows Array of the indexes of the row to select
39142 * @param {Boolean} keepExisting (optional) True to keep existing selections
39144 selectRows : function(rows, keepExisting){
39146 this.clearSelections();
39148 for(var i = 0, len = rows.length; i < len; i++){
39149 this.selectRow(rows[i], true);
39154 * Selects a range of rows. All rows in between startRow and endRow are also selected.
39155 * @param {Number} startRow The index of the first row in the range
39156 * @param {Number} endRow The index of the last row in the range
39157 * @param {Boolean} keepExisting (optional) True to retain existing selections
39159 selectRange : function(startRow, endRow, keepExisting){
39160 if(this.locked) return;
39162 this.clearSelections();
39164 if(startRow <= endRow){
39165 for(var i = startRow; i <= endRow; i++){
39166 this.selectRow(i, true);
39169 for(var i = startRow; i >= endRow; i--){
39170 this.selectRow(i, true);
39176 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
39177 * @param {Number} startRow The index of the first row in the range
39178 * @param {Number} endRow The index of the last row in the range
39180 deselectRange : function(startRow, endRow, preventViewNotify){
39181 if(this.locked) return;
39182 for(var i = startRow; i <= endRow; i++){
39183 this.deselectRow(i, preventViewNotify);
39189 * @param {Number} row The index of the row to select
39190 * @param {Boolean} keepExisting (optional) True to keep existing selections
39192 selectRow : function(index, keepExisting, preventViewNotify){
39193 if(this.locked || (index < 0 || index >= this.grid.dataSource.getCount())) return;
39194 if(this.fireEvent("beforerowselect", this, index, keepExisting) !== false){
39195 if(!keepExisting || this.singleSelect){
39196 this.clearSelections();
39198 var r = this.grid.dataSource.getAt(index);
39199 this.selections.add(r);
39200 this.last = this.lastActive = index;
39201 if(!preventViewNotify){
39202 this.grid.getView().onRowSelect(index);
39204 this.fireEvent("rowselect", this, index, r);
39205 this.fireEvent("selectionchange", this);
39211 * @param {Number} row The index of the row to deselect
39213 deselectRow : function(index, preventViewNotify){
39214 if(this.locked) return;
39215 if(this.last == index){
39218 if(this.lastActive == index){
39219 this.lastActive = false;
39221 var r = this.grid.dataSource.getAt(index);
39222 this.selections.remove(r);
39223 if(!preventViewNotify){
39224 this.grid.getView().onRowDeselect(index);
39226 this.fireEvent("rowdeselect", this, index);
39227 this.fireEvent("selectionchange", this);
39231 restoreLast : function(){
39233 this.last = this._last;
39238 acceptsNav : function(row, col, cm){
39239 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39243 onEditorKey : function(field, e){
39244 var k = e.getKey(), newCell, g = this.grid, ed = g.activeEditor;
39249 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39251 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39253 }else if(k == e.ENTER && !e.ctrlKey){
39257 newCell = g.walkCells(ed.row-1, ed.col, -1, this.acceptsNav, this);
39259 newCell = g.walkCells(ed.row+1, ed.col, 1, this.acceptsNav, this);
39261 }else if(k == e.ESC){
39265 g.startEditing(newCell[0], newCell[1]);
39270 * Ext JS Library 1.1.1
39271 * Copyright(c) 2006-2007, Ext JS, LLC.
39273 * Originally Released Under LGPL - original licence link has changed is not relivant.
39276 * <script type="text/javascript">
39279 * @class Roo.grid.CellSelectionModel
39280 * @extends Roo.grid.AbstractSelectionModel
39281 * This class provides the basic implementation for cell selection in a grid.
39283 * @param {Object} config The object containing the configuration of this model.
39284 * @cfg {Boolean} enter_is_tab Enter behaves the same as tab. (eg. goes to next cell) default: false
39286 Roo.grid.CellSelectionModel = function(config){
39287 Roo.apply(this, config);
39289 this.selection = null;
39293 * @event beforerowselect
39294 * Fires before a cell is selected.
39295 * @param {SelectionModel} this
39296 * @param {Number} rowIndex The selected row index
39297 * @param {Number} colIndex The selected cell index
39299 "beforecellselect" : true,
39301 * @event cellselect
39302 * Fires when a cell is selected.
39303 * @param {SelectionModel} this
39304 * @param {Number} rowIndex The selected row index
39305 * @param {Number} colIndex The selected cell index
39307 "cellselect" : true,
39309 * @event selectionchange
39310 * Fires when the active selection changes.
39311 * @param {SelectionModel} this
39312 * @param {Object} selection null for no selection or an object (o) with two properties
39314 <li>o.record: the record object for the row the selection is in</li>
39315 <li>o.cell: An array of [rowIndex, columnIndex]</li>
39318 "selectionchange" : true,
39321 * Fires when the tab (or enter) was pressed on the last editable cell
39322 * You can use this to trigger add new row.
39323 * @param {SelectionModel} this
39327 * @event beforeeditnext
39328 * Fires before the next editable sell is made active
39329 * You can use this to skip to another cell or fire the tabend
39330 * if you set cell to false
39331 * @param {Object} eventdata object : { cell : [ row, col ] }
39333 "beforeeditnext" : true
39335 Roo.grid.CellSelectionModel.superclass.constructor.call(this);
39338 Roo.extend(Roo.grid.CellSelectionModel, Roo.grid.AbstractSelectionModel, {
39340 enter_is_tab: false,
39343 initEvents : function(){
39344 this.grid.on("mousedown", this.handleMouseDown, this);
39345 this.grid.getGridEl().on(Roo.isIE ? "keydown" : "keypress", this.handleKeyDown, this);
39346 var view = this.grid.view;
39347 view.on("refresh", this.onViewChange, this);
39348 view.on("rowupdated", this.onRowUpdated, this);
39349 view.on("beforerowremoved", this.clearSelections, this);
39350 view.on("beforerowsinserted", this.clearSelections, this);
39351 if(this.grid.isEditor){
39352 this.grid.on("beforeedit", this.beforeEdit, this);
39357 beforeEdit : function(e){
39358 this.select(e.row, e.column, false, true, e.record);
39362 onRowUpdated : function(v, index, r){
39363 if(this.selection && this.selection.record == r){
39364 v.onCellSelect(index, this.selection.cell[1]);
39369 onViewChange : function(){
39370 this.clearSelections(true);
39374 * Returns the currently selected cell,.
39375 * @return {Array} The selected cell (row, column) or null if none selected.
39377 getSelectedCell : function(){
39378 return this.selection ? this.selection.cell : null;
39382 * Clears all selections.
39383 * @param {Boolean} true to prevent the gridview from being notified about the change.
39385 clearSelections : function(preventNotify){
39386 var s = this.selection;
39388 if(preventNotify !== true){
39389 this.grid.view.onCellDeselect(s.cell[0], s.cell[1]);
39391 this.selection = null;
39392 this.fireEvent("selectionchange", this, null);
39397 * Returns true if there is a selection.
39398 * @return {Boolean}
39400 hasSelection : function(){
39401 return this.selection ? true : false;
39405 handleMouseDown : function(e, t){
39406 var v = this.grid.getView();
39407 if(this.isLocked()){
39410 var row = v.findRowIndex(t);
39411 var cell = v.findCellIndex(t);
39412 if(row !== false && cell !== false){
39413 this.select(row, cell);
39419 * @param {Number} rowIndex
39420 * @param {Number} collIndex
39422 select : function(rowIndex, colIndex, preventViewNotify, preventFocus, /*internal*/ r){
39423 if(this.fireEvent("beforecellselect", this, rowIndex, colIndex) !== false){
39424 this.clearSelections();
39425 r = r || this.grid.dataSource.getAt(rowIndex);
39428 cell : [rowIndex, colIndex]
39430 if(!preventViewNotify){
39431 var v = this.grid.getView();
39432 v.onCellSelect(rowIndex, colIndex);
39433 if(preventFocus !== true){
39434 v.focusCell(rowIndex, colIndex);
39437 this.fireEvent("cellselect", this, rowIndex, colIndex);
39438 this.fireEvent("selectionchange", this, this.selection);
39443 isSelectable : function(rowIndex, colIndex, cm){
39444 return !cm.isHidden(colIndex);
39448 handleKeyDown : function(e){
39449 //Roo.log('Cell Sel Model handleKeyDown');
39450 if(!e.isNavKeyPress()){
39453 var g = this.grid, s = this.selection;
39456 var cell = g.walkCells(0, 0, 1, this.isSelectable, this);
39458 this.select(cell[0], cell[1]);
39463 var walk = function(row, col, step){
39464 return g.walkCells(row, col, step, sm.isSelectable, sm);
39466 var k = e.getKey(), r = s.cell[0], c = s.cell[1];
39473 // handled by onEditorKey
39474 if (g.isEditor && g.editing) {
39478 newCell = walk(r, c-1, -1);
39480 newCell = walk(r, c+1, 1);
39485 newCell = walk(r+1, c, 1);
39489 newCell = walk(r-1, c, -1);
39493 newCell = walk(r, c+1, 1);
39497 newCell = walk(r, c-1, -1);
39502 if(g.isEditor && !g.editing){
39503 g.startEditing(r, c);
39512 this.select(newCell[0], newCell[1]);
39518 acceptsNav : function(row, col, cm){
39519 return !cm.isHidden(col) && cm.isCellEditable(col, row);
39523 * @param {Number} field (not used) - as it's normally used as a listener
39524 * @param {Number} e - event - fake it by using
39526 * var e = Roo.EventObjectImpl.prototype;
39527 * e.keyCode = e.TAB
39531 onEditorKey : function(field, e){
39533 var k = e.getKey(),
39536 ed = g.activeEditor,
39538 ///Roo.log('onEditorKey' + k);
39541 if (this.enter_is_tab && k == e.ENTER) {
39547 newCell = g.walkCells(ed.row, ed.col-1, -1, this.acceptsNav, this);
39549 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39555 } else if(k == e.ENTER && !e.ctrlKey){
39558 newCell = g.walkCells(ed.row, ed.col+1, 1, this.acceptsNav, this);
39560 } else if(k == e.ESC){
39565 var ecall = { cell : newCell, forward : forward };
39566 this.fireEvent('beforeeditnext', ecall );
39567 newCell = ecall.cell;
39568 forward = ecall.forward;
39572 //Roo.log('next cell after edit');
39573 g.startEditing.defer(100, g, [newCell[0], newCell[1]]);
39574 } else if (forward) {
39575 // tabbed past last
39576 this.fireEvent.defer(100, this, ['tabend',this]);
39581 * Ext JS Library 1.1.1
39582 * Copyright(c) 2006-2007, Ext JS, LLC.
39584 * Originally Released Under LGPL - original licence link has changed is not relivant.
39587 * <script type="text/javascript">
39591 * @class Roo.grid.EditorGrid
39592 * @extends Roo.grid.Grid
39593 * Class for creating and editable grid.
39594 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
39595 * The container MUST have some type of size defined for the grid to fill. The container will be
39596 * automatically set to position relative if it isn't already.
39597 * @param {Object} dataSource The data model to bind to
39598 * @param {Object} colModel The column model with info about this grid's columns
39600 Roo.grid.EditorGrid = function(container, config){
39601 Roo.grid.EditorGrid.superclass.constructor.call(this, container, config);
39602 this.getGridEl().addClass("xedit-grid");
39604 if(!this.selModel){
39605 this.selModel = new Roo.grid.CellSelectionModel();
39608 this.activeEditor = null;
39612 * @event beforeedit
39613 * Fires before cell editing is triggered. The edit event object has the following properties <br />
39614 * <ul style="padding:5px;padding-left:16px;">
39615 * <li>grid - This grid</li>
39616 * <li>record - The record being edited</li>
39617 * <li>field - The field name being edited</li>
39618 * <li>value - The value for the field being edited.</li>
39619 * <li>row - The grid row index</li>
39620 * <li>column - The grid column index</li>
39621 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39623 * @param {Object} e An edit event (see above for description)
39625 "beforeedit" : true,
39628 * Fires after a cell is edited. <br />
39629 * <ul style="padding:5px;padding-left:16px;">
39630 * <li>grid - This grid</li>
39631 * <li>record - The record being edited</li>
39632 * <li>field - The field name being edited</li>
39633 * <li>value - The value being set</li>
39634 * <li>originalValue - The original value for the field, before the edit.</li>
39635 * <li>row - The grid row index</li>
39636 * <li>column - The grid column index</li>
39638 * @param {Object} e An edit event (see above for description)
39640 "afteredit" : true,
39642 * @event validateedit
39643 * Fires after a cell is edited, but before the value is set in the record.
39644 * You can use this to modify the value being set in the field, Return false
39645 * to cancel the change. The edit event object has the following properties <br />
39646 * <ul style="padding:5px;padding-left:16px;">
39647 * <li>editor - This editor</li>
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 being set</li>
39652 * <li>originalValue - The original value for the field, before the edit.</li>
39653 * <li>row - The grid row index</li>
39654 * <li>column - The grid column index</li>
39655 * <li>cancel - Set this to true to cancel the edit or return false from your handler.</li>
39657 * @param {Object} e An edit event (see above for description)
39659 "validateedit" : true
39661 this.on("bodyscroll", this.stopEditing, this);
39662 this.on(this.clicksToEdit == 1 ? "cellclick" : "celldblclick", this.onCellDblClick, this);
39665 Roo.extend(Roo.grid.EditorGrid, Roo.grid.Grid, {
39667 * @cfg {Number} clicksToEdit
39668 * The number of clicks on a cell required to display the cell's editor (defaults to 2)
39675 trackMouseOver: false, // causes very odd FF errors
39677 onCellDblClick : function(g, row, col){
39678 this.startEditing(row, col);
39681 onEditComplete : function(ed, value, startValue){
39682 this.editing = false;
39683 this.activeEditor = null;
39684 ed.un("specialkey", this.selModel.onEditorKey, this.selModel);
39686 var field = this.colModel.getDataIndex(ed.col);
39691 originalValue: startValue,
39698 var cell = Roo.get(this.view.getCell(ed.row,ed.col))
39701 if(String(value) !== String(startValue)){
39703 if(this.fireEvent("validateedit", e) !== false && !e.cancel){
39704 r.set(field, e.value);
39705 // if we are dealing with a combo box..
39706 // then we also set the 'name' colum to be the displayField
39707 if (ed.field.displayField && ed.field.name) {
39708 r.set(ed.field.name, ed.field.el.dom.value);
39711 delete e.cancel; //?? why!!!
39712 this.fireEvent("afteredit", e);
39715 this.fireEvent("afteredit", e); // always fire it!
39717 this.view.focusCell(ed.row, ed.col);
39721 * Starts editing the specified for the specified row/column
39722 * @param {Number} rowIndex
39723 * @param {Number} colIndex
39725 startEditing : function(row, col){
39726 this.stopEditing();
39727 if(this.colModel.isCellEditable(col, row)){
39728 this.view.ensureVisible(row, col, true);
39730 var r = this.dataSource.getAt(row);
39731 var field = this.colModel.getDataIndex(col);
39732 var cell = Roo.get(this.view.getCell(row,col));
39737 value: r.data[field],
39742 if(this.fireEvent("beforeedit", e) !== false && !e.cancel){
39743 this.editing = true;
39744 var ed = this.colModel.getCellEditor(col, row);
39750 ed.render(ed.parentEl || document.body);
39756 (function(){ // complex but required for focus issues in safari, ie and opera
39760 ed.on("complete", this.onEditComplete, this, {single: true});
39761 ed.on("specialkey", this.selModel.onEditorKey, this.selModel);
39762 this.activeEditor = ed;
39763 var v = r.data[field];
39764 ed.startEdit(this.view.getCell(row, col), v);
39765 // combo's with 'displayField and name set
39766 if (ed.field.displayField && ed.field.name) {
39767 ed.field.el.dom.value = r.data[ed.field.name];
39771 }).defer(50, this);
39777 * Stops any active editing
39779 stopEditing : function(){
39780 if(this.activeEditor){
39781 this.activeEditor.completeEdit();
39783 this.activeEditor = null;
39787 * Called to get grid's drag proxy text, by default returns this.ddText.
39790 getDragDropText : function(){
39791 var count = this.selModel.getSelectedCell() ? 1 : 0;
39792 return String.format(this.ddText, count, count == 1 ? '' : 's');
39797 * Ext JS Library 1.1.1
39798 * Copyright(c) 2006-2007, Ext JS, LLC.
39800 * Originally Released Under LGPL - original licence link has changed is not relivant.
39803 * <script type="text/javascript">
39806 // private - not really -- you end up using it !
39807 // This is a support class used internally by the Grid components
39810 * @class Roo.grid.GridEditor
39811 * @extends Roo.Editor
39812 * Class for creating and editable grid elements.
39813 * @param {Object} config any settings (must include field)
39815 Roo.grid.GridEditor = function(field, config){
39816 if (!config && field.field) {
39818 field = Roo.factory(config.field, Roo.form);
39820 Roo.grid.GridEditor.superclass.constructor.call(this, field, config);
39821 field.monitorTab = false;
39824 Roo.extend(Roo.grid.GridEditor, Roo.Editor, {
39827 * @cfg {Roo.form.Field} field Field to wrap (or xtyped)
39830 alignment: "tl-tl",
39833 cls: "x-small-editor x-grid-editor",
39838 * Ext JS Library 1.1.1
39839 * Copyright(c) 2006-2007, Ext JS, LLC.
39841 * Originally Released Under LGPL - original licence link has changed is not relivant.
39844 * <script type="text/javascript">
39849 Roo.grid.PropertyRecord = Roo.data.Record.create([
39850 {name:'name',type:'string'}, 'value'
39854 Roo.grid.PropertyStore = function(grid, source){
39856 this.store = new Roo.data.Store({
39857 recordType : Roo.grid.PropertyRecord
39859 this.store.on('update', this.onUpdate, this);
39861 this.setSource(source);
39863 Roo.grid.PropertyStore.superclass.constructor.call(this);
39868 Roo.extend(Roo.grid.PropertyStore, Roo.util.Observable, {
39869 setSource : function(o){
39871 this.store.removeAll();
39874 if(this.isEditableValue(o[k])){
39875 data.push(new Roo.grid.PropertyRecord({name: k, value: o[k]}, k));
39878 this.store.loadRecords({records: data}, {}, true);
39881 onUpdate : function(ds, record, type){
39882 if(type == Roo.data.Record.EDIT){
39883 var v = record.data['value'];
39884 var oldValue = record.modified['value'];
39885 if(this.grid.fireEvent('beforepropertychange', this.source, record.id, v, oldValue) !== false){
39886 this.source[record.id] = v;
39888 this.grid.fireEvent('propertychange', this.source, record.id, v, oldValue);
39895 getProperty : function(row){
39896 return this.store.getAt(row);
39899 isEditableValue: function(val){
39900 if(val && val instanceof Date){
39902 }else if(typeof val == 'object' || typeof val == 'function'){
39908 setValue : function(prop, value){
39909 this.source[prop] = value;
39910 this.store.getById(prop).set('value', value);
39913 getSource : function(){
39914 return this.source;
39918 Roo.grid.PropertyColumnModel = function(grid, store){
39921 g.PropertyColumnModel.superclass.constructor.call(this, [
39922 {header: this.nameText, sortable: true, dataIndex:'name', id: 'name'},
39923 {header: this.valueText, resizable:false, dataIndex: 'value', id: 'value'}
39925 this.store = store;
39926 this.bselect = Roo.DomHelper.append(document.body, {
39927 tag: 'select', style:'display:none', cls: 'x-grid-editor', children: [
39928 {tag: 'option', value: 'true', html: 'true'},
39929 {tag: 'option', value: 'false', html: 'false'}
39932 Roo.id(this.bselect);
39935 'date' : new g.GridEditor(new f.DateField({selectOnFocus:true})),
39936 'string' : new g.GridEditor(new f.TextField({selectOnFocus:true})),
39937 'number' : new g.GridEditor(new f.NumberField({selectOnFocus:true, style:'text-align:left;'})),
39938 'int' : new g.GridEditor(new f.NumberField({selectOnFocus:true, allowDecimals:false, style:'text-align:left;'})),
39939 'boolean' : new g.GridEditor(new f.Field({el:this.bselect,selectOnFocus:true}))
39941 this.renderCellDelegate = this.renderCell.createDelegate(this);
39942 this.renderPropDelegate = this.renderProp.createDelegate(this);
39945 Roo.extend(Roo.grid.PropertyColumnModel, Roo.grid.ColumnModel, {
39949 valueText : 'Value',
39951 dateFormat : 'm/j/Y',
39954 renderDate : function(dateVal){
39955 return dateVal.dateFormat(this.dateFormat);
39958 renderBool : function(bVal){
39959 return bVal ? 'true' : 'false';
39962 isCellEditable : function(colIndex, rowIndex){
39963 return colIndex == 1;
39966 getRenderer : function(col){
39968 this.renderCellDelegate : this.renderPropDelegate;
39971 renderProp : function(v){
39972 return this.getPropertyName(v);
39975 renderCell : function(val){
39977 if(val instanceof Date){
39978 rv = this.renderDate(val);
39979 }else if(typeof val == 'boolean'){
39980 rv = this.renderBool(val);
39982 return Roo.util.Format.htmlEncode(rv);
39985 getPropertyName : function(name){
39986 var pn = this.grid.propertyNames;
39987 return pn && pn[name] ? pn[name] : name;
39990 getCellEditor : function(colIndex, rowIndex){
39991 var p = this.store.getProperty(rowIndex);
39992 var n = p.data['name'], val = p.data['value'];
39994 if(typeof(this.grid.customEditors[n]) == 'string'){
39995 return this.editors[this.grid.customEditors[n]];
39997 if(typeof(this.grid.customEditors[n]) != 'undefined'){
39998 return this.grid.customEditors[n];
40000 if(val instanceof Date){
40001 return this.editors['date'];
40002 }else if(typeof val == 'number'){
40003 return this.editors['number'];
40004 }else if(typeof val == 'boolean'){
40005 return this.editors['boolean'];
40007 return this.editors['string'];
40013 * @class Roo.grid.PropertyGrid
40014 * @extends Roo.grid.EditorGrid
40015 * This class represents the interface of a component based property grid control.
40016 * <br><br>Usage:<pre><code>
40017 var grid = new Roo.grid.PropertyGrid("my-container-id", {
40025 * @param {String/HTMLElement/Roo.Element} container The element into which this grid will be rendered -
40026 * The container MUST have some type of size defined for the grid to fill. The container will be
40027 * automatically set to position relative if it isn't already.
40028 * @param {Object} config A config object that sets properties on this grid.
40030 Roo.grid.PropertyGrid = function(container, config){
40031 config = config || {};
40032 var store = new Roo.grid.PropertyStore(this);
40033 this.store = store;
40034 var cm = new Roo.grid.PropertyColumnModel(this, store);
40035 store.store.sort('name', 'ASC');
40036 Roo.grid.PropertyGrid.superclass.constructor.call(this, container, Roo.apply({
40039 enableColLock:false,
40040 enableColumnMove:false,
40042 trackMouseOver: false,
40045 this.getGridEl().addClass('x-props-grid');
40046 this.lastEditRow = null;
40047 this.on('columnresize', this.onColumnResize, this);
40050 * @event beforepropertychange
40051 * Fires before a property changes (return false to stop?)
40052 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40053 * @param {String} id Record Id
40054 * @param {String} newval New Value
40055 * @param {String} oldval Old Value
40057 "beforepropertychange": true,
40059 * @event propertychange
40060 * Fires after a property changes
40061 * @param {Roo.grid.PropertyGrid} grid property grid? (check could be store)
40062 * @param {String} id Record Id
40063 * @param {String} newval New Value
40064 * @param {String} oldval Old Value
40066 "propertychange": true
40068 this.customEditors = this.customEditors || {};
40070 Roo.extend(Roo.grid.PropertyGrid, Roo.grid.EditorGrid, {
40073 * @cfg {Object} customEditors map of colnames=> custom editors.
40074 * the custom editor can be one of the standard ones (date|string|number|int|boolean), or a
40075 * grid editor eg. Roo.grid.GridEditor(new Roo.form.TextArea({selectOnFocus:true})),
40076 * false disables editing of the field.
40080 * @cfg {Object} propertyNames map of property Names to their displayed value
40083 render : function(){
40084 Roo.grid.PropertyGrid.superclass.render.call(this);
40085 this.autoSize.defer(100, this);
40088 autoSize : function(){
40089 Roo.grid.PropertyGrid.superclass.autoSize.call(this);
40091 this.view.fitColumns();
40095 onColumnResize : function(){
40096 this.colModel.setColumnWidth(1, this.container.getWidth(true)-this.colModel.getColumnWidth(0));
40100 * Sets the data for the Grid
40101 * accepts a Key => Value object of all the elements avaiable.
40102 * @param {Object} data to appear in grid.
40104 setSource : function(source){
40105 this.store.setSource(source);
40109 * Gets all the data from the grid.
40110 * @return {Object} data data stored in grid
40112 getSource : function(){
40113 return this.store.getSource();
40117 * Ext JS Library 1.1.1
40118 * Copyright(c) 2006-2007, Ext JS, LLC.
40120 * Originally Released Under LGPL - original licence link has changed is not relivant.
40123 * <script type="text/javascript">
40127 * @class Roo.LoadMask
40128 * A simple utility class for generically masking elements while loading data. If the element being masked has
40129 * an underlying {@link Roo.data.Store}, the masking will be automatically synchronized with the store's loading
40130 * process and the mask element will be cached for reuse. For all other elements, this mask will replace the
40131 * element's UpdateManager load indicator and will be destroyed after the initial load.
40133 * Create a new LoadMask
40134 * @param {String/HTMLElement/Roo.Element} el The element or DOM node, or its id
40135 * @param {Object} config The config object
40137 Roo.LoadMask = function(el, config){
40138 this.el = Roo.get(el);
40139 Roo.apply(this, config);
40141 this.store.on('beforeload', this.onBeforeLoad, this);
40142 this.store.on('load', this.onLoad, this);
40143 this.store.on('loadexception', this.onLoadException, this);
40144 this.removeMask = false;
40146 var um = this.el.getUpdateManager();
40147 um.showLoadIndicator = false; // disable the default indicator
40148 um.on('beforeupdate', this.onBeforeLoad, this);
40149 um.on('update', this.onLoad, this);
40150 um.on('failure', this.onLoad, this);
40151 this.removeMask = true;
40155 Roo.LoadMask.prototype = {
40157 * @cfg {Boolean} removeMask
40158 * True to create a single-use mask that is automatically destroyed after loading (useful for page loads),
40159 * False to persist the mask element reference for multiple uses (e.g., for paged data widgets). Defaults to false.
40162 * @cfg {String} msg
40163 * The text to display in a centered loading message box (defaults to 'Loading...')
40165 msg : 'Loading...',
40167 * @cfg {String} msgCls
40168 * The CSS class to apply to the loading message element (defaults to "x-mask-loading")
40170 msgCls : 'x-mask-loading',
40173 * Read-only. True if the mask is currently disabled so that it will not be displayed (defaults to false)
40179 * Disables the mask to prevent it from being displayed
40181 disable : function(){
40182 this.disabled = true;
40186 * Enables the mask so that it can be displayed
40188 enable : function(){
40189 this.disabled = false;
40192 onLoadException : function()
40194 Roo.log(arguments);
40196 if (typeof(arguments[3]) != 'undefined') {
40197 Roo.MessageBox.alert("Error loading",arguments[3]);
40201 if (this.store && typeof(this.store.reader.jsonData.errorMsg) != 'undefined') {
40202 Roo.MessageBox.alert("Error loading",this.store.reader.jsonData.errorMsg);
40211 this.el.unmask(this.removeMask);
40214 onLoad : function()
40216 this.el.unmask(this.removeMask);
40220 onBeforeLoad : function(){
40221 if(!this.disabled){
40222 this.el.mask(this.msg, this.msgCls);
40227 destroy : function(){
40229 this.store.un('beforeload', this.onBeforeLoad, this);
40230 this.store.un('load', this.onLoad, this);
40231 this.store.un('loadexception', this.onLoadException, this);
40233 var um = this.el.getUpdateManager();
40234 um.un('beforeupdate', this.onBeforeLoad, this);
40235 um.un('update', this.onLoad, this);
40236 um.un('failure', this.onLoad, this);
40241 * Ext JS Library 1.1.1
40242 * Copyright(c) 2006-2007, Ext JS, LLC.
40244 * Originally Released Under LGPL - original licence link has changed is not relivant.
40247 * <script type="text/javascript">
40252 * @class Roo.XTemplate
40253 * @extends Roo.Template
40254 * Provides a template that can have nested templates for loops or conditionals. The syntax is:
40256 var t = new Roo.XTemplate(
40257 '<select name="{name}">',
40258 '<tpl for="options"><option value="{value:trim}">{text:ellipsis(10)}</option></tpl>',
40262 // then append, applying the master template values
40265 * Supported features:
40270 {a_variable} - output encoded.
40271 {a_variable.format:("Y-m-d")} - call a method on the variable
40272 {a_variable:raw} - unencoded output
40273 {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
40274 {a_variable:this.method_on_template(...)} - call a method on the template object.
40279 <tpl for="a_variable or condition.."></tpl>
40280 <tpl if="a_variable or condition"></tpl>
40281 <tpl exec="some javascript"></tpl>
40282 <tpl name="named_template"></tpl> (experimental)
40284 <tpl for="."></tpl> - just iterate the property..
40285 <tpl for=".."></tpl> - iterates with the parent (probably the template)
40289 Roo.XTemplate = function()
40291 Roo.XTemplate.superclass.constructor.apply(this, arguments);
40298 Roo.extend(Roo.XTemplate, Roo.Template, {
40301 * The various sub templates
40306 * basic tag replacing syntax
40309 * // you can fake an object call by doing this
40313 re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
40316 * compile the template
40318 * This is not recursive, so I'm not sure how nested templates are really going to be handled..
40321 compile: function()
40325 s = ['<tpl>', s, '</tpl>'].join('');
40327 var re = /<tpl\b[^>]*>((?:(?=([^<]+))\2|<(?!tpl\b[^>]*>))*?)<\/tpl>/,
40328 nameRe = /^<tpl\b[^>]*?for="(.*?)"/,
40329 ifRe = /^<tpl\b[^>]*?if="(.*?)"/,
40330 execRe = /^<tpl\b[^>]*?exec="(.*?)"/,
40331 namedRe = /^<tpl\b[^>]*?name="(\w+)"/, // named templates..
40336 while(true == !!(m = s.match(re))){
40337 var forMatch = m[0].match(nameRe),
40338 ifMatch = m[0].match(ifRe),
40339 execMatch = m[0].match(execRe),
40340 namedMatch = m[0].match(namedRe),
40345 name = forMatch && forMatch[1] ? forMatch[1] : '';
40348 // if - puts fn into test..
40349 exp = ifMatch && ifMatch[1] ? ifMatch[1] : null;
40351 fn = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(exp))+'; }');
40356 // exec - calls a function... returns empty if true is returned.
40357 exp = execMatch && execMatch[1] ? execMatch[1] : null;
40359 exec = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(exp))+'; }');
40367 case '.': name = new Function('values', 'parent', 'with(values){ return values; }'); break;
40368 case '..': name = new Function('values', 'parent', 'with(values){ return parent; }'); break;
40369 default: name = new Function('values', 'parent', 'with(values){ return '+name+'; }');
40372 var uid = namedMatch ? namedMatch[1] : id;
40376 id: namedMatch ? namedMatch[1] : id,
40383 s = s.replace(m[0], '');
40385 s = s.replace(m[0], '{xtpl'+ id + '}');
40390 for(var i = tpls.length-1; i >= 0; --i){
40391 this.compileTpl(tpls[i]);
40392 this.tpls[tpls[i].id] = tpls[i];
40394 this.master = tpls[tpls.length-1];
40398 * same as applyTemplate, except it's done to one of the subTemplates
40399 * when using named templates, you can do:
40401 * var str = pl.applySubTemplate('your-name', values);
40404 * @param {Number} id of the template
40405 * @param {Object} values to apply to template
40406 * @param {Object} parent (normaly the instance of this object)
40408 applySubTemplate : function(id, values, parent)
40412 var t = this.tpls[id];
40416 if(t.test && !t.test.call(this, values, parent)){
40420 Roo.log("Xtemplate.applySubTemplate 'test': Exception thrown");
40421 Roo.log(e.toString());
40427 if(t.exec && t.exec.call(this, values, parent)){
40431 Roo.log("Xtemplate.applySubTemplate 'exec': Exception thrown");
40432 Roo.log(e.toString());
40437 var vs = t.target ? t.target.call(this, values, parent) : values;
40438 parent = t.target ? values : parent;
40439 if(t.target && vs instanceof Array){
40441 for(var i = 0, len = vs.length; i < len; i++){
40442 buf[buf.length] = t.compiled.call(this, vs[i], parent);
40444 return buf.join('');
40446 return t.compiled.call(this, vs, parent);
40448 Roo.log("Xtemplate.applySubTemplate : Exception thrown");
40449 Roo.log(e.toString());
40450 Roo.log(t.compiled);
40455 compileTpl : function(tpl)
40457 var fm = Roo.util.Format;
40458 var useF = this.disableFormats !== true;
40459 var sep = Roo.isGecko ? "+" : ",";
40460 var undef = function(str) {
40461 Roo.log("Property not found :" + str);
40465 var fn = function(m, name, format, args)
40467 //Roo.log(arguments);
40468 args = args ? args.replace(/\\'/g,"'") : args;
40469 //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
40470 if (typeof(format) == 'undefined') {
40471 format= 'htmlEncode';
40473 if (format == 'raw' ) {
40477 if(name.substr(0, 4) == 'xtpl'){
40478 return "'"+ sep +'this.applySubTemplate('+name.substr(4)+', values, parent)'+sep+"'";
40481 // build an array of options to determine if value is undefined..
40483 // basically get 'xxxx.yyyy' then do
40484 // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
40485 // (function () { Roo.log("Property not found"); return ''; })() :
40490 Roo.each(name.split('.'), function(st) {
40491 lookfor += (lookfor.length ? '.': '') + st;
40492 udef_ar.push( "(typeof(" + lookfor + ") == 'undefined')" );
40495 var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
40498 if(format && useF){
40500 args = args ? ',' + args : "";
40502 if(format.substr(0, 5) != "this."){
40503 format = "fm." + format + '(';
40505 format = 'this.call("'+ format.substr(5) + '", ';
40509 return "'"+ sep + udef_st + format + name + args + "))"+sep+"'";
40513 // called with xxyx.yuu:(test,test)
40515 return "'"+ sep + udef_st + name + '(' + args + "))"+sep+"'";
40517 // raw.. - :raw modifier..
40518 return "'"+ sep + udef_st + name + ")"+sep+"'";
40522 // branched to use + in gecko and [].join() in others
40524 body = "tpl.compiled = function(values, parent){ with(values) { return '" +
40525 tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
40528 body = ["tpl.compiled = function(values, parent){ with (values) { return ['"];
40529 body.push(tpl.body.replace(/(\r\n|\n)/g,
40530 '\\n').replace(/'/g, "\\'").replace(this.re, fn));
40531 body.push("'].join('');};};");
40532 body = body.join('');
40535 Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
40537 /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef */
40543 applyTemplate : function(values){
40544 return this.master.compiled.call(this, values, {});
40545 //var s = this.subs;
40548 apply : function(){
40549 return this.applyTemplate.apply(this, arguments);
40554 Roo.XTemplate.from = function(el){
40555 el = Roo.getDom(el);
40556 return new Roo.XTemplate(el.value || el.innerHTML);
40558 * Original code for Roojs - LGPL
40559 * <script type="text/javascript">
40563 * @class Roo.XComponent
40564 * A delayed Element creator...
40565 * Or a way to group chunks of interface together.
40567 * Mypart.xyx = new Roo.XComponent({
40569 parent : 'Mypart.xyz', // empty == document.element.!!
40573 disabled : function() {}
40575 tree : function() { // return an tree of xtype declared components
40579 xtype : 'NestedLayoutPanel',
40586 * It can be used to build a big heiracy, with parent etc.
40587 * or you can just use this to render a single compoent to a dom element
40588 * MYPART.render(Roo.Element | String(id) | dom_element )
40590 * @extends Roo.util.Observable
40592 * @param cfg {Object} configuration of component
40595 Roo.XComponent = function(cfg) {
40596 Roo.apply(this, cfg);
40600 * Fires when this the componnt is built
40601 * @param {Roo.XComponent} c the component
40606 this.region = this.region || 'center'; // default..
40607 Roo.XComponent.register(this);
40608 this.modules = false;
40609 this.el = false; // where the layout goes..
40613 Roo.extend(Roo.XComponent, Roo.util.Observable, {
40616 * The created element (with Roo.factory())
40617 * @type {Roo.Layout}
40623 * for BC - use el in new code
40624 * @type {Roo.Layout}
40630 * for BC - use el in new code
40631 * @type {Roo.Layout}
40636 * @cfg {Function|boolean} disabled
40637 * If this module is disabled by some rule, return true from the funtion
40642 * @cfg {String} parent
40643 * Name of parent element which it get xtype added to..
40648 * @cfg {String} order
40649 * Used to set the order in which elements are created (usefull for multiple tabs)
40654 * @cfg {String} name
40655 * String to display while loading.
40659 * @cfg {String} region
40660 * Region to render component to (defaults to center)
40665 * @cfg {Array} items
40666 * A single item array - the first element is the root of the tree..
40667 * It's done this way to stay compatible with the Xtype system...
40673 * The method that retuns the tree of parts that make up this compoennt
40680 * render element to dom or tree
40681 * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
40684 render : function(el)
40688 var hp = this.parent ? 1 : 0;
40690 if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
40691 // if parent is a '#.....' string, then let's use that..
40692 var ename = this.parent.substr(1)
40693 this.parent = false;
40694 el = Roo.get(ename);
40696 Roo.log("Warning - element can not be found :#" + ename );
40702 if (!this.parent) {
40704 el = el ? Roo.get(el) : false;
40706 // it's a top level one..
40708 el : new Roo.BorderLayout(el || document.body, {
40714 tabPosition: 'top',
40715 //resizeTabs: true,
40716 alwaysShowTabs: el && hp? false : true,
40717 hideTabs: el || !hp ? true : false,
40724 if (!this.parent.el) {
40725 // probably an old style ctor, which has been disabled.
40729 // The 'tree' method is '_tree now'
40731 var tree = this._tree ? this._tree() : this.tree();
40732 tree.region = tree.region || this.region;
40733 this.el = this.parent.el.addxtype(tree);
40734 this.fireEvent('built', this);
40736 this.panel = this.el;
40737 this.layout = this.panel.layout;
40738 this.parentLayout = this.parent.layout || false;
40744 Roo.apply(Roo.XComponent, {
40746 * @property hideProgress
40747 * true to disable the building progress bar.. usefull on single page renders.
40750 hideProgress : false,
40752 * @property buildCompleted
40753 * True when the builder has completed building the interface.
40756 buildCompleted : false,
40759 * @property topModule
40760 * the upper most module - uses document.element as it's constructor.
40767 * @property modules
40768 * array of modules to be created by registration system.
40769 * @type {Array} of Roo.XComponent
40774 * @property elmodules
40775 * array of modules to be created by which use #ID
40776 * @type {Array} of Roo.XComponent
40783 * Register components to be built later.
40785 * This solves the following issues
40786 * - Building is not done on page load, but after an authentication process has occured.
40787 * - Interface elements are registered on page load
40788 * - Parent Interface elements may not be loaded before child, so this handles that..
40795 module : 'Pman.Tab.projectMgr',
40797 parent : 'Pman.layout',
40798 disabled : false, // or use a function..
40801 * * @param {Object} details about module
40803 register : function(obj) {
40805 Roo.XComponent.event.fireEvent('register', obj);
40806 switch(typeof(obj.disabled) ) {
40812 if ( obj.disabled() ) {
40818 if (obj.disabled) {
40824 this.modules.push(obj);
40828 * convert a string to an object..
40829 * eg. 'AAA.BBB' -> finds AAA.BBB
40833 toObject : function(str)
40835 if (!str || typeof(str) == 'object') {
40838 if (str.substring(0,1) == '#') {
40842 var ar = str.split('.');
40847 eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
40849 throw "Module not found : " + str;
40853 throw "Module not found : " + str;
40855 Roo.each(ar, function(e) {
40856 if (typeof(o[e]) == 'undefined') {
40857 throw "Module not found : " + str;
40868 * move modules into their correct place in the tree..
40871 preBuild : function ()
40874 Roo.each(this.modules , function (obj)
40876 Roo.XComponent.event.fireEvent('beforebuild', obj);
40878 var opar = obj.parent;
40880 obj.parent = this.toObject(opar);
40882 Roo.log("parent:toObject failed: " + e.toString());
40887 Roo.debug && Roo.log("GOT top level module");
40888 Roo.debug && Roo.log(obj);
40889 obj.modules = new Roo.util.MixedCollection(false,
40890 function(o) { return o.order + '' }
40892 this.topModule = obj;
40895 // parent is a string (usually a dom element name..)
40896 if (typeof(obj.parent) == 'string') {
40897 this.elmodules.push(obj);
40900 if (obj.parent.constructor != Roo.XComponent) {
40901 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
40903 if (!obj.parent.modules) {
40904 obj.parent.modules = new Roo.util.MixedCollection(false,
40905 function(o) { return o.order + '' }
40908 if (obj.parent.disabled) {
40909 obj.disabled = true;
40911 obj.parent.modules.add(obj);
40916 * make a list of modules to build.
40917 * @return {Array} list of modules.
40920 buildOrder : function()
40923 var cmp = function(a,b) {
40924 return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
40926 if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
40927 throw "No top level modules to build";
40930 // make a flat list in order of modules to build.
40931 var mods = this.topModule ? [ this.topModule ] : [];
40934 // elmodules (is a list of DOM based modules )
40935 Roo.each(this.elmodules, function(e) {
40937 if (!this.topModule &&
40938 typeof(e.parent) == 'string' &&
40939 e.parent.substring(0,1) == '#' &&
40940 Roo.get(e.parent.substr(1))
40943 _this.topModule = e;
40949 // add modules to their parents..
40950 var addMod = function(m) {
40951 Roo.debug && Roo.log("build Order: add: " + m.name);
40954 if (m.modules && !m.disabled) {
40955 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
40956 m.modules.keySort('ASC', cmp );
40957 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
40959 m.modules.each(addMod);
40961 Roo.debug && Roo.log("build Order: no child modules");
40963 // not sure if this is used any more..
40965 m.finalize.name = m.name + " (clean up) ";
40966 mods.push(m.finalize);
40970 if (this.topModule && this.topModule.modules) {
40971 this.topModule.modules.keySort('ASC', cmp );
40972 this.topModule.modules.each(addMod);
40978 * Build the registered modules.
40979 * @param {Object} parent element.
40980 * @param {Function} optional method to call after module has been added.
40988 var mods = this.buildOrder();
40990 //this.allmods = mods;
40991 //Roo.debug && Roo.log(mods);
40993 if (!mods.length) { // should not happen
40994 throw "NO modules!!!";
40998 var msg = "Building Interface...";
40999 // flash it up as modal - so we store the mask!?
41000 if (!this.hideProgress) {
41001 Roo.MessageBox.show({ title: 'loading' });
41002 Roo.MessageBox.show({
41003 title: "Please wait...",
41012 var total = mods.length;
41015 var progressRun = function() {
41016 if (!mods.length) {
41017 Roo.debug && Roo.log('hide?');
41018 if (!this.hideProgress) {
41019 Roo.MessageBox.hide();
41021 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
41027 var m = mods.shift();
41030 Roo.debug && Roo.log(m);
41031 // not sure if this is supported any more.. - modules that are are just function
41032 if (typeof(m) == 'function') {
41034 return progressRun.defer(10, _this);
41038 msg = "Building Interface " + (total - mods.length) +
41040 (m.name ? (' - ' + m.name) : '');
41041 Roo.debug && Roo.log(msg);
41042 if (!this.hideProgress) {
41043 Roo.MessageBox.updateProgress( (total - mods.length)/total, msg );
41047 // is the module disabled?
41048 var disabled = (typeof(m.disabled) == 'function') ?
41049 m.disabled.call(m.module.disabled) : m.disabled;
41053 return progressRun(); // we do not update the display!
41061 // it's 10 on top level, and 1 on others??? why...
41062 return progressRun.defer(10, _this);
41065 progressRun.defer(1, _this);
41079 * wrapper for event.on - aliased later..
41080 * Typically use to register a event handler for register:
41082 * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
41091 Roo.XComponent.event = new Roo.util.Observable({
41095 * Fires when an Component is registered,
41096 * set the disable property on the Component to stop registration.
41097 * @param {Roo.XComponent} c the component being registerd.
41102 * @event beforebuild
41103 * Fires before each Component is built
41104 * can be used to apply permissions.
41105 * @param {Roo.XComponent} c the component being registerd.
41108 'beforebuild' : true,
41110 * @event buildcomplete
41111 * Fires on the top level element when all elements have been built
41112 * @param {Roo.XComponent} the top level component.
41114 'buildcomplete' : true
41119 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event);