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 * @scope Roo.dd.DropTarget
3905 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3906 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3907 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3909 * IMPORTANT : it should set this.overClass and this.dropAllowed
3911 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3912 * @param {Event} e The event
3913 * @param {Object} data An object containing arbitrary data supplied by the drag source
3919 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3920 * This method will be called on every mouse movement while the drag source is over the drop target.
3921 * This default implementation simply returns the dropAllowed config value.
3923 * IMPORTANT : it should set this.dropAllowed
3925 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3926 * @param {Event} e The event
3927 * @param {Object} data An object containing arbitrary data supplied by the drag source
3933 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3934 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3935 * overClass (if any) from the drop element.
3936 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3937 * @param {Event} e The event
3938 * @param {Object} data An object containing arbitrary data supplied by the drag source
3944 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3945 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3946 * implementation that does something to process the drop event and returns true so that the drag source's
3947 * repair action does not run.
3949 * IMPORTANT : it should set this.success
3951 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3952 * @param {Event} e The event
3953 * @param {Object} data An object containing arbitrary data supplied by the drag source
3959 Roo.dd.DropTarget.superclass.constructor.call( this,
3961 this.ddGroup || this.group,
3964 listeners : config.listeners || {}
3972 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3974 * @cfg {String} overClass
3975 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3978 * @cfg {String} ddGroup
3979 * The drag drop group to handle drop events for
3983 * @cfg {String} dropAllowed
3984 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3986 dropAllowed : "x-dd-drop-ok",
3988 * @cfg {String} dropNotAllowed
3989 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3991 dropNotAllowed : "x-dd-drop-nodrop",
3993 * @cfg {boolean} success
3994 * set this after drop listener..
3998 * @cfg {boolean} valid
3999 * if the drop point is valid for over/enter..
4006 isNotifyTarget : true,
4011 notifyEnter : function(dd, e, data){
4013 this.fireEvent('enter', this, dd, e, data);
4015 this.el.addClass(this.overClass);
4017 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4023 notifyOver : function(dd, e, data){
4025 this.fireEvent('over', this, dd, e, data);
4026 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4032 notifyOut : function(dd, e, data){
4033 this.fireEvent('out', this, dd, e, data);
4035 this.el.removeClass(this.overClass);
4042 notifyDrop : function(dd, e, data){
4043 this.success = false;
4044 this.fireEvent('drop', this, dd, e, data);
4045 return this.success;
4049 * Ext JS Library 1.1.1
4050 * Copyright(c) 2006-2007, Ext JS, LLC.
4052 * Originally Released Under LGPL - original licence link has changed is not relivant.
4055 * <script type="text/javascript">
4060 * @class Roo.dd.DragZone
4061 * @extends Roo.dd.DragSource
4062 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4063 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4065 * @param {String/HTMLElement/Element} el The container element
4066 * @param {Object} config
4068 Roo.dd.DragZone = function(el, config){
4069 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4070 if(this.containerScroll){
4071 Roo.dd.ScrollManager.register(this.el);
4075 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4077 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4078 * for auto scrolling during drag operations.
4081 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4082 * method after a failed drop (defaults to "c3daf9" - light blue)
4086 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4087 * for a valid target to drag based on the mouse down. Override this method
4088 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4089 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4090 * @param {EventObject} e The mouse down event
4091 * @return {Object} The dragData
4093 getDragData : function(e){
4094 return Roo.dd.Registry.getHandleFromEvent(e);
4098 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4099 * this.dragData.ddel
4100 * @param {Number} x The x position of the click on the dragged object
4101 * @param {Number} y The y position of the click on the dragged object
4102 * @return {Boolean} true to continue the drag, false to cancel
4104 onInitDrag : function(x, y){
4105 this.proxy.update(this.dragData.ddel.cloneNode(true));
4106 this.onStartDrag(x, y);
4111 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4113 afterRepair : function(){
4115 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4117 this.dragging = false;
4121 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4122 * the XY of this.dragData.ddel
4123 * @param {EventObject} e The mouse up event
4124 * @return {Array} The xy location (e.g. [100, 200])
4126 getRepairXY : function(e){
4127 return Roo.Element.fly(this.dragData.ddel).getXY();
4131 * Ext JS Library 1.1.1
4132 * Copyright(c) 2006-2007, Ext JS, LLC.
4134 * Originally Released Under LGPL - original licence link has changed is not relivant.
4137 * <script type="text/javascript">
4140 * @class Roo.dd.DropZone
4141 * @extends Roo.dd.DropTarget
4142 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4143 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4145 * @param {String/HTMLElement/Element} el The container element
4146 * @param {Object} config
4148 Roo.dd.DropZone = function(el, config){
4149 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4152 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4154 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4155 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4156 * provide your own custom lookup.
4157 * @param {Event} e The event
4158 * @return {Object} data The custom data
4160 getTargetFromEvent : function(e){
4161 return Roo.dd.Registry.getTargetFromEvent(e);
4165 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4166 * that it has registered. This method has no default implementation and should be overridden to provide
4167 * node-specific processing if necessary.
4168 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4169 * {@link #getTargetFromEvent} for this node)
4170 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4171 * @param {Event} e The event
4172 * @param {Object} data An object containing arbitrary data supplied by the drag source
4174 onNodeEnter : function(n, dd, e, data){
4179 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4180 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4181 * overridden to provide the proper feedback.
4182 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4183 * {@link #getTargetFromEvent} for this node)
4184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4185 * @param {Event} e The event
4186 * @param {Object} data An object containing arbitrary data supplied by the drag source
4187 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4188 * underlying {@link Roo.dd.StatusProxy} can be updated
4190 onNodeOver : function(n, dd, e, data){
4191 return this.dropAllowed;
4195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4196 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4197 * node-specific processing if necessary.
4198 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4199 * {@link #getTargetFromEvent} for this node)
4200 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4201 * @param {Event} e The event
4202 * @param {Object} data An object containing arbitrary data supplied by the drag source
4204 onNodeOut : function(n, dd, e, data){
4209 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4210 * the drop node. The default implementation returns false, so it should be overridden to provide the
4211 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4212 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4213 * {@link #getTargetFromEvent} for this node)
4214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4215 * @param {Event} e The event
4216 * @param {Object} data An object containing arbitrary data supplied by the drag source
4217 * @return {Boolean} True if the drop was valid, else false
4219 onNodeDrop : function(n, dd, e, data){
4224 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4225 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4226 * it should be overridden to provide the proper feedback if necessary.
4227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4228 * @param {Event} e The event
4229 * @param {Object} data An object containing arbitrary data supplied by the drag source
4230 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4231 * underlying {@link Roo.dd.StatusProxy} can be updated
4233 onContainerOver : function(dd, e, data){
4234 return this.dropNotAllowed;
4238 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4239 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4240 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4241 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4242 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4243 * @param {Event} e The event
4244 * @param {Object} data An object containing arbitrary data supplied by the drag source
4245 * @return {Boolean} True if the drop was valid, else false
4247 onContainerDrop : function(dd, e, data){
4252 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4253 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4254 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4255 * you should override this method and provide a custom implementation.
4256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4257 * @param {Event} e The event
4258 * @param {Object} data An object containing arbitrary data supplied by the drag source
4259 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4260 * underlying {@link Roo.dd.StatusProxy} can be updated
4262 notifyEnter : function(dd, e, data){
4263 return this.dropNotAllowed;
4267 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4268 * This method will be called on every mouse movement while the drag source is over the drop zone.
4269 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4270 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4271 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4272 * registered node, it will call {@link #onContainerOver}.
4273 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4274 * @param {Event} e The event
4275 * @param {Object} data An object containing arbitrary data supplied by the drag source
4276 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4277 * underlying {@link Roo.dd.StatusProxy} can be updated
4279 notifyOver : function(dd, e, data){
4280 var n = this.getTargetFromEvent(e);
4281 if(!n){ // not over valid drop target
4282 if(this.lastOverNode){
4283 this.onNodeOut(this.lastOverNode, dd, e, data);
4284 this.lastOverNode = null;
4286 return this.onContainerOver(dd, e, data);
4288 if(this.lastOverNode != n){
4289 if(this.lastOverNode){
4290 this.onNodeOut(this.lastOverNode, dd, e, data);
4292 this.onNodeEnter(n, dd, e, data);
4293 this.lastOverNode = n;
4295 return this.onNodeOver(n, dd, e, data);
4299 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4300 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4301 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4303 * @param {Event} e The event
4304 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4306 notifyOut : function(dd, e, data){
4307 if(this.lastOverNode){
4308 this.onNodeOut(this.lastOverNode, dd, e, data);
4309 this.lastOverNode = null;
4314 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4315 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4316 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4317 * otherwise it will call {@link #onContainerDrop}.
4318 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4319 * @param {Event} e The event
4320 * @param {Object} data An object containing arbitrary data supplied by the drag source
4321 * @return {Boolean} True if the drop was valid, else false
4323 notifyDrop : function(dd, e, data){
4324 if(this.lastOverNode){
4325 this.onNodeOut(this.lastOverNode, dd, e, data);
4326 this.lastOverNode = null;
4328 var n = this.getTargetFromEvent(e);
4330 this.onNodeDrop(n, dd, e, data) :
4331 this.onContainerDrop(dd, e, data);
4335 triggerCacheRefresh : function(){
4336 Roo.dd.DDM.refreshCache(this.groups);
4340 * Ext JS Library 1.1.1
4341 * Copyright(c) 2006-2007, Ext JS, LLC.
4343 * Originally Released Under LGPL - original licence link has changed is not relivant.
4346 * <script type="text/javascript">
4351 * @class Roo.data.SortTypes
4353 * Defines the default sorting (casting?) comparison functions used when sorting data.
4355 Roo.data.SortTypes = {
4357 * Default sort that does nothing
4358 * @param {Mixed} s The value being converted
4359 * @return {Mixed} The comparison value
4366 * The regular expression used to strip tags
4370 stripTagsRE : /<\/?[^>]+>/gi,
4373 * Strips all HTML tags to sort on text only
4374 * @param {Mixed} s The value being converted
4375 * @return {String} The comparison value
4377 asText : function(s){
4378 return String(s).replace(this.stripTagsRE, "");
4382 * Strips all HTML tags to sort on text only - Case insensitive
4383 * @param {Mixed} s The value being converted
4384 * @return {String} The comparison value
4386 asUCText : function(s){
4387 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4391 * Case insensitive string
4392 * @param {Mixed} s The value being converted
4393 * @return {String} The comparison value
4395 asUCString : function(s) {
4396 return String(s).toUpperCase();
4401 * @param {Mixed} s The value being converted
4402 * @return {Number} The comparison value
4404 asDate : function(s) {
4408 if(s instanceof Date){
4411 return Date.parse(String(s));
4416 * @param {Mixed} s The value being converted
4417 * @return {Float} The comparison value
4419 asFloat : function(s) {
4420 var val = parseFloat(String(s).replace(/,/g, ""));
4421 if(isNaN(val)) val = 0;
4427 * @param {Mixed} s The value being converted
4428 * @return {Number} The comparison value
4430 asInt : function(s) {
4431 var val = parseInt(String(s).replace(/,/g, ""));
4432 if(isNaN(val)) val = 0;
4437 * Ext JS Library 1.1.1
4438 * Copyright(c) 2006-2007, Ext JS, LLC.
4440 * Originally Released Under LGPL - original licence link has changed is not relivant.
4443 * <script type="text/javascript">
4447 * @class Roo.data.Record
4448 * Instances of this class encapsulate both record <em>definition</em> information, and record
4449 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4450 * to access Records cached in an {@link Roo.data.Store} object.<br>
4452 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4453 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4456 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4458 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4459 * {@link #create}. The parameters are the same.
4460 * @param {Array} data An associative Array of data values keyed by the field name.
4461 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4462 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4463 * not specified an integer id is generated.
4465 Roo.data.Record = function(data, id){
4466 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4471 * Generate a constructor for a specific record layout.
4472 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4473 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4474 * Each field definition object may contain the following properties: <ul>
4475 * <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,
4476 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4477 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4478 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4479 * is being used, then this is a string containing the javascript expression to reference the data relative to
4480 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4481 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4482 * this may be omitted.</p></li>
4483 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4484 * <ul><li>auto (Default, implies no conversion)</li>
4489 * <li>date</li></ul></p></li>
4490 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4491 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4492 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4493 * by the Reader into an object that will be stored in the Record. It is passed the
4494 * following parameters:<ul>
4495 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4497 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4499 * <br>usage:<br><pre><code>
4500 var TopicRecord = Roo.data.Record.create(
4501 {name: 'title', mapping: 'topic_title'},
4502 {name: 'author', mapping: 'username'},
4503 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4504 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4505 {name: 'lastPoster', mapping: 'user2'},
4506 {name: 'excerpt', mapping: 'post_text'}
4509 var myNewRecord = new TopicRecord({
4510 title: 'Do my job please',
4513 lastPost: new Date(),
4514 lastPoster: 'Animal',
4515 excerpt: 'No way dude!'
4517 myStore.add(myNewRecord);
4522 Roo.data.Record.create = function(o){
4524 f.superclass.constructor.apply(this, arguments);
4526 Roo.extend(f, Roo.data.Record);
4527 var p = f.prototype;
4528 p.fields = new Roo.util.MixedCollection(false, function(field){
4531 for(var i = 0, len = o.length; i < len; i++){
4532 p.fields.add(new Roo.data.Field(o[i]));
4534 f.getField = function(name){
4535 return p.fields.get(name);
4540 Roo.data.Record.AUTO_ID = 1000;
4541 Roo.data.Record.EDIT = 'edit';
4542 Roo.data.Record.REJECT = 'reject';
4543 Roo.data.Record.COMMIT = 'commit';
4545 Roo.data.Record.prototype = {
4547 * Readonly flag - true if this record has been modified.
4556 join : function(store){
4561 * Set the named field to the specified value.
4562 * @param {String} name The name of the field to set.
4563 * @param {Object} value The value to set the field to.
4565 set : function(name, value){
4566 if(this.data[name] == value){
4573 if(typeof this.modified[name] == 'undefined'){
4574 this.modified[name] = this.data[name];
4576 this.data[name] = value;
4578 this.store.afterEdit(this);
4583 * Get the value of the named field.
4584 * @param {String} name The name of the field to get the value of.
4585 * @return {Object} The value of the field.
4587 get : function(name){
4588 return this.data[name];
4592 beginEdit : function(){
4593 this.editing = true;
4598 cancelEdit : function(){
4599 this.editing = false;
4600 delete this.modified;
4604 endEdit : function(){
4605 this.editing = false;
4606 if(this.dirty && this.store){
4607 this.store.afterEdit(this);
4612 * Usually called by the {@link Roo.data.Store} which owns the Record.
4613 * Rejects all changes made to the Record since either creation, or the last commit operation.
4614 * Modified fields are reverted to their original values.
4616 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4617 * of reject operations.
4619 reject : function(){
4620 var m = this.modified;
4622 if(typeof m[n] != "function"){
4623 this.data[n] = m[n];
4627 delete this.modified;
4628 this.editing = false;
4630 this.store.afterReject(this);
4635 * Usually called by the {@link Roo.data.Store} which owns the Record.
4636 * Commits all changes made to the Record since either creation, or the last commit operation.
4638 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4639 * of commit operations.
4641 commit : function(){
4643 delete this.modified;
4644 this.editing = false;
4646 this.store.afterCommit(this);
4651 hasError : function(){
4652 return this.error != null;
4656 clearError : function(){
4661 * Creates a copy of this record.
4662 * @param {String} id (optional) A new record id if you don't want to use this record's id
4665 copy : function(newId) {
4666 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4670 * Ext JS Library 1.1.1
4671 * Copyright(c) 2006-2007, Ext JS, LLC.
4673 * Originally Released Under LGPL - original licence link has changed is not relivant.
4676 * <script type="text/javascript">
4682 * @class Roo.data.Store
4683 * @extends Roo.util.Observable
4684 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4685 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4687 * 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
4688 * has no knowledge of the format of the data returned by the Proxy.<br>
4690 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4691 * instances from the data object. These records are cached and made available through accessor functions.
4693 * Creates a new Store.
4694 * @param {Object} config A config object containing the objects needed for the Store to access data,
4695 * and read the data into Records.
4697 Roo.data.Store = function(config){
4698 this.data = new Roo.util.MixedCollection(false);
4699 this.data.getKey = function(o){
4702 this.baseParams = {};
4711 if(config && config.data){
4712 this.inlineData = config.data;
4716 Roo.apply(this, config);
4718 if(this.reader){ // reader passed
4719 this.reader = Roo.factory(this.reader, Roo.data);
4720 this.reader.xmodule = this.xmodule || false;
4721 if(!this.recordType){
4722 this.recordType = this.reader.recordType;
4724 if(this.reader.onMetaChange){
4725 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4729 if(this.recordType){
4730 this.fields = this.recordType.prototype.fields;
4736 * @event datachanged
4737 * Fires when the data cache has changed, and a widget which is using this Store
4738 * as a Record cache should refresh its view.
4739 * @param {Store} this
4744 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4745 * @param {Store} this
4746 * @param {Object} meta The JSON metadata
4751 * Fires when Records have been added to the Store
4752 * @param {Store} this
4753 * @param {Roo.data.Record[]} records The array of Records added
4754 * @param {Number} index The index at which the record(s) were added
4759 * Fires when a Record has been removed from the Store
4760 * @param {Store} this
4761 * @param {Roo.data.Record} record The Record that was removed
4762 * @param {Number} index The index at which the record was removed
4767 * Fires when a Record has been updated
4768 * @param {Store} this
4769 * @param {Roo.data.Record} record The Record that was updated
4770 * @param {String} operation The update operation being performed. Value may be one of:
4772 Roo.data.Record.EDIT
4773 Roo.data.Record.REJECT
4774 Roo.data.Record.COMMIT
4780 * Fires when the data cache has been cleared.
4781 * @param {Store} this
4786 * Fires before a request is made for a new data object. If the beforeload handler returns false
4787 * the load action will be canceled.
4788 * @param {Store} this
4789 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4794 * Fires after a new set of Records has been loaded.
4795 * @param {Store} this
4796 * @param {Roo.data.Record[]} records The Records that were loaded
4797 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4801 * @event loadexception
4802 * Fires if an exception occurs in the Proxy during loading.
4803 * Called with the signature of the Proxy's "loadexception" event.
4804 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4807 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4808 * @param {Object} load options
4809 * @param {Object} jsonData from your request (normally this contains the Exception)
4811 loadexception : true
4815 this.proxy = Roo.factory(this.proxy, Roo.data);
4816 this.proxy.xmodule = this.xmodule || false;
4817 this.relayEvents(this.proxy, ["loadexception"]);
4819 this.sortToggle = {};
4821 Roo.data.Store.superclass.constructor.call(this);
4823 if(this.inlineData){
4824 this.loadData(this.inlineData);
4825 delete this.inlineData;
4828 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4830 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4831 * without a remote query - used by combo/forms at present.
4835 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4838 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4841 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4842 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4845 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4846 * on any HTTP request
4849 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4852 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4853 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4858 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4859 * loaded or when a record is removed. (defaults to false).
4861 pruneModifiedRecords : false,
4867 * Add Records to the Store and fires the add event.
4868 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4870 add : function(records){
4871 records = [].concat(records);
4872 for(var i = 0, len = records.length; i < len; i++){
4873 records[i].join(this);
4875 var index = this.data.length;
4876 this.data.addAll(records);
4877 this.fireEvent("add", this, records, index);
4881 * Remove a Record from the Store and fires the remove event.
4882 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4884 remove : function(record){
4885 var index = this.data.indexOf(record);
4886 this.data.removeAt(index);
4887 if(this.pruneModifiedRecords){
4888 this.modified.remove(record);
4890 this.fireEvent("remove", this, record, index);
4894 * Remove all Records from the Store and fires the clear event.
4896 removeAll : function(){
4898 if(this.pruneModifiedRecords){
4901 this.fireEvent("clear", this);
4905 * Inserts Records to the Store at the given index and fires the add event.
4906 * @param {Number} index The start index at which to insert the passed Records.
4907 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4909 insert : function(index, records){
4910 records = [].concat(records);
4911 for(var i = 0, len = records.length; i < len; i++){
4912 this.data.insert(index, records[i]);
4913 records[i].join(this);
4915 this.fireEvent("add", this, records, index);
4919 * Get the index within the cache of the passed Record.
4920 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4921 * @return {Number} The index of the passed Record. Returns -1 if not found.
4923 indexOf : function(record){
4924 return this.data.indexOf(record);
4928 * Get the index within the cache of the Record with the passed id.
4929 * @param {String} id The id of the Record to find.
4930 * @return {Number} The index of the Record. Returns -1 if not found.
4932 indexOfId : function(id){
4933 return this.data.indexOfKey(id);
4937 * Get the Record with the specified id.
4938 * @param {String} id The id of the Record to find.
4939 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4941 getById : function(id){
4942 return this.data.key(id);
4946 * Get the Record at the specified index.
4947 * @param {Number} index The index of the Record to find.
4948 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4950 getAt : function(index){
4951 return this.data.itemAt(index);
4955 * Returns a range of Records between specified indices.
4956 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4957 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4958 * @return {Roo.data.Record[]} An array of Records
4960 getRange : function(start, end){
4961 return this.data.getRange(start, end);
4965 storeOptions : function(o){
4966 o = Roo.apply({}, o);
4969 this.lastOptions = o;
4973 * Loads the Record cache from the configured Proxy using the configured Reader.
4975 * If using remote paging, then the first load call must specify the <em>start</em>
4976 * and <em>limit</em> properties in the options.params property to establish the initial
4977 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4979 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4980 * and this call will return before the new data has been loaded. Perform any post-processing
4981 * in a callback function, or in a "load" event handler.</strong>
4983 * @param {Object} options An object containing properties which control loading options:<ul>
4984 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4985 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4986 * passed the following arguments:<ul>
4987 * <li>r : Roo.data.Record[]</li>
4988 * <li>options: Options object from the load call</li>
4989 * <li>success: Boolean success indicator</li></ul></li>
4990 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4991 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4994 load : function(options){
4995 options = options || {};
4996 if(this.fireEvent("beforeload", this, options) !== false){
4997 this.storeOptions(options);
4998 var p = Roo.apply(options.params || {}, this.baseParams);
4999 // if meta was not loaded from remote source.. try requesting it.
5000 if (!this.reader.metaFromRemote) {
5003 if(this.sortInfo && this.remoteSort){
5004 var pn = this.paramNames;
5005 p[pn["sort"]] = this.sortInfo.field;
5006 p[pn["dir"]] = this.sortInfo.direction;
5008 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5013 * Reloads the Record cache from the configured Proxy using the configured Reader and
5014 * the options from the last load operation performed.
5015 * @param {Object} options (optional) An object containing properties which may override the options
5016 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5017 * the most recently used options are reused).
5019 reload : function(options){
5020 this.load(Roo.applyIf(options||{}, this.lastOptions));
5024 // Called as a callback by the Reader during a load operation.
5025 loadRecords : function(o, options, success){
5026 if(!o || success === false){
5027 if(success !== false){
5028 this.fireEvent("load", this, [], options);
5030 if(options.callback){
5031 options.callback.call(options.scope || this, [], options, false);
5035 // if data returned failure - throw an exception.
5036 if (o.success === false) {
5037 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5040 var r = o.records, t = o.totalRecords || r.length;
5041 if(!options || options.add !== true){
5042 if(this.pruneModifiedRecords){
5045 for(var i = 0, len = r.length; i < len; i++){
5049 this.data = this.snapshot;
5050 delete this.snapshot;
5053 this.data.addAll(r);
5054 this.totalLength = t;
5056 this.fireEvent("datachanged", this);
5058 this.totalLength = Math.max(t, this.data.length+r.length);
5061 this.fireEvent("load", this, r, options);
5062 if(options.callback){
5063 options.callback.call(options.scope || this, r, options, true);
5068 * Loads data from a passed data block. A Reader which understands the format of the data
5069 * must have been configured in the constructor.
5070 * @param {Object} data The data block from which to read the Records. The format of the data expected
5071 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5072 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5074 loadData : function(o, append){
5075 var r = this.reader.readRecords(o);
5076 this.loadRecords(r, {add: append}, true);
5080 * Gets the number of cached records.
5082 * <em>If using paging, this may not be the total size of the dataset. If the data object
5083 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5084 * the data set size</em>
5086 getCount : function(){
5087 return this.data.length || 0;
5091 * Gets the total number of records in the dataset as returned by the server.
5093 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5094 * the dataset size</em>
5096 getTotalCount : function(){
5097 return this.totalLength || 0;
5101 * Returns the sort state of the Store as an object with two properties:
5103 field {String} The name of the field by which the Records are sorted
5104 direction {String} The sort order, "ASC" or "DESC"
5107 getSortState : function(){
5108 return this.sortInfo;
5112 applySort : function(){
5113 if(this.sortInfo && !this.remoteSort){
5114 var s = this.sortInfo, f = s.field;
5115 var st = this.fields.get(f).sortType;
5116 var fn = function(r1, r2){
5117 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5118 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5120 this.data.sort(s.direction, fn);
5121 if(this.snapshot && this.snapshot != this.data){
5122 this.snapshot.sort(s.direction, fn);
5128 * Sets the default sort column and order to be used by the next load operation.
5129 * @param {String} fieldName The name of the field to sort by.
5130 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5132 setDefaultSort : function(field, dir){
5133 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5138 * If remote sorting is used, the sort is performed on the server, and the cache is
5139 * reloaded. If local sorting is used, the cache is sorted internally.
5140 * @param {String} fieldName The name of the field to sort by.
5141 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5143 sort : function(fieldName, dir){
5144 var f = this.fields.get(fieldName);
5146 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5147 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5152 this.sortToggle[f.name] = dir;
5153 this.sortInfo = {field: f.name, direction: dir};
5154 if(!this.remoteSort){
5156 this.fireEvent("datachanged", this);
5158 this.load(this.lastOptions);
5163 * Calls the specified function for each of the Records in the cache.
5164 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5165 * Returning <em>false</em> aborts and exits the iteration.
5166 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5168 each : function(fn, scope){
5169 this.data.each(fn, scope);
5173 * Gets all records modified since the last commit. Modified records are persisted across load operations
5174 * (e.g., during paging).
5175 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5177 getModifiedRecords : function(){
5178 return this.modified;
5182 createFilterFn : function(property, value, anyMatch){
5183 if(!value.exec){ // not a regex
5184 value = String(value);
5185 if(value.length == 0){
5188 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5191 return value.test(r.data[property]);
5196 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5197 * @param {String} property A field on your records
5198 * @param {Number} start The record index to start at (defaults to 0)
5199 * @param {Number} end The last record index to include (defaults to length - 1)
5200 * @return {Number} The sum
5202 sum : function(property, start, end){
5203 var rs = this.data.items, v = 0;
5205 end = (end || end === 0) ? end : rs.length-1;
5207 for(var i = start; i <= end; i++){
5208 v += (rs[i].data[property] || 0);
5214 * Filter the records by a specified property.
5215 * @param {String} field A field on your records
5216 * @param {String/RegExp} value Either a string that the field
5217 * should start with or a RegExp to test against the field
5218 * @param {Boolean} anyMatch True to match any part not just the beginning
5220 filter : function(property, value, anyMatch){
5221 var fn = this.createFilterFn(property, value, anyMatch);
5222 return fn ? this.filterBy(fn) : this.clearFilter();
5226 * Filter by a function. The specified function will be called with each
5227 * record in this data source. If the function returns true the record is included,
5228 * otherwise it is filtered.
5229 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5230 * @param {Object} scope (optional) The scope of the function (defaults to this)
5232 filterBy : function(fn, scope){
5233 this.snapshot = this.snapshot || this.data;
5234 this.data = this.queryBy(fn, scope||this);
5235 this.fireEvent("datachanged", this);
5239 * Query the records by a specified property.
5240 * @param {String} field A field on your records
5241 * @param {String/RegExp} value Either a string that the field
5242 * should start with or a RegExp to test against the field
5243 * @param {Boolean} anyMatch True to match any part not just the beginning
5244 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5246 query : function(property, value, anyMatch){
5247 var fn = this.createFilterFn(property, value, anyMatch);
5248 return fn ? this.queryBy(fn) : this.data.clone();
5252 * Query by a function. The specified function will be called with each
5253 * record in this data source. If the function returns true the record is included
5255 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5256 * @param {Object} scope (optional) The scope of the function (defaults to this)
5257 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5259 queryBy : function(fn, scope){
5260 var data = this.snapshot || this.data;
5261 return data.filterBy(fn, scope||this);
5265 * Collects unique values for a particular dataIndex from this store.
5266 * @param {String} dataIndex The property to collect
5267 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5268 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5269 * @return {Array} An array of the unique values
5271 collect : function(dataIndex, allowNull, bypassFilter){
5272 var d = (bypassFilter === true && this.snapshot) ?
5273 this.snapshot.items : this.data.items;
5274 var v, sv, r = [], l = {};
5275 for(var i = 0, len = d.length; i < len; i++){
5276 v = d[i].data[dataIndex];
5278 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5287 * Revert to a view of the Record cache with no filtering applied.
5288 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5290 clearFilter : function(suppressEvent){
5291 if(this.snapshot && this.snapshot != this.data){
5292 this.data = this.snapshot;
5293 delete this.snapshot;
5294 if(suppressEvent !== true){
5295 this.fireEvent("datachanged", this);
5301 afterEdit : function(record){
5302 if(this.modified.indexOf(record) == -1){
5303 this.modified.push(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5309 afterReject : function(record){
5310 this.modified.remove(record);
5311 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5315 afterCommit : function(record){
5316 this.modified.remove(record);
5317 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5321 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5322 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5324 commitChanges : function(){
5325 var m = this.modified.slice(0);
5327 for(var i = 0, len = m.length; i < len; i++){
5333 * Cancel outstanding changes on all changed records.
5335 rejectChanges : function(){
5336 var m = this.modified.slice(0);
5338 for(var i = 0, len = m.length; i < len; i++){
5343 onMetaChange : function(meta, rtype, o){
5344 this.recordType = rtype;
5345 this.fields = rtype.prototype.fields;
5346 delete this.snapshot;
5347 this.sortInfo = meta.sortInfo || this.sortInfo;
5349 this.fireEvent('metachange', this, this.reader.meta);
5353 * Ext JS Library 1.1.1
5354 * Copyright(c) 2006-2007, Ext JS, LLC.
5356 * Originally Released Under LGPL - original licence link has changed is not relivant.
5359 * <script type="text/javascript">
5363 * @class Roo.data.SimpleStore
5364 * @extends Roo.data.Store
5365 * Small helper class to make creating Stores from Array data easier.
5366 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5367 * @cfg {Array} fields An array of field definition objects, or field name strings.
5368 * @cfg {Array} data The multi-dimensional array of data
5370 * @param {Object} config
5372 Roo.data.SimpleStore = function(config){
5373 Roo.data.SimpleStore.superclass.constructor.call(this, {
5375 reader: new Roo.data.ArrayReader({
5378 Roo.data.Record.create(config.fields)
5380 proxy : new Roo.data.MemoryProxy(config.data)
5384 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5386 * Ext JS Library 1.1.1
5387 * Copyright(c) 2006-2007, Ext JS, LLC.
5389 * Originally Released Under LGPL - original licence link has changed is not relivant.
5392 * <script type="text/javascript">
5397 * @extends Roo.data.Store
5398 * @class Roo.data.JsonStore
5399 * Small helper class to make creating Stores for JSON data easier. <br/>
5401 var store = new Roo.data.JsonStore({
5402 url: 'get-images.php',
5404 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5407 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5408 * JsonReader and HttpProxy (unless inline data is provided).</b>
5409 * @cfg {Array} fields An array of field definition objects, or field name strings.
5411 * @param {Object} config
5413 Roo.data.JsonStore = function(c){
5414 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5415 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5416 reader: new Roo.data.JsonReader(c, c.fields)
5419 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5421 * Ext JS Library 1.1.1
5422 * Copyright(c) 2006-2007, Ext JS, LLC.
5424 * Originally Released Under LGPL - original licence link has changed is not relivant.
5427 * <script type="text/javascript">
5431 Roo.data.Field = function(config){
5432 if(typeof config == "string"){
5433 config = {name: config};
5435 Roo.apply(this, config);
5441 var st = Roo.data.SortTypes;
5442 // named sortTypes are supported, here we look them up
5443 if(typeof this.sortType == "string"){
5444 this.sortType = st[this.sortType];
5447 // set default sortType for strings and dates
5451 this.sortType = st.asUCString;
5454 this.sortType = st.asDate;
5457 this.sortType = st.none;
5462 var stripRe = /[\$,%]/g;
5464 // prebuilt conversion function for this field, instead of
5465 // switching every time we're reading a value
5467 var cv, dateFormat = this.dateFormat;
5472 cv = function(v){ return v; };
5475 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5479 return v !== undefined && v !== null && v !== '' ?
5480 parseInt(String(v).replace(stripRe, ""), 10) : '';
5485 return v !== undefined && v !== null && v !== '' ?
5486 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5491 cv = function(v){ return v === true || v === "true" || v == 1; };
5498 if(v instanceof Date){
5502 if(dateFormat == "timestamp"){
5503 return new Date(v*1000);
5505 return Date.parseDate(v, dateFormat);
5507 var parsed = Date.parse(v);
5508 return parsed ? new Date(parsed) : null;
5517 Roo.data.Field.prototype = {
5525 * Ext JS Library 1.1.1
5526 * Copyright(c) 2006-2007, Ext JS, LLC.
5528 * Originally Released Under LGPL - original licence link has changed is not relivant.
5531 * <script type="text/javascript">
5534 // Base class for reading structured data from a data source. This class is intended to be
5535 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5538 * @class Roo.data.DataReader
5539 * Base class for reading structured data from a data source. This class is intended to be
5540 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5543 Roo.data.DataReader = function(meta, recordType){
5547 this.recordType = recordType instanceof Array ?
5548 Roo.data.Record.create(recordType) : recordType;
5551 Roo.data.DataReader.prototype = {
5553 * Create an empty record
5554 * @param {Object} data (optional) - overlay some values
5555 * @return {Roo.data.Record} record created.
5557 newRow : function(d) {
5559 this.recordType.prototype.fields.each(function(c) {
5561 case 'int' : da[c.name] = 0; break;
5562 case 'date' : da[c.name] = new Date(); break;
5563 case 'float' : da[c.name] = 0.0; break;
5564 case 'boolean' : da[c.name] = false; break;
5565 default : da[c.name] = ""; break;
5569 return new this.recordType(Roo.apply(da, d));
5574 * Ext JS Library 1.1.1
5575 * Copyright(c) 2006-2007, Ext JS, LLC.
5577 * Originally Released Under LGPL - original licence link has changed is not relivant.
5580 * <script type="text/javascript">
5584 * @class Roo.data.DataProxy
5585 * @extends Roo.data.Observable
5586 * This class is an abstract base class for implementations which provide retrieval of
5587 * unformatted data objects.<br>
5589 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5590 * (of the appropriate type which knows how to parse the data object) to provide a block of
5591 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5593 * Custom implementations must implement the load method as described in
5594 * {@link Roo.data.HttpProxy#load}.
5596 Roo.data.DataProxy = function(){
5600 * Fires before a network request is made to retrieve a data object.
5601 * @param {Object} This DataProxy object.
5602 * @param {Object} params The params parameter to the load function.
5607 * Fires before the load method's callback is called.
5608 * @param {Object} This DataProxy object.
5609 * @param {Object} o The data object.
5610 * @param {Object} arg The callback argument object passed to the load function.
5614 * @event loadexception
5615 * Fires if an Exception occurs during data retrieval.
5616 * @param {Object} This DataProxy object.
5617 * @param {Object} o The data object.
5618 * @param {Object} arg The callback argument object passed to the load function.
5619 * @param {Object} e The Exception.
5621 loadexception : true
5623 Roo.data.DataProxy.superclass.constructor.call(this);
5626 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5629 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5633 * Ext JS Library 1.1.1
5634 * Copyright(c) 2006-2007, Ext JS, LLC.
5636 * Originally Released Under LGPL - original licence link has changed is not relivant.
5639 * <script type="text/javascript">
5642 * @class Roo.data.MemoryProxy
5643 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5644 * to the Reader when its load method is called.
5646 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5648 Roo.data.MemoryProxy = function(data){
5652 Roo.data.MemoryProxy.superclass.constructor.call(this);
5656 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5658 * Load data from the requested source (in this case an in-memory
5659 * data object passed to the constructor), read the data object into
5660 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5661 * process that block using the passed callback.
5662 * @param {Object} params This parameter is not used by the MemoryProxy class.
5663 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5664 * object into a block of Roo.data.Records.
5665 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5666 * The function must be passed <ul>
5667 * <li>The Record block object</li>
5668 * <li>The "arg" argument from the load function</li>
5669 * <li>A boolean success indicator</li>
5671 * @param {Object} scope The scope in which to call the callback
5672 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5674 load : function(params, reader, callback, scope, arg){
5675 params = params || {};
5678 result = reader.readRecords(this.data);
5680 this.fireEvent("loadexception", this, arg, null, e);
5681 callback.call(scope, null, arg, false);
5684 callback.call(scope, result, arg, true);
5688 update : function(params, records){
5693 * Ext JS Library 1.1.1
5694 * Copyright(c) 2006-2007, Ext JS, LLC.
5696 * Originally Released Under LGPL - original licence link has changed is not relivant.
5699 * <script type="text/javascript">
5702 * @class Roo.data.HttpProxy
5703 * @extends Roo.data.DataProxy
5704 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5705 * configured to reference a certain URL.<br><br>
5707 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5708 * from which the running page was served.<br><br>
5710 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5712 * Be aware that to enable the browser to parse an XML document, the server must set
5713 * the Content-Type header in the HTTP response to "text/xml".
5715 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5716 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5717 * will be used to make the request.
5719 Roo.data.HttpProxy = function(conn){
5720 Roo.data.HttpProxy.superclass.constructor.call(this);
5721 // is conn a conn config or a real conn?
5723 this.useAjax = !conn || !conn.events;
5727 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5728 // thse are take from connection...
5731 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5734 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5735 * extra parameters to each request made by this object. (defaults to undefined)
5738 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5739 * to each request made by this object. (defaults to undefined)
5742 * @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)
5745 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5748 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5754 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5758 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5759 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5760 * a finer-grained basis than the DataProxy events.
5762 getConnection : function(){
5763 return this.useAjax ? Roo.Ajax : this.conn;
5767 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5768 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5769 * process that block using the passed callback.
5770 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5771 * for the request to the remote server.
5772 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5773 * object into a block of Roo.data.Records.
5774 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5775 * The function must be passed <ul>
5776 * <li>The Record block object</li>
5777 * <li>The "arg" argument from the load function</li>
5778 * <li>A boolean success indicator</li>
5780 * @param {Object} scope The scope in which to call the callback
5781 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5783 load : function(params, reader, callback, scope, arg){
5784 if(this.fireEvent("beforeload", this, params) !== false){
5786 params : params || {},
5788 callback : callback,
5793 callback : this.loadResponse,
5797 Roo.applyIf(o, this.conn);
5798 if(this.activeRequest){
5799 Roo.Ajax.abort(this.activeRequest);
5801 this.activeRequest = Roo.Ajax.request(o);
5803 this.conn.request(o);
5806 callback.call(scope||this, null, arg, false);
5811 loadResponse : function(o, success, response){
5812 delete this.activeRequest;
5814 this.fireEvent("loadexception", this, o, response);
5815 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5820 result = o.reader.read(response);
5822 this.fireEvent("loadexception", this, o, response, e);
5823 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5827 this.fireEvent("load", this, o, o.request.arg);
5828 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5832 update : function(dataSet){
5837 updateResponse : function(dataSet){
5842 * Ext JS Library 1.1.1
5843 * Copyright(c) 2006-2007, Ext JS, LLC.
5845 * Originally Released Under LGPL - original licence link has changed is not relivant.
5848 * <script type="text/javascript">
5852 * @class Roo.data.ScriptTagProxy
5853 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5854 * other than the originating domain of the running page.<br><br>
5856 * <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
5857 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5859 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5860 * source code that is used as the source inside a <script> tag.<br><br>
5862 * In order for the browser to process the returned data, the server must wrap the data object
5863 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5864 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5865 * depending on whether the callback name was passed:
5868 boolean scriptTag = false;
5869 String cb = request.getParameter("callback");
5872 response.setContentType("text/javascript");
5874 response.setContentType("application/x-json");
5876 Writer out = response.getWriter();
5878 out.write(cb + "(");
5880 out.print(dataBlock.toJsonString());
5887 * @param {Object} config A configuration object.
5889 Roo.data.ScriptTagProxy = function(config){
5890 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5891 Roo.apply(this, config);
5892 this.head = document.getElementsByTagName("head")[0];
5895 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5897 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5899 * @cfg {String} url The URL from which to request the data object.
5902 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5906 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5907 * the server the name of the callback function set up by the load call to process the returned data object.
5908 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5909 * javascript output which calls this named function passing the data object as its only parameter.
5911 callbackParam : "callback",
5913 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5914 * name to the request.
5919 * Load data from the configured URL, read the data object into
5920 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5921 * process that block using the passed callback.
5922 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5923 * for the request to the remote server.
5924 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5925 * object into a block of Roo.data.Records.
5926 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5927 * The function must be passed <ul>
5928 * <li>The Record block object</li>
5929 * <li>The "arg" argument from the load function</li>
5930 * <li>A boolean success indicator</li>
5932 * @param {Object} scope The scope in which to call the callback
5933 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5935 load : function(params, reader, callback, scope, arg){
5936 if(this.fireEvent("beforeload", this, params) !== false){
5938 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5941 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5943 url += "&_dc=" + (new Date().getTime());
5945 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5948 cb : "stcCallback"+transId,
5949 scriptId : "stcScript"+transId,
5953 callback : callback,
5959 window[trans.cb] = function(o){
5960 conn.handleResponse(o, trans);
5963 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5965 if(this.autoAbort !== false){
5969 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5971 var script = document.createElement("script");
5972 script.setAttribute("src", url);
5973 script.setAttribute("type", "text/javascript");
5974 script.setAttribute("id", trans.scriptId);
5975 this.head.appendChild(script);
5979 callback.call(scope||this, null, arg, false);
5984 isLoading : function(){
5985 return this.trans ? true : false;
5989 * Abort the current server request.
5992 if(this.isLoading()){
5993 this.destroyTrans(this.trans);
5998 destroyTrans : function(trans, isLoaded){
5999 this.head.removeChild(document.getElementById(trans.scriptId));
6000 clearTimeout(trans.timeoutId);
6002 window[trans.cb] = undefined;
6004 delete window[trans.cb];
6007 // if hasn't been loaded, wait for load to remove it to prevent script error
6008 window[trans.cb] = function(){
6009 window[trans.cb] = undefined;
6011 delete window[trans.cb];
6018 handleResponse : function(o, trans){
6020 this.destroyTrans(trans, true);
6023 result = trans.reader.readRecords(o);
6025 this.fireEvent("loadexception", this, o, trans.arg, e);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6029 this.fireEvent("load", this, o, trans.arg);
6030 trans.callback.call(trans.scope||window, result, trans.arg, true);
6034 handleFailure : function(trans){
6036 this.destroyTrans(trans, false);
6037 this.fireEvent("loadexception", this, null, trans.arg);
6038 trans.callback.call(trans.scope||window, null, trans.arg, false);
6042 * Ext JS Library 1.1.1
6043 * Copyright(c) 2006-2007, Ext JS, LLC.
6045 * Originally Released Under LGPL - original licence link has changed is not relivant.
6048 * <script type="text/javascript">
6052 * @class Roo.data.JsonReader
6053 * @extends Roo.data.DataReader
6054 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6055 * based on mappings in a provided Roo.data.Record constructor.
6057 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6058 * in the reply previously.
6063 var RecordDef = Roo.data.Record.create([
6064 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6065 {name: 'occupation'} // This field will use "occupation" as the mapping.
6067 var myReader = new Roo.data.JsonReader({
6068 totalProperty: "results", // The property which contains the total dataset size (optional)
6069 root: "rows", // The property which contains an Array of row objects
6070 id: "id" // The property within each row object that provides an ID for the record (optional)
6074 * This would consume a JSON file like this:
6076 { 'results': 2, 'rows': [
6077 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6078 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6081 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6082 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6083 * paged from the remote server.
6084 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6085 * @cfg {String} root name of the property which contains the Array of row objects.
6086 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6088 * Create a new JsonReader
6089 * @param {Object} meta Metadata configuration options
6090 * @param {Object} recordType Either an Array of field definition objects,
6091 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6093 Roo.data.JsonReader = function(meta, recordType){
6096 // set some defaults:
6098 totalProperty: 'total',
6099 successProperty : 'success',
6104 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6106 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6109 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6110 * Used by Store query builder to append _requestMeta to params.
6113 metaFromRemote : false,
6115 * This method is only used by a DataProxy which has retrieved data from a remote server.
6116 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6117 * @return {Object} data A data block which is used by an Roo.data.Store object as
6118 * a cache of Roo.data.Records.
6120 read : function(response){
6121 var json = response.responseText;
6123 var o = /* eval:var:o */ eval("("+json+")");
6125 throw {message: "JsonReader.read: Json object not found"};
6131 this.metaFromRemote = true;
6132 this.meta = o.metaData;
6133 this.recordType = Roo.data.Record.create(o.metaData.fields);
6134 this.onMetaChange(this.meta, this.recordType, o);
6136 return this.readRecords(o);
6139 // private function a store will implement
6140 onMetaChange : function(meta, recordType, o){
6147 simpleAccess: function(obj, subsc) {
6154 getJsonAccessor: function(){
6156 return function(expr) {
6158 return(re.test(expr))
6159 ? new Function("obj", "return obj." + expr)
6169 * Create a data block containing Roo.data.Records from an XML document.
6170 * @param {Object} o An object which contains an Array of row objects in the property specified
6171 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6172 * which contains the total size of the dataset.
6173 * @return {Object} data A data block which is used by an Roo.data.Store object as
6174 * a cache of Roo.data.Records.
6176 readRecords : function(o){
6178 * After any data loads, the raw JSON data is available for further custom processing.
6182 var s = this.meta, Record = this.recordType,
6183 f = Record.prototype.fields, fi = f.items, fl = f.length;
6185 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6187 if(s.totalProperty) {
6188 this.getTotal = this.getJsonAccessor(s.totalProperty);
6190 if(s.successProperty) {
6191 this.getSuccess = this.getJsonAccessor(s.successProperty);
6193 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6195 var g = this.getJsonAccessor(s.id);
6196 this.getId = function(rec) {
6198 return (r === undefined || r === "") ? null : r;
6201 this.getId = function(){return null;};
6204 for(var jj = 0; jj < fl; jj++){
6206 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6207 this.ef[jj] = this.getJsonAccessor(map);
6211 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6212 if(s.totalProperty){
6213 var vt = parseInt(this.getTotal(o), 10);
6218 if(s.successProperty){
6219 var vs = this.getSuccess(o);
6220 if(vs === false || vs === 'false'){
6225 for(var i = 0; i < c; i++){
6228 var id = this.getId(n);
6229 for(var j = 0; j < fl; j++){
6231 var v = this.ef[j](n);
6233 Roo.log('missing convert for ' + f.name);
6237 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6239 var record = new Record(values, id);
6241 records[i] = record;
6246 totalRecords : totalRecords
6251 * Ext JS Library 1.1.1
6252 * Copyright(c) 2006-2007, Ext JS, LLC.
6254 * Originally Released Under LGPL - original licence link has changed is not relivant.
6257 * <script type="text/javascript">
6261 * @class Roo.data.XmlReader
6262 * @extends Roo.data.DataReader
6263 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6264 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6266 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6267 * header in the HTTP response must be set to "text/xml".</em>
6271 var RecordDef = Roo.data.Record.create([
6272 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6273 {name: 'occupation'} // This field will use "occupation" as the mapping.
6275 var myReader = new Roo.data.XmlReader({
6276 totalRecords: "results", // The element which contains the total dataset size (optional)
6277 record: "row", // The repeated element which contains row information
6278 id: "id" // The element within the row that provides an ID for the record (optional)
6282 * This would consume an XML file like this:
6286 <results>2</results>
6289 <name>Bill</name>
6290 <occupation>Gardener</occupation>
6294 <name>Ben</name>
6295 <occupation>Horticulturalist</occupation>
6299 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6300 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6301 * paged from the remote server.
6302 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6303 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6304 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6305 * a record identifier value.
6307 * Create a new XmlReader
6308 * @param {Object} meta Metadata configuration options
6309 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6310 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6311 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6313 Roo.data.XmlReader = function(meta, recordType){
6315 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6317 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6319 * This method is only used by a DataProxy which has retrieved data from a remote server.
6320 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6321 * to contain a method called 'responseXML' that returns an XML document object.
6322 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6323 * a cache of Roo.data.Records.
6325 read : function(response){
6326 var doc = response.responseXML;
6328 throw {message: "XmlReader.read: XML Document not available"};
6330 return this.readRecords(doc);
6334 * Create a data block containing Roo.data.Records from an XML document.
6335 * @param {Object} doc A parsed XML document.
6336 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6337 * a cache of Roo.data.Records.
6339 readRecords : function(doc){
6341 * After any data loads/reads, the raw XML Document is available for further custom processing.
6345 var root = doc.documentElement || doc;
6346 var q = Roo.DomQuery;
6347 var recordType = this.recordType, fields = recordType.prototype.fields;
6348 var sid = this.meta.id;
6349 var totalRecords = 0, success = true;
6350 if(this.meta.totalRecords){
6351 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6354 if(this.meta.success){
6355 var sv = q.selectValue(this.meta.success, root, true);
6356 success = sv !== false && sv !== 'false';
6359 var ns = q.select(this.meta.record, root);
6360 for(var i = 0, len = ns.length; i < len; i++) {
6363 var id = sid ? q.selectValue(sid, n) : undefined;
6364 for(var j = 0, jlen = fields.length; j < jlen; j++){
6365 var f = fields.items[j];
6366 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6370 var record = new recordType(values, id);
6372 records[records.length] = record;
6378 totalRecords : totalRecords || records.length
6383 * Ext JS Library 1.1.1
6384 * Copyright(c) 2006-2007, Ext JS, LLC.
6386 * Originally Released Under LGPL - original licence link has changed is not relivant.
6389 * <script type="text/javascript">
6393 * @class Roo.data.ArrayReader
6394 * @extends Roo.data.DataReader
6395 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6396 * Each element of that Array represents a row of data fields. The
6397 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6398 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6402 var RecordDef = Roo.data.Record.create([
6403 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6404 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6406 var myReader = new Roo.data.ArrayReader({
6407 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6411 * This would consume an Array like this:
6413 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6415 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6417 * Create a new JsonReader
6418 * @param {Object} meta Metadata configuration options.
6419 * @param {Object} recordType Either an Array of field definition objects
6420 * as specified to {@link Roo.data.Record#create},
6421 * or an {@link Roo.data.Record} object
6422 * created using {@link Roo.data.Record#create}.
6424 Roo.data.ArrayReader = function(meta, recordType){
6425 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6428 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6430 * Create a data block containing Roo.data.Records from an XML document.
6431 * @param {Object} o An Array of row objects which represents the dataset.
6432 * @return {Object} data A data block which is used by an Roo.data.Store object as
6433 * a cache of Roo.data.Records.
6435 readRecords : function(o){
6436 var sid = this.meta ? this.meta.id : null;
6437 var recordType = this.recordType, fields = recordType.prototype.fields;
6440 for(var i = 0; i < root.length; i++){
6443 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6444 for(var j = 0, jlen = fields.length; j < jlen; j++){
6445 var f = fields.items[j];
6446 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6447 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6451 var record = new recordType(values, id);
6453 records[records.length] = record;
6457 totalRecords : records.length
6462 * Ext JS Library 1.1.1
6463 * Copyright(c) 2006-2007, Ext JS, LLC.
6465 * Originally Released Under LGPL - original licence link has changed is not relivant.
6468 * <script type="text/javascript">
6473 * @class Roo.data.Tree
6474 * @extends Roo.util.Observable
6475 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6476 * in the tree have most standard DOM functionality.
6478 * @param {Node} root (optional) The root node
6480 Roo.data.Tree = function(root){
6483 * The root node for this tree
6488 this.setRootNode(root);
6493 * Fires when a new child node is appended to a node in this tree.
6494 * @param {Tree} tree The owner tree
6495 * @param {Node} parent The parent node
6496 * @param {Node} node The newly appended node
6497 * @param {Number} index The index of the newly appended node
6502 * Fires when a child node is removed from a node in this tree.
6503 * @param {Tree} tree The owner tree
6504 * @param {Node} parent The parent node
6505 * @param {Node} node The child node removed
6510 * Fires when a node is moved to a new location in the tree
6511 * @param {Tree} tree The owner tree
6512 * @param {Node} node The node moved
6513 * @param {Node} oldParent The old parent of this node
6514 * @param {Node} newParent The new parent of this node
6515 * @param {Number} index The index it was moved to
6520 * Fires when a new child node is inserted in a node in this tree.
6521 * @param {Tree} tree The owner tree
6522 * @param {Node} parent The parent node
6523 * @param {Node} node The child node inserted
6524 * @param {Node} refNode The child node the node was inserted before
6528 * @event beforeappend
6529 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6530 * @param {Tree} tree The owner tree
6531 * @param {Node} parent The parent node
6532 * @param {Node} node The child node to be appended
6534 "beforeappend" : true,
6536 * @event beforeremove
6537 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6538 * @param {Tree} tree The owner tree
6539 * @param {Node} parent The parent node
6540 * @param {Node} node The child node to be removed
6542 "beforeremove" : true,
6545 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6546 * @param {Tree} tree The owner tree
6547 * @param {Node} node The node being moved
6548 * @param {Node} oldParent The parent of the node
6549 * @param {Node} newParent The new parent the node is moving to
6550 * @param {Number} index The index it is being moved to
6552 "beforemove" : true,
6554 * @event beforeinsert
6555 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6556 * @param {Tree} tree The owner tree
6557 * @param {Node} parent The parent node
6558 * @param {Node} node The child node to be inserted
6559 * @param {Node} refNode The child node the node is being inserted before
6561 "beforeinsert" : true
6564 Roo.data.Tree.superclass.constructor.call(this);
6567 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6570 proxyNodeEvent : function(){
6571 return this.fireEvent.apply(this, arguments);
6575 * Returns the root node for this tree.
6578 getRootNode : function(){
6583 * Sets the root node for this tree.
6584 * @param {Node} node
6587 setRootNode : function(node){
6589 node.ownerTree = this;
6591 this.registerNode(node);
6596 * Gets a node in this tree by its id.
6597 * @param {String} id
6600 getNodeById : function(id){
6601 return this.nodeHash[id];
6604 registerNode : function(node){
6605 this.nodeHash[node.id] = node;
6608 unregisterNode : function(node){
6609 delete this.nodeHash[node.id];
6612 toString : function(){
6613 return "[Tree"+(this.id?" "+this.id:"")+"]";
6618 * @class Roo.data.Node
6619 * @extends Roo.util.Observable
6620 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6621 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6623 * @param {Object} attributes The attributes/config for the node
6625 Roo.data.Node = function(attributes){
6627 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6630 this.attributes = attributes || {};
6631 this.leaf = this.attributes.leaf;
6633 * The node id. @type String
6635 this.id = this.attributes.id;
6637 this.id = Roo.id(null, "ynode-");
6638 this.attributes.id = this.id;
6641 * All child nodes of this node. @type Array
6643 this.childNodes = [];
6644 if(!this.childNodes.indexOf){ // indexOf is a must
6645 this.childNodes.indexOf = function(o){
6646 for(var i = 0, len = this.length; i < len; i++){
6655 * The parent node for this node. @type Node
6657 this.parentNode = null;
6659 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6661 this.firstChild = null;
6663 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6665 this.lastChild = null;
6667 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6669 this.previousSibling = null;
6671 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6673 this.nextSibling = null;
6678 * Fires when a new child node is appended
6679 * @param {Tree} tree The owner tree
6680 * @param {Node} this This node
6681 * @param {Node} node The newly appended node
6682 * @param {Number} index The index of the newly appended node
6687 * Fires when a child node is removed
6688 * @param {Tree} tree The owner tree
6689 * @param {Node} this This node
6690 * @param {Node} node The removed node
6695 * Fires when this node is moved to a new location in the tree
6696 * @param {Tree} tree The owner tree
6697 * @param {Node} this This node
6698 * @param {Node} oldParent The old parent of this node
6699 * @param {Node} newParent The new parent of this node
6700 * @param {Number} index The index it was moved to
6705 * Fires when a new child node is inserted.
6706 * @param {Tree} tree The owner tree
6707 * @param {Node} this This node
6708 * @param {Node} node The child node inserted
6709 * @param {Node} refNode The child node the node was inserted before
6713 * @event beforeappend
6714 * Fires before a new child is appended, return false to cancel the append.
6715 * @param {Tree} tree The owner tree
6716 * @param {Node} this This node
6717 * @param {Node} node The child node to be appended
6719 "beforeappend" : true,
6721 * @event beforeremove
6722 * Fires before a child is removed, return false to cancel the remove.
6723 * @param {Tree} tree The owner tree
6724 * @param {Node} this This node
6725 * @param {Node} node The child node to be removed
6727 "beforeremove" : true,
6730 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6731 * @param {Tree} tree The owner tree
6732 * @param {Node} this This node
6733 * @param {Node} oldParent The parent of this node
6734 * @param {Node} newParent The new parent this node is moving to
6735 * @param {Number} index The index it is being moved to
6737 "beforemove" : true,
6739 * @event beforeinsert
6740 * Fires before a new child is inserted, return false to cancel the insert.
6741 * @param {Tree} tree The owner tree
6742 * @param {Node} this This node
6743 * @param {Node} node The child node to be inserted
6744 * @param {Node} refNode The child node the node is being inserted before
6746 "beforeinsert" : true
6748 this.listeners = this.attributes.listeners;
6749 Roo.data.Node.superclass.constructor.call(this);
6752 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6753 fireEvent : function(evtName){
6754 // first do standard event for this node
6755 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6758 // then bubble it up to the tree if the event wasn't cancelled
6759 var ot = this.getOwnerTree();
6761 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6769 * Returns true if this node is a leaf
6772 isLeaf : function(){
6773 return this.leaf === true;
6777 setFirstChild : function(node){
6778 this.firstChild = node;
6782 setLastChild : function(node){
6783 this.lastChild = node;
6788 * Returns true if this node is the last child of its parent
6791 isLast : function(){
6792 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6796 * Returns true if this node is the first child of its parent
6799 isFirst : function(){
6800 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6803 hasChildNodes : function(){
6804 return !this.isLeaf() && this.childNodes.length > 0;
6808 * Insert node(s) as the last child node of this node.
6809 * @param {Node/Array} node The node or Array of nodes to append
6810 * @return {Node} The appended node if single append, or null if an array was passed
6812 appendChild : function(node){
6814 if(node instanceof Array){
6816 }else if(arguments.length > 1){
6819 // if passed an array or multiple args do them one by one
6821 for(var i = 0, len = multi.length; i < len; i++) {
6822 this.appendChild(multi[i]);
6825 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6828 var index = this.childNodes.length;
6829 var oldParent = node.parentNode;
6830 // it's a move, make sure we move it cleanly
6832 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6835 oldParent.removeChild(node);
6837 index = this.childNodes.length;
6839 this.setFirstChild(node);
6841 this.childNodes.push(node);
6842 node.parentNode = this;
6843 var ps = this.childNodes[index-1];
6845 node.previousSibling = ps;
6846 ps.nextSibling = node;
6848 node.previousSibling = null;
6850 node.nextSibling = null;
6851 this.setLastChild(node);
6852 node.setOwnerTree(this.getOwnerTree());
6853 this.fireEvent("append", this.ownerTree, this, node, index);
6855 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6862 * Removes a child node from this node.
6863 * @param {Node} node The node to remove
6864 * @return {Node} The removed node
6866 removeChild : function(node){
6867 var index = this.childNodes.indexOf(node);
6871 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6875 // remove it from childNodes collection
6876 this.childNodes.splice(index, 1);
6879 if(node.previousSibling){
6880 node.previousSibling.nextSibling = node.nextSibling;
6882 if(node.nextSibling){
6883 node.nextSibling.previousSibling = node.previousSibling;
6886 // update child refs
6887 if(this.firstChild == node){
6888 this.setFirstChild(node.nextSibling);
6890 if(this.lastChild == node){
6891 this.setLastChild(node.previousSibling);
6894 node.setOwnerTree(null);
6895 // clear any references from the node
6896 node.parentNode = null;
6897 node.previousSibling = null;
6898 node.nextSibling = null;
6899 this.fireEvent("remove", this.ownerTree, this, node);
6904 * Inserts the first node before the second node in this nodes childNodes collection.
6905 * @param {Node} node The node to insert
6906 * @param {Node} refNode The node to insert before (if null the node is appended)
6907 * @return {Node} The inserted node
6909 insertBefore : function(node, refNode){
6910 if(!refNode){ // like standard Dom, refNode can be null for append
6911 return this.appendChild(node);
6914 if(node == refNode){
6918 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6921 var index = this.childNodes.indexOf(refNode);
6922 var oldParent = node.parentNode;
6923 var refIndex = index;
6925 // when moving internally, indexes will change after remove
6926 if(oldParent == this && this.childNodes.indexOf(node) < index){
6930 // it's a move, make sure we move it cleanly
6932 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6935 oldParent.removeChild(node);
6938 this.setFirstChild(node);
6940 this.childNodes.splice(refIndex, 0, node);
6941 node.parentNode = this;
6942 var ps = this.childNodes[refIndex-1];
6944 node.previousSibling = ps;
6945 ps.nextSibling = node;
6947 node.previousSibling = null;
6949 node.nextSibling = refNode;
6950 refNode.previousSibling = node;
6951 node.setOwnerTree(this.getOwnerTree());
6952 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6954 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6960 * Returns the child node at the specified index.
6961 * @param {Number} index
6964 item : function(index){
6965 return this.childNodes[index];
6969 * Replaces one child node in this node with another.
6970 * @param {Node} newChild The replacement node
6971 * @param {Node} oldChild The node to replace
6972 * @return {Node} The replaced node
6974 replaceChild : function(newChild, oldChild){
6975 this.insertBefore(newChild, oldChild);
6976 this.removeChild(oldChild);
6981 * Returns the index of a child node
6982 * @param {Node} node
6983 * @return {Number} The index of the node or -1 if it was not found
6985 indexOf : function(child){
6986 return this.childNodes.indexOf(child);
6990 * Returns the tree this node is in.
6993 getOwnerTree : function(){
6994 // if it doesn't have one, look for one
6995 if(!this.ownerTree){
6999 this.ownerTree = p.ownerTree;
7005 return this.ownerTree;
7009 * Returns depth of this node (the root node has a depth of 0)
7012 getDepth : function(){
7015 while(p.parentNode){
7023 setOwnerTree : function(tree){
7024 // if it's move, we need to update everyone
7025 if(tree != this.ownerTree){
7027 this.ownerTree.unregisterNode(this);
7029 this.ownerTree = tree;
7030 var cs = this.childNodes;
7031 for(var i = 0, len = cs.length; i < len; i++) {
7032 cs[i].setOwnerTree(tree);
7035 tree.registerNode(this);
7041 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7042 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7043 * @return {String} The path
7045 getPath : function(attr){
7046 attr = attr || "id";
7047 var p = this.parentNode;
7048 var b = [this.attributes[attr]];
7050 b.unshift(p.attributes[attr]);
7053 var sep = this.getOwnerTree().pathSeparator;
7054 return sep + b.join(sep);
7058 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7059 * function call will be the scope provided or the current node. The arguments to the function
7060 * will be the args provided or the current node. If the function returns false at any point,
7061 * the bubble is stopped.
7062 * @param {Function} fn The function to call
7063 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7064 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7066 bubble : function(fn, scope, args){
7069 if(fn.call(scope || p, args || p) === false){
7077 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7078 * function call will be the scope provided or the current node. The arguments to the function
7079 * will be the args provided or the current node. If the function returns false at any point,
7080 * the cascade is stopped on that branch.
7081 * @param {Function} fn The function to call
7082 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7083 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7085 cascade : function(fn, scope, args){
7086 if(fn.call(scope || this, args || this) !== false){
7087 var cs = this.childNodes;
7088 for(var i = 0, len = cs.length; i < len; i++) {
7089 cs[i].cascade(fn, scope, args);
7095 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7096 * function call will be the scope provided or the current node. The arguments to the function
7097 * will be the args provided or the current node. If the function returns false at any point,
7098 * the iteration stops.
7099 * @param {Function} fn The function to call
7100 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7101 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7103 eachChild : function(fn, scope, args){
7104 var cs = this.childNodes;
7105 for(var i = 0, len = cs.length; i < len; i++) {
7106 if(fn.call(scope || this, args || cs[i]) === false){
7113 * Finds the first child that has the attribute with the specified value.
7114 * @param {String} attribute The attribute name
7115 * @param {Mixed} value The value to search for
7116 * @return {Node} The found child or null if none was found
7118 findChild : function(attribute, value){
7119 var cs = this.childNodes;
7120 for(var i = 0, len = cs.length; i < len; i++) {
7121 if(cs[i].attributes[attribute] == value){
7129 * Finds the first child by a custom function. The child matches if the function passed
7131 * @param {Function} fn
7132 * @param {Object} scope (optional)
7133 * @return {Node} The found child or null if none was found
7135 findChildBy : function(fn, scope){
7136 var cs = this.childNodes;
7137 for(var i = 0, len = cs.length; i < len; i++) {
7138 if(fn.call(scope||cs[i], cs[i]) === true){
7146 * Sorts this nodes children using the supplied sort function
7147 * @param {Function} fn
7148 * @param {Object} scope (optional)
7150 sort : function(fn, scope){
7151 var cs = this.childNodes;
7152 var len = cs.length;
7154 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7156 for(var i = 0; i < len; i++){
7158 n.previousSibling = cs[i-1];
7159 n.nextSibling = cs[i+1];
7161 this.setFirstChild(n);
7164 this.setLastChild(n);
7171 * Returns true if this node is an ancestor (at any point) of the passed node.
7172 * @param {Node} node
7175 contains : function(node){
7176 return node.isAncestor(this);
7180 * Returns true if the passed node is an ancestor (at any point) of this node.
7181 * @param {Node} node
7184 isAncestor : function(node){
7185 var p = this.parentNode;
7195 toString : function(){
7196 return "[Node"+(this.id?" "+this.id:"")+"]";
7200 * Ext JS Library 1.1.1
7201 * Copyright(c) 2006-2007, Ext JS, LLC.
7203 * Originally Released Under LGPL - original licence link has changed is not relivant.
7206 * <script type="text/javascript">
7211 * @class Roo.ComponentMgr
7212 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7215 Roo.ComponentMgr = function(){
7216 var all = new Roo.util.MixedCollection();
7220 * Registers a component.
7221 * @param {Roo.Component} c The component
7223 register : function(c){
7228 * Unregisters a component.
7229 * @param {Roo.Component} c The component
7231 unregister : function(c){
7236 * Returns a component by id
7237 * @param {String} id The component id
7244 * Registers a function that will be called when a specified component is added to ComponentMgr
7245 * @param {String} id The component id
7246 * @param {Funtction} fn The callback function
7247 * @param {Object} scope The scope of the callback
7249 onAvailable : function(id, fn, scope){
7250 all.on("add", function(index, o){
7252 fn.call(scope || o, o);
7253 all.un("add", fn, scope);
7260 * Ext JS Library 1.1.1
7261 * Copyright(c) 2006-2007, Ext JS, LLC.
7263 * Originally Released Under LGPL - original licence link has changed is not relivant.
7266 * <script type="text/javascript">
7270 * @class Roo.Component
7271 * @extends Roo.util.Observable
7272 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7273 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7274 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7275 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7276 * All visual components (widgets) that require rendering into a layout should subclass Component.
7278 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7279 * 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
7280 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7282 Roo.Component = function(config){
7283 config = config || {};
7284 if(config.tagName || config.dom || typeof config == "string"){ // element object
7285 config = {el: config, id: config.id || config};
7287 this.initialConfig = config;
7289 Roo.apply(this, config);
7293 * Fires after the component is disabled.
7294 * @param {Roo.Component} this
7299 * Fires after the component is enabled.
7300 * @param {Roo.Component} this
7305 * Fires before the component is shown. Return false to stop the show.
7306 * @param {Roo.Component} this
7311 * Fires after the component is shown.
7312 * @param {Roo.Component} this
7317 * Fires before the component is hidden. Return false to stop the hide.
7318 * @param {Roo.Component} this
7323 * Fires after the component is hidden.
7324 * @param {Roo.Component} this
7328 * @event beforerender
7329 * Fires before the component is rendered. Return false to stop the render.
7330 * @param {Roo.Component} this
7332 beforerender : true,
7335 * Fires after the component is rendered.
7336 * @param {Roo.Component} this
7340 * @event beforedestroy
7341 * Fires before the component is destroyed. Return false to stop the destroy.
7342 * @param {Roo.Component} this
7344 beforedestroy : true,
7347 * Fires after the component is destroyed.
7348 * @param {Roo.Component} this
7353 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7355 Roo.ComponentMgr.register(this);
7356 Roo.Component.superclass.constructor.call(this);
7357 this.initComponent();
7358 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7359 this.render(this.renderTo);
7360 delete this.renderTo;
7365 Roo.Component.AUTO_ID = 1000;
7367 Roo.extend(Roo.Component, Roo.util.Observable, {
7369 * @property {Boolean} hidden
7370 * true if this component is hidden. Read-only.
7374 * true if this component is disabled. Read-only.
7378 * true if this component has been rendered. Read-only.
7382 /** @cfg {String} disableClass
7383 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7385 disabledClass : "x-item-disabled",
7386 /** @cfg {Boolean} allowDomMove
7387 * Whether the component can move the Dom node when rendering (defaults to true).
7389 allowDomMove : true,
7390 /** @cfg {String} hideMode
7391 * How this component should hidden. Supported values are
7392 * "visibility" (css visibility), "offsets" (negative offset position) and
7393 * "display" (css display) - defaults to "display".
7395 hideMode: 'display',
7398 ctype : "Roo.Component",
7400 /** @cfg {String} actionMode
7401 * which property holds the element that used for hide() / show() / disable() / enable()
7407 getActionEl : function(){
7408 return this[this.actionMode];
7411 initComponent : Roo.emptyFn,
7413 * If this is a lazy rendering component, render it to its container element.
7414 * @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.
7416 render : function(container, position){
7417 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7418 if(!container && this.el){
7419 this.el = Roo.get(this.el);
7420 container = this.el.dom.parentNode;
7421 this.allowDomMove = false;
7423 this.container = Roo.get(container);
7424 this.rendered = true;
7425 if(position !== undefined){
7426 if(typeof position == 'number'){
7427 position = this.container.dom.childNodes[position];
7429 position = Roo.getDom(position);
7432 this.onRender(this.container, position || null);
7434 this.el.addClass(this.cls);
7438 this.el.applyStyles(this.style);
7441 this.fireEvent("render", this);
7442 this.afterRender(this.container);
7454 // default function is not really useful
7455 onRender : function(ct, position){
7457 this.el = Roo.get(this.el);
7458 if(this.allowDomMove !== false){
7459 ct.dom.insertBefore(this.el.dom, position);
7465 getAutoCreate : function(){
7466 var cfg = typeof this.autoCreate == "object" ?
7467 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7468 if(this.id && !cfg.id){
7475 afterRender : Roo.emptyFn,
7478 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7479 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7481 destroy : function(){
7482 if(this.fireEvent("beforedestroy", this) !== false){
7483 this.purgeListeners();
7484 this.beforeDestroy();
7486 this.el.removeAllListeners();
7488 if(this.actionMode == "container"){
7489 this.container.remove();
7493 Roo.ComponentMgr.unregister(this);
7494 this.fireEvent("destroy", this);
7499 beforeDestroy : function(){
7504 onDestroy : function(){
7509 * Returns the underlying {@link Roo.Element}.
7510 * @return {Roo.Element} The element
7517 * Returns the id of this component.
7525 * Try to focus this component.
7526 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7527 * @return {Roo.Component} this
7529 focus : function(selectText){
7532 if(selectText === true){
7533 this.el.dom.select();
7548 * Disable this component.
7549 * @return {Roo.Component} this
7551 disable : function(){
7555 this.disabled = true;
7556 this.fireEvent("disable", this);
7561 onDisable : function(){
7562 this.getActionEl().addClass(this.disabledClass);
7563 this.el.dom.disabled = true;
7567 * Enable this component.
7568 * @return {Roo.Component} this
7570 enable : function(){
7574 this.disabled = false;
7575 this.fireEvent("enable", this);
7580 onEnable : function(){
7581 this.getActionEl().removeClass(this.disabledClass);
7582 this.el.dom.disabled = false;
7586 * Convenience function for setting disabled/enabled by boolean.
7587 * @param {Boolean} disabled
7589 setDisabled : function(disabled){
7590 this[disabled ? "disable" : "enable"]();
7594 * Show this component.
7595 * @return {Roo.Component} this
7598 if(this.fireEvent("beforeshow", this) !== false){
7599 this.hidden = false;
7603 this.fireEvent("show", this);
7609 onShow : function(){
7610 var ae = this.getActionEl();
7611 if(this.hideMode == 'visibility'){
7612 ae.dom.style.visibility = "visible";
7613 }else if(this.hideMode == 'offsets'){
7614 ae.removeClass('x-hidden');
7616 ae.dom.style.display = "";
7621 * Hide this component.
7622 * @return {Roo.Component} this
7625 if(this.fireEvent("beforehide", this) !== false){
7630 this.fireEvent("hide", this);
7636 onHide : function(){
7637 var ae = this.getActionEl();
7638 if(this.hideMode == 'visibility'){
7639 ae.dom.style.visibility = "hidden";
7640 }else if(this.hideMode == 'offsets'){
7641 ae.addClass('x-hidden');
7643 ae.dom.style.display = "none";
7648 * Convenience function to hide or show this component by boolean.
7649 * @param {Boolean} visible True to show, false to hide
7650 * @return {Roo.Component} this
7652 setVisible: function(visible){
7662 * Returns true if this component is visible.
7664 isVisible : function(){
7665 return this.getActionEl().isVisible();
7668 cloneConfig : function(overrides){
7669 overrides = overrides || {};
7670 var id = overrides.id || Roo.id();
7671 var cfg = Roo.applyIf(overrides, this.initialConfig);
7672 cfg.id = id; // prevent dup id
7673 return new this.constructor(cfg);
7677 * Ext JS Library 1.1.1
7678 * Copyright(c) 2006-2007, Ext JS, LLC.
7680 * Originally Released Under LGPL - original licence link has changed is not relivant.
7683 * <script type="text/javascript">
7688 * @extends Roo.Element
7689 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7690 * automatic maintaining of shadow/shim positions.
7691 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7692 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7693 * you can pass a string with a CSS class name. False turns off the shadow.
7694 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7695 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7696 * @cfg {String} cls CSS class to add to the element
7697 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7698 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7700 * @param {Object} config An object with config options.
7701 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7704 Roo.Layer = function(config, existingEl){
7705 config = config || {};
7706 var dh = Roo.DomHelper;
7707 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7709 this.dom = Roo.getDom(existingEl);
7712 var o = config.dh || {tag: "div", cls: "x-layer"};
7713 this.dom = dh.append(pel, o);
7716 this.addClass(config.cls);
7718 this.constrain = config.constrain !== false;
7719 this.visibilityMode = Roo.Element.VISIBILITY;
7721 this.id = this.dom.id = config.id;
7723 this.id = Roo.id(this.dom);
7725 this.zindex = config.zindex || this.getZIndex();
7726 this.position("absolute", this.zindex);
7728 this.shadowOffset = config.shadowOffset || 4;
7729 this.shadow = new Roo.Shadow({
7730 offset : this.shadowOffset,
7731 mode : config.shadow
7734 this.shadowOffset = 0;
7736 this.useShim = config.shim !== false && Roo.useShims;
7737 this.useDisplay = config.useDisplay;
7741 var supr = Roo.Element.prototype;
7743 // shims are shared among layer to keep from having 100 iframes
7746 Roo.extend(Roo.Layer, Roo.Element, {
7748 getZIndex : function(){
7749 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7752 getShim : function(){
7759 var shim = shims.shift();
7761 shim = this.createShim();
7762 shim.enableDisplayMode('block');
7763 shim.dom.style.display = 'none';
7764 shim.dom.style.visibility = 'visible';
7766 var pn = this.dom.parentNode;
7767 if(shim.dom.parentNode != pn){
7768 pn.insertBefore(shim.dom, this.dom);
7770 shim.setStyle('z-index', this.getZIndex()-2);
7775 hideShim : function(){
7777 this.shim.setDisplayed(false);
7778 shims.push(this.shim);
7783 disableShadow : function(){
7785 this.shadowDisabled = true;
7787 this.lastShadowOffset = this.shadowOffset;
7788 this.shadowOffset = 0;
7792 enableShadow : function(show){
7794 this.shadowDisabled = false;
7795 this.shadowOffset = this.lastShadowOffset;
7796 delete this.lastShadowOffset;
7804 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7805 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7806 sync : function(doShow){
7807 var sw = this.shadow;
7808 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7809 var sh = this.getShim();
7811 var w = this.getWidth(),
7812 h = this.getHeight();
7814 var l = this.getLeft(true),
7815 t = this.getTop(true);
7817 if(sw && !this.shadowDisabled){
7818 if(doShow && !sw.isVisible()){
7821 sw.realign(l, t, w, h);
7827 // fit the shim behind the shadow, so it is shimmed too
7828 var a = sw.adjusts, s = sh.dom.style;
7829 s.left = (Math.min(l, l+a.l))+"px";
7830 s.top = (Math.min(t, t+a.t))+"px";
7831 s.width = (w+a.w)+"px";
7832 s.height = (h+a.h)+"px";
7839 sh.setLeftTop(l, t);
7846 destroy : function(){
7851 this.removeAllListeners();
7852 var pn = this.dom.parentNode;
7854 pn.removeChild(this.dom);
7856 Roo.Element.uncache(this.id);
7859 remove : function(){
7864 beginUpdate : function(){
7865 this.updating = true;
7869 endUpdate : function(){
7870 this.updating = false;
7875 hideUnders : function(negOffset){
7883 constrainXY : function(){
7885 var vw = Roo.lib.Dom.getViewWidth(),
7886 vh = Roo.lib.Dom.getViewHeight();
7887 var s = Roo.get(document).getScroll();
7889 var xy = this.getXY();
7890 var x = xy[0], y = xy[1];
7891 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7892 // only move it if it needs it
7894 // first validate right/bottom
7895 if((x + w) > vw+s.left){
7896 x = vw - w - this.shadowOffset;
7899 if((y + h) > vh+s.top){
7900 y = vh - h - this.shadowOffset;
7903 // then make sure top/left isn't negative
7914 var ay = this.avoidY;
7915 if(y <= ay && (y+h) >= ay){
7921 supr.setXY.call(this, xy);
7927 isVisible : function(){
7928 return this.visible;
7932 showAction : function(){
7933 this.visible = true; // track visibility to prevent getStyle calls
7934 if(this.useDisplay === true){
7935 this.setDisplayed("");
7936 }else if(this.lastXY){
7937 supr.setXY.call(this, this.lastXY);
7938 }else if(this.lastLT){
7939 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7944 hideAction : function(){
7945 this.visible = false;
7946 if(this.useDisplay === true){
7947 this.setDisplayed(false);
7949 this.setLeftTop(-10000,-10000);
7953 // overridden Element method
7954 setVisible : function(v, a, d, c, e){
7959 var cb = function(){
7964 }.createDelegate(this);
7965 supr.setVisible.call(this, true, true, d, cb, e);
7968 this.hideUnders(true);
7977 }.createDelegate(this);
7979 supr.setVisible.call(this, v, a, d, cb, e);
7988 storeXY : function(xy){
7993 storeLeftTop : function(left, top){
7995 this.lastLT = [left, top];
7999 beforeFx : function(){
8000 this.beforeAction();
8001 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8005 afterFx : function(){
8006 Roo.Layer.superclass.afterFx.apply(this, arguments);
8007 this.sync(this.isVisible());
8011 beforeAction : function(){
8012 if(!this.updating && this.shadow){
8017 // overridden Element method
8018 setLeft : function(left){
8019 this.storeLeftTop(left, this.getTop(true));
8020 supr.setLeft.apply(this, arguments);
8024 setTop : function(top){
8025 this.storeLeftTop(this.getLeft(true), top);
8026 supr.setTop.apply(this, arguments);
8030 setLeftTop : function(left, top){
8031 this.storeLeftTop(left, top);
8032 supr.setLeftTop.apply(this, arguments);
8036 setXY : function(xy, a, d, c, e){
8038 this.beforeAction();
8040 var cb = this.createCB(c);
8041 supr.setXY.call(this, xy, a, d, cb, e);
8048 createCB : function(c){
8059 // overridden Element method
8060 setX : function(x, a, d, c, e){
8061 this.setXY([x, this.getY()], a, d, c, e);
8064 // overridden Element method
8065 setY : function(y, a, d, c, e){
8066 this.setXY([this.getX(), y], a, d, c, e);
8069 // overridden Element method
8070 setSize : function(w, h, a, d, c, e){
8071 this.beforeAction();
8072 var cb = this.createCB(c);
8073 supr.setSize.call(this, w, h, a, d, cb, e);
8079 // overridden Element method
8080 setWidth : function(w, a, d, c, e){
8081 this.beforeAction();
8082 var cb = this.createCB(c);
8083 supr.setWidth.call(this, w, a, d, cb, e);
8089 // overridden Element method
8090 setHeight : function(h, a, d, c, e){
8091 this.beforeAction();
8092 var cb = this.createCB(c);
8093 supr.setHeight.call(this, h, a, d, cb, e);
8099 // overridden Element method
8100 setBounds : function(x, y, w, h, a, d, c, e){
8101 this.beforeAction();
8102 var cb = this.createCB(c);
8104 this.storeXY([x, y]);
8105 supr.setXY.call(this, [x, y]);
8106 supr.setSize.call(this, w, h, a, d, cb, e);
8109 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8115 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8116 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8117 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8118 * @param {Number} zindex The new z-index to set
8119 * @return {this} The Layer
8121 setZIndex : function(zindex){
8122 this.zindex = zindex;
8123 this.setStyle("z-index", zindex + 2);
8125 this.shadow.setZIndex(zindex + 1);
8128 this.shim.setStyle("z-index", zindex);
8134 * Ext JS Library 1.1.1
8135 * Copyright(c) 2006-2007, Ext JS, LLC.
8137 * Originally Released Under LGPL - original licence link has changed is not relivant.
8140 * <script type="text/javascript">
8146 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8147 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8148 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8150 * Create a new Shadow
8151 * @param {Object} config The config object
8153 Roo.Shadow = function(config){
8154 Roo.apply(this, config);
8155 if(typeof this.mode != "string"){
8156 this.mode = this.defaultMode;
8158 var o = this.offset, a = {h: 0};
8159 var rad = Math.floor(this.offset/2);
8160 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8166 a.l -= this.offset + rad;
8167 a.t -= this.offset + rad;
8178 a.l -= (this.offset - rad);
8179 a.t -= this.offset + rad;
8181 a.w -= (this.offset - rad)*2;
8192 a.l -= (this.offset - rad);
8193 a.t -= (this.offset - rad);
8195 a.w -= (this.offset + rad + 1);
8196 a.h -= (this.offset + rad);
8205 Roo.Shadow.prototype = {
8207 * @cfg {String} mode
8208 * The shadow display mode. Supports the following options:<br />
8209 * sides: Shadow displays on both sides and bottom only<br />
8210 * frame: Shadow displays equally on all four sides<br />
8211 * drop: Traditional bottom-right drop shadow (default)
8214 * @cfg {String} offset
8215 * The number of pixels to offset the shadow from the element (defaults to 4)
8220 defaultMode: "drop",
8223 * Displays the shadow under the target element
8224 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8226 show : function(target){
8227 target = Roo.get(target);
8229 this.el = Roo.Shadow.Pool.pull();
8230 if(this.el.dom.nextSibling != target.dom){
8231 this.el.insertBefore(target);
8234 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8236 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8239 target.getLeft(true),
8240 target.getTop(true),
8244 this.el.dom.style.display = "block";
8248 * Returns true if the shadow is visible, else false
8250 isVisible : function(){
8251 return this.el ? true : false;
8255 * Direct alignment when values are already available. Show must be called at least once before
8256 * calling this method to ensure it is initialized.
8257 * @param {Number} left The target element left position
8258 * @param {Number} top The target element top position
8259 * @param {Number} width The target element width
8260 * @param {Number} height The target element height
8262 realign : function(l, t, w, h){
8266 var a = this.adjusts, d = this.el.dom, s = d.style;
8268 s.left = (l+a.l)+"px";
8269 s.top = (t+a.t)+"px";
8270 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8272 if(s.width != sws || s.height != shs){
8276 var cn = d.childNodes;
8277 var sww = Math.max(0, (sw-12))+"px";
8278 cn[0].childNodes[1].style.width = sww;
8279 cn[1].childNodes[1].style.width = sww;
8280 cn[2].childNodes[1].style.width = sww;
8281 cn[1].style.height = Math.max(0, (sh-12))+"px";
8291 this.el.dom.style.display = "none";
8292 Roo.Shadow.Pool.push(this.el);
8298 * Adjust the z-index of this shadow
8299 * @param {Number} zindex The new z-index
8301 setZIndex : function(z){
8304 this.el.setStyle("z-index", z);
8309 // Private utility class that manages the internal Shadow cache
8310 Roo.Shadow.Pool = function(){
8312 var markup = Roo.isIE ?
8313 '<div class="x-ie-shadow"></div>' :
8314 '<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>';
8319 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8320 sh.autoBoxAdjust = false;
8325 push : function(sh){
8331 * Ext JS Library 1.1.1
8332 * Copyright(c) 2006-2007, Ext JS, LLC.
8334 * Originally Released Under LGPL - original licence link has changed is not relivant.
8337 * <script type="text/javascript">
8341 * @class Roo.BoxComponent
8342 * @extends Roo.Component
8343 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8344 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8345 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8346 * layout containers.
8348 * @param {Roo.Element/String/Object} config The configuration options.
8350 Roo.BoxComponent = function(config){
8351 Roo.Component.call(this, config);
8355 * Fires after the component is resized.
8356 * @param {Roo.Component} this
8357 * @param {Number} adjWidth The box-adjusted width that was set
8358 * @param {Number} adjHeight The box-adjusted height that was set
8359 * @param {Number} rawWidth The width that was originally specified
8360 * @param {Number} rawHeight The height that was originally specified
8365 * Fires after the component is moved.
8366 * @param {Roo.Component} this
8367 * @param {Number} x The new x position
8368 * @param {Number} y The new y position
8374 Roo.extend(Roo.BoxComponent, Roo.Component, {
8375 // private, set in afterRender to signify that the component has been rendered
8377 // private, used to defer height settings to subclasses
8379 /** @cfg {Number} width
8380 * width (optional) size of component
8382 /** @cfg {Number} height
8383 * height (optional) size of component
8387 * Sets the width and height of the component. This method fires the resize event. This method can accept
8388 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8389 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8390 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8391 * @return {Roo.BoxComponent} this
8393 setSize : function(w, h){
8394 // support for standard size objects
8395 if(typeof w == 'object'){
8406 // prevent recalcs when not needed
8407 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8410 this.lastSize = {width: w, height: h};
8412 var adj = this.adjustSize(w, h);
8413 var aw = adj.width, ah = adj.height;
8414 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8415 var rz = this.getResizeEl();
8416 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8418 }else if(!this.deferHeight && ah !== undefined){
8420 }else if(aw !== undefined){
8423 this.onResize(aw, ah, w, h);
8424 this.fireEvent('resize', this, aw, ah, w, h);
8430 * Gets the current size of the component's underlying element.
8431 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8433 getSize : function(){
8434 return this.el.getSize();
8438 * Gets the current XY position 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 * @return {Array} The XY position of the element (e.g., [100, 200])
8442 getPosition : function(local){
8444 return [this.el.getLeft(true), this.el.getTop(true)];
8446 return this.xy || this.el.getXY();
8450 * Gets the current box measurements of the component's underlying element.
8451 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8452 * @returns {Object} box An object in the format {x, y, width, height}
8454 getBox : function(local){
8455 var s = this.el.getSize();
8457 s.x = this.el.getLeft(true);
8458 s.y = this.el.getTop(true);
8460 var xy = this.xy || this.el.getXY();
8468 * Sets the current box measurements of the component's underlying element.
8469 * @param {Object} box An object in the format {x, y, width, height}
8470 * @returns {Roo.BoxComponent} this
8472 updateBox : function(box){
8473 this.setSize(box.width, box.height);
8474 this.setPagePosition(box.x, box.y);
8479 getResizeEl : function(){
8480 return this.resizeEl || this.el;
8484 getPositionEl : function(){
8485 return this.positionEl || this.el;
8489 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8490 * This method fires the move event.
8491 * @param {Number} left The new left
8492 * @param {Number} top The new top
8493 * @returns {Roo.BoxComponent} this
8495 setPosition : function(x, y){
8501 var adj = this.adjustPosition(x, y);
8502 var ax = adj.x, ay = adj.y;
8504 var el = this.getPositionEl();
8505 if(ax !== undefined || ay !== undefined){
8506 if(ax !== undefined && ay !== undefined){
8507 el.setLeftTop(ax, ay);
8508 }else if(ax !== undefined){
8510 }else if(ay !== undefined){
8513 this.onPosition(ax, ay);
8514 this.fireEvent('move', this, ax, ay);
8520 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8521 * This method fires the move event.
8522 * @param {Number} x The new x position
8523 * @param {Number} y The new y position
8524 * @returns {Roo.BoxComponent} this
8526 setPagePosition : function(x, y){
8532 if(x === undefined || y === undefined){ // cannot translate undefined points
8535 var p = this.el.translatePoints(x, y);
8536 this.setPosition(p.left, p.top);
8541 onRender : function(ct, position){
8542 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8544 this.resizeEl = Roo.get(this.resizeEl);
8546 if(this.positionEl){
8547 this.positionEl = Roo.get(this.positionEl);
8552 afterRender : function(){
8553 Roo.BoxComponent.superclass.afterRender.call(this);
8554 this.boxReady = true;
8555 this.setSize(this.width, this.height);
8556 if(this.x || this.y){
8557 this.setPosition(this.x, this.y);
8559 if(this.pageX || this.pageY){
8560 this.setPagePosition(this.pageX, this.pageY);
8565 * Force the component's size to recalculate based on the underlying element's current height and width.
8566 * @returns {Roo.BoxComponent} this
8568 syncSize : function(){
8569 delete this.lastSize;
8570 this.setSize(this.el.getWidth(), this.el.getHeight());
8575 * Called after the component is resized, this method is empty by default but can be implemented by any
8576 * subclass that needs to perform custom logic after a resize occurs.
8577 * @param {Number} adjWidth The box-adjusted width that was set
8578 * @param {Number} adjHeight The box-adjusted height that was set
8579 * @param {Number} rawWidth The width that was originally specified
8580 * @param {Number} rawHeight The height that was originally specified
8582 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8587 * Called after the component is moved, this method is empty by default but can be implemented by any
8588 * subclass that needs to perform custom logic after a move occurs.
8589 * @param {Number} x The new x position
8590 * @param {Number} y The new y position
8592 onPosition : function(x, y){
8597 adjustSize : function(w, h){
8601 if(this.autoHeight){
8604 return {width : w, height: h};
8608 adjustPosition : function(x, y){
8609 return {x : x, y: y};
8613 * Ext JS Library 1.1.1
8614 * Copyright(c) 2006-2007, Ext JS, LLC.
8616 * Originally Released Under LGPL - original licence link has changed is not relivant.
8619 * <script type="text/javascript">
8624 * @class Roo.SplitBar
8625 * @extends Roo.util.Observable
8626 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8630 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8631 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8632 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8633 split.minSize = 100;
8634 split.maxSize = 600;
8635 split.animate = true;
8636 split.on('moved', splitterMoved);
8639 * Create a new SplitBar
8640 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8641 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8642 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8643 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8644 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8645 position of the SplitBar).
8647 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8650 this.el = Roo.get(dragElement, true);
8651 this.el.dom.unselectable = "on";
8653 this.resizingEl = Roo.get(resizingElement, true);
8657 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8658 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8661 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8664 * The minimum size of the resizing element. (Defaults to 0)
8670 * The maximum size of the resizing element. (Defaults to 2000)
8673 this.maxSize = 2000;
8676 * Whether to animate the transition to the new size
8679 this.animate = false;
8682 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8685 this.useShim = false;
8692 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8694 this.proxy = Roo.get(existingProxy).dom;
8697 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8700 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8703 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8706 this.dragSpecs = {};
8709 * @private The adapter to use to positon and resize elements
8711 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8712 this.adapter.init(this);
8714 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8716 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8717 this.el.addClass("x-splitbar-h");
8720 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8721 this.el.addClass("x-splitbar-v");
8727 * Fires when the splitter is moved (alias for {@link #event-moved})
8728 * @param {Roo.SplitBar} this
8729 * @param {Number} newSize the new width or height
8734 * Fires when the splitter is moved
8735 * @param {Roo.SplitBar} this
8736 * @param {Number} newSize the new width or height
8740 * @event beforeresize
8741 * Fires before the splitter is dragged
8742 * @param {Roo.SplitBar} this
8744 "beforeresize" : true,
8746 "beforeapply" : true
8749 Roo.util.Observable.call(this);
8752 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8753 onStartProxyDrag : function(x, y){
8754 this.fireEvent("beforeresize", this);
8756 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8758 o.enableDisplayMode("block");
8759 // all splitbars share the same overlay
8760 Roo.SplitBar.prototype.overlay = o;
8762 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8763 this.overlay.show();
8764 Roo.get(this.proxy).setDisplayed("block");
8765 var size = this.adapter.getElementSize(this);
8766 this.activeMinSize = this.getMinimumSize();;
8767 this.activeMaxSize = this.getMaximumSize();;
8768 var c1 = size - this.activeMinSize;
8769 var c2 = Math.max(this.activeMaxSize - size, 0);
8770 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8771 this.dd.resetConstraints();
8772 this.dd.setXConstraint(
8773 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8774 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8776 this.dd.setYConstraint(0, 0);
8778 this.dd.resetConstraints();
8779 this.dd.setXConstraint(0, 0);
8780 this.dd.setYConstraint(
8781 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8782 this.placement == Roo.SplitBar.TOP ? c2 : c1
8785 this.dragSpecs.startSize = size;
8786 this.dragSpecs.startPoint = [x, y];
8787 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8791 * @private Called after the drag operation by the DDProxy
8793 onEndProxyDrag : function(e){
8794 Roo.get(this.proxy).setDisplayed(false);
8795 var endPoint = Roo.lib.Event.getXY(e);
8797 this.overlay.hide();
8800 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8801 newSize = this.dragSpecs.startSize +
8802 (this.placement == Roo.SplitBar.LEFT ?
8803 endPoint[0] - this.dragSpecs.startPoint[0] :
8804 this.dragSpecs.startPoint[0] - endPoint[0]
8807 newSize = this.dragSpecs.startSize +
8808 (this.placement == Roo.SplitBar.TOP ?
8809 endPoint[1] - this.dragSpecs.startPoint[1] :
8810 this.dragSpecs.startPoint[1] - endPoint[1]
8813 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8814 if(newSize != this.dragSpecs.startSize){
8815 if(this.fireEvent('beforeapply', this, newSize) !== false){
8816 this.adapter.setElementSize(this, newSize);
8817 this.fireEvent("moved", this, newSize);
8818 this.fireEvent("resize", this, newSize);
8824 * Get the adapter this SplitBar uses
8825 * @return The adapter object
8827 getAdapter : function(){
8828 return this.adapter;
8832 * Set the adapter this SplitBar uses
8833 * @param {Object} adapter A SplitBar adapter object
8835 setAdapter : function(adapter){
8836 this.adapter = adapter;
8837 this.adapter.init(this);
8841 * Gets the minimum size for the resizing element
8842 * @return {Number} The minimum size
8844 getMinimumSize : function(){
8845 return this.minSize;
8849 * Sets the minimum size for the resizing element
8850 * @param {Number} minSize The minimum size
8852 setMinimumSize : function(minSize){
8853 this.minSize = minSize;
8857 * Gets the maximum size for the resizing element
8858 * @return {Number} The maximum size
8860 getMaximumSize : function(){
8861 return this.maxSize;
8865 * Sets the maximum size for the resizing element
8866 * @param {Number} maxSize The maximum size
8868 setMaximumSize : function(maxSize){
8869 this.maxSize = maxSize;
8873 * Sets the initialize size for the resizing element
8874 * @param {Number} size The initial size
8876 setCurrentSize : function(size){
8877 var oldAnimate = this.animate;
8878 this.animate = false;
8879 this.adapter.setElementSize(this, size);
8880 this.animate = oldAnimate;
8884 * Destroy this splitbar.
8885 * @param {Boolean} removeEl True to remove the element
8887 destroy : function(removeEl){
8892 this.proxy.parentNode.removeChild(this.proxy);
8900 * @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.
8902 Roo.SplitBar.createProxy = function(dir){
8903 var proxy = new Roo.Element(document.createElement("div"));
8904 proxy.unselectable();
8905 var cls = 'x-splitbar-proxy';
8906 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8907 document.body.appendChild(proxy.dom);
8912 * @class Roo.SplitBar.BasicLayoutAdapter
8913 * Default Adapter. It assumes the splitter and resizing element are not positioned
8914 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8916 Roo.SplitBar.BasicLayoutAdapter = function(){
8919 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8920 // do nothing for now
8925 * Called before drag operations to get the current size of the resizing element.
8926 * @param {Roo.SplitBar} s The SplitBar using this adapter
8928 getElementSize : function(s){
8929 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8930 return s.resizingEl.getWidth();
8932 return s.resizingEl.getHeight();
8937 * Called after drag operations to set the size of the resizing element.
8938 * @param {Roo.SplitBar} s The SplitBar using this adapter
8939 * @param {Number} newSize The new size to set
8940 * @param {Function} onComplete A function to be invoked when resizing is complete
8942 setElementSize : function(s, newSize, onComplete){
8943 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8945 s.resizingEl.setWidth(newSize);
8947 onComplete(s, newSize);
8950 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8955 s.resizingEl.setHeight(newSize);
8957 onComplete(s, newSize);
8960 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8967 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8968 * @extends Roo.SplitBar.BasicLayoutAdapter
8969 * Adapter that moves the splitter element to align with the resized sizing element.
8970 * Used with an absolute positioned SplitBar.
8971 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8972 * document.body, make sure you assign an id to the body element.
8974 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8975 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8976 this.container = Roo.get(container);
8979 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8984 getElementSize : function(s){
8985 return this.basic.getElementSize(s);
8988 setElementSize : function(s, newSize, onComplete){
8989 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8992 moveSplitter : function(s){
8993 var yes = Roo.SplitBar;
8994 switch(s.placement){
8996 s.el.setX(s.resizingEl.getRight());
8999 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9002 s.el.setY(s.resizingEl.getBottom());
9005 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9012 * Orientation constant - Create a vertical SplitBar
9016 Roo.SplitBar.VERTICAL = 1;
9019 * Orientation constant - Create a horizontal SplitBar
9023 Roo.SplitBar.HORIZONTAL = 2;
9026 * Placement constant - The resizing element is to the left of the splitter element
9030 Roo.SplitBar.LEFT = 1;
9033 * Placement constant - The resizing element is to the right of the splitter element
9037 Roo.SplitBar.RIGHT = 2;
9040 * Placement constant - The resizing element is positioned above the splitter element
9044 Roo.SplitBar.TOP = 3;
9047 * Placement constant - The resizing element is positioned under splitter element
9051 Roo.SplitBar.BOTTOM = 4;
9054 * Ext JS Library 1.1.1
9055 * Copyright(c) 2006-2007, Ext JS, LLC.
9057 * Originally Released Under LGPL - original licence link has changed is not relivant.
9060 * <script type="text/javascript">
9065 * @extends Roo.util.Observable
9066 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9067 * This class also supports single and multi selection modes. <br>
9068 * Create a data model bound view:
9070 var store = new Roo.data.Store(...);
9072 var view = new Roo.View({
9074 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9077 selectedClass: "ydataview-selected",
9081 // listen for node click?
9082 view.on("click", function(vw, index, node, e){
9083 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9087 dataModel.load("foobar.xml");
9089 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9091 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9092 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9094 * Note: old style constructor is still suported (container, template, config)
9098 * @param {Object} config The config object
9101 Roo.View = function(config, depreciated_tpl, depreciated_config){
9103 if (typeof(depreciated_tpl) == 'undefined') {
9104 // new way.. - universal constructor.
9105 Roo.apply(this, config);
9106 this.el = Roo.get(this.el);
9109 this.el = Roo.get(config);
9110 this.tpl = depreciated_tpl;
9111 Roo.apply(this, depreciated_config);
9115 if(typeof(this.tpl) == "string"){
9116 this.tpl = new Roo.Template(this.tpl);
9118 // support xtype ctors..
9119 this.tpl = new Roo.factory(this.tpl, Roo);
9130 * @event beforeclick
9131 * Fires before a click is processed. Returns false to cancel the default action.
9132 * @param {Roo.View} this
9133 * @param {Number} index The index of the target node
9134 * @param {HTMLElement} node The target node
9135 * @param {Roo.EventObject} e The raw event object
9137 "beforeclick" : true,
9140 * Fires when a template node is clicked.
9141 * @param {Roo.View} this
9142 * @param {Number} index The index of the target node
9143 * @param {HTMLElement} node The target node
9144 * @param {Roo.EventObject} e The raw event object
9149 * Fires when a template node is double clicked.
9150 * @param {Roo.View} this
9151 * @param {Number} index The index of the target node
9152 * @param {HTMLElement} node The target node
9153 * @param {Roo.EventObject} e The raw event object
9157 * @event contextmenu
9158 * Fires when a template node is right clicked.
9159 * @param {Roo.View} this
9160 * @param {Number} index The index of the target node
9161 * @param {HTMLElement} node The target node
9162 * @param {Roo.EventObject} e The raw event object
9164 "contextmenu" : true,
9166 * @event selectionchange
9167 * Fires when the selected nodes change.
9168 * @param {Roo.View} this
9169 * @param {Array} selections Array of the selected nodes
9171 "selectionchange" : true,
9174 * @event beforeselect
9175 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9176 * @param {Roo.View} this
9177 * @param {HTMLElement} node The node to be selected
9178 * @param {Array} selections Array of currently selected nodes
9180 "beforeselect" : true
9184 "click": this.onClick,
9185 "dblclick": this.onDblClick,
9186 "contextmenu": this.onContextMenu,
9190 this.selections = [];
9192 this.cmp = new Roo.CompositeElementLite([]);
9194 this.store = Roo.factory(this.store, Roo.data);
9195 this.setStore(this.store, true);
9197 Roo.View.superclass.constructor.call(this);
9200 Roo.extend(Roo.View, Roo.util.Observable, {
9203 * @cfg {Roo.data.Store} store Data store to load data from.
9208 * @cfg {String|Roo.Element} el The container element.
9213 * @cfg {String|Roo.Template} tpl The template used by this View
9218 * @cfg {String} selectedClass The css class to add to selected nodes
9220 selectedClass : "x-view-selected",
9222 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9226 * @cfg {Boolean} multiSelect Allow multiple selection
9229 multiSelect : false,
9231 * @cfg {Boolean} singleSelect Allow single selection
9233 singleSelect: false,
9236 * Returns the element this view is bound to.
9237 * @return {Roo.Element}
9244 * Refreshes the view.
9246 refresh : function(){
9248 this.clearSelections();
9251 var records = this.store.getRange();
9252 if(records.length < 1){
9253 this.el.update(this.emptyText);
9256 for(var i = 0, len = records.length; i < len; i++){
9257 var data = this.prepareData(records[i].data, i, records[i]);
9258 html[html.length] = t.apply(data);
9260 this.el.update(html.join(""));
9261 this.nodes = this.el.dom.childNodes;
9262 this.updateIndexes(0);
9266 * Function to override to reformat the data that is sent to
9267 * the template for each node.
9268 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9269 * a JSON object for an UpdateManager bound view).
9271 prepareData : function(data){
9275 onUpdate : function(ds, record){
9276 this.clearSelections();
9277 var index = this.store.indexOf(record);
9278 var n = this.nodes[index];
9279 this.tpl.insertBefore(n, this.prepareData(record.data));
9280 n.parentNode.removeChild(n);
9281 this.updateIndexes(index, index);
9284 onAdd : function(ds, records, index){
9285 this.clearSelections();
9286 if(this.nodes.length == 0){
9290 var n = this.nodes[index];
9291 for(var i = 0, len = records.length; i < len; i++){
9292 var d = this.prepareData(records[i].data);
9294 this.tpl.insertBefore(n, d);
9296 this.tpl.append(this.el, d);
9299 this.updateIndexes(index);
9302 onRemove : function(ds, record, index){
9303 this.clearSelections();
9304 this.el.dom.removeChild(this.nodes[index]);
9305 this.updateIndexes(index);
9309 * Refresh an individual node.
9310 * @param {Number} index
9312 refreshNode : function(index){
9313 this.onUpdate(this.store, this.store.getAt(index));
9316 updateIndexes : function(startIndex, endIndex){
9317 var ns = this.nodes;
9318 startIndex = startIndex || 0;
9319 endIndex = endIndex || ns.length - 1;
9320 for(var i = startIndex; i <= endIndex; i++){
9321 ns[i].nodeIndex = i;
9326 * Changes the data store this view uses and refresh the view.
9327 * @param {Store} store
9329 setStore : function(store, initial){
9330 if(!initial && this.store){
9331 this.store.un("datachanged", this.refresh);
9332 this.store.un("add", this.onAdd);
9333 this.store.un("remove", this.onRemove);
9334 this.store.un("update", this.onUpdate);
9335 this.store.un("clear", this.refresh);
9339 store.on("datachanged", this.refresh, this);
9340 store.on("add", this.onAdd, this);
9341 store.on("remove", this.onRemove, this);
9342 store.on("update", this.onUpdate, this);
9343 store.on("clear", this.refresh, this);
9352 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9353 * @param {HTMLElement} node
9354 * @return {HTMLElement} The template node
9356 findItemFromChild : function(node){
9357 var el = this.el.dom;
9358 if(!node || node.parentNode == el){
9361 var p = node.parentNode;
9362 while(p && p != el){
9363 if(p.parentNode == el){
9372 onClick : function(e){
9373 var item = this.findItemFromChild(e.getTarget());
9375 var index = this.indexOf(item);
9376 if(this.onItemClick(item, index, e) !== false){
9377 this.fireEvent("click", this, index, item, e);
9380 this.clearSelections();
9385 onContextMenu : function(e){
9386 var item = this.findItemFromChild(e.getTarget());
9388 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9393 onDblClick : function(e){
9394 var item = this.findItemFromChild(e.getTarget());
9396 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9400 onItemClick : function(item, index, e){
9401 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9404 if(this.multiSelect || this.singleSelect){
9405 if(this.multiSelect && e.shiftKey && this.lastSelection){
9406 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9408 this.select(item, this.multiSelect && e.ctrlKey);
9409 this.lastSelection = item;
9417 * Get the number of selected nodes.
9420 getSelectionCount : function(){
9421 return this.selections.length;
9425 * Get the currently selected nodes.
9426 * @return {Array} An array of HTMLElements
9428 getSelectedNodes : function(){
9429 return this.selections;
9433 * Get the indexes of the selected nodes.
9436 getSelectedIndexes : function(){
9437 var indexes = [], s = this.selections;
9438 for(var i = 0, len = s.length; i < len; i++){
9439 indexes.push(s[i].nodeIndex);
9445 * Clear all selections
9446 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9448 clearSelections : function(suppressEvent){
9449 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9450 this.cmp.elements = this.selections;
9451 this.cmp.removeClass(this.selectedClass);
9452 this.selections = [];
9454 this.fireEvent("selectionchange", this, this.selections);
9460 * Returns true if the passed node is selected
9461 * @param {HTMLElement/Number} node The node or node index
9464 isSelected : function(node){
9465 var s = this.selections;
9469 node = this.getNode(node);
9470 return s.indexOf(node) !== -1;
9475 * @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
9476 * @param {Boolean} keepExisting (optional) true to keep existing selections
9477 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9479 select : function(nodeInfo, keepExisting, suppressEvent){
9480 if(nodeInfo instanceof Array){
9482 this.clearSelections(true);
9484 for(var i = 0, len = nodeInfo.length; i < len; i++){
9485 this.select(nodeInfo[i], true, true);
9488 var node = this.getNode(nodeInfo);
9489 if(node && !this.isSelected(node)){
9491 this.clearSelections(true);
9493 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9494 Roo.fly(node).addClass(this.selectedClass);
9495 this.selections.push(node);
9497 this.fireEvent("selectionchange", this, this.selections);
9505 * Gets a template node.
9506 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9507 * @return {HTMLElement} The node or null if it wasn't found
9509 getNode : function(nodeInfo){
9510 if(typeof nodeInfo == "string"){
9511 return document.getElementById(nodeInfo);
9512 }else if(typeof nodeInfo == "number"){
9513 return this.nodes[nodeInfo];
9519 * Gets a range template nodes.
9520 * @param {Number} startIndex
9521 * @param {Number} endIndex
9522 * @return {Array} An array of nodes
9524 getNodes : function(start, end){
9525 var ns = this.nodes;
9527 end = typeof end == "undefined" ? ns.length - 1 : end;
9530 for(var i = start; i <= end; i++){
9534 for(var i = start; i >= end; i--){
9542 * Finds the index of the passed node
9543 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9544 * @return {Number} The index of the node or -1
9546 indexOf : function(node){
9547 node = this.getNode(node);
9548 if(typeof node.nodeIndex == "number"){
9549 return node.nodeIndex;
9551 var ns = this.nodes;
9552 for(var i = 0, len = ns.length; i < len; i++){
9562 * Ext JS Library 1.1.1
9563 * Copyright(c) 2006-2007, Ext JS, LLC.
9565 * Originally Released Under LGPL - original licence link has changed is not relivant.
9568 * <script type="text/javascript">
9572 * @class Roo.JsonView
9574 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9576 var view = new Roo.JsonView({
9577 container: "my-element",
9578 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9583 // listen for node click?
9584 view.on("click", function(vw, index, node, e){
9585 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9588 // direct load of JSON data
9589 view.load("foobar.php");
9591 // Example from my blog list
9592 var tpl = new Roo.Template(
9593 '<div class="entry">' +
9594 '<a class="entry-title" href="{link}">{title}</a>' +
9595 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9596 "</div><hr />"
9599 var moreView = new Roo.JsonView({
9600 container : "entry-list",
9604 moreView.on("beforerender", this.sortEntries, this);
9606 url: "/blog/get-posts.php",
9607 params: "allposts=true",
9608 text: "Loading Blog Entries..."
9612 * Note: old code is supported with arguments : (container, template, config)
9616 * Create a new JsonView
9618 * @param {Object} config The config object
9621 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9624 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9626 var um = this.el.getUpdateManager();
9627 um.setRenderer(this);
9628 um.on("update", this.onLoad, this);
9629 um.on("failure", this.onLoadException, this);
9632 * @event beforerender
9633 * Fires before rendering of the downloaded JSON data.
9634 * @param {Roo.JsonView} this
9635 * @param {Object} data The JSON data loaded
9639 * Fires when data is loaded.
9640 * @param {Roo.JsonView} this
9641 * @param {Object} data The JSON data loaded
9642 * @param {Object} response The raw Connect response object
9645 * @event loadexception
9646 * Fires when loading fails.
9647 * @param {Roo.JsonView} this
9648 * @param {Object} response The raw Connect response object
9651 'beforerender' : true,
9653 'loadexception' : true
9656 Roo.extend(Roo.JsonView, Roo.View, {
9658 * @type {String} The root property in the loaded JSON object that contains the data
9663 * Refreshes the view.
9665 refresh : function(){
9666 this.clearSelections();
9669 var o = this.jsonData;
9670 if(o && o.length > 0){
9671 for(var i = 0, len = o.length; i < len; i++){
9672 var data = this.prepareData(o[i], i, o);
9673 html[html.length] = this.tpl.apply(data);
9676 html.push(this.emptyText);
9678 this.el.update(html.join(""));
9679 this.nodes = this.el.dom.childNodes;
9680 this.updateIndexes(0);
9684 * 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.
9685 * @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:
9688 url: "your-url.php",
9689 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9690 callback: yourFunction,
9691 scope: yourObject, //(optional scope)
9699 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9700 * 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.
9701 * @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}
9702 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9703 * @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.
9706 var um = this.el.getUpdateManager();
9707 um.update.apply(um, arguments);
9710 render : function(el, response){
9711 this.clearSelections();
9715 o = Roo.util.JSON.decode(response.responseText);
9718 o = o[this.jsonRoot];
9723 * The current JSON data or null
9726 this.beforeRender();
9731 * Get the number of records in the current JSON dataset
9734 getCount : function(){
9735 return this.jsonData ? this.jsonData.length : 0;
9739 * Returns the JSON object for the specified node(s)
9740 * @param {HTMLElement/Array} node The node or an array of nodes
9741 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9742 * you get the JSON object for the node
9744 getNodeData : function(node){
9745 if(node instanceof Array){
9747 for(var i = 0, len = node.length; i < len; i++){
9748 data.push(this.getNodeData(node[i]));
9752 return this.jsonData[this.indexOf(node)] || null;
9755 beforeRender : function(){
9756 this.snapshot = this.jsonData;
9758 this.sort.apply(this, this.sortInfo);
9760 this.fireEvent("beforerender", this, this.jsonData);
9763 onLoad : function(el, o){
9764 this.fireEvent("load", this, this.jsonData, o);
9767 onLoadException : function(el, o){
9768 this.fireEvent("loadexception", this, o);
9772 * Filter the data by a specific property.
9773 * @param {String} property A property on your JSON objects
9774 * @param {String/RegExp} value Either string that the property values
9775 * should start with, or a RegExp to test against the property
9777 filter : function(property, value){
9780 var ss = this.snapshot;
9781 if(typeof value == "string"){
9782 var vlen = value.length;
9787 value = value.toLowerCase();
9788 for(var i = 0, len = ss.length; i < len; i++){
9790 if(o[property].substr(0, vlen).toLowerCase() == value){
9794 } else if(value.exec){ // regex?
9795 for(var i = 0, len = ss.length; i < len; i++){
9797 if(value.test(o[property])){
9804 this.jsonData = data;
9810 * Filter by a function. The passed function will be called with each
9811 * object in the current dataset. If the function returns true the value is kept,
9812 * otherwise it is filtered.
9813 * @param {Function} fn
9814 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9816 filterBy : function(fn, scope){
9819 var ss = this.snapshot;
9820 for(var i = 0, len = ss.length; i < len; i++){
9822 if(fn.call(scope || this, o)){
9826 this.jsonData = data;
9832 * Clears the current filter.
9834 clearFilter : function(){
9835 if(this.snapshot && this.jsonData != this.snapshot){
9836 this.jsonData = this.snapshot;
9843 * Sorts the data for this view and refreshes it.
9844 * @param {String} property A property on your JSON objects to sort on
9845 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9846 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9848 sort : function(property, dir, sortType){
9849 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9852 var dsc = dir && dir.toLowerCase() == "desc";
9853 var f = function(o1, o2){
9854 var v1 = sortType ? sortType(o1[p]) : o1[p];
9855 var v2 = sortType ? sortType(o2[p]) : o2[p];
9858 return dsc ? +1 : -1;
9860 return dsc ? -1 : +1;
9865 this.jsonData.sort(f);
9867 if(this.jsonData != this.snapshot){
9868 this.snapshot.sort(f);
9874 * Ext JS Library 1.1.1
9875 * Copyright(c) 2006-2007, Ext JS, LLC.
9877 * Originally Released Under LGPL - original licence link has changed is not relivant.
9880 * <script type="text/javascript">
9885 * @class Roo.ColorPalette
9886 * @extends Roo.Component
9887 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9888 * Here's an example of typical usage:
9890 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9891 cp.render('my-div');
9893 cp.on('select', function(palette, selColor){
9894 // do something with selColor
9898 * Create a new ColorPalette
9899 * @param {Object} config The config object
9901 Roo.ColorPalette = function(config){
9902 Roo.ColorPalette.superclass.constructor.call(this, config);
9906 * Fires when a color is selected
9907 * @param {ColorPalette} this
9908 * @param {String} color The 6-digit color hex code (without the # symbol)
9914 this.on("select", this.handler, this.scope, true);
9917 Roo.extend(Roo.ColorPalette, Roo.Component, {
9919 * @cfg {String} itemCls
9920 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9922 itemCls : "x-color-palette",
9924 * @cfg {String} value
9925 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9926 * the hex codes are case-sensitive.
9931 ctype: "Roo.ColorPalette",
9934 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9936 allowReselect : false,
9939 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9940 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9941 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9942 * of colors with the width setting until the box is symmetrical.</p>
9943 * <p>You can override individual colors if needed:</p>
9945 var cp = new Roo.ColorPalette();
9946 cp.colors[0] = "FF0000"; // change the first box to red
9949 Or you can provide a custom array of your own for complete control:
9951 var cp = new Roo.ColorPalette();
9952 cp.colors = ["000000", "993300", "333300"];
9957 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9958 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9959 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9960 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9961 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9965 onRender : function(container, position){
9966 var t = new Roo.MasterTemplate(
9967 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9969 var c = this.colors;
9970 for(var i = 0, len = c.length; i < len; i++){
9973 var el = document.createElement("div");
9974 el.className = this.itemCls;
9976 container.dom.insertBefore(el, position);
9977 this.el = Roo.get(el);
9978 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9979 if(this.clickEvent != 'click'){
9980 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9985 afterRender : function(){
9986 Roo.ColorPalette.superclass.afterRender.call(this);
9995 handleClick : function(e, t){
9998 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9999 this.select(c.toUpperCase());
10004 * Selects the specified color in the palette (fires the select event)
10005 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10007 select : function(color){
10008 color = color.replace("#", "");
10009 if(color != this.value || this.allowReselect){
10012 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10014 el.child("a.color-"+color).addClass("x-color-palette-sel");
10015 this.value = color;
10016 this.fireEvent("select", this, color);
10021 * Ext JS Library 1.1.1
10022 * Copyright(c) 2006-2007, Ext JS, LLC.
10024 * Originally Released Under LGPL - original licence link has changed is not relivant.
10027 * <script type="text/javascript">
10031 * @class Roo.DatePicker
10032 * @extends Roo.Component
10033 * Simple date picker class.
10035 * Create a new DatePicker
10036 * @param {Object} config The config object
10038 Roo.DatePicker = function(config){
10039 Roo.DatePicker.superclass.constructor.call(this, config);
10041 this.value = config && config.value ?
10042 config.value.clearTime() : new Date().clearTime();
10047 * Fires when a date is selected
10048 * @param {DatePicker} this
10049 * @param {Date} date The selected date
10055 this.on("select", this.handler, this.scope || this);
10057 // build the disabledDatesRE
10058 if(!this.disabledDatesRE && this.disabledDates){
10059 var dd = this.disabledDates;
10061 for(var i = 0; i < dd.length; i++){
10063 if(i != dd.length-1) re += "|";
10065 this.disabledDatesRE = new RegExp(re + ")");
10069 Roo.extend(Roo.DatePicker, Roo.Component, {
10071 * @cfg {String} todayText
10072 * The text to display on the button that selects the current date (defaults to "Today")
10074 todayText : "Today",
10076 * @cfg {String} okText
10077 * The text to display on the ok button
10079 okText : " OK ", //   to give the user extra clicking room
10081 * @cfg {String} cancelText
10082 * The text to display on the cancel button
10084 cancelText : "Cancel",
10086 * @cfg {String} todayTip
10087 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10089 todayTip : "{0} (Spacebar)",
10091 * @cfg {Date} minDate
10092 * Minimum allowable date (JavaScript date object, defaults to null)
10096 * @cfg {Date} maxDate
10097 * Maximum allowable date (JavaScript date object, defaults to null)
10101 * @cfg {String} minText
10102 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10104 minText : "This date is before the minimum date",
10106 * @cfg {String} maxText
10107 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10109 maxText : "This date is after the maximum date",
10111 * @cfg {String} format
10112 * The default date format string which can be overriden for localization support. The format must be
10113 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10117 * @cfg {Array} disabledDays
10118 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10120 disabledDays : null,
10122 * @cfg {String} disabledDaysText
10123 * The tooltip to display when the date falls on a disabled day (defaults to "")
10125 disabledDaysText : "",
10127 * @cfg {RegExp} disabledDatesRE
10128 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10130 disabledDatesRE : null,
10132 * @cfg {String} disabledDatesText
10133 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10135 disabledDatesText : "",
10137 * @cfg {Boolean} constrainToViewport
10138 * True to constrain the date picker to the viewport (defaults to true)
10140 constrainToViewport : true,
10142 * @cfg {Array} monthNames
10143 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10145 monthNames : Date.monthNames,
10147 * @cfg {Array} dayNames
10148 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10150 dayNames : Date.dayNames,
10152 * @cfg {String} nextText
10153 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10155 nextText: 'Next Month (Control+Right)',
10157 * @cfg {String} prevText
10158 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10160 prevText: 'Previous Month (Control+Left)',
10162 * @cfg {String} monthYearText
10163 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10165 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10167 * @cfg {Number} startDay
10168 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10172 * @cfg {Bool} showClear
10173 * Show a clear button (usefull for date form elements that can be blank.)
10179 * Sets the value of the date field
10180 * @param {Date} value The date to set
10182 setValue : function(value){
10183 var old = this.value;
10184 this.value = value.clearTime(true);
10186 this.update(this.value);
10191 * Gets the current selected value of the date field
10192 * @return {Date} The selected date
10194 getValue : function(){
10199 focus : function(){
10201 this.update(this.activeDate);
10206 onRender : function(container, position){
10208 '<table cellspacing="0">',
10209 '<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>',
10210 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10211 var dn = this.dayNames;
10212 for(var i = 0; i < 7; i++){
10213 var d = this.startDay+i;
10217 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10219 m[m.length] = "</tr></thead><tbody><tr>";
10220 for(var i = 0; i < 42; i++) {
10221 if(i % 7 == 0 && i != 0){
10222 m[m.length] = "</tr><tr>";
10224 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10226 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10227 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10229 var el = document.createElement("div");
10230 el.className = "x-date-picker";
10231 el.innerHTML = m.join("");
10233 container.dom.insertBefore(el, position);
10235 this.el = Roo.get(el);
10236 this.eventEl = Roo.get(el.firstChild);
10238 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10239 handler: this.showPrevMonth,
10241 preventDefault:true,
10245 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10246 handler: this.showNextMonth,
10248 preventDefault:true,
10252 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10254 this.monthPicker = this.el.down('div.x-date-mp');
10255 this.monthPicker.enableDisplayMode('block');
10257 var kn = new Roo.KeyNav(this.eventEl, {
10258 "left" : function(e){
10260 this.showPrevMonth() :
10261 this.update(this.activeDate.add("d", -1));
10264 "right" : function(e){
10266 this.showNextMonth() :
10267 this.update(this.activeDate.add("d", 1));
10270 "up" : function(e){
10272 this.showNextYear() :
10273 this.update(this.activeDate.add("d", -7));
10276 "down" : function(e){
10278 this.showPrevYear() :
10279 this.update(this.activeDate.add("d", 7));
10282 "pageUp" : function(e){
10283 this.showNextMonth();
10286 "pageDown" : function(e){
10287 this.showPrevMonth();
10290 "enter" : function(e){
10291 e.stopPropagation();
10298 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10300 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10302 this.el.unselectable();
10304 this.cells = this.el.select("table.x-date-inner tbody td");
10305 this.textNodes = this.el.query("table.x-date-inner tbody span");
10307 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10309 tooltip: this.monthYearText
10312 this.mbtn.on('click', this.showMonthPicker, this);
10313 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10316 var today = (new Date()).dateFormat(this.format);
10318 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10319 if (this.showClear) {
10320 baseTb.add( new Roo.Toolbar.Fill());
10323 text: String.format(this.todayText, today),
10324 tooltip: String.format(this.todayTip, today),
10325 handler: this.selectToday,
10329 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10332 if (this.showClear) {
10334 baseTb.add( new Roo.Toolbar.Fill());
10337 cls: 'x-btn-icon x-btn-clear',
10338 handler: function() {
10340 this.fireEvent("select", this, '');
10350 this.update(this.value);
10353 createMonthPicker : function(){
10354 if(!this.monthPicker.dom.firstChild){
10355 var buf = ['<table border="0" cellspacing="0">'];
10356 for(var i = 0; i < 6; i++){
10358 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10359 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10361 '<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>' :
10362 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10366 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10368 '</button><button type="button" class="x-date-mp-cancel">',
10370 '</button></td></tr>',
10373 this.monthPicker.update(buf.join(''));
10374 this.monthPicker.on('click', this.onMonthClick, this);
10375 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10377 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10378 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10380 this.mpMonths.each(function(m, a, i){
10383 m.dom.xmonth = 5 + Math.round(i * .5);
10385 m.dom.xmonth = Math.round((i-1) * .5);
10391 showMonthPicker : function(){
10392 this.createMonthPicker();
10393 var size = this.el.getSize();
10394 this.monthPicker.setSize(size);
10395 this.monthPicker.child('table').setSize(size);
10397 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10398 this.updateMPMonth(this.mpSelMonth);
10399 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10400 this.updateMPYear(this.mpSelYear);
10402 this.monthPicker.slideIn('t', {duration:.2});
10405 updateMPYear : function(y){
10407 var ys = this.mpYears.elements;
10408 for(var i = 1; i <= 10; i++){
10409 var td = ys[i-1], y2;
10411 y2 = y + Math.round(i * .5);
10412 td.firstChild.innerHTML = y2;
10415 y2 = y - (5-Math.round(i * .5));
10416 td.firstChild.innerHTML = y2;
10419 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10423 updateMPMonth : function(sm){
10424 this.mpMonths.each(function(m, a, i){
10425 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10429 selectMPMonth: function(m){
10433 onMonthClick : function(e, t){
10435 var el = new Roo.Element(t), pn;
10436 if(el.is('button.x-date-mp-cancel')){
10437 this.hideMonthPicker();
10439 else if(el.is('button.x-date-mp-ok')){
10440 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10441 this.hideMonthPicker();
10443 else if(pn = el.up('td.x-date-mp-month', 2)){
10444 this.mpMonths.removeClass('x-date-mp-sel');
10445 pn.addClass('x-date-mp-sel');
10446 this.mpSelMonth = pn.dom.xmonth;
10448 else if(pn = el.up('td.x-date-mp-year', 2)){
10449 this.mpYears.removeClass('x-date-mp-sel');
10450 pn.addClass('x-date-mp-sel');
10451 this.mpSelYear = pn.dom.xyear;
10453 else if(el.is('a.x-date-mp-prev')){
10454 this.updateMPYear(this.mpyear-10);
10456 else if(el.is('a.x-date-mp-next')){
10457 this.updateMPYear(this.mpyear+10);
10461 onMonthDblClick : function(e, t){
10463 var el = new Roo.Element(t), pn;
10464 if(pn = el.up('td.x-date-mp-month', 2)){
10465 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10466 this.hideMonthPicker();
10468 else if(pn = el.up('td.x-date-mp-year', 2)){
10469 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10470 this.hideMonthPicker();
10474 hideMonthPicker : function(disableAnim){
10475 if(this.monthPicker){
10476 if(disableAnim === true){
10477 this.monthPicker.hide();
10479 this.monthPicker.slideOut('t', {duration:.2});
10485 showPrevMonth : function(e){
10486 this.update(this.activeDate.add("mo", -1));
10490 showNextMonth : function(e){
10491 this.update(this.activeDate.add("mo", 1));
10495 showPrevYear : function(){
10496 this.update(this.activeDate.add("y", -1));
10500 showNextYear : function(){
10501 this.update(this.activeDate.add("y", 1));
10505 handleMouseWheel : function(e){
10506 var delta = e.getWheelDelta();
10508 this.showPrevMonth();
10510 } else if(delta < 0){
10511 this.showNextMonth();
10517 handleDateClick : function(e, t){
10519 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10520 this.setValue(new Date(t.dateValue));
10521 this.fireEvent("select", this, this.value);
10526 selectToday : function(){
10527 this.setValue(new Date().clearTime());
10528 this.fireEvent("select", this, this.value);
10532 update : function(date){
10533 var vd = this.activeDate;
10534 this.activeDate = date;
10536 var t = date.getTime();
10537 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10538 this.cells.removeClass("x-date-selected");
10539 this.cells.each(function(c){
10540 if(c.dom.firstChild.dateValue == t){
10541 c.addClass("x-date-selected");
10542 setTimeout(function(){
10543 try{c.dom.firstChild.focus();}catch(e){}
10551 var days = date.getDaysInMonth();
10552 var firstOfMonth = date.getFirstDateOfMonth();
10553 var startingPos = firstOfMonth.getDay()-this.startDay;
10555 if(startingPos <= this.startDay){
10559 var pm = date.add("mo", -1);
10560 var prevStart = pm.getDaysInMonth()-startingPos;
10562 var cells = this.cells.elements;
10563 var textEls = this.textNodes;
10564 days += startingPos;
10566 // convert everything to numbers so it's fast
10567 var day = 86400000;
10568 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10569 var today = new Date().clearTime().getTime();
10570 var sel = date.clearTime().getTime();
10571 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10572 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10573 var ddMatch = this.disabledDatesRE;
10574 var ddText = this.disabledDatesText;
10575 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10576 var ddaysText = this.disabledDaysText;
10577 var format = this.format;
10579 var setCellClass = function(cal, cell){
10581 var t = d.getTime();
10582 cell.firstChild.dateValue = t;
10584 cell.className += " x-date-today";
10585 cell.title = cal.todayText;
10588 cell.className += " x-date-selected";
10589 setTimeout(function(){
10590 try{cell.firstChild.focus();}catch(e){}
10595 cell.className = " x-date-disabled";
10596 cell.title = cal.minText;
10600 cell.className = " x-date-disabled";
10601 cell.title = cal.maxText;
10605 if(ddays.indexOf(d.getDay()) != -1){
10606 cell.title = ddaysText;
10607 cell.className = " x-date-disabled";
10610 if(ddMatch && format){
10611 var fvalue = d.dateFormat(format);
10612 if(ddMatch.test(fvalue)){
10613 cell.title = ddText.replace("%0", fvalue);
10614 cell.className = " x-date-disabled";
10620 for(; i < startingPos; i++) {
10621 textEls[i].innerHTML = (++prevStart);
10622 d.setDate(d.getDate()+1);
10623 cells[i].className = "x-date-prevday";
10624 setCellClass(this, cells[i]);
10626 for(; i < days; i++){
10627 intDay = i - startingPos + 1;
10628 textEls[i].innerHTML = (intDay);
10629 d.setDate(d.getDate()+1);
10630 cells[i].className = "x-date-active";
10631 setCellClass(this, cells[i]);
10634 for(; i < 42; i++) {
10635 textEls[i].innerHTML = (++extraDays);
10636 d.setDate(d.getDate()+1);
10637 cells[i].className = "x-date-nextday";
10638 setCellClass(this, cells[i]);
10641 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10643 if(!this.internalRender){
10644 var main = this.el.dom.firstChild;
10645 var w = main.offsetWidth;
10646 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10647 Roo.fly(main).setWidth(w);
10648 this.internalRender = true;
10649 // opera does not respect the auto grow header center column
10650 // then, after it gets a width opera refuses to recalculate
10651 // without a second pass
10652 if(Roo.isOpera && !this.secondPass){
10653 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10654 this.secondPass = true;
10655 this.update.defer(10, this, [date]);
10661 * Ext JS Library 1.1.1
10662 * Copyright(c) 2006-2007, Ext JS, LLC.
10664 * Originally Released Under LGPL - original licence link has changed is not relivant.
10667 * <script type="text/javascript">
10670 * @class Roo.TabPanel
10671 * @extends Roo.util.Observable
10672 * A lightweight tab container.
10676 // basic tabs 1, built from existing content
10677 var tabs = new Roo.TabPanel("tabs1");
10678 tabs.addTab("script", "View Script");
10679 tabs.addTab("markup", "View Markup");
10680 tabs.activate("script");
10682 // more advanced tabs, built from javascript
10683 var jtabs = new Roo.TabPanel("jtabs");
10684 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10686 // set up the UpdateManager
10687 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10688 var updater = tab2.getUpdateManager();
10689 updater.setDefaultUrl("ajax1.htm");
10690 tab2.on('activate', updater.refresh, updater, true);
10692 // Use setUrl for Ajax loading
10693 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10694 tab3.setUrl("ajax2.htm", null, true);
10697 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10700 jtabs.activate("jtabs-1");
10703 * Create a new TabPanel.
10704 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10705 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10707 Roo.TabPanel = function(container, config){
10709 * The container element for this TabPanel.
10710 * @type Roo.Element
10712 this.el = Roo.get(container, true);
10714 if(typeof config == "boolean"){
10715 this.tabPosition = config ? "bottom" : "top";
10717 Roo.apply(this, config);
10720 if(this.tabPosition == "bottom"){
10721 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10722 this.el.addClass("x-tabs-bottom");
10724 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10725 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10726 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10728 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10730 if(this.tabPosition != "bottom"){
10731 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10732 * @type Roo.Element
10734 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10735 this.el.addClass("x-tabs-top");
10739 this.bodyEl.setStyle("position", "relative");
10741 this.active = null;
10742 this.activateDelegate = this.activate.createDelegate(this);
10747 * Fires when the active tab changes
10748 * @param {Roo.TabPanel} this
10749 * @param {Roo.TabPanelItem} activePanel The new active tab
10753 * @event beforetabchange
10754 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10755 * @param {Roo.TabPanel} this
10756 * @param {Object} e Set cancel to true on this object to cancel the tab change
10757 * @param {Roo.TabPanelItem} tab The tab being changed to
10759 "beforetabchange" : true
10762 Roo.EventManager.onWindowResize(this.onResize, this);
10763 this.cpad = this.el.getPadding("lr");
10764 this.hiddenCount = 0;
10766 Roo.TabPanel.superclass.constructor.call(this);
10769 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10771 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10773 tabPosition : "top",
10775 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10777 currentTabWidth : 0,
10779 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10783 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10787 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10789 preferredTabWidth : 175,
10791 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10793 resizeTabs : false,
10795 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10797 monitorResize : true,
10800 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10801 * @param {String} id The id of the div to use <b>or create</b>
10802 * @param {String} text The text for the tab
10803 * @param {String} content (optional) Content to put in the TabPanelItem body
10804 * @param {Boolean} closable (optional) True to create a close icon on the tab
10805 * @return {Roo.TabPanelItem} The created TabPanelItem
10807 addTab : function(id, text, content, closable){
10808 var item = new Roo.TabPanelItem(this, id, text, closable);
10809 this.addTabItem(item);
10811 item.setContent(content);
10817 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10818 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10819 * @return {Roo.TabPanelItem}
10821 getTab : function(id){
10822 return this.items[id];
10826 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10827 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10829 hideTab : function(id){
10830 var t = this.items[id];
10833 this.hiddenCount++;
10834 this.autoSizeTabs();
10839 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10840 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10842 unhideTab : function(id){
10843 var t = this.items[id];
10845 t.setHidden(false);
10846 this.hiddenCount--;
10847 this.autoSizeTabs();
10852 * Adds an existing {@link Roo.TabPanelItem}.
10853 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10855 addTabItem : function(item){
10856 this.items[item.id] = item;
10857 this.items.push(item);
10858 if(this.resizeTabs){
10859 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10860 this.autoSizeTabs();
10867 * Removes a {@link Roo.TabPanelItem}.
10868 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10870 removeTab : function(id){
10871 var items = this.items;
10872 var tab = items[id];
10873 if(!tab) { return; }
10874 var index = items.indexOf(tab);
10875 if(this.active == tab && items.length > 1){
10876 var newTab = this.getNextAvailable(index);
10881 this.stripEl.dom.removeChild(tab.pnode.dom);
10882 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10883 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10885 items.splice(index, 1);
10886 delete this.items[tab.id];
10887 tab.fireEvent("close", tab);
10888 tab.purgeListeners();
10889 this.autoSizeTabs();
10892 getNextAvailable : function(start){
10893 var items = this.items;
10895 // look for a next tab that will slide over to
10896 // replace the one being removed
10897 while(index < items.length){
10898 var item = items[++index];
10899 if(item && !item.isHidden()){
10903 // if one isn't found select the previous tab (on the left)
10906 var item = items[--index];
10907 if(item && !item.isHidden()){
10915 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10916 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10918 disableTab : function(id){
10919 var tab = this.items[id];
10920 if(tab && this.active != tab){
10926 * Enables a {@link Roo.TabPanelItem} that is disabled.
10927 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10929 enableTab : function(id){
10930 var tab = this.items[id];
10935 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10936 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10937 * @return {Roo.TabPanelItem} The TabPanelItem.
10939 activate : function(id){
10940 var tab = this.items[id];
10944 if(tab == this.active || tab.disabled){
10948 this.fireEvent("beforetabchange", this, e, tab);
10949 if(e.cancel !== true && !tab.disabled){
10951 this.active.hide();
10953 this.active = this.items[id];
10954 this.active.show();
10955 this.fireEvent("tabchange", this, this.active);
10961 * Gets the active {@link Roo.TabPanelItem}.
10962 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10964 getActiveTab : function(){
10965 return this.active;
10969 * Updates the tab body element to fit the height of the container element
10970 * for overflow scrolling
10971 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10973 syncHeight : function(targetHeight){
10974 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10975 var bm = this.bodyEl.getMargins();
10976 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10977 this.bodyEl.setHeight(newHeight);
10981 onResize : function(){
10982 if(this.monitorResize){
10983 this.autoSizeTabs();
10988 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10990 beginUpdate : function(){
10991 this.updating = true;
10995 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10997 endUpdate : function(){
10998 this.updating = false;
10999 this.autoSizeTabs();
11003 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11005 autoSizeTabs : function(){
11006 var count = this.items.length;
11007 var vcount = count - this.hiddenCount;
11008 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11009 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11010 var availWidth = Math.floor(w / vcount);
11011 var b = this.stripBody;
11012 if(b.getWidth() > w){
11013 var tabs = this.items;
11014 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11015 if(availWidth < this.minTabWidth){
11016 /*if(!this.sleft){ // incomplete scrolling code
11017 this.createScrollButtons();
11020 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11023 if(this.currentTabWidth < this.preferredTabWidth){
11024 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11030 * Returns the number of tabs in this TabPanel.
11033 getCount : function(){
11034 return this.items.length;
11038 * Resizes all the tabs to the passed width
11039 * @param {Number} The new width
11041 setTabWidth : function(width){
11042 this.currentTabWidth = width;
11043 for(var i = 0, len = this.items.length; i < len; i++) {
11044 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11049 * Destroys this TabPanel
11050 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11052 destroy : function(removeEl){
11053 Roo.EventManager.removeResizeListener(this.onResize, this);
11054 for(var i = 0, len = this.items.length; i < len; i++){
11055 this.items[i].purgeListeners();
11057 if(removeEl === true){
11058 this.el.update("");
11065 * @class Roo.TabPanelItem
11066 * @extends Roo.util.Observable
11067 * Represents an individual item (tab plus body) in a TabPanel.
11068 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11069 * @param {String} id The id of this TabPanelItem
11070 * @param {String} text The text for the tab of this TabPanelItem
11071 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11073 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11075 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11076 * @type Roo.TabPanel
11078 this.tabPanel = tabPanel;
11080 * The id for this TabPanelItem
11085 this.disabled = false;
11089 this.loaded = false;
11090 this.closable = closable;
11093 * The body element for this TabPanelItem.
11094 * @type Roo.Element
11096 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11097 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11098 this.bodyEl.setStyle("display", "block");
11099 this.bodyEl.setStyle("zoom", "1");
11102 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11104 this.el = Roo.get(els.el, true);
11105 this.inner = Roo.get(els.inner, true);
11106 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11107 this.pnode = Roo.get(els.el.parentNode, true);
11108 this.el.on("mousedown", this.onTabMouseDown, this);
11109 this.el.on("click", this.onTabClick, this);
11112 var c = Roo.get(els.close, true);
11113 c.dom.title = this.closeText;
11114 c.addClassOnOver("close-over");
11115 c.on("click", this.closeClick, this);
11121 * Fires when this tab becomes the active tab.
11122 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11123 * @param {Roo.TabPanelItem} this
11127 * @event beforeclose
11128 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11129 * @param {Roo.TabPanelItem} this
11130 * @param {Object} e Set cancel to true on this object to cancel the close.
11132 "beforeclose": true,
11135 * Fires when this tab is closed.
11136 * @param {Roo.TabPanelItem} this
11140 * @event deactivate
11141 * Fires when this tab is no longer the active tab.
11142 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11143 * @param {Roo.TabPanelItem} this
11145 "deactivate" : true
11147 this.hidden = false;
11149 Roo.TabPanelItem.superclass.constructor.call(this);
11152 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11153 purgeListeners : function(){
11154 Roo.util.Observable.prototype.purgeListeners.call(this);
11155 this.el.removeAllListeners();
11158 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11161 this.pnode.addClass("on");
11164 this.tabPanel.stripWrap.repaint();
11166 this.fireEvent("activate", this.tabPanel, this);
11170 * Returns true if this tab is the active tab.
11171 * @return {Boolean}
11173 isActive : function(){
11174 return this.tabPanel.getActiveTab() == this;
11178 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11181 this.pnode.removeClass("on");
11183 this.fireEvent("deactivate", this.tabPanel, this);
11186 hideAction : function(){
11187 this.bodyEl.hide();
11188 this.bodyEl.setStyle("position", "absolute");
11189 this.bodyEl.setLeft("-20000px");
11190 this.bodyEl.setTop("-20000px");
11193 showAction : function(){
11194 this.bodyEl.setStyle("position", "relative");
11195 this.bodyEl.setTop("");
11196 this.bodyEl.setLeft("");
11197 this.bodyEl.show();
11201 * Set the tooltip for the tab.
11202 * @param {String} tooltip The tab's tooltip
11204 setTooltip : function(text){
11205 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11206 this.textEl.dom.qtip = text;
11207 this.textEl.dom.removeAttribute('title');
11209 this.textEl.dom.title = text;
11213 onTabClick : function(e){
11214 e.preventDefault();
11215 this.tabPanel.activate(this.id);
11218 onTabMouseDown : function(e){
11219 e.preventDefault();
11220 this.tabPanel.activate(this.id);
11223 getWidth : function(){
11224 return this.inner.getWidth();
11227 setWidth : function(width){
11228 var iwidth = width - this.pnode.getPadding("lr");
11229 this.inner.setWidth(iwidth);
11230 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11231 this.pnode.setWidth(width);
11235 * Show or hide the tab
11236 * @param {Boolean} hidden True to hide or false to show.
11238 setHidden : function(hidden){
11239 this.hidden = hidden;
11240 this.pnode.setStyle("display", hidden ? "none" : "");
11244 * Returns true if this tab is "hidden"
11245 * @return {Boolean}
11247 isHidden : function(){
11248 return this.hidden;
11252 * Returns the text for this tab
11255 getText : function(){
11259 autoSize : function(){
11260 //this.el.beginMeasure();
11261 this.textEl.setWidth(1);
11262 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11263 //this.el.endMeasure();
11267 * Sets the text for the tab (Note: this also sets the tooltip text)
11268 * @param {String} text The tab's text and tooltip
11270 setText : function(text){
11272 this.textEl.update(text);
11273 this.setTooltip(text);
11274 if(!this.tabPanel.resizeTabs){
11279 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11281 activate : function(){
11282 this.tabPanel.activate(this.id);
11286 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11288 disable : function(){
11289 if(this.tabPanel.active != this){
11290 this.disabled = true;
11291 this.pnode.addClass("disabled");
11296 * Enables this TabPanelItem if it was previously disabled.
11298 enable : function(){
11299 this.disabled = false;
11300 this.pnode.removeClass("disabled");
11304 * Sets the content for this TabPanelItem.
11305 * @param {String} content The content
11306 * @param {Boolean} loadScripts true to look for and load scripts
11308 setContent : function(content, loadScripts){
11309 this.bodyEl.update(content, loadScripts);
11313 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11314 * @return {Roo.UpdateManager} The UpdateManager
11316 getUpdateManager : function(){
11317 return this.bodyEl.getUpdateManager();
11321 * Set a URL to be used to load the content for this TabPanelItem.
11322 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11323 * @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)
11324 * @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)
11325 * @return {Roo.UpdateManager} The UpdateManager
11327 setUrl : function(url, params, loadOnce){
11328 if(this.refreshDelegate){
11329 this.un('activate', this.refreshDelegate);
11331 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11332 this.on("activate", this.refreshDelegate);
11333 return this.bodyEl.getUpdateManager();
11337 _handleRefresh : function(url, params, loadOnce){
11338 if(!loadOnce || !this.loaded){
11339 var updater = this.bodyEl.getUpdateManager();
11340 updater.update(url, params, this._setLoaded.createDelegate(this));
11345 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11346 * Will fail silently if the setUrl method has not been called.
11347 * This does not activate the panel, just updates its content.
11349 refresh : function(){
11350 if(this.refreshDelegate){
11351 this.loaded = false;
11352 this.refreshDelegate();
11357 _setLoaded : function(){
11358 this.loaded = true;
11362 closeClick : function(e){
11365 this.fireEvent("beforeclose", this, o);
11366 if(o.cancel !== true){
11367 this.tabPanel.removeTab(this.id);
11371 * The text displayed in the tooltip for the close icon.
11374 closeText : "Close this tab"
11378 Roo.TabPanel.prototype.createStrip = function(container){
11379 var strip = document.createElement("div");
11380 strip.className = "x-tabs-wrap";
11381 container.appendChild(strip);
11385 Roo.TabPanel.prototype.createStripList = function(strip){
11386 // div wrapper for retard IE
11387 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>';
11388 return strip.firstChild.firstChild.firstChild.firstChild;
11391 Roo.TabPanel.prototype.createBody = function(container){
11392 var body = document.createElement("div");
11393 Roo.id(body, "tab-body");
11394 Roo.fly(body).addClass("x-tabs-body");
11395 container.appendChild(body);
11399 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11400 var body = Roo.getDom(id);
11402 body = document.createElement("div");
11405 Roo.fly(body).addClass("x-tabs-item-body");
11406 bodyEl.insertBefore(body, bodyEl.firstChild);
11410 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11411 var td = document.createElement("td");
11412 stripEl.appendChild(td);
11414 td.className = "x-tabs-closable";
11415 if(!this.closeTpl){
11416 this.closeTpl = 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>' +
11419 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11422 var el = this.closeTpl.overwrite(td, {"text": text});
11423 var close = el.getElementsByTagName("div")[0];
11424 var inner = el.getElementsByTagName("em")[0];
11425 return {"el": el, "close": close, "inner": inner};
11428 this.tabTpl = new Roo.Template(
11429 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11430 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11433 var el = this.tabTpl.overwrite(td, {"text": text});
11434 var inner = el.getElementsByTagName("em")[0];
11435 return {"el": el, "inner": inner};
11439 * Ext JS Library 1.1.1
11440 * Copyright(c) 2006-2007, Ext JS, LLC.
11442 * Originally Released Under LGPL - original licence link has changed is not relivant.
11445 * <script type="text/javascript">
11449 * @class Roo.Button
11450 * @extends Roo.util.Observable
11451 * Simple Button class
11452 * @cfg {String} text The button text
11453 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11454 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11455 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11456 * @cfg {Object} scope The scope of the handler
11457 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11458 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11459 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11460 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11461 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11462 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11463 applies if enableToggle = true)
11464 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11465 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11466 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11468 * Create a new button
11469 * @param {Object} config The config object
11471 Roo.Button = function(renderTo, config)
11475 renderTo = config.renderTo || false;
11478 Roo.apply(this, config);
11482 * Fires when this button is clicked
11483 * @param {Button} this
11484 * @param {EventObject} e The click event
11489 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11490 * @param {Button} this
11491 * @param {Boolean} pressed
11496 * Fires when the mouse hovers over the button
11497 * @param {Button} this
11498 * @param {Event} e The event object
11500 'mouseover' : true,
11503 * Fires when the mouse exits the button
11504 * @param {Button} this
11505 * @param {Event} e The event object
11510 * Fires when the button is rendered
11511 * @param {Button} this
11516 this.menu = Roo.menu.MenuMgr.get(this.menu);
11518 // register listeners first!! - so render can be captured..
11519 Roo.util.Observable.call(this);
11521 this.render(renderTo);
11527 Roo.extend(Roo.Button, Roo.util.Observable, {
11533 * Read-only. True if this button is hidden
11538 * Read-only. True if this button is disabled
11543 * Read-only. True if this button is pressed (only if enableToggle = true)
11549 * @cfg {Number} tabIndex
11550 * The DOM tabIndex for this button (defaults to undefined)
11552 tabIndex : undefined,
11555 * @cfg {Boolean} enableToggle
11556 * True to enable pressed/not pressed toggling (defaults to false)
11558 enableToggle: false,
11560 * @cfg {Mixed} menu
11561 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11565 * @cfg {String} menuAlign
11566 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11568 menuAlign : "tl-bl?",
11571 * @cfg {String} iconCls
11572 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11574 iconCls : undefined,
11576 * @cfg {String} type
11577 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11582 menuClassTarget: 'tr',
11585 * @cfg {String} clickEvent
11586 * The type of event to map to the button's event handler (defaults to 'click')
11588 clickEvent : 'click',
11591 * @cfg {Boolean} handleMouseEvents
11592 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11594 handleMouseEvents : true,
11597 * @cfg {String} tooltipType
11598 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11600 tooltipType : 'qtip',
11603 * @cfg {String} cls
11604 * A CSS class to apply to the button's main element.
11608 * @cfg {Roo.Template} template (Optional)
11609 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11610 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11611 * require code modifications if required elements (e.g. a button) aren't present.
11615 render : function(renderTo){
11617 if(this.hideParent){
11618 this.parentEl = Roo.get(renderTo);
11620 if(!this.dhconfig){
11621 if(!this.template){
11622 if(!Roo.Button.buttonTemplate){
11623 // hideous table template
11624 Roo.Button.buttonTemplate = new Roo.Template(
11625 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11626 '<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>',
11627 "</tr></tbody></table>");
11629 this.template = Roo.Button.buttonTemplate;
11631 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11632 var btnEl = btn.child("button:first");
11633 btnEl.on('focus', this.onFocus, this);
11634 btnEl.on('blur', this.onBlur, this);
11636 btn.addClass(this.cls);
11639 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11642 btnEl.addClass(this.iconCls);
11644 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11647 if(this.tabIndex !== undefined){
11648 btnEl.dom.tabIndex = this.tabIndex;
11651 if(typeof this.tooltip == 'object'){
11652 Roo.QuickTips.tips(Roo.apply({
11656 btnEl.dom[this.tooltipType] = this.tooltip;
11660 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11664 this.el.dom.id = this.el.id = this.id;
11667 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11668 this.menu.on("show", this.onMenuShow, this);
11669 this.menu.on("hide", this.onMenuHide, this);
11671 btn.addClass("x-btn");
11672 if(Roo.isIE && !Roo.isIE7){
11673 this.autoWidth.defer(1, this);
11677 if(this.handleMouseEvents){
11678 btn.on("mouseover", this.onMouseOver, this);
11679 btn.on("mouseout", this.onMouseOut, this);
11680 btn.on("mousedown", this.onMouseDown, this);
11682 btn.on(this.clickEvent, this.onClick, this);
11683 //btn.on("mouseup", this.onMouseUp, this);
11690 Roo.ButtonToggleMgr.register(this);
11692 this.el.addClass("x-btn-pressed");
11695 var repeater = new Roo.util.ClickRepeater(btn,
11696 typeof this.repeat == "object" ? this.repeat : {}
11698 repeater.on("click", this.onClick, this);
11701 this.fireEvent('render', this);
11705 * Returns the button's underlying element
11706 * @return {Roo.Element} The element
11708 getEl : function(){
11713 * Destroys this Button and removes any listeners.
11715 destroy : function(){
11716 Roo.ButtonToggleMgr.unregister(this);
11717 this.el.removeAllListeners();
11718 this.purgeListeners();
11723 autoWidth : function(){
11725 this.el.setWidth("auto");
11726 if(Roo.isIE7 && Roo.isStrict){
11727 var ib = this.el.child('button');
11728 if(ib && ib.getWidth() > 20){
11730 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11735 this.el.beginMeasure();
11737 if(this.el.getWidth() < this.minWidth){
11738 this.el.setWidth(this.minWidth);
11741 this.el.endMeasure();
11748 * Assigns this button's click handler
11749 * @param {Function} handler The function to call when the button is clicked
11750 * @param {Object} scope (optional) Scope for the function passed in
11752 setHandler : function(handler, scope){
11753 this.handler = handler;
11754 this.scope = scope;
11758 * Sets this button's text
11759 * @param {String} text The button text
11761 setText : function(text){
11764 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11770 * Gets the text for this button
11771 * @return {String} The button text
11773 getText : function(){
11781 this.hidden = false;
11783 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11791 this.hidden = true;
11793 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11798 * Convenience function for boolean show/hide
11799 * @param {Boolean} visible True to show, false to hide
11801 setVisible: function(visible){
11810 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11811 * @param {Boolean} state (optional) Force a particular state
11813 toggle : function(state){
11814 state = state === undefined ? !this.pressed : state;
11815 if(state != this.pressed){
11817 this.el.addClass("x-btn-pressed");
11818 this.pressed = true;
11819 this.fireEvent("toggle", this, true);
11821 this.el.removeClass("x-btn-pressed");
11822 this.pressed = false;
11823 this.fireEvent("toggle", this, false);
11825 if(this.toggleHandler){
11826 this.toggleHandler.call(this.scope || this, this, state);
11834 focus : function(){
11835 this.el.child('button:first').focus();
11839 * Disable this button
11841 disable : function(){
11843 this.el.addClass("x-btn-disabled");
11845 this.disabled = true;
11849 * Enable this button
11851 enable : function(){
11853 this.el.removeClass("x-btn-disabled");
11855 this.disabled = false;
11859 * Convenience function for boolean enable/disable
11860 * @param {Boolean} enabled True to enable, false to disable
11862 setDisabled : function(v){
11863 this[v !== true ? "enable" : "disable"]();
11867 onClick : function(e){
11869 e.preventDefault();
11874 if(!this.disabled){
11875 if(this.enableToggle){
11878 if(this.menu && !this.menu.isVisible()){
11879 this.menu.show(this.el, this.menuAlign);
11881 this.fireEvent("click", this, e);
11883 this.el.removeClass("x-btn-over");
11884 this.handler.call(this.scope || this, this, e);
11889 onMouseOver : function(e){
11890 if(!this.disabled){
11891 this.el.addClass("x-btn-over");
11892 this.fireEvent('mouseover', this, e);
11896 onMouseOut : function(e){
11897 if(!e.within(this.el, true)){
11898 this.el.removeClass("x-btn-over");
11899 this.fireEvent('mouseout', this, e);
11903 onFocus : function(e){
11904 if(!this.disabled){
11905 this.el.addClass("x-btn-focus");
11909 onBlur : function(e){
11910 this.el.removeClass("x-btn-focus");
11913 onMouseDown : function(e){
11914 if(!this.disabled && e.button == 0){
11915 this.el.addClass("x-btn-click");
11916 Roo.get(document).on('mouseup', this.onMouseUp, this);
11920 onMouseUp : function(e){
11922 this.el.removeClass("x-btn-click");
11923 Roo.get(document).un('mouseup', this.onMouseUp, this);
11927 onMenuShow : function(e){
11928 this.el.addClass("x-btn-menu-active");
11931 onMenuHide : function(e){
11932 this.el.removeClass("x-btn-menu-active");
11936 // Private utility class used by Button
11937 Roo.ButtonToggleMgr = function(){
11940 function toggleGroup(btn, state){
11942 var g = groups[btn.toggleGroup];
11943 for(var i = 0, l = g.length; i < l; i++){
11945 g[i].toggle(false);
11952 register : function(btn){
11953 if(!btn.toggleGroup){
11956 var g = groups[btn.toggleGroup];
11958 g = groups[btn.toggleGroup] = [];
11961 btn.on("toggle", toggleGroup);
11964 unregister : function(btn){
11965 if(!btn.toggleGroup){
11968 var g = groups[btn.toggleGroup];
11971 btn.un("toggle", toggleGroup);
11977 * Ext JS Library 1.1.1
11978 * Copyright(c) 2006-2007, Ext JS, LLC.
11980 * Originally Released Under LGPL - original licence link has changed is not relivant.
11983 * <script type="text/javascript">
11987 * @class Roo.SplitButton
11988 * @extends Roo.Button
11989 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11990 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11991 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11992 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11993 * @cfg {String} arrowTooltip The title attribute of the arrow
11995 * Create a new menu button
11996 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11997 * @param {Object} config The config object
11999 Roo.SplitButton = function(renderTo, config){
12000 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12002 * @event arrowclick
12003 * Fires when this button's arrow is clicked
12004 * @param {SplitButton} this
12005 * @param {EventObject} e The click event
12007 this.addEvents({"arrowclick":true});
12010 Roo.extend(Roo.SplitButton, Roo.Button, {
12011 render : function(renderTo){
12012 // this is one sweet looking template!
12013 var tpl = new Roo.Template(
12014 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12015 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12016 '<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>',
12017 "</tbody></table></td><td>",
12018 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12019 '<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>',
12020 "</tbody></table></td></tr></table>"
12022 var btn = tpl.append(renderTo, [this.text, this.type], true);
12023 var btnEl = btn.child("button");
12025 btn.addClass(this.cls);
12028 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12031 btnEl.addClass(this.iconCls);
12033 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12037 if(this.handleMouseEvents){
12038 btn.on("mouseover", this.onMouseOver, this);
12039 btn.on("mouseout", this.onMouseOut, this);
12040 btn.on("mousedown", this.onMouseDown, this);
12041 btn.on("mouseup", this.onMouseUp, this);
12043 btn.on(this.clickEvent, this.onClick, this);
12045 if(typeof this.tooltip == 'object'){
12046 Roo.QuickTips.tips(Roo.apply({
12050 btnEl.dom[this.tooltipType] = this.tooltip;
12053 if(this.arrowTooltip){
12054 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12063 this.el.addClass("x-btn-pressed");
12065 if(Roo.isIE && !Roo.isIE7){
12066 this.autoWidth.defer(1, this);
12071 this.menu.on("show", this.onMenuShow, this);
12072 this.menu.on("hide", this.onMenuHide, this);
12074 this.fireEvent('render', this);
12078 autoWidth : function(){
12080 var tbl = this.el.child("table:first");
12081 var tbl2 = this.el.child("table:last");
12082 this.el.setWidth("auto");
12083 tbl.setWidth("auto");
12084 if(Roo.isIE7 && Roo.isStrict){
12085 var ib = this.el.child('button:first');
12086 if(ib && ib.getWidth() > 20){
12088 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12093 this.el.beginMeasure();
12095 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12096 tbl.setWidth(this.minWidth-tbl2.getWidth());
12099 this.el.endMeasure();
12102 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12106 * Sets this button's click handler
12107 * @param {Function} handler The function to call when the button is clicked
12108 * @param {Object} scope (optional) Scope for the function passed above
12110 setHandler : function(handler, scope){
12111 this.handler = handler;
12112 this.scope = scope;
12116 * Sets this button's arrow click handler
12117 * @param {Function} handler The function to call when the arrow is clicked
12118 * @param {Object} scope (optional) Scope for the function passed above
12120 setArrowHandler : function(handler, scope){
12121 this.arrowHandler = handler;
12122 this.scope = scope;
12128 focus : function(){
12130 this.el.child("button:first").focus();
12135 onClick : function(e){
12136 e.preventDefault();
12137 if(!this.disabled){
12138 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12139 if(this.menu && !this.menu.isVisible()){
12140 this.menu.show(this.el, this.menuAlign);
12142 this.fireEvent("arrowclick", this, e);
12143 if(this.arrowHandler){
12144 this.arrowHandler.call(this.scope || this, this, e);
12147 this.fireEvent("click", this, e);
12149 this.handler.call(this.scope || this, this, e);
12155 onMouseDown : function(e){
12156 if(!this.disabled){
12157 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12161 onMouseUp : function(e){
12162 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12167 // backwards compat
12168 Roo.MenuButton = Roo.SplitButton;/*
12170 * Ext JS Library 1.1.1
12171 * Copyright(c) 2006-2007, Ext JS, LLC.
12173 * Originally Released Under LGPL - original licence link has changed is not relivant.
12176 * <script type="text/javascript">
12180 * @class Roo.Toolbar
12181 * Basic Toolbar class.
12183 * Creates a new Toolbar
12184 * @param {Object} config The config object
12186 Roo.Toolbar = function(container, buttons, config)
12188 /// old consturctor format still supported..
12189 if(container instanceof Array){ // omit the container for later rendering
12190 buttons = container;
12194 if (typeof(container) == 'object' && container.xtype) {
12195 config = container;
12196 container = config.container;
12197 buttons = config.buttons; // not really - use items!!
12200 if (config && config.items) {
12201 xitems = config.items;
12202 delete config.items;
12204 Roo.apply(this, config);
12205 this.buttons = buttons;
12208 this.render(container);
12210 Roo.each(xitems, function(b) {
12216 Roo.Toolbar.prototype = {
12218 * @cfg {Roo.data.Store} items
12219 * array of button configs or elements to add
12223 * @cfg {String/HTMLElement/Element} container
12224 * The id or element that will contain the toolbar
12227 render : function(ct){
12228 this.el = Roo.get(ct);
12230 this.el.addClass(this.cls);
12232 // using a table allows for vertical alignment
12233 // 100% width is needed by Safari...
12234 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12235 this.tr = this.el.child("tr", true);
12237 this.items = new Roo.util.MixedCollection(false, function(o){
12238 return o.id || ("item" + (++autoId));
12241 this.add.apply(this, this.buttons);
12242 delete this.buttons;
12247 * Adds element(s) to the toolbar -- this function takes a variable number of
12248 * arguments of mixed type and adds them to the toolbar.
12249 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12251 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12252 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12253 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12254 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12255 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12256 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12257 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12258 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12259 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12261 * @param {Mixed} arg2
12262 * @param {Mixed} etc.
12265 var a = arguments, l = a.length;
12266 for(var i = 0; i < l; i++){
12271 _add : function(el) {
12274 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12277 if (el.applyTo){ // some kind of form field
12278 return this.addField(el);
12280 if (el.render){ // some kind of Toolbar.Item
12281 return this.addItem(el);
12283 if (typeof el == "string"){ // string
12284 if(el == "separator" || el == "-"){
12285 return this.addSeparator();
12288 return this.addSpacer();
12291 return this.addFill();
12293 return this.addText(el);
12296 if(el.tagName){ // element
12297 return this.addElement(el);
12299 if(typeof el == "object"){ // must be button config?
12300 return this.addButton(el);
12302 // and now what?!?!
12308 * Add an Xtype element
12309 * @param {Object} xtype Xtype Object
12310 * @return {Object} created Object
12312 addxtype : function(e){
12313 return this.add(e);
12317 * Returns the Element for this toolbar.
12318 * @return {Roo.Element}
12320 getEl : function(){
12326 * @return {Roo.Toolbar.Item} The separator item
12328 addSeparator : function(){
12329 return this.addItem(new Roo.Toolbar.Separator());
12333 * Adds a spacer element
12334 * @return {Roo.Toolbar.Spacer} The spacer item
12336 addSpacer : function(){
12337 return this.addItem(new Roo.Toolbar.Spacer());
12341 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12342 * @return {Roo.Toolbar.Fill} The fill item
12344 addFill : function(){
12345 return this.addItem(new Roo.Toolbar.Fill());
12349 * Adds any standard HTML element to the toolbar
12350 * @param {String/HTMLElement/Element} el The element or id of the element to add
12351 * @return {Roo.Toolbar.Item} The element's item
12353 addElement : function(el){
12354 return this.addItem(new Roo.Toolbar.Item(el));
12357 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12358 * @type Roo.util.MixedCollection
12363 * Adds any Toolbar.Item or subclass
12364 * @param {Roo.Toolbar.Item} item
12365 * @return {Roo.Toolbar.Item} The item
12367 addItem : function(item){
12368 var td = this.nextBlock();
12370 this.items.add(item);
12375 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12376 * @param {Object/Array} config A button config or array of configs
12377 * @return {Roo.Toolbar.Button/Array}
12379 addButton : function(config){
12380 if(config instanceof Array){
12382 for(var i = 0, len = config.length; i < len; i++) {
12383 buttons.push(this.addButton(config[i]));
12388 if(!(config instanceof Roo.Toolbar.Button)){
12390 new Roo.Toolbar.SplitButton(config) :
12391 new Roo.Toolbar.Button(config);
12393 var td = this.nextBlock();
12400 * Adds text to the toolbar
12401 * @param {String} text The text to add
12402 * @return {Roo.Toolbar.Item} The element's item
12404 addText : function(text){
12405 return this.addItem(new Roo.Toolbar.TextItem(text));
12409 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12410 * @param {Number} index The index where the item is to be inserted
12411 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12412 * @return {Roo.Toolbar.Button/Item}
12414 insertButton : function(index, item){
12415 if(item instanceof Array){
12417 for(var i = 0, len = item.length; i < len; i++) {
12418 buttons.push(this.insertButton(index + i, item[i]));
12422 if (!(item instanceof Roo.Toolbar.Button)){
12423 item = new Roo.Toolbar.Button(item);
12425 var td = document.createElement("td");
12426 this.tr.insertBefore(td, this.tr.childNodes[index]);
12428 this.items.insert(index, item);
12433 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12434 * @param {Object} config
12435 * @return {Roo.Toolbar.Item} The element's item
12437 addDom : function(config, returnEl){
12438 var td = this.nextBlock();
12439 Roo.DomHelper.overwrite(td, config);
12440 var ti = new Roo.Toolbar.Item(td.firstChild);
12442 this.items.add(ti);
12447 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12448 * @type Roo.util.MixedCollection
12453 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12454 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12455 * @param {Roo.form.Field} field
12456 * @return {Roo.ToolbarItem}
12460 addField : function(field) {
12461 if (!this.fields) {
12463 this.fields = new Roo.util.MixedCollection(false, function(o){
12464 return o.id || ("item" + (++autoId));
12469 var td = this.nextBlock();
12471 var ti = new Roo.Toolbar.Item(td.firstChild);
12473 this.items.add(ti);
12474 this.fields.add(field);
12485 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12486 this.el.child('div').hide();
12494 this.el.child('div').show();
12498 nextBlock : function(){
12499 var td = document.createElement("td");
12500 this.tr.appendChild(td);
12505 destroy : function(){
12506 if(this.items){ // rendered?
12507 Roo.destroy.apply(Roo, this.items.items);
12509 if(this.fields){ // rendered?
12510 Roo.destroy.apply(Roo, this.fields.items);
12512 Roo.Element.uncache(this.el, this.tr);
12517 * @class Roo.Toolbar.Item
12518 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12520 * Creates a new Item
12521 * @param {HTMLElement} el
12523 Roo.Toolbar.Item = function(el){
12524 this.el = Roo.getDom(el);
12525 this.id = Roo.id(this.el);
12526 this.hidden = false;
12529 Roo.Toolbar.Item.prototype = {
12532 * Get this item's HTML Element
12533 * @return {HTMLElement}
12535 getEl : function(){
12540 render : function(td){
12542 td.appendChild(this.el);
12546 * Removes and destroys this item.
12548 destroy : function(){
12549 this.td.parentNode.removeChild(this.td);
12556 this.hidden = false;
12557 this.td.style.display = "";
12564 this.hidden = true;
12565 this.td.style.display = "none";
12569 * Convenience function for boolean show/hide.
12570 * @param {Boolean} visible true to show/false to hide
12572 setVisible: function(visible){
12581 * Try to focus this item.
12583 focus : function(){
12584 Roo.fly(this.el).focus();
12588 * Disables this item.
12590 disable : function(){
12591 Roo.fly(this.td).addClass("x-item-disabled");
12592 this.disabled = true;
12593 this.el.disabled = true;
12597 * Enables this item.
12599 enable : function(){
12600 Roo.fly(this.td).removeClass("x-item-disabled");
12601 this.disabled = false;
12602 this.el.disabled = false;
12608 * @class Roo.Toolbar.Separator
12609 * @extends Roo.Toolbar.Item
12610 * A simple toolbar separator class
12612 * Creates a new Separator
12614 Roo.Toolbar.Separator = function(){
12615 var s = document.createElement("span");
12616 s.className = "ytb-sep";
12617 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12619 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12620 enable:Roo.emptyFn,
12621 disable:Roo.emptyFn,
12626 * @class Roo.Toolbar.Spacer
12627 * @extends Roo.Toolbar.Item
12628 * A simple element that adds extra horizontal space to a toolbar.
12630 * Creates a new Spacer
12632 Roo.Toolbar.Spacer = function(){
12633 var s = document.createElement("div");
12634 s.className = "ytb-spacer";
12635 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12637 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12638 enable:Roo.emptyFn,
12639 disable:Roo.emptyFn,
12644 * @class Roo.Toolbar.Fill
12645 * @extends Roo.Toolbar.Spacer
12646 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12648 * Creates a new Spacer
12650 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12652 render : function(td){
12653 td.style.width = '100%';
12654 Roo.Toolbar.Fill.superclass.render.call(this, td);
12659 * @class Roo.Toolbar.TextItem
12660 * @extends Roo.Toolbar.Item
12661 * A simple class that renders text directly into a toolbar.
12663 * Creates a new TextItem
12664 * @param {String} text
12666 Roo.Toolbar.TextItem = function(text){
12667 if (typeof(text) == 'object') {
12670 var s = document.createElement("span");
12671 s.className = "ytb-text";
12672 s.innerHTML = text;
12673 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12675 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12676 enable:Roo.emptyFn,
12677 disable:Roo.emptyFn,
12682 * @class Roo.Toolbar.Button
12683 * @extends Roo.Button
12684 * A button that renders into a toolbar.
12686 * Creates a new Button
12687 * @param {Object} config A standard {@link Roo.Button} config object
12689 Roo.Toolbar.Button = function(config){
12690 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12692 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12693 render : function(td){
12695 Roo.Toolbar.Button.superclass.render.call(this, td);
12699 * Removes and destroys this button
12701 destroy : function(){
12702 Roo.Toolbar.Button.superclass.destroy.call(this);
12703 this.td.parentNode.removeChild(this.td);
12707 * Shows this button
12710 this.hidden = false;
12711 this.td.style.display = "";
12715 * Hides this button
12718 this.hidden = true;
12719 this.td.style.display = "none";
12723 * Disables this item
12725 disable : function(){
12726 Roo.fly(this.td).addClass("x-item-disabled");
12727 this.disabled = true;
12731 * Enables this item
12733 enable : function(){
12734 Roo.fly(this.td).removeClass("x-item-disabled");
12735 this.disabled = false;
12738 // backwards compat
12739 Roo.ToolbarButton = Roo.Toolbar.Button;
12742 * @class Roo.Toolbar.SplitButton
12743 * @extends Roo.SplitButton
12744 * A menu button that renders into a toolbar.
12746 * Creates a new SplitButton
12747 * @param {Object} config A standard {@link Roo.SplitButton} config object
12749 Roo.Toolbar.SplitButton = function(config){
12750 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12752 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12753 render : function(td){
12755 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12759 * Removes and destroys this button
12761 destroy : function(){
12762 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12763 this.td.parentNode.removeChild(this.td);
12767 * Shows this button
12770 this.hidden = false;
12771 this.td.style.display = "";
12775 * Hides this button
12778 this.hidden = true;
12779 this.td.style.display = "none";
12783 // backwards compat
12784 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12796 * @class Roo.PagingToolbar
12797 * @extends Roo.Toolbar
12798 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12800 * Create a new PagingToolbar
12801 * @param {Object} config The config object
12803 Roo.PagingToolbar = function(el, ds, config)
12805 // old args format still supported... - xtype is prefered..
12806 if (typeof(el) == 'object' && el.xtype) {
12807 // created from xtype...
12809 ds = el.dataSource;
12810 el = config.container;
12813 if (config.items) {
12814 items = config.items;
12818 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12821 this.renderButtons(this.el);
12824 // supprot items array.
12826 Roo.each(items, function(e) {
12827 this.add(Roo.factory(e));
12832 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12834 * @cfg {Roo.data.Store} dataSource
12835 * The underlying data store providing the paged data
12838 * @cfg {String/HTMLElement/Element} container
12839 * container The id or element that will contain the toolbar
12842 * @cfg {Boolean} displayInfo
12843 * True to display the displayMsg (defaults to false)
12846 * @cfg {Number} pageSize
12847 * The number of records to display per page (defaults to 20)
12851 * @cfg {String} displayMsg
12852 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12854 displayMsg : 'Displaying {0} - {1} of {2}',
12856 * @cfg {String} emptyMsg
12857 * The message to display when no records are found (defaults to "No data to display")
12859 emptyMsg : 'No data to display',
12861 * Customizable piece of the default paging text (defaults to "Page")
12864 beforePageText : "Page",
12866 * Customizable piece of the default paging text (defaults to "of %0")
12869 afterPageText : "of {0}",
12871 * Customizable piece of the default paging text (defaults to "First Page")
12874 firstText : "First Page",
12876 * Customizable piece of the default paging text (defaults to "Previous Page")
12879 prevText : "Previous Page",
12881 * Customizable piece of the default paging text (defaults to "Next Page")
12884 nextText : "Next Page",
12886 * Customizable piece of the default paging text (defaults to "Last Page")
12889 lastText : "Last Page",
12891 * Customizable piece of the default paging text (defaults to "Refresh")
12894 refreshText : "Refresh",
12897 renderButtons : function(el){
12898 Roo.PagingToolbar.superclass.render.call(this, el);
12899 this.first = this.addButton({
12900 tooltip: this.firstText,
12901 cls: "x-btn-icon x-grid-page-first",
12903 handler: this.onClick.createDelegate(this, ["first"])
12905 this.prev = this.addButton({
12906 tooltip: this.prevText,
12907 cls: "x-btn-icon x-grid-page-prev",
12909 handler: this.onClick.createDelegate(this, ["prev"])
12911 //this.addSeparator();
12912 this.add(this.beforePageText);
12913 this.field = Roo.get(this.addDom({
12918 cls: "x-grid-page-number"
12920 this.field.on("keydown", this.onPagingKeydown, this);
12921 this.field.on("focus", function(){this.dom.select();});
12922 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12923 this.field.setHeight(18);
12924 //this.addSeparator();
12925 this.next = this.addButton({
12926 tooltip: this.nextText,
12927 cls: "x-btn-icon x-grid-page-next",
12929 handler: this.onClick.createDelegate(this, ["next"])
12931 this.last = this.addButton({
12932 tooltip: this.lastText,
12933 cls: "x-btn-icon x-grid-page-last",
12935 handler: this.onClick.createDelegate(this, ["last"])
12937 //this.addSeparator();
12938 this.loading = this.addButton({
12939 tooltip: this.refreshText,
12940 cls: "x-btn-icon x-grid-loading",
12941 handler: this.onClick.createDelegate(this, ["refresh"])
12944 if(this.displayInfo){
12945 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12950 updateInfo : function(){
12951 if(this.displayEl){
12952 var count = this.ds.getCount();
12953 var msg = count == 0 ?
12957 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12959 this.displayEl.update(msg);
12964 onLoad : function(ds, r, o){
12965 this.cursor = o.params ? o.params.start : 0;
12966 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12968 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12969 this.field.dom.value = ap;
12970 this.first.setDisabled(ap == 1);
12971 this.prev.setDisabled(ap == 1);
12972 this.next.setDisabled(ap == ps);
12973 this.last.setDisabled(ap == ps);
12974 this.loading.enable();
12979 getPageData : function(){
12980 var total = this.ds.getTotalCount();
12983 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12984 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12989 onLoadError : function(){
12990 this.loading.enable();
12994 onPagingKeydown : function(e){
12995 var k = e.getKey();
12996 var d = this.getPageData();
12998 var v = this.field.dom.value, pageNum;
12999 if(!v || isNaN(pageNum = parseInt(v, 10))){
13000 this.field.dom.value = d.activePage;
13003 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13004 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13007 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))
13009 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13010 this.field.dom.value = pageNum;
13011 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13014 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13016 var v = this.field.dom.value, pageNum;
13017 var increment = (e.shiftKey) ? 10 : 1;
13018 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13020 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13021 this.field.dom.value = d.activePage;
13024 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13026 this.field.dom.value = parseInt(v, 10) + increment;
13027 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13028 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13035 beforeLoad : function(){
13037 this.loading.disable();
13042 onClick : function(which){
13046 ds.load({params:{start: 0, limit: this.pageSize}});
13049 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13052 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13055 var total = ds.getTotalCount();
13056 var extra = total % this.pageSize;
13057 var lastStart = extra ? (total - extra) : total-this.pageSize;
13058 ds.load({params:{start: lastStart, limit: this.pageSize}});
13061 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13067 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13068 * @param {Roo.data.Store} store The data store to unbind
13070 unbind : function(ds){
13071 ds.un("beforeload", this.beforeLoad, this);
13072 ds.un("load", this.onLoad, this);
13073 ds.un("loadexception", this.onLoadError, this);
13074 ds.un("remove", this.updateInfo, this);
13075 ds.un("add", this.updateInfo, this);
13076 this.ds = undefined;
13080 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13081 * @param {Roo.data.Store} store The data store to bind
13083 bind : function(ds){
13084 ds.on("beforeload", this.beforeLoad, this);
13085 ds.on("load", this.onLoad, this);
13086 ds.on("loadexception", this.onLoadError, this);
13087 ds.on("remove", this.updateInfo, this);
13088 ds.on("add", this.updateInfo, this);
13093 * Ext JS Library 1.1.1
13094 * Copyright(c) 2006-2007, Ext JS, LLC.
13096 * Originally Released Under LGPL - original licence link has changed is not relivant.
13099 * <script type="text/javascript">
13103 * @class Roo.Resizable
13104 * @extends Roo.util.Observable
13105 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13106 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13107 * 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
13108 * the element will be wrapped for you automatically.</p>
13109 * <p>Here is the list of valid resize handles:</p>
13112 ------ -------------------
13121 'hd' horizontal drag
13124 * <p>Here's an example showing the creation of a typical Resizable:</p>
13126 var resizer = new Roo.Resizable("element-id", {
13134 resizer.on("resize", myHandler);
13136 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13137 * resizer.east.setDisplayed(false);</p>
13138 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13139 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13140 * resize operation's new size (defaults to [0, 0])
13141 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13142 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13143 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13144 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13145 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13146 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13147 * @cfg {Number} width The width of the element in pixels (defaults to null)
13148 * @cfg {Number} height The height of the element in pixels (defaults to null)
13149 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13150 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13151 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13152 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13153 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13154 * in favor of the handles config option (defaults to false)
13155 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13156 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13157 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13158 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13159 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13160 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13161 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13162 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13163 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13164 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13165 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13167 * Create a new resizable component
13168 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13169 * @param {Object} config configuration options
13171 Roo.Resizable = function(el, config)
13173 this.el = Roo.get(el);
13175 if(config && config.wrap){
13176 config.resizeChild = this.el;
13177 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13178 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13179 this.el.setStyle("overflow", "hidden");
13180 this.el.setPositioning(config.resizeChild.getPositioning());
13181 config.resizeChild.clearPositioning();
13182 if(!config.width || !config.height){
13183 var csize = config.resizeChild.getSize();
13184 this.el.setSize(csize.width, csize.height);
13186 if(config.pinned && !config.adjustments){
13187 config.adjustments = "auto";
13191 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13192 this.proxy.unselectable();
13193 this.proxy.enableDisplayMode('block');
13195 Roo.apply(this, config);
13198 this.disableTrackOver = true;
13199 this.el.addClass("x-resizable-pinned");
13201 // if the element isn't positioned, make it relative
13202 var position = this.el.getStyle("position");
13203 if(position != "absolute" && position != "fixed"){
13204 this.el.setStyle("position", "relative");
13206 if(!this.handles){ // no handles passed, must be legacy style
13207 this.handles = 's,e,se';
13208 if(this.multiDirectional){
13209 this.handles += ',n,w';
13212 if(this.handles == "all"){
13213 this.handles = "n s e w ne nw se sw";
13215 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13216 var ps = Roo.Resizable.positions;
13217 for(var i = 0, len = hs.length; i < len; i++){
13218 if(hs[i] && ps[hs[i]]){
13219 var pos = ps[hs[i]];
13220 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13224 this.corner = this.southeast;
13226 // updateBox = the box can move..
13227 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13228 this.updateBox = true;
13231 this.activeHandle = null;
13233 if(this.resizeChild){
13234 if(typeof this.resizeChild == "boolean"){
13235 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13237 this.resizeChild = Roo.get(this.resizeChild, true);
13241 if(this.adjustments == "auto"){
13242 var rc = this.resizeChild;
13243 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13244 if(rc && (hw || hn)){
13245 rc.position("relative");
13246 rc.setLeft(hw ? hw.el.getWidth() : 0);
13247 rc.setTop(hn ? hn.el.getHeight() : 0);
13249 this.adjustments = [
13250 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13251 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13255 if(this.draggable){
13256 this.dd = this.dynamic ?
13257 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13258 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13264 * @event beforeresize
13265 * Fired before resize is allowed. Set enabled to false to cancel resize.
13266 * @param {Roo.Resizable} this
13267 * @param {Roo.EventObject} e The mousedown event
13269 "beforeresize" : true,
13272 * Fired after a resize.
13273 * @param {Roo.Resizable} this
13274 * @param {Number} width The new width
13275 * @param {Number} height The new height
13276 * @param {Roo.EventObject} e The mouseup event
13281 if(this.width !== null && this.height !== null){
13282 this.resizeTo(this.width, this.height);
13284 this.updateChildSize();
13287 this.el.dom.style.zoom = 1;
13289 Roo.Resizable.superclass.constructor.call(this);
13292 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13293 resizeChild : false,
13294 adjustments : [0, 0],
13304 multiDirectional : false,
13305 disableTrackOver : false,
13306 easing : 'easeOutStrong',
13307 widthIncrement : 0,
13308 heightIncrement : 0,
13312 preserveRatio : false,
13313 transparent: false,
13319 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13321 constrainTo: undefined,
13323 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13325 resizeRegion: undefined,
13329 * Perform a manual resize
13330 * @param {Number} width
13331 * @param {Number} height
13333 resizeTo : function(width, height){
13334 this.el.setSize(width, height);
13335 this.updateChildSize();
13336 this.fireEvent("resize", this, width, height, null);
13340 startSizing : function(e, handle){
13341 this.fireEvent("beforeresize", this, e);
13342 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13345 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13346 this.overlay.unselectable();
13347 this.overlay.enableDisplayMode("block");
13348 this.overlay.on("mousemove", this.onMouseMove, this);
13349 this.overlay.on("mouseup", this.onMouseUp, this);
13351 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13353 this.resizing = true;
13354 this.startBox = this.el.getBox();
13355 this.startPoint = e.getXY();
13356 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13357 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13359 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13360 this.overlay.show();
13362 if(this.constrainTo) {
13363 var ct = Roo.get(this.constrainTo);
13364 this.resizeRegion = ct.getRegion().adjust(
13365 ct.getFrameWidth('t'),
13366 ct.getFrameWidth('l'),
13367 -ct.getFrameWidth('b'),
13368 -ct.getFrameWidth('r')
13372 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13374 this.proxy.setBox(this.startBox);
13376 this.proxy.setStyle('visibility', 'visible');
13382 onMouseDown : function(handle, e){
13385 this.activeHandle = handle;
13386 this.startSizing(e, handle);
13391 onMouseUp : function(e){
13392 var size = this.resizeElement();
13393 this.resizing = false;
13395 this.overlay.hide();
13397 this.fireEvent("resize", this, size.width, size.height, e);
13401 updateChildSize : function(){
13402 if(this.resizeChild){
13404 var child = this.resizeChild;
13405 var adj = this.adjustments;
13406 if(el.dom.offsetWidth){
13407 var b = el.getSize(true);
13408 child.setSize(b.width+adj[0], b.height+adj[1]);
13410 // Second call here for IE
13411 // The first call enables instant resizing and
13412 // the second call corrects scroll bars if they
13415 setTimeout(function(){
13416 if(el.dom.offsetWidth){
13417 var b = el.getSize(true);
13418 child.setSize(b.width+adj[0], b.height+adj[1]);
13426 snap : function(value, inc, min){
13427 if(!inc || !value) return value;
13428 var newValue = value;
13429 var m = value % inc;
13432 newValue = value + (inc-m);
13434 newValue = value - m;
13437 return Math.max(min, newValue);
13441 resizeElement : function(){
13442 var box = this.proxy.getBox();
13443 if(this.updateBox){
13444 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13446 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13448 this.updateChildSize();
13456 constrain : function(v, diff, m, mx){
13459 }else if(v - diff > mx){
13466 onMouseMove : function(e){
13468 try{// try catch so if something goes wrong the user doesn't get hung
13470 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13474 //var curXY = this.startPoint;
13475 var curSize = this.curSize || this.startBox;
13476 var x = this.startBox.x, y = this.startBox.y;
13477 var ox = x, oy = y;
13478 var w = curSize.width, h = curSize.height;
13479 var ow = w, oh = h;
13480 var mw = this.minWidth, mh = this.minHeight;
13481 var mxw = this.maxWidth, mxh = this.maxHeight;
13482 var wi = this.widthIncrement;
13483 var hi = this.heightIncrement;
13485 var eventXY = e.getXY();
13486 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13487 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13489 var pos = this.activeHandle.position;
13494 w = Math.min(Math.max(mw, w), mxw);
13499 h = Math.min(Math.max(mh, h), mxh);
13504 w = Math.min(Math.max(mw, w), mxw);
13505 h = Math.min(Math.max(mh, h), mxh);
13508 diffY = this.constrain(h, diffY, mh, mxh);
13515 var adiffX = Math.abs(diffX);
13516 var sub = (adiffX % wi); // how much
13517 if (sub > (wi/2)) { // far enough to snap
13518 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13520 // remove difference..
13521 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13525 x = Math.max(this.minX, x);
13528 diffX = this.constrain(w, diffX, mw, mxw);
13534 w = Math.min(Math.max(mw, w), mxw);
13535 diffY = this.constrain(h, diffY, mh, mxh);
13540 diffX = this.constrain(w, diffX, mw, mxw);
13541 diffY = this.constrain(h, diffY, mh, mxh);
13548 diffX = this.constrain(w, diffX, mw, mxw);
13550 h = Math.min(Math.max(mh, h), mxh);
13556 var sw = this.snap(w, wi, mw);
13557 var sh = this.snap(h, hi, mh);
13558 if(sw != w || sh != h){
13581 if(this.preserveRatio){
13586 h = Math.min(Math.max(mh, h), mxh);
13591 w = Math.min(Math.max(mw, w), mxw);
13596 w = Math.min(Math.max(mw, w), mxw);
13602 w = Math.min(Math.max(mw, w), mxw);
13608 h = Math.min(Math.max(mh, h), mxh);
13616 h = Math.min(Math.max(mh, h), mxh);
13626 h = Math.min(Math.max(mh, h), mxh);
13634 if (pos == 'hdrag') {
13637 this.proxy.setBounds(x, y, w, h);
13639 this.resizeElement();
13646 handleOver : function(){
13648 this.el.addClass("x-resizable-over");
13653 handleOut : function(){
13654 if(!this.resizing){
13655 this.el.removeClass("x-resizable-over");
13660 * Returns the element this component is bound to.
13661 * @return {Roo.Element}
13663 getEl : function(){
13668 * Returns the resizeChild element (or null).
13669 * @return {Roo.Element}
13671 getResizeChild : function(){
13672 return this.resizeChild;
13676 * Destroys this resizable. If the element was wrapped and
13677 * removeEl is not true then the element remains.
13678 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13680 destroy : function(removeEl){
13681 this.proxy.remove();
13683 this.overlay.removeAllListeners();
13684 this.overlay.remove();
13686 var ps = Roo.Resizable.positions;
13688 if(typeof ps[k] != "function" && this[ps[k]]){
13689 var h = this[ps[k]];
13690 h.el.removeAllListeners();
13695 this.el.update("");
13702 // hash to map config positions to true positions
13703 Roo.Resizable.positions = {
13704 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13709 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13711 // only initialize the template if resizable is used
13712 var tpl = Roo.DomHelper.createTemplate(
13713 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13716 Roo.Resizable.Handle.prototype.tpl = tpl;
13718 this.position = pos;
13720 // show north drag fro topdra
13721 var handlepos = pos == 'hdrag' ? 'north' : pos;
13723 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13724 if (pos == 'hdrag') {
13725 this.el.setStyle('cursor', 'pointer');
13727 this.el.unselectable();
13729 this.el.setOpacity(0);
13731 this.el.on("mousedown", this.onMouseDown, this);
13732 if(!disableTrackOver){
13733 this.el.on("mouseover", this.onMouseOver, this);
13734 this.el.on("mouseout", this.onMouseOut, this);
13739 Roo.Resizable.Handle.prototype = {
13740 afterResize : function(rz){
13744 onMouseDown : function(e){
13745 this.rz.onMouseDown(this, e);
13748 onMouseOver : function(e){
13749 this.rz.handleOver(this, e);
13752 onMouseOut : function(e){
13753 this.rz.handleOut(this, e);
13757 * Ext JS Library 1.1.1
13758 * Copyright(c) 2006-2007, Ext JS, LLC.
13760 * Originally Released Under LGPL - original licence link has changed is not relivant.
13763 * <script type="text/javascript">
13767 * @class Roo.Editor
13768 * @extends Roo.Component
13769 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13771 * Create a new Editor
13772 * @param {Roo.form.Field} field The Field object (or descendant)
13773 * @param {Object} config The config object
13775 Roo.Editor = function(field, config){
13776 Roo.Editor.superclass.constructor.call(this, config);
13777 this.field = field;
13780 * @event beforestartedit
13781 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13782 * false from the handler of this event.
13783 * @param {Editor} this
13784 * @param {Roo.Element} boundEl The underlying element bound to this editor
13785 * @param {Mixed} value The field value being set
13787 "beforestartedit" : true,
13790 * Fires when this editor is displayed
13791 * @param {Roo.Element} boundEl The underlying element bound to this editor
13792 * @param {Mixed} value The starting field value
13794 "startedit" : true,
13796 * @event beforecomplete
13797 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13798 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13799 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13800 * event will not fire since no edit actually occurred.
13801 * @param {Editor} this
13802 * @param {Mixed} value The current field value
13803 * @param {Mixed} startValue The original field value
13805 "beforecomplete" : true,
13808 * Fires after editing is complete and any changed value has been written to the underlying field.
13809 * @param {Editor} this
13810 * @param {Mixed} value The current field value
13811 * @param {Mixed} startValue The original field value
13815 * @event specialkey
13816 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13817 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13818 * @param {Roo.form.Field} this
13819 * @param {Roo.EventObject} e The event object
13821 "specialkey" : true
13825 Roo.extend(Roo.Editor, Roo.Component, {
13827 * @cfg {Boolean/String} autosize
13828 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13829 * or "height" to adopt the height only (defaults to false)
13832 * @cfg {Boolean} revertInvalid
13833 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13834 * validation fails (defaults to true)
13837 * @cfg {Boolean} ignoreNoChange
13838 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13839 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13840 * will never be ignored.
13843 * @cfg {Boolean} hideEl
13844 * False to keep the bound element visible while the editor is displayed (defaults to true)
13847 * @cfg {Mixed} value
13848 * The data value of the underlying field (defaults to "")
13852 * @cfg {String} alignment
13853 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13857 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13858 * for bottom-right shadow (defaults to "frame")
13862 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13866 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13868 completeOnEnter : false,
13870 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13872 cancelOnEsc : false,
13874 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13879 onRender : function(ct, position){
13880 this.el = new Roo.Layer({
13881 shadow: this.shadow,
13887 constrain: this.constrain
13889 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13890 if(this.field.msgTarget != 'title'){
13891 this.field.msgTarget = 'qtip';
13893 this.field.render(this.el);
13895 this.field.el.dom.setAttribute('autocomplete', 'off');
13897 this.field.on("specialkey", this.onSpecialKey, this);
13898 if(this.swallowKeys){
13899 this.field.el.swallowEvent(['keydown','keypress']);
13902 this.field.on("blur", this.onBlur, this);
13903 if(this.field.grow){
13904 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13908 onSpecialKey : function(field, e){
13909 //Roo.log('editor onSpecialKey');
13910 if(this.completeOnEnter && e.getKey() == e.ENTER){
13912 this.completeEdit();
13913 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13916 this.fireEvent('specialkey', field, e);
13921 * Starts the editing process and shows the editor.
13922 * @param {String/HTMLElement/Element} el The element to edit
13923 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13924 * to the innerHTML of el.
13926 startEdit : function(el, value){
13928 this.completeEdit();
13930 this.boundEl = Roo.get(el);
13931 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13932 if(!this.rendered){
13933 this.render(this.parentEl || document.body);
13935 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13938 this.startValue = v;
13939 this.field.setValue(v);
13941 var sz = this.boundEl.getSize();
13942 switch(this.autoSize){
13944 this.setSize(sz.width, "");
13947 this.setSize("", sz.height);
13950 this.setSize(sz.width, sz.height);
13953 this.el.alignTo(this.boundEl, this.alignment);
13954 this.editing = true;
13956 Roo.QuickTips.disable();
13962 * Sets the height and width of this editor.
13963 * @param {Number} width The new width
13964 * @param {Number} height The new height
13966 setSize : function(w, h){
13967 this.field.setSize(w, h);
13974 * Realigns the editor to the bound field based on the current alignment config value.
13976 realign : function(){
13977 this.el.alignTo(this.boundEl, this.alignment);
13981 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13982 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13984 completeEdit : function(remainVisible){
13988 var v = this.getValue();
13989 if(this.revertInvalid !== false && !this.field.isValid()){
13990 v = this.startValue;
13991 this.cancelEdit(true);
13993 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13994 this.editing = false;
13998 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13999 this.editing = false;
14000 if(this.updateEl && this.boundEl){
14001 this.boundEl.update(v);
14003 if(remainVisible !== true){
14006 this.fireEvent("complete", this, v, this.startValue);
14011 onShow : function(){
14013 if(this.hideEl !== false){
14014 this.boundEl.hide();
14017 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14018 this.fixIEFocus = true;
14019 this.deferredFocus.defer(50, this);
14021 this.field.focus();
14023 this.fireEvent("startedit", this.boundEl, this.startValue);
14026 deferredFocus : function(){
14028 this.field.focus();
14033 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14034 * reverted to the original starting value.
14035 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14036 * cancel (defaults to false)
14038 cancelEdit : function(remainVisible){
14040 this.setValue(this.startValue);
14041 if(remainVisible !== true){
14048 onBlur : function(){
14049 if(this.allowBlur !== true && this.editing){
14050 this.completeEdit();
14055 onHide : function(){
14057 this.completeEdit();
14061 if(this.field.collapse){
14062 this.field.collapse();
14065 if(this.hideEl !== false){
14066 this.boundEl.show();
14069 Roo.QuickTips.enable();
14074 * Sets the data value of the editor
14075 * @param {Mixed} value Any valid value supported by the underlying field
14077 setValue : function(v){
14078 this.field.setValue(v);
14082 * Gets the data value of the editor
14083 * @return {Mixed} The data value
14085 getValue : function(){
14086 return this.field.getValue();
14090 * Ext JS Library 1.1.1
14091 * Copyright(c) 2006-2007, Ext JS, LLC.
14093 * Originally Released Under LGPL - original licence link has changed is not relivant.
14096 * <script type="text/javascript">
14100 * @class Roo.BasicDialog
14101 * @extends Roo.util.Observable
14102 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14104 var dlg = new Roo.BasicDialog("my-dlg", {
14113 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14114 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14115 dlg.addButton('Cancel', dlg.hide, dlg);
14118 <b>A Dialog should always be a direct child of the body element.</b>
14119 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14120 * @cfg {String} title Default text to display in the title bar (defaults to null)
14121 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14122 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14123 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14124 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14125 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14126 * (defaults to null with no animation)
14127 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14128 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14129 * property for valid values (defaults to 'all')
14130 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14131 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14132 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14133 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14134 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14135 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14136 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14137 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14138 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14139 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14140 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14141 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14142 * draggable = true (defaults to false)
14143 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14144 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14145 * shadow (defaults to false)
14146 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14147 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14148 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14149 * @cfg {Array} buttons Array of buttons
14150 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14152 * Create a new BasicDialog.
14153 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14154 * @param {Object} config Configuration options
14156 Roo.BasicDialog = function(el, config){
14157 this.el = Roo.get(el);
14158 var dh = Roo.DomHelper;
14159 if(!this.el && config && config.autoCreate){
14160 if(typeof config.autoCreate == "object"){
14161 if(!config.autoCreate.id){
14162 config.autoCreate.id = el;
14164 this.el = dh.append(document.body,
14165 config.autoCreate, true);
14167 this.el = dh.append(document.body,
14168 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14172 el.setDisplayed(true);
14173 el.hide = this.hideAction;
14175 el.addClass("x-dlg");
14177 Roo.apply(this, config);
14179 this.proxy = el.createProxy("x-dlg-proxy");
14180 this.proxy.hide = this.hideAction;
14181 this.proxy.setOpacity(.5);
14185 el.setWidth(config.width);
14188 el.setHeight(config.height);
14190 this.size = el.getSize();
14191 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14192 this.xy = [config.x,config.y];
14194 this.xy = el.getCenterXY(true);
14196 /** The header element @type Roo.Element */
14197 this.header = el.child("> .x-dlg-hd");
14198 /** The body element @type Roo.Element */
14199 this.body = el.child("> .x-dlg-bd");
14200 /** The footer element @type Roo.Element */
14201 this.footer = el.child("> .x-dlg-ft");
14204 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14207 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14210 this.header.unselectable();
14212 this.header.update(this.title);
14214 // this element allows the dialog to be focused for keyboard event
14215 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14216 this.focusEl.swallowEvent("click", true);
14218 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14220 // wrap the body and footer for special rendering
14221 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14223 this.bwrap.dom.appendChild(this.footer.dom);
14226 this.bg = this.el.createChild({
14227 tag: "div", cls:"x-dlg-bg",
14228 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14230 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14233 if(this.autoScroll !== false && !this.autoTabs){
14234 this.body.setStyle("overflow", "auto");
14237 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14239 if(this.closable !== false){
14240 this.el.addClass("x-dlg-closable");
14241 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14242 this.close.on("click", this.closeClick, this);
14243 this.close.addClassOnOver("x-dlg-close-over");
14245 if(this.collapsible !== false){
14246 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14247 this.collapseBtn.on("click", this.collapseClick, this);
14248 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14249 this.header.on("dblclick", this.collapseClick, this);
14251 if(this.resizable !== false){
14252 this.el.addClass("x-dlg-resizable");
14253 this.resizer = new Roo.Resizable(el, {
14254 minWidth: this.minWidth || 80,
14255 minHeight:this.minHeight || 80,
14256 handles: this.resizeHandles || "all",
14259 this.resizer.on("beforeresize", this.beforeResize, this);
14260 this.resizer.on("resize", this.onResize, this);
14262 if(this.draggable !== false){
14263 el.addClass("x-dlg-draggable");
14264 if (!this.proxyDrag) {
14265 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14268 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14270 dd.setHandleElId(this.header.id);
14271 dd.endDrag = this.endMove.createDelegate(this);
14272 dd.startDrag = this.startMove.createDelegate(this);
14273 dd.onDrag = this.onDrag.createDelegate(this);
14278 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14279 this.mask.enableDisplayMode("block");
14281 this.el.addClass("x-dlg-modal");
14284 this.shadow = new Roo.Shadow({
14285 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14286 offset : this.shadowOffset
14289 this.shadowOffset = 0;
14291 if(Roo.useShims && this.shim !== false){
14292 this.shim = this.el.createShim();
14293 this.shim.hide = this.hideAction;
14301 if (this.buttons) {
14302 var bts= this.buttons;
14304 Roo.each(bts, function(b) {
14313 * Fires when a key is pressed
14314 * @param {Roo.BasicDialog} this
14315 * @param {Roo.EventObject} e
14320 * Fires when this dialog is moved by the user.
14321 * @param {Roo.BasicDialog} this
14322 * @param {Number} x The new page X
14323 * @param {Number} y The new page Y
14328 * Fires when this dialog is resized by the user.
14329 * @param {Roo.BasicDialog} this
14330 * @param {Number} width The new width
14331 * @param {Number} height The new height
14335 * @event beforehide
14336 * Fires before this dialog is hidden.
14337 * @param {Roo.BasicDialog} this
14339 "beforehide" : true,
14342 * Fires when this dialog is hidden.
14343 * @param {Roo.BasicDialog} this
14347 * @event beforeshow
14348 * Fires before this dialog is shown.
14349 * @param {Roo.BasicDialog} this
14351 "beforeshow" : true,
14354 * Fires when this dialog is shown.
14355 * @param {Roo.BasicDialog} this
14359 el.on("keydown", this.onKeyDown, this);
14360 el.on("mousedown", this.toFront, this);
14361 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14363 Roo.DialogManager.register(this);
14364 Roo.BasicDialog.superclass.constructor.call(this);
14367 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14368 shadowOffset: Roo.isIE ? 6 : 5,
14371 minButtonWidth: 75,
14372 defaultButton: null,
14373 buttonAlign: "right",
14378 * Sets the dialog title text
14379 * @param {String} text The title text to display
14380 * @return {Roo.BasicDialog} this
14382 setTitle : function(text){
14383 this.header.update(text);
14388 closeClick : function(){
14393 collapseClick : function(){
14394 this[this.collapsed ? "expand" : "collapse"]();
14398 * Collapses the dialog to its minimized state (only the title bar is visible).
14399 * Equivalent to the user clicking the collapse dialog button.
14401 collapse : function(){
14402 if(!this.collapsed){
14403 this.collapsed = true;
14404 this.el.addClass("x-dlg-collapsed");
14405 this.restoreHeight = this.el.getHeight();
14406 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14411 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14412 * clicking the expand dialog button.
14414 expand : function(){
14415 if(this.collapsed){
14416 this.collapsed = false;
14417 this.el.removeClass("x-dlg-collapsed");
14418 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14423 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14424 * @return {Roo.TabPanel} The tabs component
14426 initTabs : function(){
14427 var tabs = this.getTabs();
14428 while(tabs.getTab(0)){
14431 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14433 tabs.addTab(Roo.id(dom), dom.title);
14441 beforeResize : function(){
14442 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14446 onResize : function(){
14447 this.refreshSize();
14448 this.syncBodyHeight();
14449 this.adjustAssets();
14451 this.fireEvent("resize", this, this.size.width, this.size.height);
14455 onKeyDown : function(e){
14456 if(this.isVisible()){
14457 this.fireEvent("keydown", this, e);
14462 * Resizes the dialog.
14463 * @param {Number} width
14464 * @param {Number} height
14465 * @return {Roo.BasicDialog} this
14467 resizeTo : function(width, height){
14468 this.el.setSize(width, height);
14469 this.size = {width: width, height: height};
14470 this.syncBodyHeight();
14471 if(this.fixedcenter){
14474 if(this.isVisible()){
14475 this.constrainXY();
14476 this.adjustAssets();
14478 this.fireEvent("resize", this, width, height);
14484 * Resizes the dialog to fit the specified content size.
14485 * @param {Number} width
14486 * @param {Number} height
14487 * @return {Roo.BasicDialog} this
14489 setContentSize : function(w, h){
14490 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14491 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14492 //if(!this.el.isBorderBox()){
14493 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14494 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14497 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14498 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14500 this.resizeTo(w, h);
14505 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14506 * executed in response to a particular key being pressed while the dialog is active.
14507 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14508 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14509 * @param {Function} fn The function to call
14510 * @param {Object} scope (optional) The scope of the function
14511 * @return {Roo.BasicDialog} this
14513 addKeyListener : function(key, fn, scope){
14514 var keyCode, shift, ctrl, alt;
14515 if(typeof key == "object" && !(key instanceof Array)){
14516 keyCode = key["key"];
14517 shift = key["shift"];
14518 ctrl = key["ctrl"];
14523 var handler = function(dlg, e){
14524 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14525 var k = e.getKey();
14526 if(keyCode instanceof Array){
14527 for(var i = 0, len = keyCode.length; i < len; i++){
14528 if(keyCode[i] == k){
14529 fn.call(scope || window, dlg, k, e);
14535 fn.call(scope || window, dlg, k, e);
14540 this.on("keydown", handler);
14545 * Returns the TabPanel component (creates it if it doesn't exist).
14546 * Note: If you wish to simply check for the existence of tabs without creating them,
14547 * check for a null 'tabs' property.
14548 * @return {Roo.TabPanel} The tabs component
14550 getTabs : function(){
14552 this.el.addClass("x-dlg-auto-tabs");
14553 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14554 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14560 * Adds a button to the footer section of the dialog.
14561 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14562 * object or a valid Roo.DomHelper element config
14563 * @param {Function} handler The function called when the button is clicked
14564 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14565 * @return {Roo.Button} The new button
14567 addButton : function(config, handler, scope){
14568 var dh = Roo.DomHelper;
14570 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14572 if(!this.btnContainer){
14573 var tb = this.footer.createChild({
14575 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14576 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14578 this.btnContainer = tb.firstChild.firstChild.firstChild;
14583 minWidth: this.minButtonWidth,
14586 if(typeof config == "string"){
14587 bconfig.text = config;
14590 bconfig.dhconfig = config;
14592 Roo.apply(bconfig, config);
14596 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14597 bconfig.position = Math.max(0, bconfig.position);
14598 fc = this.btnContainer.childNodes[bconfig.position];
14601 var btn = new Roo.Button(
14603 this.btnContainer.insertBefore(document.createElement("td"),fc)
14604 : this.btnContainer.appendChild(document.createElement("td")),
14605 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14608 this.syncBodyHeight();
14611 * Array of all the buttons that have been added to this dialog via addButton
14616 this.buttons.push(btn);
14621 * Sets the default button to be focused when the dialog is displayed.
14622 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14623 * @return {Roo.BasicDialog} this
14625 setDefaultButton : function(btn){
14626 this.defaultButton = btn;
14631 getHeaderFooterHeight : function(safe){
14634 height += this.header.getHeight();
14637 var fm = this.footer.getMargins();
14638 height += (this.footer.getHeight()+fm.top+fm.bottom);
14640 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14641 height += this.centerBg.getPadding("tb");
14646 syncBodyHeight : function(){
14647 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14648 var height = this.size.height - this.getHeaderFooterHeight(false);
14649 bd.setHeight(height-bd.getMargins("tb"));
14650 var hh = this.header.getHeight();
14651 var h = this.size.height-hh;
14653 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14654 bw.setHeight(h-cb.getPadding("tb"));
14655 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14656 bd.setWidth(bw.getWidth(true));
14658 this.tabs.syncHeight();
14660 this.tabs.el.repaint();
14666 * Restores the previous state of the dialog if Roo.state is configured.
14667 * @return {Roo.BasicDialog} this
14669 restoreState : function(){
14670 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14671 if(box && box.width){
14672 this.xy = [box.x, box.y];
14673 this.resizeTo(box.width, box.height);
14679 beforeShow : function(){
14681 if(this.fixedcenter){
14682 this.xy = this.el.getCenterXY(true);
14685 Roo.get(document.body).addClass("x-body-masked");
14686 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14689 this.constrainXY();
14693 animShow : function(){
14694 var b = Roo.get(this.animateTarget).getBox();
14695 this.proxy.setSize(b.width, b.height);
14696 this.proxy.setLocation(b.x, b.y);
14698 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14699 true, .35, this.showEl.createDelegate(this));
14703 * Shows the dialog.
14704 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14705 * @return {Roo.BasicDialog} this
14707 show : function(animateTarget){
14708 if (this.fireEvent("beforeshow", this) === false){
14711 if(this.syncHeightBeforeShow){
14712 this.syncBodyHeight();
14713 }else if(this.firstShow){
14714 this.firstShow = false;
14715 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14717 this.animateTarget = animateTarget || this.animateTarget;
14718 if(!this.el.isVisible()){
14720 if(this.animateTarget && Roo.get(this.animateTarget)){
14730 showEl : function(){
14732 this.el.setXY(this.xy);
14734 this.adjustAssets(true);
14737 // IE peekaboo bug - fix found by Dave Fenwick
14741 this.fireEvent("show", this);
14745 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14746 * dialog itself will receive focus.
14748 focus : function(){
14749 if(this.defaultButton){
14750 this.defaultButton.focus();
14752 this.focusEl.focus();
14757 constrainXY : function(){
14758 if(this.constraintoviewport !== false){
14759 if(!this.viewSize){
14760 if(this.container){
14761 var s = this.container.getSize();
14762 this.viewSize = [s.width, s.height];
14764 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14767 var s = Roo.get(this.container||document).getScroll();
14769 var x = this.xy[0], y = this.xy[1];
14770 var w = this.size.width, h = this.size.height;
14771 var vw = this.viewSize[0], vh = this.viewSize[1];
14772 // only move it if it needs it
14774 // first validate right/bottom
14775 if(x + w > vw+s.left){
14779 if(y + h > vh+s.top){
14783 // then make sure top/left isn't negative
14795 if(this.isVisible()){
14796 this.el.setLocation(x, y);
14797 this.adjustAssets();
14804 onDrag : function(){
14805 if(!this.proxyDrag){
14806 this.xy = this.el.getXY();
14807 this.adjustAssets();
14812 adjustAssets : function(doShow){
14813 var x = this.xy[0], y = this.xy[1];
14814 var w = this.size.width, h = this.size.height;
14815 if(doShow === true){
14817 this.shadow.show(this.el);
14823 if(this.shadow && this.shadow.isVisible()){
14824 this.shadow.show(this.el);
14826 if(this.shim && this.shim.isVisible()){
14827 this.shim.setBounds(x, y, w, h);
14832 adjustViewport : function(w, h){
14834 w = Roo.lib.Dom.getViewWidth();
14835 h = Roo.lib.Dom.getViewHeight();
14838 this.viewSize = [w, h];
14839 if(this.modal && this.mask.isVisible()){
14840 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14841 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14843 if(this.isVisible()){
14844 this.constrainXY();
14849 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14850 * shadow, proxy, mask, etc.) Also removes all event listeners.
14851 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14853 destroy : function(removeEl){
14854 if(this.isVisible()){
14855 this.animateTarget = null;
14858 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14860 this.tabs.destroy(removeEl);
14873 for(var i = 0, len = this.buttons.length; i < len; i++){
14874 this.buttons[i].destroy();
14877 this.el.removeAllListeners();
14878 if(removeEl === true){
14879 this.el.update("");
14882 Roo.DialogManager.unregister(this);
14886 startMove : function(){
14887 if(this.proxyDrag){
14890 if(this.constraintoviewport !== false){
14891 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14896 endMove : function(){
14897 if(!this.proxyDrag){
14898 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14900 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14903 this.refreshSize();
14904 this.adjustAssets();
14906 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14910 * Brings this dialog to the front of any other visible dialogs
14911 * @return {Roo.BasicDialog} this
14913 toFront : function(){
14914 Roo.DialogManager.bringToFront(this);
14919 * Sends this dialog to the back (under) of any other visible dialogs
14920 * @return {Roo.BasicDialog} this
14922 toBack : function(){
14923 Roo.DialogManager.sendToBack(this);
14928 * Centers this dialog in the viewport
14929 * @return {Roo.BasicDialog} this
14931 center : function(){
14932 var xy = this.el.getCenterXY(true);
14933 this.moveTo(xy[0], xy[1]);
14938 * Moves the dialog's top-left corner to the specified point
14939 * @param {Number} x
14940 * @param {Number} y
14941 * @return {Roo.BasicDialog} this
14943 moveTo : function(x, y){
14945 if(this.isVisible()){
14946 this.el.setXY(this.xy);
14947 this.adjustAssets();
14953 * Aligns the dialog to the specified element
14954 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14955 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14956 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14957 * @return {Roo.BasicDialog} this
14959 alignTo : function(element, position, offsets){
14960 this.xy = this.el.getAlignToXY(element, position, offsets);
14961 if(this.isVisible()){
14962 this.el.setXY(this.xy);
14963 this.adjustAssets();
14969 * Anchors an element to another element and realigns it when the window is resized.
14970 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14971 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14972 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14973 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14974 * is a number, it is used as the buffer delay (defaults to 50ms).
14975 * @return {Roo.BasicDialog} this
14977 anchorTo : function(el, alignment, offsets, monitorScroll){
14978 var action = function(){
14979 this.alignTo(el, alignment, offsets);
14981 Roo.EventManager.onWindowResize(action, this);
14982 var tm = typeof monitorScroll;
14983 if(tm != 'undefined'){
14984 Roo.EventManager.on(window, 'scroll', action, this,
14985 {buffer: tm == 'number' ? monitorScroll : 50});
14992 * Returns true if the dialog is visible
14993 * @return {Boolean}
14995 isVisible : function(){
14996 return this.el.isVisible();
15000 animHide : function(callback){
15001 var b = Roo.get(this.animateTarget).getBox();
15003 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15005 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15006 this.hideEl.createDelegate(this, [callback]));
15010 * Hides the dialog.
15011 * @param {Function} callback (optional) Function to call when the dialog is hidden
15012 * @return {Roo.BasicDialog} this
15014 hide : function(callback){
15015 if (this.fireEvent("beforehide", this) === false){
15019 this.shadow.hide();
15024 // sometimes animateTarget seems to get set.. causing problems...
15025 // this just double checks..
15026 if(this.animateTarget && Roo.get(this.animateTarget)) {
15027 this.animHide(callback);
15030 this.hideEl(callback);
15036 hideEl : function(callback){
15040 Roo.get(document.body).removeClass("x-body-masked");
15042 this.fireEvent("hide", this);
15043 if(typeof callback == "function"){
15049 hideAction : function(){
15050 this.setLeft("-10000px");
15051 this.setTop("-10000px");
15052 this.setStyle("visibility", "hidden");
15056 refreshSize : function(){
15057 this.size = this.el.getSize();
15058 this.xy = this.el.getXY();
15059 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15063 // z-index is managed by the DialogManager and may be overwritten at any time
15064 setZIndex : function(index){
15066 this.mask.setStyle("z-index", index);
15069 this.shim.setStyle("z-index", ++index);
15072 this.shadow.setZIndex(++index);
15074 this.el.setStyle("z-index", ++index);
15076 this.proxy.setStyle("z-index", ++index);
15079 this.resizer.proxy.setStyle("z-index", ++index);
15082 this.lastZIndex = index;
15086 * Returns the element for this dialog
15087 * @return {Roo.Element} The underlying dialog Element
15089 getEl : function(){
15095 * @class Roo.DialogManager
15096 * Provides global access to BasicDialogs that have been created and
15097 * support for z-indexing (layering) multiple open dialogs.
15099 Roo.DialogManager = function(){
15101 var accessList = [];
15105 var sortDialogs = function(d1, d2){
15106 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15110 var orderDialogs = function(){
15111 accessList.sort(sortDialogs);
15112 var seed = Roo.DialogManager.zseed;
15113 for(var i = 0, len = accessList.length; i < len; i++){
15114 var dlg = accessList[i];
15116 dlg.setZIndex(seed + (i*10));
15123 * The starting z-index for BasicDialogs (defaults to 9000)
15124 * @type Number The z-index value
15129 register : function(dlg){
15130 list[dlg.id] = dlg;
15131 accessList.push(dlg);
15135 unregister : function(dlg){
15136 delete list[dlg.id];
15139 if(!accessList.indexOf){
15140 for( i = 0, len = accessList.length; i < len; i++){
15141 if(accessList[i] == dlg){
15142 accessList.splice(i, 1);
15147 i = accessList.indexOf(dlg);
15149 accessList.splice(i, 1);
15155 * Gets a registered dialog by id
15156 * @param {String/Object} id The id of the dialog or a dialog
15157 * @return {Roo.BasicDialog} this
15159 get : function(id){
15160 return typeof id == "object" ? id : list[id];
15164 * Brings the specified dialog to the front
15165 * @param {String/Object} dlg The id of the dialog or a dialog
15166 * @return {Roo.BasicDialog} this
15168 bringToFront : function(dlg){
15169 dlg = this.get(dlg);
15172 dlg._lastAccess = new Date().getTime();
15179 * Sends the specified dialog to the back
15180 * @param {String/Object} dlg The id of the dialog or a dialog
15181 * @return {Roo.BasicDialog} this
15183 sendToBack : function(dlg){
15184 dlg = this.get(dlg);
15185 dlg._lastAccess = -(new Date().getTime());
15191 * Hides all dialogs
15193 hideAll : function(){
15194 for(var id in list){
15195 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15204 * @class Roo.LayoutDialog
15205 * @extends Roo.BasicDialog
15206 * Dialog which provides adjustments for working with a layout in a Dialog.
15207 * Add your necessary layout config options to the dialog's config.<br>
15208 * Example usage (including a nested layout):
15211 dialog = new Roo.LayoutDialog("download-dlg", {
15220 // layout config merges with the dialog config
15222 tabPosition: "top",
15223 alwaysShowTabs: true
15226 dialog.addKeyListener(27, dialog.hide, dialog);
15227 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15228 dialog.addButton("Build It!", this.getDownload, this);
15230 // we can even add nested layouts
15231 var innerLayout = new Roo.BorderLayout("dl-inner", {
15241 innerLayout.beginUpdate();
15242 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15243 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15244 innerLayout.endUpdate(true);
15246 var layout = dialog.getLayout();
15247 layout.beginUpdate();
15248 layout.add("center", new Roo.ContentPanel("standard-panel",
15249 {title: "Download the Source", fitToFrame:true}));
15250 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15251 {title: "Build your own roo.js"}));
15252 layout.getRegion("center").showPanel(sp);
15253 layout.endUpdate();
15257 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15258 * @param {Object} config configuration options
15260 Roo.LayoutDialog = function(el, cfg){
15263 if (typeof(cfg) == 'undefined') {
15264 config = Roo.apply({}, el);
15265 // not sure why we use documentElement here.. - it should always be body.
15266 // IE7 borks horribly if we use documentElement.
15267 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15268 //config.autoCreate = true;
15272 config.autoTabs = false;
15273 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15274 this.body.setStyle({overflow:"hidden", position:"relative"});
15275 this.layout = new Roo.BorderLayout(this.body.dom, config);
15276 this.layout.monitorWindowResize = false;
15277 this.el.addClass("x-dlg-auto-layout");
15278 // fix case when center region overwrites center function
15279 this.center = Roo.BasicDialog.prototype.center;
15280 this.on("show", this.layout.layout, this.layout, true);
15281 if (config.items) {
15282 var xitems = config.items;
15283 delete config.items;
15284 Roo.each(xitems, this.addxtype, this);
15289 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15291 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15294 endUpdate : function(){
15295 this.layout.endUpdate();
15299 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15302 beginUpdate : function(){
15303 this.layout.beginUpdate();
15307 * Get the BorderLayout for this dialog
15308 * @return {Roo.BorderLayout}
15310 getLayout : function(){
15311 return this.layout;
15314 showEl : function(){
15315 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15317 this.layout.layout();
15322 // Use the syncHeightBeforeShow config option to control this automatically
15323 syncBodyHeight : function(){
15324 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15325 if(this.layout){this.layout.layout();}
15329 * Add an xtype element (actually adds to the layout.)
15330 * @return {Object} xdata xtype object data.
15333 addxtype : function(c) {
15334 return this.layout.addxtype(c);
15338 * Ext JS Library 1.1.1
15339 * Copyright(c) 2006-2007, Ext JS, LLC.
15341 * Originally Released Under LGPL - original licence link has changed is not relivant.
15344 * <script type="text/javascript">
15348 * @class Roo.MessageBox
15349 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15353 Roo.Msg.alert('Status', 'Changes saved successfully.');
15355 // Prompt for user data:
15356 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15358 // process text value...
15362 // Show a dialog using config options:
15364 title:'Save Changes?',
15365 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15366 buttons: Roo.Msg.YESNOCANCEL,
15373 Roo.MessageBox = function(){
15374 var dlg, opt, mask, waitTimer;
15375 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15376 var buttons, activeTextEl, bwidth;
15379 var handleButton = function(button){
15381 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15385 var handleHide = function(){
15386 if(opt && opt.cls){
15387 dlg.el.removeClass(opt.cls);
15390 Roo.TaskMgr.stop(waitTimer);
15396 var updateButtons = function(b){
15399 buttons["ok"].hide();
15400 buttons["cancel"].hide();
15401 buttons["yes"].hide();
15402 buttons["no"].hide();
15403 dlg.footer.dom.style.display = 'none';
15406 dlg.footer.dom.style.display = '';
15407 for(var k in buttons){
15408 if(typeof buttons[k] != "function"){
15411 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15412 width += buttons[k].el.getWidth()+15;
15422 var handleEsc = function(d, k, e){
15423 if(opt && opt.closable !== false){
15433 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15434 * @return {Roo.BasicDialog} The BasicDialog element
15436 getDialog : function(){
15438 dlg = new Roo.BasicDialog("x-msg-box", {
15443 constraintoviewport:false,
15445 collapsible : false,
15448 width:400, height:100,
15449 buttonAlign:"center",
15450 closeClick : function(){
15451 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15452 handleButton("no");
15454 handleButton("cancel");
15458 dlg.on("hide", handleHide);
15460 dlg.addKeyListener(27, handleEsc);
15462 var bt = this.buttonText;
15463 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15464 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15465 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15466 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15467 bodyEl = dlg.body.createChild({
15469 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>'
15471 msgEl = bodyEl.dom.firstChild;
15472 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15473 textboxEl.enableDisplayMode();
15474 textboxEl.addKeyListener([10,13], function(){
15475 if(dlg.isVisible() && opt && opt.buttons){
15476 if(opt.buttons.ok){
15477 handleButton("ok");
15478 }else if(opt.buttons.yes){
15479 handleButton("yes");
15483 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15484 textareaEl.enableDisplayMode();
15485 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15486 progressEl.enableDisplayMode();
15487 var pf = progressEl.dom.firstChild;
15489 pp = Roo.get(pf.firstChild);
15490 pp.setHeight(pf.offsetHeight);
15498 * Updates the message box body text
15499 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15500 * the XHTML-compliant non-breaking space character '&#160;')
15501 * @return {Roo.MessageBox} This message box
15503 updateText : function(text){
15504 if(!dlg.isVisible() && !opt.width){
15505 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15507 msgEl.innerHTML = text || ' ';
15508 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15509 Math.max(opt.minWidth || this.minWidth, bwidth));
15511 activeTextEl.setWidth(w);
15513 if(dlg.isVisible()){
15514 dlg.fixedcenter = false;
15516 dlg.setContentSize(w, bodyEl.getHeight());
15517 if(dlg.isVisible()){
15518 dlg.fixedcenter = true;
15524 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15525 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15526 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15527 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15528 * @return {Roo.MessageBox} This message box
15530 updateProgress : function(value, text){
15532 this.updateText(text);
15534 if (pp) { // weird bug on my firefox - for some reason this is not defined
15535 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15541 * Returns true if the message box is currently displayed
15542 * @return {Boolean} True if the message box is visible, else false
15544 isVisible : function(){
15545 return dlg && dlg.isVisible();
15549 * Hides the message box if it is displayed
15552 if(this.isVisible()){
15558 * Displays a new message box, or reinitializes an existing message box, based on the config options
15559 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15560 * The following config object properties are supported:
15562 Property Type Description
15563 ---------- --------------- ------------------------------------------------------------------------------------
15564 animEl String/Element An id or Element from which the message box should animate as it opens and
15565 closes (defaults to undefined)
15566 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15567 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15568 closable Boolean False to hide the top-right close button (defaults to true). Note that
15569 progress and wait dialogs will ignore this property and always hide the
15570 close button as they can only be closed programmatically.
15571 cls String A custom CSS class to apply to the message box element
15572 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15573 displayed (defaults to 75)
15574 fn Function A callback function to execute after closing the dialog. The arguments to the
15575 function will be btn (the name of the button that was clicked, if applicable,
15576 e.g. "ok"), and text (the value of the active text field, if applicable).
15577 Progress and wait dialogs will ignore this option since they do not respond to
15578 user actions and can only be closed programmatically, so any required function
15579 should be called by the same code after it closes the dialog.
15580 icon String A CSS class that provides a background image to be used as an icon for
15581 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15582 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15583 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15584 modal Boolean False to allow user interaction with the page while the message box is
15585 displayed (defaults to true)
15586 msg String A string that will replace the existing message box body text (defaults
15587 to the XHTML-compliant non-breaking space character ' ')
15588 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15589 progress Boolean True to display a progress bar (defaults to false)
15590 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15591 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15592 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15593 title String The title text
15594 value String The string value to set into the active textbox element if displayed
15595 wait Boolean True to display a progress bar (defaults to false)
15596 width Number The width of the dialog in pixels
15603 msg: 'Please enter your address:',
15605 buttons: Roo.MessageBox.OKCANCEL,
15608 animEl: 'addAddressBtn'
15611 * @param {Object} config Configuration options
15612 * @return {Roo.MessageBox} This message box
15614 show : function(options){
15615 if(this.isVisible()){
15618 var d = this.getDialog();
15620 d.setTitle(opt.title || " ");
15621 d.close.setDisplayed(opt.closable !== false);
15622 activeTextEl = textboxEl;
15623 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15628 textareaEl.setHeight(typeof opt.multiline == "number" ?
15629 opt.multiline : this.defaultTextHeight);
15630 activeTextEl = textareaEl;
15639 progressEl.setDisplayed(opt.progress === true);
15640 this.updateProgress(0);
15641 activeTextEl.dom.value = opt.value || "";
15643 dlg.setDefaultButton(activeTextEl);
15645 var bs = opt.buttons;
15648 db = buttons["ok"];
15649 }else if(bs && bs.yes){
15650 db = buttons["yes"];
15652 dlg.setDefaultButton(db);
15654 bwidth = updateButtons(opt.buttons);
15655 this.updateText(opt.msg);
15657 d.el.addClass(opt.cls);
15659 d.proxyDrag = opt.proxyDrag === true;
15660 d.modal = opt.modal !== false;
15661 d.mask = opt.modal !== false ? mask : false;
15662 if(!d.isVisible()){
15663 // force it to the end of the z-index stack so it gets a cursor in FF
15664 document.body.appendChild(dlg.el.dom);
15665 d.animateTarget = null;
15666 d.show(options.animEl);
15672 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15673 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15674 * and closing the message box when the process is complete.
15675 * @param {String} title The title bar text
15676 * @param {String} msg The message box body text
15677 * @return {Roo.MessageBox} This message box
15679 progress : function(title, msg){
15686 minWidth: this.minProgressWidth,
15693 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15694 * If a callback function is passed it will be called after the user clicks the button, and the
15695 * id of the button that was clicked will be passed as the only parameter to the callback
15696 * (could also be the top-right close button).
15697 * @param {String} title The title bar text
15698 * @param {String} msg The message box body text
15699 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15700 * @param {Object} scope (optional) The scope of the callback function
15701 * @return {Roo.MessageBox} This message box
15703 alert : function(title, msg, fn, scope){
15716 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15717 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15718 * You are responsible for closing the message box when the process is complete.
15719 * @param {String} msg The message box body text
15720 * @param {String} title (optional) The title bar text
15721 * @return {Roo.MessageBox} This message box
15723 wait : function(msg, title){
15734 waitTimer = Roo.TaskMgr.start({
15736 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15744 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15745 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15746 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15747 * @param {String} title The title bar text
15748 * @param {String} msg The message box body text
15749 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15750 * @param {Object} scope (optional) The scope of the callback function
15751 * @return {Roo.MessageBox} This message box
15753 confirm : function(title, msg, fn, scope){
15757 buttons: this.YESNO,
15766 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15767 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15768 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15769 * (could also be the top-right close button) and the text that was entered will be passed as the two
15770 * parameters to the callback.
15771 * @param {String} title The title bar text
15772 * @param {String} msg The message box body text
15773 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15774 * @param {Object} scope (optional) The scope of the callback function
15775 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15776 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15777 * @return {Roo.MessageBox} This message box
15779 prompt : function(title, msg, fn, scope, multiline){
15783 buttons: this.OKCANCEL,
15788 multiline: multiline,
15795 * Button config that displays a single OK button
15800 * Button config that displays Yes and No buttons
15803 YESNO : {yes:true, no:true},
15805 * Button config that displays OK and Cancel buttons
15808 OKCANCEL : {ok:true, cancel:true},
15810 * Button config that displays Yes, No and Cancel buttons
15813 YESNOCANCEL : {yes:true, no:true, cancel:true},
15816 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15819 defaultTextHeight : 75,
15821 * The maximum width in pixels of the message box (defaults to 600)
15826 * The minimum width in pixels of the message box (defaults to 100)
15831 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15832 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15835 minProgressWidth : 250,
15837 * An object containing the default button text strings that can be overriden for localized language support.
15838 * Supported properties are: ok, cancel, yes and no.
15839 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15852 * Shorthand for {@link Roo.MessageBox}
15854 Roo.Msg = Roo.MessageBox;/*
15856 * Ext JS Library 1.1.1
15857 * Copyright(c) 2006-2007, Ext JS, LLC.
15859 * Originally Released Under LGPL - original licence link has changed is not relivant.
15862 * <script type="text/javascript">
15865 * @class Roo.QuickTips
15866 * Provides attractive and customizable tooltips for any element.
15869 Roo.QuickTips = function(){
15870 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15871 var ce, bd, xy, dd;
15872 var visible = false, disabled = true, inited = false;
15873 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15875 var onOver = function(e){
15879 var t = e.getTarget();
15880 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15883 if(ce && t == ce.el){
15884 clearTimeout(hideProc);
15887 if(t && tagEls[t.id]){
15888 tagEls[t.id].el = t;
15889 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15892 var ttp, et = Roo.fly(t);
15893 var ns = cfg.namespace;
15894 if(tm.interceptTitles && t.title){
15897 t.removeAttribute("title");
15898 e.preventDefault();
15900 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15903 showProc = show.defer(tm.showDelay, tm, [{
15906 width: et.getAttributeNS(ns, cfg.width),
15907 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15908 title: et.getAttributeNS(ns, cfg.title),
15909 cls: et.getAttributeNS(ns, cfg.cls)
15914 var onOut = function(e){
15915 clearTimeout(showProc);
15916 var t = e.getTarget();
15917 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15918 hideProc = setTimeout(hide, tm.hideDelay);
15922 var onMove = function(e){
15928 if(tm.trackMouse && ce){
15933 var onDown = function(e){
15934 clearTimeout(showProc);
15935 clearTimeout(hideProc);
15937 if(tm.hideOnClick){
15940 tm.enable.defer(100, tm);
15945 var getPad = function(){
15946 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15949 var show = function(o){
15953 clearTimeout(dismissProc);
15955 if(removeCls){ // in case manually hidden
15956 el.removeClass(removeCls);
15960 el.addClass(ce.cls);
15961 removeCls = ce.cls;
15964 tipTitle.update(ce.title);
15967 tipTitle.update('');
15970 el.dom.style.width = tm.maxWidth+'px';
15971 //tipBody.dom.style.width = '';
15972 tipBodyText.update(o.text);
15973 var p = getPad(), w = ce.width;
15975 var td = tipBodyText.dom;
15976 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15977 if(aw > tm.maxWidth){
15979 }else if(aw < tm.minWidth){
15985 //tipBody.setWidth(w);
15986 el.setWidth(parseInt(w, 10) + p);
15987 if(ce.autoHide === false){
15988 close.setDisplayed(true);
15993 close.setDisplayed(false);
15999 el.avoidY = xy[1]-18;
16004 el.setStyle("visibility", "visible");
16005 el.fadeIn({callback: afterShow});
16011 var afterShow = function(){
16015 if(tm.autoDismiss && ce.autoHide !== false){
16016 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16021 var hide = function(noanim){
16022 clearTimeout(dismissProc);
16023 clearTimeout(hideProc);
16025 if(el.isVisible()){
16027 if(noanim !== true && tm.animate){
16028 el.fadeOut({callback: afterHide});
16035 var afterHide = function(){
16038 el.removeClass(removeCls);
16045 * @cfg {Number} minWidth
16046 * The minimum width of the quick tip (defaults to 40)
16050 * @cfg {Number} maxWidth
16051 * The maximum width of the quick tip (defaults to 300)
16055 * @cfg {Boolean} interceptTitles
16056 * True to automatically use the element's DOM title value if available (defaults to false)
16058 interceptTitles : false,
16060 * @cfg {Boolean} trackMouse
16061 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16063 trackMouse : false,
16065 * @cfg {Boolean} hideOnClick
16066 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16068 hideOnClick : true,
16070 * @cfg {Number} showDelay
16071 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16075 * @cfg {Number} hideDelay
16076 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16080 * @cfg {Boolean} autoHide
16081 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16082 * Used in conjunction with hideDelay.
16087 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16088 * (defaults to true). Used in conjunction with autoDismissDelay.
16090 autoDismiss : true,
16093 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16095 autoDismissDelay : 5000,
16097 * @cfg {Boolean} animate
16098 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16103 * @cfg {String} title
16104 * Title text to display (defaults to ''). This can be any valid HTML markup.
16108 * @cfg {String} text
16109 * Body text to display (defaults to ''). This can be any valid HTML markup.
16113 * @cfg {String} cls
16114 * A CSS class to apply to the base quick tip element (defaults to '').
16118 * @cfg {Number} width
16119 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16120 * minWidth or maxWidth.
16125 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16126 * or display QuickTips in a page.
16129 tm = Roo.QuickTips;
16130 cfg = tm.tagConfig;
16132 if(!Roo.isReady){ // allow calling of init() before onReady
16133 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16136 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16137 el.fxDefaults = {stopFx: true};
16138 // maximum custom styling
16139 //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>');
16140 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>');
16141 tipTitle = el.child('h3');
16142 tipTitle.enableDisplayMode("block");
16143 tipBody = el.child('div.x-tip-bd');
16144 tipBodyText = el.child('div.x-tip-bd-inner');
16145 //bdLeft = el.child('div.x-tip-bd-left');
16146 //bdRight = el.child('div.x-tip-bd-right');
16147 close = el.child('div.x-tip-close');
16148 close.enableDisplayMode("block");
16149 close.on("click", hide);
16150 var d = Roo.get(document);
16151 d.on("mousedown", onDown);
16152 d.on("mouseover", onOver);
16153 d.on("mouseout", onOut);
16154 d.on("mousemove", onMove);
16155 esc = d.addKeyListener(27, hide);
16158 dd = el.initDD("default", null, {
16159 onDrag : function(){
16163 dd.setHandleElId(tipTitle.id);
16172 * Configures a new quick tip instance and assigns it to a target element. The following config options
16175 Property Type Description
16176 ---------- --------------------- ------------------------------------------------------------------------
16177 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16179 * @param {Object} config The config object
16181 register : function(config){
16182 var cs = config instanceof Array ? config : arguments;
16183 for(var i = 0, len = cs.length; i < len; i++) {
16185 var target = c.target;
16187 if(target instanceof Array){
16188 for(var j = 0, jlen = target.length; j < jlen; j++){
16189 tagEls[target[j]] = c;
16192 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16199 * Removes this quick tip from its element and destroys it.
16200 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16202 unregister : function(el){
16203 delete tagEls[Roo.id(el)];
16207 * Enable this quick tip.
16209 enable : function(){
16210 if(inited && disabled){
16212 if(locks.length < 1){
16219 * Disable this quick tip.
16221 disable : function(){
16223 clearTimeout(showProc);
16224 clearTimeout(hideProc);
16225 clearTimeout(dismissProc);
16233 * Returns true if the quick tip is enabled, else false.
16235 isEnabled : function(){
16242 attribute : "qtip",
16252 // backwards compat
16253 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16255 * Ext JS Library 1.1.1
16256 * Copyright(c) 2006-2007, Ext JS, LLC.
16258 * Originally Released Under LGPL - original licence link has changed is not relivant.
16261 * <script type="text/javascript">
16266 * @class Roo.tree.TreePanel
16267 * @extends Roo.data.Tree
16269 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16270 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16271 * @cfg {Boolean} enableDD true to enable drag and drop
16272 * @cfg {Boolean} enableDrag true to enable just drag
16273 * @cfg {Boolean} enableDrop true to enable just drop
16274 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16275 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16276 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16277 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16278 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16279 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16280 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16281 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16282 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16283 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16284 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16285 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16286 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16287 * @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>
16288 * @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>
16291 * @param {String/HTMLElement/Element} el The container element
16292 * @param {Object} config
16294 Roo.tree.TreePanel = function(el, config){
16296 var loader = false;
16298 root = config.root;
16299 delete config.root;
16301 if (config.loader) {
16302 loader = config.loader;
16303 delete config.loader;
16306 Roo.apply(this, config);
16307 Roo.tree.TreePanel.superclass.constructor.call(this);
16308 this.el = Roo.get(el);
16309 this.el.addClass('x-tree');
16310 //console.log(root);
16312 this.setRootNode( Roo.factory(root, Roo.tree));
16315 this.loader = Roo.factory(loader, Roo.tree);
16318 * Read-only. The id of the container element becomes this TreePanel's id.
16320 this.id = this.el.id;
16323 * @event beforeload
16324 * Fires before a node is loaded, return false to cancel
16325 * @param {Node} node The node being loaded
16327 "beforeload" : true,
16330 * Fires when a node is loaded
16331 * @param {Node} node The node that was loaded
16335 * @event textchange
16336 * Fires when the text for a node is changed
16337 * @param {Node} node The node
16338 * @param {String} text The new text
16339 * @param {String} oldText The old text
16341 "textchange" : true,
16343 * @event beforeexpand
16344 * Fires before a node is expanded, return false to cancel.
16345 * @param {Node} node The node
16346 * @param {Boolean} deep
16347 * @param {Boolean} anim
16349 "beforeexpand" : true,
16351 * @event beforecollapse
16352 * Fires before a node is collapsed, return false to cancel.
16353 * @param {Node} node The node
16354 * @param {Boolean} deep
16355 * @param {Boolean} anim
16357 "beforecollapse" : true,
16360 * Fires when a node is expanded
16361 * @param {Node} node The node
16365 * @event disabledchange
16366 * Fires when the disabled status of a node changes
16367 * @param {Node} node The node
16368 * @param {Boolean} disabled
16370 "disabledchange" : true,
16373 * Fires when a node is collapsed
16374 * @param {Node} node The node
16378 * @event beforeclick
16379 * Fires before click processing on a node. Return false to cancel the default action.
16380 * @param {Node} node The node
16381 * @param {Roo.EventObject} e The event object
16383 "beforeclick":true,
16385 * @event checkchange
16386 * Fires when a node with a checkbox's checked property changes
16387 * @param {Node} this This node
16388 * @param {Boolean} checked
16390 "checkchange":true,
16393 * Fires when a node is clicked
16394 * @param {Node} node The node
16395 * @param {Roo.EventObject} e The event object
16400 * Fires when a node is double clicked
16401 * @param {Node} node The node
16402 * @param {Roo.EventObject} e The event object
16406 * @event contextmenu
16407 * Fires when a node is right clicked
16408 * @param {Node} node The node
16409 * @param {Roo.EventObject} e The event object
16411 "contextmenu":true,
16413 * @event beforechildrenrendered
16414 * Fires right before the child nodes for a node are rendered
16415 * @param {Node} node The node
16417 "beforechildrenrendered":true,
16420 * Fires when a node starts being dragged
16421 * @param {Roo.tree.TreePanel} this
16422 * @param {Roo.tree.TreeNode} node
16423 * @param {event} e The raw browser event
16425 "startdrag" : true,
16428 * Fires when a drag operation is complete
16429 * @param {Roo.tree.TreePanel} this
16430 * @param {Roo.tree.TreeNode} node
16431 * @param {event} e The raw browser event
16436 * Fires when a dragged node is dropped on a valid DD target
16437 * @param {Roo.tree.TreePanel} this
16438 * @param {Roo.tree.TreeNode} node
16439 * @param {DD} dd The dd it was dropped on
16440 * @param {event} e The raw browser event
16444 * @event beforenodedrop
16445 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16446 * passed to handlers has the following properties:<br />
16447 * <ul style="padding:5px;padding-left:16px;">
16448 * <li>tree - The TreePanel</li>
16449 * <li>target - The node being targeted for the drop</li>
16450 * <li>data - The drag data from the drag source</li>
16451 * <li>point - The point of the drop - append, above or below</li>
16452 * <li>source - The drag source</li>
16453 * <li>rawEvent - Raw mouse event</li>
16454 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16455 * to be inserted by setting them on this object.</li>
16456 * <li>cancel - Set this to true to cancel the drop.</li>
16458 * @param {Object} dropEvent
16460 "beforenodedrop" : true,
16463 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16464 * passed to handlers has the following properties:<br />
16465 * <ul style="padding:5px;padding-left:16px;">
16466 * <li>tree - The TreePanel</li>
16467 * <li>target - The node being targeted for the drop</li>
16468 * <li>data - The drag data from the drag source</li>
16469 * <li>point - The point of the drop - append, above or below</li>
16470 * <li>source - The drag source</li>
16471 * <li>rawEvent - Raw mouse event</li>
16472 * <li>dropNode - Dropped node(s).</li>
16474 * @param {Object} dropEvent
16478 * @event nodedragover
16479 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16480 * passed to handlers has the following properties:<br />
16481 * <ul style="padding:5px;padding-left:16px;">
16482 * <li>tree - The TreePanel</li>
16483 * <li>target - The node being targeted for the drop</li>
16484 * <li>data - The drag data from the drag source</li>
16485 * <li>point - The point of the drop - append, above or below</li>
16486 * <li>source - The drag source</li>
16487 * <li>rawEvent - Raw mouse event</li>
16488 * <li>dropNode - Drop node(s) provided by the source.</li>
16489 * <li>cancel - Set this to true to signal drop not allowed.</li>
16491 * @param {Object} dragOverEvent
16493 "nodedragover" : true
16496 if(this.singleExpand){
16497 this.on("beforeexpand", this.restrictExpand, this);
16500 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16501 rootVisible : true,
16502 animate: Roo.enableFx,
16505 hlDrop : Roo.enableFx,
16509 rendererTip: false,
16511 restrictExpand : function(node){
16512 var p = node.parentNode;
16514 if(p.expandedChild && p.expandedChild.parentNode == p){
16515 p.expandedChild.collapse();
16517 p.expandedChild = node;
16521 // private override
16522 setRootNode : function(node){
16523 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16524 if(!this.rootVisible){
16525 node.ui = new Roo.tree.RootTreeNodeUI(node);
16531 * Returns the container element for this TreePanel
16533 getEl : function(){
16538 * Returns the default TreeLoader for this TreePanel
16540 getLoader : function(){
16541 return this.loader;
16547 expandAll : function(){
16548 this.root.expand(true);
16552 * Collapse all nodes
16554 collapseAll : function(){
16555 this.root.collapse(true);
16559 * Returns the selection model used by this TreePanel
16561 getSelectionModel : function(){
16562 if(!this.selModel){
16563 this.selModel = new Roo.tree.DefaultSelectionModel();
16565 return this.selModel;
16569 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16570 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16571 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16574 getChecked : function(a, startNode){
16575 startNode = startNode || this.root;
16577 var f = function(){
16578 if(this.attributes.checked){
16579 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16582 startNode.cascade(f);
16587 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16588 * @param {String} path
16589 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16590 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16591 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16593 expandPath : function(path, attr, callback){
16594 attr = attr || "id";
16595 var keys = path.split(this.pathSeparator);
16596 var curNode = this.root;
16597 if(curNode.attributes[attr] != keys[1]){ // invalid root
16599 callback(false, null);
16604 var f = function(){
16605 if(++index == keys.length){
16607 callback(true, curNode);
16611 var c = curNode.findChild(attr, keys[index]);
16614 callback(false, curNode);
16619 c.expand(false, false, f);
16621 curNode.expand(false, false, f);
16625 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16626 * @param {String} path
16627 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16628 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16629 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16631 selectPath : function(path, attr, callback){
16632 attr = attr || "id";
16633 var keys = path.split(this.pathSeparator);
16634 var v = keys.pop();
16635 if(keys.length > 0){
16636 var f = function(success, node){
16637 if(success && node){
16638 var n = node.findChild(attr, v);
16644 }else if(callback){
16645 callback(false, n);
16649 callback(false, n);
16653 this.expandPath(keys.join(this.pathSeparator), attr, f);
16655 this.root.select();
16657 callback(true, this.root);
16662 getTreeEl : function(){
16667 * Trigger rendering of this TreePanel
16669 render : function(){
16670 if (this.innerCt) {
16671 return this; // stop it rendering more than once!!
16674 this.innerCt = this.el.createChild({tag:"ul",
16675 cls:"x-tree-root-ct " +
16676 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16678 if(this.containerScroll){
16679 Roo.dd.ScrollManager.register(this.el);
16681 if((this.enableDD || this.enableDrop) && !this.dropZone){
16683 * The dropZone used by this tree if drop is enabled
16684 * @type Roo.tree.TreeDropZone
16686 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16687 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16690 if((this.enableDD || this.enableDrag) && !this.dragZone){
16692 * The dragZone used by this tree if drag is enabled
16693 * @type Roo.tree.TreeDragZone
16695 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16696 ddGroup: this.ddGroup || "TreeDD",
16697 scroll: this.ddScroll
16700 this.getSelectionModel().init(this);
16702 console.log("ROOT not set in tree");
16705 this.root.render();
16706 if(!this.rootVisible){
16707 this.root.renderChildren();
16713 * Ext JS Library 1.1.1
16714 * Copyright(c) 2006-2007, Ext JS, LLC.
16716 * Originally Released Under LGPL - original licence link has changed is not relivant.
16719 * <script type="text/javascript">
16724 * @class Roo.tree.DefaultSelectionModel
16725 * @extends Roo.util.Observable
16726 * The default single selection for a TreePanel.
16728 Roo.tree.DefaultSelectionModel = function(){
16729 this.selNode = null;
16733 * @event selectionchange
16734 * Fires when the selected node changes
16735 * @param {DefaultSelectionModel} this
16736 * @param {TreeNode} node the new selection
16738 "selectionchange" : true,
16741 * @event beforeselect
16742 * Fires before the selected node changes, return false to cancel the change
16743 * @param {DefaultSelectionModel} this
16744 * @param {TreeNode} node the new selection
16745 * @param {TreeNode} node the old selection
16747 "beforeselect" : true
16751 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16752 init : function(tree){
16754 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16755 tree.on("click", this.onNodeClick, this);
16758 onNodeClick : function(node, e){
16759 if (e.ctrlKey && this.selNode == node) {
16760 this.unselect(node);
16768 * @param {TreeNode} node The node to select
16769 * @return {TreeNode} The selected node
16771 select : function(node){
16772 var last = this.selNode;
16773 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16775 last.ui.onSelectedChange(false);
16777 this.selNode = node;
16778 node.ui.onSelectedChange(true);
16779 this.fireEvent("selectionchange", this, node, last);
16786 * @param {TreeNode} node The node to unselect
16788 unselect : function(node){
16789 if(this.selNode == node){
16790 this.clearSelections();
16795 * Clear all selections
16797 clearSelections : function(){
16798 var n = this.selNode;
16800 n.ui.onSelectedChange(false);
16801 this.selNode = null;
16802 this.fireEvent("selectionchange", this, null);
16808 * Get the selected node
16809 * @return {TreeNode} The selected node
16811 getSelectedNode : function(){
16812 return this.selNode;
16816 * Returns true if the node is selected
16817 * @param {TreeNode} node The node to check
16818 * @return {Boolean}
16820 isSelected : function(node){
16821 return this.selNode == node;
16825 * Selects the node above the selected node in the tree, intelligently walking the nodes
16826 * @return TreeNode The new selection
16828 selectPrevious : function(){
16829 var s = this.selNode || this.lastSelNode;
16833 var ps = s.previousSibling;
16835 if(!ps.isExpanded() || ps.childNodes.length < 1){
16836 return this.select(ps);
16838 var lc = ps.lastChild;
16839 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16842 return this.select(lc);
16844 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16845 return this.select(s.parentNode);
16851 * Selects the node above the selected node in the tree, intelligently walking the nodes
16852 * @return TreeNode The new selection
16854 selectNext : function(){
16855 var s = this.selNode || this.lastSelNode;
16859 if(s.firstChild && s.isExpanded()){
16860 return this.select(s.firstChild);
16861 }else if(s.nextSibling){
16862 return this.select(s.nextSibling);
16863 }else if(s.parentNode){
16865 s.parentNode.bubble(function(){
16866 if(this.nextSibling){
16867 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16876 onKeyDown : function(e){
16877 var s = this.selNode || this.lastSelNode;
16878 // undesirable, but required
16883 var k = e.getKey();
16891 this.selectPrevious();
16894 e.preventDefault();
16895 if(s.hasChildNodes()){
16896 if(!s.isExpanded()){
16898 }else if(s.firstChild){
16899 this.select(s.firstChild, e);
16904 e.preventDefault();
16905 if(s.hasChildNodes() && s.isExpanded()){
16907 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16908 this.select(s.parentNode, e);
16916 * @class Roo.tree.MultiSelectionModel
16917 * @extends Roo.util.Observable
16918 * Multi selection for a TreePanel.
16920 Roo.tree.MultiSelectionModel = function(){
16921 this.selNodes = [];
16925 * @event selectionchange
16926 * Fires when the selected nodes change
16927 * @param {MultiSelectionModel} this
16928 * @param {Array} nodes Array of the selected nodes
16930 "selectionchange" : true
16934 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16935 init : function(tree){
16937 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16938 tree.on("click", this.onNodeClick, this);
16941 onNodeClick : function(node, e){
16942 this.select(node, e, e.ctrlKey);
16947 * @param {TreeNode} node The node to select
16948 * @param {EventObject} e (optional) An event associated with the selection
16949 * @param {Boolean} keepExisting True to retain existing selections
16950 * @return {TreeNode} The selected node
16952 select : function(node, e, keepExisting){
16953 if(keepExisting !== true){
16954 this.clearSelections(true);
16956 if(this.isSelected(node)){
16957 this.lastSelNode = node;
16960 this.selNodes.push(node);
16961 this.selMap[node.id] = node;
16962 this.lastSelNode = node;
16963 node.ui.onSelectedChange(true);
16964 this.fireEvent("selectionchange", this, this.selNodes);
16970 * @param {TreeNode} node The node to unselect
16972 unselect : function(node){
16973 if(this.selMap[node.id]){
16974 node.ui.onSelectedChange(false);
16975 var sn = this.selNodes;
16978 index = sn.indexOf(node);
16980 for(var i = 0, len = sn.length; i < len; i++){
16988 this.selNodes.splice(index, 1);
16990 delete this.selMap[node.id];
16991 this.fireEvent("selectionchange", this, this.selNodes);
16996 * Clear all selections
16998 clearSelections : function(suppressEvent){
16999 var sn = this.selNodes;
17001 for(var i = 0, len = sn.length; i < len; i++){
17002 sn[i].ui.onSelectedChange(false);
17004 this.selNodes = [];
17006 if(suppressEvent !== true){
17007 this.fireEvent("selectionchange", this, this.selNodes);
17013 * Returns true if the node is selected
17014 * @param {TreeNode} node The node to check
17015 * @return {Boolean}
17017 isSelected : function(node){
17018 return this.selMap[node.id] ? true : false;
17022 * Returns an array of the selected nodes
17025 getSelectedNodes : function(){
17026 return this.selNodes;
17029 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17031 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17033 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17036 * Ext JS Library 1.1.1
17037 * Copyright(c) 2006-2007, Ext JS, LLC.
17039 * Originally Released Under LGPL - original licence link has changed is not relivant.
17042 * <script type="text/javascript">
17046 * @class Roo.tree.TreeNode
17047 * @extends Roo.data.Node
17048 * @cfg {String} text The text for this node
17049 * @cfg {Boolean} expanded true to start the node expanded
17050 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17051 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17052 * @cfg {Boolean} disabled true to start the node disabled
17053 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17054 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17055 * @cfg {String} cls A css class to be added to the node
17056 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17057 * @cfg {String} href URL of the link used for the node (defaults to #)
17058 * @cfg {String} hrefTarget target frame for the link
17059 * @cfg {String} qtip An Ext QuickTip for the node
17060 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17061 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17062 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17063 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17064 * (defaults to undefined with no checkbox rendered)
17066 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17068 Roo.tree.TreeNode = function(attributes){
17069 attributes = attributes || {};
17070 if(typeof attributes == "string"){
17071 attributes = {text: attributes};
17073 this.childrenRendered = false;
17074 this.rendered = false;
17075 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17076 this.expanded = attributes.expanded === true;
17077 this.isTarget = attributes.isTarget !== false;
17078 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17079 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17082 * Read-only. The text for this node. To change it use setText().
17085 this.text = attributes.text;
17087 * True if this node is disabled.
17090 this.disabled = attributes.disabled === true;
17094 * @event textchange
17095 * Fires when the text for this node is changed
17096 * @param {Node} this This node
17097 * @param {String} text The new text
17098 * @param {String} oldText The old text
17100 "textchange" : true,
17102 * @event beforeexpand
17103 * Fires before this node is expanded, return false to cancel.
17104 * @param {Node} this This node
17105 * @param {Boolean} deep
17106 * @param {Boolean} anim
17108 "beforeexpand" : true,
17110 * @event beforecollapse
17111 * Fires before this node is collapsed, return false to cancel.
17112 * @param {Node} this This node
17113 * @param {Boolean} deep
17114 * @param {Boolean} anim
17116 "beforecollapse" : true,
17119 * Fires when this node is expanded
17120 * @param {Node} this This node
17124 * @event disabledchange
17125 * Fires when the disabled status of this node changes
17126 * @param {Node} this This node
17127 * @param {Boolean} disabled
17129 "disabledchange" : true,
17132 * Fires when this node is collapsed
17133 * @param {Node} this This node
17137 * @event beforeclick
17138 * Fires before click processing. Return false to cancel the default action.
17139 * @param {Node} this This node
17140 * @param {Roo.EventObject} e The event object
17142 "beforeclick":true,
17144 * @event checkchange
17145 * Fires when a node with a checkbox's checked property changes
17146 * @param {Node} this This node
17147 * @param {Boolean} checked
17149 "checkchange":true,
17152 * Fires when this node is clicked
17153 * @param {Node} this This node
17154 * @param {Roo.EventObject} e The event object
17159 * Fires when this node is double clicked
17160 * @param {Node} this This node
17161 * @param {Roo.EventObject} e The event object
17165 * @event contextmenu
17166 * Fires when this node is right clicked
17167 * @param {Node} this This node
17168 * @param {Roo.EventObject} e The event object
17170 "contextmenu":true,
17172 * @event beforechildrenrendered
17173 * Fires right before the child nodes for this node are rendered
17174 * @param {Node} this This node
17176 "beforechildrenrendered":true
17179 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17182 * Read-only. The UI for this node
17185 this.ui = new uiClass(this);
17187 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17188 preventHScroll: true,
17190 * Returns true if this node is expanded
17191 * @return {Boolean}
17193 isExpanded : function(){
17194 return this.expanded;
17198 * Returns the UI object for this node
17199 * @return {TreeNodeUI}
17201 getUI : function(){
17205 // private override
17206 setFirstChild : function(node){
17207 var of = this.firstChild;
17208 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17209 if(this.childrenRendered && of && node != of){
17210 of.renderIndent(true, true);
17213 this.renderIndent(true, true);
17217 // private override
17218 setLastChild : function(node){
17219 var ol = this.lastChild;
17220 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17221 if(this.childrenRendered && ol && node != ol){
17222 ol.renderIndent(true, true);
17225 this.renderIndent(true, true);
17229 // these methods are overridden to provide lazy rendering support
17230 // private override
17231 appendChild : function(){
17232 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17233 if(node && this.childrenRendered){
17236 this.ui.updateExpandIcon();
17240 // private override
17241 removeChild : function(node){
17242 this.ownerTree.getSelectionModel().unselect(node);
17243 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17244 // if it's been rendered remove dom node
17245 if(this.childrenRendered){
17248 if(this.childNodes.length < 1){
17249 this.collapse(false, false);
17251 this.ui.updateExpandIcon();
17253 if(!this.firstChild) {
17254 this.childrenRendered = false;
17259 // private override
17260 insertBefore : function(node, refNode){
17261 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17262 if(newNode && refNode && this.childrenRendered){
17265 this.ui.updateExpandIcon();
17270 * Sets the text for this node
17271 * @param {String} text
17273 setText : function(text){
17274 var oldText = this.text;
17276 this.attributes.text = text;
17277 if(this.rendered){ // event without subscribing
17278 this.ui.onTextChange(this, text, oldText);
17280 this.fireEvent("textchange", this, text, oldText);
17284 * Triggers selection of this node
17286 select : function(){
17287 this.getOwnerTree().getSelectionModel().select(this);
17291 * Triggers deselection of this node
17293 unselect : function(){
17294 this.getOwnerTree().getSelectionModel().unselect(this);
17298 * Returns true if this node is selected
17299 * @return {Boolean}
17301 isSelected : function(){
17302 return this.getOwnerTree().getSelectionModel().isSelected(this);
17306 * Expand this node.
17307 * @param {Boolean} deep (optional) True to expand all children as well
17308 * @param {Boolean} anim (optional) false to cancel the default animation
17309 * @param {Function} callback (optional) A callback to be called when
17310 * expanding this node completes (does not wait for deep expand to complete).
17311 * Called with 1 parameter, this node.
17313 expand : function(deep, anim, callback){
17314 if(!this.expanded){
17315 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17318 if(!this.childrenRendered){
17319 this.renderChildren();
17321 this.expanded = true;
17322 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17323 this.ui.animExpand(function(){
17324 this.fireEvent("expand", this);
17325 if(typeof callback == "function"){
17329 this.expandChildNodes(true);
17331 }.createDelegate(this));
17335 this.fireEvent("expand", this);
17336 if(typeof callback == "function"){
17341 if(typeof callback == "function"){
17346 this.expandChildNodes(true);
17350 isHiddenRoot : function(){
17351 return this.isRoot && !this.getOwnerTree().rootVisible;
17355 * Collapse this node.
17356 * @param {Boolean} deep (optional) True to collapse all children as well
17357 * @param {Boolean} anim (optional) false to cancel the default animation
17359 collapse : function(deep, anim){
17360 if(this.expanded && !this.isHiddenRoot()){
17361 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17364 this.expanded = false;
17365 if((this.getOwnerTree().animate && anim !== false) || anim){
17366 this.ui.animCollapse(function(){
17367 this.fireEvent("collapse", this);
17369 this.collapseChildNodes(true);
17371 }.createDelegate(this));
17374 this.ui.collapse();
17375 this.fireEvent("collapse", this);
17379 var cs = this.childNodes;
17380 for(var i = 0, len = cs.length; i < len; i++) {
17381 cs[i].collapse(true, false);
17387 delayedExpand : function(delay){
17388 if(!this.expandProcId){
17389 this.expandProcId = this.expand.defer(delay, this);
17394 cancelExpand : function(){
17395 if(this.expandProcId){
17396 clearTimeout(this.expandProcId);
17398 this.expandProcId = false;
17402 * Toggles expanded/collapsed state of the node
17404 toggle : function(){
17413 * Ensures all parent nodes are expanded
17415 ensureVisible : function(callback){
17416 var tree = this.getOwnerTree();
17417 tree.expandPath(this.parentNode.getPath(), false, function(){
17418 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17419 Roo.callback(callback);
17420 }.createDelegate(this));
17424 * Expand all child nodes
17425 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17427 expandChildNodes : function(deep){
17428 var cs = this.childNodes;
17429 for(var i = 0, len = cs.length; i < len; i++) {
17430 cs[i].expand(deep);
17435 * Collapse all child nodes
17436 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17438 collapseChildNodes : function(deep){
17439 var cs = this.childNodes;
17440 for(var i = 0, len = cs.length; i < len; i++) {
17441 cs[i].collapse(deep);
17446 * Disables this node
17448 disable : function(){
17449 this.disabled = true;
17451 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17452 this.ui.onDisableChange(this, true);
17454 this.fireEvent("disabledchange", this, true);
17458 * Enables this node
17460 enable : function(){
17461 this.disabled = false;
17462 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17463 this.ui.onDisableChange(this, false);
17465 this.fireEvent("disabledchange", this, false);
17469 renderChildren : function(suppressEvent){
17470 if(suppressEvent !== false){
17471 this.fireEvent("beforechildrenrendered", this);
17473 var cs = this.childNodes;
17474 for(var i = 0, len = cs.length; i < len; i++){
17475 cs[i].render(true);
17477 this.childrenRendered = true;
17481 sort : function(fn, scope){
17482 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17483 if(this.childrenRendered){
17484 var cs = this.childNodes;
17485 for(var i = 0, len = cs.length; i < len; i++){
17486 cs[i].render(true);
17492 render : function(bulkRender){
17493 this.ui.render(bulkRender);
17494 if(!this.rendered){
17495 this.rendered = true;
17497 this.expanded = false;
17498 this.expand(false, false);
17504 renderIndent : function(deep, refresh){
17506 this.ui.childIndent = null;
17508 this.ui.renderIndent();
17509 if(deep === true && this.childrenRendered){
17510 var cs = this.childNodes;
17511 for(var i = 0, len = cs.length; i < len; i++){
17512 cs[i].renderIndent(true, refresh);
17518 * Ext JS Library 1.1.1
17519 * Copyright(c) 2006-2007, Ext JS, LLC.
17521 * Originally Released Under LGPL - original licence link has changed is not relivant.
17524 * <script type="text/javascript">
17528 * @class Roo.tree.AsyncTreeNode
17529 * @extends Roo.tree.TreeNode
17530 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17532 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17534 Roo.tree.AsyncTreeNode = function(config){
17535 this.loaded = false;
17536 this.loading = false;
17537 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17539 * @event beforeload
17540 * Fires before this node is loaded, return false to cancel
17541 * @param {Node} this This node
17543 this.addEvents({'beforeload':true, 'load': true});
17546 * Fires when this node is loaded
17547 * @param {Node} this This node
17550 * The loader used by this node (defaults to using the tree's defined loader)
17555 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17556 expand : function(deep, anim, callback){
17557 if(this.loading){ // if an async load is already running, waiting til it's done
17559 var f = function(){
17560 if(!this.loading){ // done loading
17561 clearInterval(timer);
17562 this.expand(deep, anim, callback);
17564 }.createDelegate(this);
17565 timer = setInterval(f, 200);
17569 if(this.fireEvent("beforeload", this) === false){
17572 this.loading = true;
17573 this.ui.beforeLoad(this);
17574 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17576 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17580 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17584 * Returns true if this node is currently loading
17585 * @return {Boolean}
17587 isLoading : function(){
17588 return this.loading;
17591 loadComplete : function(deep, anim, callback){
17592 this.loading = false;
17593 this.loaded = true;
17594 this.ui.afterLoad(this);
17595 this.fireEvent("load", this);
17596 this.expand(deep, anim, callback);
17600 * Returns true if this node has been loaded
17601 * @return {Boolean}
17603 isLoaded : function(){
17604 return this.loaded;
17607 hasChildNodes : function(){
17608 if(!this.isLeaf() && !this.loaded){
17611 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17616 * Trigger a reload for this node
17617 * @param {Function} callback
17619 reload : function(callback){
17620 this.collapse(false, false);
17621 while(this.firstChild){
17622 this.removeChild(this.firstChild);
17624 this.childrenRendered = false;
17625 this.loaded = false;
17626 if(this.isHiddenRoot()){
17627 this.expanded = false;
17629 this.expand(false, false, callback);
17633 * Ext JS Library 1.1.1
17634 * Copyright(c) 2006-2007, Ext JS, LLC.
17636 * Originally Released Under LGPL - original licence link has changed is not relivant.
17639 * <script type="text/javascript">
17643 * @class Roo.tree.TreeNodeUI
17645 * @param {Object} node The node to render
17646 * The TreeNode UI implementation is separate from the
17647 * tree implementation. Unless you are customizing the tree UI,
17648 * you should never have to use this directly.
17650 Roo.tree.TreeNodeUI = function(node){
17652 this.rendered = false;
17653 this.animating = false;
17654 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17657 Roo.tree.TreeNodeUI.prototype = {
17658 removeChild : function(node){
17660 this.ctNode.removeChild(node.ui.getEl());
17664 beforeLoad : function(){
17665 this.addClass("x-tree-node-loading");
17668 afterLoad : function(){
17669 this.removeClass("x-tree-node-loading");
17672 onTextChange : function(node, text, oldText){
17674 this.textNode.innerHTML = text;
17678 onDisableChange : function(node, state){
17679 this.disabled = state;
17681 this.addClass("x-tree-node-disabled");
17683 this.removeClass("x-tree-node-disabled");
17687 onSelectedChange : function(state){
17690 this.addClass("x-tree-selected");
17693 this.removeClass("x-tree-selected");
17697 onMove : function(tree, node, oldParent, newParent, index, refNode){
17698 this.childIndent = null;
17700 var targetNode = newParent.ui.getContainer();
17701 if(!targetNode){//target not rendered
17702 this.holder = document.createElement("div");
17703 this.holder.appendChild(this.wrap);
17706 var insertBefore = refNode ? refNode.ui.getEl() : null;
17708 targetNode.insertBefore(this.wrap, insertBefore);
17710 targetNode.appendChild(this.wrap);
17712 this.node.renderIndent(true);
17716 addClass : function(cls){
17718 Roo.fly(this.elNode).addClass(cls);
17722 removeClass : function(cls){
17724 Roo.fly(this.elNode).removeClass(cls);
17728 remove : function(){
17730 this.holder = document.createElement("div");
17731 this.holder.appendChild(this.wrap);
17735 fireEvent : function(){
17736 return this.node.fireEvent.apply(this.node, arguments);
17739 initEvents : function(){
17740 this.node.on("move", this.onMove, this);
17741 var E = Roo.EventManager;
17742 var a = this.anchor;
17744 var el = Roo.fly(a, '_treeui');
17746 if(Roo.isOpera){ // opera render bug ignores the CSS
17747 el.setStyle("text-decoration", "none");
17750 el.on("click", this.onClick, this);
17751 el.on("dblclick", this.onDblClick, this);
17754 Roo.EventManager.on(this.checkbox,
17755 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17758 el.on("contextmenu", this.onContextMenu, this);
17760 var icon = Roo.fly(this.iconNode);
17761 icon.on("click", this.onClick, this);
17762 icon.on("dblclick", this.onDblClick, this);
17763 icon.on("contextmenu", this.onContextMenu, this);
17764 E.on(this.ecNode, "click", this.ecClick, this, true);
17766 if(this.node.disabled){
17767 this.addClass("x-tree-node-disabled");
17769 if(this.node.hidden){
17770 this.addClass("x-tree-node-disabled");
17772 var ot = this.node.getOwnerTree();
17773 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17774 if(dd && (!this.node.isRoot || ot.rootVisible)){
17775 Roo.dd.Registry.register(this.elNode, {
17777 handles: this.getDDHandles(),
17783 getDDHandles : function(){
17784 return [this.iconNode, this.textNode];
17789 this.wrap.style.display = "none";
17795 this.wrap.style.display = "";
17799 onContextMenu : function(e){
17800 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17801 e.preventDefault();
17803 this.fireEvent("contextmenu", this.node, e);
17807 onClick : function(e){
17812 if(this.fireEvent("beforeclick", this.node, e) !== false){
17813 if(!this.disabled && this.node.attributes.href){
17814 this.fireEvent("click", this.node, e);
17817 e.preventDefault();
17822 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17823 this.node.toggle();
17826 this.fireEvent("click", this.node, e);
17832 onDblClick : function(e){
17833 e.preventDefault();
17838 this.toggleCheck();
17840 if(!this.animating && this.node.hasChildNodes()){
17841 this.node.toggle();
17843 this.fireEvent("dblclick", this.node, e);
17846 onCheckChange : function(){
17847 var checked = this.checkbox.checked;
17848 this.node.attributes.checked = checked;
17849 this.fireEvent('checkchange', this.node, checked);
17852 ecClick : function(e){
17853 if(!this.animating && this.node.hasChildNodes()){
17854 this.node.toggle();
17858 startDrop : function(){
17859 this.dropping = true;
17862 // delayed drop so the click event doesn't get fired on a drop
17863 endDrop : function(){
17864 setTimeout(function(){
17865 this.dropping = false;
17866 }.createDelegate(this), 50);
17869 expand : function(){
17870 this.updateExpandIcon();
17871 this.ctNode.style.display = "";
17874 focus : function(){
17875 if(!this.node.preventHScroll){
17876 try{this.anchor.focus();
17878 }else if(!Roo.isIE){
17880 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17881 var l = noscroll.scrollLeft;
17882 this.anchor.focus();
17883 noscroll.scrollLeft = l;
17888 toggleCheck : function(value){
17889 var cb = this.checkbox;
17891 cb.checked = (value === undefined ? !cb.checked : value);
17897 this.anchor.blur();
17901 animExpand : function(callback){
17902 var ct = Roo.get(this.ctNode);
17904 if(!this.node.hasChildNodes()){
17905 this.updateExpandIcon();
17906 this.ctNode.style.display = "";
17907 Roo.callback(callback);
17910 this.animating = true;
17911 this.updateExpandIcon();
17914 callback : function(){
17915 this.animating = false;
17916 Roo.callback(callback);
17919 duration: this.node.ownerTree.duration || .25
17923 highlight : function(){
17924 var tree = this.node.getOwnerTree();
17925 Roo.fly(this.wrap).highlight(
17926 tree.hlColor || "C3DAF9",
17927 {endColor: tree.hlBaseColor}
17931 collapse : function(){
17932 this.updateExpandIcon();
17933 this.ctNode.style.display = "none";
17936 animCollapse : function(callback){
17937 var ct = Roo.get(this.ctNode);
17938 ct.enableDisplayMode('block');
17941 this.animating = true;
17942 this.updateExpandIcon();
17945 callback : function(){
17946 this.animating = false;
17947 Roo.callback(callback);
17950 duration: this.node.ownerTree.duration || .25
17954 getContainer : function(){
17955 return this.ctNode;
17958 getEl : function(){
17962 appendDDGhost : function(ghostNode){
17963 ghostNode.appendChild(this.elNode.cloneNode(true));
17966 getDDRepairXY : function(){
17967 return Roo.lib.Dom.getXY(this.iconNode);
17970 onRender : function(){
17974 render : function(bulkRender){
17975 var n = this.node, a = n.attributes;
17976 var targetNode = n.parentNode ?
17977 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17979 if(!this.rendered){
17980 this.rendered = true;
17982 this.renderElements(n, a, targetNode, bulkRender);
17985 if(this.textNode.setAttributeNS){
17986 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17988 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17991 this.textNode.setAttribute("ext:qtip", a.qtip);
17993 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17996 }else if(a.qtipCfg){
17997 a.qtipCfg.target = Roo.id(this.textNode);
17998 Roo.QuickTips.register(a.qtipCfg);
18001 if(!this.node.expanded){
18002 this.updateExpandIcon();
18005 if(bulkRender === true) {
18006 targetNode.appendChild(this.wrap);
18011 renderElements : function(n, a, targetNode, bulkRender){
18012 // add some indent caching, this helps performance when rendering a large tree
18013 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18014 var t = n.getOwnerTree();
18015 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18016 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18017 var cb = typeof a.checked == 'boolean';
18018 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18019 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18020 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18021 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18022 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18023 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18024 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18025 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18026 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18027 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18030 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18031 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18032 n.nextSibling.ui.getEl(), buf.join(""));
18034 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18037 this.elNode = this.wrap.childNodes[0];
18038 this.ctNode = this.wrap.childNodes[1];
18039 var cs = this.elNode.childNodes;
18040 this.indentNode = cs[0];
18041 this.ecNode = cs[1];
18042 this.iconNode = cs[2];
18045 this.checkbox = cs[3];
18048 this.anchor = cs[index];
18049 this.textNode = cs[index].firstChild;
18052 getAnchor : function(){
18053 return this.anchor;
18056 getTextEl : function(){
18057 return this.textNode;
18060 getIconEl : function(){
18061 return this.iconNode;
18064 isChecked : function(){
18065 return this.checkbox ? this.checkbox.checked : false;
18068 updateExpandIcon : function(){
18070 var n = this.node, c1, c2;
18071 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18072 var hasChild = n.hasChildNodes();
18076 c1 = "x-tree-node-collapsed";
18077 c2 = "x-tree-node-expanded";
18080 c1 = "x-tree-node-expanded";
18081 c2 = "x-tree-node-collapsed";
18084 this.removeClass("x-tree-node-leaf");
18085 this.wasLeaf = false;
18087 if(this.c1 != c1 || this.c2 != c2){
18088 Roo.fly(this.elNode).replaceClass(c1, c2);
18089 this.c1 = c1; this.c2 = c2;
18093 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18096 this.wasLeaf = true;
18099 var ecc = "x-tree-ec-icon "+cls;
18100 if(this.ecc != ecc){
18101 this.ecNode.className = ecc;
18107 getChildIndent : function(){
18108 if(!this.childIndent){
18112 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18114 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18116 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18121 this.childIndent = buf.join("");
18123 return this.childIndent;
18126 renderIndent : function(){
18129 var p = this.node.parentNode;
18131 indent = p.ui.getChildIndent();
18133 if(this.indentMarkup != indent){ // don't rerender if not required
18134 this.indentNode.innerHTML = indent;
18135 this.indentMarkup = indent;
18137 this.updateExpandIcon();
18142 Roo.tree.RootTreeNodeUI = function(){
18143 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18145 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18146 render : function(){
18147 if(!this.rendered){
18148 var targetNode = this.node.ownerTree.innerCt.dom;
18149 this.node.expanded = true;
18150 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18151 this.wrap = this.ctNode = targetNode.firstChild;
18154 collapse : function(){
18156 expand : function(){