4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 Roo.dd.DropTarget.superclass.constructor.call( this,
3902 this.ddGroup || this.group,
3907 * @scope Roo.dd.DropTarget
3912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3916 * IMPORTANT : it should set this.overClass and this.dropAllowed
3918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919 * @param {Event} e The event
3920 * @param {Object} data An object containing arbitrary data supplied by the drag source
3926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927 * This method will be called on every mouse movement while the drag source is over the drop target.
3928 * This default implementation simply returns the dropAllowed config value.
3930 * IMPORTANT : it should set this.dropAllowed
3932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933 * @param {Event} e The event
3934 * @param {Object} data An object containing arbitrary data supplied by the drag source
3940 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3942 * overClass (if any) from the drop element.
3943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944 * @param {Event} e The event
3945 * @param {Object} data An object containing arbitrary data supplied by the drag source
3951 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3953 * implementation that does something to process the drop event and returns true so that the drag source's
3954 * repair action does not run.
3956 * IMPORTANT : it should set this.success
3958 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959 * @param {Event} e The event
3960 * @param {Object} data An object containing arbitrary data supplied by the drag source
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973 * @cfg {String} overClass
3974 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3977 * @cfg {String} dropAllowed
3978 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3980 dropAllowed : "x-dd-drop-ok",
3982 * @cfg {String} dropNotAllowed
3983 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3985 dropNotAllowed : "x-dd-drop-nodrop",
3987 * @cfg {boolean} success
3988 * set this after drop listener..
3992 * @cfg {boolean} valid
3993 * if the drop point is valid for over/enter..
4000 isNotifyTarget : true,
4004 notifyEnter : function(dd, e, data){
4006 this.fireEvent('enter', this, dd, e, data);
4008 this.el.addClass(this.overClass);
4010 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4015 notifyOver : function(dd, e, data){
4017 this.fireEvent('over', this, dd, e, data);
4018 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOut : function(dd, e, data){
4023 this.fireEvent('out', this, dd, e, data);
4025 this.el.removeClass(this.overClass);
4030 notifyDrop : function(dd, e, data){
4031 this.success = false;
4032 this.fireEvent('drop', this, dd, e, data);
4033 return this.success;
4037 * Ext JS Library 1.1.1
4038 * Copyright(c) 2006-2007, Ext JS, LLC.
4040 * Originally Released Under LGPL - original licence link has changed is not relivant.
4043 * <script type="text/javascript">
4048 * @class Roo.dd.DragZone
4049 * @extends Roo.dd.DragSource
4050 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4051 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4053 * @param {String/HTMLElement/Element} el The container element
4054 * @param {Object} config
4056 Roo.dd.DragZone = function(el, config){
4057 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4058 if(this.containerScroll){
4059 Roo.dd.ScrollManager.register(this.el);
4063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4065 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4066 * for auto scrolling during drag operations.
4069 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4070 * method after a failed drop (defaults to "c3daf9" - light blue)
4074 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4075 * for a valid target to drag based on the mouse down. Override this method
4076 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4077 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4078 * @param {EventObject} e The mouse down event
4079 * @return {Object} The dragData
4081 getDragData : function(e){
4082 return Roo.dd.Registry.getHandleFromEvent(e);
4086 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4087 * this.dragData.ddel
4088 * @param {Number} x The x position of the click on the dragged object
4089 * @param {Number} y The y position of the click on the dragged object
4090 * @return {Boolean} true to continue the drag, false to cancel
4092 onInitDrag : function(x, y){
4093 this.proxy.update(this.dragData.ddel.cloneNode(true));
4094 this.onStartDrag(x, y);
4099 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4101 afterRepair : function(){
4103 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4105 this.dragging = false;
4109 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4110 * the XY of this.dragData.ddel
4111 * @param {EventObject} e The mouse up event
4112 * @return {Array} The xy location (e.g. [100, 200])
4114 getRepairXY : function(e){
4115 return Roo.Element.fly(this.dragData.ddel).getXY();
4119 * Ext JS Library 1.1.1
4120 * Copyright(c) 2006-2007, Ext JS, LLC.
4122 * Originally Released Under LGPL - original licence link has changed is not relivant.
4125 * <script type="text/javascript">
4128 * @class Roo.dd.DropZone
4129 * @extends Roo.dd.DropTarget
4130 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4131 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4133 * @param {String/HTMLElement/Element} el The container element
4134 * @param {Object} config
4136 Roo.dd.DropZone = function(el, config){
4137 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4142 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4143 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4144 * provide your own custom lookup.
4145 * @param {Event} e The event
4146 * @return {Object} data The custom data
4148 getTargetFromEvent : function(e){
4149 return Roo.dd.Registry.getTargetFromEvent(e);
4153 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4154 * that it has registered. This method has no default implementation and should be overridden to provide
4155 * node-specific processing if necessary.
4156 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4157 * {@link #getTargetFromEvent} for this node)
4158 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4159 * @param {Event} e The event
4160 * @param {Object} data An object containing arbitrary data supplied by the drag source
4162 onNodeEnter : function(n, dd, e, data){
4167 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4168 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4169 * overridden to provide the proper feedback.
4170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4171 * {@link #getTargetFromEvent} for this node)
4172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4173 * @param {Event} e The event
4174 * @param {Object} data An object containing arbitrary data supplied by the drag source
4175 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4176 * underlying {@link Roo.dd.StatusProxy} can be updated
4178 onNodeOver : function(n, dd, e, data){
4179 return this.dropAllowed;
4183 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4184 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4185 * node-specific processing if necessary.
4186 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4187 * {@link #getTargetFromEvent} for this node)
4188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4189 * @param {Event} e The event
4190 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 onNodeOut : function(n, dd, e, data){
4197 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4198 * the drop node. The default implementation returns false, so it should be overridden to provide the
4199 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4200 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4201 * {@link #getTargetFromEvent} for this node)
4202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4203 * @param {Event} e The event
4204 * @param {Object} data An object containing arbitrary data supplied by the drag source
4205 * @return {Boolean} True if the drop was valid, else false
4207 onNodeDrop : function(n, dd, e, data){
4212 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4213 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4214 * it should be overridden to provide the proper feedback if necessary.
4215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216 * @param {Event} e The event
4217 * @param {Object} data An object containing arbitrary data supplied by the drag source
4218 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4219 * underlying {@link Roo.dd.StatusProxy} can be updated
4221 onContainerOver : function(dd, e, data){
4222 return this.dropNotAllowed;
4226 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4227 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4228 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4229 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4231 * @param {Event} e The event
4232 * @param {Object} data An object containing arbitrary data supplied by the drag source
4233 * @return {Boolean} True if the drop was valid, else false
4235 onContainerDrop : function(dd, e, data){
4240 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4241 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4242 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4243 * you should override this method and provide a custom implementation.
4244 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4245 * @param {Event} e The event
4246 * @param {Object} data An object containing arbitrary data supplied by the drag source
4247 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4248 * underlying {@link Roo.dd.StatusProxy} can be updated
4250 notifyEnter : function(dd, e, data){
4251 return this.dropNotAllowed;
4255 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4256 * This method will be called on every mouse movement while the drag source is over the drop zone.
4257 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4258 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4259 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4260 * registered node, it will call {@link #onContainerOver}.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyOver : function(dd, e, data){
4268 var n = this.getTargetFromEvent(e);
4269 if(!n){ // not over valid drop target
4270 if(this.lastOverNode){
4271 this.onNodeOut(this.lastOverNode, dd, e, data);
4272 this.lastOverNode = null;
4274 return this.onContainerOver(dd, e, data);
4276 if(this.lastOverNode != n){
4277 if(this.lastOverNode){
4278 this.onNodeOut(this.lastOverNode, dd, e, data);
4280 this.onNodeEnter(n, dd, e, data);
4281 this.lastOverNode = n;
4283 return this.onNodeOver(n, dd, e, data);
4287 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4288 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4289 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4291 * @param {Event} e The event
4292 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4294 notifyOut : function(dd, e, data){
4295 if(this.lastOverNode){
4296 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.lastOverNode = null;
4302 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4303 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4304 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4305 * otherwise it will call {@link #onContainerDrop}.
4306 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4307 * @param {Event} e The event
4308 * @param {Object} data An object containing arbitrary data supplied by the drag source
4309 * @return {Boolean} True if the drop was valid, else false
4311 notifyDrop : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4316 var n = this.getTargetFromEvent(e);
4318 this.onNodeDrop(n, dd, e, data) :
4319 this.onContainerDrop(dd, e, data);
4323 triggerCacheRefresh : function(){
4324 Roo.dd.DDM.refreshCache(this.groups);
4328 * Ext JS Library 1.1.1
4329 * Copyright(c) 2006-2007, Ext JS, LLC.
4331 * Originally Released Under LGPL - original licence link has changed is not relivant.
4334 * <script type="text/javascript">
4339 * @class Roo.data.SortTypes
4341 * Defines the default sorting (casting?) comparison functions used when sorting data.
4343 Roo.data.SortTypes = {
4345 * Default sort that does nothing
4346 * @param {Mixed} s The value being converted
4347 * @return {Mixed} The comparison value
4354 * The regular expression used to strip tags
4358 stripTagsRE : /<\/?[^>]+>/gi,
4361 * Strips all HTML tags to sort on text only
4362 * @param {Mixed} s The value being converted
4363 * @return {String} The comparison value
4365 asText : function(s){
4366 return String(s).replace(this.stripTagsRE, "");
4370 * Strips all HTML tags to sort on text only - Case insensitive
4371 * @param {Mixed} s The value being converted
4372 * @return {String} The comparison value
4374 asUCText : function(s){
4375 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4379 * Case insensitive string
4380 * @param {Mixed} s The value being converted
4381 * @return {String} The comparison value
4383 asUCString : function(s) {
4384 return String(s).toUpperCase();
4389 * @param {Mixed} s The value being converted
4390 * @return {Number} The comparison value
4392 asDate : function(s) {
4396 if(s instanceof Date){
4399 return Date.parse(String(s));
4404 * @param {Mixed} s The value being converted
4405 * @return {Float} The comparison value
4407 asFloat : function(s) {
4408 var val = parseFloat(String(s).replace(/,/g, ""));
4409 if(isNaN(val)) val = 0;
4415 * @param {Mixed} s The value being converted
4416 * @return {Number} The comparison value
4418 asInt : function(s) {
4419 var val = parseInt(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4425 * Ext JS Library 1.1.1
4426 * Copyright(c) 2006-2007, Ext JS, LLC.
4428 * Originally Released Under LGPL - original licence link has changed is not relivant.
4431 * <script type="text/javascript">
4435 * @class Roo.data.Record
4436 * Instances of this class encapsulate both record <em>definition</em> information, and record
4437 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4438 * to access Records cached in an {@link Roo.data.Store} object.<br>
4440 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4441 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4444 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4446 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4447 * {@link #create}. The parameters are the same.
4448 * @param {Array} data An associative Array of data values keyed by the field name.
4449 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4450 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4451 * not specified an integer id is generated.
4453 Roo.data.Record = function(data, id){
4454 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4459 * Generate a constructor for a specific record layout.
4460 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4461 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4462 * Each field definition object may contain the following properties: <ul>
4463 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4464 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4465 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4466 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4467 * is being used, then this is a string containing the javascript expression to reference the data relative to
4468 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4469 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4470 * this may be omitted.</p></li>
4471 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4472 * <ul><li>auto (Default, implies no conversion)</li>
4477 * <li>date</li></ul></p></li>
4478 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4479 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4480 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4481 * by the Reader into an object that will be stored in the Record. It is passed the
4482 * following parameters:<ul>
4483 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4485 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4487 * <br>usage:<br><pre><code>
4488 var TopicRecord = Roo.data.Record.create(
4489 {name: 'title', mapping: 'topic_title'},
4490 {name: 'author', mapping: 'username'},
4491 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4492 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4493 {name: 'lastPoster', mapping: 'user2'},
4494 {name: 'excerpt', mapping: 'post_text'}
4497 var myNewRecord = new TopicRecord({
4498 title: 'Do my job please',
4501 lastPost: new Date(),
4502 lastPoster: 'Animal',
4503 excerpt: 'No way dude!'
4505 myStore.add(myNewRecord);
4510 Roo.data.Record.create = function(o){
4512 f.superclass.constructor.apply(this, arguments);
4514 Roo.extend(f, Roo.data.Record);
4515 var p = f.prototype;
4516 p.fields = new Roo.util.MixedCollection(false, function(field){
4519 for(var i = 0, len = o.length; i < len; i++){
4520 p.fields.add(new Roo.data.Field(o[i]));
4522 f.getField = function(name){
4523 return p.fields.get(name);
4528 Roo.data.Record.AUTO_ID = 1000;
4529 Roo.data.Record.EDIT = 'edit';
4530 Roo.data.Record.REJECT = 'reject';
4531 Roo.data.Record.COMMIT = 'commit';
4533 Roo.data.Record.prototype = {
4535 * Readonly flag - true if this record has been modified.
4544 join : function(store){
4549 * Set the named field to the specified value.
4550 * @param {String} name The name of the field to set.
4551 * @param {Object} value The value to set the field to.
4553 set : function(name, value){
4554 if(this.data[name] == value){
4561 if(typeof this.modified[name] == 'undefined'){
4562 this.modified[name] = this.data[name];
4564 this.data[name] = value;
4566 this.store.afterEdit(this);
4571 * Get the value of the named field.
4572 * @param {String} name The name of the field to get the value of.
4573 * @return {Object} The value of the field.
4575 get : function(name){
4576 return this.data[name];
4580 beginEdit : function(){
4581 this.editing = true;
4586 cancelEdit : function(){
4587 this.editing = false;
4588 delete this.modified;
4592 endEdit : function(){
4593 this.editing = false;
4594 if(this.dirty && this.store){
4595 this.store.afterEdit(this);
4600 * Usually called by the {@link Roo.data.Store} which owns the Record.
4601 * Rejects all changes made to the Record since either creation, or the last commit operation.
4602 * Modified fields are reverted to their original values.
4604 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4605 * of reject operations.
4607 reject : function(){
4608 var m = this.modified;
4610 if(typeof m[n] != "function"){
4611 this.data[n] = m[n];
4615 delete this.modified;
4616 this.editing = false;
4618 this.store.afterReject(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Commits all changes made to the Record since either creation, or the last commit operation.
4626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627 * of commit operations.
4629 commit : function(){
4631 delete this.modified;
4632 this.editing = false;
4634 this.store.afterCommit(this);
4639 hasError : function(){
4640 return this.error != null;
4644 clearError : function(){
4649 * Creates a copy of this record.
4650 * @param {String} id (optional) A new record id if you don't want to use this record's id
4653 copy : function(newId) {
4654 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4658 * Ext JS Library 1.1.1
4659 * Copyright(c) 2006-2007, Ext JS, LLC.
4661 * Originally Released Under LGPL - original licence link has changed is not relivant.
4664 * <script type="text/javascript">
4670 * @class Roo.data.Store
4671 * @extends Roo.util.Observable
4672 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4673 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4675 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4676 * has no knowledge of the format of the data returned by the Proxy.<br>
4678 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4679 * instances from the data object. These records are cached and made available through accessor functions.
4681 * Creates a new Store.
4682 * @param {Object} config A config object containing the objects needed for the Store to access data,
4683 * and read the data into Records.
4685 Roo.data.Store = function(config){
4686 this.data = new Roo.util.MixedCollection(false);
4687 this.data.getKey = function(o){
4690 this.baseParams = {};
4699 if(config && config.data){
4700 this.inlineData = config.data;
4704 Roo.apply(this, config);
4706 if(this.reader){ // reader passed
4707 this.reader = Roo.factory(this.reader, Roo.data);
4708 this.reader.xmodule = this.xmodule || false;
4709 if(!this.recordType){
4710 this.recordType = this.reader.recordType;
4712 if(this.reader.onMetaChange){
4713 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4717 if(this.recordType){
4718 this.fields = this.recordType.prototype.fields;
4724 * @event datachanged
4725 * Fires when the data cache has changed, and a widget which is using this Store
4726 * as a Record cache should refresh its view.
4727 * @param {Store} this
4732 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4733 * @param {Store} this
4734 * @param {Object} meta The JSON metadata
4739 * Fires when Records have been added to the Store
4740 * @param {Store} this
4741 * @param {Roo.data.Record[]} records The array of Records added
4742 * @param {Number} index The index at which the record(s) were added
4747 * Fires when a Record has been removed from the Store
4748 * @param {Store} this
4749 * @param {Roo.data.Record} record The Record that was removed
4750 * @param {Number} index The index at which the record was removed
4755 * Fires when a Record has been updated
4756 * @param {Store} this
4757 * @param {Roo.data.Record} record The Record that was updated
4758 * @param {String} operation The update operation being performed. Value may be one of:
4760 Roo.data.Record.EDIT
4761 Roo.data.Record.REJECT
4762 Roo.data.Record.COMMIT
4768 * Fires when the data cache has been cleared.
4769 * @param {Store} this
4774 * Fires before a request is made for a new data object. If the beforeload handler returns false
4775 * the load action will be canceled.
4776 * @param {Store} this
4777 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4782 * Fires after a new set of Records has been loaded.
4783 * @param {Store} this
4784 * @param {Roo.data.Record[]} records The Records that were loaded
4785 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4789 * @event loadexception
4790 * Fires if an exception occurs in the Proxy during loading.
4791 * Called with the signature of the Proxy's "loadexception" event.
4792 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4795 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4796 * @param {Object} load options
4797 * @param {Object} jsonData from your request (normally this contains the Exception)
4799 loadexception : true
4803 this.proxy = Roo.factory(this.proxy, Roo.data);
4804 this.proxy.xmodule = this.xmodule || false;
4805 this.relayEvents(this.proxy, ["loadexception"]);
4807 this.sortToggle = {};
4809 Roo.data.Store.superclass.constructor.call(this);
4811 if(this.inlineData){
4812 this.loadData(this.inlineData);
4813 delete this.inlineData;
4816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4818 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4819 * without a remote query - used by combo/forms at present.
4823 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4826 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4829 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4830 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4833 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4834 * on any HTTP request
4837 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4840 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4841 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4846 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4847 * loaded or when a record is removed. (defaults to false).
4849 pruneModifiedRecords : false,
4855 * Add Records to the Store and fires the add event.
4856 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4858 add : function(records){
4859 records = [].concat(records);
4860 for(var i = 0, len = records.length; i < len; i++){
4861 records[i].join(this);
4863 var index = this.data.length;
4864 this.data.addAll(records);
4865 this.fireEvent("add", this, records, index);
4869 * Remove a Record from the Store and fires the remove event.
4870 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4872 remove : function(record){
4873 var index = this.data.indexOf(record);
4874 this.data.removeAt(index);
4875 if(this.pruneModifiedRecords){
4876 this.modified.remove(record);
4878 this.fireEvent("remove", this, record, index);
4882 * Remove all Records from the Store and fires the clear event.
4884 removeAll : function(){
4886 if(this.pruneModifiedRecords){
4889 this.fireEvent("clear", this);
4893 * Inserts Records to the Store at the given index and fires the add event.
4894 * @param {Number} index The start index at which to insert the passed Records.
4895 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4897 insert : function(index, records){
4898 records = [].concat(records);
4899 for(var i = 0, len = records.length; i < len; i++){
4900 this.data.insert(index, records[i]);
4901 records[i].join(this);
4903 this.fireEvent("add", this, records, index);
4907 * Get the index within the cache of the passed Record.
4908 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4909 * @return {Number} The index of the passed Record. Returns -1 if not found.
4911 indexOf : function(record){
4912 return this.data.indexOf(record);
4916 * Get the index within the cache of the Record with the passed id.
4917 * @param {String} id The id of the Record to find.
4918 * @return {Number} The index of the Record. Returns -1 if not found.
4920 indexOfId : function(id){
4921 return this.data.indexOfKey(id);
4925 * Get the Record with the specified id.
4926 * @param {String} id The id of the Record to find.
4927 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4929 getById : function(id){
4930 return this.data.key(id);
4934 * Get the Record at the specified index.
4935 * @param {Number} index The index of the Record to find.
4936 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4938 getAt : function(index){
4939 return this.data.itemAt(index);
4943 * Returns a range of Records between specified indices.
4944 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4945 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4946 * @return {Roo.data.Record[]} An array of Records
4948 getRange : function(start, end){
4949 return this.data.getRange(start, end);
4953 storeOptions : function(o){
4954 o = Roo.apply({}, o);
4957 this.lastOptions = o;
4961 * Loads the Record cache from the configured Proxy using the configured Reader.
4963 * If using remote paging, then the first load call must specify the <em>start</em>
4964 * and <em>limit</em> properties in the options.params property to establish the initial
4965 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4967 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4968 * and this call will return before the new data has been loaded. Perform any post-processing
4969 * in a callback function, or in a "load" event handler.</strong>
4971 * @param {Object} options An object containing properties which control loading options:<ul>
4972 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4973 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4974 * passed the following arguments:<ul>
4975 * <li>r : Roo.data.Record[]</li>
4976 * <li>options: Options object from the load call</li>
4977 * <li>success: Boolean success indicator</li></ul></li>
4978 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4979 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4982 load : function(options){
4983 options = options || {};
4984 if(this.fireEvent("beforeload", this, options) !== false){
4985 this.storeOptions(options);
4986 var p = Roo.apply(options.params || {}, this.baseParams);
4987 // if meta was not loaded from remote source.. try requesting it.
4988 if (!this.reader.metaFromRemote) {
4991 if(this.sortInfo && this.remoteSort){
4992 var pn = this.paramNames;
4993 p[pn["sort"]] = this.sortInfo.field;
4994 p[pn["dir"]] = this.sortInfo.direction;
4996 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5001 * Reloads the Record cache from the configured Proxy using the configured Reader and
5002 * the options from the last load operation performed.
5003 * @param {Object} options (optional) An object containing properties which may override the options
5004 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5005 * the most recently used options are reused).
5007 reload : function(options){
5008 this.load(Roo.applyIf(options||{}, this.lastOptions));
5012 // Called as a callback by the Reader during a load operation.
5013 loadRecords : function(o, options, success){
5014 if(!o || success === false){
5015 if(success !== false){
5016 this.fireEvent("load", this, [], options);
5018 if(options.callback){
5019 options.callback.call(options.scope || this, [], options, false);
5023 // if data returned failure - throw an exception.
5024 if (o.success === false) {
5025 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5028 var r = o.records, t = o.totalRecords || r.length;
5029 if(!options || options.add !== true){
5030 if(this.pruneModifiedRecords){
5033 for(var i = 0, len = r.length; i < len; i++){
5037 this.data = this.snapshot;
5038 delete this.snapshot;
5041 this.data.addAll(r);
5042 this.totalLength = t;
5044 this.fireEvent("datachanged", this);
5046 this.totalLength = Math.max(t, this.data.length+r.length);
5049 this.fireEvent("load", this, r, options);
5050 if(options.callback){
5051 options.callback.call(options.scope || this, r, options, true);
5056 * Loads data from a passed data block. A Reader which understands the format of the data
5057 * must have been configured in the constructor.
5058 * @param {Object} data The data block from which to read the Records. The format of the data expected
5059 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5060 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5062 loadData : function(o, append){
5063 var r = this.reader.readRecords(o);
5064 this.loadRecords(r, {add: append}, true);
5068 * Gets the number of cached records.
5070 * <em>If using paging, this may not be the total size of the dataset. If the data object
5071 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5072 * the data set size</em>
5074 getCount : function(){
5075 return this.data.length || 0;
5079 * Gets the total number of records in the dataset as returned by the server.
5081 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5082 * the dataset size</em>
5084 getTotalCount : function(){
5085 return this.totalLength || 0;
5089 * Returns the sort state of the Store as an object with two properties:
5091 field {String} The name of the field by which the Records are sorted
5092 direction {String} The sort order, "ASC" or "DESC"
5095 getSortState : function(){
5096 return this.sortInfo;
5100 applySort : function(){
5101 if(this.sortInfo && !this.remoteSort){
5102 var s = this.sortInfo, f = s.field;
5103 var st = this.fields.get(f).sortType;
5104 var fn = function(r1, r2){
5105 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5106 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5108 this.data.sort(s.direction, fn);
5109 if(this.snapshot && this.snapshot != this.data){
5110 this.snapshot.sort(s.direction, fn);
5116 * Sets the default sort column and order to be used by the next load operation.
5117 * @param {String} fieldName The name of the field to sort by.
5118 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5120 setDefaultSort : function(field, dir){
5121 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5126 * If remote sorting is used, the sort is performed on the server, and the cache is
5127 * reloaded. If local sorting is used, the cache is sorted internally.
5128 * @param {String} fieldName The name of the field to sort by.
5129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131 sort : function(fieldName, dir){
5132 var f = this.fields.get(fieldName);
5134 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5135 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5140 this.sortToggle[f.name] = dir;
5141 this.sortInfo = {field: f.name, direction: dir};
5142 if(!this.remoteSort){
5144 this.fireEvent("datachanged", this);
5146 this.load(this.lastOptions);
5151 * Calls the specified function for each of the Records in the cache.
5152 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5153 * Returning <em>false</em> aborts and exits the iteration.
5154 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5156 each : function(fn, scope){
5157 this.data.each(fn, scope);
5161 * Gets all records modified since the last commit. Modified records are persisted across load operations
5162 * (e.g., during paging).
5163 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5165 getModifiedRecords : function(){
5166 return this.modified;
5170 createFilterFn : function(property, value, anyMatch){
5171 if(!value.exec){ // not a regex
5172 value = String(value);
5173 if(value.length == 0){
5176 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5179 return value.test(r.data[property]);
5184 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5185 * @param {String} property A field on your records
5186 * @param {Number} start The record index to start at (defaults to 0)
5187 * @param {Number} end The last record index to include (defaults to length - 1)
5188 * @return {Number} The sum
5190 sum : function(property, start, end){
5191 var rs = this.data.items, v = 0;
5193 end = (end || end === 0) ? end : rs.length-1;
5195 for(var i = start; i <= end; i++){
5196 v += (rs[i].data[property] || 0);
5202 * Filter the records by a specified property.
5203 * @param {String} field A field on your records
5204 * @param {String/RegExp} value Either a string that the field
5205 * should start with or a RegExp to test against the field
5206 * @param {Boolean} anyMatch True to match any part not just the beginning
5208 filter : function(property, value, anyMatch){
5209 var fn = this.createFilterFn(property, value, anyMatch);
5210 return fn ? this.filterBy(fn) : this.clearFilter();
5214 * Filter by a function. The specified function will be called with each
5215 * record in this data source. If the function returns true the record is included,
5216 * otherwise it is filtered.
5217 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5218 * @param {Object} scope (optional) The scope of the function (defaults to this)
5220 filterBy : function(fn, scope){
5221 this.snapshot = this.snapshot || this.data;
5222 this.data = this.queryBy(fn, scope||this);
5223 this.fireEvent("datachanged", this);
5227 * Query the records by a specified property.
5228 * @param {String} field A field on your records
5229 * @param {String/RegExp} value Either a string that the field
5230 * should start with or a RegExp to test against the field
5231 * @param {Boolean} anyMatch True to match any part not just the beginning
5232 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5234 query : function(property, value, anyMatch){
5235 var fn = this.createFilterFn(property, value, anyMatch);
5236 return fn ? this.queryBy(fn) : this.data.clone();
5240 * Query by a function. The specified function will be called with each
5241 * record in this data source. If the function returns true the record is included
5243 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5244 * @param {Object} scope (optional) The scope of the function (defaults to this)
5245 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5247 queryBy : function(fn, scope){
5248 var data = this.snapshot || this.data;
5249 return data.filterBy(fn, scope||this);
5253 * Collects unique values for a particular dataIndex from this store.
5254 * @param {String} dataIndex The property to collect
5255 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5256 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5257 * @return {Array} An array of the unique values
5259 collect : function(dataIndex, allowNull, bypassFilter){
5260 var d = (bypassFilter === true && this.snapshot) ?
5261 this.snapshot.items : this.data.items;
5262 var v, sv, r = [], l = {};
5263 for(var i = 0, len = d.length; i < len; i++){
5264 v = d[i].data[dataIndex];
5266 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5275 * Revert to a view of the Record cache with no filtering applied.
5276 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5278 clearFilter : function(suppressEvent){
5279 if(this.snapshot && this.snapshot != this.data){
5280 this.data = this.snapshot;
5281 delete this.snapshot;
5282 if(suppressEvent !== true){
5283 this.fireEvent("datachanged", this);
5289 afterEdit : function(record){
5290 if(this.modified.indexOf(record) == -1){
5291 this.modified.push(record);
5293 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5297 afterReject : function(record){
5298 this.modified.remove(record);
5299 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5303 afterCommit : function(record){
5304 this.modified.remove(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5309 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5310 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5312 commitChanges : function(){
5313 var m = this.modified.slice(0);
5315 for(var i = 0, len = m.length; i < len; i++){
5321 * Cancel outstanding changes on all changed records.
5323 rejectChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5331 onMetaChange : function(meta, rtype, o){
5332 this.recordType = rtype;
5333 this.fields = rtype.prototype.fields;
5334 delete this.snapshot;
5335 this.sortInfo = meta.sortInfo || this.sortInfo;
5337 this.fireEvent('metachange', this, this.reader.meta);
5341 * Ext JS Library 1.1.1
5342 * Copyright(c) 2006-2007, Ext JS, LLC.
5344 * Originally Released Under LGPL - original licence link has changed is not relivant.
5347 * <script type="text/javascript">
5351 * @class Roo.data.SimpleStore
5352 * @extends Roo.data.Store
5353 * Small helper class to make creating Stores from Array data easier.
5354 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5355 * @cfg {Array} fields An array of field definition objects, or field name strings.
5356 * @cfg {Array} data The multi-dimensional array of data
5358 * @param {Object} config
5360 Roo.data.SimpleStore = function(config){
5361 Roo.data.SimpleStore.superclass.constructor.call(this, {
5363 reader: new Roo.data.ArrayReader({
5366 Roo.data.Record.create(config.fields)
5368 proxy : new Roo.data.MemoryProxy(config.data)
5372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5374 * Ext JS Library 1.1.1
5375 * Copyright(c) 2006-2007, Ext JS, LLC.
5377 * Originally Released Under LGPL - original licence link has changed is not relivant.
5380 * <script type="text/javascript">
5385 * @extends Roo.data.Store
5386 * @class Roo.data.JsonStore
5387 * Small helper class to make creating Stores for JSON data easier. <br/>
5389 var store = new Roo.data.JsonStore({
5390 url: 'get-images.php',
5392 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5395 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5396 * JsonReader and HttpProxy (unless inline data is provided).</b>
5397 * @cfg {Array} fields An array of field definition objects, or field name strings.
5399 * @param {Object} config
5401 Roo.data.JsonStore = function(c){
5402 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5403 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5404 reader: new Roo.data.JsonReader(c, c.fields)
5407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5409 * Ext JS Library 1.1.1
5410 * Copyright(c) 2006-2007, Ext JS, LLC.
5412 * Originally Released Under LGPL - original licence link has changed is not relivant.
5415 * <script type="text/javascript">
5419 Roo.data.Field = function(config){
5420 if(typeof config == "string"){
5421 config = {name: config};
5423 Roo.apply(this, config);
5429 var st = Roo.data.SortTypes;
5430 // named sortTypes are supported, here we look them up
5431 if(typeof this.sortType == "string"){
5432 this.sortType = st[this.sortType];
5435 // set default sortType for strings and dates
5439 this.sortType = st.asUCString;
5442 this.sortType = st.asDate;
5445 this.sortType = st.none;
5450 var stripRe = /[\$,%]/g;
5452 // prebuilt conversion function for this field, instead of
5453 // switching every time we're reading a value
5455 var cv, dateFormat = this.dateFormat;
5460 cv = function(v){ return v; };
5463 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5467 return v !== undefined && v !== null && v !== '' ?
5468 parseInt(String(v).replace(stripRe, ""), 10) : '';
5473 return v !== undefined && v !== null && v !== '' ?
5474 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5479 cv = function(v){ return v === true || v === "true" || v == 1; };
5486 if(v instanceof Date){
5490 if(dateFormat == "timestamp"){
5491 return new Date(v*1000);
5493 return Date.parseDate(v, dateFormat);
5495 var parsed = Date.parse(v);
5496 return parsed ? new Date(parsed) : null;
5505 Roo.data.Field.prototype = {
5513 * Ext JS Library 1.1.1
5514 * Copyright(c) 2006-2007, Ext JS, LLC.
5516 * Originally Released Under LGPL - original licence link has changed is not relivant.
5519 * <script type="text/javascript">
5522 // Base class for reading structured data from a data source. This class is intended to be
5523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5526 * @class Roo.data.DataReader
5527 * Base class for reading structured data from a data source. This class is intended to be
5528 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5531 Roo.data.DataReader = function(meta, recordType){
5535 this.recordType = recordType instanceof Array ?
5536 Roo.data.Record.create(recordType) : recordType;
5539 Roo.data.DataReader.prototype = {
5541 * Create an empty record
5542 * @param {Object} data (optional) - overlay some values
5543 * @return {Roo.data.Record} record created.
5545 newRow : function(d) {
5547 this.recordType.prototype.fields.each(function(c) {
5549 case 'int' : da[c.name] = 0; break;
5550 case 'date' : da[c.name] = new Date(); break;
5551 case 'float' : da[c.name] = 0.0; break;
5552 case 'boolean' : da[c.name] = false; break;
5553 default : da[c.name] = ""; break;
5557 return new this.recordType(Roo.apply(da, d));
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.data.DataProxy
5573 * @extends Roo.data.Observable
5574 * This class is an abstract base class for implementations which provide retrieval of
5575 * unformatted data objects.<br>
5577 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5578 * (of the appropriate type which knows how to parse the data object) to provide a block of
5579 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5581 * Custom implementations must implement the load method as described in
5582 * {@link Roo.data.HttpProxy#load}.
5584 Roo.data.DataProxy = function(){
5588 * Fires before a network request is made to retrieve a data object.
5589 * @param {Object} This DataProxy object.
5590 * @param {Object} params The params parameter to the load function.
5595 * Fires before the load method's callback is called.
5596 * @param {Object} This DataProxy object.
5597 * @param {Object} o The data object.
5598 * @param {Object} arg The callback argument object passed to the load function.
5602 * @event loadexception
5603 * Fires if an Exception occurs during data retrieval.
5604 * @param {Object} This DataProxy object.
5605 * @param {Object} o The data object.
5606 * @param {Object} arg The callback argument object passed to the load function.
5607 * @param {Object} e The Exception.
5609 loadexception : true
5611 Roo.data.DataProxy.superclass.constructor.call(this);
5614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5617 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5621 * Ext JS Library 1.1.1
5622 * Copyright(c) 2006-2007, Ext JS, LLC.
5624 * Originally Released Under LGPL - original licence link has changed is not relivant.
5627 * <script type="text/javascript">
5630 * @class Roo.data.MemoryProxy
5631 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5632 * to the Reader when its load method is called.
5634 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5636 Roo.data.MemoryProxy = function(data){
5640 Roo.data.MemoryProxy.superclass.constructor.call(this);
5644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5646 * Load data from the requested source (in this case an in-memory
5647 * data object passed to the constructor), read the data object into
5648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5649 * process that block using the passed callback.
5650 * @param {Object} params This parameter is not used by the MemoryProxy class.
5651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652 * object into a block of Roo.data.Records.
5653 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5654 * The function must be passed <ul>
5655 * <li>The Record block object</li>
5656 * <li>The "arg" argument from the load function</li>
5657 * <li>A boolean success indicator</li>
5659 * @param {Object} scope The scope in which to call the callback
5660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5662 load : function(params, reader, callback, scope, arg){
5663 params = params || {};
5666 result = reader.readRecords(this.data);
5668 this.fireEvent("loadexception", this, arg, null, e);
5669 callback.call(scope, null, arg, false);
5672 callback.call(scope, result, arg, true);
5676 update : function(params, records){
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5690 * @class Roo.data.HttpProxy
5691 * @extends Roo.data.DataProxy
5692 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5693 * configured to reference a certain URL.<br><br>
5695 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5696 * from which the running page was served.<br><br>
5698 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5700 * Be aware that to enable the browser to parse an XML document, the server must set
5701 * the Content-Type header in the HTTP response to "text/xml".
5703 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5704 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5705 * will be used to make the request.
5707 Roo.data.HttpProxy = function(conn){
5708 Roo.data.HttpProxy.superclass.constructor.call(this);
5709 // is conn a conn config or a real conn?
5711 this.useAjax = !conn || !conn.events;
5715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5716 // thse are take from connection...
5719 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5722 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5723 * extra parameters to each request made by this object. (defaults to undefined)
5726 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5727 * to each request made by this object. (defaults to undefined)
5730 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5733 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5736 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5742 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5746 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5747 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5748 * a finer-grained basis than the DataProxy events.
5750 getConnection : function(){
5751 return this.useAjax ? Roo.Ajax : this.conn;
5755 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5756 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5757 * process that block using the passed callback.
5758 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5759 * for the request to the remote server.
5760 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5761 * object into a block of Roo.data.Records.
5762 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5763 * The function must be passed <ul>
5764 * <li>The Record block object</li>
5765 * <li>The "arg" argument from the load function</li>
5766 * <li>A boolean success indicator</li>
5768 * @param {Object} scope The scope in which to call the callback
5769 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5771 load : function(params, reader, callback, scope, arg){
5772 if(this.fireEvent("beforeload", this, params) !== false){
5774 params : params || {},
5776 callback : callback,
5781 callback : this.loadResponse,
5785 Roo.applyIf(o, this.conn);
5786 if(this.activeRequest){
5787 Roo.Ajax.abort(this.activeRequest);
5789 this.activeRequest = Roo.Ajax.request(o);
5791 this.conn.request(o);
5794 callback.call(scope||this, null, arg, false);
5799 loadResponse : function(o, success, response){
5800 delete this.activeRequest;
5802 this.fireEvent("loadexception", this, o, response);
5803 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5808 result = o.reader.read(response);
5810 this.fireEvent("loadexception", this, o, response, e);
5811 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5815 this.fireEvent("load", this, o, o.request.arg);
5816 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5820 update : function(dataSet){
5825 updateResponse : function(dataSet){
5830 * Ext JS Library 1.1.1
5831 * Copyright(c) 2006-2007, Ext JS, LLC.
5833 * Originally Released Under LGPL - original licence link has changed is not relivant.
5836 * <script type="text/javascript">
5840 * @class Roo.data.ScriptTagProxy
5841 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5842 * other than the originating domain of the running page.<br><br>
5844 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5845 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5847 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5848 * source code that is used as the source inside a <script> tag.<br><br>
5850 * In order for the browser to process the returned data, the server must wrap the data object
5851 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5852 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5853 * depending on whether the callback name was passed:
5856 boolean scriptTag = false;
5857 String cb = request.getParameter("callback");
5860 response.setContentType("text/javascript");
5862 response.setContentType("application/x-json");
5864 Writer out = response.getWriter();
5866 out.write(cb + "(");
5868 out.print(dataBlock.toJsonString());
5875 * @param {Object} config A configuration object.
5877 Roo.data.ScriptTagProxy = function(config){
5878 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5879 Roo.apply(this, config);
5880 this.head = document.getElementsByTagName("head")[0];
5883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5887 * @cfg {String} url The URL from which to request the data object.
5890 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5894 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5895 * the server the name of the callback function set up by the load call to process the returned data object.
5896 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5897 * javascript output which calls this named function passing the data object as its only parameter.
5899 callbackParam : "callback",
5901 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5902 * name to the request.
5907 * Load data from the configured URL, read the data object into
5908 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5909 * process that block using the passed callback.
5910 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5911 * for the request to the remote server.
5912 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5913 * object into a block of Roo.data.Records.
5914 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5915 * The function must be passed <ul>
5916 * <li>The Record block object</li>
5917 * <li>The "arg" argument from the load function</li>
5918 * <li>A boolean success indicator</li>
5920 * @param {Object} scope The scope in which to call the callback
5921 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5923 load : function(params, reader, callback, scope, arg){
5924 if(this.fireEvent("beforeload", this, params) !== false){
5926 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5929 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5931 url += "&_dc=" + (new Date().getTime());
5933 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5936 cb : "stcCallback"+transId,
5937 scriptId : "stcScript"+transId,
5941 callback : callback,
5947 window[trans.cb] = function(o){
5948 conn.handleResponse(o, trans);
5951 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5953 if(this.autoAbort !== false){
5957 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5959 var script = document.createElement("script");
5960 script.setAttribute("src", url);
5961 script.setAttribute("type", "text/javascript");
5962 script.setAttribute("id", trans.scriptId);
5963 this.head.appendChild(script);
5967 callback.call(scope||this, null, arg, false);
5972 isLoading : function(){
5973 return this.trans ? true : false;
5977 * Abort the current server request.
5980 if(this.isLoading()){
5981 this.destroyTrans(this.trans);
5986 destroyTrans : function(trans, isLoaded){
5987 this.head.removeChild(document.getElementById(trans.scriptId));
5988 clearTimeout(trans.timeoutId);
5990 window[trans.cb] = undefined;
5992 delete window[trans.cb];
5995 // if hasn't been loaded, wait for load to remove it to prevent script error
5996 window[trans.cb] = function(){
5997 window[trans.cb] = undefined;
5999 delete window[trans.cb];
6006 handleResponse : function(o, trans){
6008 this.destroyTrans(trans, true);
6011 result = trans.reader.readRecords(o);
6013 this.fireEvent("loadexception", this, o, trans.arg, e);
6014 trans.callback.call(trans.scope||window, null, trans.arg, false);
6017 this.fireEvent("load", this, o, trans.arg);
6018 trans.callback.call(trans.scope||window, result, trans.arg, true);
6022 handleFailure : function(trans){
6024 this.destroyTrans(trans, false);
6025 this.fireEvent("loadexception", this, null, trans.arg);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6040 * @class Roo.data.JsonReader
6041 * @extends Roo.data.DataReader
6042 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6043 * based on mappings in a provided Roo.data.Record constructor.
6045 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6046 * in the reply previously.
6051 var RecordDef = Roo.data.Record.create([
6052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6053 {name: 'occupation'} // This field will use "occupation" as the mapping.
6055 var myReader = new Roo.data.JsonReader({
6056 totalProperty: "results", // The property which contains the total dataset size (optional)
6057 root: "rows", // The property which contains an Array of row objects
6058 id: "id" // The property within each row object that provides an ID for the record (optional)
6062 * This would consume a JSON file like this:
6064 { 'results': 2, 'rows': [
6065 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6066 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6069 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6070 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6071 * paged from the remote server.
6072 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6073 * @cfg {String} root name of the property which contains the Array of row objects.
6074 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6076 * Create a new JsonReader
6077 * @param {Object} meta Metadata configuration options
6078 * @param {Object} recordType Either an Array of field definition objects,
6079 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6081 Roo.data.JsonReader = function(meta, recordType){
6084 // set some defaults:
6086 totalProperty: 'total',
6087 successProperty : 'success',
6092 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6097 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6098 * Used by Store query builder to append _requestMeta to params.
6101 metaFromRemote : false,
6103 * This method is only used by a DataProxy which has retrieved data from a remote server.
6104 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6105 * @return {Object} data A data block which is used by an Roo.data.Store object as
6106 * a cache of Roo.data.Records.
6108 read : function(response){
6109 var json = response.responseText;
6111 var o = /* eval:var:o */ eval("("+json+")");
6113 throw {message: "JsonReader.read: Json object not found"};
6119 this.metaFromRemote = true;
6120 this.meta = o.metaData;
6121 this.recordType = Roo.data.Record.create(o.metaData.fields);
6122 this.onMetaChange(this.meta, this.recordType, o);
6124 return this.readRecords(o);
6127 // private function a store will implement
6128 onMetaChange : function(meta, recordType, o){
6135 simpleAccess: function(obj, subsc) {
6142 getJsonAccessor: function(){
6144 return function(expr) {
6146 return(re.test(expr))
6147 ? new Function("obj", "return obj." + expr)
6157 * Create a data block containing Roo.data.Records from an XML document.
6158 * @param {Object} o An object which contains an Array of row objects in the property specified
6159 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6160 * which contains the total size of the dataset.
6161 * @return {Object} data A data block which is used by an Roo.data.Store object as
6162 * a cache of Roo.data.Records.
6164 readRecords : function(o){
6166 * After any data loads, the raw JSON data is available for further custom processing.
6170 var s = this.meta, Record = this.recordType,
6171 f = Record.prototype.fields, fi = f.items, fl = f.length;
6173 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6175 if(s.totalProperty) {
6176 this.getTotal = this.getJsonAccessor(s.totalProperty);
6178 if(s.successProperty) {
6179 this.getSuccess = this.getJsonAccessor(s.successProperty);
6181 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6183 var g = this.getJsonAccessor(s.id);
6184 this.getId = function(rec) {
6186 return (r === undefined || r === "") ? null : r;
6189 this.getId = function(){return null;};
6192 for(var jj = 0; jj < fl; jj++){
6194 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6195 this.ef[jj] = this.getJsonAccessor(map);
6199 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6200 if(s.totalProperty){
6201 var vt = parseInt(this.getTotal(o), 10);
6206 if(s.successProperty){
6207 var vs = this.getSuccess(o);
6208 if(vs === false || vs === 'false'){
6213 for(var i = 0; i < c; i++){
6216 var id = this.getId(n);
6217 for(var j = 0; j < fl; j++){
6219 var v = this.ef[j](n);
6221 Roo.log('missing convert for ' + f.name);
6225 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6227 var record = new Record(values, id);
6229 records[i] = record;
6234 totalRecords : totalRecords
6239 * Ext JS Library 1.1.1
6240 * Copyright(c) 2006-2007, Ext JS, LLC.
6242 * Originally Released Under LGPL - original licence link has changed is not relivant.
6245 * <script type="text/javascript">
6249 * @class Roo.data.XmlReader
6250 * @extends Roo.data.DataReader
6251 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6252 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6254 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6255 * header in the HTTP response must be set to "text/xml".</em>
6259 var RecordDef = Roo.data.Record.create([
6260 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6261 {name: 'occupation'} // This field will use "occupation" as the mapping.
6263 var myReader = new Roo.data.XmlReader({
6264 totalRecords: "results", // The element which contains the total dataset size (optional)
6265 record: "row", // The repeated element which contains row information
6266 id: "id" // The element within the row that provides an ID for the record (optional)
6270 * This would consume an XML file like this:
6274 <results>2</results>
6277 <name>Bill</name>
6278 <occupation>Gardener</occupation>
6282 <name>Ben</name>
6283 <occupation>Horticulturalist</occupation>
6287 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6288 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6289 * paged from the remote server.
6290 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6291 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6292 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6293 * a record identifier value.
6295 * Create a new XmlReader
6296 * @param {Object} meta Metadata configuration options
6297 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6298 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6299 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6301 Roo.data.XmlReader = function(meta, recordType){
6303 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6305 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6307 * This method is only used by a DataProxy which has retrieved data from a remote server.
6308 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6309 * to contain a method called 'responseXML' that returns an XML document object.
6310 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6311 * a cache of Roo.data.Records.
6313 read : function(response){
6314 var doc = response.responseXML;
6316 throw {message: "XmlReader.read: XML Document not available"};
6318 return this.readRecords(doc);
6322 * Create a data block containing Roo.data.Records from an XML document.
6323 * @param {Object} doc A parsed XML document.
6324 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6325 * a cache of Roo.data.Records.
6327 readRecords : function(doc){
6329 * After any data loads/reads, the raw XML Document is available for further custom processing.
6333 var root = doc.documentElement || doc;
6334 var q = Roo.DomQuery;
6335 var recordType = this.recordType, fields = recordType.prototype.fields;
6336 var sid = this.meta.id;
6337 var totalRecords = 0, success = true;
6338 if(this.meta.totalRecords){
6339 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6342 if(this.meta.success){
6343 var sv = q.selectValue(this.meta.success, root, true);
6344 success = sv !== false && sv !== 'false';
6347 var ns = q.select(this.meta.record, root);
6348 for(var i = 0, len = ns.length; i < len; i++) {
6351 var id = sid ? q.selectValue(sid, n) : undefined;
6352 for(var j = 0, jlen = fields.length; j < jlen; j++){
6353 var f = fields.items[j];
6354 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6358 var record = new recordType(values, id);
6360 records[records.length] = record;
6366 totalRecords : totalRecords || records.length
6371 * Ext JS Library 1.1.1
6372 * Copyright(c) 2006-2007, Ext JS, LLC.
6374 * Originally Released Under LGPL - original licence link has changed is not relivant.
6377 * <script type="text/javascript">
6381 * @class Roo.data.ArrayReader
6382 * @extends Roo.data.DataReader
6383 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6384 * Each element of that Array represents a row of data fields. The
6385 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6386 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6390 var RecordDef = Roo.data.Record.create([
6391 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6392 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6394 var myReader = new Roo.data.ArrayReader({
6395 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6399 * This would consume an Array like this:
6401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6403 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6405 * Create a new JsonReader
6406 * @param {Object} meta Metadata configuration options.
6407 * @param {Object} recordType Either an Array of field definition objects
6408 * as specified to {@link Roo.data.Record#create},
6409 * or an {@link Roo.data.Record} object
6410 * created using {@link Roo.data.Record#create}.
6412 Roo.data.ArrayReader = function(meta, recordType){
6413 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6418 * Create a data block containing Roo.data.Records from an XML document.
6419 * @param {Object} o An Array of row objects which represents the dataset.
6420 * @return {Object} data A data block which is used by an Roo.data.Store object as
6421 * a cache of Roo.data.Records.
6423 readRecords : function(o){
6424 var sid = this.meta ? this.meta.id : null;
6425 var recordType = this.recordType, fields = recordType.prototype.fields;
6428 for(var i = 0; i < root.length; i++){
6431 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6432 for(var j = 0, jlen = fields.length; j < jlen; j++){
6433 var f = fields.items[j];
6434 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6435 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6439 var record = new recordType(values, id);
6441 records[records.length] = record;
6445 totalRecords : records.length
6450 * Ext JS Library 1.1.1
6451 * Copyright(c) 2006-2007, Ext JS, LLC.
6453 * Originally Released Under LGPL - original licence link has changed is not relivant.
6456 * <script type="text/javascript">
6461 * @class Roo.data.Tree
6462 * @extends Roo.util.Observable
6463 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6464 * in the tree have most standard DOM functionality.
6466 * @param {Node} root (optional) The root node
6468 Roo.data.Tree = function(root){
6471 * The root node for this tree
6476 this.setRootNode(root);
6481 * Fires when a new child node is appended to a node in this tree.
6482 * @param {Tree} tree The owner tree
6483 * @param {Node} parent The parent node
6484 * @param {Node} node The newly appended node
6485 * @param {Number} index The index of the newly appended node
6490 * Fires when a child node is removed from a node in this tree.
6491 * @param {Tree} tree The owner tree
6492 * @param {Node} parent The parent node
6493 * @param {Node} node The child node removed
6498 * Fires when a node is moved to a new location in the tree
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} node The node moved
6501 * @param {Node} oldParent The old parent of this node
6502 * @param {Node} newParent The new parent of this node
6503 * @param {Number} index The index it was moved to
6508 * Fires when a new child node is inserted in a node in this tree.
6509 * @param {Tree} tree The owner tree
6510 * @param {Node} parent The parent node
6511 * @param {Node} node The child node inserted
6512 * @param {Node} refNode The child node the node was inserted before
6516 * @event beforeappend
6517 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6518 * @param {Tree} tree The owner tree
6519 * @param {Node} parent The parent node
6520 * @param {Node} node The child node to be appended
6522 "beforeappend" : true,
6524 * @event beforeremove
6525 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node to be removed
6530 "beforeremove" : true,
6533 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6534 * @param {Tree} tree The owner tree
6535 * @param {Node} node The node being moved
6536 * @param {Node} oldParent The parent of the node
6537 * @param {Node} newParent The new parent the node is moving to
6538 * @param {Number} index The index it is being moved to
6540 "beforemove" : true,
6542 * @event beforeinsert
6543 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6544 * @param {Tree} tree The owner tree
6545 * @param {Node} parent The parent node
6546 * @param {Node} node The child node to be inserted
6547 * @param {Node} refNode The child node the node is being inserted before
6549 "beforeinsert" : true
6552 Roo.data.Tree.superclass.constructor.call(this);
6555 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6558 proxyNodeEvent : function(){
6559 return this.fireEvent.apply(this, arguments);
6563 * Returns the root node for this tree.
6566 getRootNode : function(){
6571 * Sets the root node for this tree.
6572 * @param {Node} node
6575 setRootNode : function(node){
6577 node.ownerTree = this;
6579 this.registerNode(node);
6584 * Gets a node in this tree by its id.
6585 * @param {String} id
6588 getNodeById : function(id){
6589 return this.nodeHash[id];
6592 registerNode : function(node){
6593 this.nodeHash[node.id] = node;
6596 unregisterNode : function(node){
6597 delete this.nodeHash[node.id];
6600 toString : function(){
6601 return "[Tree"+(this.id?" "+this.id:"")+"]";
6606 * @class Roo.data.Node
6607 * @extends Roo.util.Observable
6608 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6609 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6611 * @param {Object} attributes The attributes/config for the node
6613 Roo.data.Node = function(attributes){
6615 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6618 this.attributes = attributes || {};
6619 this.leaf = this.attributes.leaf;
6621 * The node id. @type String
6623 this.id = this.attributes.id;
6625 this.id = Roo.id(null, "ynode-");
6626 this.attributes.id = this.id;
6629 * All child nodes of this node. @type Array
6631 this.childNodes = [];
6632 if(!this.childNodes.indexOf){ // indexOf is a must
6633 this.childNodes.indexOf = function(o){
6634 for(var i = 0, len = this.length; i < len; i++){
6643 * The parent node for this node. @type Node
6645 this.parentNode = null;
6647 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6649 this.firstChild = null;
6651 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6653 this.lastChild = null;
6655 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6657 this.previousSibling = null;
6659 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6661 this.nextSibling = null;
6666 * Fires when a new child node is appended
6667 * @param {Tree} tree The owner tree
6668 * @param {Node} this This node
6669 * @param {Node} node The newly appended node
6670 * @param {Number} index The index of the newly appended node
6675 * Fires when a child node is removed
6676 * @param {Tree} tree The owner tree
6677 * @param {Node} this This node
6678 * @param {Node} node The removed node
6683 * Fires when this node is moved to a new location in the tree
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} oldParent The old parent of this node
6687 * @param {Node} newParent The new parent of this node
6688 * @param {Number} index The index it was moved to
6693 * Fires when a new child node is inserted.
6694 * @param {Tree} tree The owner tree
6695 * @param {Node} this This node
6696 * @param {Node} node The child node inserted
6697 * @param {Node} refNode The child node the node was inserted before
6701 * @event beforeappend
6702 * Fires before a new child is appended, return false to cancel the append.
6703 * @param {Tree} tree The owner tree
6704 * @param {Node} this This node
6705 * @param {Node} node The child node to be appended
6707 "beforeappend" : true,
6709 * @event beforeremove
6710 * Fires before a child is removed, return false to cancel the remove.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node to be removed
6715 "beforeremove" : true,
6718 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6719 * @param {Tree} tree The owner tree
6720 * @param {Node} this This node
6721 * @param {Node} oldParent The parent of this node
6722 * @param {Node} newParent The new parent this node is moving to
6723 * @param {Number} index The index it is being moved to
6725 "beforemove" : true,
6727 * @event beforeinsert
6728 * Fires before a new child is inserted, return false to cancel the insert.
6729 * @param {Tree} tree The owner tree
6730 * @param {Node} this This node
6731 * @param {Node} node The child node to be inserted
6732 * @param {Node} refNode The child node the node is being inserted before
6734 "beforeinsert" : true
6736 this.listeners = this.attributes.listeners;
6737 Roo.data.Node.superclass.constructor.call(this);
6740 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6741 fireEvent : function(evtName){
6742 // first do standard event for this node
6743 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6746 // then bubble it up to the tree if the event wasn't cancelled
6747 var ot = this.getOwnerTree();
6749 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6757 * Returns true if this node is a leaf
6760 isLeaf : function(){
6761 return this.leaf === true;
6765 setFirstChild : function(node){
6766 this.firstChild = node;
6770 setLastChild : function(node){
6771 this.lastChild = node;
6776 * Returns true if this node is the last child of its parent
6779 isLast : function(){
6780 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6784 * Returns true if this node is the first child of its parent
6787 isFirst : function(){
6788 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6791 hasChildNodes : function(){
6792 return !this.isLeaf() && this.childNodes.length > 0;
6796 * Insert node(s) as the last child node of this node.
6797 * @param {Node/Array} node The node or Array of nodes to append
6798 * @return {Node} The appended node if single append, or null if an array was passed
6800 appendChild : function(node){
6802 if(node instanceof Array){
6804 }else if(arguments.length > 1){
6807 // if passed an array or multiple args do them one by one
6809 for(var i = 0, len = multi.length; i < len; i++) {
6810 this.appendChild(multi[i]);
6813 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6816 var index = this.childNodes.length;
6817 var oldParent = node.parentNode;
6818 // it's a move, make sure we move it cleanly
6820 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6823 oldParent.removeChild(node);
6825 index = this.childNodes.length;
6827 this.setFirstChild(node);
6829 this.childNodes.push(node);
6830 node.parentNode = this;
6831 var ps = this.childNodes[index-1];
6833 node.previousSibling = ps;
6834 ps.nextSibling = node;
6836 node.previousSibling = null;
6838 node.nextSibling = null;
6839 this.setLastChild(node);
6840 node.setOwnerTree(this.getOwnerTree());
6841 this.fireEvent("append", this.ownerTree, this, node, index);
6843 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6850 * Removes a child node from this node.
6851 * @param {Node} node The node to remove
6852 * @return {Node} The removed node
6854 removeChild : function(node){
6855 var index = this.childNodes.indexOf(node);
6859 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6863 // remove it from childNodes collection
6864 this.childNodes.splice(index, 1);
6867 if(node.previousSibling){
6868 node.previousSibling.nextSibling = node.nextSibling;
6870 if(node.nextSibling){
6871 node.nextSibling.previousSibling = node.previousSibling;
6874 // update child refs
6875 if(this.firstChild == node){
6876 this.setFirstChild(node.nextSibling);
6878 if(this.lastChild == node){
6879 this.setLastChild(node.previousSibling);
6882 node.setOwnerTree(null);
6883 // clear any references from the node
6884 node.parentNode = null;
6885 node.previousSibling = null;
6886 node.nextSibling = null;
6887 this.fireEvent("remove", this.ownerTree, this, node);
6892 * Inserts the first node before the second node in this nodes childNodes collection.
6893 * @param {Node} node The node to insert
6894 * @param {Node} refNode The node to insert before (if null the node is appended)
6895 * @return {Node} The inserted node
6897 insertBefore : function(node, refNode){
6898 if(!refNode){ // like standard Dom, refNode can be null for append
6899 return this.appendChild(node);
6902 if(node == refNode){
6906 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6909 var index = this.childNodes.indexOf(refNode);
6910 var oldParent = node.parentNode;
6911 var refIndex = index;
6913 // when moving internally, indexes will change after remove
6914 if(oldParent == this && this.childNodes.indexOf(node) < index){
6918 // it's a move, make sure we move it cleanly
6920 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6923 oldParent.removeChild(node);
6926 this.setFirstChild(node);
6928 this.childNodes.splice(refIndex, 0, node);
6929 node.parentNode = this;
6930 var ps = this.childNodes[refIndex-1];
6932 node.previousSibling = ps;
6933 ps.nextSibling = node;
6935 node.previousSibling = null;
6937 node.nextSibling = refNode;
6938 refNode.previousSibling = node;
6939 node.setOwnerTree(this.getOwnerTree());
6940 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6942 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6948 * Returns the child node at the specified index.
6949 * @param {Number} index
6952 item : function(index){
6953 return this.childNodes[index];
6957 * Replaces one child node in this node with another.
6958 * @param {Node} newChild The replacement node
6959 * @param {Node} oldChild The node to replace
6960 * @return {Node} The replaced node
6962 replaceChild : function(newChild, oldChild){
6963 this.insertBefore(newChild, oldChild);
6964 this.removeChild(oldChild);
6969 * Returns the index of a child node
6970 * @param {Node} node
6971 * @return {Number} The index of the node or -1 if it was not found
6973 indexOf : function(child){
6974 return this.childNodes.indexOf(child);
6978 * Returns the tree this node is in.
6981 getOwnerTree : function(){
6982 // if it doesn't have one, look for one
6983 if(!this.ownerTree){
6987 this.ownerTree = p.ownerTree;
6993 return this.ownerTree;
6997 * Returns depth of this node (the root node has a depth of 0)
7000 getDepth : function(){
7003 while(p.parentNode){
7011 setOwnerTree : function(tree){
7012 // if it's move, we need to update everyone
7013 if(tree != this.ownerTree){
7015 this.ownerTree.unregisterNode(this);
7017 this.ownerTree = tree;
7018 var cs = this.childNodes;
7019 for(var i = 0, len = cs.length; i < len; i++) {
7020 cs[i].setOwnerTree(tree);
7023 tree.registerNode(this);
7029 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7030 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7031 * @return {String} The path
7033 getPath : function(attr){
7034 attr = attr || "id";
7035 var p = this.parentNode;
7036 var b = [this.attributes[attr]];
7038 b.unshift(p.attributes[attr]);
7041 var sep = this.getOwnerTree().pathSeparator;
7042 return sep + b.join(sep);
7046 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7047 * function call will be the scope provided or the current node. The arguments to the function
7048 * will be the args provided or the current node. If the function returns false at any point,
7049 * the bubble is stopped.
7050 * @param {Function} fn The function to call
7051 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7052 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7054 bubble : function(fn, scope, args){
7057 if(fn.call(scope || p, args || p) === false){
7065 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7066 * function call will be the scope provided or the current node. The arguments to the function
7067 * will be the args provided or the current node. If the function returns false at any point,
7068 * the cascade is stopped on that branch.
7069 * @param {Function} fn The function to call
7070 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7071 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7073 cascade : function(fn, scope, args){
7074 if(fn.call(scope || this, args || this) !== false){
7075 var cs = this.childNodes;
7076 for(var i = 0, len = cs.length; i < len; i++) {
7077 cs[i].cascade(fn, scope, args);
7083 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7084 * function call will be the scope provided or the current node. The arguments to the function
7085 * will be the args provided or the current node. If the function returns false at any point,
7086 * the iteration stops.
7087 * @param {Function} fn The function to call
7088 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7091 eachChild : function(fn, scope, args){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 if(fn.call(scope || this, args || cs[i]) === false){
7101 * Finds the first child that has the attribute with the specified value.
7102 * @param {String} attribute The attribute name
7103 * @param {Mixed} value The value to search for
7104 * @return {Node} The found child or null if none was found
7106 findChild : function(attribute, value){
7107 var cs = this.childNodes;
7108 for(var i = 0, len = cs.length; i < len; i++) {
7109 if(cs[i].attributes[attribute] == value){
7117 * Finds the first child by a custom function. The child matches if the function passed
7119 * @param {Function} fn
7120 * @param {Object} scope (optional)
7121 * @return {Node} The found child or null if none was found
7123 findChildBy : function(fn, scope){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(fn.call(scope||cs[i], cs[i]) === true){
7134 * Sorts this nodes children using the supplied sort function
7135 * @param {Function} fn
7136 * @param {Object} scope (optional)
7138 sort : function(fn, scope){
7139 var cs = this.childNodes;
7140 var len = cs.length;
7142 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7144 for(var i = 0; i < len; i++){
7146 n.previousSibling = cs[i-1];
7147 n.nextSibling = cs[i+1];
7149 this.setFirstChild(n);
7152 this.setLastChild(n);
7159 * Returns true if this node is an ancestor (at any point) of the passed node.
7160 * @param {Node} node
7163 contains : function(node){
7164 return node.isAncestor(this);
7168 * Returns true if the passed node is an ancestor (at any point) of this node.
7169 * @param {Node} node
7172 isAncestor : function(node){
7173 var p = this.parentNode;
7183 toString : function(){
7184 return "[Node"+(this.id?" "+this.id:"")+"]";
7188 * Ext JS Library 1.1.1
7189 * Copyright(c) 2006-2007, Ext JS, LLC.
7191 * Originally Released Under LGPL - original licence link has changed is not relivant.
7194 * <script type="text/javascript">
7199 * @class Roo.ComponentMgr
7200 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7203 Roo.ComponentMgr = function(){
7204 var all = new Roo.util.MixedCollection();
7208 * Registers a component.
7209 * @param {Roo.Component} c The component
7211 register : function(c){
7216 * Unregisters a component.
7217 * @param {Roo.Component} c The component
7219 unregister : function(c){
7224 * Returns a component by id
7225 * @param {String} id The component id
7232 * Registers a function that will be called when a specified component is added to ComponentMgr
7233 * @param {String} id The component id
7234 * @param {Funtction} fn The callback function
7235 * @param {Object} scope The scope of the callback
7237 onAvailable : function(id, fn, scope){
7238 all.on("add", function(index, o){
7240 fn.call(scope || o, o);
7241 all.un("add", fn, scope);
7248 * Ext JS Library 1.1.1
7249 * Copyright(c) 2006-2007, Ext JS, LLC.
7251 * Originally Released Under LGPL - original licence link has changed is not relivant.
7254 * <script type="text/javascript">
7258 * @class Roo.Component
7259 * @extends Roo.util.Observable
7260 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7261 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7262 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7263 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7264 * All visual components (widgets) that require rendering into a layout should subclass Component.
7266 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7267 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
7268 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7270 Roo.Component = function(config){
7271 config = config || {};
7272 if(config.tagName || config.dom || typeof config == "string"){ // element object
7273 config = {el: config, id: config.id || config};
7275 this.initialConfig = config;
7277 Roo.apply(this, config);
7281 * Fires after the component is disabled.
7282 * @param {Roo.Component} this
7287 * Fires after the component is enabled.
7288 * @param {Roo.Component} this
7293 * Fires before the component is shown. Return false to stop the show.
7294 * @param {Roo.Component} this
7299 * Fires after the component is shown.
7300 * @param {Roo.Component} this
7305 * Fires before the component is hidden. Return false to stop the hide.
7306 * @param {Roo.Component} this
7311 * Fires after the component is hidden.
7312 * @param {Roo.Component} this
7316 * @event beforerender
7317 * Fires before the component is rendered. Return false to stop the render.
7318 * @param {Roo.Component} this
7320 beforerender : true,
7323 * Fires after the component is rendered.
7324 * @param {Roo.Component} this
7328 * @event beforedestroy
7329 * Fires before the component is destroyed. Return false to stop the destroy.
7330 * @param {Roo.Component} this
7332 beforedestroy : true,
7335 * Fires after the component is destroyed.
7336 * @param {Roo.Component} this
7341 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7343 Roo.ComponentMgr.register(this);
7344 Roo.Component.superclass.constructor.call(this);
7345 this.initComponent();
7346 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7347 this.render(this.renderTo);
7348 delete this.renderTo;
7353 Roo.Component.AUTO_ID = 1000;
7355 Roo.extend(Roo.Component, Roo.util.Observable, {
7357 * @property {Boolean} hidden
7358 * true if this component is hidden. Read-only.
7362 * true if this component is disabled. Read-only.
7366 * true if this component has been rendered. Read-only.
7370 /** @cfg {String} disableClass
7371 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7373 disabledClass : "x-item-disabled",
7374 /** @cfg {Boolean} allowDomMove
7375 * Whether the component can move the Dom node when rendering (defaults to true).
7377 allowDomMove : true,
7378 /** @cfg {String} hideMode
7379 * How this component should hidden. Supported values are
7380 * "visibility" (css visibility), "offsets" (negative offset position) and
7381 * "display" (css display) - defaults to "display".
7383 hideMode: 'display',
7386 ctype : "Roo.Component",
7388 /** @cfg {String} actionMode
7389 * which property holds the element that used for hide() / show() / disable() / enable()
7395 getActionEl : function(){
7396 return this[this.actionMode];
7399 initComponent : Roo.emptyFn,
7401 * If this is a lazy rendering component, render it to its container element.
7402 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
7404 render : function(container, position){
7405 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7406 if(!container && this.el){
7407 this.el = Roo.get(this.el);
7408 container = this.el.dom.parentNode;
7409 this.allowDomMove = false;
7411 this.container = Roo.get(container);
7412 this.rendered = true;
7413 if(position !== undefined){
7414 if(typeof position == 'number'){
7415 position = this.container.dom.childNodes[position];
7417 position = Roo.getDom(position);
7420 this.onRender(this.container, position || null);
7422 this.el.addClass(this.cls);
7426 this.el.applyStyles(this.style);
7429 this.fireEvent("render", this);
7430 this.afterRender(this.container);
7442 // default function is not really useful
7443 onRender : function(ct, position){
7445 this.el = Roo.get(this.el);
7446 if(this.allowDomMove !== false){
7447 ct.dom.insertBefore(this.el.dom, position);
7453 getAutoCreate : function(){
7454 var cfg = typeof this.autoCreate == "object" ?
7455 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7456 if(this.id && !cfg.id){
7463 afterRender : Roo.emptyFn,
7466 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7467 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7469 destroy : function(){
7470 if(this.fireEvent("beforedestroy", this) !== false){
7471 this.purgeListeners();
7472 this.beforeDestroy();
7474 this.el.removeAllListeners();
7476 if(this.actionMode == "container"){
7477 this.container.remove();
7481 Roo.ComponentMgr.unregister(this);
7482 this.fireEvent("destroy", this);
7487 beforeDestroy : function(){
7492 onDestroy : function(){
7497 * Returns the underlying {@link Roo.Element}.
7498 * @return {Roo.Element} The element
7505 * Returns the id of this component.
7513 * Try to focus this component.
7514 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7515 * @return {Roo.Component} this
7517 focus : function(selectText){
7520 if(selectText === true){
7521 this.el.dom.select();
7536 * Disable this component.
7537 * @return {Roo.Component} this
7539 disable : function(){
7543 this.disabled = true;
7544 this.fireEvent("disable", this);
7549 onDisable : function(){
7550 this.getActionEl().addClass(this.disabledClass);
7551 this.el.dom.disabled = true;
7555 * Enable this component.
7556 * @return {Roo.Component} this
7558 enable : function(){
7562 this.disabled = false;
7563 this.fireEvent("enable", this);
7568 onEnable : function(){
7569 this.getActionEl().removeClass(this.disabledClass);
7570 this.el.dom.disabled = false;
7574 * Convenience function for setting disabled/enabled by boolean.
7575 * @param {Boolean} disabled
7577 setDisabled : function(disabled){
7578 this[disabled ? "disable" : "enable"]();
7582 * Show this component.
7583 * @return {Roo.Component} this
7586 if(this.fireEvent("beforeshow", this) !== false){
7587 this.hidden = false;
7591 this.fireEvent("show", this);
7597 onShow : function(){
7598 var ae = this.getActionEl();
7599 if(this.hideMode == 'visibility'){
7600 ae.dom.style.visibility = "visible";
7601 }else if(this.hideMode == 'offsets'){
7602 ae.removeClass('x-hidden');
7604 ae.dom.style.display = "";
7609 * Hide this component.
7610 * @return {Roo.Component} this
7613 if(this.fireEvent("beforehide", this) !== false){
7618 this.fireEvent("hide", this);
7624 onHide : function(){
7625 var ae = this.getActionEl();
7626 if(this.hideMode == 'visibility'){
7627 ae.dom.style.visibility = "hidden";
7628 }else if(this.hideMode == 'offsets'){
7629 ae.addClass('x-hidden');
7631 ae.dom.style.display = "none";
7636 * Convenience function to hide or show this component by boolean.
7637 * @param {Boolean} visible True to show, false to hide
7638 * @return {Roo.Component} this
7640 setVisible: function(visible){
7650 * Returns true if this component is visible.
7652 isVisible : function(){
7653 return this.getActionEl().isVisible();
7656 cloneConfig : function(overrides){
7657 overrides = overrides || {};
7658 var id = overrides.id || Roo.id();
7659 var cfg = Roo.applyIf(overrides, this.initialConfig);
7660 cfg.id = id; // prevent dup id
7661 return new this.constructor(cfg);
7665 * Ext JS Library 1.1.1
7666 * Copyright(c) 2006-2007, Ext JS, LLC.
7668 * Originally Released Under LGPL - original licence link has changed is not relivant.
7671 * <script type="text/javascript">
7676 * @extends Roo.Element
7677 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7678 * automatic maintaining of shadow/shim positions.
7679 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7680 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7681 * you can pass a string with a CSS class name. False turns off the shadow.
7682 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7683 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7684 * @cfg {String} cls CSS class to add to the element
7685 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7686 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7688 * @param {Object} config An object with config options.
7689 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7692 Roo.Layer = function(config, existingEl){
7693 config = config || {};
7694 var dh = Roo.DomHelper;
7695 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7697 this.dom = Roo.getDom(existingEl);
7700 var o = config.dh || {tag: "div", cls: "x-layer"};
7701 this.dom = dh.append(pel, o);
7704 this.addClass(config.cls);
7706 this.constrain = config.constrain !== false;
7707 this.visibilityMode = Roo.Element.VISIBILITY;
7709 this.id = this.dom.id = config.id;
7711 this.id = Roo.id(this.dom);
7713 this.zindex = config.zindex || this.getZIndex();
7714 this.position("absolute", this.zindex);
7716 this.shadowOffset = config.shadowOffset || 4;
7717 this.shadow = new Roo.Shadow({
7718 offset : this.shadowOffset,
7719 mode : config.shadow
7722 this.shadowOffset = 0;
7724 this.useShim = config.shim !== false && Roo.useShims;
7725 this.useDisplay = config.useDisplay;
7729 var supr = Roo.Element.prototype;
7731 // shims are shared among layer to keep from having 100 iframes
7734 Roo.extend(Roo.Layer, Roo.Element, {
7736 getZIndex : function(){
7737 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7740 getShim : function(){
7747 var shim = shims.shift();
7749 shim = this.createShim();
7750 shim.enableDisplayMode('block');
7751 shim.dom.style.display = 'none';
7752 shim.dom.style.visibility = 'visible';
7754 var pn = this.dom.parentNode;
7755 if(shim.dom.parentNode != pn){
7756 pn.insertBefore(shim.dom, this.dom);
7758 shim.setStyle('z-index', this.getZIndex()-2);
7763 hideShim : function(){
7765 this.shim.setDisplayed(false);
7766 shims.push(this.shim);
7771 disableShadow : function(){
7773 this.shadowDisabled = true;
7775 this.lastShadowOffset = this.shadowOffset;
7776 this.shadowOffset = 0;
7780 enableShadow : function(show){
7782 this.shadowDisabled = false;
7783 this.shadowOffset = this.lastShadowOffset;
7784 delete this.lastShadowOffset;
7792 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7793 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7794 sync : function(doShow){
7795 var sw = this.shadow;
7796 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7797 var sh = this.getShim();
7799 var w = this.getWidth(),
7800 h = this.getHeight();
7802 var l = this.getLeft(true),
7803 t = this.getTop(true);
7805 if(sw && !this.shadowDisabled){
7806 if(doShow && !sw.isVisible()){
7809 sw.realign(l, t, w, h);
7815 // fit the shim behind the shadow, so it is shimmed too
7816 var a = sw.adjusts, s = sh.dom.style;
7817 s.left = (Math.min(l, l+a.l))+"px";
7818 s.top = (Math.min(t, t+a.t))+"px";
7819 s.width = (w+a.w)+"px";
7820 s.height = (h+a.h)+"px";
7827 sh.setLeftTop(l, t);
7834 destroy : function(){
7839 this.removeAllListeners();
7840 var pn = this.dom.parentNode;
7842 pn.removeChild(this.dom);
7844 Roo.Element.uncache(this.id);
7847 remove : function(){
7852 beginUpdate : function(){
7853 this.updating = true;
7857 endUpdate : function(){
7858 this.updating = false;
7863 hideUnders : function(negOffset){
7871 constrainXY : function(){
7873 var vw = Roo.lib.Dom.getViewWidth(),
7874 vh = Roo.lib.Dom.getViewHeight();
7875 var s = Roo.get(document).getScroll();
7877 var xy = this.getXY();
7878 var x = xy[0], y = xy[1];
7879 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7880 // only move it if it needs it
7882 // first validate right/bottom
7883 if((x + w) > vw+s.left){
7884 x = vw - w - this.shadowOffset;
7887 if((y + h) > vh+s.top){
7888 y = vh - h - this.shadowOffset;
7891 // then make sure top/left isn't negative
7902 var ay = this.avoidY;
7903 if(y <= ay && (y+h) >= ay){
7909 supr.setXY.call(this, xy);
7915 isVisible : function(){
7916 return this.visible;
7920 showAction : function(){
7921 this.visible = true; // track visibility to prevent getStyle calls
7922 if(this.useDisplay === true){
7923 this.setDisplayed("");
7924 }else if(this.lastXY){
7925 supr.setXY.call(this, this.lastXY);
7926 }else if(this.lastLT){
7927 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7932 hideAction : function(){
7933 this.visible = false;
7934 if(this.useDisplay === true){
7935 this.setDisplayed(false);
7937 this.setLeftTop(-10000,-10000);
7941 // overridden Element method
7942 setVisible : function(v, a, d, c, e){
7947 var cb = function(){
7952 }.createDelegate(this);
7953 supr.setVisible.call(this, true, true, d, cb, e);
7956 this.hideUnders(true);
7965 }.createDelegate(this);
7967 supr.setVisible.call(this, v, a, d, cb, e);
7976 storeXY : function(xy){
7981 storeLeftTop : function(left, top){
7983 this.lastLT = [left, top];
7987 beforeFx : function(){
7988 this.beforeAction();
7989 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
7993 afterFx : function(){
7994 Roo.Layer.superclass.afterFx.apply(this, arguments);
7995 this.sync(this.isVisible());
7999 beforeAction : function(){
8000 if(!this.updating && this.shadow){
8005 // overridden Element method
8006 setLeft : function(left){
8007 this.storeLeftTop(left, this.getTop(true));
8008 supr.setLeft.apply(this, arguments);
8012 setTop : function(top){
8013 this.storeLeftTop(this.getLeft(true), top);
8014 supr.setTop.apply(this, arguments);
8018 setLeftTop : function(left, top){
8019 this.storeLeftTop(left, top);
8020 supr.setLeftTop.apply(this, arguments);
8024 setXY : function(xy, a, d, c, e){
8026 this.beforeAction();
8028 var cb = this.createCB(c);
8029 supr.setXY.call(this, xy, a, d, cb, e);
8036 createCB : function(c){
8047 // overridden Element method
8048 setX : function(x, a, d, c, e){
8049 this.setXY([x, this.getY()], a, d, c, e);
8052 // overridden Element method
8053 setY : function(y, a, d, c, e){
8054 this.setXY([this.getX(), y], a, d, c, e);
8057 // overridden Element method
8058 setSize : function(w, h, a, d, c, e){
8059 this.beforeAction();
8060 var cb = this.createCB(c);
8061 supr.setSize.call(this, w, h, a, d, cb, e);
8067 // overridden Element method
8068 setWidth : function(w, a, d, c, e){
8069 this.beforeAction();
8070 var cb = this.createCB(c);
8071 supr.setWidth.call(this, w, a, d, cb, e);
8077 // overridden Element method
8078 setHeight : function(h, a, d, c, e){
8079 this.beforeAction();
8080 var cb = this.createCB(c);
8081 supr.setHeight.call(this, h, a, d, cb, e);
8087 // overridden Element method
8088 setBounds : function(x, y, w, h, a, d, c, e){
8089 this.beforeAction();
8090 var cb = this.createCB(c);
8092 this.storeXY([x, y]);
8093 supr.setXY.call(this, [x, y]);
8094 supr.setSize.call(this, w, h, a, d, cb, e);
8097 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8103 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8104 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8105 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8106 * @param {Number} zindex The new z-index to set
8107 * @return {this} The Layer
8109 setZIndex : function(zindex){
8110 this.zindex = zindex;
8111 this.setStyle("z-index", zindex + 2);
8113 this.shadow.setZIndex(zindex + 1);
8116 this.shim.setStyle("z-index", zindex);
8122 * Ext JS Library 1.1.1
8123 * Copyright(c) 2006-2007, Ext JS, LLC.
8125 * Originally Released Under LGPL - original licence link has changed is not relivant.
8128 * <script type="text/javascript">
8134 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8135 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8136 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8138 * Create a new Shadow
8139 * @param {Object} config The config object
8141 Roo.Shadow = function(config){
8142 Roo.apply(this, config);
8143 if(typeof this.mode != "string"){
8144 this.mode = this.defaultMode;
8146 var o = this.offset, a = {h: 0};
8147 var rad = Math.floor(this.offset/2);
8148 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8154 a.l -= this.offset + rad;
8155 a.t -= this.offset + rad;
8166 a.l -= (this.offset - rad);
8167 a.t -= this.offset + rad;
8169 a.w -= (this.offset - rad)*2;
8180 a.l -= (this.offset - rad);
8181 a.t -= (this.offset - rad);
8183 a.w -= (this.offset + rad + 1);
8184 a.h -= (this.offset + rad);
8193 Roo.Shadow.prototype = {
8195 * @cfg {String} mode
8196 * The shadow display mode. Supports the following options:<br />
8197 * sides: Shadow displays on both sides and bottom only<br />
8198 * frame: Shadow displays equally on all four sides<br />
8199 * drop: Traditional bottom-right drop shadow (default)
8202 * @cfg {String} offset
8203 * The number of pixels to offset the shadow from the element (defaults to 4)
8208 defaultMode: "drop",
8211 * Displays the shadow under the target element
8212 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8214 show : function(target){
8215 target = Roo.get(target);
8217 this.el = Roo.Shadow.Pool.pull();
8218 if(this.el.dom.nextSibling != target.dom){
8219 this.el.insertBefore(target);
8222 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8224 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8227 target.getLeft(true),
8228 target.getTop(true),
8232 this.el.dom.style.display = "block";
8236 * Returns true if the shadow is visible, else false
8238 isVisible : function(){
8239 return this.el ? true : false;
8243 * Direct alignment when values are already available. Show must be called at least once before
8244 * calling this method to ensure it is initialized.
8245 * @param {Number} left The target element left position
8246 * @param {Number} top The target element top position
8247 * @param {Number} width The target element width
8248 * @param {Number} height The target element height
8250 realign : function(l, t, w, h){
8254 var a = this.adjusts, d = this.el.dom, s = d.style;
8256 s.left = (l+a.l)+"px";
8257 s.top = (t+a.t)+"px";
8258 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8260 if(s.width != sws || s.height != shs){
8264 var cn = d.childNodes;
8265 var sww = Math.max(0, (sw-12))+"px";
8266 cn[0].childNodes[1].style.width = sww;
8267 cn[1].childNodes[1].style.width = sww;
8268 cn[2].childNodes[1].style.width = sww;
8269 cn[1].style.height = Math.max(0, (sh-12))+"px";
8279 this.el.dom.style.display = "none";
8280 Roo.Shadow.Pool.push(this.el);
8286 * Adjust the z-index of this shadow
8287 * @param {Number} zindex The new z-index
8289 setZIndex : function(z){
8292 this.el.setStyle("z-index", z);
8297 // Private utility class that manages the internal Shadow cache
8298 Roo.Shadow.Pool = function(){
8300 var markup = Roo.isIE ?
8301 '<div class="x-ie-shadow"></div>' :
8302 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
8307 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8308 sh.autoBoxAdjust = false;
8313 push : function(sh){
8319 * Ext JS Library 1.1.1
8320 * Copyright(c) 2006-2007, Ext JS, LLC.
8322 * Originally Released Under LGPL - original licence link has changed is not relivant.
8325 * <script type="text/javascript">
8329 * @class Roo.BoxComponent
8330 * @extends Roo.Component
8331 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8332 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8333 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8334 * layout containers.
8336 * @param {Roo.Element/String/Object} config The configuration options.
8338 Roo.BoxComponent = function(config){
8339 Roo.Component.call(this, config);
8343 * Fires after the component is resized.
8344 * @param {Roo.Component} this
8345 * @param {Number} adjWidth The box-adjusted width that was set
8346 * @param {Number} adjHeight The box-adjusted height that was set
8347 * @param {Number} rawWidth The width that was originally specified
8348 * @param {Number} rawHeight The height that was originally specified
8353 * Fires after the component is moved.
8354 * @param {Roo.Component} this
8355 * @param {Number} x The new x position
8356 * @param {Number} y The new y position
8362 Roo.extend(Roo.BoxComponent, Roo.Component, {
8363 // private, set in afterRender to signify that the component has been rendered
8365 // private, used to defer height settings to subclasses
8367 /** @cfg {Number} width
8368 * width (optional) size of component
8370 /** @cfg {Number} height
8371 * height (optional) size of component
8375 * Sets the width and height of the component. This method fires the resize event. This method can accept
8376 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8377 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8378 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8379 * @return {Roo.BoxComponent} this
8381 setSize : function(w, h){
8382 // support for standard size objects
8383 if(typeof w == 'object'){
8394 // prevent recalcs when not needed
8395 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8398 this.lastSize = {width: w, height: h};
8400 var adj = this.adjustSize(w, h);
8401 var aw = adj.width, ah = adj.height;
8402 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8403 var rz = this.getResizeEl();
8404 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8406 }else if(!this.deferHeight && ah !== undefined){
8408 }else if(aw !== undefined){
8411 this.onResize(aw, ah, w, h);
8412 this.fireEvent('resize', this, aw, ah, w, h);
8418 * Gets the current size of the component's underlying element.
8419 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8421 getSize : function(){
8422 return this.el.getSize();
8426 * Gets the current XY position of the component's underlying element.
8427 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8428 * @return {Array} The XY position of the element (e.g., [100, 200])
8430 getPosition : function(local){
8432 return [this.el.getLeft(true), this.el.getTop(true)];
8434 return this.xy || this.el.getXY();
8438 * Gets the current box measurements of the component's underlying element.
8439 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8440 * @returns {Object} box An object in the format {x, y, width, height}
8442 getBox : function(local){
8443 var s = this.el.getSize();
8445 s.x = this.el.getLeft(true);
8446 s.y = this.el.getTop(true);
8448 var xy = this.xy || this.el.getXY();
8456 * Sets the current box measurements of the component's underlying element.
8457 * @param {Object} box An object in the format {x, y, width, height}
8458 * @returns {Roo.BoxComponent} this
8460 updateBox : function(box){
8461 this.setSize(box.width, box.height);
8462 this.setPagePosition(box.x, box.y);
8467 getResizeEl : function(){
8468 return this.resizeEl || this.el;
8472 getPositionEl : function(){
8473 return this.positionEl || this.el;
8477 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8478 * This method fires the move event.
8479 * @param {Number} left The new left
8480 * @param {Number} top The new top
8481 * @returns {Roo.BoxComponent} this
8483 setPosition : function(x, y){
8489 var adj = this.adjustPosition(x, y);
8490 var ax = adj.x, ay = adj.y;
8492 var el = this.getPositionEl();
8493 if(ax !== undefined || ay !== undefined){
8494 if(ax !== undefined && ay !== undefined){
8495 el.setLeftTop(ax, ay);
8496 }else if(ax !== undefined){
8498 }else if(ay !== undefined){
8501 this.onPosition(ax, ay);
8502 this.fireEvent('move', this, ax, ay);
8508 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8509 * This method fires the move event.
8510 * @param {Number} x The new x position
8511 * @param {Number} y The new y position
8512 * @returns {Roo.BoxComponent} this
8514 setPagePosition : function(x, y){
8520 if(x === undefined || y === undefined){ // cannot translate undefined points
8523 var p = this.el.translatePoints(x, y);
8524 this.setPosition(p.left, p.top);
8529 onRender : function(ct, position){
8530 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8532 this.resizeEl = Roo.get(this.resizeEl);
8534 if(this.positionEl){
8535 this.positionEl = Roo.get(this.positionEl);
8540 afterRender : function(){
8541 Roo.BoxComponent.superclass.afterRender.call(this);
8542 this.boxReady = true;
8543 this.setSize(this.width, this.height);
8544 if(this.x || this.y){
8545 this.setPosition(this.x, this.y);
8547 if(this.pageX || this.pageY){
8548 this.setPagePosition(this.pageX, this.pageY);
8553 * Force the component's size to recalculate based on the underlying element's current height and width.
8554 * @returns {Roo.BoxComponent} this
8556 syncSize : function(){
8557 delete this.lastSize;
8558 this.setSize(this.el.getWidth(), this.el.getHeight());
8563 * Called after the component is resized, this method is empty by default but can be implemented by any
8564 * subclass that needs to perform custom logic after a resize occurs.
8565 * @param {Number} adjWidth The box-adjusted width that was set
8566 * @param {Number} adjHeight The box-adjusted height that was set
8567 * @param {Number} rawWidth The width that was originally specified
8568 * @param {Number} rawHeight The height that was originally specified
8570 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8575 * Called after the component is moved, this method is empty by default but can be implemented by any
8576 * subclass that needs to perform custom logic after a move occurs.
8577 * @param {Number} x The new x position
8578 * @param {Number} y The new y position
8580 onPosition : function(x, y){
8585 adjustSize : function(w, h){
8589 if(this.autoHeight){
8592 return {width : w, height: h};
8596 adjustPosition : function(x, y){
8597 return {x : x, y: y};
8601 * Ext JS Library 1.1.1
8602 * Copyright(c) 2006-2007, Ext JS, LLC.
8604 * Originally Released Under LGPL - original licence link has changed is not relivant.
8607 * <script type="text/javascript">
8612 * @class Roo.SplitBar
8613 * @extends Roo.util.Observable
8614 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8618 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8619 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8620 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8621 split.minSize = 100;
8622 split.maxSize = 600;
8623 split.animate = true;
8624 split.on('moved', splitterMoved);
8627 * Create a new SplitBar
8628 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8629 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8630 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8631 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8632 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8633 position of the SplitBar).
8635 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8638 this.el = Roo.get(dragElement, true);
8639 this.el.dom.unselectable = "on";
8641 this.resizingEl = Roo.get(resizingElement, true);
8645 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8646 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8649 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8652 * The minimum size of the resizing element. (Defaults to 0)
8658 * The maximum size of the resizing element. (Defaults to 2000)
8661 this.maxSize = 2000;
8664 * Whether to animate the transition to the new size
8667 this.animate = false;
8670 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8673 this.useShim = false;
8680 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8682 this.proxy = Roo.get(existingProxy).dom;
8685 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8688 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8691 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8694 this.dragSpecs = {};
8697 * @private The adapter to use to positon and resize elements
8699 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8700 this.adapter.init(this);
8702 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8704 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8705 this.el.addClass("x-splitbar-h");
8708 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8709 this.el.addClass("x-splitbar-v");
8715 * Fires when the splitter is moved (alias for {@link #event-moved})
8716 * @param {Roo.SplitBar} this
8717 * @param {Number} newSize the new width or height
8722 * Fires when the splitter is moved
8723 * @param {Roo.SplitBar} this
8724 * @param {Number} newSize the new width or height
8728 * @event beforeresize
8729 * Fires before the splitter is dragged
8730 * @param {Roo.SplitBar} this
8732 "beforeresize" : true,
8734 "beforeapply" : true
8737 Roo.util.Observable.call(this);
8740 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8741 onStartProxyDrag : function(x, y){
8742 this.fireEvent("beforeresize", this);
8744 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8746 o.enableDisplayMode("block");
8747 // all splitbars share the same overlay
8748 Roo.SplitBar.prototype.overlay = o;
8750 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8751 this.overlay.show();
8752 Roo.get(this.proxy).setDisplayed("block");
8753 var size = this.adapter.getElementSize(this);
8754 this.activeMinSize = this.getMinimumSize();;
8755 this.activeMaxSize = this.getMaximumSize();;
8756 var c1 = size - this.activeMinSize;
8757 var c2 = Math.max(this.activeMaxSize - size, 0);
8758 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8759 this.dd.resetConstraints();
8760 this.dd.setXConstraint(
8761 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8762 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8764 this.dd.setYConstraint(0, 0);
8766 this.dd.resetConstraints();
8767 this.dd.setXConstraint(0, 0);
8768 this.dd.setYConstraint(
8769 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8770 this.placement == Roo.SplitBar.TOP ? c2 : c1
8773 this.dragSpecs.startSize = size;
8774 this.dragSpecs.startPoint = [x, y];
8775 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8779 * @private Called after the drag operation by the DDProxy
8781 onEndProxyDrag : function(e){
8782 Roo.get(this.proxy).setDisplayed(false);
8783 var endPoint = Roo.lib.Event.getXY(e);
8785 this.overlay.hide();
8788 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8789 newSize = this.dragSpecs.startSize +
8790 (this.placement == Roo.SplitBar.LEFT ?
8791 endPoint[0] - this.dragSpecs.startPoint[0] :
8792 this.dragSpecs.startPoint[0] - endPoint[0]
8795 newSize = this.dragSpecs.startSize +
8796 (this.placement == Roo.SplitBar.TOP ?
8797 endPoint[1] - this.dragSpecs.startPoint[1] :
8798 this.dragSpecs.startPoint[1] - endPoint[1]
8801 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8802 if(newSize != this.dragSpecs.startSize){
8803 if(this.fireEvent('beforeapply', this, newSize) !== false){
8804 this.adapter.setElementSize(this, newSize);
8805 this.fireEvent("moved", this, newSize);
8806 this.fireEvent("resize", this, newSize);
8812 * Get the adapter this SplitBar uses
8813 * @return The adapter object
8815 getAdapter : function(){
8816 return this.adapter;
8820 * Set the adapter this SplitBar uses
8821 * @param {Object} adapter A SplitBar adapter object
8823 setAdapter : function(adapter){
8824 this.adapter = adapter;
8825 this.adapter.init(this);
8829 * Gets the minimum size for the resizing element
8830 * @return {Number} The minimum size
8832 getMinimumSize : function(){
8833 return this.minSize;
8837 * Sets the minimum size for the resizing element
8838 * @param {Number} minSize The minimum size
8840 setMinimumSize : function(minSize){
8841 this.minSize = minSize;
8845 * Gets the maximum size for the resizing element
8846 * @return {Number} The maximum size
8848 getMaximumSize : function(){
8849 return this.maxSize;
8853 * Sets the maximum size for the resizing element
8854 * @param {Number} maxSize The maximum size
8856 setMaximumSize : function(maxSize){
8857 this.maxSize = maxSize;
8861 * Sets the initialize size for the resizing element
8862 * @param {Number} size The initial size
8864 setCurrentSize : function(size){
8865 var oldAnimate = this.animate;
8866 this.animate = false;
8867 this.adapter.setElementSize(this, size);
8868 this.animate = oldAnimate;
8872 * Destroy this splitbar.
8873 * @param {Boolean} removeEl True to remove the element
8875 destroy : function(removeEl){
8880 this.proxy.parentNode.removeChild(this.proxy);
8888 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
8890 Roo.SplitBar.createProxy = function(dir){
8891 var proxy = new Roo.Element(document.createElement("div"));
8892 proxy.unselectable();
8893 var cls = 'x-splitbar-proxy';
8894 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8895 document.body.appendChild(proxy.dom);
8900 * @class Roo.SplitBar.BasicLayoutAdapter
8901 * Default Adapter. It assumes the splitter and resizing element are not positioned
8902 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8904 Roo.SplitBar.BasicLayoutAdapter = function(){
8907 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8908 // do nothing for now
8913 * Called before drag operations to get the current size of the resizing element.
8914 * @param {Roo.SplitBar} s The SplitBar using this adapter
8916 getElementSize : function(s){
8917 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8918 return s.resizingEl.getWidth();
8920 return s.resizingEl.getHeight();
8925 * Called after drag operations to set the size of the resizing element.
8926 * @param {Roo.SplitBar} s The SplitBar using this adapter
8927 * @param {Number} newSize The new size to set
8928 * @param {Function} onComplete A function to be invoked when resizing is complete
8930 setElementSize : function(s, newSize, onComplete){
8931 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8933 s.resizingEl.setWidth(newSize);
8935 onComplete(s, newSize);
8938 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8943 s.resizingEl.setHeight(newSize);
8945 onComplete(s, newSize);
8948 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8955 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8956 * @extends Roo.SplitBar.BasicLayoutAdapter
8957 * Adapter that moves the splitter element to align with the resized sizing element.
8958 * Used with an absolute positioned SplitBar.
8959 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8960 * document.body, make sure you assign an id to the body element.
8962 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8963 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8964 this.container = Roo.get(container);
8967 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8972 getElementSize : function(s){
8973 return this.basic.getElementSize(s);
8976 setElementSize : function(s, newSize, onComplete){
8977 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8980 moveSplitter : function(s){
8981 var yes = Roo.SplitBar;
8982 switch(s.placement){
8984 s.el.setX(s.resizingEl.getRight());
8987 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
8990 s.el.setY(s.resizingEl.getBottom());
8993 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9000 * Orientation constant - Create a vertical SplitBar
9004 Roo.SplitBar.VERTICAL = 1;
9007 * Orientation constant - Create a horizontal SplitBar
9011 Roo.SplitBar.HORIZONTAL = 2;
9014 * Placement constant - The resizing element is to the left of the splitter element
9018 Roo.SplitBar.LEFT = 1;
9021 * Placement constant - The resizing element is to the right of the splitter element
9025 Roo.SplitBar.RIGHT = 2;
9028 * Placement constant - The resizing element is positioned above the splitter element
9032 Roo.SplitBar.TOP = 3;
9035 * Placement constant - The resizing element is positioned under splitter element
9039 Roo.SplitBar.BOTTOM = 4;
9042 * Ext JS Library 1.1.1
9043 * Copyright(c) 2006-2007, Ext JS, LLC.
9045 * Originally Released Under LGPL - original licence link has changed is not relivant.
9048 * <script type="text/javascript">
9053 * @extends Roo.util.Observable
9054 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9055 * This class also supports single and multi selection modes. <br>
9056 * Create a data model bound view:
9058 var store = new Roo.data.Store(...);
9060 var view = new Roo.View({
9062 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9065 selectedClass: "ydataview-selected",
9069 // listen for node click?
9070 view.on("click", function(vw, index, node, e){
9071 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9075 dataModel.load("foobar.xml");
9077 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9079 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9080 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9082 * Note: old style constructor is still suported (container, template, config)
9086 * @param {Object} config The config object
9089 Roo.View = function(config, depreciated_tpl, depreciated_config){
9091 if (typeof(depreciated_tpl) == 'undefined') {
9092 // new way.. - universal constructor.
9093 Roo.apply(this, config);
9094 this.el = Roo.get(this.el);
9097 this.el = Roo.get(config);
9098 this.tpl = depreciated_tpl;
9099 Roo.apply(this, depreciated_config);
9103 if(typeof(this.tpl) == "string"){
9104 this.tpl = new Roo.Template(this.tpl);
9106 // support xtype ctors..
9107 this.tpl = new Roo.factory(this.tpl, Roo);
9118 * @event beforeclick
9119 * Fires before a click is processed. Returns false to cancel the default action.
9120 * @param {Roo.View} this
9121 * @param {Number} index The index of the target node
9122 * @param {HTMLElement} node The target node
9123 * @param {Roo.EventObject} e The raw event object
9125 "beforeclick" : true,
9128 * Fires when a template node is clicked.
9129 * @param {Roo.View} this
9130 * @param {Number} index The index of the target node
9131 * @param {HTMLElement} node The target node
9132 * @param {Roo.EventObject} e The raw event object
9137 * Fires when a template node is double clicked.
9138 * @param {Roo.View} this
9139 * @param {Number} index The index of the target node
9140 * @param {HTMLElement} node The target node
9141 * @param {Roo.EventObject} e The raw event object
9145 * @event contextmenu
9146 * Fires when a template node is right clicked.
9147 * @param {Roo.View} this
9148 * @param {Number} index The index of the target node
9149 * @param {HTMLElement} node The target node
9150 * @param {Roo.EventObject} e The raw event object
9152 "contextmenu" : true,
9154 * @event selectionchange
9155 * Fires when the selected nodes change.
9156 * @param {Roo.View} this
9157 * @param {Array} selections Array of the selected nodes
9159 "selectionchange" : true,
9162 * @event beforeselect
9163 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9164 * @param {Roo.View} this
9165 * @param {HTMLElement} node The node to be selected
9166 * @param {Array} selections Array of currently selected nodes
9168 "beforeselect" : true
9172 "click": this.onClick,
9173 "dblclick": this.onDblClick,
9174 "contextmenu": this.onContextMenu,
9178 this.selections = [];
9180 this.cmp = new Roo.CompositeElementLite([]);
9182 this.store = Roo.factory(this.store, Roo.data);
9183 this.setStore(this.store, true);
9185 Roo.View.superclass.constructor.call(this);
9188 Roo.extend(Roo.View, Roo.util.Observable, {
9191 * @cfg {Roo.data.Store} store Data store to load data from.
9196 * @cfg {String|Roo.Element} el The container element.
9201 * @cfg {String|Roo.Template} tpl The template used by this View
9206 * @cfg {String} selectedClass The css class to add to selected nodes
9208 selectedClass : "x-view-selected",
9210 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9214 * @cfg {Boolean} multiSelect Allow multiple selection
9217 multiSelect : false,
9219 * @cfg {Boolean} singleSelect Allow single selection
9221 singleSelect: false,
9224 * Returns the element this view is bound to.
9225 * @return {Roo.Element}
9232 * Refreshes the view.
9234 refresh : function(){
9236 this.clearSelections();
9239 var records = this.store.getRange();
9240 if(records.length < 1){
9241 this.el.update(this.emptyText);
9244 for(var i = 0, len = records.length; i < len; i++){
9245 var data = this.prepareData(records[i].data, i, records[i]);
9246 html[html.length] = t.apply(data);
9248 this.el.update(html.join(""));
9249 this.nodes = this.el.dom.childNodes;
9250 this.updateIndexes(0);
9254 * Function to override to reformat the data that is sent to
9255 * the template for each node.
9256 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9257 * a JSON object for an UpdateManager bound view).
9259 prepareData : function(data){
9263 onUpdate : function(ds, record){
9264 this.clearSelections();
9265 var index = this.store.indexOf(record);
9266 var n = this.nodes[index];
9267 this.tpl.insertBefore(n, this.prepareData(record.data));
9268 n.parentNode.removeChild(n);
9269 this.updateIndexes(index, index);
9272 onAdd : function(ds, records, index){
9273 this.clearSelections();
9274 if(this.nodes.length == 0){
9278 var n = this.nodes[index];
9279 for(var i = 0, len = records.length; i < len; i++){
9280 var d = this.prepareData(records[i].data);
9282 this.tpl.insertBefore(n, d);
9284 this.tpl.append(this.el, d);
9287 this.updateIndexes(index);
9290 onRemove : function(ds, record, index){
9291 this.clearSelections();
9292 this.el.dom.removeChild(this.nodes[index]);
9293 this.updateIndexes(index);
9297 * Refresh an individual node.
9298 * @param {Number} index
9300 refreshNode : function(index){
9301 this.onUpdate(this.store, this.store.getAt(index));
9304 updateIndexes : function(startIndex, endIndex){
9305 var ns = this.nodes;
9306 startIndex = startIndex || 0;
9307 endIndex = endIndex || ns.length - 1;
9308 for(var i = startIndex; i <= endIndex; i++){
9309 ns[i].nodeIndex = i;
9314 * Changes the data store this view uses and refresh the view.
9315 * @param {Store} store
9317 setStore : function(store, initial){
9318 if(!initial && this.store){
9319 this.store.un("datachanged", this.refresh);
9320 this.store.un("add", this.onAdd);
9321 this.store.un("remove", this.onRemove);
9322 this.store.un("update", this.onUpdate);
9323 this.store.un("clear", this.refresh);
9327 store.on("datachanged", this.refresh, this);
9328 store.on("add", this.onAdd, this);
9329 store.on("remove", this.onRemove, this);
9330 store.on("update", this.onUpdate, this);
9331 store.on("clear", this.refresh, this);
9340 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9341 * @param {HTMLElement} node
9342 * @return {HTMLElement} The template node
9344 findItemFromChild : function(node){
9345 var el = this.el.dom;
9346 if(!node || node.parentNode == el){
9349 var p = node.parentNode;
9350 while(p && p != el){
9351 if(p.parentNode == el){
9360 onClick : function(e){
9361 var item = this.findItemFromChild(e.getTarget());
9363 var index = this.indexOf(item);
9364 if(this.onItemClick(item, index, e) !== false){
9365 this.fireEvent("click", this, index, item, e);
9368 this.clearSelections();
9373 onContextMenu : function(e){
9374 var item = this.findItemFromChild(e.getTarget());
9376 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9381 onDblClick : function(e){
9382 var item = this.findItemFromChild(e.getTarget());
9384 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9388 onItemClick : function(item, index, e){
9389 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9392 if(this.multiSelect || this.singleSelect){
9393 if(this.multiSelect && e.shiftKey && this.lastSelection){
9394 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9396 this.select(item, this.multiSelect && e.ctrlKey);
9397 this.lastSelection = item;
9405 * Get the number of selected nodes.
9408 getSelectionCount : function(){
9409 return this.selections.length;
9413 * Get the currently selected nodes.
9414 * @return {Array} An array of HTMLElements
9416 getSelectedNodes : function(){
9417 return this.selections;
9421 * Get the indexes of the selected nodes.
9424 getSelectedIndexes : function(){
9425 var indexes = [], s = this.selections;
9426 for(var i = 0, len = s.length; i < len; i++){
9427 indexes.push(s[i].nodeIndex);
9433 * Clear all selections
9434 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9436 clearSelections : function(suppressEvent){
9437 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9438 this.cmp.elements = this.selections;
9439 this.cmp.removeClass(this.selectedClass);
9440 this.selections = [];
9442 this.fireEvent("selectionchange", this, this.selections);
9448 * Returns true if the passed node is selected
9449 * @param {HTMLElement/Number} node The node or node index
9452 isSelected : function(node){
9453 var s = this.selections;
9457 node = this.getNode(node);
9458 return s.indexOf(node) !== -1;
9463 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
9464 * @param {Boolean} keepExisting (optional) true to keep existing selections
9465 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9467 select : function(nodeInfo, keepExisting, suppressEvent){
9468 if(nodeInfo instanceof Array){
9470 this.clearSelections(true);
9472 for(var i = 0, len = nodeInfo.length; i < len; i++){
9473 this.select(nodeInfo[i], true, true);
9476 var node = this.getNode(nodeInfo);
9477 if(node && !this.isSelected(node)){
9479 this.clearSelections(true);
9481 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9482 Roo.fly(node).addClass(this.selectedClass);
9483 this.selections.push(node);
9485 this.fireEvent("selectionchange", this, this.selections);
9493 * Gets a template node.
9494 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9495 * @return {HTMLElement} The node or null if it wasn't found
9497 getNode : function(nodeInfo){
9498 if(typeof nodeInfo == "string"){
9499 return document.getElementById(nodeInfo);
9500 }else if(typeof nodeInfo == "number"){
9501 return this.nodes[nodeInfo];
9507 * Gets a range template nodes.
9508 * @param {Number} startIndex
9509 * @param {Number} endIndex
9510 * @return {Array} An array of nodes
9512 getNodes : function(start, end){
9513 var ns = this.nodes;
9515 end = typeof end == "undefined" ? ns.length - 1 : end;
9518 for(var i = start; i <= end; i++){
9522 for(var i = start; i >= end; i--){
9530 * Finds the index of the passed node
9531 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9532 * @return {Number} The index of the node or -1
9534 indexOf : function(node){
9535 node = this.getNode(node);
9536 if(typeof node.nodeIndex == "number"){
9537 return node.nodeIndex;
9539 var ns = this.nodes;
9540 for(var i = 0, len = ns.length; i < len; i++){
9550 * Ext JS Library 1.1.1
9551 * Copyright(c) 2006-2007, Ext JS, LLC.
9553 * Originally Released Under LGPL - original licence link has changed is not relivant.
9556 * <script type="text/javascript">
9560 * @class Roo.JsonView
9562 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9564 var view = new Roo.JsonView({
9565 container: "my-element",
9566 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9571 // listen for node click?
9572 view.on("click", function(vw, index, node, e){
9573 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9576 // direct load of JSON data
9577 view.load("foobar.php");
9579 // Example from my blog list
9580 var tpl = new Roo.Template(
9581 '<div class="entry">' +
9582 '<a class="entry-title" href="{link}">{title}</a>' +
9583 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9584 "</div><hr />"
9587 var moreView = new Roo.JsonView({
9588 container : "entry-list",
9592 moreView.on("beforerender", this.sortEntries, this);
9594 url: "/blog/get-posts.php",
9595 params: "allposts=true",
9596 text: "Loading Blog Entries..."
9600 * Note: old code is supported with arguments : (container, template, config)
9604 * Create a new JsonView
9606 * @param {Object} config The config object
9609 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9612 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9614 var um = this.el.getUpdateManager();
9615 um.setRenderer(this);
9616 um.on("update", this.onLoad, this);
9617 um.on("failure", this.onLoadException, this);
9620 * @event beforerender
9621 * Fires before rendering of the downloaded JSON data.
9622 * @param {Roo.JsonView} this
9623 * @param {Object} data The JSON data loaded
9627 * Fires when data is loaded.
9628 * @param {Roo.JsonView} this
9629 * @param {Object} data The JSON data loaded
9630 * @param {Object} response The raw Connect response object
9633 * @event loadexception
9634 * Fires when loading fails.
9635 * @param {Roo.JsonView} this
9636 * @param {Object} response The raw Connect response object
9639 'beforerender' : true,
9641 'loadexception' : true
9644 Roo.extend(Roo.JsonView, Roo.View, {
9646 * @type {String} The root property in the loaded JSON object that contains the data
9651 * Refreshes the view.
9653 refresh : function(){
9654 this.clearSelections();
9657 var o = this.jsonData;
9658 if(o && o.length > 0){
9659 for(var i = 0, len = o.length; i < len; i++){
9660 var data = this.prepareData(o[i], i, o);
9661 html[html.length] = this.tpl.apply(data);
9664 html.push(this.emptyText);
9666 this.el.update(html.join(""));
9667 this.nodes = this.el.dom.childNodes;
9668 this.updateIndexes(0);
9672 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
9673 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
9676 url: "your-url.php",
9677 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9678 callback: yourFunction,
9679 scope: yourObject, //(optional scope)
9687 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9688 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
9689 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
9690 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9691 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
9694 var um = this.el.getUpdateManager();
9695 um.update.apply(um, arguments);
9698 render : function(el, response){
9699 this.clearSelections();
9703 o = Roo.util.JSON.decode(response.responseText);
9706 o = o[this.jsonRoot];
9711 * The current JSON data or null
9714 this.beforeRender();
9719 * Get the number of records in the current JSON dataset
9722 getCount : function(){
9723 return this.jsonData ? this.jsonData.length : 0;
9727 * Returns the JSON object for the specified node(s)
9728 * @param {HTMLElement/Array} node The node or an array of nodes
9729 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9730 * you get the JSON object for the node
9732 getNodeData : function(node){
9733 if(node instanceof Array){
9735 for(var i = 0, len = node.length; i < len; i++){
9736 data.push(this.getNodeData(node[i]));
9740 return this.jsonData[this.indexOf(node)] || null;
9743 beforeRender : function(){
9744 this.snapshot = this.jsonData;
9746 this.sort.apply(this, this.sortInfo);
9748 this.fireEvent("beforerender", this, this.jsonData);
9751 onLoad : function(el, o){
9752 this.fireEvent("load", this, this.jsonData, o);
9755 onLoadException : function(el, o){
9756 this.fireEvent("loadexception", this, o);
9760 * Filter the data by a specific property.
9761 * @param {String} property A property on your JSON objects
9762 * @param {String/RegExp} value Either string that the property values
9763 * should start with, or a RegExp to test against the property
9765 filter : function(property, value){
9768 var ss = this.snapshot;
9769 if(typeof value == "string"){
9770 var vlen = value.length;
9775 value = value.toLowerCase();
9776 for(var i = 0, len = ss.length; i < len; i++){
9778 if(o[property].substr(0, vlen).toLowerCase() == value){
9782 } else if(value.exec){ // regex?
9783 for(var i = 0, len = ss.length; i < len; i++){
9785 if(value.test(o[property])){
9792 this.jsonData = data;
9798 * Filter by a function. The passed function will be called with each
9799 * object in the current dataset. If the function returns true the value is kept,
9800 * otherwise it is filtered.
9801 * @param {Function} fn
9802 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9804 filterBy : function(fn, scope){
9807 var ss = this.snapshot;
9808 for(var i = 0, len = ss.length; i < len; i++){
9810 if(fn.call(scope || this, o)){
9814 this.jsonData = data;
9820 * Clears the current filter.
9822 clearFilter : function(){
9823 if(this.snapshot && this.jsonData != this.snapshot){
9824 this.jsonData = this.snapshot;
9831 * Sorts the data for this view and refreshes it.
9832 * @param {String} property A property on your JSON objects to sort on
9833 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9834 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9836 sort : function(property, dir, sortType){
9837 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9840 var dsc = dir && dir.toLowerCase() == "desc";
9841 var f = function(o1, o2){
9842 var v1 = sortType ? sortType(o1[p]) : o1[p];
9843 var v2 = sortType ? sortType(o2[p]) : o2[p];
9846 return dsc ? +1 : -1;
9848 return dsc ? -1 : +1;
9853 this.jsonData.sort(f);
9855 if(this.jsonData != this.snapshot){
9856 this.snapshot.sort(f);
9862 * Ext JS Library 1.1.1
9863 * Copyright(c) 2006-2007, Ext JS, LLC.
9865 * Originally Released Under LGPL - original licence link has changed is not relivant.
9868 * <script type="text/javascript">
9873 * @class Roo.ColorPalette
9874 * @extends Roo.Component
9875 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9876 * Here's an example of typical usage:
9878 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9879 cp.render('my-div');
9881 cp.on('select', function(palette, selColor){
9882 // do something with selColor
9886 * Create a new ColorPalette
9887 * @param {Object} config The config object
9889 Roo.ColorPalette = function(config){
9890 Roo.ColorPalette.superclass.constructor.call(this, config);
9894 * Fires when a color is selected
9895 * @param {ColorPalette} this
9896 * @param {String} color The 6-digit color hex code (without the # symbol)
9902 this.on("select", this.handler, this.scope, true);
9905 Roo.extend(Roo.ColorPalette, Roo.Component, {
9907 * @cfg {String} itemCls
9908 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9910 itemCls : "x-color-palette",
9912 * @cfg {String} value
9913 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9914 * the hex codes are case-sensitive.
9919 ctype: "Roo.ColorPalette",
9922 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9924 allowReselect : false,
9927 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9928 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9929 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9930 * of colors with the width setting until the box is symmetrical.</p>
9931 * <p>You can override individual colors if needed:</p>
9933 var cp = new Roo.ColorPalette();
9934 cp.colors[0] = "FF0000"; // change the first box to red
9937 Or you can provide a custom array of your own for complete control:
9939 var cp = new Roo.ColorPalette();
9940 cp.colors = ["000000", "993300", "333300"];
9945 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9946 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9947 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9948 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9949 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9953 onRender : function(container, position){
9954 var t = new Roo.MasterTemplate(
9955 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9957 var c = this.colors;
9958 for(var i = 0, len = c.length; i < len; i++){
9961 var el = document.createElement("div");
9962 el.className = this.itemCls;
9964 container.dom.insertBefore(el, position);
9965 this.el = Roo.get(el);
9966 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9967 if(this.clickEvent != 'click'){
9968 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9973 afterRender : function(){
9974 Roo.ColorPalette.superclass.afterRender.call(this);
9983 handleClick : function(e, t){
9986 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9987 this.select(c.toUpperCase());
9992 * Selects the specified color in the palette (fires the select event)
9993 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
9995 select : function(color){
9996 color = color.replace("#", "");
9997 if(color != this.value || this.allowReselect){
10000 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10002 el.child("a.color-"+color).addClass("x-color-palette-sel");
10003 this.value = color;
10004 this.fireEvent("select", this, color);
10009 * Ext JS Library 1.1.1
10010 * Copyright(c) 2006-2007, Ext JS, LLC.
10012 * Originally Released Under LGPL - original licence link has changed is not relivant.
10015 * <script type="text/javascript">
10019 * @class Roo.DatePicker
10020 * @extends Roo.Component
10021 * Simple date picker class.
10023 * Create a new DatePicker
10024 * @param {Object} config The config object
10026 Roo.DatePicker = function(config){
10027 Roo.DatePicker.superclass.constructor.call(this, config);
10029 this.value = config && config.value ?
10030 config.value.clearTime() : new Date().clearTime();
10035 * Fires when a date is selected
10036 * @param {DatePicker} this
10037 * @param {Date} date The selected date
10043 this.on("select", this.handler, this.scope || this);
10045 // build the disabledDatesRE
10046 if(!this.disabledDatesRE && this.disabledDates){
10047 var dd = this.disabledDates;
10049 for(var i = 0; i < dd.length; i++){
10051 if(i != dd.length-1) re += "|";
10053 this.disabledDatesRE = new RegExp(re + ")");
10057 Roo.extend(Roo.DatePicker, Roo.Component, {
10059 * @cfg {String} todayText
10060 * The text to display on the button that selects the current date (defaults to "Today")
10062 todayText : "Today",
10064 * @cfg {String} okText
10065 * The text to display on the ok button
10067 okText : " OK ", //   to give the user extra clicking room
10069 * @cfg {String} cancelText
10070 * The text to display on the cancel button
10072 cancelText : "Cancel",
10074 * @cfg {String} todayTip
10075 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10077 todayTip : "{0} (Spacebar)",
10079 * @cfg {Date} minDate
10080 * Minimum allowable date (JavaScript date object, defaults to null)
10084 * @cfg {Date} maxDate
10085 * Maximum allowable date (JavaScript date object, defaults to null)
10089 * @cfg {String} minText
10090 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10092 minText : "This date is before the minimum date",
10094 * @cfg {String} maxText
10095 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10097 maxText : "This date is after the maximum date",
10099 * @cfg {String} format
10100 * The default date format string which can be overriden for localization support. The format must be
10101 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10105 * @cfg {Array} disabledDays
10106 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10108 disabledDays : null,
10110 * @cfg {String} disabledDaysText
10111 * The tooltip to display when the date falls on a disabled day (defaults to "")
10113 disabledDaysText : "",
10115 * @cfg {RegExp} disabledDatesRE
10116 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10118 disabledDatesRE : null,
10120 * @cfg {String} disabledDatesText
10121 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10123 disabledDatesText : "",
10125 * @cfg {Boolean} constrainToViewport
10126 * True to constrain the date picker to the viewport (defaults to true)
10128 constrainToViewport : true,
10130 * @cfg {Array} monthNames
10131 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10133 monthNames : Date.monthNames,
10135 * @cfg {Array} dayNames
10136 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10138 dayNames : Date.dayNames,
10140 * @cfg {String} nextText
10141 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10143 nextText: 'Next Month (Control+Right)',
10145 * @cfg {String} prevText
10146 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10148 prevText: 'Previous Month (Control+Left)',
10150 * @cfg {String} monthYearText
10151 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10153 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10155 * @cfg {Number} startDay
10156 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10160 * @cfg {Bool} showClear
10161 * Show a clear button (usefull for date form elements that can be blank.)
10167 * Sets the value of the date field
10168 * @param {Date} value The date to set
10170 setValue : function(value){
10171 var old = this.value;
10172 this.value = value.clearTime(true);
10174 this.update(this.value);
10179 * Gets the current selected value of the date field
10180 * @return {Date} The selected date
10182 getValue : function(){
10187 focus : function(){
10189 this.update(this.activeDate);
10194 onRender : function(container, position){
10196 '<table cellspacing="0">',
10197 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
10198 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10199 var dn = this.dayNames;
10200 for(var i = 0; i < 7; i++){
10201 var d = this.startDay+i;
10205 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10207 m[m.length] = "</tr></thead><tbody><tr>";
10208 for(var i = 0; i < 42; i++) {
10209 if(i % 7 == 0 && i != 0){
10210 m[m.length] = "</tr><tr>";
10212 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10214 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10215 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10217 var el = document.createElement("div");
10218 el.className = "x-date-picker";
10219 el.innerHTML = m.join("");
10221 container.dom.insertBefore(el, position);
10223 this.el = Roo.get(el);
10224 this.eventEl = Roo.get(el.firstChild);
10226 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10227 handler: this.showPrevMonth,
10229 preventDefault:true,
10233 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10234 handler: this.showNextMonth,
10236 preventDefault:true,
10240 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10242 this.monthPicker = this.el.down('div.x-date-mp');
10243 this.monthPicker.enableDisplayMode('block');
10245 var kn = new Roo.KeyNav(this.eventEl, {
10246 "left" : function(e){
10248 this.showPrevMonth() :
10249 this.update(this.activeDate.add("d", -1));
10252 "right" : function(e){
10254 this.showNextMonth() :
10255 this.update(this.activeDate.add("d", 1));
10258 "up" : function(e){
10260 this.showNextYear() :
10261 this.update(this.activeDate.add("d", -7));
10264 "down" : function(e){
10266 this.showPrevYear() :
10267 this.update(this.activeDate.add("d", 7));
10270 "pageUp" : function(e){
10271 this.showNextMonth();
10274 "pageDown" : function(e){
10275 this.showPrevMonth();
10278 "enter" : function(e){
10279 e.stopPropagation();
10286 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10288 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10290 this.el.unselectable();
10292 this.cells = this.el.select("table.x-date-inner tbody td");
10293 this.textNodes = this.el.query("table.x-date-inner tbody span");
10295 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10297 tooltip: this.monthYearText
10300 this.mbtn.on('click', this.showMonthPicker, this);
10301 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10304 var today = (new Date()).dateFormat(this.format);
10306 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10307 if (this.showClear) {
10308 baseTb.add( new Roo.Toolbar.Fill());
10311 text: String.format(this.todayText, today),
10312 tooltip: String.format(this.todayTip, today),
10313 handler: this.selectToday,
10317 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10320 if (this.showClear) {
10322 baseTb.add( new Roo.Toolbar.Fill());
10325 cls: 'x-btn-icon x-btn-clear',
10326 handler: function() {
10328 this.fireEvent("select", this, '');
10338 this.update(this.value);
10341 createMonthPicker : function(){
10342 if(!this.monthPicker.dom.firstChild){
10343 var buf = ['<table border="0" cellspacing="0">'];
10344 for(var i = 0; i < 6; i++){
10346 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10347 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10349 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
10350 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10354 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10356 '</button><button type="button" class="x-date-mp-cancel">',
10358 '</button></td></tr>',
10361 this.monthPicker.update(buf.join(''));
10362 this.monthPicker.on('click', this.onMonthClick, this);
10363 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10365 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10366 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10368 this.mpMonths.each(function(m, a, i){
10371 m.dom.xmonth = 5 + Math.round(i * .5);
10373 m.dom.xmonth = Math.round((i-1) * .5);
10379 showMonthPicker : function(){
10380 this.createMonthPicker();
10381 var size = this.el.getSize();
10382 this.monthPicker.setSize(size);
10383 this.monthPicker.child('table').setSize(size);
10385 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10386 this.updateMPMonth(this.mpSelMonth);
10387 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10388 this.updateMPYear(this.mpSelYear);
10390 this.monthPicker.slideIn('t', {duration:.2});
10393 updateMPYear : function(y){
10395 var ys = this.mpYears.elements;
10396 for(var i = 1; i <= 10; i++){
10397 var td = ys[i-1], y2;
10399 y2 = y + Math.round(i * .5);
10400 td.firstChild.innerHTML = y2;
10403 y2 = y - (5-Math.round(i * .5));
10404 td.firstChild.innerHTML = y2;
10407 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10411 updateMPMonth : function(sm){
10412 this.mpMonths.each(function(m, a, i){
10413 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10417 selectMPMonth: function(m){
10421 onMonthClick : function(e, t){
10423 var el = new Roo.Element(t), pn;
10424 if(el.is('button.x-date-mp-cancel')){
10425 this.hideMonthPicker();
10427 else if(el.is('button.x-date-mp-ok')){
10428 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10429 this.hideMonthPicker();
10431 else if(pn = el.up('td.x-date-mp-month', 2)){
10432 this.mpMonths.removeClass('x-date-mp-sel');
10433 pn.addClass('x-date-mp-sel');
10434 this.mpSelMonth = pn.dom.xmonth;
10436 else if(pn = el.up('td.x-date-mp-year', 2)){
10437 this.mpYears.removeClass('x-date-mp-sel');
10438 pn.addClass('x-date-mp-sel');
10439 this.mpSelYear = pn.dom.xyear;
10441 else if(el.is('a.x-date-mp-prev')){
10442 this.updateMPYear(this.mpyear-10);
10444 else if(el.is('a.x-date-mp-next')){
10445 this.updateMPYear(this.mpyear+10);
10449 onMonthDblClick : function(e, t){
10451 var el = new Roo.Element(t), pn;
10452 if(pn = el.up('td.x-date-mp-month', 2)){
10453 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10454 this.hideMonthPicker();
10456 else if(pn = el.up('td.x-date-mp-year', 2)){
10457 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10458 this.hideMonthPicker();
10462 hideMonthPicker : function(disableAnim){
10463 if(this.monthPicker){
10464 if(disableAnim === true){
10465 this.monthPicker.hide();
10467 this.monthPicker.slideOut('t', {duration:.2});
10473 showPrevMonth : function(e){
10474 this.update(this.activeDate.add("mo", -1));
10478 showNextMonth : function(e){
10479 this.update(this.activeDate.add("mo", 1));
10483 showPrevYear : function(){
10484 this.update(this.activeDate.add("y", -1));
10488 showNextYear : function(){
10489 this.update(this.activeDate.add("y", 1));
10493 handleMouseWheel : function(e){
10494 var delta = e.getWheelDelta();
10496 this.showPrevMonth();
10498 } else if(delta < 0){
10499 this.showNextMonth();
10505 handleDateClick : function(e, t){
10507 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10508 this.setValue(new Date(t.dateValue));
10509 this.fireEvent("select", this, this.value);
10514 selectToday : function(){
10515 this.setValue(new Date().clearTime());
10516 this.fireEvent("select", this, this.value);
10520 update : function(date){
10521 var vd = this.activeDate;
10522 this.activeDate = date;
10524 var t = date.getTime();
10525 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10526 this.cells.removeClass("x-date-selected");
10527 this.cells.each(function(c){
10528 if(c.dom.firstChild.dateValue == t){
10529 c.addClass("x-date-selected");
10530 setTimeout(function(){
10531 try{c.dom.firstChild.focus();}catch(e){}
10539 var days = date.getDaysInMonth();
10540 var firstOfMonth = date.getFirstDateOfMonth();
10541 var startingPos = firstOfMonth.getDay()-this.startDay;
10543 if(startingPos <= this.startDay){
10547 var pm = date.add("mo", -1);
10548 var prevStart = pm.getDaysInMonth()-startingPos;
10550 var cells = this.cells.elements;
10551 var textEls = this.textNodes;
10552 days += startingPos;
10554 // convert everything to numbers so it's fast
10555 var day = 86400000;
10556 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10557 var today = new Date().clearTime().getTime();
10558 var sel = date.clearTime().getTime();
10559 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10560 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10561 var ddMatch = this.disabledDatesRE;
10562 var ddText = this.disabledDatesText;
10563 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10564 var ddaysText = this.disabledDaysText;
10565 var format = this.format;
10567 var setCellClass = function(cal, cell){
10569 var t = d.getTime();
10570 cell.firstChild.dateValue = t;
10572 cell.className += " x-date-today";
10573 cell.title = cal.todayText;
10576 cell.className += " x-date-selected";
10577 setTimeout(function(){
10578 try{cell.firstChild.focus();}catch(e){}
10583 cell.className = " x-date-disabled";
10584 cell.title = cal.minText;
10588 cell.className = " x-date-disabled";
10589 cell.title = cal.maxText;
10593 if(ddays.indexOf(d.getDay()) != -1){
10594 cell.title = ddaysText;
10595 cell.className = " x-date-disabled";
10598 if(ddMatch && format){
10599 var fvalue = d.dateFormat(format);
10600 if(ddMatch.test(fvalue)){
10601 cell.title = ddText.replace("%0", fvalue);
10602 cell.className = " x-date-disabled";
10608 for(; i < startingPos; i++) {
10609 textEls[i].innerHTML = (++prevStart);
10610 d.setDate(d.getDate()+1);
10611 cells[i].className = "x-date-prevday";
10612 setCellClass(this, cells[i]);
10614 for(; i < days; i++){
10615 intDay = i - startingPos + 1;
10616 textEls[i].innerHTML = (intDay);
10617 d.setDate(d.getDate()+1);
10618 cells[i].className = "x-date-active";
10619 setCellClass(this, cells[i]);
10622 for(; i < 42; i++) {
10623 textEls[i].innerHTML = (++extraDays);
10624 d.setDate(d.getDate()+1);
10625 cells[i].className = "x-date-nextday";
10626 setCellClass(this, cells[i]);
10629 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10631 if(!this.internalRender){
10632 var main = this.el.dom.firstChild;
10633 var w = main.offsetWidth;
10634 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10635 Roo.fly(main).setWidth(w);
10636 this.internalRender = true;
10637 // opera does not respect the auto grow header center column
10638 // then, after it gets a width opera refuses to recalculate
10639 // without a second pass
10640 if(Roo.isOpera && !this.secondPass){
10641 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10642 this.secondPass = true;
10643 this.update.defer(10, this, [date]);
10649 * Ext JS Library 1.1.1
10650 * Copyright(c) 2006-2007, Ext JS, LLC.
10652 * Originally Released Under LGPL - original licence link has changed is not relivant.
10655 * <script type="text/javascript">
10658 * @class Roo.TabPanel
10659 * @extends Roo.util.Observable
10660 * A lightweight tab container.
10664 // basic tabs 1, built from existing content
10665 var tabs = new Roo.TabPanel("tabs1");
10666 tabs.addTab("script", "View Script");
10667 tabs.addTab("markup", "View Markup");
10668 tabs.activate("script");
10670 // more advanced tabs, built from javascript
10671 var jtabs = new Roo.TabPanel("jtabs");
10672 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10674 // set up the UpdateManager
10675 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10676 var updater = tab2.getUpdateManager();
10677 updater.setDefaultUrl("ajax1.htm");
10678 tab2.on('activate', updater.refresh, updater, true);
10680 // Use setUrl for Ajax loading
10681 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10682 tab3.setUrl("ajax2.htm", null, true);
10685 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10688 jtabs.activate("jtabs-1");
10691 * Create a new TabPanel.
10692 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10693 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10695 Roo.TabPanel = function(container, config){
10697 * The container element for this TabPanel.
10698 * @type Roo.Element
10700 this.el = Roo.get(container, true);
10702 if(typeof config == "boolean"){
10703 this.tabPosition = config ? "bottom" : "top";
10705 Roo.apply(this, config);
10708 if(this.tabPosition == "bottom"){
10709 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10710 this.el.addClass("x-tabs-bottom");
10712 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10713 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10714 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10716 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10718 if(this.tabPosition != "bottom"){
10719 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10720 * @type Roo.Element
10722 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10723 this.el.addClass("x-tabs-top");
10727 this.bodyEl.setStyle("position", "relative");
10729 this.active = null;
10730 this.activateDelegate = this.activate.createDelegate(this);
10735 * Fires when the active tab changes
10736 * @param {Roo.TabPanel} this
10737 * @param {Roo.TabPanelItem} activePanel The new active tab
10741 * @event beforetabchange
10742 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10743 * @param {Roo.TabPanel} this
10744 * @param {Object} e Set cancel to true on this object to cancel the tab change
10745 * @param {Roo.TabPanelItem} tab The tab being changed to
10747 "beforetabchange" : true
10750 Roo.EventManager.onWindowResize(this.onResize, this);
10751 this.cpad = this.el.getPadding("lr");
10752 this.hiddenCount = 0;
10754 Roo.TabPanel.superclass.constructor.call(this);
10757 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10759 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10761 tabPosition : "top",
10763 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10765 currentTabWidth : 0,
10767 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10771 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10775 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10777 preferredTabWidth : 175,
10779 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10781 resizeTabs : false,
10783 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10785 monitorResize : true,
10788 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10789 * @param {String} id The id of the div to use <b>or create</b>
10790 * @param {String} text The text for the tab
10791 * @param {String} content (optional) Content to put in the TabPanelItem body
10792 * @param {Boolean} closable (optional) True to create a close icon on the tab
10793 * @return {Roo.TabPanelItem} The created TabPanelItem
10795 addTab : function(id, text, content, closable){
10796 var item = new Roo.TabPanelItem(this, id, text, closable);
10797 this.addTabItem(item);
10799 item.setContent(content);
10805 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10806 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10807 * @return {Roo.TabPanelItem}
10809 getTab : function(id){
10810 return this.items[id];
10814 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10815 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10817 hideTab : function(id){
10818 var t = this.items[id];
10821 this.hiddenCount++;
10822 this.autoSizeTabs();
10827 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10828 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10830 unhideTab : function(id){
10831 var t = this.items[id];
10833 t.setHidden(false);
10834 this.hiddenCount--;
10835 this.autoSizeTabs();
10840 * Adds an existing {@link Roo.TabPanelItem}.
10841 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10843 addTabItem : function(item){
10844 this.items[item.id] = item;
10845 this.items.push(item);
10846 if(this.resizeTabs){
10847 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10848 this.autoSizeTabs();
10855 * Removes a {@link Roo.TabPanelItem}.
10856 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10858 removeTab : function(id){
10859 var items = this.items;
10860 var tab = items[id];
10861 if(!tab) { return; }
10862 var index = items.indexOf(tab);
10863 if(this.active == tab && items.length > 1){
10864 var newTab = this.getNextAvailable(index);
10869 this.stripEl.dom.removeChild(tab.pnode.dom);
10870 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10871 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10873 items.splice(index, 1);
10874 delete this.items[tab.id];
10875 tab.fireEvent("close", tab);
10876 tab.purgeListeners();
10877 this.autoSizeTabs();
10880 getNextAvailable : function(start){
10881 var items = this.items;
10883 // look for a next tab that will slide over to
10884 // replace the one being removed
10885 while(index < items.length){
10886 var item = items[++index];
10887 if(item && !item.isHidden()){
10891 // if one isn't found select the previous tab (on the left)
10894 var item = items[--index];
10895 if(item && !item.isHidden()){
10903 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10904 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10906 disableTab : function(id){
10907 var tab = this.items[id];
10908 if(tab && this.active != tab){
10914 * Enables a {@link Roo.TabPanelItem} that is disabled.
10915 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10917 enableTab : function(id){
10918 var tab = this.items[id];
10923 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10924 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10925 * @return {Roo.TabPanelItem} The TabPanelItem.
10927 activate : function(id){
10928 var tab = this.items[id];
10932 if(tab == this.active || tab.disabled){
10936 this.fireEvent("beforetabchange", this, e, tab);
10937 if(e.cancel !== true && !tab.disabled){
10939 this.active.hide();
10941 this.active = this.items[id];
10942 this.active.show();
10943 this.fireEvent("tabchange", this, this.active);
10949 * Gets the active {@link Roo.TabPanelItem}.
10950 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10952 getActiveTab : function(){
10953 return this.active;
10957 * Updates the tab body element to fit the height of the container element
10958 * for overflow scrolling
10959 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10961 syncHeight : function(targetHeight){
10962 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10963 var bm = this.bodyEl.getMargins();
10964 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10965 this.bodyEl.setHeight(newHeight);
10969 onResize : function(){
10970 if(this.monitorResize){
10971 this.autoSizeTabs();
10976 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10978 beginUpdate : function(){
10979 this.updating = true;
10983 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10985 endUpdate : function(){
10986 this.updating = false;
10987 this.autoSizeTabs();
10991 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
10993 autoSizeTabs : function(){
10994 var count = this.items.length;
10995 var vcount = count - this.hiddenCount;
10996 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
10997 var w = Math.max(this.el.getWidth() - this.cpad, 10);
10998 var availWidth = Math.floor(w / vcount);
10999 var b = this.stripBody;
11000 if(b.getWidth() > w){
11001 var tabs = this.items;
11002 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11003 if(availWidth < this.minTabWidth){
11004 /*if(!this.sleft){ // incomplete scrolling code
11005 this.createScrollButtons();
11008 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11011 if(this.currentTabWidth < this.preferredTabWidth){
11012 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11018 * Returns the number of tabs in this TabPanel.
11021 getCount : function(){
11022 return this.items.length;
11026 * Resizes all the tabs to the passed width
11027 * @param {Number} The new width
11029 setTabWidth : function(width){
11030 this.currentTabWidth = width;
11031 for(var i = 0, len = this.items.length; i < len; i++) {
11032 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11037 * Destroys this TabPanel
11038 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11040 destroy : function(removeEl){
11041 Roo.EventManager.removeResizeListener(this.onResize, this);
11042 for(var i = 0, len = this.items.length; i < len; i++){
11043 this.items[i].purgeListeners();
11045 if(removeEl === true){
11046 this.el.update("");
11053 * @class Roo.TabPanelItem
11054 * @extends Roo.util.Observable
11055 * Represents an individual item (tab plus body) in a TabPanel.
11056 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11057 * @param {String} id The id of this TabPanelItem
11058 * @param {String} text The text for the tab of this TabPanelItem
11059 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11061 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11063 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11064 * @type Roo.TabPanel
11066 this.tabPanel = tabPanel;
11068 * The id for this TabPanelItem
11073 this.disabled = false;
11077 this.loaded = false;
11078 this.closable = closable;
11081 * The body element for this TabPanelItem.
11082 * @type Roo.Element
11084 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11085 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11086 this.bodyEl.setStyle("display", "block");
11087 this.bodyEl.setStyle("zoom", "1");
11090 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11092 this.el = Roo.get(els.el, true);
11093 this.inner = Roo.get(els.inner, true);
11094 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11095 this.pnode = Roo.get(els.el.parentNode, true);
11096 this.el.on("mousedown", this.onTabMouseDown, this);
11097 this.el.on("click", this.onTabClick, this);
11100 var c = Roo.get(els.close, true);
11101 c.dom.title = this.closeText;
11102 c.addClassOnOver("close-over");
11103 c.on("click", this.closeClick, this);
11109 * Fires when this tab becomes the active tab.
11110 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11111 * @param {Roo.TabPanelItem} this
11115 * @event beforeclose
11116 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11117 * @param {Roo.TabPanelItem} this
11118 * @param {Object} e Set cancel to true on this object to cancel the close.
11120 "beforeclose": true,
11123 * Fires when this tab is closed.
11124 * @param {Roo.TabPanelItem} this
11128 * @event deactivate
11129 * Fires when this tab is no longer the active tab.
11130 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11131 * @param {Roo.TabPanelItem} this
11133 "deactivate" : true
11135 this.hidden = false;
11137 Roo.TabPanelItem.superclass.constructor.call(this);
11140 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11141 purgeListeners : function(){
11142 Roo.util.Observable.prototype.purgeListeners.call(this);
11143 this.el.removeAllListeners();
11146 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11149 this.pnode.addClass("on");
11152 this.tabPanel.stripWrap.repaint();
11154 this.fireEvent("activate", this.tabPanel, this);
11158 * Returns true if this tab is the active tab.
11159 * @return {Boolean}
11161 isActive : function(){
11162 return this.tabPanel.getActiveTab() == this;
11166 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11169 this.pnode.removeClass("on");
11171 this.fireEvent("deactivate", this.tabPanel, this);
11174 hideAction : function(){
11175 this.bodyEl.hide();
11176 this.bodyEl.setStyle("position", "absolute");
11177 this.bodyEl.setLeft("-20000px");
11178 this.bodyEl.setTop("-20000px");
11181 showAction : function(){
11182 this.bodyEl.setStyle("position", "relative");
11183 this.bodyEl.setTop("");
11184 this.bodyEl.setLeft("");
11185 this.bodyEl.show();
11189 * Set the tooltip for the tab.
11190 * @param {String} tooltip The tab's tooltip
11192 setTooltip : function(text){
11193 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11194 this.textEl.dom.qtip = text;
11195 this.textEl.dom.removeAttribute('title');
11197 this.textEl.dom.title = text;
11201 onTabClick : function(e){
11202 e.preventDefault();
11203 this.tabPanel.activate(this.id);
11206 onTabMouseDown : function(e){
11207 e.preventDefault();
11208 this.tabPanel.activate(this.id);
11211 getWidth : function(){
11212 return this.inner.getWidth();
11215 setWidth : function(width){
11216 var iwidth = width - this.pnode.getPadding("lr");
11217 this.inner.setWidth(iwidth);
11218 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11219 this.pnode.setWidth(width);
11223 * Show or hide the tab
11224 * @param {Boolean} hidden True to hide or false to show.
11226 setHidden : function(hidden){
11227 this.hidden = hidden;
11228 this.pnode.setStyle("display", hidden ? "none" : "");
11232 * Returns true if this tab is "hidden"
11233 * @return {Boolean}
11235 isHidden : function(){
11236 return this.hidden;
11240 * Returns the text for this tab
11243 getText : function(){
11247 autoSize : function(){
11248 //this.el.beginMeasure();
11249 this.textEl.setWidth(1);
11250 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11251 //this.el.endMeasure();
11255 * Sets the text for the tab (Note: this also sets the tooltip text)
11256 * @param {String} text The tab's text and tooltip
11258 setText : function(text){
11260 this.textEl.update(text);
11261 this.setTooltip(text);
11262 if(!this.tabPanel.resizeTabs){
11267 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11269 activate : function(){
11270 this.tabPanel.activate(this.id);
11274 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11276 disable : function(){
11277 if(this.tabPanel.active != this){
11278 this.disabled = true;
11279 this.pnode.addClass("disabled");
11284 * Enables this TabPanelItem if it was previously disabled.
11286 enable : function(){
11287 this.disabled = false;
11288 this.pnode.removeClass("disabled");
11292 * Sets the content for this TabPanelItem.
11293 * @param {String} content The content
11294 * @param {Boolean} loadScripts true to look for and load scripts
11296 setContent : function(content, loadScripts){
11297 this.bodyEl.update(content, loadScripts);
11301 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11302 * @return {Roo.UpdateManager} The UpdateManager
11304 getUpdateManager : function(){
11305 return this.bodyEl.getUpdateManager();
11309 * Set a URL to be used to load the content for this TabPanelItem.
11310 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11311 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
11312 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
11313 * @return {Roo.UpdateManager} The UpdateManager
11315 setUrl : function(url, params, loadOnce){
11316 if(this.refreshDelegate){
11317 this.un('activate', this.refreshDelegate);
11319 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11320 this.on("activate", this.refreshDelegate);
11321 return this.bodyEl.getUpdateManager();
11325 _handleRefresh : function(url, params, loadOnce){
11326 if(!loadOnce || !this.loaded){
11327 var updater = this.bodyEl.getUpdateManager();
11328 updater.update(url, params, this._setLoaded.createDelegate(this));
11333 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11334 * Will fail silently if the setUrl method has not been called.
11335 * This does not activate the panel, just updates its content.
11337 refresh : function(){
11338 if(this.refreshDelegate){
11339 this.loaded = false;
11340 this.refreshDelegate();
11345 _setLoaded : function(){
11346 this.loaded = true;
11350 closeClick : function(e){
11353 this.fireEvent("beforeclose", this, o);
11354 if(o.cancel !== true){
11355 this.tabPanel.removeTab(this.id);
11359 * The text displayed in the tooltip for the close icon.
11362 closeText : "Close this tab"
11366 Roo.TabPanel.prototype.createStrip = function(container){
11367 var strip = document.createElement("div");
11368 strip.className = "x-tabs-wrap";
11369 container.appendChild(strip);
11373 Roo.TabPanel.prototype.createStripList = function(strip){
11374 // div wrapper for retard IE
11375 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11376 return strip.firstChild.firstChild.firstChild.firstChild;
11379 Roo.TabPanel.prototype.createBody = function(container){
11380 var body = document.createElement("div");
11381 Roo.id(body, "tab-body");
11382 Roo.fly(body).addClass("x-tabs-body");
11383 container.appendChild(body);
11387 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11388 var body = Roo.getDom(id);
11390 body = document.createElement("div");
11393 Roo.fly(body).addClass("x-tabs-item-body");
11394 bodyEl.insertBefore(body, bodyEl.firstChild);
11398 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11399 var td = document.createElement("td");
11400 stripEl.appendChild(td);
11402 td.className = "x-tabs-closable";
11403 if(!this.closeTpl){
11404 this.closeTpl = new Roo.Template(
11405 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11406 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11407 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11410 var el = this.closeTpl.overwrite(td, {"text": text});
11411 var close = el.getElementsByTagName("div")[0];
11412 var inner = el.getElementsByTagName("em")[0];
11413 return {"el": el, "close": close, "inner": inner};
11416 this.tabTpl = new Roo.Template(
11417 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11418 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11421 var el = this.tabTpl.overwrite(td, {"text": text});
11422 var inner = el.getElementsByTagName("em")[0];
11423 return {"el": el, "inner": inner};
11427 * Ext JS Library 1.1.1
11428 * Copyright(c) 2006-2007, Ext JS, LLC.
11430 * Originally Released Under LGPL - original licence link has changed is not relivant.
11433 * <script type="text/javascript">
11437 * @class Roo.Button
11438 * @extends Roo.util.Observable
11439 * Simple Button class
11440 * @cfg {String} text The button text
11441 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11442 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11443 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11444 * @cfg {Object} scope The scope of the handler
11445 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11446 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11447 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11448 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11449 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11450 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11451 applies if enableToggle = true)
11452 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11453 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11454 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11456 * Create a new button
11457 * @param {Object} config The config object
11459 Roo.Button = function(renderTo, config)
11463 renderTo = config.renderTo || false;
11466 Roo.apply(this, config);
11470 * Fires when this button is clicked
11471 * @param {Button} this
11472 * @param {EventObject} e The click event
11477 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11478 * @param {Button} this
11479 * @param {Boolean} pressed
11484 * Fires when the mouse hovers over the button
11485 * @param {Button} this
11486 * @param {Event} e The event object
11488 'mouseover' : true,
11491 * Fires when the mouse exits the button
11492 * @param {Button} this
11493 * @param {Event} e The event object
11498 * Fires when the button is rendered
11499 * @param {Button} this
11504 this.menu = Roo.menu.MenuMgr.get(this.menu);
11506 // register listeners first!! - so render can be captured..
11507 Roo.util.Observable.call(this);
11509 this.render(renderTo);
11515 Roo.extend(Roo.Button, Roo.util.Observable, {
11521 * Read-only. True if this button is hidden
11526 * Read-only. True if this button is disabled
11531 * Read-only. True if this button is pressed (only if enableToggle = true)
11537 * @cfg {Number} tabIndex
11538 * The DOM tabIndex for this button (defaults to undefined)
11540 tabIndex : undefined,
11543 * @cfg {Boolean} enableToggle
11544 * True to enable pressed/not pressed toggling (defaults to false)
11546 enableToggle: false,
11548 * @cfg {Mixed} menu
11549 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11553 * @cfg {String} menuAlign
11554 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11556 menuAlign : "tl-bl?",
11559 * @cfg {String} iconCls
11560 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11562 iconCls : undefined,
11564 * @cfg {String} type
11565 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11570 menuClassTarget: 'tr',
11573 * @cfg {String} clickEvent
11574 * The type of event to map to the button's event handler (defaults to 'click')
11576 clickEvent : 'click',
11579 * @cfg {Boolean} handleMouseEvents
11580 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11582 handleMouseEvents : true,
11585 * @cfg {String} tooltipType
11586 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11588 tooltipType : 'qtip',
11591 * @cfg {String} cls
11592 * A CSS class to apply to the button's main element.
11596 * @cfg {Roo.Template} template (Optional)
11597 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11598 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11599 * require code modifications if required elements (e.g. a button) aren't present.
11603 render : function(renderTo){
11605 if(this.hideParent){
11606 this.parentEl = Roo.get(renderTo);
11608 if(!this.dhconfig){
11609 if(!this.template){
11610 if(!Roo.Button.buttonTemplate){
11611 // hideous table template
11612 Roo.Button.buttonTemplate = new Roo.Template(
11613 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11614 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
11615 "</tr></tbody></table>");
11617 this.template = Roo.Button.buttonTemplate;
11619 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11620 var btnEl = btn.child("button:first");
11621 btnEl.on('focus', this.onFocus, this);
11622 btnEl.on('blur', this.onBlur, this);
11624 btn.addClass(this.cls);
11627 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11630 btnEl.addClass(this.iconCls);
11632 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11635 if(this.tabIndex !== undefined){
11636 btnEl.dom.tabIndex = this.tabIndex;
11639 if(typeof this.tooltip == 'object'){
11640 Roo.QuickTips.tips(Roo.apply({
11644 btnEl.dom[this.tooltipType] = this.tooltip;
11648 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11652 this.el.dom.id = this.el.id = this.id;
11655 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11656 this.menu.on("show", this.onMenuShow, this);
11657 this.menu.on("hide", this.onMenuHide, this);
11659 btn.addClass("x-btn");
11660 if(Roo.isIE && !Roo.isIE7){
11661 this.autoWidth.defer(1, this);
11665 if(this.handleMouseEvents){
11666 btn.on("mouseover", this.onMouseOver, this);
11667 btn.on("mouseout", this.onMouseOut, this);
11668 btn.on("mousedown", this.onMouseDown, this);
11670 btn.on(this.clickEvent, this.onClick, this);
11671 //btn.on("mouseup", this.onMouseUp, this);
11678 Roo.ButtonToggleMgr.register(this);
11680 this.el.addClass("x-btn-pressed");
11683 var repeater = new Roo.util.ClickRepeater(btn,
11684 typeof this.repeat == "object" ? this.repeat : {}
11686 repeater.on("click", this.onClick, this);
11689 this.fireEvent('render', this);
11693 * Returns the button's underlying element
11694 * @return {Roo.Element} The element
11696 getEl : function(){
11701 * Destroys this Button and removes any listeners.
11703 destroy : function(){
11704 Roo.ButtonToggleMgr.unregister(this);
11705 this.el.removeAllListeners();
11706 this.purgeListeners();
11711 autoWidth : function(){
11713 this.el.setWidth("auto");
11714 if(Roo.isIE7 && Roo.isStrict){
11715 var ib = this.el.child('button');
11716 if(ib && ib.getWidth() > 20){
11718 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11723 this.el.beginMeasure();
11725 if(this.el.getWidth() < this.minWidth){
11726 this.el.setWidth(this.minWidth);
11729 this.el.endMeasure();
11736 * Assigns this button's click handler
11737 * @param {Function} handler The function to call when the button is clicked
11738 * @param {Object} scope (optional) Scope for the function passed in
11740 setHandler : function(handler, scope){
11741 this.handler = handler;
11742 this.scope = scope;
11746 * Sets this button's text
11747 * @param {String} text The button text
11749 setText : function(text){
11752 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11758 * Gets the text for this button
11759 * @return {String} The button text
11761 getText : function(){
11769 this.hidden = false;
11771 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11779 this.hidden = true;
11781 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11786 * Convenience function for boolean show/hide
11787 * @param {Boolean} visible True to show, false to hide
11789 setVisible: function(visible){
11798 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11799 * @param {Boolean} state (optional) Force a particular state
11801 toggle : function(state){
11802 state = state === undefined ? !this.pressed : state;
11803 if(state != this.pressed){
11805 this.el.addClass("x-btn-pressed");
11806 this.pressed = true;
11807 this.fireEvent("toggle", this, true);
11809 this.el.removeClass("x-btn-pressed");
11810 this.pressed = false;
11811 this.fireEvent("toggle", this, false);
11813 if(this.toggleHandler){
11814 this.toggleHandler.call(this.scope || this, this, state);
11822 focus : function(){
11823 this.el.child('button:first').focus();
11827 * Disable this button
11829 disable : function(){
11831 this.el.addClass("x-btn-disabled");
11833 this.disabled = true;
11837 * Enable this button
11839 enable : function(){
11841 this.el.removeClass("x-btn-disabled");
11843 this.disabled = false;
11847 * Convenience function for boolean enable/disable
11848 * @param {Boolean} enabled True to enable, false to disable
11850 setDisabled : function(v){
11851 this[v !== true ? "enable" : "disable"]();
11855 onClick : function(e){
11857 e.preventDefault();
11862 if(!this.disabled){
11863 if(this.enableToggle){
11866 if(this.menu && !this.menu.isVisible()){
11867 this.menu.show(this.el, this.menuAlign);
11869 this.fireEvent("click", this, e);
11871 this.el.removeClass("x-btn-over");
11872 this.handler.call(this.scope || this, this, e);
11877 onMouseOver : function(e){
11878 if(!this.disabled){
11879 this.el.addClass("x-btn-over");
11880 this.fireEvent('mouseover', this, e);
11884 onMouseOut : function(e){
11885 if(!e.within(this.el, true)){
11886 this.el.removeClass("x-btn-over");
11887 this.fireEvent('mouseout', this, e);
11891 onFocus : function(e){
11892 if(!this.disabled){
11893 this.el.addClass("x-btn-focus");
11897 onBlur : function(e){
11898 this.el.removeClass("x-btn-focus");
11901 onMouseDown : function(e){
11902 if(!this.disabled && e.button == 0){
11903 this.el.addClass("x-btn-click");
11904 Roo.get(document).on('mouseup', this.onMouseUp, this);
11908 onMouseUp : function(e){
11910 this.el.removeClass("x-btn-click");
11911 Roo.get(document).un('mouseup', this.onMouseUp, this);
11915 onMenuShow : function(e){
11916 this.el.addClass("x-btn-menu-active");
11919 onMenuHide : function(e){
11920 this.el.removeClass("x-btn-menu-active");
11924 // Private utility class used by Button
11925 Roo.ButtonToggleMgr = function(){
11928 function toggleGroup(btn, state){
11930 var g = groups[btn.toggleGroup];
11931 for(var i = 0, l = g.length; i < l; i++){
11933 g[i].toggle(false);
11940 register : function(btn){
11941 if(!btn.toggleGroup){
11944 var g = groups[btn.toggleGroup];
11946 g = groups[btn.toggleGroup] = [];
11949 btn.on("toggle", toggleGroup);
11952 unregister : function(btn){
11953 if(!btn.toggleGroup){
11956 var g = groups[btn.toggleGroup];
11959 btn.un("toggle", toggleGroup);
11965 * Ext JS Library 1.1.1
11966 * Copyright(c) 2006-2007, Ext JS, LLC.
11968 * Originally Released Under LGPL - original licence link has changed is not relivant.
11971 * <script type="text/javascript">
11975 * @class Roo.SplitButton
11976 * @extends Roo.Button
11977 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11978 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11979 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11980 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11981 * @cfg {String} arrowTooltip The title attribute of the arrow
11983 * Create a new menu button
11984 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11985 * @param {Object} config The config object
11987 Roo.SplitButton = function(renderTo, config){
11988 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
11990 * @event arrowclick
11991 * Fires when this button's arrow is clicked
11992 * @param {SplitButton} this
11993 * @param {EventObject} e The click event
11995 this.addEvents({"arrowclick":true});
11998 Roo.extend(Roo.SplitButton, Roo.Button, {
11999 render : function(renderTo){
12000 // this is one sweet looking template!
12001 var tpl = new Roo.Template(
12002 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12003 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12004 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
12005 "</tbody></table></td><td>",
12006 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12007 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
12008 "</tbody></table></td></tr></table>"
12010 var btn = tpl.append(renderTo, [this.text, this.type], true);
12011 var btnEl = btn.child("button");
12013 btn.addClass(this.cls);
12016 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12019 btnEl.addClass(this.iconCls);
12021 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12025 if(this.handleMouseEvents){
12026 btn.on("mouseover", this.onMouseOver, this);
12027 btn.on("mouseout", this.onMouseOut, this);
12028 btn.on("mousedown", this.onMouseDown, this);
12029 btn.on("mouseup", this.onMouseUp, this);
12031 btn.on(this.clickEvent, this.onClick, this);
12033 if(typeof this.tooltip == 'object'){
12034 Roo.QuickTips.tips(Roo.apply({
12038 btnEl.dom[this.tooltipType] = this.tooltip;
12041 if(this.arrowTooltip){
12042 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12051 this.el.addClass("x-btn-pressed");
12053 if(Roo.isIE && !Roo.isIE7){
12054 this.autoWidth.defer(1, this);
12059 this.menu.on("show", this.onMenuShow, this);
12060 this.menu.on("hide", this.onMenuHide, this);
12062 this.fireEvent('render', this);
12066 autoWidth : function(){
12068 var tbl = this.el.child("table:first");
12069 var tbl2 = this.el.child("table:last");
12070 this.el.setWidth("auto");
12071 tbl.setWidth("auto");
12072 if(Roo.isIE7 && Roo.isStrict){
12073 var ib = this.el.child('button:first');
12074 if(ib && ib.getWidth() > 20){
12076 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12081 this.el.beginMeasure();
12083 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12084 tbl.setWidth(this.minWidth-tbl2.getWidth());
12087 this.el.endMeasure();
12090 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12094 * Sets this button's click handler
12095 * @param {Function} handler The function to call when the button is clicked
12096 * @param {Object} scope (optional) Scope for the function passed above
12098 setHandler : function(handler, scope){
12099 this.handler = handler;
12100 this.scope = scope;
12104 * Sets this button's arrow click handler
12105 * @param {Function} handler The function to call when the arrow is clicked
12106 * @param {Object} scope (optional) Scope for the function passed above
12108 setArrowHandler : function(handler, scope){
12109 this.arrowHandler = handler;
12110 this.scope = scope;
12116 focus : function(){
12118 this.el.child("button:first").focus();
12123 onClick : function(e){
12124 e.preventDefault();
12125 if(!this.disabled){
12126 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12127 if(this.menu && !this.menu.isVisible()){
12128 this.menu.show(this.el, this.menuAlign);
12130 this.fireEvent("arrowclick", this, e);
12131 if(this.arrowHandler){
12132 this.arrowHandler.call(this.scope || this, this, e);
12135 this.fireEvent("click", this, e);
12137 this.handler.call(this.scope || this, this, e);
12143 onMouseDown : function(e){
12144 if(!this.disabled){
12145 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12149 onMouseUp : function(e){
12150 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12155 // backwards compat
12156 Roo.MenuButton = Roo.SplitButton;/*
12158 * Ext JS Library 1.1.1
12159 * Copyright(c) 2006-2007, Ext JS, LLC.
12161 * Originally Released Under LGPL - original licence link has changed is not relivant.
12164 * <script type="text/javascript">
12168 * @class Roo.Toolbar
12169 * Basic Toolbar class.
12171 * Creates a new Toolbar
12172 * @param {Object} config The config object
12174 Roo.Toolbar = function(container, buttons, config)
12176 /// old consturctor format still supported..
12177 if(container instanceof Array){ // omit the container for later rendering
12178 buttons = container;
12182 if (typeof(container) == 'object' && container.xtype) {
12183 config = container;
12184 container = config.container;
12185 buttons = config.buttons; // not really - use items!!
12188 if (config && config.items) {
12189 xitems = config.items;
12190 delete config.items;
12192 Roo.apply(this, config);
12193 this.buttons = buttons;
12196 this.render(container);
12198 Roo.each(xitems, function(b) {
12204 Roo.Toolbar.prototype = {
12206 * @cfg {Roo.data.Store} items
12207 * array of button configs or elements to add
12211 * @cfg {String/HTMLElement/Element} container
12212 * The id or element that will contain the toolbar
12215 render : function(ct){
12216 this.el = Roo.get(ct);
12218 this.el.addClass(this.cls);
12220 // using a table allows for vertical alignment
12221 // 100% width is needed by Safari...
12222 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12223 this.tr = this.el.child("tr", true);
12225 this.items = new Roo.util.MixedCollection(false, function(o){
12226 return o.id || ("item" + (++autoId));
12229 this.add.apply(this, this.buttons);
12230 delete this.buttons;
12235 * Adds element(s) to the toolbar -- this function takes a variable number of
12236 * arguments of mixed type and adds them to the toolbar.
12237 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12239 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12240 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12241 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12242 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12243 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12244 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12245 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12246 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12247 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12249 * @param {Mixed} arg2
12250 * @param {Mixed} etc.
12253 var a = arguments, l = a.length;
12254 for(var i = 0; i < l; i++){
12259 _add : function(el) {
12262 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12265 if (el.applyTo){ // some kind of form field
12266 return this.addField(el);
12268 if (el.render){ // some kind of Toolbar.Item
12269 return this.addItem(el);
12271 if (typeof el == "string"){ // string
12272 if(el == "separator" || el == "-"){
12273 return this.addSeparator();
12276 return this.addSpacer();
12279 return this.addFill();
12281 return this.addText(el);
12284 if(el.tagName){ // element
12285 return this.addElement(el);
12287 if(typeof el == "object"){ // must be button config?
12288 return this.addButton(el);
12290 // and now what?!?!
12296 * Add an Xtype element
12297 * @param {Object} xtype Xtype Object
12298 * @return {Object} created Object
12300 addxtype : function(e){
12301 return this.add(e);
12305 * Returns the Element for this toolbar.
12306 * @return {Roo.Element}
12308 getEl : function(){
12314 * @return {Roo.Toolbar.Item} The separator item
12316 addSeparator : function(){
12317 return this.addItem(new Roo.Toolbar.Separator());
12321 * Adds a spacer element
12322 * @return {Roo.Toolbar.Spacer} The spacer item
12324 addSpacer : function(){
12325 return this.addItem(new Roo.Toolbar.Spacer());
12329 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12330 * @return {Roo.Toolbar.Fill} The fill item
12332 addFill : function(){
12333 return this.addItem(new Roo.Toolbar.Fill());
12337 * Adds any standard HTML element to the toolbar
12338 * @param {String/HTMLElement/Element} el The element or id of the element to add
12339 * @return {Roo.Toolbar.Item} The element's item
12341 addElement : function(el){
12342 return this.addItem(new Roo.Toolbar.Item(el));
12345 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12346 * @type Roo.util.MixedCollection
12351 * Adds any Toolbar.Item or subclass
12352 * @param {Roo.Toolbar.Item} item
12353 * @return {Roo.Toolbar.Item} The item
12355 addItem : function(item){
12356 var td = this.nextBlock();
12358 this.items.add(item);
12363 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12364 * @param {Object/Array} config A button config or array of configs
12365 * @return {Roo.Toolbar.Button/Array}
12367 addButton : function(config){
12368 if(config instanceof Array){
12370 for(var i = 0, len = config.length; i < len; i++) {
12371 buttons.push(this.addButton(config[i]));
12376 if(!(config instanceof Roo.Toolbar.Button)){
12378 new Roo.Toolbar.SplitButton(config) :
12379 new Roo.Toolbar.Button(config);
12381 var td = this.nextBlock();
12388 * Adds text to the toolbar
12389 * @param {String} text The text to add
12390 * @return {Roo.Toolbar.Item} The element's item
12392 addText : function(text){
12393 return this.addItem(new Roo.Toolbar.TextItem(text));
12397 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12398 * @param {Number} index The index where the item is to be inserted
12399 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12400 * @return {Roo.Toolbar.Button/Item}
12402 insertButton : function(index, item){
12403 if(item instanceof Array){
12405 for(var i = 0, len = item.length; i < len; i++) {
12406 buttons.push(this.insertButton(index + i, item[i]));
12410 if (!(item instanceof Roo.Toolbar.Button)){
12411 item = new Roo.Toolbar.Button(item);
12413 var td = document.createElement("td");
12414 this.tr.insertBefore(td, this.tr.childNodes[index]);
12416 this.items.insert(index, item);
12421 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12422 * @param {Object} config
12423 * @return {Roo.Toolbar.Item} The element's item
12425 addDom : function(config, returnEl){
12426 var td = this.nextBlock();
12427 Roo.DomHelper.overwrite(td, config);
12428 var ti = new Roo.Toolbar.Item(td.firstChild);
12430 this.items.add(ti);
12435 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12436 * @type Roo.util.MixedCollection
12441 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12442 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12443 * @param {Roo.form.Field} field
12444 * @return {Roo.ToolbarItem}
12448 addField : function(field) {
12449 if (!this.fields) {
12451 this.fields = new Roo.util.MixedCollection(false, function(o){
12452 return o.id || ("item" + (++autoId));
12457 var td = this.nextBlock();
12459 var ti = new Roo.Toolbar.Item(td.firstChild);
12461 this.items.add(ti);
12462 this.fields.add(field);
12473 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12474 this.el.child('div').hide();
12482 this.el.child('div').show();
12486 nextBlock : function(){
12487 var td = document.createElement("td");
12488 this.tr.appendChild(td);
12493 destroy : function(){
12494 if(this.items){ // rendered?
12495 Roo.destroy.apply(Roo, this.items.items);
12497 if(this.fields){ // rendered?
12498 Roo.destroy.apply(Roo, this.fields.items);
12500 Roo.Element.uncache(this.el, this.tr);
12505 * @class Roo.Toolbar.Item
12506 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12508 * Creates a new Item
12509 * @param {HTMLElement} el
12511 Roo.Toolbar.Item = function(el){
12512 this.el = Roo.getDom(el);
12513 this.id = Roo.id(this.el);
12514 this.hidden = false;
12517 Roo.Toolbar.Item.prototype = {
12520 * Get this item's HTML Element
12521 * @return {HTMLElement}
12523 getEl : function(){
12528 render : function(td){
12530 td.appendChild(this.el);
12534 * Removes and destroys this item.
12536 destroy : function(){
12537 this.td.parentNode.removeChild(this.td);
12544 this.hidden = false;
12545 this.td.style.display = "";
12552 this.hidden = true;
12553 this.td.style.display = "none";
12557 * Convenience function for boolean show/hide.
12558 * @param {Boolean} visible true to show/false to hide
12560 setVisible: function(visible){
12569 * Try to focus this item.
12571 focus : function(){
12572 Roo.fly(this.el).focus();
12576 * Disables this item.
12578 disable : function(){
12579 Roo.fly(this.td).addClass("x-item-disabled");
12580 this.disabled = true;
12581 this.el.disabled = true;
12585 * Enables this item.
12587 enable : function(){
12588 Roo.fly(this.td).removeClass("x-item-disabled");
12589 this.disabled = false;
12590 this.el.disabled = false;
12596 * @class Roo.Toolbar.Separator
12597 * @extends Roo.Toolbar.Item
12598 * A simple toolbar separator class
12600 * Creates a new Separator
12602 Roo.Toolbar.Separator = function(){
12603 var s = document.createElement("span");
12604 s.className = "ytb-sep";
12605 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12607 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12608 enable:Roo.emptyFn,
12609 disable:Roo.emptyFn,
12614 * @class Roo.Toolbar.Spacer
12615 * @extends Roo.Toolbar.Item
12616 * A simple element that adds extra horizontal space to a toolbar.
12618 * Creates a new Spacer
12620 Roo.Toolbar.Spacer = function(){
12621 var s = document.createElement("div");
12622 s.className = "ytb-spacer";
12623 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12625 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12626 enable:Roo.emptyFn,
12627 disable:Roo.emptyFn,
12632 * @class Roo.Toolbar.Fill
12633 * @extends Roo.Toolbar.Spacer
12634 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12636 * Creates a new Spacer
12638 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12640 render : function(td){
12641 td.style.width = '100%';
12642 Roo.Toolbar.Fill.superclass.render.call(this, td);
12647 * @class Roo.Toolbar.TextItem
12648 * @extends Roo.Toolbar.Item
12649 * A simple class that renders text directly into a toolbar.
12651 * Creates a new TextItem
12652 * @param {String} text
12654 Roo.Toolbar.TextItem = function(text){
12655 if (typeof(text) == 'object') {
12658 var s = document.createElement("span");
12659 s.className = "ytb-text";
12660 s.innerHTML = text;
12661 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12663 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12664 enable:Roo.emptyFn,
12665 disable:Roo.emptyFn,
12670 * @class Roo.Toolbar.Button
12671 * @extends Roo.Button
12672 * A button that renders into a toolbar.
12674 * Creates a new Button
12675 * @param {Object} config A standard {@link Roo.Button} config object
12677 Roo.Toolbar.Button = function(config){
12678 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12680 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12681 render : function(td){
12683 Roo.Toolbar.Button.superclass.render.call(this, td);
12687 * Removes and destroys this button
12689 destroy : function(){
12690 Roo.Toolbar.Button.superclass.destroy.call(this);
12691 this.td.parentNode.removeChild(this.td);
12695 * Shows this button
12698 this.hidden = false;
12699 this.td.style.display = "";
12703 * Hides this button
12706 this.hidden = true;
12707 this.td.style.display = "none";
12711 * Disables this item
12713 disable : function(){
12714 Roo.fly(this.td).addClass("x-item-disabled");
12715 this.disabled = true;
12719 * Enables this item
12721 enable : function(){
12722 Roo.fly(this.td).removeClass("x-item-disabled");
12723 this.disabled = false;
12726 // backwards compat
12727 Roo.ToolbarButton = Roo.Toolbar.Button;
12730 * @class Roo.Toolbar.SplitButton
12731 * @extends Roo.SplitButton
12732 * A menu button that renders into a toolbar.
12734 * Creates a new SplitButton
12735 * @param {Object} config A standard {@link Roo.SplitButton} config object
12737 Roo.Toolbar.SplitButton = function(config){
12738 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12740 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12741 render : function(td){
12743 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12747 * Removes and destroys this button
12749 destroy : function(){
12750 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12751 this.td.parentNode.removeChild(this.td);
12755 * Shows this button
12758 this.hidden = false;
12759 this.td.style.display = "";
12763 * Hides this button
12766 this.hidden = true;
12767 this.td.style.display = "none";
12771 // backwards compat
12772 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12774 * Ext JS Library 1.1.1
12775 * Copyright(c) 2006-2007, Ext JS, LLC.
12777 * Originally Released Under LGPL - original licence link has changed is not relivant.
12780 * <script type="text/javascript">
12784 * @class Roo.PagingToolbar
12785 * @extends Roo.Toolbar
12786 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12788 * Create a new PagingToolbar
12789 * @param {Object} config The config object
12791 Roo.PagingToolbar = function(el, ds, config)
12793 // old args format still supported... - xtype is prefered..
12794 if (typeof(el) == 'object' && el.xtype) {
12795 // created from xtype...
12797 ds = el.dataSource;
12798 el = config.container;
12801 if (config.items) {
12802 items = config.items;
12806 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12809 this.renderButtons(this.el);
12812 // supprot items array.
12814 Roo.each(items, function(e) {
12815 this.add(Roo.factory(e));
12820 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12822 * @cfg {Roo.data.Store} dataSource
12823 * The underlying data store providing the paged data
12826 * @cfg {String/HTMLElement/Element} container
12827 * container The id or element that will contain the toolbar
12830 * @cfg {Boolean} displayInfo
12831 * True to display the displayMsg (defaults to false)
12834 * @cfg {Number} pageSize
12835 * The number of records to display per page (defaults to 20)
12839 * @cfg {String} displayMsg
12840 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12842 displayMsg : 'Displaying {0} - {1} of {2}',
12844 * @cfg {String} emptyMsg
12845 * The message to display when no records are found (defaults to "No data to display")
12847 emptyMsg : 'No data to display',
12849 * Customizable piece of the default paging text (defaults to "Page")
12852 beforePageText : "Page",
12854 * Customizable piece of the default paging text (defaults to "of %0")
12857 afterPageText : "of {0}",
12859 * Customizable piece of the default paging text (defaults to "First Page")
12862 firstText : "First Page",
12864 * Customizable piece of the default paging text (defaults to "Previous Page")
12867 prevText : "Previous Page",
12869 * Customizable piece of the default paging text (defaults to "Next Page")
12872 nextText : "Next Page",
12874 * Customizable piece of the default paging text (defaults to "Last Page")
12877 lastText : "Last Page",
12879 * Customizable piece of the default paging text (defaults to "Refresh")
12882 refreshText : "Refresh",
12885 renderButtons : function(el){
12886 Roo.PagingToolbar.superclass.render.call(this, el);
12887 this.first = this.addButton({
12888 tooltip: this.firstText,
12889 cls: "x-btn-icon x-grid-page-first",
12891 handler: this.onClick.createDelegate(this, ["first"])
12893 this.prev = this.addButton({
12894 tooltip: this.prevText,
12895 cls: "x-btn-icon x-grid-page-prev",
12897 handler: this.onClick.createDelegate(this, ["prev"])
12899 //this.addSeparator();
12900 this.add(this.beforePageText);
12901 this.field = Roo.get(this.addDom({
12906 cls: "x-grid-page-number"
12908 this.field.on("keydown", this.onPagingKeydown, this);
12909 this.field.on("focus", function(){this.dom.select();});
12910 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12911 this.field.setHeight(18);
12912 //this.addSeparator();
12913 this.next = this.addButton({
12914 tooltip: this.nextText,
12915 cls: "x-btn-icon x-grid-page-next",
12917 handler: this.onClick.createDelegate(this, ["next"])
12919 this.last = this.addButton({
12920 tooltip: this.lastText,
12921 cls: "x-btn-icon x-grid-page-last",
12923 handler: this.onClick.createDelegate(this, ["last"])
12925 //this.addSeparator();
12926 this.loading = this.addButton({
12927 tooltip: this.refreshText,
12928 cls: "x-btn-icon x-grid-loading",
12929 handler: this.onClick.createDelegate(this, ["refresh"])
12932 if(this.displayInfo){
12933 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12938 updateInfo : function(){
12939 if(this.displayEl){
12940 var count = this.ds.getCount();
12941 var msg = count == 0 ?
12945 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12947 this.displayEl.update(msg);
12952 onLoad : function(ds, r, o){
12953 this.cursor = o.params ? o.params.start : 0;
12954 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12956 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12957 this.field.dom.value = ap;
12958 this.first.setDisabled(ap == 1);
12959 this.prev.setDisabled(ap == 1);
12960 this.next.setDisabled(ap == ps);
12961 this.last.setDisabled(ap == ps);
12962 this.loading.enable();
12967 getPageData : function(){
12968 var total = this.ds.getTotalCount();
12971 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12972 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12977 onLoadError : function(){
12978 this.loading.enable();
12982 onPagingKeydown : function(e){
12983 var k = e.getKey();
12984 var d = this.getPageData();
12986 var v = this.field.dom.value, pageNum;
12987 if(!v || isNaN(pageNum = parseInt(v, 10))){
12988 this.field.dom.value = d.activePage;
12991 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
12992 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
12995 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
12997 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
12998 this.field.dom.value = pageNum;
12999 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13002 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13004 var v = this.field.dom.value, pageNum;
13005 var increment = (e.shiftKey) ? 10 : 1;
13006 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13008 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13009 this.field.dom.value = d.activePage;
13012 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13014 this.field.dom.value = parseInt(v, 10) + increment;
13015 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13016 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13023 beforeLoad : function(){
13025 this.loading.disable();
13030 onClick : function(which){
13034 ds.load({params:{start: 0, limit: this.pageSize}});
13037 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13040 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13043 var total = ds.getTotalCount();
13044 var extra = total % this.pageSize;
13045 var lastStart = extra ? (total - extra) : total-this.pageSize;
13046 ds.load({params:{start: lastStart, limit: this.pageSize}});
13049 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13055 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13056 * @param {Roo.data.Store} store The data store to unbind
13058 unbind : function(ds){
13059 ds.un("beforeload", this.beforeLoad, this);
13060 ds.un("load", this.onLoad, this);
13061 ds.un("loadexception", this.onLoadError, this);
13062 ds.un("remove", this.updateInfo, this);
13063 ds.un("add", this.updateInfo, this);
13064 this.ds = undefined;
13068 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13069 * @param {Roo.data.Store} store The data store to bind
13071 bind : function(ds){
13072 ds.on("beforeload", this.beforeLoad, this);
13073 ds.on("load", this.onLoad, this);
13074 ds.on("loadexception", this.onLoadError, this);
13075 ds.on("remove", this.updateInfo, this);
13076 ds.on("add", this.updateInfo, this);
13081 * Ext JS Library 1.1.1
13082 * Copyright(c) 2006-2007, Ext JS, LLC.
13084 * Originally Released Under LGPL - original licence link has changed is not relivant.
13087 * <script type="text/javascript">
13091 * @class Roo.Resizable
13092 * @extends Roo.util.Observable
13093 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13094 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13095 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
13096 * the element will be wrapped for you automatically.</p>
13097 * <p>Here is the list of valid resize handles:</p>
13100 ------ -------------------
13109 'hd' horizontal drag
13112 * <p>Here's an example showing the creation of a typical Resizable:</p>
13114 var resizer = new Roo.Resizable("element-id", {
13122 resizer.on("resize", myHandler);
13124 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13125 * resizer.east.setDisplayed(false);</p>
13126 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13127 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13128 * resize operation's new size (defaults to [0, 0])
13129 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13130 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13131 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13132 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13133 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13134 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13135 * @cfg {Number} width The width of the element in pixels (defaults to null)
13136 * @cfg {Number} height The height of the element in pixels (defaults to null)
13137 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13138 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13139 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13140 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13141 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13142 * in favor of the handles config option (defaults to false)
13143 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13144 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13145 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13146 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13147 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13148 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13149 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13150 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13151 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13152 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13153 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13155 * Create a new resizable component
13156 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13157 * @param {Object} config configuration options
13159 Roo.Resizable = function(el, config)
13161 this.el = Roo.get(el);
13163 if(config && config.wrap){
13164 config.resizeChild = this.el;
13165 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13166 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13167 this.el.setStyle("overflow", "hidden");
13168 this.el.setPositioning(config.resizeChild.getPositioning());
13169 config.resizeChild.clearPositioning();
13170 if(!config.width || !config.height){
13171 var csize = config.resizeChild.getSize();
13172 this.el.setSize(csize.width, csize.height);
13174 if(config.pinned && !config.adjustments){
13175 config.adjustments = "auto";
13179 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13180 this.proxy.unselectable();
13181 this.proxy.enableDisplayMode('block');
13183 Roo.apply(this, config);
13186 this.disableTrackOver = true;
13187 this.el.addClass("x-resizable-pinned");
13189 // if the element isn't positioned, make it relative
13190 var position = this.el.getStyle("position");
13191 if(position != "absolute" && position != "fixed"){
13192 this.el.setStyle("position", "relative");
13194 if(!this.handles){ // no handles passed, must be legacy style
13195 this.handles = 's,e,se';
13196 if(this.multiDirectional){
13197 this.handles += ',n,w';
13200 if(this.handles == "all"){
13201 this.handles = "n s e w ne nw se sw";
13203 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13204 var ps = Roo.Resizable.positions;
13205 for(var i = 0, len = hs.length; i < len; i++){
13206 if(hs[i] && ps[hs[i]]){
13207 var pos = ps[hs[i]];
13208 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13212 this.corner = this.southeast;
13214 // updateBox = the box can move..
13215 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13216 this.updateBox = true;
13219 this.activeHandle = null;
13221 if(this.resizeChild){
13222 if(typeof this.resizeChild == "boolean"){
13223 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13225 this.resizeChild = Roo.get(this.resizeChild, true);
13229 if(this.adjustments == "auto"){
13230 var rc = this.resizeChild;
13231 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13232 if(rc && (hw || hn)){
13233 rc.position("relative");
13234 rc.setLeft(hw ? hw.el.getWidth() : 0);
13235 rc.setTop(hn ? hn.el.getHeight() : 0);
13237 this.adjustments = [
13238 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13239 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13243 if(this.draggable){
13244 this.dd = this.dynamic ?
13245 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13246 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13252 * @event beforeresize
13253 * Fired before resize is allowed. Set enabled to false to cancel resize.
13254 * @param {Roo.Resizable} this
13255 * @param {Roo.EventObject} e The mousedown event
13257 "beforeresize" : true,
13260 * Fired after a resize.
13261 * @param {Roo.Resizable} this
13262 * @param {Number} width The new width
13263 * @param {Number} height The new height
13264 * @param {Roo.EventObject} e The mouseup event
13269 if(this.width !== null && this.height !== null){
13270 this.resizeTo(this.width, this.height);
13272 this.updateChildSize();
13275 this.el.dom.style.zoom = 1;
13277 Roo.Resizable.superclass.constructor.call(this);
13280 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13281 resizeChild : false,
13282 adjustments : [0, 0],
13292 multiDirectional : false,
13293 disableTrackOver : false,
13294 easing : 'easeOutStrong',
13295 widthIncrement : 0,
13296 heightIncrement : 0,
13300 preserveRatio : false,
13301 transparent: false,
13307 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13309 constrainTo: undefined,
13311 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13313 resizeRegion: undefined,
13317 * Perform a manual resize
13318 * @param {Number} width
13319 * @param {Number} height
13321 resizeTo : function(width, height){
13322 this.el.setSize(width, height);
13323 this.updateChildSize();
13324 this.fireEvent("resize", this, width, height, null);
13328 startSizing : function(e, handle){
13329 this.fireEvent("beforeresize", this, e);
13330 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13333 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13334 this.overlay.unselectable();
13335 this.overlay.enableDisplayMode("block");
13336 this.overlay.on("mousemove", this.onMouseMove, this);
13337 this.overlay.on("mouseup", this.onMouseUp, this);
13339 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13341 this.resizing = true;
13342 this.startBox = this.el.getBox();
13343 this.startPoint = e.getXY();
13344 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13345 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13347 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13348 this.overlay.show();
13350 if(this.constrainTo) {
13351 var ct = Roo.get(this.constrainTo);
13352 this.resizeRegion = ct.getRegion().adjust(
13353 ct.getFrameWidth('t'),
13354 ct.getFrameWidth('l'),
13355 -ct.getFrameWidth('b'),
13356 -ct.getFrameWidth('r')
13360 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13362 this.proxy.setBox(this.startBox);
13364 this.proxy.setStyle('visibility', 'visible');
13370 onMouseDown : function(handle, e){
13373 this.activeHandle = handle;
13374 this.startSizing(e, handle);
13379 onMouseUp : function(e){
13380 var size = this.resizeElement();
13381 this.resizing = false;
13383 this.overlay.hide();
13385 this.fireEvent("resize", this, size.width, size.height, e);
13389 updateChildSize : function(){
13390 if(this.resizeChild){
13392 var child = this.resizeChild;
13393 var adj = this.adjustments;
13394 if(el.dom.offsetWidth){
13395 var b = el.getSize(true);
13396 child.setSize(b.width+adj[0], b.height+adj[1]);
13398 // Second call here for IE
13399 // The first call enables instant resizing and
13400 // the second call corrects scroll bars if they
13403 setTimeout(function(){
13404 if(el.dom.offsetWidth){
13405 var b = el.getSize(true);
13406 child.setSize(b.width+adj[0], b.height+adj[1]);
13414 snap : function(value, inc, min){
13415 if(!inc || !value) return value;
13416 var newValue = value;
13417 var m = value % inc;
13420 newValue = value + (inc-m);
13422 newValue = value - m;
13425 return Math.max(min, newValue);
13429 resizeElement : function(){
13430 var box = this.proxy.getBox();
13431 if(this.updateBox){
13432 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13434 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13436 this.updateChildSize();
13444 constrain : function(v, diff, m, mx){
13447 }else if(v - diff > mx){
13454 onMouseMove : function(e){
13456 try{// try catch so if something goes wrong the user doesn't get hung
13458 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13462 //var curXY = this.startPoint;
13463 var curSize = this.curSize || this.startBox;
13464 var x = this.startBox.x, y = this.startBox.y;
13465 var ox = x, oy = y;
13466 var w = curSize.width, h = curSize.height;
13467 var ow = w, oh = h;
13468 var mw = this.minWidth, mh = this.minHeight;
13469 var mxw = this.maxWidth, mxh = this.maxHeight;
13470 var wi = this.widthIncrement;
13471 var hi = this.heightIncrement;
13473 var eventXY = e.getXY();
13474 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13475 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13477 var pos = this.activeHandle.position;
13482 w = Math.min(Math.max(mw, w), mxw);
13487 h = Math.min(Math.max(mh, h), mxh);
13492 w = Math.min(Math.max(mw, w), mxw);
13493 h = Math.min(Math.max(mh, h), mxh);
13496 diffY = this.constrain(h, diffY, mh, mxh);
13503 var adiffX = Math.abs(diffX);
13504 var sub = (adiffX % wi); // how much
13505 if (sub > (wi/2)) { // far enough to snap
13506 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13508 // remove difference..
13509 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13513 x = Math.max(this.minX, x);
13516 diffX = this.constrain(w, diffX, mw, mxw);
13522 w = Math.min(Math.max(mw, w), mxw);
13523 diffY = this.constrain(h, diffY, mh, mxh);
13528 diffX = this.constrain(w, diffX, mw, mxw);
13529 diffY = this.constrain(h, diffY, mh, mxh);
13536 diffX = this.constrain(w, diffX, mw, mxw);
13538 h = Math.min(Math.max(mh, h), mxh);
13544 var sw = this.snap(w, wi, mw);
13545 var sh = this.snap(h, hi, mh);
13546 if(sw != w || sh != h){
13569 if(this.preserveRatio){
13574 h = Math.min(Math.max(mh, h), mxh);
13579 w = Math.min(Math.max(mw, w), mxw);
13584 w = Math.min(Math.max(mw, w), mxw);
13590 w = Math.min(Math.max(mw, w), mxw);
13596 h = Math.min(Math.max(mh, h), mxh);
13604 h = Math.min(Math.max(mh, h), mxh);
13614 h = Math.min(Math.max(mh, h), mxh);
13622 if (pos == 'hdrag') {
13625 this.proxy.setBounds(x, y, w, h);
13627 this.resizeElement();
13634 handleOver : function(){
13636 this.el.addClass("x-resizable-over");
13641 handleOut : function(){
13642 if(!this.resizing){
13643 this.el.removeClass("x-resizable-over");
13648 * Returns the element this component is bound to.
13649 * @return {Roo.Element}
13651 getEl : function(){
13656 * Returns the resizeChild element (or null).
13657 * @return {Roo.Element}
13659 getResizeChild : function(){
13660 return this.resizeChild;
13664 * Destroys this resizable. If the element was wrapped and
13665 * removeEl is not true then the element remains.
13666 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13668 destroy : function(removeEl){
13669 this.proxy.remove();
13671 this.overlay.removeAllListeners();
13672 this.overlay.remove();
13674 var ps = Roo.Resizable.positions;
13676 if(typeof ps[k] != "function" && this[ps[k]]){
13677 var h = this[ps[k]];
13678 h.el.removeAllListeners();
13683 this.el.update("");
13690 // hash to map config positions to true positions
13691 Roo.Resizable.positions = {
13692 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13697 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13699 // only initialize the template if resizable is used
13700 var tpl = Roo.DomHelper.createTemplate(
13701 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13704 Roo.Resizable.Handle.prototype.tpl = tpl;
13706 this.position = pos;
13708 // show north drag fro topdra
13709 var handlepos = pos == 'hdrag' ? 'north' : pos;
13711 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13712 if (pos == 'hdrag') {
13713 this.el.setStyle('cursor', 'pointer');
13715 this.el.unselectable();
13717 this.el.setOpacity(0);
13719 this.el.on("mousedown", this.onMouseDown, this);
13720 if(!disableTrackOver){
13721 this.el.on("mouseover", this.onMouseOver, this);
13722 this.el.on("mouseout", this.onMouseOut, this);
13727 Roo.Resizable.Handle.prototype = {
13728 afterResize : function(rz){
13732 onMouseDown : function(e){
13733 this.rz.onMouseDown(this, e);
13736 onMouseOver : function(e){
13737 this.rz.handleOver(this, e);
13740 onMouseOut : function(e){
13741 this.rz.handleOut(this, e);
13745 * Ext JS Library 1.1.1
13746 * Copyright(c) 2006-2007, Ext JS, LLC.
13748 * Originally Released Under LGPL - original licence link has changed is not relivant.
13751 * <script type="text/javascript">
13755 * @class Roo.Editor
13756 * @extends Roo.Component
13757 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13759 * Create a new Editor
13760 * @param {Roo.form.Field} field The Field object (or descendant)
13761 * @param {Object} config The config object
13763 Roo.Editor = function(field, config){
13764 Roo.Editor.superclass.constructor.call(this, config);
13765 this.field = field;
13768 * @event beforestartedit
13769 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13770 * false from the handler of this event.
13771 * @param {Editor} this
13772 * @param {Roo.Element} boundEl The underlying element bound to this editor
13773 * @param {Mixed} value The field value being set
13775 "beforestartedit" : true,
13778 * Fires when this editor is displayed
13779 * @param {Roo.Element} boundEl The underlying element bound to this editor
13780 * @param {Mixed} value The starting field value
13782 "startedit" : true,
13784 * @event beforecomplete
13785 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13786 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13787 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13788 * event will not fire since no edit actually occurred.
13789 * @param {Editor} this
13790 * @param {Mixed} value The current field value
13791 * @param {Mixed} startValue The original field value
13793 "beforecomplete" : true,
13796 * Fires after editing is complete and any changed value has been written to the underlying field.
13797 * @param {Editor} this
13798 * @param {Mixed} value The current field value
13799 * @param {Mixed} startValue The original field value
13803 * @event specialkey
13804 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13805 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13806 * @param {Roo.form.Field} this
13807 * @param {Roo.EventObject} e The event object
13809 "specialkey" : true
13813 Roo.extend(Roo.Editor, Roo.Component, {
13815 * @cfg {Boolean/String} autosize
13816 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13817 * or "height" to adopt the height only (defaults to false)
13820 * @cfg {Boolean} revertInvalid
13821 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13822 * validation fails (defaults to true)
13825 * @cfg {Boolean} ignoreNoChange
13826 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13827 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13828 * will never be ignored.
13831 * @cfg {Boolean} hideEl
13832 * False to keep the bound element visible while the editor is displayed (defaults to true)
13835 * @cfg {Mixed} value
13836 * The data value of the underlying field (defaults to "")
13840 * @cfg {String} alignment
13841 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13845 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13846 * for bottom-right shadow (defaults to "frame")
13850 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13854 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13856 completeOnEnter : false,
13858 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13860 cancelOnEsc : false,
13862 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13867 onRender : function(ct, position){
13868 this.el = new Roo.Layer({
13869 shadow: this.shadow,
13875 constrain: this.constrain
13877 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13878 if(this.field.msgTarget != 'title'){
13879 this.field.msgTarget = 'qtip';
13881 this.field.render(this.el);
13883 this.field.el.dom.setAttribute('autocomplete', 'off');
13885 this.field.on("specialkey", this.onSpecialKey, this);
13886 if(this.swallowKeys){
13887 this.field.el.swallowEvent(['keydown','keypress']);
13890 this.field.on("blur", this.onBlur, this);
13891 if(this.field.grow){
13892 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13896 onSpecialKey : function(field, e){
13897 //Roo.log('editor onSpecialKey');
13898 if(this.completeOnEnter && e.getKey() == e.ENTER){
13900 this.completeEdit();
13901 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13904 this.fireEvent('specialkey', field, e);
13909 * Starts the editing process and shows the editor.
13910 * @param {String/HTMLElement/Element} el The element to edit
13911 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13912 * to the innerHTML of el.
13914 startEdit : function(el, value){
13916 this.completeEdit();
13918 this.boundEl = Roo.get(el);
13919 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13920 if(!this.rendered){
13921 this.render(this.parentEl || document.body);
13923 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13926 this.startValue = v;
13927 this.field.setValue(v);
13929 var sz = this.boundEl.getSize();
13930 switch(this.autoSize){
13932 this.setSize(sz.width, "");
13935 this.setSize("", sz.height);
13938 this.setSize(sz.width, sz.height);
13941 this.el.alignTo(this.boundEl, this.alignment);
13942 this.editing = true;
13944 Roo.QuickTips.disable();
13950 * Sets the height and width of this editor.
13951 * @param {Number} width The new width
13952 * @param {Number} height The new height
13954 setSize : function(w, h){
13955 this.field.setSize(w, h);
13962 * Realigns the editor to the bound field based on the current alignment config value.
13964 realign : function(){
13965 this.el.alignTo(this.boundEl, this.alignment);
13969 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13970 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13972 completeEdit : function(remainVisible){
13976 var v = this.getValue();
13977 if(this.revertInvalid !== false && !this.field.isValid()){
13978 v = this.startValue;
13979 this.cancelEdit(true);
13981 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13982 this.editing = false;
13986 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13987 this.editing = false;
13988 if(this.updateEl && this.boundEl){
13989 this.boundEl.update(v);
13991 if(remainVisible !== true){
13994 this.fireEvent("complete", this, v, this.startValue);
13999 onShow : function(){
14001 if(this.hideEl !== false){
14002 this.boundEl.hide();
14005 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14006 this.fixIEFocus = true;
14007 this.deferredFocus.defer(50, this);
14009 this.field.focus();
14011 this.fireEvent("startedit", this.boundEl, this.startValue);
14014 deferredFocus : function(){
14016 this.field.focus();
14021 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14022 * reverted to the original starting value.
14023 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14024 * cancel (defaults to false)
14026 cancelEdit : function(remainVisible){
14028 this.setValue(this.startValue);
14029 if(remainVisible !== true){
14036 onBlur : function(){
14037 if(this.allowBlur !== true && this.editing){
14038 this.completeEdit();
14043 onHide : function(){
14045 this.completeEdit();
14049 if(this.field.collapse){
14050 this.field.collapse();
14053 if(this.hideEl !== false){
14054 this.boundEl.show();
14057 Roo.QuickTips.enable();
14062 * Sets the data value of the editor
14063 * @param {Mixed} value Any valid value supported by the underlying field
14065 setValue : function(v){
14066 this.field.setValue(v);
14070 * Gets the data value of the editor
14071 * @return {Mixed} The data value
14073 getValue : function(){
14074 return this.field.getValue();
14078 * Ext JS Library 1.1.1
14079 * Copyright(c) 2006-2007, Ext JS, LLC.
14081 * Originally Released Under LGPL - original licence link has changed is not relivant.
14084 * <script type="text/javascript">
14088 * @class Roo.BasicDialog
14089 * @extends Roo.util.Observable
14090 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14092 var dlg = new Roo.BasicDialog("my-dlg", {
14101 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14102 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14103 dlg.addButton('Cancel', dlg.hide, dlg);
14106 <b>A Dialog should always be a direct child of the body element.</b>
14107 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14108 * @cfg {String} title Default text to display in the title bar (defaults to null)
14109 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14110 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14111 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14112 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14113 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14114 * (defaults to null with no animation)
14115 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14116 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14117 * property for valid values (defaults to 'all')
14118 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14119 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14120 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14121 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14122 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14123 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14124 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14125 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14126 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14127 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14128 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14129 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14130 * draggable = true (defaults to false)
14131 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14132 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14133 * shadow (defaults to false)
14134 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14135 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14136 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14137 * @cfg {Array} buttons Array of buttons
14138 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14140 * Create a new BasicDialog.
14141 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14142 * @param {Object} config Configuration options
14144 Roo.BasicDialog = function(el, config){
14145 this.el = Roo.get(el);
14146 var dh = Roo.DomHelper;
14147 if(!this.el && config && config.autoCreate){
14148 if(typeof config.autoCreate == "object"){
14149 if(!config.autoCreate.id){
14150 config.autoCreate.id = el;
14152 this.el = dh.append(document.body,
14153 config.autoCreate, true);
14155 this.el = dh.append(document.body,
14156 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14160 el.setDisplayed(true);
14161 el.hide = this.hideAction;
14163 el.addClass("x-dlg");
14165 Roo.apply(this, config);
14167 this.proxy = el.createProxy("x-dlg-proxy");
14168 this.proxy.hide = this.hideAction;
14169 this.proxy.setOpacity(.5);
14173 el.setWidth(config.width);
14176 el.setHeight(config.height);
14178 this.size = el.getSize();
14179 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14180 this.xy = [config.x,config.y];
14182 this.xy = el.getCenterXY(true);
14184 /** The header element @type Roo.Element */
14185 this.header = el.child("> .x-dlg-hd");
14186 /** The body element @type Roo.Element */
14187 this.body = el.child("> .x-dlg-bd");
14188 /** The footer element @type Roo.Element */
14189 this.footer = el.child("> .x-dlg-ft");
14192 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14195 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14198 this.header.unselectable();
14200 this.header.update(this.title);
14202 // this element allows the dialog to be focused for keyboard event
14203 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14204 this.focusEl.swallowEvent("click", true);
14206 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14208 // wrap the body and footer for special rendering
14209 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14211 this.bwrap.dom.appendChild(this.footer.dom);
14214 this.bg = this.el.createChild({
14215 tag: "div", cls:"x-dlg-bg",
14216 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14218 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14221 if(this.autoScroll !== false && !this.autoTabs){
14222 this.body.setStyle("overflow", "auto");
14225 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14227 if(this.closable !== false){
14228 this.el.addClass("x-dlg-closable");
14229 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14230 this.close.on("click", this.closeClick, this);
14231 this.close.addClassOnOver("x-dlg-close-over");
14233 if(this.collapsible !== false){
14234 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14235 this.collapseBtn.on("click", this.collapseClick, this);
14236 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14237 this.header.on("dblclick", this.collapseClick, this);
14239 if(this.resizable !== false){
14240 this.el.addClass("x-dlg-resizable");
14241 this.resizer = new Roo.Resizable(el, {
14242 minWidth: this.minWidth || 80,
14243 minHeight:this.minHeight || 80,
14244 handles: this.resizeHandles || "all",
14247 this.resizer.on("beforeresize", this.beforeResize, this);
14248 this.resizer.on("resize", this.onResize, this);
14250 if(this.draggable !== false){
14251 el.addClass("x-dlg-draggable");
14252 if (!this.proxyDrag) {
14253 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14256 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14258 dd.setHandleElId(this.header.id);
14259 dd.endDrag = this.endMove.createDelegate(this);
14260 dd.startDrag = this.startMove.createDelegate(this);
14261 dd.onDrag = this.onDrag.createDelegate(this);
14266 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14267 this.mask.enableDisplayMode("block");
14269 this.el.addClass("x-dlg-modal");
14272 this.shadow = new Roo.Shadow({
14273 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14274 offset : this.shadowOffset
14277 this.shadowOffset = 0;
14279 if(Roo.useShims && this.shim !== false){
14280 this.shim = this.el.createShim();
14281 this.shim.hide = this.hideAction;
14289 if (this.buttons) {
14290 var bts= this.buttons;
14292 Roo.each(bts, function(b) {
14301 * Fires when a key is pressed
14302 * @param {Roo.BasicDialog} this
14303 * @param {Roo.EventObject} e
14308 * Fires when this dialog is moved by the user.
14309 * @param {Roo.BasicDialog} this
14310 * @param {Number} x The new page X
14311 * @param {Number} y The new page Y
14316 * Fires when this dialog is resized by the user.
14317 * @param {Roo.BasicDialog} this
14318 * @param {Number} width The new width
14319 * @param {Number} height The new height
14323 * @event beforehide
14324 * Fires before this dialog is hidden.
14325 * @param {Roo.BasicDialog} this
14327 "beforehide" : true,
14330 * Fires when this dialog is hidden.
14331 * @param {Roo.BasicDialog} this
14335 * @event beforeshow
14336 * Fires before this dialog is shown.
14337 * @param {Roo.BasicDialog} this
14339 "beforeshow" : true,
14342 * Fires when this dialog is shown.
14343 * @param {Roo.BasicDialog} this
14347 el.on("keydown", this.onKeyDown, this);
14348 el.on("mousedown", this.toFront, this);
14349 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14351 Roo.DialogManager.register(this);
14352 Roo.BasicDialog.superclass.constructor.call(this);
14355 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14356 shadowOffset: Roo.isIE ? 6 : 5,
14359 minButtonWidth: 75,
14360 defaultButton: null,
14361 buttonAlign: "right",
14366 * Sets the dialog title text
14367 * @param {String} text The title text to display
14368 * @return {Roo.BasicDialog} this
14370 setTitle : function(text){
14371 this.header.update(text);
14376 closeClick : function(){
14381 collapseClick : function(){
14382 this[this.collapsed ? "expand" : "collapse"]();
14386 * Collapses the dialog to its minimized state (only the title bar is visible).
14387 * Equivalent to the user clicking the collapse dialog button.
14389 collapse : function(){
14390 if(!this.collapsed){
14391 this.collapsed = true;
14392 this.el.addClass("x-dlg-collapsed");
14393 this.restoreHeight = this.el.getHeight();
14394 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14399 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14400 * clicking the expand dialog button.
14402 expand : function(){
14403 if(this.collapsed){
14404 this.collapsed = false;
14405 this.el.removeClass("x-dlg-collapsed");
14406 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14411 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14412 * @return {Roo.TabPanel} The tabs component
14414 initTabs : function(){
14415 var tabs = this.getTabs();
14416 while(tabs.getTab(0)){
14419 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14421 tabs.addTab(Roo.id(dom), dom.title);
14429 beforeResize : function(){
14430 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14434 onResize : function(){
14435 this.refreshSize();
14436 this.syncBodyHeight();
14437 this.adjustAssets();
14439 this.fireEvent("resize", this, this.size.width, this.size.height);
14443 onKeyDown : function(e){
14444 if(this.isVisible()){
14445 this.fireEvent("keydown", this, e);
14450 * Resizes the dialog.
14451 * @param {Number} width
14452 * @param {Number} height
14453 * @return {Roo.BasicDialog} this
14455 resizeTo : function(width, height){
14456 this.el.setSize(width, height);
14457 this.size = {width: width, height: height};
14458 this.syncBodyHeight();
14459 if(this.fixedcenter){
14462 if(this.isVisible()){
14463 this.constrainXY();
14464 this.adjustAssets();
14466 this.fireEvent("resize", this, width, height);
14472 * Resizes the dialog to fit the specified content size.
14473 * @param {Number} width
14474 * @param {Number} height
14475 * @return {Roo.BasicDialog} this
14477 setContentSize : function(w, h){
14478 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14479 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14480 //if(!this.el.isBorderBox()){
14481 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14482 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14485 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14486 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14488 this.resizeTo(w, h);
14493 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14494 * executed in response to a particular key being pressed while the dialog is active.
14495 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14496 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14497 * @param {Function} fn The function to call
14498 * @param {Object} scope (optional) The scope of the function
14499 * @return {Roo.BasicDialog} this
14501 addKeyListener : function(key, fn, scope){
14502 var keyCode, shift, ctrl, alt;
14503 if(typeof key == "object" && !(key instanceof Array)){
14504 keyCode = key["key"];
14505 shift = key["shift"];
14506 ctrl = key["ctrl"];
14511 var handler = function(dlg, e){
14512 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14513 var k = e.getKey();
14514 if(keyCode instanceof Array){
14515 for(var i = 0, len = keyCode.length; i < len; i++){
14516 if(keyCode[i] == k){
14517 fn.call(scope || window, dlg, k, e);
14523 fn.call(scope || window, dlg, k, e);
14528 this.on("keydown", handler);
14533 * Returns the TabPanel component (creates it if it doesn't exist).
14534 * Note: If you wish to simply check for the existence of tabs without creating them,
14535 * check for a null 'tabs' property.
14536 * @return {Roo.TabPanel} The tabs component
14538 getTabs : function(){
14540 this.el.addClass("x-dlg-auto-tabs");
14541 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14542 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14548 * Adds a button to the footer section of the dialog.
14549 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14550 * object or a valid Roo.DomHelper element config
14551 * @param {Function} handler The function called when the button is clicked
14552 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14553 * @return {Roo.Button} The new button
14555 addButton : function(config, handler, scope){
14556 var dh = Roo.DomHelper;
14558 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14560 if(!this.btnContainer){
14561 var tb = this.footer.createChild({
14563 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14564 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14566 this.btnContainer = tb.firstChild.firstChild.firstChild;
14571 minWidth: this.minButtonWidth,
14574 if(typeof config == "string"){
14575 bconfig.text = config;
14578 bconfig.dhconfig = config;
14580 Roo.apply(bconfig, config);
14584 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14585 bconfig.position = Math.max(0, bconfig.position);
14586 fc = this.btnContainer.childNodes[bconfig.position];
14589 var btn = new Roo.Button(
14591 this.btnContainer.insertBefore(document.createElement("td"),fc)
14592 : this.btnContainer.appendChild(document.createElement("td")),
14593 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14596 this.syncBodyHeight();
14599 * Array of all the buttons that have been added to this dialog via addButton
14604 this.buttons.push(btn);
14609 * Sets the default button to be focused when the dialog is displayed.
14610 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14611 * @return {Roo.BasicDialog} this
14613 setDefaultButton : function(btn){
14614 this.defaultButton = btn;
14619 getHeaderFooterHeight : function(safe){
14622 height += this.header.getHeight();
14625 var fm = this.footer.getMargins();
14626 height += (this.footer.getHeight()+fm.top+fm.bottom);
14628 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14629 height += this.centerBg.getPadding("tb");
14634 syncBodyHeight : function(){
14635 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14636 var height = this.size.height - this.getHeaderFooterHeight(false);
14637 bd.setHeight(height-bd.getMargins("tb"));
14638 var hh = this.header.getHeight();
14639 var h = this.size.height-hh;
14641 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14642 bw.setHeight(h-cb.getPadding("tb"));
14643 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14644 bd.setWidth(bw.getWidth(true));
14646 this.tabs.syncHeight();
14648 this.tabs.el.repaint();
14654 * Restores the previous state of the dialog if Roo.state is configured.
14655 * @return {Roo.BasicDialog} this
14657 restoreState : function(){
14658 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14659 if(box && box.width){
14660 this.xy = [box.x, box.y];
14661 this.resizeTo(box.width, box.height);
14667 beforeShow : function(){
14669 if(this.fixedcenter){
14670 this.xy = this.el.getCenterXY(true);
14673 Roo.get(document.body).addClass("x-body-masked");
14674 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14677 this.constrainXY();
14681 animShow : function(){
14682 var b = Roo.get(this.animateTarget).getBox();
14683 this.proxy.setSize(b.width, b.height);
14684 this.proxy.setLocation(b.x, b.y);
14686 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14687 true, .35, this.showEl.createDelegate(this));
14691 * Shows the dialog.
14692 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14693 * @return {Roo.BasicDialog} this
14695 show : function(animateTarget){
14696 if (this.fireEvent("beforeshow", this) === false){
14699 if(this.syncHeightBeforeShow){
14700 this.syncBodyHeight();
14701 }else if(this.firstShow){
14702 this.firstShow = false;
14703 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14705 this.animateTarget = animateTarget || this.animateTarget;
14706 if(!this.el.isVisible()){
14708 if(this.animateTarget && Roo.get(this.animateTarget)){
14718 showEl : function(){
14720 this.el.setXY(this.xy);
14722 this.adjustAssets(true);
14725 // IE peekaboo bug - fix found by Dave Fenwick
14729 this.fireEvent("show", this);
14733 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14734 * dialog itself will receive focus.
14736 focus : function(){
14737 if(this.defaultButton){
14738 this.defaultButton.focus();
14740 this.focusEl.focus();
14745 constrainXY : function(){
14746 if(this.constraintoviewport !== false){
14747 if(!this.viewSize){
14748 if(this.container){
14749 var s = this.container.getSize();
14750 this.viewSize = [s.width, s.height];
14752 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14755 var s = Roo.get(this.container||document).getScroll();
14757 var x = this.xy[0], y = this.xy[1];
14758 var w = this.size.width, h = this.size.height;
14759 var vw = this.viewSize[0], vh = this.viewSize[1];
14760 // only move it if it needs it
14762 // first validate right/bottom
14763 if(x + w > vw+s.left){
14767 if(y + h > vh+s.top){
14771 // then make sure top/left isn't negative
14783 if(this.isVisible()){
14784 this.el.setLocation(x, y);
14785 this.adjustAssets();
14792 onDrag : function(){
14793 if(!this.proxyDrag){
14794 this.xy = this.el.getXY();
14795 this.adjustAssets();
14800 adjustAssets : function(doShow){
14801 var x = this.xy[0], y = this.xy[1];
14802 var w = this.size.width, h = this.size.height;
14803 if(doShow === true){
14805 this.shadow.show(this.el);
14811 if(this.shadow && this.shadow.isVisible()){
14812 this.shadow.show(this.el);
14814 if(this.shim && this.shim.isVisible()){
14815 this.shim.setBounds(x, y, w, h);
14820 adjustViewport : function(w, h){
14822 w = Roo.lib.Dom.getViewWidth();
14823 h = Roo.lib.Dom.getViewHeight();
14826 this.viewSize = [w, h];
14827 if(this.modal && this.mask.isVisible()){
14828 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14829 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14831 if(this.isVisible()){
14832 this.constrainXY();
14837 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14838 * shadow, proxy, mask, etc.) Also removes all event listeners.
14839 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14841 destroy : function(removeEl){
14842 if(this.isVisible()){
14843 this.animateTarget = null;
14846 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14848 this.tabs.destroy(removeEl);
14861 for(var i = 0, len = this.buttons.length; i < len; i++){
14862 this.buttons[i].destroy();
14865 this.el.removeAllListeners();
14866 if(removeEl === true){
14867 this.el.update("");
14870 Roo.DialogManager.unregister(this);
14874 startMove : function(){
14875 if(this.proxyDrag){
14878 if(this.constraintoviewport !== false){
14879 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14884 endMove : function(){
14885 if(!this.proxyDrag){
14886 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14888 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14891 this.refreshSize();
14892 this.adjustAssets();
14894 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14898 * Brings this dialog to the front of any other visible dialogs
14899 * @return {Roo.BasicDialog} this
14901 toFront : function(){
14902 Roo.DialogManager.bringToFront(this);
14907 * Sends this dialog to the back (under) of any other visible dialogs
14908 * @return {Roo.BasicDialog} this
14910 toBack : function(){
14911 Roo.DialogManager.sendToBack(this);
14916 * Centers this dialog in the viewport
14917 * @return {Roo.BasicDialog} this
14919 center : function(){
14920 var xy = this.el.getCenterXY(true);
14921 this.moveTo(xy[0], xy[1]);
14926 * Moves the dialog's top-left corner to the specified point
14927 * @param {Number} x
14928 * @param {Number} y
14929 * @return {Roo.BasicDialog} this
14931 moveTo : function(x, y){
14933 if(this.isVisible()){
14934 this.el.setXY(this.xy);
14935 this.adjustAssets();
14941 * Aligns the dialog to the specified element
14942 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14943 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14944 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14945 * @return {Roo.BasicDialog} this
14947 alignTo : function(element, position, offsets){
14948 this.xy = this.el.getAlignToXY(element, position, offsets);
14949 if(this.isVisible()){
14950 this.el.setXY(this.xy);
14951 this.adjustAssets();
14957 * Anchors an element to another element and realigns it when the window is resized.
14958 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14959 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14960 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14961 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14962 * is a number, it is used as the buffer delay (defaults to 50ms).
14963 * @return {Roo.BasicDialog} this
14965 anchorTo : function(el, alignment, offsets, monitorScroll){
14966 var action = function(){
14967 this.alignTo(el, alignment, offsets);
14969 Roo.EventManager.onWindowResize(action, this);
14970 var tm = typeof monitorScroll;
14971 if(tm != 'undefined'){
14972 Roo.EventManager.on(window, 'scroll', action, this,
14973 {buffer: tm == 'number' ? monitorScroll : 50});
14980 * Returns true if the dialog is visible
14981 * @return {Boolean}
14983 isVisible : function(){
14984 return this.el.isVisible();
14988 animHide : function(callback){
14989 var b = Roo.get(this.animateTarget).getBox();
14991 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
14993 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
14994 this.hideEl.createDelegate(this, [callback]));
14998 * Hides the dialog.
14999 * @param {Function} callback (optional) Function to call when the dialog is hidden
15000 * @return {Roo.BasicDialog} this
15002 hide : function(callback){
15003 if (this.fireEvent("beforehide", this) === false){
15007 this.shadow.hide();
15012 // sometimes animateTarget seems to get set.. causing problems...
15013 // this just double checks..
15014 if(this.animateTarget && Roo.get(this.animateTarget)) {
15015 this.animHide(callback);
15018 this.hideEl(callback);
15024 hideEl : function(callback){
15028 Roo.get(document.body).removeClass("x-body-masked");
15030 this.fireEvent("hide", this);
15031 if(typeof callback == "function"){
15037 hideAction : function(){
15038 this.setLeft("-10000px");
15039 this.setTop("-10000px");
15040 this.setStyle("visibility", "hidden");
15044 refreshSize : function(){
15045 this.size = this.el.getSize();
15046 this.xy = this.el.getXY();
15047 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15051 // z-index is managed by the DialogManager and may be overwritten at any time
15052 setZIndex : function(index){
15054 this.mask.setStyle("z-index", index);
15057 this.shim.setStyle("z-index", ++index);
15060 this.shadow.setZIndex(++index);
15062 this.el.setStyle("z-index", ++index);
15064 this.proxy.setStyle("z-index", ++index);
15067 this.resizer.proxy.setStyle("z-index", ++index);
15070 this.lastZIndex = index;
15074 * Returns the element for this dialog
15075 * @return {Roo.Element} The underlying dialog Element
15077 getEl : function(){
15083 * @class Roo.DialogManager
15084 * Provides global access to BasicDialogs that have been created and
15085 * support for z-indexing (layering) multiple open dialogs.
15087 Roo.DialogManager = function(){
15089 var accessList = [];
15093 var sortDialogs = function(d1, d2){
15094 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15098 var orderDialogs = function(){
15099 accessList.sort(sortDialogs);
15100 var seed = Roo.DialogManager.zseed;
15101 for(var i = 0, len = accessList.length; i < len; i++){
15102 var dlg = accessList[i];
15104 dlg.setZIndex(seed + (i*10));
15111 * The starting z-index for BasicDialogs (defaults to 9000)
15112 * @type Number The z-index value
15117 register : function(dlg){
15118 list[dlg.id] = dlg;
15119 accessList.push(dlg);
15123 unregister : function(dlg){
15124 delete list[dlg.id];
15127 if(!accessList.indexOf){
15128 for( i = 0, len = accessList.length; i < len; i++){
15129 if(accessList[i] == dlg){
15130 accessList.splice(i, 1);
15135 i = accessList.indexOf(dlg);
15137 accessList.splice(i, 1);
15143 * Gets a registered dialog by id
15144 * @param {String/Object} id The id of the dialog or a dialog
15145 * @return {Roo.BasicDialog} this
15147 get : function(id){
15148 return typeof id == "object" ? id : list[id];
15152 * Brings the specified dialog to the front
15153 * @param {String/Object} dlg The id of the dialog or a dialog
15154 * @return {Roo.BasicDialog} this
15156 bringToFront : function(dlg){
15157 dlg = this.get(dlg);
15160 dlg._lastAccess = new Date().getTime();
15167 * Sends the specified dialog to the back
15168 * @param {String/Object} dlg The id of the dialog or a dialog
15169 * @return {Roo.BasicDialog} this
15171 sendToBack : function(dlg){
15172 dlg = this.get(dlg);
15173 dlg._lastAccess = -(new Date().getTime());
15179 * Hides all dialogs
15181 hideAll : function(){
15182 for(var id in list){
15183 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15192 * @class Roo.LayoutDialog
15193 * @extends Roo.BasicDialog
15194 * Dialog which provides adjustments for working with a layout in a Dialog.
15195 * Add your necessary layout config options to the dialog's config.<br>
15196 * Example usage (including a nested layout):
15199 dialog = new Roo.LayoutDialog("download-dlg", {
15208 // layout config merges with the dialog config
15210 tabPosition: "top",
15211 alwaysShowTabs: true
15214 dialog.addKeyListener(27, dialog.hide, dialog);
15215 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15216 dialog.addButton("Build It!", this.getDownload, this);
15218 // we can even add nested layouts
15219 var innerLayout = new Roo.BorderLayout("dl-inner", {
15229 innerLayout.beginUpdate();
15230 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15231 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15232 innerLayout.endUpdate(true);
15234 var layout = dialog.getLayout();
15235 layout.beginUpdate();
15236 layout.add("center", new Roo.ContentPanel("standard-panel",
15237 {title: "Download the Source", fitToFrame:true}));
15238 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15239 {title: "Build your own roo.js"}));
15240 layout.getRegion("center").showPanel(sp);
15241 layout.endUpdate();
15245 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15246 * @param {Object} config configuration options
15248 Roo.LayoutDialog = function(el, cfg){
15251 if (typeof(cfg) == 'undefined') {
15252 config = Roo.apply({}, el);
15253 // not sure why we use documentElement here.. - it should always be body.
15254 // IE7 borks horribly if we use documentElement.
15255 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15256 //config.autoCreate = true;
15260 config.autoTabs = false;
15261 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15262 this.body.setStyle({overflow:"hidden", position:"relative"});
15263 this.layout = new Roo.BorderLayout(this.body.dom, config);
15264 this.layout.monitorWindowResize = false;
15265 this.el.addClass("x-dlg-auto-layout");
15266 // fix case when center region overwrites center function
15267 this.center = Roo.BasicDialog.prototype.center;
15268 this.on("show", this.layout.layout, this.layout, true);
15269 if (config.items) {
15270 var xitems = config.items;
15271 delete config.items;
15272 Roo.each(xitems, this.addxtype, this);
15277 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15279 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15282 endUpdate : function(){
15283 this.layout.endUpdate();
15287 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15290 beginUpdate : function(){
15291 this.layout.beginUpdate();
15295 * Get the BorderLayout for this dialog
15296 * @return {Roo.BorderLayout}
15298 getLayout : function(){
15299 return this.layout;
15302 showEl : function(){
15303 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15305 this.layout.layout();
15310 // Use the syncHeightBeforeShow config option to control this automatically
15311 syncBodyHeight : function(){
15312 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15313 if(this.layout){this.layout.layout();}
15317 * Add an xtype element (actually adds to the layout.)
15318 * @return {Object} xdata xtype object data.
15321 addxtype : function(c) {
15322 return this.layout.addxtype(c);
15326 * Ext JS Library 1.1.1
15327 * Copyright(c) 2006-2007, Ext JS, LLC.
15329 * Originally Released Under LGPL - original licence link has changed is not relivant.
15332 * <script type="text/javascript">
15336 * @class Roo.MessageBox
15337 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15341 Roo.Msg.alert('Status', 'Changes saved successfully.');
15343 // Prompt for user data:
15344 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15346 // process text value...
15350 // Show a dialog using config options:
15352 title:'Save Changes?',
15353 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15354 buttons: Roo.Msg.YESNOCANCEL,
15361 Roo.MessageBox = function(){
15362 var dlg, opt, mask, waitTimer;
15363 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15364 var buttons, activeTextEl, bwidth;
15367 var handleButton = function(button){
15369 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15373 var handleHide = function(){
15374 if(opt && opt.cls){
15375 dlg.el.removeClass(opt.cls);
15378 Roo.TaskMgr.stop(waitTimer);
15384 var updateButtons = function(b){
15387 buttons["ok"].hide();
15388 buttons["cancel"].hide();
15389 buttons["yes"].hide();
15390 buttons["no"].hide();
15391 dlg.footer.dom.style.display = 'none';
15394 dlg.footer.dom.style.display = '';
15395 for(var k in buttons){
15396 if(typeof buttons[k] != "function"){
15399 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15400 width += buttons[k].el.getWidth()+15;
15410 var handleEsc = function(d, k, e){
15411 if(opt && opt.closable !== false){
15421 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15422 * @return {Roo.BasicDialog} The BasicDialog element
15424 getDialog : function(){
15426 dlg = new Roo.BasicDialog("x-msg-box", {
15431 constraintoviewport:false,
15433 collapsible : false,
15436 width:400, height:100,
15437 buttonAlign:"center",
15438 closeClick : function(){
15439 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15440 handleButton("no");
15442 handleButton("cancel");
15446 dlg.on("hide", handleHide);
15448 dlg.addKeyListener(27, handleEsc);
15450 var bt = this.buttonText;
15451 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15452 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15453 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15454 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15455 bodyEl = dlg.body.createChild({
15457 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
15459 msgEl = bodyEl.dom.firstChild;
15460 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15461 textboxEl.enableDisplayMode();
15462 textboxEl.addKeyListener([10,13], function(){
15463 if(dlg.isVisible() && opt && opt.buttons){
15464 if(opt.buttons.ok){
15465 handleButton("ok");
15466 }else if(opt.buttons.yes){
15467 handleButton("yes");
15471 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15472 textareaEl.enableDisplayMode();
15473 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15474 progressEl.enableDisplayMode();
15475 var pf = progressEl.dom.firstChild;
15477 pp = Roo.get(pf.firstChild);
15478 pp.setHeight(pf.offsetHeight);
15486 * Updates the message box body text
15487 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15488 * the XHTML-compliant non-breaking space character '&#160;')
15489 * @return {Roo.MessageBox} This message box
15491 updateText : function(text){
15492 if(!dlg.isVisible() && !opt.width){
15493 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15495 msgEl.innerHTML = text || ' ';
15496 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15497 Math.max(opt.minWidth || this.minWidth, bwidth));
15499 activeTextEl.setWidth(w);
15501 if(dlg.isVisible()){
15502 dlg.fixedcenter = false;
15504 dlg.setContentSize(w, bodyEl.getHeight());
15505 if(dlg.isVisible()){
15506 dlg.fixedcenter = true;
15512 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15513 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15514 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15515 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15516 * @return {Roo.MessageBox} This message box
15518 updateProgress : function(value, text){
15520 this.updateText(text);
15522 if (pp) { // weird bug on my firefox - for some reason this is not defined
15523 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15529 * Returns true if the message box is currently displayed
15530 * @return {Boolean} True if the message box is visible, else false
15532 isVisible : function(){
15533 return dlg && dlg.isVisible();
15537 * Hides the message box if it is displayed
15540 if(this.isVisible()){
15546 * Displays a new message box, or reinitializes an existing message box, based on the config options
15547 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15548 * The following config object properties are supported:
15550 Property Type Description
15551 ---------- --------------- ------------------------------------------------------------------------------------
15552 animEl String/Element An id or Element from which the message box should animate as it opens and
15553 closes (defaults to undefined)
15554 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15555 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15556 closable Boolean False to hide the top-right close button (defaults to true). Note that
15557 progress and wait dialogs will ignore this property and always hide the
15558 close button as they can only be closed programmatically.
15559 cls String A custom CSS class to apply to the message box element
15560 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15561 displayed (defaults to 75)
15562 fn Function A callback function to execute after closing the dialog. The arguments to the
15563 function will be btn (the name of the button that was clicked, if applicable,
15564 e.g. "ok"), and text (the value of the active text field, if applicable).
15565 Progress and wait dialogs will ignore this option since they do not respond to
15566 user actions and can only be closed programmatically, so any required function
15567 should be called by the same code after it closes the dialog.
15568 icon String A CSS class that provides a background image to be used as an icon for
15569 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15570 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15571 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15572 modal Boolean False to allow user interaction with the page while the message box is
15573 displayed (defaults to true)
15574 msg String A string that will replace the existing message box body text (defaults
15575 to the XHTML-compliant non-breaking space character ' ')
15576 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15577 progress Boolean True to display a progress bar (defaults to false)
15578 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15579 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15580 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15581 title String The title text
15582 value String The string value to set into the active textbox element if displayed
15583 wait Boolean True to display a progress bar (defaults to false)
15584 width Number The width of the dialog in pixels
15591 msg: 'Please enter your address:',
15593 buttons: Roo.MessageBox.OKCANCEL,
15596 animEl: 'addAddressBtn'
15599 * @param {Object} config Configuration options
15600 * @return {Roo.MessageBox} This message box
15602 show : function(options){
15603 if(this.isVisible()){
15606 var d = this.getDialog();
15608 d.setTitle(opt.title || " ");
15609 d.close.setDisplayed(opt.closable !== false);
15610 activeTextEl = textboxEl;
15611 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15616 textareaEl.setHeight(typeof opt.multiline == "number" ?
15617 opt.multiline : this.defaultTextHeight);
15618 activeTextEl = textareaEl;
15627 progressEl.setDisplayed(opt.progress === true);
15628 this.updateProgress(0);
15629 activeTextEl.dom.value = opt.value || "";
15631 dlg.setDefaultButton(activeTextEl);
15633 var bs = opt.buttons;
15636 db = buttons["ok"];
15637 }else if(bs && bs.yes){
15638 db = buttons["yes"];
15640 dlg.setDefaultButton(db);
15642 bwidth = updateButtons(opt.buttons);
15643 this.updateText(opt.msg);
15645 d.el.addClass(opt.cls);
15647 d.proxyDrag = opt.proxyDrag === true;
15648 d.modal = opt.modal !== false;
15649 d.mask = opt.modal !== false ? mask : false;
15650 if(!d.isVisible()){
15651 // force it to the end of the z-index stack so it gets a cursor in FF
15652 document.body.appendChild(dlg.el.dom);
15653 d.animateTarget = null;
15654 d.show(options.animEl);
15660 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15661 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15662 * and closing the message box when the process is complete.
15663 * @param {String} title The title bar text
15664 * @param {String} msg The message box body text
15665 * @return {Roo.MessageBox} This message box
15667 progress : function(title, msg){
15674 minWidth: this.minProgressWidth,
15681 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15682 * If a callback function is passed it will be called after the user clicks the button, and the
15683 * id of the button that was clicked will be passed as the only parameter to the callback
15684 * (could also be the top-right close button).
15685 * @param {String} title The title bar text
15686 * @param {String} msg The message box body text
15687 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15688 * @param {Object} scope (optional) The scope of the callback function
15689 * @return {Roo.MessageBox} This message box
15691 alert : function(title, msg, fn, scope){
15704 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15705 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15706 * You are responsible for closing the message box when the process is complete.
15707 * @param {String} msg The message box body text
15708 * @param {String} title (optional) The title bar text
15709 * @return {Roo.MessageBox} This message box
15711 wait : function(msg, title){
15722 waitTimer = Roo.TaskMgr.start({
15724 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15732 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15733 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15734 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15735 * @param {String} title The title bar text
15736 * @param {String} msg The message box body text
15737 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15738 * @param {Object} scope (optional) The scope of the callback function
15739 * @return {Roo.MessageBox} This message box
15741 confirm : function(title, msg, fn, scope){
15745 buttons: this.YESNO,
15754 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15755 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15756 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15757 * (could also be the top-right close button) and the text that was entered will be passed as the two
15758 * parameters to the callback.
15759 * @param {String} title The title bar text
15760 * @param {String} msg The message box body text
15761 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15762 * @param {Object} scope (optional) The scope of the callback function
15763 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15764 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15765 * @return {Roo.MessageBox} This message box
15767 prompt : function(title, msg, fn, scope, multiline){
15771 buttons: this.OKCANCEL,
15776 multiline: multiline,
15783 * Button config that displays a single OK button
15788 * Button config that displays Yes and No buttons
15791 YESNO : {yes:true, no:true},
15793 * Button config that displays OK and Cancel buttons
15796 OKCANCEL : {ok:true, cancel:true},
15798 * Button config that displays Yes, No and Cancel buttons
15801 YESNOCANCEL : {yes:true, no:true, cancel:true},
15804 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15807 defaultTextHeight : 75,
15809 * The maximum width in pixels of the message box (defaults to 600)
15814 * The minimum width in pixels of the message box (defaults to 100)
15819 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15820 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15823 minProgressWidth : 250,
15825 * An object containing the default button text strings that can be overriden for localized language support.
15826 * Supported properties are: ok, cancel, yes and no.
15827 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15840 * Shorthand for {@link Roo.MessageBox}
15842 Roo.Msg = Roo.MessageBox;/*
15844 * Ext JS Library 1.1.1
15845 * Copyright(c) 2006-2007, Ext JS, LLC.
15847 * Originally Released Under LGPL - original licence link has changed is not relivant.
15850 * <script type="text/javascript">
15853 * @class Roo.QuickTips
15854 * Provides attractive and customizable tooltips for any element.
15857 Roo.QuickTips = function(){
15858 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15859 var ce, bd, xy, dd;
15860 var visible = false, disabled = true, inited = false;
15861 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15863 var onOver = function(e){
15867 var t = e.getTarget();
15868 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15871 if(ce && t == ce.el){
15872 clearTimeout(hideProc);
15875 if(t && tagEls[t.id]){
15876 tagEls[t.id].el = t;
15877 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15880 var ttp, et = Roo.fly(t);
15881 var ns = cfg.namespace;
15882 if(tm.interceptTitles && t.title){
15885 t.removeAttribute("title");
15886 e.preventDefault();
15888 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15891 showProc = show.defer(tm.showDelay, tm, [{
15894 width: et.getAttributeNS(ns, cfg.width),
15895 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15896 title: et.getAttributeNS(ns, cfg.title),
15897 cls: et.getAttributeNS(ns, cfg.cls)
15902 var onOut = function(e){
15903 clearTimeout(showProc);
15904 var t = e.getTarget();
15905 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15906 hideProc = setTimeout(hide, tm.hideDelay);
15910 var onMove = function(e){
15916 if(tm.trackMouse && ce){
15921 var onDown = function(e){
15922 clearTimeout(showProc);
15923 clearTimeout(hideProc);
15925 if(tm.hideOnClick){
15928 tm.enable.defer(100, tm);
15933 var getPad = function(){
15934 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15937 var show = function(o){
15941 clearTimeout(dismissProc);
15943 if(removeCls){ // in case manually hidden
15944 el.removeClass(removeCls);
15948 el.addClass(ce.cls);
15949 removeCls = ce.cls;
15952 tipTitle.update(ce.title);
15955 tipTitle.update('');
15958 el.dom.style.width = tm.maxWidth+'px';
15959 //tipBody.dom.style.width = '';
15960 tipBodyText.update(o.text);
15961 var p = getPad(), w = ce.width;
15963 var td = tipBodyText.dom;
15964 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15965 if(aw > tm.maxWidth){
15967 }else if(aw < tm.minWidth){
15973 //tipBody.setWidth(w);
15974 el.setWidth(parseInt(w, 10) + p);
15975 if(ce.autoHide === false){
15976 close.setDisplayed(true);
15981 close.setDisplayed(false);
15987 el.avoidY = xy[1]-18;
15992 el.setStyle("visibility", "visible");
15993 el.fadeIn({callback: afterShow});
15999 var afterShow = function(){
16003 if(tm.autoDismiss && ce.autoHide !== false){
16004 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16009 var hide = function(noanim){
16010 clearTimeout(dismissProc);
16011 clearTimeout(hideProc);
16013 if(el.isVisible()){
16015 if(noanim !== true && tm.animate){
16016 el.fadeOut({callback: afterHide});
16023 var afterHide = function(){
16026 el.removeClass(removeCls);
16033 * @cfg {Number} minWidth
16034 * The minimum width of the quick tip (defaults to 40)
16038 * @cfg {Number} maxWidth
16039 * The maximum width of the quick tip (defaults to 300)
16043 * @cfg {Boolean} interceptTitles
16044 * True to automatically use the element's DOM title value if available (defaults to false)
16046 interceptTitles : false,
16048 * @cfg {Boolean} trackMouse
16049 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16051 trackMouse : false,
16053 * @cfg {Boolean} hideOnClick
16054 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16056 hideOnClick : true,
16058 * @cfg {Number} showDelay
16059 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16063 * @cfg {Number} hideDelay
16064 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16068 * @cfg {Boolean} autoHide
16069 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16070 * Used in conjunction with hideDelay.
16075 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16076 * (defaults to true). Used in conjunction with autoDismissDelay.
16078 autoDismiss : true,
16081 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16083 autoDismissDelay : 5000,
16085 * @cfg {Boolean} animate
16086 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16091 * @cfg {String} title
16092 * Title text to display (defaults to ''). This can be any valid HTML markup.
16096 * @cfg {String} text
16097 * Body text to display (defaults to ''). This can be any valid HTML markup.
16101 * @cfg {String} cls
16102 * A CSS class to apply to the base quick tip element (defaults to '').
16106 * @cfg {Number} width
16107 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16108 * minWidth or maxWidth.
16113 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16114 * or display QuickTips in a page.
16117 tm = Roo.QuickTips;
16118 cfg = tm.tagConfig;
16120 if(!Roo.isReady){ // allow calling of init() before onReady
16121 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16124 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16125 el.fxDefaults = {stopFx: true};
16126 // maximum custom styling
16127 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
16128 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
16129 tipTitle = el.child('h3');
16130 tipTitle.enableDisplayMode("block");
16131 tipBody = el.child('div.x-tip-bd');
16132 tipBodyText = el.child('div.x-tip-bd-inner');
16133 //bdLeft = el.child('div.x-tip-bd-left');
16134 //bdRight = el.child('div.x-tip-bd-right');
16135 close = el.child('div.x-tip-close');
16136 close.enableDisplayMode("block");
16137 close.on("click", hide);
16138 var d = Roo.get(document);
16139 d.on("mousedown", onDown);
16140 d.on("mouseover", onOver);
16141 d.on("mouseout", onOut);
16142 d.on("mousemove", onMove);
16143 esc = d.addKeyListener(27, hide);
16146 dd = el.initDD("default", null, {
16147 onDrag : function(){
16151 dd.setHandleElId(tipTitle.id);
16160 * Configures a new quick tip instance and assigns it to a target element. The following config options
16163 Property Type Description
16164 ---------- --------------------- ------------------------------------------------------------------------
16165 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16167 * @param {Object} config The config object
16169 register : function(config){
16170 var cs = config instanceof Array ? config : arguments;
16171 for(var i = 0, len = cs.length; i < len; i++) {
16173 var target = c.target;
16175 if(target instanceof Array){
16176 for(var j = 0, jlen = target.length; j < jlen; j++){
16177 tagEls[target[j]] = c;
16180 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16187 * Removes this quick tip from its element and destroys it.
16188 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16190 unregister : function(el){
16191 delete tagEls[Roo.id(el)];
16195 * Enable this quick tip.
16197 enable : function(){
16198 if(inited && disabled){
16200 if(locks.length < 1){
16207 * Disable this quick tip.
16209 disable : function(){
16211 clearTimeout(showProc);
16212 clearTimeout(hideProc);
16213 clearTimeout(dismissProc);
16221 * Returns true if the quick tip is enabled, else false.
16223 isEnabled : function(){
16230 attribute : "qtip",
16240 // backwards compat
16241 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16243 * Ext JS Library 1.1.1
16244 * Copyright(c) 2006-2007, Ext JS, LLC.
16246 * Originally Released Under LGPL - original licence link has changed is not relivant.
16249 * <script type="text/javascript">
16254 * @class Roo.tree.TreePanel
16255 * @extends Roo.data.Tree
16257 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16258 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16259 * @cfg {Boolean} enableDD true to enable drag and drop
16260 * @cfg {Boolean} enableDrag true to enable just drag
16261 * @cfg {Boolean} enableDrop true to enable just drop
16262 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16263 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16264 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16265 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16266 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16267 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16268 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16269 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16270 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16271 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16272 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16273 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16274 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16275 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16276 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16279 * @param {String/HTMLElement/Element} el The container element
16280 * @param {Object} config
16282 Roo.tree.TreePanel = function(el, config){
16284 var loader = false;
16286 root = config.root;
16287 delete config.root;
16289 if (config.loader) {
16290 loader = config.loader;
16291 delete config.loader;
16294 Roo.apply(this, config);
16295 Roo.tree.TreePanel.superclass.constructor.call(this);
16296 this.el = Roo.get(el);
16297 this.el.addClass('x-tree');
16298 //console.log(root);
16300 this.setRootNode( Roo.factory(root, Roo.tree));
16303 this.loader = Roo.factory(loader, Roo.tree);
16306 * Read-only. The id of the container element becomes this TreePanel's id.
16308 this.id = this.el.id;
16311 * @event beforeload
16312 * Fires before a node is loaded, return false to cancel
16313 * @param {Node} node The node being loaded
16315 "beforeload" : true,
16318 * Fires when a node is loaded
16319 * @param {Node} node The node that was loaded
16323 * @event textchange
16324 * Fires when the text for a node is changed
16325 * @param {Node} node The node
16326 * @param {String} text The new text
16327 * @param {String} oldText The old text
16329 "textchange" : true,
16331 * @event beforeexpand
16332 * Fires before a node is expanded, return false to cancel.
16333 * @param {Node} node The node
16334 * @param {Boolean} deep
16335 * @param {Boolean} anim
16337 "beforeexpand" : true,
16339 * @event beforecollapse
16340 * Fires before a node is collapsed, return false to cancel.
16341 * @param {Node} node The node
16342 * @param {Boolean} deep
16343 * @param {Boolean} anim
16345 "beforecollapse" : true,
16348 * Fires when a node is expanded
16349 * @param {Node} node The node
16353 * @event disabledchange
16354 * Fires when the disabled status of a node changes
16355 * @param {Node} node The node
16356 * @param {Boolean} disabled
16358 "disabledchange" : true,
16361 * Fires when a node is collapsed
16362 * @param {Node} node The node
16366 * @event beforeclick
16367 * Fires before click processing on a node. Return false to cancel the default action.
16368 * @param {Node} node The node
16369 * @param {Roo.EventObject} e The event object
16371 "beforeclick":true,
16373 * @event checkchange
16374 * Fires when a node with a checkbox's checked property changes
16375 * @param {Node} this This node
16376 * @param {Boolean} checked
16378 "checkchange":true,
16381 * Fires when a node is clicked
16382 * @param {Node} node The node
16383 * @param {Roo.EventObject} e The event object
16388 * Fires when a node is double clicked
16389 * @param {Node} node The node
16390 * @param {Roo.EventObject} e The event object
16394 * @event contextmenu
16395 * Fires when a node is right clicked
16396 * @param {Node} node The node
16397 * @param {Roo.EventObject} e The event object
16399 "contextmenu":true,
16401 * @event beforechildrenrendered
16402 * Fires right before the child nodes for a node are rendered
16403 * @param {Node} node The node
16405 "beforechildrenrendered":true,
16408 * Fires when a node starts being dragged
16409 * @param {Roo.tree.TreePanel} this
16410 * @param {Roo.tree.TreeNode} node
16411 * @param {event} e The raw browser event
16413 "startdrag" : true,
16416 * Fires when a drag operation is complete
16417 * @param {Roo.tree.TreePanel} this
16418 * @param {Roo.tree.TreeNode} node
16419 * @param {event} e The raw browser event
16424 * Fires when a dragged node is dropped on a valid DD target
16425 * @param {Roo.tree.TreePanel} this
16426 * @param {Roo.tree.TreeNode} node
16427 * @param {DD} dd The dd it was dropped on
16428 * @param {event} e The raw browser event
16432 * @event beforenodedrop
16433 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16434 * passed to handlers has the following properties:<br />
16435 * <ul style="padding:5px;padding-left:16px;">
16436 * <li>tree - The TreePanel</li>
16437 * <li>target - The node being targeted for the drop</li>
16438 * <li>data - The drag data from the drag source</li>
16439 * <li>point - The point of the drop - append, above or below</li>
16440 * <li>source - The drag source</li>
16441 * <li>rawEvent - Raw mouse event</li>
16442 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16443 * to be inserted by setting them on this object.</li>
16444 * <li>cancel - Set this to true to cancel the drop.</li>
16446 * @param {Object} dropEvent
16448 "beforenodedrop" : true,
16451 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16452 * passed to handlers has the following properties:<br />
16453 * <ul style="padding:5px;padding-left:16px;">
16454 * <li>tree - The TreePanel</li>
16455 * <li>target - The node being targeted for the drop</li>
16456 * <li>data - The drag data from the drag source</li>
16457 * <li>point - The point of the drop - append, above or below</li>
16458 * <li>source - The drag source</li>
16459 * <li>rawEvent - Raw mouse event</li>
16460 * <li>dropNode - Dropped node(s).</li>
16462 * @param {Object} dropEvent
16466 * @event nodedragover
16467 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16468 * passed to handlers has the following properties:<br />
16469 * <ul style="padding:5px;padding-left:16px;">
16470 * <li>tree - The TreePanel</li>
16471 * <li>target - The node being targeted for the drop</li>
16472 * <li>data - The drag data from the drag source</li>
16473 * <li>point - The point of the drop - append, above or below</li>
16474 * <li>source - The drag source</li>
16475 * <li>rawEvent - Raw mouse event</li>
16476 * <li>dropNode - Drop node(s) provided by the source.</li>
16477 * <li>cancel - Set this to true to signal drop not allowed.</li>
16479 * @param {Object} dragOverEvent
16481 "nodedragover" : true
16484 if(this.singleExpand){
16485 this.on("beforeexpand", this.restrictExpand, this);
16488 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16489 rootVisible : true,
16490 animate: Roo.enableFx,
16493 hlDrop : Roo.enableFx,
16497 rendererTip: false,
16499 restrictExpand : function(node){
16500 var p = node.parentNode;
16502 if(p.expandedChild && p.expandedChild.parentNode == p){
16503 p.expandedChild.collapse();
16505 p.expandedChild = node;
16509 // private override
16510 setRootNode : function(node){
16511 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16512 if(!this.rootVisible){
16513 node.ui = new Roo.tree.RootTreeNodeUI(node);
16519 * Returns the container element for this TreePanel
16521 getEl : function(){
16526 * Returns the default TreeLoader for this TreePanel
16528 getLoader : function(){
16529 return this.loader;
16535 expandAll : function(){
16536 this.root.expand(true);
16540 * Collapse all nodes
16542 collapseAll : function(){
16543 this.root.collapse(true);
16547 * Returns the selection model used by this TreePanel
16549 getSelectionModel : function(){
16550 if(!this.selModel){
16551 this.selModel = new Roo.tree.DefaultSelectionModel();
16553 return this.selModel;
16557 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16558 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16559 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16562 getChecked : function(a, startNode){
16563 startNode = startNode || this.root;
16565 var f = function(){
16566 if(this.attributes.checked){
16567 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16570 startNode.cascade(f);
16575 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16576 * @param {String} path
16577 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16578 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16579 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16581 expandPath : function(path, attr, callback){
16582 attr = attr || "id";
16583 var keys = path.split(this.pathSeparator);
16584 var curNode = this.root;
16585 if(curNode.attributes[attr] != keys[1]){ // invalid root
16587 callback(false, null);
16592 var f = function(){
16593 if(++index == keys.length){
16595 callback(true, curNode);
16599 var c = curNode.findChild(attr, keys[index]);
16602 callback(false, curNode);
16607 c.expand(false, false, f);
16609 curNode.expand(false, false, f);
16613 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16614 * @param {String} path
16615 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16616 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16617 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16619 selectPath : function(path, attr, callback){
16620 attr = attr || "id";
16621 var keys = path.split(this.pathSeparator);
16622 var v = keys.pop();
16623 if(keys.length > 0){
16624 var f = function(success, node){
16625 if(success && node){
16626 var n = node.findChild(attr, v);
16632 }else if(callback){
16633 callback(false, n);
16637 callback(false, n);
16641 this.expandPath(keys.join(this.pathSeparator), attr, f);
16643 this.root.select();
16645 callback(true, this.root);
16650 getTreeEl : function(){
16655 * Trigger rendering of this TreePanel
16657 render : function(){
16658 if (this.innerCt) {
16659 return this; // stop it rendering more than once!!
16662 this.innerCt = this.el.createChild({tag:"ul",
16663 cls:"x-tree-root-ct " +
16664 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16666 if(this.containerScroll){
16667 Roo.dd.ScrollManager.register(this.el);
16669 if((this.enableDD || this.enableDrop) && !this.dropZone){
16671 * The dropZone used by this tree if drop is enabled
16672 * @type Roo.tree.TreeDropZone
16674 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16675 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16678 if((this.enableDD || this.enableDrag) && !this.dragZone){
16680 * The dragZone used by this tree if drag is enabled
16681 * @type Roo.tree.TreeDragZone
16683 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16684 ddGroup: this.ddGroup || "TreeDD",
16685 scroll: this.ddScroll
16688 this.getSelectionModel().init(this);
16690 console.log("ROOT not set in tree");
16693 this.root.render();
16694 if(!this.rootVisible){
16695 this.root.renderChildren();
16701 * Ext JS Library 1.1.1
16702 * Copyright(c) 2006-2007, Ext JS, LLC.
16704 * Originally Released Under LGPL - original licence link has changed is not relivant.
16707 * <script type="text/javascript">
16712 * @class Roo.tree.DefaultSelectionModel
16713 * @extends Roo.util.Observable
16714 * The default single selection for a TreePanel.
16716 Roo.tree.DefaultSelectionModel = function(){
16717 this.selNode = null;
16721 * @event selectionchange
16722 * Fires when the selected node changes
16723 * @param {DefaultSelectionModel} this
16724 * @param {TreeNode} node the new selection
16726 "selectionchange" : true,
16729 * @event beforeselect
16730 * Fires before the selected node changes, return false to cancel the change
16731 * @param {DefaultSelectionModel} this
16732 * @param {TreeNode} node the new selection
16733 * @param {TreeNode} node the old selection
16735 "beforeselect" : true
16739 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16740 init : function(tree){
16742 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16743 tree.on("click", this.onNodeClick, this);
16746 onNodeClick : function(node, e){
16747 if (e.ctrlKey && this.selNode == node) {
16748 this.unselect(node);
16756 * @param {TreeNode} node The node to select
16757 * @return {TreeNode} The selected node
16759 select : function(node){
16760 var last = this.selNode;
16761 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16763 last.ui.onSelectedChange(false);
16765 this.selNode = node;
16766 node.ui.onSelectedChange(true);
16767 this.fireEvent("selectionchange", this, node, last);
16774 * @param {TreeNode} node The node to unselect
16776 unselect : function(node){
16777 if(this.selNode == node){
16778 this.clearSelections();
16783 * Clear all selections
16785 clearSelections : function(){
16786 var n = this.selNode;
16788 n.ui.onSelectedChange(false);
16789 this.selNode = null;
16790 this.fireEvent("selectionchange", this, null);
16796 * Get the selected node
16797 * @return {TreeNode} The selected node
16799 getSelectedNode : function(){
16800 return this.selNode;
16804 * Returns true if the node is selected
16805 * @param {TreeNode} node The node to check
16806 * @return {Boolean}
16808 isSelected : function(node){
16809 return this.selNode == node;
16813 * Selects the node above the selected node in the tree, intelligently walking the nodes
16814 * @return TreeNode The new selection
16816 selectPrevious : function(){
16817 var s = this.selNode || this.lastSelNode;
16821 var ps = s.previousSibling;
16823 if(!ps.isExpanded() || ps.childNodes.length < 1){
16824 return this.select(ps);
16826 var lc = ps.lastChild;
16827 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16830 return this.select(lc);
16832 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16833 return this.select(s.parentNode);
16839 * Selects the node above the selected node in the tree, intelligently walking the nodes
16840 * @return TreeNode The new selection
16842 selectNext : function(){
16843 var s = this.selNode || this.lastSelNode;
16847 if(s.firstChild && s.isExpanded()){
16848 return this.select(s.firstChild);
16849 }else if(s.nextSibling){
16850 return this.select(s.nextSibling);
16851 }else if(s.parentNode){
16853 s.parentNode.bubble(function(){
16854 if(this.nextSibling){
16855 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16864 onKeyDown : function(e){
16865 var s = this.selNode || this.lastSelNode;
16866 // undesirable, but required
16871 var k = e.getKey();
16879 this.selectPrevious();
16882 e.preventDefault();
16883 if(s.hasChildNodes()){
16884 if(!s.isExpanded()){
16886 }else if(s.firstChild){
16887 this.select(s.firstChild, e);
16892 e.preventDefault();
16893 if(s.hasChildNodes() && s.isExpanded()){
16895 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16896 this.select(s.parentNode, e);
16904 * @class Roo.tree.MultiSelectionModel
16905 * @extends Roo.util.Observable
16906 * Multi selection for a TreePanel.
16908 Roo.tree.MultiSelectionModel = function(){
16909 this.selNodes = [];
16913 * @event selectionchange
16914 * Fires when the selected nodes change
16915 * @param {MultiSelectionModel} this
16916 * @param {Array} nodes Array of the selected nodes
16918 "selectionchange" : true
16922 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16923 init : function(tree){
16925 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16926 tree.on("click", this.onNodeClick, this);
16929 onNodeClick : function(node, e){
16930 this.select(node, e, e.ctrlKey);
16935 * @param {TreeNode} node The node to select
16936 * @param {EventObject} e (optional) An event associated with the selection
16937 * @param {Boolean} keepExisting True to retain existing selections
16938 * @return {TreeNode} The selected node
16940 select : function(node, e, keepExisting){
16941 if(keepExisting !== true){
16942 this.clearSelections(true);
16944 if(this.isSelected(node)){
16945 this.lastSelNode = node;
16948 this.selNodes.push(node);
16949 this.selMap[node.id] = node;
16950 this.lastSelNode = node;
16951 node.ui.onSelectedChange(true);
16952 this.fireEvent("selectionchange", this, this.selNodes);
16958 * @param {TreeNode} node The node to unselect
16960 unselect : function(node){
16961 if(this.selMap[node.id]){
16962 node.ui.onSelectedChange(false);
16963 var sn = this.selNodes;
16966 index = sn.indexOf(node);
16968 for(var i = 0, len = sn.length; i < len; i++){
16976 this.selNodes.splice(index, 1);
16978 delete this.selMap[node.id];
16979 this.fireEvent("selectionchange", this, this.selNodes);
16984 * Clear all selections
16986 clearSelections : function(suppressEvent){
16987 var sn = this.selNodes;
16989 for(var i = 0, len = sn.length; i < len; i++){
16990 sn[i].ui.onSelectedChange(false);
16992 this.selNodes = [];
16994 if(suppressEvent !== true){
16995 this.fireEvent("selectionchange", this, this.selNodes);
17001 * Returns true if the node is selected
17002 * @param {TreeNode} node The node to check
17003 * @return {Boolean}
17005 isSelected : function(node){
17006 return this.selMap[node.id] ? true : false;
17010 * Returns an array of the selected nodes
17013 getSelectedNodes : function(){
17014 return this.selNodes;
17017 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17019 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17021 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17024 * Ext JS Library 1.1.1
17025 * Copyright(c) 2006-2007, Ext JS, LLC.
17027 * Originally Released Under LGPL - original licence link has changed is not relivant.
17030 * <script type="text/javascript">
17034 * @class Roo.tree.TreeNode
17035 * @extends Roo.data.Node
17036 * @cfg {String} text The text for this node
17037 * @cfg {Boolean} expanded true to start the node expanded
17038 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17039 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17040 * @cfg {Boolean} disabled true to start the node disabled
17041 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17042 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17043 * @cfg {String} cls A css class to be added to the node
17044 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17045 * @cfg {String} href URL of the link used for the node (defaults to #)
17046 * @cfg {String} hrefTarget target frame for the link
17047 * @cfg {String} qtip An Ext QuickTip for the node
17048 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17049 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17050 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17051 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17052 * (defaults to undefined with no checkbox rendered)
17054 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17056 Roo.tree.TreeNode = function(attributes){
17057 attributes = attributes || {};
17058 if(typeof attributes == "string"){
17059 attributes = {text: attributes};
17061 this.childrenRendered = false;
17062 this.rendered = false;
17063 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17064 this.expanded = attributes.expanded === true;
17065 this.isTarget = attributes.isTarget !== false;
17066 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17067 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17070 * Read-only. The text for this node. To change it use setText().
17073 this.text = attributes.text;
17075 * True if this node is disabled.
17078 this.disabled = attributes.disabled === true;
17082 * @event textchange
17083 * Fires when the text for this node is changed
17084 * @param {Node} this This node
17085 * @param {String} text The new text
17086 * @param {String} oldText The old text
17088 "textchange" : true,
17090 * @event beforeexpand
17091 * Fires before this node is expanded, return false to cancel.
17092 * @param {Node} this This node
17093 * @param {Boolean} deep
17094 * @param {Boolean} anim
17096 "beforeexpand" : true,
17098 * @event beforecollapse
17099 * Fires before this node is collapsed, return false to cancel.
17100 * @param {Node} this This node
17101 * @param {Boolean} deep
17102 * @param {Boolean} anim
17104 "beforecollapse" : true,
17107 * Fires when this node is expanded
17108 * @param {Node} this This node
17112 * @event disabledchange
17113 * Fires when the disabled status of this node changes
17114 * @param {Node} this This node
17115 * @param {Boolean} disabled
17117 "disabledchange" : true,
17120 * Fires when this node is collapsed
17121 * @param {Node} this This node
17125 * @event beforeclick
17126 * Fires before click processing. Return false to cancel the default action.
17127 * @param {Node} this This node
17128 * @param {Roo.EventObject} e The event object
17130 "beforeclick":true,
17132 * @event checkchange
17133 * Fires when a node with a checkbox's checked property changes
17134 * @param {Node} this This node
17135 * @param {Boolean} checked
17137 "checkchange":true,
17140 * Fires when this node is clicked
17141 * @param {Node} this This node
17142 * @param {Roo.EventObject} e The event object
17147 * Fires when this node is double clicked
17148 * @param {Node} this This node
17149 * @param {Roo.EventObject} e The event object
17153 * @event contextmenu
17154 * Fires when this node is right clicked
17155 * @param {Node} this This node
17156 * @param {Roo.EventObject} e The event object
17158 "contextmenu":true,
17160 * @event beforechildrenrendered
17161 * Fires right before the child nodes for this node are rendered
17162 * @param {Node} this This node
17164 "beforechildrenrendered":true
17167 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17170 * Read-only. The UI for this node
17173 this.ui = new uiClass(this);
17175 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17176 preventHScroll: true,
17178 * Returns true if this node is expanded
17179 * @return {Boolean}
17181 isExpanded : function(){
17182 return this.expanded;
17186 * Returns the UI object for this node
17187 * @return {TreeNodeUI}
17189 getUI : function(){
17193 // private override
17194 setFirstChild : function(node){
17195 var of = this.firstChild;
17196 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17197 if(this.childrenRendered && of && node != of){
17198 of.renderIndent(true, true);
17201 this.renderIndent(true, true);
17205 // private override
17206 setLastChild : function(node){
17207 var ol = this.lastChild;
17208 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17209 if(this.childrenRendered && ol && node != ol){
17210 ol.renderIndent(true, true);
17213 this.renderIndent(true, true);
17217 // these methods are overridden to provide lazy rendering support
17218 // private override
17219 appendChild : function(){
17220 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17221 if(node && this.childrenRendered){
17224 this.ui.updateExpandIcon();
17228 // private override
17229 removeChild : function(node){
17230 this.ownerTree.getSelectionModel().unselect(node);
17231 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17232 // if it's been rendered remove dom node
17233 if(this.childrenRendered){
17236 if(this.childNodes.length < 1){
17237 this.collapse(false, false);
17239 this.ui.updateExpandIcon();
17241 if(!this.firstChild) {
17242 this.childrenRendered = false;
17247 // private override
17248 insertBefore : function(node, refNode){
17249 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17250 if(newNode && refNode && this.childrenRendered){
17253 this.ui.updateExpandIcon();
17258 * Sets the text for this node
17259 * @param {String} text
17261 setText : function(text){
17262 var oldText = this.text;
17264 this.attributes.text = text;
17265 if(this.rendered){ // event without subscribing
17266 this.ui.onTextChange(this, text, oldText);
17268 this.fireEvent("textchange", this, text, oldText);
17272 * Triggers selection of this node
17274 select : function(){
17275 this.getOwnerTree().getSelectionModel().select(this);
17279 * Triggers deselection of this node
17281 unselect : function(){
17282 this.getOwnerTree().getSelectionModel().unselect(this);
17286 * Returns true if this node is selected
17287 * @return {Boolean}
17289 isSelected : function(){
17290 return this.getOwnerTree().getSelectionModel().isSelected(this);
17294 * Expand this node.
17295 * @param {Boolean} deep (optional) True to expand all children as well
17296 * @param {Boolean} anim (optional) false to cancel the default animation
17297 * @param {Function} callback (optional) A callback to be called when
17298 * expanding this node completes (does not wait for deep expand to complete).
17299 * Called with 1 parameter, this node.
17301 expand : function(deep, anim, callback){
17302 if(!this.expanded){
17303 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17306 if(!this.childrenRendered){
17307 this.renderChildren();
17309 this.expanded = true;
17310 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17311 this.ui.animExpand(function(){
17312 this.fireEvent("expand", this);
17313 if(typeof callback == "function"){
17317 this.expandChildNodes(true);
17319 }.createDelegate(this));
17323 this.fireEvent("expand", this);
17324 if(typeof callback == "function"){
17329 if(typeof callback == "function"){
17334 this.expandChildNodes(true);
17338 isHiddenRoot : function(){
17339 return this.isRoot && !this.getOwnerTree().rootVisible;
17343 * Collapse this node.
17344 * @param {Boolean} deep (optional) True to collapse all children as well
17345 * @param {Boolean} anim (optional) false to cancel the default animation
17347 collapse : function(deep, anim){
17348 if(this.expanded && !this.isHiddenRoot()){
17349 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17352 this.expanded = false;
17353 if((this.getOwnerTree().animate && anim !== false) || anim){
17354 this.ui.animCollapse(function(){
17355 this.fireEvent("collapse", this);
17357 this.collapseChildNodes(true);
17359 }.createDelegate(this));
17362 this.ui.collapse();
17363 this.fireEvent("collapse", this);
17367 var cs = this.childNodes;
17368 for(var i = 0, len = cs.length; i < len; i++) {
17369 cs[i].collapse(true, false);
17375 delayedExpand : function(delay){
17376 if(!this.expandProcId){
17377 this.expandProcId = this.expand.defer(delay, this);
17382 cancelExpand : function(){
17383 if(this.expandProcId){
17384 clearTimeout(this.expandProcId);
17386 this.expandProcId = false;
17390 * Toggles expanded/collapsed state of the node
17392 toggle : function(){
17401 * Ensures all parent nodes are expanded
17403 ensureVisible : function(callback){
17404 var tree = this.getOwnerTree();
17405 tree.expandPath(this.parentNode.getPath(), false, function(){
17406 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17407 Roo.callback(callback);
17408 }.createDelegate(this));
17412 * Expand all child nodes
17413 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17415 expandChildNodes : function(deep){
17416 var cs = this.childNodes;
17417 for(var i = 0, len = cs.length; i < len; i++) {
17418 cs[i].expand(deep);
17423 * Collapse all child nodes
17424 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17426 collapseChildNodes : function(deep){
17427 var cs = this.childNodes;
17428 for(var i = 0, len = cs.length; i < len; i++) {
17429 cs[i].collapse(deep);
17434 * Disables this node
17436 disable : function(){
17437 this.disabled = true;
17439 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17440 this.ui.onDisableChange(this, true);
17442 this.fireEvent("disabledchange", this, true);
17446 * Enables this node
17448 enable : function(){
17449 this.disabled = false;
17450 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17451 this.ui.onDisableChange(this, false);
17453 this.fireEvent("disabledchange", this, false);
17457 renderChildren : function(suppressEvent){
17458 if(suppressEvent !== false){
17459 this.fireEvent("beforechildrenrendered", this);
17461 var cs = this.childNodes;
17462 for(var i = 0, len = cs.length; i < len; i++){
17463 cs[i].render(true);
17465 this.childrenRendered = true;
17469 sort : function(fn, scope){
17470 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17471 if(this.childrenRendered){
17472 var cs = this.childNodes;
17473 for(var i = 0, len = cs.length; i < len; i++){
17474 cs[i].render(true);
17480 render : function(bulkRender){
17481 this.ui.render(bulkRender);
17482 if(!this.rendered){
17483 this.rendered = true;
17485 this.expanded = false;
17486 this.expand(false, false);
17492 renderIndent : function(deep, refresh){
17494 this.ui.childIndent = null;
17496 this.ui.renderIndent();
17497 if(deep === true && this.childrenRendered){
17498 var cs = this.childNodes;
17499 for(var i = 0, len = cs.length; i < len; i++){
17500 cs[i].renderIndent(true, refresh);