4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 Roo.dd.DropTarget.superclass.constructor.call( this,
3902 this.ddGroup || this.group,
3907 * @scope Roo.dd.DropTarget
3912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3916 * IMPORTANT : it should set this.overClass and this.dropAllowed
3918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919 * @param {Event} e The event
3920 * @param {Object} data An object containing arbitrary data supplied by the drag source
3926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927 * This method will be called on every mouse movement while the drag source is over the drop target.
3928 * This default implementation simply returns the dropAllowed config value.
3930 * IMPORTANT : it should set this.dropAllowed
3932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933 * @param {Event} e The event
3934 * @param {Object} data An object containing arbitrary data supplied by the drag source
3940 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3942 * overClass (if any) from the drop element.
3943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944 * @param {Event} e The event
3945 * @param {Object} data An object containing arbitrary data supplied by the drag source
3951 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3953 * implementation that does something to process the drop event and returns true so that the drag source's
3954 * repair action does not run.
3956 * IMPORTANT : it should set this.success
3958 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959 * @param {Event} e The event
3960 * @param {Object} data An object containing arbitrary data supplied by the drag source
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973 * @cfg {String} overClass
3974 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3977 * @cfg {String} ddGroup
3978 * The drag drop group to handle drop events for
3982 * @cfg {String} dropAllowed
3983 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3985 dropAllowed : "x-dd-drop-ok",
3987 * @cfg {String} dropNotAllowed
3988 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3990 dropNotAllowed : "x-dd-drop-nodrop",
3992 * @cfg {boolean} success
3993 * set this after drop listener..
3997 * @cfg {boolean} valid
3998 * if the drop point is valid for over/enter..
4005 isNotifyTarget : true,
4010 notifyEnter : function(dd, e, data){
4012 this.fireEvent('enter', this, dd, e, data);
4014 this.el.addClass(this.overClass);
4016 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOver : function(dd, e, data){
4024 this.fireEvent('over', this, dd, e, data);
4025 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4031 notifyOut : function(dd, e, data){
4032 this.fireEvent('out', this, dd, e, data);
4034 this.el.removeClass(this.overClass);
4041 notifyDrop : function(dd, e, data){
4042 this.success = false;
4043 this.fireEvent('drop', this, dd, e, data);
4044 return this.success;
4048 * Ext JS Library 1.1.1
4049 * Copyright(c) 2006-2007, Ext JS, LLC.
4051 * Originally Released Under LGPL - original licence link has changed is not relivant.
4054 * <script type="text/javascript">
4059 * @class Roo.dd.DragZone
4060 * @extends Roo.dd.DragSource
4061 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4062 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4064 * @param {String/HTMLElement/Element} el The container element
4065 * @param {Object} config
4067 Roo.dd.DragZone = function(el, config){
4068 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4069 if(this.containerScroll){
4070 Roo.dd.ScrollManager.register(this.el);
4074 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4076 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4077 * for auto scrolling during drag operations.
4080 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4081 * method after a failed drop (defaults to "c3daf9" - light blue)
4085 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4086 * for a valid target to drag based on the mouse down. Override this method
4087 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4088 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4089 * @param {EventObject} e The mouse down event
4090 * @return {Object} The dragData
4092 getDragData : function(e){
4093 return Roo.dd.Registry.getHandleFromEvent(e);
4097 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4098 * this.dragData.ddel
4099 * @param {Number} x The x position of the click on the dragged object
4100 * @param {Number} y The y position of the click on the dragged object
4101 * @return {Boolean} true to continue the drag, false to cancel
4103 onInitDrag : function(x, y){
4104 this.proxy.update(this.dragData.ddel.cloneNode(true));
4105 this.onStartDrag(x, y);
4110 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4112 afterRepair : function(){
4114 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4116 this.dragging = false;
4120 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4121 * the XY of this.dragData.ddel
4122 * @param {EventObject} e The mouse up event
4123 * @return {Array} The xy location (e.g. [100, 200])
4125 getRepairXY : function(e){
4126 return Roo.Element.fly(this.dragData.ddel).getXY();
4130 * Ext JS Library 1.1.1
4131 * Copyright(c) 2006-2007, Ext JS, LLC.
4133 * Originally Released Under LGPL - original licence link has changed is not relivant.
4136 * <script type="text/javascript">
4139 * @class Roo.dd.DropZone
4140 * @extends Roo.dd.DropTarget
4141 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4142 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4144 * @param {String/HTMLElement/Element} el The container element
4145 * @param {Object} config
4147 Roo.dd.DropZone = function(el, config){
4148 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4151 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4153 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4154 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4155 * provide your own custom lookup.
4156 * @param {Event} e The event
4157 * @return {Object} data The custom data
4159 getTargetFromEvent : function(e){
4160 return Roo.dd.Registry.getTargetFromEvent(e);
4164 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4165 * that it has registered. This method has no default implementation and should be overridden to provide
4166 * node-specific processing if necessary.
4167 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4168 * {@link #getTargetFromEvent} for this node)
4169 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4170 * @param {Event} e The event
4171 * @param {Object} data An object containing arbitrary data supplied by the drag source
4173 onNodeEnter : function(n, dd, e, data){
4178 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4179 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4180 * overridden to provide the proper feedback.
4181 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4182 * {@link #getTargetFromEvent} for this node)
4183 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4184 * @param {Event} e The event
4185 * @param {Object} data An object containing arbitrary data supplied by the drag source
4186 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4187 * underlying {@link Roo.dd.StatusProxy} can be updated
4189 onNodeOver : function(n, dd, e, data){
4190 return this.dropAllowed;
4194 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4195 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4196 * node-specific processing if necessary.
4197 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4198 * {@link #getTargetFromEvent} for this node)
4199 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4200 * @param {Event} e The event
4201 * @param {Object} data An object containing arbitrary data supplied by the drag source
4203 onNodeOut : function(n, dd, e, data){
4208 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4209 * the drop node. The default implementation returns false, so it should be overridden to provide the
4210 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4211 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4212 * {@link #getTargetFromEvent} for this node)
4213 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4214 * @param {Event} e The event
4215 * @param {Object} data An object containing arbitrary data supplied by the drag source
4216 * @return {Boolean} True if the drop was valid, else false
4218 onNodeDrop : function(n, dd, e, data){
4223 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4224 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4225 * it should be overridden to provide the proper feedback if necessary.
4226 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4227 * @param {Event} e The event
4228 * @param {Object} data An object containing arbitrary data supplied by the drag source
4229 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4230 * underlying {@link Roo.dd.StatusProxy} can be updated
4232 onContainerOver : function(dd, e, data){
4233 return this.dropNotAllowed;
4237 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4238 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4239 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4240 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4241 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4242 * @param {Event} e The event
4243 * @param {Object} data An object containing arbitrary data supplied by the drag source
4244 * @return {Boolean} True if the drop was valid, else false
4246 onContainerDrop : function(dd, e, data){
4251 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4252 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4253 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4254 * you should override this method and provide a custom implementation.
4255 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4256 * @param {Event} e The event
4257 * @param {Object} data An object containing arbitrary data supplied by the drag source
4258 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4259 * underlying {@link Roo.dd.StatusProxy} can be updated
4261 notifyEnter : function(dd, e, data){
4262 return this.dropNotAllowed;
4266 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4267 * This method will be called on every mouse movement while the drag source is over the drop zone.
4268 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4269 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4270 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4271 * registered node, it will call {@link #onContainerOver}.
4272 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4273 * @param {Event} e The event
4274 * @param {Object} data An object containing arbitrary data supplied by the drag source
4275 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4276 * underlying {@link Roo.dd.StatusProxy} can be updated
4278 notifyOver : function(dd, e, data){
4279 var n = this.getTargetFromEvent(e);
4280 if(!n){ // not over valid drop target
4281 if(this.lastOverNode){
4282 this.onNodeOut(this.lastOverNode, dd, e, data);
4283 this.lastOverNode = null;
4285 return this.onContainerOver(dd, e, data);
4287 if(this.lastOverNode != n){
4288 if(this.lastOverNode){
4289 this.onNodeOut(this.lastOverNode, dd, e, data);
4291 this.onNodeEnter(n, dd, e, data);
4292 this.lastOverNode = n;
4294 return this.onNodeOver(n, dd, e, data);
4298 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4299 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4300 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4301 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4302 * @param {Event} e The event
4303 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4305 notifyOut : function(dd, e, data){
4306 if(this.lastOverNode){
4307 this.onNodeOut(this.lastOverNode, dd, e, data);
4308 this.lastOverNode = null;
4313 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4314 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4315 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4316 * otherwise it will call {@link #onContainerDrop}.
4317 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4318 * @param {Event} e The event
4319 * @param {Object} data An object containing arbitrary data supplied by the drag source
4320 * @return {Boolean} True if the drop was valid, else false
4322 notifyDrop : function(dd, e, data){
4323 if(this.lastOverNode){
4324 this.onNodeOut(this.lastOverNode, dd, e, data);
4325 this.lastOverNode = null;
4327 var n = this.getTargetFromEvent(e);
4329 this.onNodeDrop(n, dd, e, data) :
4330 this.onContainerDrop(dd, e, data);
4334 triggerCacheRefresh : function(){
4335 Roo.dd.DDM.refreshCache(this.groups);
4339 * Ext JS Library 1.1.1
4340 * Copyright(c) 2006-2007, Ext JS, LLC.
4342 * Originally Released Under LGPL - original licence link has changed is not relivant.
4345 * <script type="text/javascript">
4350 * @class Roo.data.SortTypes
4352 * Defines the default sorting (casting?) comparison functions used when sorting data.
4354 Roo.data.SortTypes = {
4356 * Default sort that does nothing
4357 * @param {Mixed} s The value being converted
4358 * @return {Mixed} The comparison value
4365 * The regular expression used to strip tags
4369 stripTagsRE : /<\/?[^>]+>/gi,
4372 * Strips all HTML tags to sort on text only
4373 * @param {Mixed} s The value being converted
4374 * @return {String} The comparison value
4376 asText : function(s){
4377 return String(s).replace(this.stripTagsRE, "");
4381 * Strips all HTML tags to sort on text only - Case insensitive
4382 * @param {Mixed} s The value being converted
4383 * @return {String} The comparison value
4385 asUCText : function(s){
4386 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4390 * Case insensitive string
4391 * @param {Mixed} s The value being converted
4392 * @return {String} The comparison value
4394 asUCString : function(s) {
4395 return String(s).toUpperCase();
4400 * @param {Mixed} s The value being converted
4401 * @return {Number} The comparison value
4403 asDate : function(s) {
4407 if(s instanceof Date){
4410 return Date.parse(String(s));
4415 * @param {Mixed} s The value being converted
4416 * @return {Float} The comparison value
4418 asFloat : function(s) {
4419 var val = parseFloat(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4426 * @param {Mixed} s The value being converted
4427 * @return {Number} The comparison value
4429 asInt : function(s) {
4430 var val = parseInt(String(s).replace(/,/g, ""));
4431 if(isNaN(val)) val = 0;
4436 * Ext JS Library 1.1.1
4437 * Copyright(c) 2006-2007, Ext JS, LLC.
4439 * Originally Released Under LGPL - original licence link has changed is not relivant.
4442 * <script type="text/javascript">
4446 * @class Roo.data.Record
4447 * Instances of this class encapsulate both record <em>definition</em> information, and record
4448 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4449 * to access Records cached in an {@link Roo.data.Store} object.<br>
4451 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4452 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4455 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4457 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4458 * {@link #create}. The parameters are the same.
4459 * @param {Array} data An associative Array of data values keyed by the field name.
4460 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4461 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4462 * not specified an integer id is generated.
4464 Roo.data.Record = function(data, id){
4465 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4470 * Generate a constructor for a specific record layout.
4471 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4472 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4473 * Each field definition object may contain the following properties: <ul>
4474 * <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,
4475 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4476 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4477 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4478 * is being used, then this is a string containing the javascript expression to reference the data relative to
4479 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4480 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4481 * this may be omitted.</p></li>
4482 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4483 * <ul><li>auto (Default, implies no conversion)</li>
4488 * <li>date</li></ul></p></li>
4489 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4490 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4491 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4492 * by the Reader into an object that will be stored in the Record. It is passed the
4493 * following parameters:<ul>
4494 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4496 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4498 * <br>usage:<br><pre><code>
4499 var TopicRecord = Roo.data.Record.create(
4500 {name: 'title', mapping: 'topic_title'},
4501 {name: 'author', mapping: 'username'},
4502 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4503 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4504 {name: 'lastPoster', mapping: 'user2'},
4505 {name: 'excerpt', mapping: 'post_text'}
4508 var myNewRecord = new TopicRecord({
4509 title: 'Do my job please',
4512 lastPost: new Date(),
4513 lastPoster: 'Animal',
4514 excerpt: 'No way dude!'
4516 myStore.add(myNewRecord);
4521 Roo.data.Record.create = function(o){
4523 f.superclass.constructor.apply(this, arguments);
4525 Roo.extend(f, Roo.data.Record);
4526 var p = f.prototype;
4527 p.fields = new Roo.util.MixedCollection(false, function(field){
4530 for(var i = 0, len = o.length; i < len; i++){
4531 p.fields.add(new Roo.data.Field(o[i]));
4533 f.getField = function(name){
4534 return p.fields.get(name);
4539 Roo.data.Record.AUTO_ID = 1000;
4540 Roo.data.Record.EDIT = 'edit';
4541 Roo.data.Record.REJECT = 'reject';
4542 Roo.data.Record.COMMIT = 'commit';
4544 Roo.data.Record.prototype = {
4546 * Readonly flag - true if this record has been modified.
4555 join : function(store){
4560 * Set the named field to the specified value.
4561 * @param {String} name The name of the field to set.
4562 * @param {Object} value The value to set the field to.
4564 set : function(name, value){
4565 if(this.data[name] == value){
4572 if(typeof this.modified[name] == 'undefined'){
4573 this.modified[name] = this.data[name];
4575 this.data[name] = value;
4577 this.store.afterEdit(this);
4582 * Get the value of the named field.
4583 * @param {String} name The name of the field to get the value of.
4584 * @return {Object} The value of the field.
4586 get : function(name){
4587 return this.data[name];
4591 beginEdit : function(){
4592 this.editing = true;
4597 cancelEdit : function(){
4598 this.editing = false;
4599 delete this.modified;
4603 endEdit : function(){
4604 this.editing = false;
4605 if(this.dirty && this.store){
4606 this.store.afterEdit(this);
4611 * Usually called by the {@link Roo.data.Store} which owns the Record.
4612 * Rejects all changes made to the Record since either creation, or the last commit operation.
4613 * Modified fields are reverted to their original values.
4615 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4616 * of reject operations.
4618 reject : function(){
4619 var m = this.modified;
4621 if(typeof m[n] != "function"){
4622 this.data[n] = m[n];
4626 delete this.modified;
4627 this.editing = false;
4629 this.store.afterReject(this);
4634 * Usually called by the {@link Roo.data.Store} which owns the Record.
4635 * Commits all changes made to the Record since either creation, or the last commit operation.
4637 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4638 * of commit operations.
4640 commit : function(){
4642 delete this.modified;
4643 this.editing = false;
4645 this.store.afterCommit(this);
4650 hasError : function(){
4651 return this.error != null;
4655 clearError : function(){
4660 * Creates a copy of this record.
4661 * @param {String} id (optional) A new record id if you don't want to use this record's id
4664 copy : function(newId) {
4665 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4669 * Ext JS Library 1.1.1
4670 * Copyright(c) 2006-2007, Ext JS, LLC.
4672 * Originally Released Under LGPL - original licence link has changed is not relivant.
4675 * <script type="text/javascript">
4681 * @class Roo.data.Store
4682 * @extends Roo.util.Observable
4683 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4684 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4686 * 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
4687 * has no knowledge of the format of the data returned by the Proxy.<br>
4689 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4690 * instances from the data object. These records are cached and made available through accessor functions.
4692 * Creates a new Store.
4693 * @param {Object} config A config object containing the objects needed for the Store to access data,
4694 * and read the data into Records.
4696 Roo.data.Store = function(config){
4697 this.data = new Roo.util.MixedCollection(false);
4698 this.data.getKey = function(o){
4701 this.baseParams = {};
4710 if(config && config.data){
4711 this.inlineData = config.data;
4715 Roo.apply(this, config);
4717 if(this.reader){ // reader passed
4718 this.reader = Roo.factory(this.reader, Roo.data);
4719 this.reader.xmodule = this.xmodule || false;
4720 if(!this.recordType){
4721 this.recordType = this.reader.recordType;
4723 if(this.reader.onMetaChange){
4724 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4728 if(this.recordType){
4729 this.fields = this.recordType.prototype.fields;
4735 * @event datachanged
4736 * Fires when the data cache has changed, and a widget which is using this Store
4737 * as a Record cache should refresh its view.
4738 * @param {Store} this
4743 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4744 * @param {Store} this
4745 * @param {Object} meta The JSON metadata
4750 * Fires when Records have been added to the Store
4751 * @param {Store} this
4752 * @param {Roo.data.Record[]} records The array of Records added
4753 * @param {Number} index The index at which the record(s) were added
4758 * Fires when a Record has been removed from the Store
4759 * @param {Store} this
4760 * @param {Roo.data.Record} record The Record that was removed
4761 * @param {Number} index The index at which the record was removed
4766 * Fires when a Record has been updated
4767 * @param {Store} this
4768 * @param {Roo.data.Record} record The Record that was updated
4769 * @param {String} operation The update operation being performed. Value may be one of:
4771 Roo.data.Record.EDIT
4772 Roo.data.Record.REJECT
4773 Roo.data.Record.COMMIT
4779 * Fires when the data cache has been cleared.
4780 * @param {Store} this
4785 * Fires before a request is made for a new data object. If the beforeload handler returns false
4786 * the load action will be canceled.
4787 * @param {Store} this
4788 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4793 * Fires after a new set of Records has been loaded.
4794 * @param {Store} this
4795 * @param {Roo.data.Record[]} records The Records that were loaded
4796 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4800 * @event loadexception
4801 * Fires if an exception occurs in the Proxy during loading.
4802 * Called with the signature of the Proxy's "loadexception" event.
4803 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4806 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4807 * @param {Object} load options
4808 * @param {Object} jsonData from your request (normally this contains the Exception)
4810 loadexception : true
4814 this.proxy = Roo.factory(this.proxy, Roo.data);
4815 this.proxy.xmodule = this.xmodule || false;
4816 this.relayEvents(this.proxy, ["loadexception"]);
4818 this.sortToggle = {};
4820 Roo.data.Store.superclass.constructor.call(this);
4822 if(this.inlineData){
4823 this.loadData(this.inlineData);
4824 delete this.inlineData;
4827 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4829 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4830 * without a remote query - used by combo/forms at present.
4834 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4837 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4840 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4841 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4844 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4845 * on any HTTP request
4848 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4851 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4852 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4857 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4858 * loaded or when a record is removed. (defaults to false).
4860 pruneModifiedRecords : false,
4866 * Add Records to the Store and fires the add event.
4867 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4869 add : function(records){
4870 records = [].concat(records);
4871 for(var i = 0, len = records.length; i < len; i++){
4872 records[i].join(this);
4874 var index = this.data.length;
4875 this.data.addAll(records);
4876 this.fireEvent("add", this, records, index);
4880 * Remove a Record from the Store and fires the remove event.
4881 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4883 remove : function(record){
4884 var index = this.data.indexOf(record);
4885 this.data.removeAt(index);
4886 if(this.pruneModifiedRecords){
4887 this.modified.remove(record);
4889 this.fireEvent("remove", this, record, index);
4893 * Remove all Records from the Store and fires the clear event.
4895 removeAll : function(){
4897 if(this.pruneModifiedRecords){
4900 this.fireEvent("clear", this);
4904 * Inserts Records to the Store at the given index and fires the add event.
4905 * @param {Number} index The start index at which to insert the passed Records.
4906 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4908 insert : function(index, records){
4909 records = [].concat(records);
4910 for(var i = 0, len = records.length; i < len; i++){
4911 this.data.insert(index, records[i]);
4912 records[i].join(this);
4914 this.fireEvent("add", this, records, index);
4918 * Get the index within the cache of the passed Record.
4919 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4920 * @return {Number} The index of the passed Record. Returns -1 if not found.
4922 indexOf : function(record){
4923 return this.data.indexOf(record);
4927 * Get the index within the cache of the Record with the passed id.
4928 * @param {String} id The id of the Record to find.
4929 * @return {Number} The index of the Record. Returns -1 if not found.
4931 indexOfId : function(id){
4932 return this.data.indexOfKey(id);
4936 * Get the Record with the specified id.
4937 * @param {String} id The id of the Record to find.
4938 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4940 getById : function(id){
4941 return this.data.key(id);
4945 * Get the Record at the specified index.
4946 * @param {Number} index The index of the Record to find.
4947 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4949 getAt : function(index){
4950 return this.data.itemAt(index);
4954 * Returns a range of Records between specified indices.
4955 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4956 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4957 * @return {Roo.data.Record[]} An array of Records
4959 getRange : function(start, end){
4960 return this.data.getRange(start, end);
4964 storeOptions : function(o){
4965 o = Roo.apply({}, o);
4968 this.lastOptions = o;
4972 * Loads the Record cache from the configured Proxy using the configured Reader.
4974 * If using remote paging, then the first load call must specify the <em>start</em>
4975 * and <em>limit</em> properties in the options.params property to establish the initial
4976 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4978 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4979 * and this call will return before the new data has been loaded. Perform any post-processing
4980 * in a callback function, or in a "load" event handler.</strong>
4982 * @param {Object} options An object containing properties which control loading options:<ul>
4983 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4984 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4985 * passed the following arguments:<ul>
4986 * <li>r : Roo.data.Record[]</li>
4987 * <li>options: Options object from the load call</li>
4988 * <li>success: Boolean success indicator</li></ul></li>
4989 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4990 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4993 load : function(options){
4994 options = options || {};
4995 if(this.fireEvent("beforeload", this, options) !== false){
4996 this.storeOptions(options);
4997 var p = Roo.apply(options.params || {}, this.baseParams);
4998 // if meta was not loaded from remote source.. try requesting it.
4999 if (!this.reader.metaFromRemote) {
5002 if(this.sortInfo && this.remoteSort){
5003 var pn = this.paramNames;
5004 p[pn["sort"]] = this.sortInfo.field;
5005 p[pn["dir"]] = this.sortInfo.direction;
5007 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5012 * Reloads the Record cache from the configured Proxy using the configured Reader and
5013 * the options from the last load operation performed.
5014 * @param {Object} options (optional) An object containing properties which may override the options
5015 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5016 * the most recently used options are reused).
5018 reload : function(options){
5019 this.load(Roo.applyIf(options||{}, this.lastOptions));
5023 // Called as a callback by the Reader during a load operation.
5024 loadRecords : function(o, options, success){
5025 if(!o || success === false){
5026 if(success !== false){
5027 this.fireEvent("load", this, [], options);
5029 if(options.callback){
5030 options.callback.call(options.scope || this, [], options, false);
5034 // if data returned failure - throw an exception.
5035 if (o.success === false) {
5036 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5039 var r = o.records, t = o.totalRecords || r.length;
5040 if(!options || options.add !== true){
5041 if(this.pruneModifiedRecords){
5044 for(var i = 0, len = r.length; i < len; i++){
5048 this.data = this.snapshot;
5049 delete this.snapshot;
5052 this.data.addAll(r);
5053 this.totalLength = t;
5055 this.fireEvent("datachanged", this);
5057 this.totalLength = Math.max(t, this.data.length+r.length);
5060 this.fireEvent("load", this, r, options);
5061 if(options.callback){
5062 options.callback.call(options.scope || this, r, options, true);
5067 * Loads data from a passed data block. A Reader which understands the format of the data
5068 * must have been configured in the constructor.
5069 * @param {Object} data The data block from which to read the Records. The format of the data expected
5070 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5071 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5073 loadData : function(o, append){
5074 var r = this.reader.readRecords(o);
5075 this.loadRecords(r, {add: append}, true);
5079 * Gets the number of cached records.
5081 * <em>If using paging, this may not be the total size of the dataset. If the data object
5082 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5083 * the data set size</em>
5085 getCount : function(){
5086 return this.data.length || 0;
5090 * Gets the total number of records in the dataset as returned by the server.
5092 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5093 * the dataset size</em>
5095 getTotalCount : function(){
5096 return this.totalLength || 0;
5100 * Returns the sort state of the Store as an object with two properties:
5102 field {String} The name of the field by which the Records are sorted
5103 direction {String} The sort order, "ASC" or "DESC"
5106 getSortState : function(){
5107 return this.sortInfo;
5111 applySort : function(){
5112 if(this.sortInfo && !this.remoteSort){
5113 var s = this.sortInfo, f = s.field;
5114 var st = this.fields.get(f).sortType;
5115 var fn = function(r1, r2){
5116 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5117 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5119 this.data.sort(s.direction, fn);
5120 if(this.snapshot && this.snapshot != this.data){
5121 this.snapshot.sort(s.direction, fn);
5127 * Sets the default sort column and order to be used by the next load operation.
5128 * @param {String} fieldName The name of the field to sort by.
5129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131 setDefaultSort : function(field, dir){
5132 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5137 * If remote sorting is used, the sort is performed on the server, and the cache is
5138 * reloaded. If local sorting is used, the cache is sorted internally.
5139 * @param {String} fieldName The name of the field to sort by.
5140 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5142 sort : function(fieldName, dir){
5143 var f = this.fields.get(fieldName);
5145 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5146 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5151 this.sortToggle[f.name] = dir;
5152 this.sortInfo = {field: f.name, direction: dir};
5153 if(!this.remoteSort){
5155 this.fireEvent("datachanged", this);
5157 this.load(this.lastOptions);
5162 * Calls the specified function for each of the Records in the cache.
5163 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5164 * Returning <em>false</em> aborts and exits the iteration.
5165 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5167 each : function(fn, scope){
5168 this.data.each(fn, scope);
5172 * Gets all records modified since the last commit. Modified records are persisted across load operations
5173 * (e.g., during paging).
5174 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5176 getModifiedRecords : function(){
5177 return this.modified;
5181 createFilterFn : function(property, value, anyMatch){
5182 if(!value.exec){ // not a regex
5183 value = String(value);
5184 if(value.length == 0){
5187 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5190 return value.test(r.data[property]);
5195 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5196 * @param {String} property A field on your records
5197 * @param {Number} start The record index to start at (defaults to 0)
5198 * @param {Number} end The last record index to include (defaults to length - 1)
5199 * @return {Number} The sum
5201 sum : function(property, start, end){
5202 var rs = this.data.items, v = 0;
5204 end = (end || end === 0) ? end : rs.length-1;
5206 for(var i = start; i <= end; i++){
5207 v += (rs[i].data[property] || 0);
5213 * Filter the records by a specified property.
5214 * @param {String} field A field on your records
5215 * @param {String/RegExp} value Either a string that the field
5216 * should start with or a RegExp to test against the field
5217 * @param {Boolean} anyMatch True to match any part not just the beginning
5219 filter : function(property, value, anyMatch){
5220 var fn = this.createFilterFn(property, value, anyMatch);
5221 return fn ? this.filterBy(fn) : this.clearFilter();
5225 * Filter by a function. The specified function will be called with each
5226 * record in this data source. If the function returns true the record is included,
5227 * otherwise it is filtered.
5228 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5229 * @param {Object} scope (optional) The scope of the function (defaults to this)
5231 filterBy : function(fn, scope){
5232 this.snapshot = this.snapshot || this.data;
5233 this.data = this.queryBy(fn, scope||this);
5234 this.fireEvent("datachanged", this);
5238 * Query the records by a specified property.
5239 * @param {String} field A field on your records
5240 * @param {String/RegExp} value Either a string that the field
5241 * should start with or a RegExp to test against the field
5242 * @param {Boolean} anyMatch True to match any part not just the beginning
5243 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5245 query : function(property, value, anyMatch){
5246 var fn = this.createFilterFn(property, value, anyMatch);
5247 return fn ? this.queryBy(fn) : this.data.clone();
5251 * Query by a function. The specified function will be called with each
5252 * record in this data source. If the function returns true the record is included
5254 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5255 * @param {Object} scope (optional) The scope of the function (defaults to this)
5256 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5258 queryBy : function(fn, scope){
5259 var data = this.snapshot || this.data;
5260 return data.filterBy(fn, scope||this);
5264 * Collects unique values for a particular dataIndex from this store.
5265 * @param {String} dataIndex The property to collect
5266 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5267 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5268 * @return {Array} An array of the unique values
5270 collect : function(dataIndex, allowNull, bypassFilter){
5271 var d = (bypassFilter === true && this.snapshot) ?
5272 this.snapshot.items : this.data.items;
5273 var v, sv, r = [], l = {};
5274 for(var i = 0, len = d.length; i < len; i++){
5275 v = d[i].data[dataIndex];
5277 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5286 * Revert to a view of the Record cache with no filtering applied.
5287 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5289 clearFilter : function(suppressEvent){
5290 if(this.snapshot && this.snapshot != this.data){
5291 this.data = this.snapshot;
5292 delete this.snapshot;
5293 if(suppressEvent !== true){
5294 this.fireEvent("datachanged", this);
5300 afterEdit : function(record){
5301 if(this.modified.indexOf(record) == -1){
5302 this.modified.push(record);
5304 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5308 afterReject : function(record){
5309 this.modified.remove(record);
5310 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5314 afterCommit : function(record){
5315 this.modified.remove(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5320 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5321 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5323 commitChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5332 * Cancel outstanding changes on all changed records.
5334 rejectChanges : function(){
5335 var m = this.modified.slice(0);
5337 for(var i = 0, len = m.length; i < len; i++){
5342 onMetaChange : function(meta, rtype, o){
5343 this.recordType = rtype;
5344 this.fields = rtype.prototype.fields;
5345 delete this.snapshot;
5346 this.sortInfo = meta.sortInfo || this.sortInfo;
5348 this.fireEvent('metachange', this, this.reader.meta);
5352 * Ext JS Library 1.1.1
5353 * Copyright(c) 2006-2007, Ext JS, LLC.
5355 * Originally Released Under LGPL - original licence link has changed is not relivant.
5358 * <script type="text/javascript">
5362 * @class Roo.data.SimpleStore
5363 * @extends Roo.data.Store
5364 * Small helper class to make creating Stores from Array data easier.
5365 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5366 * @cfg {Array} fields An array of field definition objects, or field name strings.
5367 * @cfg {Array} data The multi-dimensional array of data
5369 * @param {Object} config
5371 Roo.data.SimpleStore = function(config){
5372 Roo.data.SimpleStore.superclass.constructor.call(this, {
5374 reader: new Roo.data.ArrayReader({
5377 Roo.data.Record.create(config.fields)
5379 proxy : new Roo.data.MemoryProxy(config.data)
5383 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5385 * Ext JS Library 1.1.1
5386 * Copyright(c) 2006-2007, Ext JS, LLC.
5388 * Originally Released Under LGPL - original licence link has changed is not relivant.
5391 * <script type="text/javascript">
5396 * @extends Roo.data.Store
5397 * @class Roo.data.JsonStore
5398 * Small helper class to make creating Stores for JSON data easier. <br/>
5400 var store = new Roo.data.JsonStore({
5401 url: 'get-images.php',
5403 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5406 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5407 * JsonReader and HttpProxy (unless inline data is provided).</b>
5408 * @cfg {Array} fields An array of field definition objects, or field name strings.
5410 * @param {Object} config
5412 Roo.data.JsonStore = function(c){
5413 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5414 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5415 reader: new Roo.data.JsonReader(c, c.fields)
5418 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5420 * Ext JS Library 1.1.1
5421 * Copyright(c) 2006-2007, Ext JS, LLC.
5423 * Originally Released Under LGPL - original licence link has changed is not relivant.
5426 * <script type="text/javascript">
5430 Roo.data.Field = function(config){
5431 if(typeof config == "string"){
5432 config = {name: config};
5434 Roo.apply(this, config);
5440 var st = Roo.data.SortTypes;
5441 // named sortTypes are supported, here we look them up
5442 if(typeof this.sortType == "string"){
5443 this.sortType = st[this.sortType];
5446 // set default sortType for strings and dates
5450 this.sortType = st.asUCString;
5453 this.sortType = st.asDate;
5456 this.sortType = st.none;
5461 var stripRe = /[\$,%]/g;
5463 // prebuilt conversion function for this field, instead of
5464 // switching every time we're reading a value
5466 var cv, dateFormat = this.dateFormat;
5471 cv = function(v){ return v; };
5474 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5478 return v !== undefined && v !== null && v !== '' ?
5479 parseInt(String(v).replace(stripRe, ""), 10) : '';
5484 return v !== undefined && v !== null && v !== '' ?
5485 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5490 cv = function(v){ return v === true || v === "true" || v == 1; };
5497 if(v instanceof Date){
5501 if(dateFormat == "timestamp"){
5502 return new Date(v*1000);
5504 return Date.parseDate(v, dateFormat);
5506 var parsed = Date.parse(v);
5507 return parsed ? new Date(parsed) : null;
5516 Roo.data.Field.prototype = {
5524 * Ext JS Library 1.1.1
5525 * Copyright(c) 2006-2007, Ext JS, LLC.
5527 * Originally Released Under LGPL - original licence link has changed is not relivant.
5530 * <script type="text/javascript">
5533 // Base class for reading structured data from a data source. This class is intended to be
5534 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5537 * @class Roo.data.DataReader
5538 * Base class for reading structured data from a data source. This class is intended to be
5539 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5542 Roo.data.DataReader = function(meta, recordType){
5546 this.recordType = recordType instanceof Array ?
5547 Roo.data.Record.create(recordType) : recordType;
5550 Roo.data.DataReader.prototype = {
5552 * Create an empty record
5553 * @param {Object} data (optional) - overlay some values
5554 * @return {Roo.data.Record} record created.
5556 newRow : function(d) {
5558 this.recordType.prototype.fields.each(function(c) {
5560 case 'int' : da[c.name] = 0; break;
5561 case 'date' : da[c.name] = new Date(); break;
5562 case 'float' : da[c.name] = 0.0; break;
5563 case 'boolean' : da[c.name] = false; break;
5564 default : da[c.name] = ""; break;
5568 return new this.recordType(Roo.apply(da, d));
5573 * Ext JS Library 1.1.1
5574 * Copyright(c) 2006-2007, Ext JS, LLC.
5576 * Originally Released Under LGPL - original licence link has changed is not relivant.
5579 * <script type="text/javascript">
5583 * @class Roo.data.DataProxy
5584 * @extends Roo.data.Observable
5585 * This class is an abstract base class for implementations which provide retrieval of
5586 * unformatted data objects.<br>
5588 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5589 * (of the appropriate type which knows how to parse the data object) to provide a block of
5590 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5592 * Custom implementations must implement the load method as described in
5593 * {@link Roo.data.HttpProxy#load}.
5595 Roo.data.DataProxy = function(){
5599 * Fires before a network request is made to retrieve a data object.
5600 * @param {Object} This DataProxy object.
5601 * @param {Object} params The params parameter to the load function.
5606 * Fires before the load method's callback is called.
5607 * @param {Object} This DataProxy object.
5608 * @param {Object} o The data object.
5609 * @param {Object} arg The callback argument object passed to the load function.
5613 * @event loadexception
5614 * Fires if an Exception occurs during data retrieval.
5615 * @param {Object} This DataProxy object.
5616 * @param {Object} o The data object.
5617 * @param {Object} arg The callback argument object passed to the load function.
5618 * @param {Object} e The Exception.
5620 loadexception : true
5622 Roo.data.DataProxy.superclass.constructor.call(this);
5625 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5628 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5632 * Ext JS Library 1.1.1
5633 * Copyright(c) 2006-2007, Ext JS, LLC.
5635 * Originally Released Under LGPL - original licence link has changed is not relivant.
5638 * <script type="text/javascript">
5641 * @class Roo.data.MemoryProxy
5642 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5643 * to the Reader when its load method is called.
5645 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5647 Roo.data.MemoryProxy = function(data){
5651 Roo.data.MemoryProxy.superclass.constructor.call(this);
5655 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5657 * Load data from the requested source (in this case an in-memory
5658 * data object passed to the constructor), read the data object into
5659 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5660 * process that block using the passed callback.
5661 * @param {Object} params This parameter is not used by the MemoryProxy class.
5662 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5663 * object into a block of Roo.data.Records.
5664 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5665 * The function must be passed <ul>
5666 * <li>The Record block object</li>
5667 * <li>The "arg" argument from the load function</li>
5668 * <li>A boolean success indicator</li>
5670 * @param {Object} scope The scope in which to call the callback
5671 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5673 load : function(params, reader, callback, scope, arg){
5674 params = params || {};
5677 result = reader.readRecords(this.data);
5679 this.fireEvent("loadexception", this, arg, null, e);
5680 callback.call(scope, null, arg, false);
5683 callback.call(scope, result, arg, true);
5687 update : function(params, records){
5692 * Ext JS Library 1.1.1
5693 * Copyright(c) 2006-2007, Ext JS, LLC.
5695 * Originally Released Under LGPL - original licence link has changed is not relivant.
5698 * <script type="text/javascript">
5701 * @class Roo.data.HttpProxy
5702 * @extends Roo.data.DataProxy
5703 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5704 * configured to reference a certain URL.<br><br>
5706 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5707 * from which the running page was served.<br><br>
5709 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5711 * Be aware that to enable the browser to parse an XML document, the server must set
5712 * the Content-Type header in the HTTP response to "text/xml".
5714 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5715 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5716 * will be used to make the request.
5718 Roo.data.HttpProxy = function(conn){
5719 Roo.data.HttpProxy.superclass.constructor.call(this);
5720 // is conn a conn config or a real conn?
5722 this.useAjax = !conn || !conn.events;
5726 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5727 // thse are take from connection...
5730 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5733 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5734 * extra parameters to each request made by this object. (defaults to undefined)
5737 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5738 * to each request made by this object. (defaults to undefined)
5741 * @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)
5744 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5747 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5753 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5757 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5758 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5759 * a finer-grained basis than the DataProxy events.
5761 getConnection : function(){
5762 return this.useAjax ? Roo.Ajax : this.conn;
5766 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5767 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5768 * process that block using the passed callback.
5769 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5770 * for the request to the remote server.
5771 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5772 * object into a block of Roo.data.Records.
5773 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5774 * The function must be passed <ul>
5775 * <li>The Record block object</li>
5776 * <li>The "arg" argument from the load function</li>
5777 * <li>A boolean success indicator</li>
5779 * @param {Object} scope The scope in which to call the callback
5780 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5782 load : function(params, reader, callback, scope, arg){
5783 if(this.fireEvent("beforeload", this, params) !== false){
5785 params : params || {},
5787 callback : callback,
5792 callback : this.loadResponse,
5796 Roo.applyIf(o, this.conn);
5797 if(this.activeRequest){
5798 Roo.Ajax.abort(this.activeRequest);
5800 this.activeRequest = Roo.Ajax.request(o);
5802 this.conn.request(o);
5805 callback.call(scope||this, null, arg, false);
5810 loadResponse : function(o, success, response){
5811 delete this.activeRequest;
5813 this.fireEvent("loadexception", this, o, response);
5814 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5819 result = o.reader.read(response);
5821 this.fireEvent("loadexception", this, o, response, e);
5822 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5826 this.fireEvent("load", this, o, o.request.arg);
5827 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5831 update : function(dataSet){
5836 updateResponse : function(dataSet){
5841 * Ext JS Library 1.1.1
5842 * Copyright(c) 2006-2007, Ext JS, LLC.
5844 * Originally Released Under LGPL - original licence link has changed is not relivant.
5847 * <script type="text/javascript">
5851 * @class Roo.data.ScriptTagProxy
5852 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5853 * other than the originating domain of the running page.<br><br>
5855 * <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
5856 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5858 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5859 * source code that is used as the source inside a <script> tag.<br><br>
5861 * In order for the browser to process the returned data, the server must wrap the data object
5862 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5863 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5864 * depending on whether the callback name was passed:
5867 boolean scriptTag = false;
5868 String cb = request.getParameter("callback");
5871 response.setContentType("text/javascript");
5873 response.setContentType("application/x-json");
5875 Writer out = response.getWriter();
5877 out.write(cb + "(");
5879 out.print(dataBlock.toJsonString());
5886 * @param {Object} config A configuration object.
5888 Roo.data.ScriptTagProxy = function(config){
5889 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5890 Roo.apply(this, config);
5891 this.head = document.getElementsByTagName("head")[0];
5894 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5896 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5898 * @cfg {String} url The URL from which to request the data object.
5901 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5905 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5906 * the server the name of the callback function set up by the load call to process the returned data object.
5907 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5908 * javascript output which calls this named function passing the data object as its only parameter.
5910 callbackParam : "callback",
5912 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5913 * name to the request.
5918 * Load data from the configured URL, read the data object into
5919 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5920 * process that block using the passed callback.
5921 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5922 * for the request to the remote server.
5923 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5924 * object into a block of Roo.data.Records.
5925 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5926 * The function must be passed <ul>
5927 * <li>The Record block object</li>
5928 * <li>The "arg" argument from the load function</li>
5929 * <li>A boolean success indicator</li>
5931 * @param {Object} scope The scope in which to call the callback
5932 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5934 load : function(params, reader, callback, scope, arg){
5935 if(this.fireEvent("beforeload", this, params) !== false){
5937 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5940 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5942 url += "&_dc=" + (new Date().getTime());
5944 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5947 cb : "stcCallback"+transId,
5948 scriptId : "stcScript"+transId,
5952 callback : callback,
5958 window[trans.cb] = function(o){
5959 conn.handleResponse(o, trans);
5962 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5964 if(this.autoAbort !== false){
5968 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5970 var script = document.createElement("script");
5971 script.setAttribute("src", url);
5972 script.setAttribute("type", "text/javascript");
5973 script.setAttribute("id", trans.scriptId);
5974 this.head.appendChild(script);
5978 callback.call(scope||this, null, arg, false);
5983 isLoading : function(){
5984 return this.trans ? true : false;
5988 * Abort the current server request.
5991 if(this.isLoading()){
5992 this.destroyTrans(this.trans);
5997 destroyTrans : function(trans, isLoaded){
5998 this.head.removeChild(document.getElementById(trans.scriptId));
5999 clearTimeout(trans.timeoutId);
6001 window[trans.cb] = undefined;
6003 delete window[trans.cb];
6006 // if hasn't been loaded, wait for load to remove it to prevent script error
6007 window[trans.cb] = function(){
6008 window[trans.cb] = undefined;
6010 delete window[trans.cb];
6017 handleResponse : function(o, trans){
6019 this.destroyTrans(trans, true);
6022 result = trans.reader.readRecords(o);
6024 this.fireEvent("loadexception", this, o, trans.arg, e);
6025 trans.callback.call(trans.scope||window, null, trans.arg, false);
6028 this.fireEvent("load", this, o, trans.arg);
6029 trans.callback.call(trans.scope||window, result, trans.arg, true);
6033 handleFailure : function(trans){
6035 this.destroyTrans(trans, false);
6036 this.fireEvent("loadexception", this, null, trans.arg);
6037 trans.callback.call(trans.scope||window, null, trans.arg, false);
6041 * Ext JS Library 1.1.1
6042 * Copyright(c) 2006-2007, Ext JS, LLC.
6044 * Originally Released Under LGPL - original licence link has changed is not relivant.
6047 * <script type="text/javascript">
6051 * @class Roo.data.JsonReader
6052 * @extends Roo.data.DataReader
6053 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6054 * based on mappings in a provided Roo.data.Record constructor.
6056 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6057 * in the reply previously.
6062 var RecordDef = Roo.data.Record.create([
6063 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6064 {name: 'occupation'} // This field will use "occupation" as the mapping.
6066 var myReader = new Roo.data.JsonReader({
6067 totalProperty: "results", // The property which contains the total dataset size (optional)
6068 root: "rows", // The property which contains an Array of row objects
6069 id: "id" // The property within each row object that provides an ID for the record (optional)
6073 * This would consume a JSON file like this:
6075 { 'results': 2, 'rows': [
6076 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6077 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6080 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6081 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6082 * paged from the remote server.
6083 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6084 * @cfg {String} root name of the property which contains the Array of row objects.
6085 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6087 * Create a new JsonReader
6088 * @param {Object} meta Metadata configuration options
6089 * @param {Object} recordType Either an Array of field definition objects,
6090 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6092 Roo.data.JsonReader = function(meta, recordType){
6095 // set some defaults:
6097 totalProperty: 'total',
6098 successProperty : 'success',
6103 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6105 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6108 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6109 * Used by Store query builder to append _requestMeta to params.
6112 metaFromRemote : false,
6114 * This method is only used by a DataProxy which has retrieved data from a remote server.
6115 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6116 * @return {Object} data A data block which is used by an Roo.data.Store object as
6117 * a cache of Roo.data.Records.
6119 read : function(response){
6120 var json = response.responseText;
6122 var o = /* eval:var:o */ eval("("+json+")");
6124 throw {message: "JsonReader.read: Json object not found"};
6130 this.metaFromRemote = true;
6131 this.meta = o.metaData;
6132 this.recordType = Roo.data.Record.create(o.metaData.fields);
6133 this.onMetaChange(this.meta, this.recordType, o);
6135 return this.readRecords(o);
6138 // private function a store will implement
6139 onMetaChange : function(meta, recordType, o){
6146 simpleAccess: function(obj, subsc) {
6153 getJsonAccessor: function(){
6155 return function(expr) {
6157 return(re.test(expr))
6158 ? new Function("obj", "return obj." + expr)
6168 * Create a data block containing Roo.data.Records from an XML document.
6169 * @param {Object} o An object which contains an Array of row objects in the property specified
6170 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6171 * which contains the total size of the dataset.
6172 * @return {Object} data A data block which is used by an Roo.data.Store object as
6173 * a cache of Roo.data.Records.
6175 readRecords : function(o){
6177 * After any data loads, the raw JSON data is available for further custom processing.
6181 var s = this.meta, Record = this.recordType,
6182 f = Record.prototype.fields, fi = f.items, fl = f.length;
6184 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6186 if(s.totalProperty) {
6187 this.getTotal = this.getJsonAccessor(s.totalProperty);
6189 if(s.successProperty) {
6190 this.getSuccess = this.getJsonAccessor(s.successProperty);
6192 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6194 var g = this.getJsonAccessor(s.id);
6195 this.getId = function(rec) {
6197 return (r === undefined || r === "") ? null : r;
6200 this.getId = function(){return null;};
6203 for(var jj = 0; jj < fl; jj++){
6205 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6206 this.ef[jj] = this.getJsonAccessor(map);
6210 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6211 if(s.totalProperty){
6212 var vt = parseInt(this.getTotal(o), 10);
6217 if(s.successProperty){
6218 var vs = this.getSuccess(o);
6219 if(vs === false || vs === 'false'){
6224 for(var i = 0; i < c; i++){
6227 var id = this.getId(n);
6228 for(var j = 0; j < fl; j++){
6230 var v = this.ef[j](n);
6232 Roo.log('missing convert for ' + f.name);
6236 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6238 var record = new Record(values, id);
6240 records[i] = record;
6245 totalRecords : totalRecords
6250 * Ext JS Library 1.1.1
6251 * Copyright(c) 2006-2007, Ext JS, LLC.
6253 * Originally Released Under LGPL - original licence link has changed is not relivant.
6256 * <script type="text/javascript">
6260 * @class Roo.data.XmlReader
6261 * @extends Roo.data.DataReader
6262 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6263 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6265 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6266 * header in the HTTP response must be set to "text/xml".</em>
6270 var RecordDef = Roo.data.Record.create([
6271 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6272 {name: 'occupation'} // This field will use "occupation" as the mapping.
6274 var myReader = new Roo.data.XmlReader({
6275 totalRecords: "results", // The element which contains the total dataset size (optional)
6276 record: "row", // The repeated element which contains row information
6277 id: "id" // The element within the row that provides an ID for the record (optional)
6281 * This would consume an XML file like this:
6285 <results>2</results>
6288 <name>Bill</name>
6289 <occupation>Gardener</occupation>
6293 <name>Ben</name>
6294 <occupation>Horticulturalist</occupation>
6298 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6299 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6300 * paged from the remote server.
6301 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6302 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6303 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6304 * a record identifier value.
6306 * Create a new XmlReader
6307 * @param {Object} meta Metadata configuration options
6308 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6309 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6310 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6312 Roo.data.XmlReader = function(meta, recordType){
6314 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6316 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6318 * This method is only used by a DataProxy which has retrieved data from a remote server.
6319 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6320 * to contain a method called 'responseXML' that returns an XML document object.
6321 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6322 * a cache of Roo.data.Records.
6324 read : function(response){
6325 var doc = response.responseXML;
6327 throw {message: "XmlReader.read: XML Document not available"};
6329 return this.readRecords(doc);
6333 * Create a data block containing Roo.data.Records from an XML document.
6334 * @param {Object} doc A parsed XML document.
6335 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6336 * a cache of Roo.data.Records.
6338 readRecords : function(doc){
6340 * After any data loads/reads, the raw XML Document is available for further custom processing.
6344 var root = doc.documentElement || doc;
6345 var q = Roo.DomQuery;
6346 var recordType = this.recordType, fields = recordType.prototype.fields;
6347 var sid = this.meta.id;
6348 var totalRecords = 0, success = true;
6349 if(this.meta.totalRecords){
6350 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6353 if(this.meta.success){
6354 var sv = q.selectValue(this.meta.success, root, true);
6355 success = sv !== false && sv !== 'false';
6358 var ns = q.select(this.meta.record, root);
6359 for(var i = 0, len = ns.length; i < len; i++) {
6362 var id = sid ? q.selectValue(sid, n) : undefined;
6363 for(var j = 0, jlen = fields.length; j < jlen; j++){
6364 var f = fields.items[j];
6365 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6369 var record = new recordType(values, id);
6371 records[records.length] = record;
6377 totalRecords : totalRecords || records.length
6382 * Ext JS Library 1.1.1
6383 * Copyright(c) 2006-2007, Ext JS, LLC.
6385 * Originally Released Under LGPL - original licence link has changed is not relivant.
6388 * <script type="text/javascript">
6392 * @class Roo.data.ArrayReader
6393 * @extends Roo.data.DataReader
6394 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6395 * Each element of that Array represents a row of data fields. The
6396 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6397 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6401 var RecordDef = Roo.data.Record.create([
6402 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6403 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6405 var myReader = new Roo.data.ArrayReader({
6406 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6410 * This would consume an Array like this:
6412 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6414 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6416 * Create a new JsonReader
6417 * @param {Object} meta Metadata configuration options.
6418 * @param {Object} recordType Either an Array of field definition objects
6419 * as specified to {@link Roo.data.Record#create},
6420 * or an {@link Roo.data.Record} object
6421 * created using {@link Roo.data.Record#create}.
6423 Roo.data.ArrayReader = function(meta, recordType){
6424 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6427 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6429 * Create a data block containing Roo.data.Records from an XML document.
6430 * @param {Object} o An Array of row objects which represents the dataset.
6431 * @return {Object} data A data block which is used by an Roo.data.Store object as
6432 * a cache of Roo.data.Records.
6434 readRecords : function(o){
6435 var sid = this.meta ? this.meta.id : null;
6436 var recordType = this.recordType, fields = recordType.prototype.fields;
6439 for(var i = 0; i < root.length; i++){
6442 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6443 for(var j = 0, jlen = fields.length; j < jlen; j++){
6444 var f = fields.items[j];
6445 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6446 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6450 var record = new recordType(values, id);
6452 records[records.length] = record;
6456 totalRecords : records.length
6461 * Ext JS Library 1.1.1
6462 * Copyright(c) 2006-2007, Ext JS, LLC.
6464 * Originally Released Under LGPL - original licence link has changed is not relivant.
6467 * <script type="text/javascript">
6472 * @class Roo.data.Tree
6473 * @extends Roo.util.Observable
6474 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6475 * in the tree have most standard DOM functionality.
6477 * @param {Node} root (optional) The root node
6479 Roo.data.Tree = function(root){
6482 * The root node for this tree
6487 this.setRootNode(root);
6492 * Fires when a new child node is appended to a node in this tree.
6493 * @param {Tree} tree The owner tree
6494 * @param {Node} parent The parent node
6495 * @param {Node} node The newly appended node
6496 * @param {Number} index The index of the newly appended node
6501 * Fires when a child node is removed from a node in this tree.
6502 * @param {Tree} tree The owner tree
6503 * @param {Node} parent The parent node
6504 * @param {Node} node The child node removed
6509 * Fires when a node is moved to a new location in the tree
6510 * @param {Tree} tree The owner tree
6511 * @param {Node} node The node moved
6512 * @param {Node} oldParent The old parent of this node
6513 * @param {Node} newParent The new parent of this node
6514 * @param {Number} index The index it was moved to
6519 * Fires when a new child node is inserted in a node in this tree.
6520 * @param {Tree} tree The owner tree
6521 * @param {Node} parent The parent node
6522 * @param {Node} node The child node inserted
6523 * @param {Node} refNode The child node the node was inserted before
6527 * @event beforeappend
6528 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6529 * @param {Tree} tree The owner tree
6530 * @param {Node} parent The parent node
6531 * @param {Node} node The child node to be appended
6533 "beforeappend" : true,
6535 * @event beforeremove
6536 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6537 * @param {Tree} tree The owner tree
6538 * @param {Node} parent The parent node
6539 * @param {Node} node The child node to be removed
6541 "beforeremove" : true,
6544 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6545 * @param {Tree} tree The owner tree
6546 * @param {Node} node The node being moved
6547 * @param {Node} oldParent The parent of the node
6548 * @param {Node} newParent The new parent the node is moving to
6549 * @param {Number} index The index it is being moved to
6551 "beforemove" : true,
6553 * @event beforeinsert
6554 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6555 * @param {Tree} tree The owner tree
6556 * @param {Node} parent The parent node
6557 * @param {Node} node The child node to be inserted
6558 * @param {Node} refNode The child node the node is being inserted before
6560 "beforeinsert" : true
6563 Roo.data.Tree.superclass.constructor.call(this);
6566 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6569 proxyNodeEvent : function(){
6570 return this.fireEvent.apply(this, arguments);
6574 * Returns the root node for this tree.
6577 getRootNode : function(){
6582 * Sets the root node for this tree.
6583 * @param {Node} node
6586 setRootNode : function(node){
6588 node.ownerTree = this;
6590 this.registerNode(node);
6595 * Gets a node in this tree by its id.
6596 * @param {String} id
6599 getNodeById : function(id){
6600 return this.nodeHash[id];
6603 registerNode : function(node){
6604 this.nodeHash[node.id] = node;
6607 unregisterNode : function(node){
6608 delete this.nodeHash[node.id];
6611 toString : function(){
6612 return "[Tree"+(this.id?" "+this.id:"")+"]";
6617 * @class Roo.data.Node
6618 * @extends Roo.util.Observable
6619 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6620 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6622 * @param {Object} attributes The attributes/config for the node
6624 Roo.data.Node = function(attributes){
6626 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6629 this.attributes = attributes || {};
6630 this.leaf = this.attributes.leaf;
6632 * The node id. @type String
6634 this.id = this.attributes.id;
6636 this.id = Roo.id(null, "ynode-");
6637 this.attributes.id = this.id;
6640 * All child nodes of this node. @type Array
6642 this.childNodes = [];
6643 if(!this.childNodes.indexOf){ // indexOf is a must
6644 this.childNodes.indexOf = function(o){
6645 for(var i = 0, len = this.length; i < len; i++){
6654 * The parent node for this node. @type Node
6656 this.parentNode = null;
6658 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6660 this.firstChild = null;
6662 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6664 this.lastChild = null;
6666 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6668 this.previousSibling = null;
6670 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6672 this.nextSibling = null;
6677 * Fires when a new child node is appended
6678 * @param {Tree} tree The owner tree
6679 * @param {Node} this This node
6680 * @param {Node} node The newly appended node
6681 * @param {Number} index The index of the newly appended node
6686 * Fires when a child node is removed
6687 * @param {Tree} tree The owner tree
6688 * @param {Node} this This node
6689 * @param {Node} node The removed node
6694 * Fires when this node is moved to a new location in the tree
6695 * @param {Tree} tree The owner tree
6696 * @param {Node} this This node
6697 * @param {Node} oldParent The old parent of this node
6698 * @param {Node} newParent The new parent of this node
6699 * @param {Number} index The index it was moved to
6704 * Fires when a new child node is inserted.
6705 * @param {Tree} tree The owner tree
6706 * @param {Node} this This node
6707 * @param {Node} node The child node inserted
6708 * @param {Node} refNode The child node the node was inserted before
6712 * @event beforeappend
6713 * Fires before a new child is appended, return false to cancel the append.
6714 * @param {Tree} tree The owner tree
6715 * @param {Node} this This node
6716 * @param {Node} node The child node to be appended
6718 "beforeappend" : true,
6720 * @event beforeremove
6721 * Fires before a child is removed, return false to cancel the remove.
6722 * @param {Tree} tree The owner tree
6723 * @param {Node} this This node
6724 * @param {Node} node The child node to be removed
6726 "beforeremove" : true,
6729 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6730 * @param {Tree} tree The owner tree
6731 * @param {Node} this This node
6732 * @param {Node} oldParent The parent of this node
6733 * @param {Node} newParent The new parent this node is moving to
6734 * @param {Number} index The index it is being moved to
6736 "beforemove" : true,
6738 * @event beforeinsert
6739 * Fires before a new child is inserted, return false to cancel the insert.
6740 * @param {Tree} tree The owner tree
6741 * @param {Node} this This node
6742 * @param {Node} node The child node to be inserted
6743 * @param {Node} refNode The child node the node is being inserted before
6745 "beforeinsert" : true
6747 this.listeners = this.attributes.listeners;
6748 Roo.data.Node.superclass.constructor.call(this);
6751 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6752 fireEvent : function(evtName){
6753 // first do standard event for this node
6754 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6757 // then bubble it up to the tree if the event wasn't cancelled
6758 var ot = this.getOwnerTree();
6760 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6768 * Returns true if this node is a leaf
6771 isLeaf : function(){
6772 return this.leaf === true;
6776 setFirstChild : function(node){
6777 this.firstChild = node;
6781 setLastChild : function(node){
6782 this.lastChild = node;
6787 * Returns true if this node is the last child of its parent
6790 isLast : function(){
6791 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6795 * Returns true if this node is the first child of its parent
6798 isFirst : function(){
6799 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6802 hasChildNodes : function(){
6803 return !this.isLeaf() && this.childNodes.length > 0;
6807 * Insert node(s) as the last child node of this node.
6808 * @param {Node/Array} node The node or Array of nodes to append
6809 * @return {Node} The appended node if single append, or null if an array was passed
6811 appendChild : function(node){
6813 if(node instanceof Array){
6815 }else if(arguments.length > 1){
6818 // if passed an array or multiple args do them one by one
6820 for(var i = 0, len = multi.length; i < len; i++) {
6821 this.appendChild(multi[i]);
6824 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6827 var index = this.childNodes.length;
6828 var oldParent = node.parentNode;
6829 // it's a move, make sure we move it cleanly
6831 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6834 oldParent.removeChild(node);
6836 index = this.childNodes.length;
6838 this.setFirstChild(node);
6840 this.childNodes.push(node);
6841 node.parentNode = this;
6842 var ps = this.childNodes[index-1];
6844 node.previousSibling = ps;
6845 ps.nextSibling = node;
6847 node.previousSibling = null;
6849 node.nextSibling = null;
6850 this.setLastChild(node);
6851 node.setOwnerTree(this.getOwnerTree());
6852 this.fireEvent("append", this.ownerTree, this, node, index);
6854 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6861 * Removes a child node from this node.
6862 * @param {Node} node The node to remove
6863 * @return {Node} The removed node
6865 removeChild : function(node){
6866 var index = this.childNodes.indexOf(node);
6870 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6874 // remove it from childNodes collection
6875 this.childNodes.splice(index, 1);
6878 if(node.previousSibling){
6879 node.previousSibling.nextSibling = node.nextSibling;
6881 if(node.nextSibling){
6882 node.nextSibling.previousSibling = node.previousSibling;
6885 // update child refs
6886 if(this.firstChild == node){
6887 this.setFirstChild(node.nextSibling);
6889 if(this.lastChild == node){
6890 this.setLastChild(node.previousSibling);
6893 node.setOwnerTree(null);
6894 // clear any references from the node
6895 node.parentNode = null;
6896 node.previousSibling = null;
6897 node.nextSibling = null;
6898 this.fireEvent("remove", this.ownerTree, this, node);
6903 * Inserts the first node before the second node in this nodes childNodes collection.
6904 * @param {Node} node The node to insert
6905 * @param {Node} refNode The node to insert before (if null the node is appended)
6906 * @return {Node} The inserted node
6908 insertBefore : function(node, refNode){
6909 if(!refNode){ // like standard Dom, refNode can be null for append
6910 return this.appendChild(node);
6913 if(node == refNode){
6917 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6920 var index = this.childNodes.indexOf(refNode);
6921 var oldParent = node.parentNode;
6922 var refIndex = index;
6924 // when moving internally, indexes will change after remove
6925 if(oldParent == this && this.childNodes.indexOf(node) < index){
6929 // it's a move, make sure we move it cleanly
6931 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6934 oldParent.removeChild(node);
6937 this.setFirstChild(node);
6939 this.childNodes.splice(refIndex, 0, node);
6940 node.parentNode = this;
6941 var ps = this.childNodes[refIndex-1];
6943 node.previousSibling = ps;
6944 ps.nextSibling = node;
6946 node.previousSibling = null;
6948 node.nextSibling = refNode;
6949 refNode.previousSibling = node;
6950 node.setOwnerTree(this.getOwnerTree());
6951 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6953 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6959 * Returns the child node at the specified index.
6960 * @param {Number} index
6963 item : function(index){
6964 return this.childNodes[index];
6968 * Replaces one child node in this node with another.
6969 * @param {Node} newChild The replacement node
6970 * @param {Node} oldChild The node to replace
6971 * @return {Node} The replaced node
6973 replaceChild : function(newChild, oldChild){
6974 this.insertBefore(newChild, oldChild);
6975 this.removeChild(oldChild);
6980 * Returns the index of a child node
6981 * @param {Node} node
6982 * @return {Number} The index of the node or -1 if it was not found
6984 indexOf : function(child){
6985 return this.childNodes.indexOf(child);
6989 * Returns the tree this node is in.
6992 getOwnerTree : function(){
6993 // if it doesn't have one, look for one
6994 if(!this.ownerTree){
6998 this.ownerTree = p.ownerTree;
7004 return this.ownerTree;
7008 * Returns depth of this node (the root node has a depth of 0)
7011 getDepth : function(){
7014 while(p.parentNode){
7022 setOwnerTree : function(tree){
7023 // if it's move, we need to update everyone
7024 if(tree != this.ownerTree){
7026 this.ownerTree.unregisterNode(this);
7028 this.ownerTree = tree;
7029 var cs = this.childNodes;
7030 for(var i = 0, len = cs.length; i < len; i++) {
7031 cs[i].setOwnerTree(tree);
7034 tree.registerNode(this);
7040 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7041 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7042 * @return {String} The path
7044 getPath : function(attr){
7045 attr = attr || "id";
7046 var p = this.parentNode;
7047 var b = [this.attributes[attr]];
7049 b.unshift(p.attributes[attr]);
7052 var sep = this.getOwnerTree().pathSeparator;
7053 return sep + b.join(sep);
7057 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7058 * function call will be the scope provided or the current node. The arguments to the function
7059 * will be the args provided or the current node. If the function returns false at any point,
7060 * the bubble is stopped.
7061 * @param {Function} fn The function to call
7062 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7063 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7065 bubble : function(fn, scope, args){
7068 if(fn.call(scope || p, args || p) === false){
7076 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7077 * function call will be the scope provided or the current node. The arguments to the function
7078 * will be the args provided or the current node. If the function returns false at any point,
7079 * the cascade is stopped on that branch.
7080 * @param {Function} fn The function to call
7081 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7082 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7084 cascade : function(fn, scope, args){
7085 if(fn.call(scope || this, args || this) !== false){
7086 var cs = this.childNodes;
7087 for(var i = 0, len = cs.length; i < len; i++) {
7088 cs[i].cascade(fn, scope, args);
7094 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7095 * function call will be the scope provided or the current node. The arguments to the function
7096 * will be the args provided or the current node. If the function returns false at any point,
7097 * the iteration stops.
7098 * @param {Function} fn The function to call
7099 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7100 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7102 eachChild : function(fn, scope, args){
7103 var cs = this.childNodes;
7104 for(var i = 0, len = cs.length; i < len; i++) {
7105 if(fn.call(scope || this, args || cs[i]) === false){
7112 * Finds the first child that has the attribute with the specified value.
7113 * @param {String} attribute The attribute name
7114 * @param {Mixed} value The value to search for
7115 * @return {Node} The found child or null if none was found
7117 findChild : function(attribute, value){
7118 var cs = this.childNodes;
7119 for(var i = 0, len = cs.length; i < len; i++) {
7120 if(cs[i].attributes[attribute] == value){
7128 * Finds the first child by a custom function. The child matches if the function passed
7130 * @param {Function} fn
7131 * @param {Object} scope (optional)
7132 * @return {Node} The found child or null if none was found
7134 findChildBy : function(fn, scope){
7135 var cs = this.childNodes;
7136 for(var i = 0, len = cs.length; i < len; i++) {
7137 if(fn.call(scope||cs[i], cs[i]) === true){
7145 * Sorts this nodes children using the supplied sort function
7146 * @param {Function} fn
7147 * @param {Object} scope (optional)
7149 sort : function(fn, scope){
7150 var cs = this.childNodes;
7151 var len = cs.length;
7153 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7155 for(var i = 0; i < len; i++){
7157 n.previousSibling = cs[i-1];
7158 n.nextSibling = cs[i+1];
7160 this.setFirstChild(n);
7163 this.setLastChild(n);
7170 * Returns true if this node is an ancestor (at any point) of the passed node.
7171 * @param {Node} node
7174 contains : function(node){
7175 return node.isAncestor(this);
7179 * Returns true if the passed node is an ancestor (at any point) of this node.
7180 * @param {Node} node
7183 isAncestor : function(node){
7184 var p = this.parentNode;
7194 toString : function(){
7195 return "[Node"+(this.id?" "+this.id:"")+"]";
7199 * Ext JS Library 1.1.1
7200 * Copyright(c) 2006-2007, Ext JS, LLC.
7202 * Originally Released Under LGPL - original licence link has changed is not relivant.
7205 * <script type="text/javascript">
7210 * @class Roo.ComponentMgr
7211 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7214 Roo.ComponentMgr = function(){
7215 var all = new Roo.util.MixedCollection();
7219 * Registers a component.
7220 * @param {Roo.Component} c The component
7222 register : function(c){
7227 * Unregisters a component.
7228 * @param {Roo.Component} c The component
7230 unregister : function(c){
7235 * Returns a component by id
7236 * @param {String} id The component id
7243 * Registers a function that will be called when a specified component is added to ComponentMgr
7244 * @param {String} id The component id
7245 * @param {Funtction} fn The callback function
7246 * @param {Object} scope The scope of the callback
7248 onAvailable : function(id, fn, scope){
7249 all.on("add", function(index, o){
7251 fn.call(scope || o, o);
7252 all.un("add", fn, scope);
7259 * Ext JS Library 1.1.1
7260 * Copyright(c) 2006-2007, Ext JS, LLC.
7262 * Originally Released Under LGPL - original licence link has changed is not relivant.
7265 * <script type="text/javascript">
7269 * @class Roo.Component
7270 * @extends Roo.util.Observable
7271 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7272 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7273 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7274 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7275 * All visual components (widgets) that require rendering into a layout should subclass Component.
7277 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7278 * 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
7279 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7281 Roo.Component = function(config){
7282 config = config || {};
7283 if(config.tagName || config.dom || typeof config == "string"){ // element object
7284 config = {el: config, id: config.id || config};
7286 this.initialConfig = config;
7288 Roo.apply(this, config);
7292 * Fires after the component is disabled.
7293 * @param {Roo.Component} this
7298 * Fires after the component is enabled.
7299 * @param {Roo.Component} this
7304 * Fires before the component is shown. Return false to stop the show.
7305 * @param {Roo.Component} this
7310 * Fires after the component is shown.
7311 * @param {Roo.Component} this
7316 * Fires before the component is hidden. Return false to stop the hide.
7317 * @param {Roo.Component} this
7322 * Fires after the component is hidden.
7323 * @param {Roo.Component} this
7327 * @event beforerender
7328 * Fires before the component is rendered. Return false to stop the render.
7329 * @param {Roo.Component} this
7331 beforerender : true,
7334 * Fires after the component is rendered.
7335 * @param {Roo.Component} this
7339 * @event beforedestroy
7340 * Fires before the component is destroyed. Return false to stop the destroy.
7341 * @param {Roo.Component} this
7343 beforedestroy : true,
7346 * Fires after the component is destroyed.
7347 * @param {Roo.Component} this
7352 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7354 Roo.ComponentMgr.register(this);
7355 Roo.Component.superclass.constructor.call(this);
7356 this.initComponent();
7357 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7358 this.render(this.renderTo);
7359 delete this.renderTo;
7364 Roo.Component.AUTO_ID = 1000;
7366 Roo.extend(Roo.Component, Roo.util.Observable, {
7368 * @property {Boolean} hidden
7369 * true if this component is hidden. Read-only.
7373 * true if this component is disabled. Read-only.
7377 * true if this component has been rendered. Read-only.
7381 /** @cfg {String} disableClass
7382 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7384 disabledClass : "x-item-disabled",
7385 /** @cfg {Boolean} allowDomMove
7386 * Whether the component can move the Dom node when rendering (defaults to true).
7388 allowDomMove : true,
7389 /** @cfg {String} hideMode
7390 * How this component should hidden. Supported values are
7391 * "visibility" (css visibility), "offsets" (negative offset position) and
7392 * "display" (css display) - defaults to "display".
7394 hideMode: 'display',
7397 ctype : "Roo.Component",
7399 /** @cfg {String} actionMode
7400 * which property holds the element that used for hide() / show() / disable() / enable()
7406 getActionEl : function(){
7407 return this[this.actionMode];
7410 initComponent : Roo.emptyFn,
7412 * If this is a lazy rendering component, render it to its container element.
7413 * @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.
7415 render : function(container, position){
7416 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7417 if(!container && this.el){
7418 this.el = Roo.get(this.el);
7419 container = this.el.dom.parentNode;
7420 this.allowDomMove = false;
7422 this.container = Roo.get(container);
7423 this.rendered = true;
7424 if(position !== undefined){
7425 if(typeof position == 'number'){
7426 position = this.container.dom.childNodes[position];
7428 position = Roo.getDom(position);
7431 this.onRender(this.container, position || null);
7433 this.el.addClass(this.cls);
7437 this.el.applyStyles(this.style);
7440 this.fireEvent("render", this);
7441 this.afterRender(this.container);
7453 // default function is not really useful
7454 onRender : function(ct, position){
7456 this.el = Roo.get(this.el);
7457 if(this.allowDomMove !== false){
7458 ct.dom.insertBefore(this.el.dom, position);
7464 getAutoCreate : function(){
7465 var cfg = typeof this.autoCreate == "object" ?
7466 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7467 if(this.id && !cfg.id){
7474 afterRender : Roo.emptyFn,
7477 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7478 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7480 destroy : function(){
7481 if(this.fireEvent("beforedestroy", this) !== false){
7482 this.purgeListeners();
7483 this.beforeDestroy();
7485 this.el.removeAllListeners();
7487 if(this.actionMode == "container"){
7488 this.container.remove();
7492 Roo.ComponentMgr.unregister(this);
7493 this.fireEvent("destroy", this);
7498 beforeDestroy : function(){
7503 onDestroy : function(){
7508 * Returns the underlying {@link Roo.Element}.
7509 * @return {Roo.Element} The element
7516 * Returns the id of this component.
7524 * Try to focus this component.
7525 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7526 * @return {Roo.Component} this
7528 focus : function(selectText){
7531 if(selectText === true){
7532 this.el.dom.select();
7547 * Disable this component.
7548 * @return {Roo.Component} this
7550 disable : function(){
7554 this.disabled = true;
7555 this.fireEvent("disable", this);
7560 onDisable : function(){
7561 this.getActionEl().addClass(this.disabledClass);
7562 this.el.dom.disabled = true;
7566 * Enable this component.
7567 * @return {Roo.Component} this
7569 enable : function(){
7573 this.disabled = false;
7574 this.fireEvent("enable", this);
7579 onEnable : function(){
7580 this.getActionEl().removeClass(this.disabledClass);
7581 this.el.dom.disabled = false;
7585 * Convenience function for setting disabled/enabled by boolean.
7586 * @param {Boolean} disabled
7588 setDisabled : function(disabled){
7589 this[disabled ? "disable" : "enable"]();
7593 * Show this component.
7594 * @return {Roo.Component} this
7597 if(this.fireEvent("beforeshow", this) !== false){
7598 this.hidden = false;
7602 this.fireEvent("show", this);
7608 onShow : function(){
7609 var ae = this.getActionEl();
7610 if(this.hideMode == 'visibility'){
7611 ae.dom.style.visibility = "visible";
7612 }else if(this.hideMode == 'offsets'){
7613 ae.removeClass('x-hidden');
7615 ae.dom.style.display = "";
7620 * Hide this component.
7621 * @return {Roo.Component} this
7624 if(this.fireEvent("beforehide", this) !== false){
7629 this.fireEvent("hide", this);
7635 onHide : function(){
7636 var ae = this.getActionEl();
7637 if(this.hideMode == 'visibility'){
7638 ae.dom.style.visibility = "hidden";
7639 }else if(this.hideMode == 'offsets'){
7640 ae.addClass('x-hidden');
7642 ae.dom.style.display = "none";
7647 * Convenience function to hide or show this component by boolean.
7648 * @param {Boolean} visible True to show, false to hide
7649 * @return {Roo.Component} this
7651 setVisible: function(visible){
7661 * Returns true if this component is visible.
7663 isVisible : function(){
7664 return this.getActionEl().isVisible();
7667 cloneConfig : function(overrides){
7668 overrides = overrides || {};
7669 var id = overrides.id || Roo.id();
7670 var cfg = Roo.applyIf(overrides, this.initialConfig);
7671 cfg.id = id; // prevent dup id
7672 return new this.constructor(cfg);
7676 * Ext JS Library 1.1.1
7677 * Copyright(c) 2006-2007, Ext JS, LLC.
7679 * Originally Released Under LGPL - original licence link has changed is not relivant.
7682 * <script type="text/javascript">
7687 * @extends Roo.Element
7688 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7689 * automatic maintaining of shadow/shim positions.
7690 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7691 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7692 * you can pass a string with a CSS class name. False turns off the shadow.
7693 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7694 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7695 * @cfg {String} cls CSS class to add to the element
7696 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7697 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7699 * @param {Object} config An object with config options.
7700 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7703 Roo.Layer = function(config, existingEl){
7704 config = config || {};
7705 var dh = Roo.DomHelper;
7706 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7708 this.dom = Roo.getDom(existingEl);
7711 var o = config.dh || {tag: "div", cls: "x-layer"};
7712 this.dom = dh.append(pel, o);
7715 this.addClass(config.cls);
7717 this.constrain = config.constrain !== false;
7718 this.visibilityMode = Roo.Element.VISIBILITY;
7720 this.id = this.dom.id = config.id;
7722 this.id = Roo.id(this.dom);
7724 this.zindex = config.zindex || this.getZIndex();
7725 this.position("absolute", this.zindex);
7727 this.shadowOffset = config.shadowOffset || 4;
7728 this.shadow = new Roo.Shadow({
7729 offset : this.shadowOffset,
7730 mode : config.shadow
7733 this.shadowOffset = 0;
7735 this.useShim = config.shim !== false && Roo.useShims;
7736 this.useDisplay = config.useDisplay;
7740 var supr = Roo.Element.prototype;
7742 // shims are shared among layer to keep from having 100 iframes
7745 Roo.extend(Roo.Layer, Roo.Element, {
7747 getZIndex : function(){
7748 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7751 getShim : function(){
7758 var shim = shims.shift();
7760 shim = this.createShim();
7761 shim.enableDisplayMode('block');
7762 shim.dom.style.display = 'none';
7763 shim.dom.style.visibility = 'visible';
7765 var pn = this.dom.parentNode;
7766 if(shim.dom.parentNode != pn){
7767 pn.insertBefore(shim.dom, this.dom);
7769 shim.setStyle('z-index', this.getZIndex()-2);
7774 hideShim : function(){
7776 this.shim.setDisplayed(false);
7777 shims.push(this.shim);
7782 disableShadow : function(){
7784 this.shadowDisabled = true;
7786 this.lastShadowOffset = this.shadowOffset;
7787 this.shadowOffset = 0;
7791 enableShadow : function(show){
7793 this.shadowDisabled = false;
7794 this.shadowOffset = this.lastShadowOffset;
7795 delete this.lastShadowOffset;
7803 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7804 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7805 sync : function(doShow){
7806 var sw = this.shadow;
7807 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7808 var sh = this.getShim();
7810 var w = this.getWidth(),
7811 h = this.getHeight();
7813 var l = this.getLeft(true),
7814 t = this.getTop(true);
7816 if(sw && !this.shadowDisabled){
7817 if(doShow && !sw.isVisible()){
7820 sw.realign(l, t, w, h);
7826 // fit the shim behind the shadow, so it is shimmed too
7827 var a = sw.adjusts, s = sh.dom.style;
7828 s.left = (Math.min(l, l+a.l))+"px";
7829 s.top = (Math.min(t, t+a.t))+"px";
7830 s.width = (w+a.w)+"px";
7831 s.height = (h+a.h)+"px";
7838 sh.setLeftTop(l, t);
7845 destroy : function(){
7850 this.removeAllListeners();
7851 var pn = this.dom.parentNode;
7853 pn.removeChild(this.dom);
7855 Roo.Element.uncache(this.id);
7858 remove : function(){
7863 beginUpdate : function(){
7864 this.updating = true;
7868 endUpdate : function(){
7869 this.updating = false;
7874 hideUnders : function(negOffset){
7882 constrainXY : function(){
7884 var vw = Roo.lib.Dom.getViewWidth(),
7885 vh = Roo.lib.Dom.getViewHeight();
7886 var s = Roo.get(document).getScroll();
7888 var xy = this.getXY();
7889 var x = xy[0], y = xy[1];
7890 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7891 // only move it if it needs it
7893 // first validate right/bottom
7894 if((x + w) > vw+s.left){
7895 x = vw - w - this.shadowOffset;
7898 if((y + h) > vh+s.top){
7899 y = vh - h - this.shadowOffset;
7902 // then make sure top/left isn't negative
7913 var ay = this.avoidY;
7914 if(y <= ay && (y+h) >= ay){
7920 supr.setXY.call(this, xy);
7926 isVisible : function(){
7927 return this.visible;
7931 showAction : function(){
7932 this.visible = true; // track visibility to prevent getStyle calls
7933 if(this.useDisplay === true){
7934 this.setDisplayed("");
7935 }else if(this.lastXY){
7936 supr.setXY.call(this, this.lastXY);
7937 }else if(this.lastLT){
7938 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7943 hideAction : function(){
7944 this.visible = false;
7945 if(this.useDisplay === true){
7946 this.setDisplayed(false);
7948 this.setLeftTop(-10000,-10000);
7952 // overridden Element method
7953 setVisible : function(v, a, d, c, e){
7958 var cb = function(){
7963 }.createDelegate(this);
7964 supr.setVisible.call(this, true, true, d, cb, e);
7967 this.hideUnders(true);
7976 }.createDelegate(this);
7978 supr.setVisible.call(this, v, a, d, cb, e);
7987 storeXY : function(xy){
7992 storeLeftTop : function(left, top){
7994 this.lastLT = [left, top];
7998 beforeFx : function(){
7999 this.beforeAction();
8000 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8004 afterFx : function(){
8005 Roo.Layer.superclass.afterFx.apply(this, arguments);
8006 this.sync(this.isVisible());
8010 beforeAction : function(){
8011 if(!this.updating && this.shadow){
8016 // overridden Element method
8017 setLeft : function(left){
8018 this.storeLeftTop(left, this.getTop(true));
8019 supr.setLeft.apply(this, arguments);
8023 setTop : function(top){
8024 this.storeLeftTop(this.getLeft(true), top);
8025 supr.setTop.apply(this, arguments);
8029 setLeftTop : function(left, top){
8030 this.storeLeftTop(left, top);
8031 supr.setLeftTop.apply(this, arguments);
8035 setXY : function(xy, a, d, c, e){
8037 this.beforeAction();
8039 var cb = this.createCB(c);
8040 supr.setXY.call(this, xy, a, d, cb, e);
8047 createCB : function(c){
8058 // overridden Element method
8059 setX : function(x, a, d, c, e){
8060 this.setXY([x, this.getY()], a, d, c, e);
8063 // overridden Element method
8064 setY : function(y, a, d, c, e){
8065 this.setXY([this.getX(), y], a, d, c, e);
8068 // overridden Element method
8069 setSize : function(w, h, a, d, c, e){
8070 this.beforeAction();
8071 var cb = this.createCB(c);
8072 supr.setSize.call(this, w, h, a, d, cb, e);
8078 // overridden Element method
8079 setWidth : function(w, a, d, c, e){
8080 this.beforeAction();
8081 var cb = this.createCB(c);
8082 supr.setWidth.call(this, w, a, d, cb, e);
8088 // overridden Element method
8089 setHeight : function(h, a, d, c, e){
8090 this.beforeAction();
8091 var cb = this.createCB(c);
8092 supr.setHeight.call(this, h, a, d, cb, e);
8098 // overridden Element method
8099 setBounds : function(x, y, w, h, a, d, c, e){
8100 this.beforeAction();
8101 var cb = this.createCB(c);
8103 this.storeXY([x, y]);
8104 supr.setXY.call(this, [x, y]);
8105 supr.setSize.call(this, w, h, a, d, cb, e);
8108 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8114 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8115 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8116 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8117 * @param {Number} zindex The new z-index to set
8118 * @return {this} The Layer
8120 setZIndex : function(zindex){
8121 this.zindex = zindex;
8122 this.setStyle("z-index", zindex + 2);
8124 this.shadow.setZIndex(zindex + 1);
8127 this.shim.setStyle("z-index", zindex);
8133 * Ext JS Library 1.1.1
8134 * Copyright(c) 2006-2007, Ext JS, LLC.
8136 * Originally Released Under LGPL - original licence link has changed is not relivant.
8139 * <script type="text/javascript">
8145 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8146 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8147 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8149 * Create a new Shadow
8150 * @param {Object} config The config object
8152 Roo.Shadow = function(config){
8153 Roo.apply(this, config);
8154 if(typeof this.mode != "string"){
8155 this.mode = this.defaultMode;
8157 var o = this.offset, a = {h: 0};
8158 var rad = Math.floor(this.offset/2);
8159 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8165 a.l -= this.offset + rad;
8166 a.t -= this.offset + rad;
8177 a.l -= (this.offset - rad);
8178 a.t -= this.offset + rad;
8180 a.w -= (this.offset - rad)*2;
8191 a.l -= (this.offset - rad);
8192 a.t -= (this.offset - rad);
8194 a.w -= (this.offset + rad + 1);
8195 a.h -= (this.offset + rad);
8204 Roo.Shadow.prototype = {
8206 * @cfg {String} mode
8207 * The shadow display mode. Supports the following options:<br />
8208 * sides: Shadow displays on both sides and bottom only<br />
8209 * frame: Shadow displays equally on all four sides<br />
8210 * drop: Traditional bottom-right drop shadow (default)
8213 * @cfg {String} offset
8214 * The number of pixels to offset the shadow from the element (defaults to 4)
8219 defaultMode: "drop",
8222 * Displays the shadow under the target element
8223 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8225 show : function(target){
8226 target = Roo.get(target);
8228 this.el = Roo.Shadow.Pool.pull();
8229 if(this.el.dom.nextSibling != target.dom){
8230 this.el.insertBefore(target);
8233 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8235 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8238 target.getLeft(true),
8239 target.getTop(true),
8243 this.el.dom.style.display = "block";
8247 * Returns true if the shadow is visible, else false
8249 isVisible : function(){
8250 return this.el ? true : false;
8254 * Direct alignment when values are already available. Show must be called at least once before
8255 * calling this method to ensure it is initialized.
8256 * @param {Number} left The target element left position
8257 * @param {Number} top The target element top position
8258 * @param {Number} width The target element width
8259 * @param {Number} height The target element height
8261 realign : function(l, t, w, h){
8265 var a = this.adjusts, d = this.el.dom, s = d.style;
8267 s.left = (l+a.l)+"px";
8268 s.top = (t+a.t)+"px";
8269 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8271 if(s.width != sws || s.height != shs){
8275 var cn = d.childNodes;
8276 var sww = Math.max(0, (sw-12))+"px";
8277 cn[0].childNodes[1].style.width = sww;
8278 cn[1].childNodes[1].style.width = sww;
8279 cn[2].childNodes[1].style.width = sww;
8280 cn[1].style.height = Math.max(0, (sh-12))+"px";
8290 this.el.dom.style.display = "none";
8291 Roo.Shadow.Pool.push(this.el);
8297 * Adjust the z-index of this shadow
8298 * @param {Number} zindex The new z-index
8300 setZIndex : function(z){
8303 this.el.setStyle("z-index", z);
8308 // Private utility class that manages the internal Shadow cache
8309 Roo.Shadow.Pool = function(){
8311 var markup = Roo.isIE ?
8312 '<div class="x-ie-shadow"></div>' :
8313 '<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>';
8318 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8319 sh.autoBoxAdjust = false;
8324 push : function(sh){
8330 * Ext JS Library 1.1.1
8331 * Copyright(c) 2006-2007, Ext JS, LLC.
8333 * Originally Released Under LGPL - original licence link has changed is not relivant.
8336 * <script type="text/javascript">
8340 * @class Roo.BoxComponent
8341 * @extends Roo.Component
8342 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8343 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8344 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8345 * layout containers.
8347 * @param {Roo.Element/String/Object} config The configuration options.
8349 Roo.BoxComponent = function(config){
8350 Roo.Component.call(this, config);
8354 * Fires after the component is resized.
8355 * @param {Roo.Component} this
8356 * @param {Number} adjWidth The box-adjusted width that was set
8357 * @param {Number} adjHeight The box-adjusted height that was set
8358 * @param {Number} rawWidth The width that was originally specified
8359 * @param {Number} rawHeight The height that was originally specified
8364 * Fires after the component is moved.
8365 * @param {Roo.Component} this
8366 * @param {Number} x The new x position
8367 * @param {Number} y The new y position
8373 Roo.extend(Roo.BoxComponent, Roo.Component, {
8374 // private, set in afterRender to signify that the component has been rendered
8376 // private, used to defer height settings to subclasses
8378 /** @cfg {Number} width
8379 * width (optional) size of component
8381 /** @cfg {Number} height
8382 * height (optional) size of component
8386 * Sets the width and height of the component. This method fires the resize event. This method can accept
8387 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8388 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8389 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8390 * @return {Roo.BoxComponent} this
8392 setSize : function(w, h){
8393 // support for standard size objects
8394 if(typeof w == 'object'){
8405 // prevent recalcs when not needed
8406 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8409 this.lastSize = {width: w, height: h};
8411 var adj = this.adjustSize(w, h);
8412 var aw = adj.width, ah = adj.height;
8413 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8414 var rz = this.getResizeEl();
8415 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8417 }else if(!this.deferHeight && ah !== undefined){
8419 }else if(aw !== undefined){
8422 this.onResize(aw, ah, w, h);
8423 this.fireEvent('resize', this, aw, ah, w, h);
8429 * Gets the current size of the component's underlying element.
8430 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8432 getSize : function(){
8433 return this.el.getSize();
8437 * Gets the current XY position of the component's underlying element.
8438 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8439 * @return {Array} The XY position of the element (e.g., [100, 200])
8441 getPosition : function(local){
8443 return [this.el.getLeft(true), this.el.getTop(true)];
8445 return this.xy || this.el.getXY();
8449 * Gets the current box measurements of the component's underlying element.
8450 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8451 * @returns {Object} box An object in the format {x, y, width, height}
8453 getBox : function(local){
8454 var s = this.el.getSize();
8456 s.x = this.el.getLeft(true);
8457 s.y = this.el.getTop(true);
8459 var xy = this.xy || this.el.getXY();
8467 * Sets the current box measurements of the component's underlying element.
8468 * @param {Object} box An object in the format {x, y, width, height}
8469 * @returns {Roo.BoxComponent} this
8471 updateBox : function(box){
8472 this.setSize(box.width, box.height);
8473 this.setPagePosition(box.x, box.y);
8478 getResizeEl : function(){
8479 return this.resizeEl || this.el;
8483 getPositionEl : function(){
8484 return this.positionEl || this.el;
8488 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8489 * This method fires the move event.
8490 * @param {Number} left The new left
8491 * @param {Number} top The new top
8492 * @returns {Roo.BoxComponent} this
8494 setPosition : function(x, y){
8500 var adj = this.adjustPosition(x, y);
8501 var ax = adj.x, ay = adj.y;
8503 var el = this.getPositionEl();
8504 if(ax !== undefined || ay !== undefined){
8505 if(ax !== undefined && ay !== undefined){
8506 el.setLeftTop(ax, ay);
8507 }else if(ax !== undefined){
8509 }else if(ay !== undefined){
8512 this.onPosition(ax, ay);
8513 this.fireEvent('move', this, ax, ay);
8519 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8520 * This method fires the move event.
8521 * @param {Number} x The new x position
8522 * @param {Number} y The new y position
8523 * @returns {Roo.BoxComponent} this
8525 setPagePosition : function(x, y){
8531 if(x === undefined || y === undefined){ // cannot translate undefined points
8534 var p = this.el.translatePoints(x, y);
8535 this.setPosition(p.left, p.top);
8540 onRender : function(ct, position){
8541 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8543 this.resizeEl = Roo.get(this.resizeEl);
8545 if(this.positionEl){
8546 this.positionEl = Roo.get(this.positionEl);
8551 afterRender : function(){
8552 Roo.BoxComponent.superclass.afterRender.call(this);
8553 this.boxReady = true;
8554 this.setSize(this.width, this.height);
8555 if(this.x || this.y){
8556 this.setPosition(this.x, this.y);
8558 if(this.pageX || this.pageY){
8559 this.setPagePosition(this.pageX, this.pageY);
8564 * Force the component's size to recalculate based on the underlying element's current height and width.
8565 * @returns {Roo.BoxComponent} this
8567 syncSize : function(){
8568 delete this.lastSize;
8569 this.setSize(this.el.getWidth(), this.el.getHeight());
8574 * Called after the component is resized, this method is empty by default but can be implemented by any
8575 * subclass that needs to perform custom logic after a resize occurs.
8576 * @param {Number} adjWidth The box-adjusted width that was set
8577 * @param {Number} adjHeight The box-adjusted height that was set
8578 * @param {Number} rawWidth The width that was originally specified
8579 * @param {Number} rawHeight The height that was originally specified
8581 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8586 * Called after the component is moved, this method is empty by default but can be implemented by any
8587 * subclass that needs to perform custom logic after a move occurs.
8588 * @param {Number} x The new x position
8589 * @param {Number} y The new y position
8591 onPosition : function(x, y){
8596 adjustSize : function(w, h){
8600 if(this.autoHeight){
8603 return {width : w, height: h};
8607 adjustPosition : function(x, y){
8608 return {x : x, y: y};
8612 * Ext JS Library 1.1.1
8613 * Copyright(c) 2006-2007, Ext JS, LLC.
8615 * Originally Released Under LGPL - original licence link has changed is not relivant.
8618 * <script type="text/javascript">
8623 * @class Roo.SplitBar
8624 * @extends Roo.util.Observable
8625 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8629 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8630 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8631 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8632 split.minSize = 100;
8633 split.maxSize = 600;
8634 split.animate = true;
8635 split.on('moved', splitterMoved);
8638 * Create a new SplitBar
8639 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8640 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8641 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8642 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8643 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8644 position of the SplitBar).
8646 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8649 this.el = Roo.get(dragElement, true);
8650 this.el.dom.unselectable = "on";
8652 this.resizingEl = Roo.get(resizingElement, true);
8656 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8657 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8660 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8663 * The minimum size of the resizing element. (Defaults to 0)
8669 * The maximum size of the resizing element. (Defaults to 2000)
8672 this.maxSize = 2000;
8675 * Whether to animate the transition to the new size
8678 this.animate = false;
8681 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8684 this.useShim = false;
8691 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8693 this.proxy = Roo.get(existingProxy).dom;
8696 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8699 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8702 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8705 this.dragSpecs = {};
8708 * @private The adapter to use to positon and resize elements
8710 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8711 this.adapter.init(this);
8713 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8715 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8716 this.el.addClass("x-splitbar-h");
8719 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8720 this.el.addClass("x-splitbar-v");
8726 * Fires when the splitter is moved (alias for {@link #event-moved})
8727 * @param {Roo.SplitBar} this
8728 * @param {Number} newSize the new width or height
8733 * Fires when the splitter is moved
8734 * @param {Roo.SplitBar} this
8735 * @param {Number} newSize the new width or height
8739 * @event beforeresize
8740 * Fires before the splitter is dragged
8741 * @param {Roo.SplitBar} this
8743 "beforeresize" : true,
8745 "beforeapply" : true
8748 Roo.util.Observable.call(this);
8751 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8752 onStartProxyDrag : function(x, y){
8753 this.fireEvent("beforeresize", this);
8755 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8757 o.enableDisplayMode("block");
8758 // all splitbars share the same overlay
8759 Roo.SplitBar.prototype.overlay = o;
8761 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8762 this.overlay.show();
8763 Roo.get(this.proxy).setDisplayed("block");
8764 var size = this.adapter.getElementSize(this);
8765 this.activeMinSize = this.getMinimumSize();;
8766 this.activeMaxSize = this.getMaximumSize();;
8767 var c1 = size - this.activeMinSize;
8768 var c2 = Math.max(this.activeMaxSize - size, 0);
8769 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8770 this.dd.resetConstraints();
8771 this.dd.setXConstraint(
8772 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8773 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8775 this.dd.setYConstraint(0, 0);
8777 this.dd.resetConstraints();
8778 this.dd.setXConstraint(0, 0);
8779 this.dd.setYConstraint(
8780 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8781 this.placement == Roo.SplitBar.TOP ? c2 : c1
8784 this.dragSpecs.startSize = size;
8785 this.dragSpecs.startPoint = [x, y];
8786 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8790 * @private Called after the drag operation by the DDProxy
8792 onEndProxyDrag : function(e){
8793 Roo.get(this.proxy).setDisplayed(false);
8794 var endPoint = Roo.lib.Event.getXY(e);
8796 this.overlay.hide();
8799 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8800 newSize = this.dragSpecs.startSize +
8801 (this.placement == Roo.SplitBar.LEFT ?
8802 endPoint[0] - this.dragSpecs.startPoint[0] :
8803 this.dragSpecs.startPoint[0] - endPoint[0]
8806 newSize = this.dragSpecs.startSize +
8807 (this.placement == Roo.SplitBar.TOP ?
8808 endPoint[1] - this.dragSpecs.startPoint[1] :
8809 this.dragSpecs.startPoint[1] - endPoint[1]
8812 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8813 if(newSize != this.dragSpecs.startSize){
8814 if(this.fireEvent('beforeapply', this, newSize) !== false){
8815 this.adapter.setElementSize(this, newSize);
8816 this.fireEvent("moved", this, newSize);
8817 this.fireEvent("resize", this, newSize);
8823 * Get the adapter this SplitBar uses
8824 * @return The adapter object
8826 getAdapter : function(){
8827 return this.adapter;
8831 * Set the adapter this SplitBar uses
8832 * @param {Object} adapter A SplitBar adapter object
8834 setAdapter : function(adapter){
8835 this.adapter = adapter;
8836 this.adapter.init(this);
8840 * Gets the minimum size for the resizing element
8841 * @return {Number} The minimum size
8843 getMinimumSize : function(){
8844 return this.minSize;
8848 * Sets the minimum size for the resizing element
8849 * @param {Number} minSize The minimum size
8851 setMinimumSize : function(minSize){
8852 this.minSize = minSize;
8856 * Gets the maximum size for the resizing element
8857 * @return {Number} The maximum size
8859 getMaximumSize : function(){
8860 return this.maxSize;
8864 * Sets the maximum size for the resizing element
8865 * @param {Number} maxSize The maximum size
8867 setMaximumSize : function(maxSize){
8868 this.maxSize = maxSize;
8872 * Sets the initialize size for the resizing element
8873 * @param {Number} size The initial size
8875 setCurrentSize : function(size){
8876 var oldAnimate = this.animate;
8877 this.animate = false;
8878 this.adapter.setElementSize(this, size);
8879 this.animate = oldAnimate;
8883 * Destroy this splitbar.
8884 * @param {Boolean} removeEl True to remove the element
8886 destroy : function(removeEl){
8891 this.proxy.parentNode.removeChild(this.proxy);
8899 * @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.
8901 Roo.SplitBar.createProxy = function(dir){
8902 var proxy = new Roo.Element(document.createElement("div"));
8903 proxy.unselectable();
8904 var cls = 'x-splitbar-proxy';
8905 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8906 document.body.appendChild(proxy.dom);
8911 * @class Roo.SplitBar.BasicLayoutAdapter
8912 * Default Adapter. It assumes the splitter and resizing element are not positioned
8913 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8915 Roo.SplitBar.BasicLayoutAdapter = function(){
8918 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8919 // do nothing for now
8924 * Called before drag operations to get the current size of the resizing element.
8925 * @param {Roo.SplitBar} s The SplitBar using this adapter
8927 getElementSize : function(s){
8928 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8929 return s.resizingEl.getWidth();
8931 return s.resizingEl.getHeight();
8936 * Called after drag operations to set the size of the resizing element.
8937 * @param {Roo.SplitBar} s The SplitBar using this adapter
8938 * @param {Number} newSize The new size to set
8939 * @param {Function} onComplete A function to be invoked when resizing is complete
8941 setElementSize : function(s, newSize, onComplete){
8942 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8944 s.resizingEl.setWidth(newSize);
8946 onComplete(s, newSize);
8949 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8954 s.resizingEl.setHeight(newSize);
8956 onComplete(s, newSize);
8959 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8966 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8967 * @extends Roo.SplitBar.BasicLayoutAdapter
8968 * Adapter that moves the splitter element to align with the resized sizing element.
8969 * Used with an absolute positioned SplitBar.
8970 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8971 * document.body, make sure you assign an id to the body element.
8973 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8974 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8975 this.container = Roo.get(container);
8978 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8983 getElementSize : function(s){
8984 return this.basic.getElementSize(s);
8987 setElementSize : function(s, newSize, onComplete){
8988 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8991 moveSplitter : function(s){
8992 var yes = Roo.SplitBar;
8993 switch(s.placement){
8995 s.el.setX(s.resizingEl.getRight());
8998 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9001 s.el.setY(s.resizingEl.getBottom());
9004 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9011 * Orientation constant - Create a vertical SplitBar
9015 Roo.SplitBar.VERTICAL = 1;
9018 * Orientation constant - Create a horizontal SplitBar
9022 Roo.SplitBar.HORIZONTAL = 2;
9025 * Placement constant - The resizing element is to the left of the splitter element
9029 Roo.SplitBar.LEFT = 1;
9032 * Placement constant - The resizing element is to the right of the splitter element
9036 Roo.SplitBar.RIGHT = 2;
9039 * Placement constant - The resizing element is positioned above the splitter element
9043 Roo.SplitBar.TOP = 3;
9046 * Placement constant - The resizing element is positioned under splitter element
9050 Roo.SplitBar.BOTTOM = 4;
9053 * Ext JS Library 1.1.1
9054 * Copyright(c) 2006-2007, Ext JS, LLC.
9056 * Originally Released Under LGPL - original licence link has changed is not relivant.
9059 * <script type="text/javascript">
9064 * @extends Roo.util.Observable
9065 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9066 * This class also supports single and multi selection modes. <br>
9067 * Create a data model bound view:
9069 var store = new Roo.data.Store(...);
9071 var view = new Roo.View({
9073 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9076 selectedClass: "ydataview-selected",
9080 // listen for node click?
9081 view.on("click", function(vw, index, node, e){
9082 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9086 dataModel.load("foobar.xml");
9088 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9090 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9091 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9093 * Note: old style constructor is still suported (container, template, config)
9097 * @param {Object} config The config object
9100 Roo.View = function(config, depreciated_tpl, depreciated_config){
9102 if (typeof(depreciated_tpl) == 'undefined') {
9103 // new way.. - universal constructor.
9104 Roo.apply(this, config);
9105 this.el = Roo.get(this.el);
9108 this.el = Roo.get(config);
9109 this.tpl = depreciated_tpl;
9110 Roo.apply(this, depreciated_config);
9114 if(typeof(this.tpl) == "string"){
9115 this.tpl = new Roo.Template(this.tpl);
9117 // support xtype ctors..
9118 this.tpl = new Roo.factory(this.tpl, Roo);
9129 * @event beforeclick
9130 * Fires before a click is processed. Returns false to cancel the default action.
9131 * @param {Roo.View} this
9132 * @param {Number} index The index of the target node
9133 * @param {HTMLElement} node The target node
9134 * @param {Roo.EventObject} e The raw event object
9136 "beforeclick" : true,
9139 * Fires when a template node is clicked.
9140 * @param {Roo.View} this
9141 * @param {Number} index The index of the target node
9142 * @param {HTMLElement} node The target node
9143 * @param {Roo.EventObject} e The raw event object
9148 * Fires when a template node is double clicked.
9149 * @param {Roo.View} this
9150 * @param {Number} index The index of the target node
9151 * @param {HTMLElement} node The target node
9152 * @param {Roo.EventObject} e The raw event object
9156 * @event contextmenu
9157 * Fires when a template node is right clicked.
9158 * @param {Roo.View} this
9159 * @param {Number} index The index of the target node
9160 * @param {HTMLElement} node The target node
9161 * @param {Roo.EventObject} e The raw event object
9163 "contextmenu" : true,
9165 * @event selectionchange
9166 * Fires when the selected nodes change.
9167 * @param {Roo.View} this
9168 * @param {Array} selections Array of the selected nodes
9170 "selectionchange" : true,
9173 * @event beforeselect
9174 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9175 * @param {Roo.View} this
9176 * @param {HTMLElement} node The node to be selected
9177 * @param {Array} selections Array of currently selected nodes
9179 "beforeselect" : true
9183 "click": this.onClick,
9184 "dblclick": this.onDblClick,
9185 "contextmenu": this.onContextMenu,
9189 this.selections = [];
9191 this.cmp = new Roo.CompositeElementLite([]);
9193 this.store = Roo.factory(this.store, Roo.data);
9194 this.setStore(this.store, true);
9196 Roo.View.superclass.constructor.call(this);
9199 Roo.extend(Roo.View, Roo.util.Observable, {
9202 * @cfg {Roo.data.Store} store Data store to load data from.
9207 * @cfg {String|Roo.Element} el The container element.
9212 * @cfg {String|Roo.Template} tpl The template used by this View
9217 * @cfg {String} selectedClass The css class to add to selected nodes
9219 selectedClass : "x-view-selected",
9221 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9225 * @cfg {Boolean} multiSelect Allow multiple selection
9228 multiSelect : false,
9230 * @cfg {Boolean} singleSelect Allow single selection
9232 singleSelect: false,
9235 * Returns the element this view is bound to.
9236 * @return {Roo.Element}
9243 * Refreshes the view.
9245 refresh : function(){
9247 this.clearSelections();
9250 var records = this.store.getRange();
9251 if(records.length < 1){
9252 this.el.update(this.emptyText);
9255 for(var i = 0, len = records.length; i < len; i++){
9256 var data = this.prepareData(records[i].data, i, records[i]);
9257 html[html.length] = t.apply(data);
9259 this.el.update(html.join(""));
9260 this.nodes = this.el.dom.childNodes;
9261 this.updateIndexes(0);
9265 * Function to override to reformat the data that is sent to
9266 * the template for each node.
9267 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9268 * a JSON object for an UpdateManager bound view).
9270 prepareData : function(data){
9274 onUpdate : function(ds, record){
9275 this.clearSelections();
9276 var index = this.store.indexOf(record);
9277 var n = this.nodes[index];
9278 this.tpl.insertBefore(n, this.prepareData(record.data));
9279 n.parentNode.removeChild(n);
9280 this.updateIndexes(index, index);
9283 onAdd : function(ds, records, index){
9284 this.clearSelections();
9285 if(this.nodes.length == 0){
9289 var n = this.nodes[index];
9290 for(var i = 0, len = records.length; i < len; i++){
9291 var d = this.prepareData(records[i].data);
9293 this.tpl.insertBefore(n, d);
9295 this.tpl.append(this.el, d);
9298 this.updateIndexes(index);
9301 onRemove : function(ds, record, index){
9302 this.clearSelections();
9303 this.el.dom.removeChild(this.nodes[index]);
9304 this.updateIndexes(index);
9308 * Refresh an individual node.
9309 * @param {Number} index
9311 refreshNode : function(index){
9312 this.onUpdate(this.store, this.store.getAt(index));
9315 updateIndexes : function(startIndex, endIndex){
9316 var ns = this.nodes;
9317 startIndex = startIndex || 0;
9318 endIndex = endIndex || ns.length - 1;
9319 for(var i = startIndex; i <= endIndex; i++){
9320 ns[i].nodeIndex = i;
9325 * Changes the data store this view uses and refresh the view.
9326 * @param {Store} store
9328 setStore : function(store, initial){
9329 if(!initial && this.store){
9330 this.store.un("datachanged", this.refresh);
9331 this.store.un("add", this.onAdd);
9332 this.store.un("remove", this.onRemove);
9333 this.store.un("update", this.onUpdate);
9334 this.store.un("clear", this.refresh);
9338 store.on("datachanged", this.refresh, this);
9339 store.on("add", this.onAdd, this);
9340 store.on("remove", this.onRemove, this);
9341 store.on("update", this.onUpdate, this);
9342 store.on("clear", this.refresh, this);
9351 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9352 * @param {HTMLElement} node
9353 * @return {HTMLElement} The template node
9355 findItemFromChild : function(node){
9356 var el = this.el.dom;
9357 if(!node || node.parentNode == el){
9360 var p = node.parentNode;
9361 while(p && p != el){
9362 if(p.parentNode == el){
9371 onClick : function(e){
9372 var item = this.findItemFromChild(e.getTarget());
9374 var index = this.indexOf(item);
9375 if(this.onItemClick(item, index, e) !== false){
9376 this.fireEvent("click", this, index, item, e);
9379 this.clearSelections();
9384 onContextMenu : function(e){
9385 var item = this.findItemFromChild(e.getTarget());
9387 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9392 onDblClick : function(e){
9393 var item = this.findItemFromChild(e.getTarget());
9395 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9399 onItemClick : function(item, index, e){
9400 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9403 if(this.multiSelect || this.singleSelect){
9404 if(this.multiSelect && e.shiftKey && this.lastSelection){
9405 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9407 this.select(item, this.multiSelect && e.ctrlKey);
9408 this.lastSelection = item;
9416 * Get the number of selected nodes.
9419 getSelectionCount : function(){
9420 return this.selections.length;
9424 * Get the currently selected nodes.
9425 * @return {Array} An array of HTMLElements
9427 getSelectedNodes : function(){
9428 return this.selections;
9432 * Get the indexes of the selected nodes.
9435 getSelectedIndexes : function(){
9436 var indexes = [], s = this.selections;
9437 for(var i = 0, len = s.length; i < len; i++){
9438 indexes.push(s[i].nodeIndex);
9444 * Clear all selections
9445 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9447 clearSelections : function(suppressEvent){
9448 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9449 this.cmp.elements = this.selections;
9450 this.cmp.removeClass(this.selectedClass);
9451 this.selections = [];
9453 this.fireEvent("selectionchange", this, this.selections);
9459 * Returns true if the passed node is selected
9460 * @param {HTMLElement/Number} node The node or node index
9463 isSelected : function(node){
9464 var s = this.selections;
9468 node = this.getNode(node);
9469 return s.indexOf(node) !== -1;
9474 * @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
9475 * @param {Boolean} keepExisting (optional) true to keep existing selections
9476 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9478 select : function(nodeInfo, keepExisting, suppressEvent){
9479 if(nodeInfo instanceof Array){
9481 this.clearSelections(true);
9483 for(var i = 0, len = nodeInfo.length; i < len; i++){
9484 this.select(nodeInfo[i], true, true);
9487 var node = this.getNode(nodeInfo);
9488 if(node && !this.isSelected(node)){
9490 this.clearSelections(true);
9492 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9493 Roo.fly(node).addClass(this.selectedClass);
9494 this.selections.push(node);
9496 this.fireEvent("selectionchange", this, this.selections);
9504 * Gets a template node.
9505 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9506 * @return {HTMLElement} The node or null if it wasn't found
9508 getNode : function(nodeInfo){
9509 if(typeof nodeInfo == "string"){
9510 return document.getElementById(nodeInfo);
9511 }else if(typeof nodeInfo == "number"){
9512 return this.nodes[nodeInfo];
9518 * Gets a range template nodes.
9519 * @param {Number} startIndex
9520 * @param {Number} endIndex
9521 * @return {Array} An array of nodes
9523 getNodes : function(start, end){
9524 var ns = this.nodes;
9526 end = typeof end == "undefined" ? ns.length - 1 : end;
9529 for(var i = start; i <= end; i++){
9533 for(var i = start; i >= end; i--){
9541 * Finds the index of the passed node
9542 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9543 * @return {Number} The index of the node or -1
9545 indexOf : function(node){
9546 node = this.getNode(node);
9547 if(typeof node.nodeIndex == "number"){
9548 return node.nodeIndex;
9550 var ns = this.nodes;
9551 for(var i = 0, len = ns.length; i < len; i++){
9561 * Ext JS Library 1.1.1
9562 * Copyright(c) 2006-2007, Ext JS, LLC.
9564 * Originally Released Under LGPL - original licence link has changed is not relivant.
9567 * <script type="text/javascript">
9571 * @class Roo.JsonView
9573 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9575 var view = new Roo.JsonView({
9576 container: "my-element",
9577 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9582 // listen for node click?
9583 view.on("click", function(vw, index, node, e){
9584 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9587 // direct load of JSON data
9588 view.load("foobar.php");
9590 // Example from my blog list
9591 var tpl = new Roo.Template(
9592 '<div class="entry">' +
9593 '<a class="entry-title" href="{link}">{title}</a>' +
9594 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9595 "</div><hr />"
9598 var moreView = new Roo.JsonView({
9599 container : "entry-list",
9603 moreView.on("beforerender", this.sortEntries, this);
9605 url: "/blog/get-posts.php",
9606 params: "allposts=true",
9607 text: "Loading Blog Entries..."
9611 * Note: old code is supported with arguments : (container, template, config)
9615 * Create a new JsonView
9617 * @param {Object} config The config object
9620 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9623 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9625 var um = this.el.getUpdateManager();
9626 um.setRenderer(this);
9627 um.on("update", this.onLoad, this);
9628 um.on("failure", this.onLoadException, this);
9631 * @event beforerender
9632 * Fires before rendering of the downloaded JSON data.
9633 * @param {Roo.JsonView} this
9634 * @param {Object} data The JSON data loaded
9638 * Fires when data is loaded.
9639 * @param {Roo.JsonView} this
9640 * @param {Object} data The JSON data loaded
9641 * @param {Object} response The raw Connect response object
9644 * @event loadexception
9645 * Fires when loading fails.
9646 * @param {Roo.JsonView} this
9647 * @param {Object} response The raw Connect response object
9650 'beforerender' : true,
9652 'loadexception' : true
9655 Roo.extend(Roo.JsonView, Roo.View, {
9657 * @type {String} The root property in the loaded JSON object that contains the data
9662 * Refreshes the view.
9664 refresh : function(){
9665 this.clearSelections();
9668 var o = this.jsonData;
9669 if(o && o.length > 0){
9670 for(var i = 0, len = o.length; i < len; i++){
9671 var data = this.prepareData(o[i], i, o);
9672 html[html.length] = this.tpl.apply(data);
9675 html.push(this.emptyText);
9677 this.el.update(html.join(""));
9678 this.nodes = this.el.dom.childNodes;
9679 this.updateIndexes(0);
9683 * 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.
9684 * @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:
9687 url: "your-url.php",
9688 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9689 callback: yourFunction,
9690 scope: yourObject, //(optional scope)
9698 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9699 * 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.
9700 * @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}
9701 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9702 * @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.
9705 var um = this.el.getUpdateManager();
9706 um.update.apply(um, arguments);
9709 render : function(el, response){
9710 this.clearSelections();
9714 o = Roo.util.JSON.decode(response.responseText);
9717 o = o[this.jsonRoot];
9722 * The current JSON data or null
9725 this.beforeRender();
9730 * Get the number of records in the current JSON dataset
9733 getCount : function(){
9734 return this.jsonData ? this.jsonData.length : 0;
9738 * Returns the JSON object for the specified node(s)
9739 * @param {HTMLElement/Array} node The node or an array of nodes
9740 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9741 * you get the JSON object for the node
9743 getNodeData : function(node){
9744 if(node instanceof Array){
9746 for(var i = 0, len = node.length; i < len; i++){
9747 data.push(this.getNodeData(node[i]));
9751 return this.jsonData[this.indexOf(node)] || null;
9754 beforeRender : function(){
9755 this.snapshot = this.jsonData;
9757 this.sort.apply(this, this.sortInfo);
9759 this.fireEvent("beforerender", this, this.jsonData);
9762 onLoad : function(el, o){
9763 this.fireEvent("load", this, this.jsonData, o);
9766 onLoadException : function(el, o){
9767 this.fireEvent("loadexception", this, o);
9771 * Filter the data by a specific property.
9772 * @param {String} property A property on your JSON objects
9773 * @param {String/RegExp} value Either string that the property values
9774 * should start with, or a RegExp to test against the property
9776 filter : function(property, value){
9779 var ss = this.snapshot;
9780 if(typeof value == "string"){
9781 var vlen = value.length;
9786 value = value.toLowerCase();
9787 for(var i = 0, len = ss.length; i < len; i++){
9789 if(o[property].substr(0, vlen).toLowerCase() == value){
9793 } else if(value.exec){ // regex?
9794 for(var i = 0, len = ss.length; i < len; i++){
9796 if(value.test(o[property])){
9803 this.jsonData = data;
9809 * Filter by a function. The passed function will be called with each
9810 * object in the current dataset. If the function returns true the value is kept,
9811 * otherwise it is filtered.
9812 * @param {Function} fn
9813 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9815 filterBy : function(fn, scope){
9818 var ss = this.snapshot;
9819 for(var i = 0, len = ss.length; i < len; i++){
9821 if(fn.call(scope || this, o)){
9825 this.jsonData = data;
9831 * Clears the current filter.
9833 clearFilter : function(){
9834 if(this.snapshot && this.jsonData != this.snapshot){
9835 this.jsonData = this.snapshot;
9842 * Sorts the data for this view and refreshes it.
9843 * @param {String} property A property on your JSON objects to sort on
9844 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9845 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9847 sort : function(property, dir, sortType){
9848 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9851 var dsc = dir && dir.toLowerCase() == "desc";
9852 var f = function(o1, o2){
9853 var v1 = sortType ? sortType(o1[p]) : o1[p];
9854 var v2 = sortType ? sortType(o2[p]) : o2[p];
9857 return dsc ? +1 : -1;
9859 return dsc ? -1 : +1;
9864 this.jsonData.sort(f);
9866 if(this.jsonData != this.snapshot){
9867 this.snapshot.sort(f);
9873 * Ext JS Library 1.1.1
9874 * Copyright(c) 2006-2007, Ext JS, LLC.
9876 * Originally Released Under LGPL - original licence link has changed is not relivant.
9879 * <script type="text/javascript">
9884 * @class Roo.ColorPalette
9885 * @extends Roo.Component
9886 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9887 * Here's an example of typical usage:
9889 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9890 cp.render('my-div');
9892 cp.on('select', function(palette, selColor){
9893 // do something with selColor
9897 * Create a new ColorPalette
9898 * @param {Object} config The config object
9900 Roo.ColorPalette = function(config){
9901 Roo.ColorPalette.superclass.constructor.call(this, config);
9905 * Fires when a color is selected
9906 * @param {ColorPalette} this
9907 * @param {String} color The 6-digit color hex code (without the # symbol)
9913 this.on("select", this.handler, this.scope, true);
9916 Roo.extend(Roo.ColorPalette, Roo.Component, {
9918 * @cfg {String} itemCls
9919 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9921 itemCls : "x-color-palette",
9923 * @cfg {String} value
9924 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9925 * the hex codes are case-sensitive.
9930 ctype: "Roo.ColorPalette",
9933 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9935 allowReselect : false,
9938 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9939 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9940 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9941 * of colors with the width setting until the box is symmetrical.</p>
9942 * <p>You can override individual colors if needed:</p>
9944 var cp = new Roo.ColorPalette();
9945 cp.colors[0] = "FF0000"; // change the first box to red
9948 Or you can provide a custom array of your own for complete control:
9950 var cp = new Roo.ColorPalette();
9951 cp.colors = ["000000", "993300", "333300"];
9956 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9957 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9958 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9959 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9960 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9964 onRender : function(container, position){
9965 var t = new Roo.MasterTemplate(
9966 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9968 var c = this.colors;
9969 for(var i = 0, len = c.length; i < len; i++){
9972 var el = document.createElement("div");
9973 el.className = this.itemCls;
9975 container.dom.insertBefore(el, position);
9976 this.el = Roo.get(el);
9977 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9978 if(this.clickEvent != 'click'){
9979 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9984 afterRender : function(){
9985 Roo.ColorPalette.superclass.afterRender.call(this);
9994 handleClick : function(e, t){
9997 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9998 this.select(c.toUpperCase());
10003 * Selects the specified color in the palette (fires the select event)
10004 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10006 select : function(color){
10007 color = color.replace("#", "");
10008 if(color != this.value || this.allowReselect){
10011 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10013 el.child("a.color-"+color).addClass("x-color-palette-sel");
10014 this.value = color;
10015 this.fireEvent("select", this, color);
10020 * Ext JS Library 1.1.1
10021 * Copyright(c) 2006-2007, Ext JS, LLC.
10023 * Originally Released Under LGPL - original licence link has changed is not relivant.
10026 * <script type="text/javascript">
10030 * @class Roo.DatePicker
10031 * @extends Roo.Component
10032 * Simple date picker class.
10034 * Create a new DatePicker
10035 * @param {Object} config The config object
10037 Roo.DatePicker = function(config){
10038 Roo.DatePicker.superclass.constructor.call(this, config);
10040 this.value = config && config.value ?
10041 config.value.clearTime() : new Date().clearTime();
10046 * Fires when a date is selected
10047 * @param {DatePicker} this
10048 * @param {Date} date The selected date
10054 this.on("select", this.handler, this.scope || this);
10056 // build the disabledDatesRE
10057 if(!this.disabledDatesRE && this.disabledDates){
10058 var dd = this.disabledDates;
10060 for(var i = 0; i < dd.length; i++){
10062 if(i != dd.length-1) re += "|";
10064 this.disabledDatesRE = new RegExp(re + ")");
10068 Roo.extend(Roo.DatePicker, Roo.Component, {
10070 * @cfg {String} todayText
10071 * The text to display on the button that selects the current date (defaults to "Today")
10073 todayText : "Today",
10075 * @cfg {String} okText
10076 * The text to display on the ok button
10078 okText : " OK ", //   to give the user extra clicking room
10080 * @cfg {String} cancelText
10081 * The text to display on the cancel button
10083 cancelText : "Cancel",
10085 * @cfg {String} todayTip
10086 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10088 todayTip : "{0} (Spacebar)",
10090 * @cfg {Date} minDate
10091 * Minimum allowable date (JavaScript date object, defaults to null)
10095 * @cfg {Date} maxDate
10096 * Maximum allowable date (JavaScript date object, defaults to null)
10100 * @cfg {String} minText
10101 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10103 minText : "This date is before the minimum date",
10105 * @cfg {String} maxText
10106 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10108 maxText : "This date is after the maximum date",
10110 * @cfg {String} format
10111 * The default date format string which can be overriden for localization support. The format must be
10112 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10116 * @cfg {Array} disabledDays
10117 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10119 disabledDays : null,
10121 * @cfg {String} disabledDaysText
10122 * The tooltip to display when the date falls on a disabled day (defaults to "")
10124 disabledDaysText : "",
10126 * @cfg {RegExp} disabledDatesRE
10127 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10129 disabledDatesRE : null,
10131 * @cfg {String} disabledDatesText
10132 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10134 disabledDatesText : "",
10136 * @cfg {Boolean} constrainToViewport
10137 * True to constrain the date picker to the viewport (defaults to true)
10139 constrainToViewport : true,
10141 * @cfg {Array} monthNames
10142 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10144 monthNames : Date.monthNames,
10146 * @cfg {Array} dayNames
10147 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10149 dayNames : Date.dayNames,
10151 * @cfg {String} nextText
10152 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10154 nextText: 'Next Month (Control+Right)',
10156 * @cfg {String} prevText
10157 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10159 prevText: 'Previous Month (Control+Left)',
10161 * @cfg {String} monthYearText
10162 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10164 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10166 * @cfg {Number} startDay
10167 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10171 * @cfg {Bool} showClear
10172 * Show a clear button (usefull for date form elements that can be blank.)
10178 * Sets the value of the date field
10179 * @param {Date} value The date to set
10181 setValue : function(value){
10182 var old = this.value;
10183 this.value = value.clearTime(true);
10185 this.update(this.value);
10190 * Gets the current selected value of the date field
10191 * @return {Date} The selected date
10193 getValue : function(){
10198 focus : function(){
10200 this.update(this.activeDate);
10205 onRender : function(container, position){
10207 '<table cellspacing="0">',
10208 '<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>',
10209 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10210 var dn = this.dayNames;
10211 for(var i = 0; i < 7; i++){
10212 var d = this.startDay+i;
10216 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10218 m[m.length] = "</tr></thead><tbody><tr>";
10219 for(var i = 0; i < 42; i++) {
10220 if(i % 7 == 0 && i != 0){
10221 m[m.length] = "</tr><tr>";
10223 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10225 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10226 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10228 var el = document.createElement("div");
10229 el.className = "x-date-picker";
10230 el.innerHTML = m.join("");
10232 container.dom.insertBefore(el, position);
10234 this.el = Roo.get(el);
10235 this.eventEl = Roo.get(el.firstChild);
10237 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10238 handler: this.showPrevMonth,
10240 preventDefault:true,
10244 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10245 handler: this.showNextMonth,
10247 preventDefault:true,
10251 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10253 this.monthPicker = this.el.down('div.x-date-mp');
10254 this.monthPicker.enableDisplayMode('block');
10256 var kn = new Roo.KeyNav(this.eventEl, {
10257 "left" : function(e){
10259 this.showPrevMonth() :
10260 this.update(this.activeDate.add("d", -1));
10263 "right" : function(e){
10265 this.showNextMonth() :
10266 this.update(this.activeDate.add("d", 1));
10269 "up" : function(e){
10271 this.showNextYear() :
10272 this.update(this.activeDate.add("d", -7));
10275 "down" : function(e){
10277 this.showPrevYear() :
10278 this.update(this.activeDate.add("d", 7));
10281 "pageUp" : function(e){
10282 this.showNextMonth();
10285 "pageDown" : function(e){
10286 this.showPrevMonth();
10289 "enter" : function(e){
10290 e.stopPropagation();
10297 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10299 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10301 this.el.unselectable();
10303 this.cells = this.el.select("table.x-date-inner tbody td");
10304 this.textNodes = this.el.query("table.x-date-inner tbody span");
10306 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10308 tooltip: this.monthYearText
10311 this.mbtn.on('click', this.showMonthPicker, this);
10312 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10315 var today = (new Date()).dateFormat(this.format);
10317 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10318 if (this.showClear) {
10319 baseTb.add( new Roo.Toolbar.Fill());
10322 text: String.format(this.todayText, today),
10323 tooltip: String.format(this.todayTip, today),
10324 handler: this.selectToday,
10328 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10331 if (this.showClear) {
10333 baseTb.add( new Roo.Toolbar.Fill());
10336 cls: 'x-btn-icon x-btn-clear',
10337 handler: function() {
10339 this.fireEvent("select", this, '');
10349 this.update(this.value);
10352 createMonthPicker : function(){
10353 if(!this.monthPicker.dom.firstChild){
10354 var buf = ['<table border="0" cellspacing="0">'];
10355 for(var i = 0; i < 6; i++){
10357 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10358 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10360 '<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>' :
10361 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10365 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10367 '</button><button type="button" class="x-date-mp-cancel">',
10369 '</button></td></tr>',
10372 this.monthPicker.update(buf.join(''));
10373 this.monthPicker.on('click', this.onMonthClick, this);
10374 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10376 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10377 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10379 this.mpMonths.each(function(m, a, i){
10382 m.dom.xmonth = 5 + Math.round(i * .5);
10384 m.dom.xmonth = Math.round((i-1) * .5);
10390 showMonthPicker : function(){
10391 this.createMonthPicker();
10392 var size = this.el.getSize();
10393 this.monthPicker.setSize(size);
10394 this.monthPicker.child('table').setSize(size);
10396 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10397 this.updateMPMonth(this.mpSelMonth);
10398 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10399 this.updateMPYear(this.mpSelYear);
10401 this.monthPicker.slideIn('t', {duration:.2});
10404 updateMPYear : function(y){
10406 var ys = this.mpYears.elements;
10407 for(var i = 1; i <= 10; i++){
10408 var td = ys[i-1], y2;
10410 y2 = y + Math.round(i * .5);
10411 td.firstChild.innerHTML = y2;
10414 y2 = y - (5-Math.round(i * .5));
10415 td.firstChild.innerHTML = y2;
10418 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10422 updateMPMonth : function(sm){
10423 this.mpMonths.each(function(m, a, i){
10424 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10428 selectMPMonth: function(m){
10432 onMonthClick : function(e, t){
10434 var el = new Roo.Element(t), pn;
10435 if(el.is('button.x-date-mp-cancel')){
10436 this.hideMonthPicker();
10438 else if(el.is('button.x-date-mp-ok')){
10439 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10440 this.hideMonthPicker();
10442 else if(pn = el.up('td.x-date-mp-month', 2)){
10443 this.mpMonths.removeClass('x-date-mp-sel');
10444 pn.addClass('x-date-mp-sel');
10445 this.mpSelMonth = pn.dom.xmonth;
10447 else if(pn = el.up('td.x-date-mp-year', 2)){
10448 this.mpYears.removeClass('x-date-mp-sel');
10449 pn.addClass('x-date-mp-sel');
10450 this.mpSelYear = pn.dom.xyear;
10452 else if(el.is('a.x-date-mp-prev')){
10453 this.updateMPYear(this.mpyear-10);
10455 else if(el.is('a.x-date-mp-next')){
10456 this.updateMPYear(this.mpyear+10);
10460 onMonthDblClick : function(e, t){
10462 var el = new Roo.Element(t), pn;
10463 if(pn = el.up('td.x-date-mp-month', 2)){
10464 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10465 this.hideMonthPicker();
10467 else if(pn = el.up('td.x-date-mp-year', 2)){
10468 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10469 this.hideMonthPicker();
10473 hideMonthPicker : function(disableAnim){
10474 if(this.monthPicker){
10475 if(disableAnim === true){
10476 this.monthPicker.hide();
10478 this.monthPicker.slideOut('t', {duration:.2});
10484 showPrevMonth : function(e){
10485 this.update(this.activeDate.add("mo", -1));
10489 showNextMonth : function(e){
10490 this.update(this.activeDate.add("mo", 1));
10494 showPrevYear : function(){
10495 this.update(this.activeDate.add("y", -1));
10499 showNextYear : function(){
10500 this.update(this.activeDate.add("y", 1));
10504 handleMouseWheel : function(e){
10505 var delta = e.getWheelDelta();
10507 this.showPrevMonth();
10509 } else if(delta < 0){
10510 this.showNextMonth();
10516 handleDateClick : function(e, t){
10518 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10519 this.setValue(new Date(t.dateValue));
10520 this.fireEvent("select", this, this.value);
10525 selectToday : function(){
10526 this.setValue(new Date().clearTime());
10527 this.fireEvent("select", this, this.value);
10531 update : function(date){
10532 var vd = this.activeDate;
10533 this.activeDate = date;
10535 var t = date.getTime();
10536 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10537 this.cells.removeClass("x-date-selected");
10538 this.cells.each(function(c){
10539 if(c.dom.firstChild.dateValue == t){
10540 c.addClass("x-date-selected");
10541 setTimeout(function(){
10542 try{c.dom.firstChild.focus();}catch(e){}
10550 var days = date.getDaysInMonth();
10551 var firstOfMonth = date.getFirstDateOfMonth();
10552 var startingPos = firstOfMonth.getDay()-this.startDay;
10554 if(startingPos <= this.startDay){
10558 var pm = date.add("mo", -1);
10559 var prevStart = pm.getDaysInMonth()-startingPos;
10561 var cells = this.cells.elements;
10562 var textEls = this.textNodes;
10563 days += startingPos;
10565 // convert everything to numbers so it's fast
10566 var day = 86400000;
10567 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10568 var today = new Date().clearTime().getTime();
10569 var sel = date.clearTime().getTime();
10570 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10571 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10572 var ddMatch = this.disabledDatesRE;
10573 var ddText = this.disabledDatesText;
10574 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10575 var ddaysText = this.disabledDaysText;
10576 var format = this.format;
10578 var setCellClass = function(cal, cell){
10580 var t = d.getTime();
10581 cell.firstChild.dateValue = t;
10583 cell.className += " x-date-today";
10584 cell.title = cal.todayText;
10587 cell.className += " x-date-selected";
10588 setTimeout(function(){
10589 try{cell.firstChild.focus();}catch(e){}
10594 cell.className = " x-date-disabled";
10595 cell.title = cal.minText;
10599 cell.className = " x-date-disabled";
10600 cell.title = cal.maxText;
10604 if(ddays.indexOf(d.getDay()) != -1){
10605 cell.title = ddaysText;
10606 cell.className = " x-date-disabled";
10609 if(ddMatch && format){
10610 var fvalue = d.dateFormat(format);
10611 if(ddMatch.test(fvalue)){
10612 cell.title = ddText.replace("%0", fvalue);
10613 cell.className = " x-date-disabled";
10619 for(; i < startingPos; i++) {
10620 textEls[i].innerHTML = (++prevStart);
10621 d.setDate(d.getDate()+1);
10622 cells[i].className = "x-date-prevday";
10623 setCellClass(this, cells[i]);
10625 for(; i < days; i++){
10626 intDay = i - startingPos + 1;
10627 textEls[i].innerHTML = (intDay);
10628 d.setDate(d.getDate()+1);
10629 cells[i].className = "x-date-active";
10630 setCellClass(this, cells[i]);
10633 for(; i < 42; i++) {
10634 textEls[i].innerHTML = (++extraDays);
10635 d.setDate(d.getDate()+1);
10636 cells[i].className = "x-date-nextday";
10637 setCellClass(this, cells[i]);
10640 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10642 if(!this.internalRender){
10643 var main = this.el.dom.firstChild;
10644 var w = main.offsetWidth;
10645 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10646 Roo.fly(main).setWidth(w);
10647 this.internalRender = true;
10648 // opera does not respect the auto grow header center column
10649 // then, after it gets a width opera refuses to recalculate
10650 // without a second pass
10651 if(Roo.isOpera && !this.secondPass){
10652 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10653 this.secondPass = true;
10654 this.update.defer(10, this, [date]);
10660 * Ext JS Library 1.1.1
10661 * Copyright(c) 2006-2007, Ext JS, LLC.
10663 * Originally Released Under LGPL - original licence link has changed is not relivant.
10666 * <script type="text/javascript">
10669 * @class Roo.TabPanel
10670 * @extends Roo.util.Observable
10671 * A lightweight tab container.
10675 // basic tabs 1, built from existing content
10676 var tabs = new Roo.TabPanel("tabs1");
10677 tabs.addTab("script", "View Script");
10678 tabs.addTab("markup", "View Markup");
10679 tabs.activate("script");
10681 // more advanced tabs, built from javascript
10682 var jtabs = new Roo.TabPanel("jtabs");
10683 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10685 // set up the UpdateManager
10686 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10687 var updater = tab2.getUpdateManager();
10688 updater.setDefaultUrl("ajax1.htm");
10689 tab2.on('activate', updater.refresh, updater, true);
10691 // Use setUrl for Ajax loading
10692 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10693 tab3.setUrl("ajax2.htm", null, true);
10696 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10699 jtabs.activate("jtabs-1");
10702 * Create a new TabPanel.
10703 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10704 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10706 Roo.TabPanel = function(container, config){
10708 * The container element for this TabPanel.
10709 * @type Roo.Element
10711 this.el = Roo.get(container, true);
10713 if(typeof config == "boolean"){
10714 this.tabPosition = config ? "bottom" : "top";
10716 Roo.apply(this, config);
10719 if(this.tabPosition == "bottom"){
10720 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10721 this.el.addClass("x-tabs-bottom");
10723 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10724 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10725 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10727 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10729 if(this.tabPosition != "bottom"){
10730 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10731 * @type Roo.Element
10733 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10734 this.el.addClass("x-tabs-top");
10738 this.bodyEl.setStyle("position", "relative");
10740 this.active = null;
10741 this.activateDelegate = this.activate.createDelegate(this);
10746 * Fires when the active tab changes
10747 * @param {Roo.TabPanel} this
10748 * @param {Roo.TabPanelItem} activePanel The new active tab
10752 * @event beforetabchange
10753 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10754 * @param {Roo.TabPanel} this
10755 * @param {Object} e Set cancel to true on this object to cancel the tab change
10756 * @param {Roo.TabPanelItem} tab The tab being changed to
10758 "beforetabchange" : true
10761 Roo.EventManager.onWindowResize(this.onResize, this);
10762 this.cpad = this.el.getPadding("lr");
10763 this.hiddenCount = 0;
10765 Roo.TabPanel.superclass.constructor.call(this);
10768 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10770 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10772 tabPosition : "top",
10774 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10776 currentTabWidth : 0,
10778 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10782 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10786 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10788 preferredTabWidth : 175,
10790 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10792 resizeTabs : false,
10794 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10796 monitorResize : true,
10799 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10800 * @param {String} id The id of the div to use <b>or create</b>
10801 * @param {String} text The text for the tab
10802 * @param {String} content (optional) Content to put in the TabPanelItem body
10803 * @param {Boolean} closable (optional) True to create a close icon on the tab
10804 * @return {Roo.TabPanelItem} The created TabPanelItem
10806 addTab : function(id, text, content, closable){
10807 var item = new Roo.TabPanelItem(this, id, text, closable);
10808 this.addTabItem(item);
10810 item.setContent(content);
10816 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10817 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10818 * @return {Roo.TabPanelItem}
10820 getTab : function(id){
10821 return this.items[id];
10825 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10826 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10828 hideTab : function(id){
10829 var t = this.items[id];
10832 this.hiddenCount++;
10833 this.autoSizeTabs();
10838 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10839 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10841 unhideTab : function(id){
10842 var t = this.items[id];
10844 t.setHidden(false);
10845 this.hiddenCount--;
10846 this.autoSizeTabs();
10851 * Adds an existing {@link Roo.TabPanelItem}.
10852 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10854 addTabItem : function(item){
10855 this.items[item.id] = item;
10856 this.items.push(item);
10857 if(this.resizeTabs){
10858 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10859 this.autoSizeTabs();
10866 * Removes a {@link Roo.TabPanelItem}.
10867 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10869 removeTab : function(id){
10870 var items = this.items;
10871 var tab = items[id];
10872 if(!tab) { return; }
10873 var index = items.indexOf(tab);
10874 if(this.active == tab && items.length > 1){
10875 var newTab = this.getNextAvailable(index);
10880 this.stripEl.dom.removeChild(tab.pnode.dom);
10881 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10882 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10884 items.splice(index, 1);
10885 delete this.items[tab.id];
10886 tab.fireEvent("close", tab);
10887 tab.purgeListeners();
10888 this.autoSizeTabs();
10891 getNextAvailable : function(start){
10892 var items = this.items;
10894 // look for a next tab that will slide over to
10895 // replace the one being removed
10896 while(index < items.length){
10897 var item = items[++index];
10898 if(item && !item.isHidden()){
10902 // if one isn't found select the previous tab (on the left)
10905 var item = items[--index];
10906 if(item && !item.isHidden()){
10914 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10915 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10917 disableTab : function(id){
10918 var tab = this.items[id];
10919 if(tab && this.active != tab){
10925 * Enables a {@link Roo.TabPanelItem} that is disabled.
10926 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10928 enableTab : function(id){
10929 var tab = this.items[id];
10934 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10935 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10936 * @return {Roo.TabPanelItem} The TabPanelItem.
10938 activate : function(id){
10939 var tab = this.items[id];
10943 if(tab == this.active || tab.disabled){
10947 this.fireEvent("beforetabchange", this, e, tab);
10948 if(e.cancel !== true && !tab.disabled){
10950 this.active.hide();
10952 this.active = this.items[id];
10953 this.active.show();
10954 this.fireEvent("tabchange", this, this.active);
10960 * Gets the active {@link Roo.TabPanelItem}.
10961 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10963 getActiveTab : function(){
10964 return this.active;
10968 * Updates the tab body element to fit the height of the container element
10969 * for overflow scrolling
10970 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10972 syncHeight : function(targetHeight){
10973 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10974 var bm = this.bodyEl.getMargins();
10975 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10976 this.bodyEl.setHeight(newHeight);
10980 onResize : function(){
10981 if(this.monitorResize){
10982 this.autoSizeTabs();
10987 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10989 beginUpdate : function(){
10990 this.updating = true;
10994 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10996 endUpdate : function(){
10997 this.updating = false;
10998 this.autoSizeTabs();
11002 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11004 autoSizeTabs : function(){
11005 var count = this.items.length;
11006 var vcount = count - this.hiddenCount;
11007 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11008 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11009 var availWidth = Math.floor(w / vcount);
11010 var b = this.stripBody;
11011 if(b.getWidth() > w){
11012 var tabs = this.items;
11013 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11014 if(availWidth < this.minTabWidth){
11015 /*if(!this.sleft){ // incomplete scrolling code
11016 this.createScrollButtons();
11019 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11022 if(this.currentTabWidth < this.preferredTabWidth){
11023 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11029 * Returns the number of tabs in this TabPanel.
11032 getCount : function(){
11033 return this.items.length;
11037 * Resizes all the tabs to the passed width
11038 * @param {Number} The new width
11040 setTabWidth : function(width){
11041 this.currentTabWidth = width;
11042 for(var i = 0, len = this.items.length; i < len; i++) {
11043 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11048 * Destroys this TabPanel
11049 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11051 destroy : function(removeEl){
11052 Roo.EventManager.removeResizeListener(this.onResize, this);
11053 for(var i = 0, len = this.items.length; i < len; i++){
11054 this.items[i].purgeListeners();
11056 if(removeEl === true){
11057 this.el.update("");
11064 * @class Roo.TabPanelItem
11065 * @extends Roo.util.Observable
11066 * Represents an individual item (tab plus body) in a TabPanel.
11067 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11068 * @param {String} id The id of this TabPanelItem
11069 * @param {String} text The text for the tab of this TabPanelItem
11070 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11072 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11074 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11075 * @type Roo.TabPanel
11077 this.tabPanel = tabPanel;
11079 * The id for this TabPanelItem
11084 this.disabled = false;
11088 this.loaded = false;
11089 this.closable = closable;
11092 * The body element for this TabPanelItem.
11093 * @type Roo.Element
11095 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11096 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11097 this.bodyEl.setStyle("display", "block");
11098 this.bodyEl.setStyle("zoom", "1");
11101 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11103 this.el = Roo.get(els.el, true);
11104 this.inner = Roo.get(els.inner, true);
11105 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11106 this.pnode = Roo.get(els.el.parentNode, true);
11107 this.el.on("mousedown", this.onTabMouseDown, this);
11108 this.el.on("click", this.onTabClick, this);
11111 var c = Roo.get(els.close, true);
11112 c.dom.title = this.closeText;
11113 c.addClassOnOver("close-over");
11114 c.on("click", this.closeClick, this);
11120 * Fires when this tab becomes the active tab.
11121 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11122 * @param {Roo.TabPanelItem} this
11126 * @event beforeclose
11127 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11128 * @param {Roo.TabPanelItem} this
11129 * @param {Object} e Set cancel to true on this object to cancel the close.
11131 "beforeclose": true,
11134 * Fires when this tab is closed.
11135 * @param {Roo.TabPanelItem} this
11139 * @event deactivate
11140 * Fires when this tab is no longer the active tab.
11141 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11142 * @param {Roo.TabPanelItem} this
11144 "deactivate" : true
11146 this.hidden = false;
11148 Roo.TabPanelItem.superclass.constructor.call(this);
11151 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11152 purgeListeners : function(){
11153 Roo.util.Observable.prototype.purgeListeners.call(this);
11154 this.el.removeAllListeners();
11157 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11160 this.pnode.addClass("on");
11163 this.tabPanel.stripWrap.repaint();
11165 this.fireEvent("activate", this.tabPanel, this);
11169 * Returns true if this tab is the active tab.
11170 * @return {Boolean}
11172 isActive : function(){
11173 return this.tabPanel.getActiveTab() == this;
11177 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11180 this.pnode.removeClass("on");
11182 this.fireEvent("deactivate", this.tabPanel, this);
11185 hideAction : function(){
11186 this.bodyEl.hide();
11187 this.bodyEl.setStyle("position", "absolute");
11188 this.bodyEl.setLeft("-20000px");
11189 this.bodyEl.setTop("-20000px");
11192 showAction : function(){
11193 this.bodyEl.setStyle("position", "relative");
11194 this.bodyEl.setTop("");
11195 this.bodyEl.setLeft("");
11196 this.bodyEl.show();
11200 * Set the tooltip for the tab.
11201 * @param {String} tooltip The tab's tooltip
11203 setTooltip : function(text){
11204 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11205 this.textEl.dom.qtip = text;
11206 this.textEl.dom.removeAttribute('title');
11208 this.textEl.dom.title = text;
11212 onTabClick : function(e){
11213 e.preventDefault();
11214 this.tabPanel.activate(this.id);
11217 onTabMouseDown : function(e){
11218 e.preventDefault();
11219 this.tabPanel.activate(this.id);
11222 getWidth : function(){
11223 return this.inner.getWidth();
11226 setWidth : function(width){
11227 var iwidth = width - this.pnode.getPadding("lr");
11228 this.inner.setWidth(iwidth);
11229 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11230 this.pnode.setWidth(width);
11234 * Show or hide the tab
11235 * @param {Boolean} hidden True to hide or false to show.
11237 setHidden : function(hidden){
11238 this.hidden = hidden;
11239 this.pnode.setStyle("display", hidden ? "none" : "");
11243 * Returns true if this tab is "hidden"
11244 * @return {Boolean}
11246 isHidden : function(){
11247 return this.hidden;
11251 * Returns the text for this tab
11254 getText : function(){
11258 autoSize : function(){
11259 //this.el.beginMeasure();
11260 this.textEl.setWidth(1);
11261 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11262 //this.el.endMeasure();
11266 * Sets the text for the tab (Note: this also sets the tooltip text)
11267 * @param {String} text The tab's text and tooltip
11269 setText : function(text){
11271 this.textEl.update(text);
11272 this.setTooltip(text);
11273 if(!this.tabPanel.resizeTabs){
11278 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11280 activate : function(){
11281 this.tabPanel.activate(this.id);
11285 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11287 disable : function(){
11288 if(this.tabPanel.active != this){
11289 this.disabled = true;
11290 this.pnode.addClass("disabled");
11295 * Enables this TabPanelItem if it was previously disabled.
11297 enable : function(){
11298 this.disabled = false;
11299 this.pnode.removeClass("disabled");
11303 * Sets the content for this TabPanelItem.
11304 * @param {String} content The content
11305 * @param {Boolean} loadScripts true to look for and load scripts
11307 setContent : function(content, loadScripts){
11308 this.bodyEl.update(content, loadScripts);
11312 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11313 * @return {Roo.UpdateManager} The UpdateManager
11315 getUpdateManager : function(){
11316 return this.bodyEl.getUpdateManager();
11320 * Set a URL to be used to load the content for this TabPanelItem.
11321 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11322 * @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)
11323 * @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)
11324 * @return {Roo.UpdateManager} The UpdateManager
11326 setUrl : function(url, params, loadOnce){
11327 if(this.refreshDelegate){
11328 this.un('activate', this.refreshDelegate);
11330 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11331 this.on("activate", this.refreshDelegate);
11332 return this.bodyEl.getUpdateManager();
11336 _handleRefresh : function(url, params, loadOnce){
11337 if(!loadOnce || !this.loaded){
11338 var updater = this.bodyEl.getUpdateManager();
11339 updater.update(url, params, this._setLoaded.createDelegate(this));
11344 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11345 * Will fail silently if the setUrl method has not been called.
11346 * This does not activate the panel, just updates its content.
11348 refresh : function(){
11349 if(this.refreshDelegate){
11350 this.loaded = false;
11351 this.refreshDelegate();
11356 _setLoaded : function(){
11357 this.loaded = true;
11361 closeClick : function(e){
11364 this.fireEvent("beforeclose", this, o);
11365 if(o.cancel !== true){
11366 this.tabPanel.removeTab(this.id);
11370 * The text displayed in the tooltip for the close icon.
11373 closeText : "Close this tab"
11377 Roo.TabPanel.prototype.createStrip = function(container){
11378 var strip = document.createElement("div");
11379 strip.className = "x-tabs-wrap";
11380 container.appendChild(strip);
11384 Roo.TabPanel.prototype.createStripList = function(strip){
11385 // div wrapper for retard IE
11386 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>';
11387 return strip.firstChild.firstChild.firstChild.firstChild;
11390 Roo.TabPanel.prototype.createBody = function(container){
11391 var body = document.createElement("div");
11392 Roo.id(body, "tab-body");
11393 Roo.fly(body).addClass("x-tabs-body");
11394 container.appendChild(body);
11398 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11399 var body = Roo.getDom(id);
11401 body = document.createElement("div");
11404 Roo.fly(body).addClass("x-tabs-item-body");
11405 bodyEl.insertBefore(body, bodyEl.firstChild);
11409 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11410 var td = document.createElement("td");
11411 stripEl.appendChild(td);
11413 td.className = "x-tabs-closable";
11414 if(!this.closeTpl){
11415 this.closeTpl = new Roo.Template(
11416 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11417 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11418 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11421 var el = this.closeTpl.overwrite(td, {"text": text});
11422 var close = el.getElementsByTagName("div")[0];
11423 var inner = el.getElementsByTagName("em")[0];
11424 return {"el": el, "close": close, "inner": inner};
11427 this.tabTpl = new Roo.Template(
11428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11432 var el = this.tabTpl.overwrite(td, {"text": text});
11433 var inner = el.getElementsByTagName("em")[0];
11434 return {"el": el, "inner": inner};
11438 * Ext JS Library 1.1.1
11439 * Copyright(c) 2006-2007, Ext JS, LLC.
11441 * Originally Released Under LGPL - original licence link has changed is not relivant.
11444 * <script type="text/javascript">
11448 * @class Roo.Button
11449 * @extends Roo.util.Observable
11450 * Simple Button class
11451 * @cfg {String} text The button text
11452 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11453 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11454 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11455 * @cfg {Object} scope The scope of the handler
11456 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11457 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11458 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11459 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11460 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11461 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11462 applies if enableToggle = true)
11463 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11464 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11465 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11467 * Create a new button
11468 * @param {Object} config The config object
11470 Roo.Button = function(renderTo, config)
11474 renderTo = config.renderTo || false;
11477 Roo.apply(this, config);
11481 * Fires when this button is clicked
11482 * @param {Button} this
11483 * @param {EventObject} e The click event
11488 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11489 * @param {Button} this
11490 * @param {Boolean} pressed
11495 * Fires when the mouse hovers over the button
11496 * @param {Button} this
11497 * @param {Event} e The event object
11499 'mouseover' : true,
11502 * Fires when the mouse exits the button
11503 * @param {Button} this
11504 * @param {Event} e The event object
11509 * Fires when the button is rendered
11510 * @param {Button} this
11515 this.menu = Roo.menu.MenuMgr.get(this.menu);
11517 // register listeners first!! - so render can be captured..
11518 Roo.util.Observable.call(this);
11520 this.render(renderTo);
11526 Roo.extend(Roo.Button, Roo.util.Observable, {
11532 * Read-only. True if this button is hidden
11537 * Read-only. True if this button is disabled
11542 * Read-only. True if this button is pressed (only if enableToggle = true)
11548 * @cfg {Number} tabIndex
11549 * The DOM tabIndex for this button (defaults to undefined)
11551 tabIndex : undefined,
11554 * @cfg {Boolean} enableToggle
11555 * True to enable pressed/not pressed toggling (defaults to false)
11557 enableToggle: false,
11559 * @cfg {Mixed} menu
11560 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11564 * @cfg {String} menuAlign
11565 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11567 menuAlign : "tl-bl?",
11570 * @cfg {String} iconCls
11571 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11573 iconCls : undefined,
11575 * @cfg {String} type
11576 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11581 menuClassTarget: 'tr',
11584 * @cfg {String} clickEvent
11585 * The type of event to map to the button's event handler (defaults to 'click')
11587 clickEvent : 'click',
11590 * @cfg {Boolean} handleMouseEvents
11591 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11593 handleMouseEvents : true,
11596 * @cfg {String} tooltipType
11597 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11599 tooltipType : 'qtip',
11602 * @cfg {String} cls
11603 * A CSS class to apply to the button's main element.
11607 * @cfg {Roo.Template} template (Optional)
11608 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11609 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11610 * require code modifications if required elements (e.g. a button) aren't present.
11614 render : function(renderTo){
11616 if(this.hideParent){
11617 this.parentEl = Roo.get(renderTo);
11619 if(!this.dhconfig){
11620 if(!this.template){
11621 if(!Roo.Button.buttonTemplate){
11622 // hideous table template
11623 Roo.Button.buttonTemplate = new Roo.Template(
11624 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11625 '<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>',
11626 "</tr></tbody></table>");
11628 this.template = Roo.Button.buttonTemplate;
11630 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11631 var btnEl = btn.child("button:first");
11632 btnEl.on('focus', this.onFocus, this);
11633 btnEl.on('blur', this.onBlur, this);
11635 btn.addClass(this.cls);
11638 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11641 btnEl.addClass(this.iconCls);
11643 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11646 if(this.tabIndex !== undefined){
11647 btnEl.dom.tabIndex = this.tabIndex;
11650 if(typeof this.tooltip == 'object'){
11651 Roo.QuickTips.tips(Roo.apply({
11655 btnEl.dom[this.tooltipType] = this.tooltip;
11659 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11663 this.el.dom.id = this.el.id = this.id;
11666 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11667 this.menu.on("show", this.onMenuShow, this);
11668 this.menu.on("hide", this.onMenuHide, this);
11670 btn.addClass("x-btn");
11671 if(Roo.isIE && !Roo.isIE7){
11672 this.autoWidth.defer(1, this);
11676 if(this.handleMouseEvents){
11677 btn.on("mouseover", this.onMouseOver, this);
11678 btn.on("mouseout", this.onMouseOut, this);
11679 btn.on("mousedown", this.onMouseDown, this);
11681 btn.on(this.clickEvent, this.onClick, this);
11682 //btn.on("mouseup", this.onMouseUp, this);
11689 Roo.ButtonToggleMgr.register(this);
11691 this.el.addClass("x-btn-pressed");
11694 var repeater = new Roo.util.ClickRepeater(btn,
11695 typeof this.repeat == "object" ? this.repeat : {}
11697 repeater.on("click", this.onClick, this);
11700 this.fireEvent('render', this);
11704 * Returns the button's underlying element
11705 * @return {Roo.Element} The element
11707 getEl : function(){
11712 * Destroys this Button and removes any listeners.
11714 destroy : function(){
11715 Roo.ButtonToggleMgr.unregister(this);
11716 this.el.removeAllListeners();
11717 this.purgeListeners();
11722 autoWidth : function(){
11724 this.el.setWidth("auto");
11725 if(Roo.isIE7 && Roo.isStrict){
11726 var ib = this.el.child('button');
11727 if(ib && ib.getWidth() > 20){
11729 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11734 this.el.beginMeasure();
11736 if(this.el.getWidth() < this.minWidth){
11737 this.el.setWidth(this.minWidth);
11740 this.el.endMeasure();
11747 * Assigns this button's click handler
11748 * @param {Function} handler The function to call when the button is clicked
11749 * @param {Object} scope (optional) Scope for the function passed in
11751 setHandler : function(handler, scope){
11752 this.handler = handler;
11753 this.scope = scope;
11757 * Sets this button's text
11758 * @param {String} text The button text
11760 setText : function(text){
11763 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11769 * Gets the text for this button
11770 * @return {String} The button text
11772 getText : function(){
11780 this.hidden = false;
11782 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11790 this.hidden = true;
11792 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11797 * Convenience function for boolean show/hide
11798 * @param {Boolean} visible True to show, false to hide
11800 setVisible: function(visible){
11809 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11810 * @param {Boolean} state (optional) Force a particular state
11812 toggle : function(state){
11813 state = state === undefined ? !this.pressed : state;
11814 if(state != this.pressed){
11816 this.el.addClass("x-btn-pressed");
11817 this.pressed = true;
11818 this.fireEvent("toggle", this, true);
11820 this.el.removeClass("x-btn-pressed");
11821 this.pressed = false;
11822 this.fireEvent("toggle", this, false);
11824 if(this.toggleHandler){
11825 this.toggleHandler.call(this.scope || this, this, state);
11833 focus : function(){
11834 this.el.child('button:first').focus();
11838 * Disable this button
11840 disable : function(){
11842 this.el.addClass("x-btn-disabled");
11844 this.disabled = true;
11848 * Enable this button
11850 enable : function(){
11852 this.el.removeClass("x-btn-disabled");
11854 this.disabled = false;
11858 * Convenience function for boolean enable/disable
11859 * @param {Boolean} enabled True to enable, false to disable
11861 setDisabled : function(v){
11862 this[v !== true ? "enable" : "disable"]();
11866 onClick : function(e){
11868 e.preventDefault();
11873 if(!this.disabled){
11874 if(this.enableToggle){
11877 if(this.menu && !this.menu.isVisible()){
11878 this.menu.show(this.el, this.menuAlign);
11880 this.fireEvent("click", this, e);
11882 this.el.removeClass("x-btn-over");
11883 this.handler.call(this.scope || this, this, e);
11888 onMouseOver : function(e){
11889 if(!this.disabled){
11890 this.el.addClass("x-btn-over");
11891 this.fireEvent('mouseover', this, e);
11895 onMouseOut : function(e){
11896 if(!e.within(this.el, true)){
11897 this.el.removeClass("x-btn-over");
11898 this.fireEvent('mouseout', this, e);
11902 onFocus : function(e){
11903 if(!this.disabled){
11904 this.el.addClass("x-btn-focus");
11908 onBlur : function(e){
11909 this.el.removeClass("x-btn-focus");
11912 onMouseDown : function(e){
11913 if(!this.disabled && e.button == 0){
11914 this.el.addClass("x-btn-click");
11915 Roo.get(document).on('mouseup', this.onMouseUp, this);
11919 onMouseUp : function(e){
11921 this.el.removeClass("x-btn-click");
11922 Roo.get(document).un('mouseup', this.onMouseUp, this);
11926 onMenuShow : function(e){
11927 this.el.addClass("x-btn-menu-active");
11930 onMenuHide : function(e){
11931 this.el.removeClass("x-btn-menu-active");
11935 // Private utility class used by Button
11936 Roo.ButtonToggleMgr = function(){
11939 function toggleGroup(btn, state){
11941 var g = groups[btn.toggleGroup];
11942 for(var i = 0, l = g.length; i < l; i++){
11944 g[i].toggle(false);
11951 register : function(btn){
11952 if(!btn.toggleGroup){
11955 var g = groups[btn.toggleGroup];
11957 g = groups[btn.toggleGroup] = [];
11960 btn.on("toggle", toggleGroup);
11963 unregister : function(btn){
11964 if(!btn.toggleGroup){
11967 var g = groups[btn.toggleGroup];
11970 btn.un("toggle", toggleGroup);
11976 * Ext JS Library 1.1.1
11977 * Copyright(c) 2006-2007, Ext JS, LLC.
11979 * Originally Released Under LGPL - original licence link has changed is not relivant.
11982 * <script type="text/javascript">
11986 * @class Roo.SplitButton
11987 * @extends Roo.Button
11988 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11989 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11990 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11991 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11992 * @cfg {String} arrowTooltip The title attribute of the arrow
11994 * Create a new menu button
11995 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11996 * @param {Object} config The config object
11998 Roo.SplitButton = function(renderTo, config){
11999 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12001 * @event arrowclick
12002 * Fires when this button's arrow is clicked
12003 * @param {SplitButton} this
12004 * @param {EventObject} e The click event
12006 this.addEvents({"arrowclick":true});
12009 Roo.extend(Roo.SplitButton, Roo.Button, {
12010 render : function(renderTo){
12011 // this is one sweet looking template!
12012 var tpl = new Roo.Template(
12013 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12014 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12015 '<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>',
12016 "</tbody></table></td><td>",
12017 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12018 '<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>',
12019 "</tbody></table></td></tr></table>"
12021 var btn = tpl.append(renderTo, [this.text, this.type], true);
12022 var btnEl = btn.child("button");
12024 btn.addClass(this.cls);
12027 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12030 btnEl.addClass(this.iconCls);
12032 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12036 if(this.handleMouseEvents){
12037 btn.on("mouseover", this.onMouseOver, this);
12038 btn.on("mouseout", this.onMouseOut, this);
12039 btn.on("mousedown", this.onMouseDown, this);
12040 btn.on("mouseup", this.onMouseUp, this);
12042 btn.on(this.clickEvent, this.onClick, this);
12044 if(typeof this.tooltip == 'object'){
12045 Roo.QuickTips.tips(Roo.apply({
12049 btnEl.dom[this.tooltipType] = this.tooltip;
12052 if(this.arrowTooltip){
12053 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12062 this.el.addClass("x-btn-pressed");
12064 if(Roo.isIE && !Roo.isIE7){
12065 this.autoWidth.defer(1, this);
12070 this.menu.on("show", this.onMenuShow, this);
12071 this.menu.on("hide", this.onMenuHide, this);
12073 this.fireEvent('render', this);
12077 autoWidth : function(){
12079 var tbl = this.el.child("table:first");
12080 var tbl2 = this.el.child("table:last");
12081 this.el.setWidth("auto");
12082 tbl.setWidth("auto");
12083 if(Roo.isIE7 && Roo.isStrict){
12084 var ib = this.el.child('button:first');
12085 if(ib && ib.getWidth() > 20){
12087 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12092 this.el.beginMeasure();
12094 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12095 tbl.setWidth(this.minWidth-tbl2.getWidth());
12098 this.el.endMeasure();
12101 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12105 * Sets this button's click handler
12106 * @param {Function} handler The function to call when the button is clicked
12107 * @param {Object} scope (optional) Scope for the function passed above
12109 setHandler : function(handler, scope){
12110 this.handler = handler;
12111 this.scope = scope;
12115 * Sets this button's arrow click handler
12116 * @param {Function} handler The function to call when the arrow is clicked
12117 * @param {Object} scope (optional) Scope for the function passed above
12119 setArrowHandler : function(handler, scope){
12120 this.arrowHandler = handler;
12121 this.scope = scope;
12127 focus : function(){
12129 this.el.child("button:first").focus();
12134 onClick : function(e){
12135 e.preventDefault();
12136 if(!this.disabled){
12137 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12138 if(this.menu && !this.menu.isVisible()){
12139 this.menu.show(this.el, this.menuAlign);
12141 this.fireEvent("arrowclick", this, e);
12142 if(this.arrowHandler){
12143 this.arrowHandler.call(this.scope || this, this, e);
12146 this.fireEvent("click", this, e);
12148 this.handler.call(this.scope || this, this, e);
12154 onMouseDown : function(e){
12155 if(!this.disabled){
12156 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12160 onMouseUp : function(e){
12161 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12166 // backwards compat
12167 Roo.MenuButton = Roo.SplitButton;/*
12169 * Ext JS Library 1.1.1
12170 * Copyright(c) 2006-2007, Ext JS, LLC.
12172 * Originally Released Under LGPL - original licence link has changed is not relivant.
12175 * <script type="text/javascript">
12179 * @class Roo.Toolbar
12180 * Basic Toolbar class.
12182 * Creates a new Toolbar
12183 * @param {Object} config The config object
12185 Roo.Toolbar = function(container, buttons, config)
12187 /// old consturctor format still supported..
12188 if(container instanceof Array){ // omit the container for later rendering
12189 buttons = container;
12193 if (typeof(container) == 'object' && container.xtype) {
12194 config = container;
12195 container = config.container;
12196 buttons = config.buttons; // not really - use items!!
12199 if (config && config.items) {
12200 xitems = config.items;
12201 delete config.items;
12203 Roo.apply(this, config);
12204 this.buttons = buttons;
12207 this.render(container);
12209 Roo.each(xitems, function(b) {
12215 Roo.Toolbar.prototype = {
12217 * @cfg {Roo.data.Store} items
12218 * array of button configs or elements to add
12222 * @cfg {String/HTMLElement/Element} container
12223 * The id or element that will contain the toolbar
12226 render : function(ct){
12227 this.el = Roo.get(ct);
12229 this.el.addClass(this.cls);
12231 // using a table allows for vertical alignment
12232 // 100% width is needed by Safari...
12233 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12234 this.tr = this.el.child("tr", true);
12236 this.items = new Roo.util.MixedCollection(false, function(o){
12237 return o.id || ("item" + (++autoId));
12240 this.add.apply(this, this.buttons);
12241 delete this.buttons;
12246 * Adds element(s) to the toolbar -- this function takes a variable number of
12247 * arguments of mixed type and adds them to the toolbar.
12248 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12250 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12251 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12252 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12253 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12254 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12255 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12256 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12257 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12258 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12260 * @param {Mixed} arg2
12261 * @param {Mixed} etc.
12264 var a = arguments, l = a.length;
12265 for(var i = 0; i < l; i++){
12270 _add : function(el) {
12273 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12276 if (el.applyTo){ // some kind of form field
12277 return this.addField(el);
12279 if (el.render){ // some kind of Toolbar.Item
12280 return this.addItem(el);
12282 if (typeof el == "string"){ // string
12283 if(el == "separator" || el == "-"){
12284 return this.addSeparator();
12287 return this.addSpacer();
12290 return this.addFill();
12292 return this.addText(el);
12295 if(el.tagName){ // element
12296 return this.addElement(el);
12298 if(typeof el == "object"){ // must be button config?
12299 return this.addButton(el);
12301 // and now what?!?!
12307 * Add an Xtype element
12308 * @param {Object} xtype Xtype Object
12309 * @return {Object} created Object
12311 addxtype : function(e){
12312 return this.add(e);
12316 * Returns the Element for this toolbar.
12317 * @return {Roo.Element}
12319 getEl : function(){
12325 * @return {Roo.Toolbar.Item} The separator item
12327 addSeparator : function(){
12328 return this.addItem(new Roo.Toolbar.Separator());
12332 * Adds a spacer element
12333 * @return {Roo.Toolbar.Spacer} The spacer item
12335 addSpacer : function(){
12336 return this.addItem(new Roo.Toolbar.Spacer());
12340 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12341 * @return {Roo.Toolbar.Fill} The fill item
12343 addFill : function(){
12344 return this.addItem(new Roo.Toolbar.Fill());
12348 * Adds any standard HTML element to the toolbar
12349 * @param {String/HTMLElement/Element} el The element or id of the element to add
12350 * @return {Roo.Toolbar.Item} The element's item
12352 addElement : function(el){
12353 return this.addItem(new Roo.Toolbar.Item(el));
12356 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12357 * @type Roo.util.MixedCollection
12362 * Adds any Toolbar.Item or subclass
12363 * @param {Roo.Toolbar.Item} item
12364 * @return {Roo.Toolbar.Item} The item
12366 addItem : function(item){
12367 var td = this.nextBlock();
12369 this.items.add(item);
12374 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12375 * @param {Object/Array} config A button config or array of configs
12376 * @return {Roo.Toolbar.Button/Array}
12378 addButton : function(config){
12379 if(config instanceof Array){
12381 for(var i = 0, len = config.length; i < len; i++) {
12382 buttons.push(this.addButton(config[i]));
12387 if(!(config instanceof Roo.Toolbar.Button)){
12389 new Roo.Toolbar.SplitButton(config) :
12390 new Roo.Toolbar.Button(config);
12392 var td = this.nextBlock();
12399 * Adds text to the toolbar
12400 * @param {String} text The text to add
12401 * @return {Roo.Toolbar.Item} The element's item
12403 addText : function(text){
12404 return this.addItem(new Roo.Toolbar.TextItem(text));
12408 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12409 * @param {Number} index The index where the item is to be inserted
12410 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12411 * @return {Roo.Toolbar.Button/Item}
12413 insertButton : function(index, item){
12414 if(item instanceof Array){
12416 for(var i = 0, len = item.length; i < len; i++) {
12417 buttons.push(this.insertButton(index + i, item[i]));
12421 if (!(item instanceof Roo.Toolbar.Button)){
12422 item = new Roo.Toolbar.Button(item);
12424 var td = document.createElement("td");
12425 this.tr.insertBefore(td, this.tr.childNodes[index]);
12427 this.items.insert(index, item);
12432 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12433 * @param {Object} config
12434 * @return {Roo.Toolbar.Item} The element's item
12436 addDom : function(config, returnEl){
12437 var td = this.nextBlock();
12438 Roo.DomHelper.overwrite(td, config);
12439 var ti = new Roo.Toolbar.Item(td.firstChild);
12441 this.items.add(ti);
12446 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12447 * @type Roo.util.MixedCollection
12452 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12453 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12454 * @param {Roo.form.Field} field
12455 * @return {Roo.ToolbarItem}
12459 addField : function(field) {
12460 if (!this.fields) {
12462 this.fields = new Roo.util.MixedCollection(false, function(o){
12463 return o.id || ("item" + (++autoId));
12468 var td = this.nextBlock();
12470 var ti = new Roo.Toolbar.Item(td.firstChild);
12472 this.items.add(ti);
12473 this.fields.add(field);
12484 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12485 this.el.child('div').hide();
12493 this.el.child('div').show();
12497 nextBlock : function(){
12498 var td = document.createElement("td");
12499 this.tr.appendChild(td);
12504 destroy : function(){
12505 if(this.items){ // rendered?
12506 Roo.destroy.apply(Roo, this.items.items);
12508 if(this.fields){ // rendered?
12509 Roo.destroy.apply(Roo, this.fields.items);
12511 Roo.Element.uncache(this.el, this.tr);
12516 * @class Roo.Toolbar.Item
12517 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12519 * Creates a new Item
12520 * @param {HTMLElement} el
12522 Roo.Toolbar.Item = function(el){
12523 this.el = Roo.getDom(el);
12524 this.id = Roo.id(this.el);
12525 this.hidden = false;
12528 Roo.Toolbar.Item.prototype = {
12531 * Get this item's HTML Element
12532 * @return {HTMLElement}
12534 getEl : function(){
12539 render : function(td){
12541 td.appendChild(this.el);
12545 * Removes and destroys this item.
12547 destroy : function(){
12548 this.td.parentNode.removeChild(this.td);
12555 this.hidden = false;
12556 this.td.style.display = "";
12563 this.hidden = true;
12564 this.td.style.display = "none";
12568 * Convenience function for boolean show/hide.
12569 * @param {Boolean} visible true to show/false to hide
12571 setVisible: function(visible){
12580 * Try to focus this item.
12582 focus : function(){
12583 Roo.fly(this.el).focus();
12587 * Disables this item.
12589 disable : function(){
12590 Roo.fly(this.td).addClass("x-item-disabled");
12591 this.disabled = true;
12592 this.el.disabled = true;
12596 * Enables this item.
12598 enable : function(){
12599 Roo.fly(this.td).removeClass("x-item-disabled");
12600 this.disabled = false;
12601 this.el.disabled = false;
12607 * @class Roo.Toolbar.Separator
12608 * @extends Roo.Toolbar.Item
12609 * A simple toolbar separator class
12611 * Creates a new Separator
12613 Roo.Toolbar.Separator = function(){
12614 var s = document.createElement("span");
12615 s.className = "ytb-sep";
12616 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12618 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12619 enable:Roo.emptyFn,
12620 disable:Roo.emptyFn,
12625 * @class Roo.Toolbar.Spacer
12626 * @extends Roo.Toolbar.Item
12627 * A simple element that adds extra horizontal space to a toolbar.
12629 * Creates a new Spacer
12631 Roo.Toolbar.Spacer = function(){
12632 var s = document.createElement("div");
12633 s.className = "ytb-spacer";
12634 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12636 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12637 enable:Roo.emptyFn,
12638 disable:Roo.emptyFn,
12643 * @class Roo.Toolbar.Fill
12644 * @extends Roo.Toolbar.Spacer
12645 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12647 * Creates a new Spacer
12649 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12651 render : function(td){
12652 td.style.width = '100%';
12653 Roo.Toolbar.Fill.superclass.render.call(this, td);
12658 * @class Roo.Toolbar.TextItem
12659 * @extends Roo.Toolbar.Item
12660 * A simple class that renders text directly into a toolbar.
12662 * Creates a new TextItem
12663 * @param {String} text
12665 Roo.Toolbar.TextItem = function(text){
12666 if (typeof(text) == 'object') {
12669 var s = document.createElement("span");
12670 s.className = "ytb-text";
12671 s.innerHTML = text;
12672 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12674 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12675 enable:Roo.emptyFn,
12676 disable:Roo.emptyFn,
12681 * @class Roo.Toolbar.Button
12682 * @extends Roo.Button
12683 * A button that renders into a toolbar.
12685 * Creates a new Button
12686 * @param {Object} config A standard {@link Roo.Button} config object
12688 Roo.Toolbar.Button = function(config){
12689 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12691 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12692 render : function(td){
12694 Roo.Toolbar.Button.superclass.render.call(this, td);
12698 * Removes and destroys this button
12700 destroy : function(){
12701 Roo.Toolbar.Button.superclass.destroy.call(this);
12702 this.td.parentNode.removeChild(this.td);
12706 * Shows this button
12709 this.hidden = false;
12710 this.td.style.display = "";
12714 * Hides this button
12717 this.hidden = true;
12718 this.td.style.display = "none";
12722 * Disables this item
12724 disable : function(){
12725 Roo.fly(this.td).addClass("x-item-disabled");
12726 this.disabled = true;
12730 * Enables this item
12732 enable : function(){
12733 Roo.fly(this.td).removeClass("x-item-disabled");
12734 this.disabled = false;
12737 // backwards compat
12738 Roo.ToolbarButton = Roo.Toolbar.Button;
12741 * @class Roo.Toolbar.SplitButton
12742 * @extends Roo.SplitButton
12743 * A menu button that renders into a toolbar.
12745 * Creates a new SplitButton
12746 * @param {Object} config A standard {@link Roo.SplitButton} config object
12748 Roo.Toolbar.SplitButton = function(config){
12749 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12751 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12752 render : function(td){
12754 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12758 * Removes and destroys this button
12760 destroy : function(){
12761 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12762 this.td.parentNode.removeChild(this.td);
12766 * Shows this button
12769 this.hidden = false;
12770 this.td.style.display = "";
12774 * Hides this button
12777 this.hidden = true;
12778 this.td.style.display = "none";
12782 // backwards compat
12783 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12785 * Ext JS Library 1.1.1
12786 * Copyright(c) 2006-2007, Ext JS, LLC.
12788 * Originally Released Under LGPL - original licence link has changed is not relivant.
12791 * <script type="text/javascript">
12795 * @class Roo.PagingToolbar
12796 * @extends Roo.Toolbar
12797 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12799 * Create a new PagingToolbar
12800 * @param {Object} config The config object
12802 Roo.PagingToolbar = function(el, ds, config)
12804 // old args format still supported... - xtype is prefered..
12805 if (typeof(el) == 'object' && el.xtype) {
12806 // created from xtype...
12808 ds = el.dataSource;
12809 el = config.container;
12812 if (config.items) {
12813 items = config.items;
12817 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12820 this.renderButtons(this.el);
12823 // supprot items array.
12825 Roo.each(items, function(e) {
12826 this.add(Roo.factory(e));
12831 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12833 * @cfg {Roo.data.Store} dataSource
12834 * The underlying data store providing the paged data
12837 * @cfg {String/HTMLElement/Element} container
12838 * container The id or element that will contain the toolbar
12841 * @cfg {Boolean} displayInfo
12842 * True to display the displayMsg (defaults to false)
12845 * @cfg {Number} pageSize
12846 * The number of records to display per page (defaults to 20)
12850 * @cfg {String} displayMsg
12851 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12853 displayMsg : 'Displaying {0} - {1} of {2}',
12855 * @cfg {String} emptyMsg
12856 * The message to display when no records are found (defaults to "No data to display")
12858 emptyMsg : 'No data to display',
12860 * Customizable piece of the default paging text (defaults to "Page")
12863 beforePageText : "Page",
12865 * Customizable piece of the default paging text (defaults to "of %0")
12868 afterPageText : "of {0}",
12870 * Customizable piece of the default paging text (defaults to "First Page")
12873 firstText : "First Page",
12875 * Customizable piece of the default paging text (defaults to "Previous Page")
12878 prevText : "Previous Page",
12880 * Customizable piece of the default paging text (defaults to "Next Page")
12883 nextText : "Next Page",
12885 * Customizable piece of the default paging text (defaults to "Last Page")
12888 lastText : "Last Page",
12890 * Customizable piece of the default paging text (defaults to "Refresh")
12893 refreshText : "Refresh",
12896 renderButtons : function(el){
12897 Roo.PagingToolbar.superclass.render.call(this, el);
12898 this.first = this.addButton({
12899 tooltip: this.firstText,
12900 cls: "x-btn-icon x-grid-page-first",
12902 handler: this.onClick.createDelegate(this, ["first"])
12904 this.prev = this.addButton({
12905 tooltip: this.prevText,
12906 cls: "x-btn-icon x-grid-page-prev",
12908 handler: this.onClick.createDelegate(this, ["prev"])
12910 //this.addSeparator();
12911 this.add(this.beforePageText);
12912 this.field = Roo.get(this.addDom({
12917 cls: "x-grid-page-number"
12919 this.field.on("keydown", this.onPagingKeydown, this);
12920 this.field.on("focus", function(){this.dom.select();});
12921 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12922 this.field.setHeight(18);
12923 //this.addSeparator();
12924 this.next = this.addButton({
12925 tooltip: this.nextText,
12926 cls: "x-btn-icon x-grid-page-next",
12928 handler: this.onClick.createDelegate(this, ["next"])
12930 this.last = this.addButton({
12931 tooltip: this.lastText,
12932 cls: "x-btn-icon x-grid-page-last",
12934 handler: this.onClick.createDelegate(this, ["last"])
12936 //this.addSeparator();
12937 this.loading = this.addButton({
12938 tooltip: this.refreshText,
12939 cls: "x-btn-icon x-grid-loading",
12940 handler: this.onClick.createDelegate(this, ["refresh"])
12943 if(this.displayInfo){
12944 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12949 updateInfo : function(){
12950 if(this.displayEl){
12951 var count = this.ds.getCount();
12952 var msg = count == 0 ?
12956 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12958 this.displayEl.update(msg);
12963 onLoad : function(ds, r, o){
12964 this.cursor = o.params ? o.params.start : 0;
12965 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12967 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12968 this.field.dom.value = ap;
12969 this.first.setDisabled(ap == 1);
12970 this.prev.setDisabled(ap == 1);
12971 this.next.setDisabled(ap == ps);
12972 this.last.setDisabled(ap == ps);
12973 this.loading.enable();
12978 getPageData : function(){
12979 var total = this.ds.getTotalCount();
12982 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12983 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12988 onLoadError : function(){
12989 this.loading.enable();
12993 onPagingKeydown : function(e){
12994 var k = e.getKey();
12995 var d = this.getPageData();
12997 var v = this.field.dom.value, pageNum;
12998 if(!v || isNaN(pageNum = parseInt(v, 10))){
12999 this.field.dom.value = d.activePage;
13002 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13003 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13006 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))
13008 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13009 this.field.dom.value = pageNum;
13010 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13013 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13015 var v = this.field.dom.value, pageNum;
13016 var increment = (e.shiftKey) ? 10 : 1;
13017 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13019 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13020 this.field.dom.value = d.activePage;
13023 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13025 this.field.dom.value = parseInt(v, 10) + increment;
13026 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13027 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13034 beforeLoad : function(){
13036 this.loading.disable();
13041 onClick : function(which){
13045 ds.load({params:{start: 0, limit: this.pageSize}});
13048 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13051 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13054 var total = ds.getTotalCount();
13055 var extra = total % this.pageSize;
13056 var lastStart = extra ? (total - extra) : total-this.pageSize;
13057 ds.load({params:{start: lastStart, limit: this.pageSize}});
13060 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13066 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13067 * @param {Roo.data.Store} store The data store to unbind
13069 unbind : function(ds){
13070 ds.un("beforeload", this.beforeLoad, this);
13071 ds.un("load", this.onLoad, this);
13072 ds.un("loadexception", this.onLoadError, this);
13073 ds.un("remove", this.updateInfo, this);
13074 ds.un("add", this.updateInfo, this);
13075 this.ds = undefined;
13079 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13080 * @param {Roo.data.Store} store The data store to bind
13082 bind : function(ds){
13083 ds.on("beforeload", this.beforeLoad, this);
13084 ds.on("load", this.onLoad, this);
13085 ds.on("loadexception", this.onLoadError, this);
13086 ds.on("remove", this.updateInfo, this);
13087 ds.on("add", this.updateInfo, this);
13092 * Ext JS Library 1.1.1
13093 * Copyright(c) 2006-2007, Ext JS, LLC.
13095 * Originally Released Under LGPL - original licence link has changed is not relivant.
13098 * <script type="text/javascript">
13102 * @class Roo.Resizable
13103 * @extends Roo.util.Observable
13104 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13105 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13106 * 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
13107 * the element will be wrapped for you automatically.</p>
13108 * <p>Here is the list of valid resize handles:</p>
13111 ------ -------------------
13120 'hd' horizontal drag
13123 * <p>Here's an example showing the creation of a typical Resizable:</p>
13125 var resizer = new Roo.Resizable("element-id", {
13133 resizer.on("resize", myHandler);
13135 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13136 * resizer.east.setDisplayed(false);</p>
13137 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13138 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13139 * resize operation's new size (defaults to [0, 0])
13140 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13141 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13142 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13143 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13144 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13145 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13146 * @cfg {Number} width The width of the element in pixels (defaults to null)
13147 * @cfg {Number} height The height of the element in pixels (defaults to null)
13148 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13149 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13150 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13151 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13152 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13153 * in favor of the handles config option (defaults to false)
13154 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13155 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13156 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13157 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13158 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13159 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13160 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13161 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13162 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13163 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13164 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13166 * Create a new resizable component
13167 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13168 * @param {Object} config configuration options
13170 Roo.Resizable = function(el, config)
13172 this.el = Roo.get(el);
13174 if(config && config.wrap){
13175 config.resizeChild = this.el;
13176 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13177 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13178 this.el.setStyle("overflow", "hidden");
13179 this.el.setPositioning(config.resizeChild.getPositioning());
13180 config.resizeChild.clearPositioning();
13181 if(!config.width || !config.height){
13182 var csize = config.resizeChild.getSize();
13183 this.el.setSize(csize.width, csize.height);
13185 if(config.pinned && !config.adjustments){
13186 config.adjustments = "auto";
13190 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13191 this.proxy.unselectable();
13192 this.proxy.enableDisplayMode('block');
13194 Roo.apply(this, config);
13197 this.disableTrackOver = true;
13198 this.el.addClass("x-resizable-pinned");
13200 // if the element isn't positioned, make it relative
13201 var position = this.el.getStyle("position");
13202 if(position != "absolute" && position != "fixed"){
13203 this.el.setStyle("position", "relative");
13205 if(!this.handles){ // no handles passed, must be legacy style
13206 this.handles = 's,e,se';
13207 if(this.multiDirectional){
13208 this.handles += ',n,w';
13211 if(this.handles == "all"){
13212 this.handles = "n s e w ne nw se sw";
13214 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13215 var ps = Roo.Resizable.positions;
13216 for(var i = 0, len = hs.length; i < len; i++){
13217 if(hs[i] && ps[hs[i]]){
13218 var pos = ps[hs[i]];
13219 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13223 this.corner = this.southeast;
13225 // updateBox = the box can move..
13226 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13227 this.updateBox = true;
13230 this.activeHandle = null;
13232 if(this.resizeChild){
13233 if(typeof this.resizeChild == "boolean"){
13234 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13236 this.resizeChild = Roo.get(this.resizeChild, true);
13240 if(this.adjustments == "auto"){
13241 var rc = this.resizeChild;
13242 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13243 if(rc && (hw || hn)){
13244 rc.position("relative");
13245 rc.setLeft(hw ? hw.el.getWidth() : 0);
13246 rc.setTop(hn ? hn.el.getHeight() : 0);
13248 this.adjustments = [
13249 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13250 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13254 if(this.draggable){
13255 this.dd = this.dynamic ?
13256 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13257 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13263 * @event beforeresize
13264 * Fired before resize is allowed. Set enabled to false to cancel resize.
13265 * @param {Roo.Resizable} this
13266 * @param {Roo.EventObject} e The mousedown event
13268 "beforeresize" : true,
13271 * Fired after a resize.
13272 * @param {Roo.Resizable} this
13273 * @param {Number} width The new width
13274 * @param {Number} height The new height
13275 * @param {Roo.EventObject} e The mouseup event
13280 if(this.width !== null && this.height !== null){
13281 this.resizeTo(this.width, this.height);
13283 this.updateChildSize();
13286 this.el.dom.style.zoom = 1;
13288 Roo.Resizable.superclass.constructor.call(this);
13291 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13292 resizeChild : false,
13293 adjustments : [0, 0],
13303 multiDirectional : false,
13304 disableTrackOver : false,
13305 easing : 'easeOutStrong',
13306 widthIncrement : 0,
13307 heightIncrement : 0,
13311 preserveRatio : false,
13312 transparent: false,
13318 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13320 constrainTo: undefined,
13322 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13324 resizeRegion: undefined,
13328 * Perform a manual resize
13329 * @param {Number} width
13330 * @param {Number} height
13332 resizeTo : function(width, height){
13333 this.el.setSize(width, height);
13334 this.updateChildSize();
13335 this.fireEvent("resize", this, width, height, null);
13339 startSizing : function(e, handle){
13340 this.fireEvent("beforeresize", this, e);
13341 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13344 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13345 this.overlay.unselectable();
13346 this.overlay.enableDisplayMode("block");
13347 this.overlay.on("mousemove", this.onMouseMove, this);
13348 this.overlay.on("mouseup", this.onMouseUp, this);
13350 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13352 this.resizing = true;
13353 this.startBox = this.el.getBox();
13354 this.startPoint = e.getXY();
13355 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13356 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13358 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13359 this.overlay.show();
13361 if(this.constrainTo) {
13362 var ct = Roo.get(this.constrainTo);
13363 this.resizeRegion = ct.getRegion().adjust(
13364 ct.getFrameWidth('t'),
13365 ct.getFrameWidth('l'),
13366 -ct.getFrameWidth('b'),
13367 -ct.getFrameWidth('r')
13371 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13373 this.proxy.setBox(this.startBox);
13375 this.proxy.setStyle('visibility', 'visible');
13381 onMouseDown : function(handle, e){
13384 this.activeHandle = handle;
13385 this.startSizing(e, handle);
13390 onMouseUp : function(e){
13391 var size = this.resizeElement();
13392 this.resizing = false;
13394 this.overlay.hide();
13396 this.fireEvent("resize", this, size.width, size.height, e);
13400 updateChildSize : function(){
13401 if(this.resizeChild){
13403 var child = this.resizeChild;
13404 var adj = this.adjustments;
13405 if(el.dom.offsetWidth){
13406 var b = el.getSize(true);
13407 child.setSize(b.width+adj[0], b.height+adj[1]);
13409 // Second call here for IE
13410 // The first call enables instant resizing and
13411 // the second call corrects scroll bars if they
13414 setTimeout(function(){
13415 if(el.dom.offsetWidth){
13416 var b = el.getSize(true);
13417 child.setSize(b.width+adj[0], b.height+adj[1]);
13425 snap : function(value, inc, min){
13426 if(!inc || !value) return value;
13427 var newValue = value;
13428 var m = value % inc;
13431 newValue = value + (inc-m);
13433 newValue = value - m;
13436 return Math.max(min, newValue);
13440 resizeElement : function(){
13441 var box = this.proxy.getBox();
13442 if(this.updateBox){
13443 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13445 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13447 this.updateChildSize();
13455 constrain : function(v, diff, m, mx){
13458 }else if(v - diff > mx){
13465 onMouseMove : function(e){
13467 try{// try catch so if something goes wrong the user doesn't get hung
13469 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13473 //var curXY = this.startPoint;
13474 var curSize = this.curSize || this.startBox;
13475 var x = this.startBox.x, y = this.startBox.y;
13476 var ox = x, oy = y;
13477 var w = curSize.width, h = curSize.height;
13478 var ow = w, oh = h;
13479 var mw = this.minWidth, mh = this.minHeight;
13480 var mxw = this.maxWidth, mxh = this.maxHeight;
13481 var wi = this.widthIncrement;
13482 var hi = this.heightIncrement;
13484 var eventXY = e.getXY();
13485 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13486 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13488 var pos = this.activeHandle.position;
13493 w = Math.min(Math.max(mw, w), mxw);
13498 h = Math.min(Math.max(mh, h), mxh);
13503 w = Math.min(Math.max(mw, w), mxw);
13504 h = Math.min(Math.max(mh, h), mxh);
13507 diffY = this.constrain(h, diffY, mh, mxh);
13514 var adiffX = Math.abs(diffX);
13515 var sub = (adiffX % wi); // how much
13516 if (sub > (wi/2)) { // far enough to snap
13517 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13519 // remove difference..
13520 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13524 x = Math.max(this.minX, x);
13527 diffX = this.constrain(w, diffX, mw, mxw);
13533 w = Math.min(Math.max(mw, w), mxw);
13534 diffY = this.constrain(h, diffY, mh, mxh);
13539 diffX = this.constrain(w, diffX, mw, mxw);
13540 diffY = this.constrain(h, diffY, mh, mxh);
13547 diffX = this.constrain(w, diffX, mw, mxw);
13549 h = Math.min(Math.max(mh, h), mxh);
13555 var sw = this.snap(w, wi, mw);
13556 var sh = this.snap(h, hi, mh);
13557 if(sw != w || sh != h){
13580 if(this.preserveRatio){
13585 h = Math.min(Math.max(mh, h), mxh);
13590 w = Math.min(Math.max(mw, w), mxw);
13595 w = Math.min(Math.max(mw, w), mxw);
13601 w = Math.min(Math.max(mw, w), mxw);
13607 h = Math.min(Math.max(mh, h), mxh);
13615 h = Math.min(Math.max(mh, h), mxh);
13625 h = Math.min(Math.max(mh, h), mxh);
13633 if (pos == 'hdrag') {
13636 this.proxy.setBounds(x, y, w, h);
13638 this.resizeElement();
13645 handleOver : function(){
13647 this.el.addClass("x-resizable-over");
13652 handleOut : function(){
13653 if(!this.resizing){
13654 this.el.removeClass("x-resizable-over");
13659 * Returns the element this component is bound to.
13660 * @return {Roo.Element}
13662 getEl : function(){
13667 * Returns the resizeChild element (or null).
13668 * @return {Roo.Element}
13670 getResizeChild : function(){
13671 return this.resizeChild;
13675 * Destroys this resizable. If the element was wrapped and
13676 * removeEl is not true then the element remains.
13677 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13679 destroy : function(removeEl){
13680 this.proxy.remove();
13682 this.overlay.removeAllListeners();
13683 this.overlay.remove();
13685 var ps = Roo.Resizable.positions;
13687 if(typeof ps[k] != "function" && this[ps[k]]){
13688 var h = this[ps[k]];
13689 h.el.removeAllListeners();
13694 this.el.update("");
13701 // hash to map config positions to true positions
13702 Roo.Resizable.positions = {
13703 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13708 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13710 // only initialize the template if resizable is used
13711 var tpl = Roo.DomHelper.createTemplate(
13712 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13715 Roo.Resizable.Handle.prototype.tpl = tpl;
13717 this.position = pos;
13719 // show north drag fro topdra
13720 var handlepos = pos == 'hdrag' ? 'north' : pos;
13722 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13723 if (pos == 'hdrag') {
13724 this.el.setStyle('cursor', 'pointer');
13726 this.el.unselectable();
13728 this.el.setOpacity(0);
13730 this.el.on("mousedown", this.onMouseDown, this);
13731 if(!disableTrackOver){
13732 this.el.on("mouseover", this.onMouseOver, this);
13733 this.el.on("mouseout", this.onMouseOut, this);
13738 Roo.Resizable.Handle.prototype = {
13739 afterResize : function(rz){
13743 onMouseDown : function(e){
13744 this.rz.onMouseDown(this, e);
13747 onMouseOver : function(e){
13748 this.rz.handleOver(this, e);
13751 onMouseOut : function(e){
13752 this.rz.handleOut(this, e);
13756 * Ext JS Library 1.1.1
13757 * Copyright(c) 2006-2007, Ext JS, LLC.
13759 * Originally Released Under LGPL - original licence link has changed is not relivant.
13762 * <script type="text/javascript">
13766 * @class Roo.Editor
13767 * @extends Roo.Component
13768 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13770 * Create a new Editor
13771 * @param {Roo.form.Field} field The Field object (or descendant)
13772 * @param {Object} config The config object
13774 Roo.Editor = function(field, config){
13775 Roo.Editor.superclass.constructor.call(this, config);
13776 this.field = field;
13779 * @event beforestartedit
13780 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13781 * false from the handler of this event.
13782 * @param {Editor} this
13783 * @param {Roo.Element} boundEl The underlying element bound to this editor
13784 * @param {Mixed} value The field value being set
13786 "beforestartedit" : true,
13789 * Fires when this editor is displayed
13790 * @param {Roo.Element} boundEl The underlying element bound to this editor
13791 * @param {Mixed} value The starting field value
13793 "startedit" : true,
13795 * @event beforecomplete
13796 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13797 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13798 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13799 * event will not fire since no edit actually occurred.
13800 * @param {Editor} this
13801 * @param {Mixed} value The current field value
13802 * @param {Mixed} startValue The original field value
13804 "beforecomplete" : true,
13807 * Fires after editing is complete and any changed value has been written to the underlying field.
13808 * @param {Editor} this
13809 * @param {Mixed} value The current field value
13810 * @param {Mixed} startValue The original field value
13814 * @event specialkey
13815 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13816 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13817 * @param {Roo.form.Field} this
13818 * @param {Roo.EventObject} e The event object
13820 "specialkey" : true
13824 Roo.extend(Roo.Editor, Roo.Component, {
13826 * @cfg {Boolean/String} autosize
13827 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13828 * or "height" to adopt the height only (defaults to false)
13831 * @cfg {Boolean} revertInvalid
13832 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13833 * validation fails (defaults to true)
13836 * @cfg {Boolean} ignoreNoChange
13837 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13838 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13839 * will never be ignored.
13842 * @cfg {Boolean} hideEl
13843 * False to keep the bound element visible while the editor is displayed (defaults to true)
13846 * @cfg {Mixed} value
13847 * The data value of the underlying field (defaults to "")
13851 * @cfg {String} alignment
13852 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13856 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13857 * for bottom-right shadow (defaults to "frame")
13861 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13865 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13867 completeOnEnter : false,
13869 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13871 cancelOnEsc : false,
13873 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13878 onRender : function(ct, position){
13879 this.el = new Roo.Layer({
13880 shadow: this.shadow,
13886 constrain: this.constrain
13888 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13889 if(this.field.msgTarget != 'title'){
13890 this.field.msgTarget = 'qtip';
13892 this.field.render(this.el);
13894 this.field.el.dom.setAttribute('autocomplete', 'off');
13896 this.field.on("specialkey", this.onSpecialKey, this);
13897 if(this.swallowKeys){
13898 this.field.el.swallowEvent(['keydown','keypress']);
13901 this.field.on("blur", this.onBlur, this);
13902 if(this.field.grow){
13903 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13907 onSpecialKey : function(field, e){
13908 //Roo.log('editor onSpecialKey');
13909 if(this.completeOnEnter && e.getKey() == e.ENTER){
13911 this.completeEdit();
13912 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13915 this.fireEvent('specialkey', field, e);
13920 * Starts the editing process and shows the editor.
13921 * @param {String/HTMLElement/Element} el The element to edit
13922 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13923 * to the innerHTML of el.
13925 startEdit : function(el, value){
13927 this.completeEdit();
13929 this.boundEl = Roo.get(el);
13930 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13931 if(!this.rendered){
13932 this.render(this.parentEl || document.body);
13934 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13937 this.startValue = v;
13938 this.field.setValue(v);
13940 var sz = this.boundEl.getSize();
13941 switch(this.autoSize){
13943 this.setSize(sz.width, "");
13946 this.setSize("", sz.height);
13949 this.setSize(sz.width, sz.height);
13952 this.el.alignTo(this.boundEl, this.alignment);
13953 this.editing = true;
13955 Roo.QuickTips.disable();
13961 * Sets the height and width of this editor.
13962 * @param {Number} width The new width
13963 * @param {Number} height The new height
13965 setSize : function(w, h){
13966 this.field.setSize(w, h);
13973 * Realigns the editor to the bound field based on the current alignment config value.
13975 realign : function(){
13976 this.el.alignTo(this.boundEl, this.alignment);
13980 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13981 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13983 completeEdit : function(remainVisible){
13987 var v = this.getValue();
13988 if(this.revertInvalid !== false && !this.field.isValid()){
13989 v = this.startValue;
13990 this.cancelEdit(true);
13992 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13993 this.editing = false;
13997 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13998 this.editing = false;
13999 if(this.updateEl && this.boundEl){
14000 this.boundEl.update(v);
14002 if(remainVisible !== true){
14005 this.fireEvent("complete", this, v, this.startValue);
14010 onShow : function(){
14012 if(this.hideEl !== false){
14013 this.boundEl.hide();
14016 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14017 this.fixIEFocus = true;
14018 this.deferredFocus.defer(50, this);
14020 this.field.focus();
14022 this.fireEvent("startedit", this.boundEl, this.startValue);
14025 deferredFocus : function(){
14027 this.field.focus();
14032 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14033 * reverted to the original starting value.
14034 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14035 * cancel (defaults to false)
14037 cancelEdit : function(remainVisible){
14039 this.setValue(this.startValue);
14040 if(remainVisible !== true){
14047 onBlur : function(){
14048 if(this.allowBlur !== true && this.editing){
14049 this.completeEdit();
14054 onHide : function(){
14056 this.completeEdit();
14060 if(this.field.collapse){
14061 this.field.collapse();
14064 if(this.hideEl !== false){
14065 this.boundEl.show();
14068 Roo.QuickTips.enable();
14073 * Sets the data value of the editor
14074 * @param {Mixed} value Any valid value supported by the underlying field
14076 setValue : function(v){
14077 this.field.setValue(v);
14081 * Gets the data value of the editor
14082 * @return {Mixed} The data value
14084 getValue : function(){
14085 return this.field.getValue();
14089 * Ext JS Library 1.1.1
14090 * Copyright(c) 2006-2007, Ext JS, LLC.
14092 * Originally Released Under LGPL - original licence link has changed is not relivant.
14095 * <script type="text/javascript">
14099 * @class Roo.BasicDialog
14100 * @extends Roo.util.Observable
14101 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14103 var dlg = new Roo.BasicDialog("my-dlg", {
14112 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14113 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14114 dlg.addButton('Cancel', dlg.hide, dlg);
14117 <b>A Dialog should always be a direct child of the body element.</b>
14118 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14119 * @cfg {String} title Default text to display in the title bar (defaults to null)
14120 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14121 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14122 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14123 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14124 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14125 * (defaults to null with no animation)
14126 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14127 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14128 * property for valid values (defaults to 'all')
14129 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14130 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14131 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14132 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14133 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14134 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14135 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14136 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14137 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14138 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14139 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14140 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14141 * draggable = true (defaults to false)
14142 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14143 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14144 * shadow (defaults to false)
14145 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14146 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14147 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14148 * @cfg {Array} buttons Array of buttons
14149 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14151 * Create a new BasicDialog.
14152 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14153 * @param {Object} config Configuration options
14155 Roo.BasicDialog = function(el, config){
14156 this.el = Roo.get(el);
14157 var dh = Roo.DomHelper;
14158 if(!this.el && config && config.autoCreate){
14159 if(typeof config.autoCreate == "object"){
14160 if(!config.autoCreate.id){
14161 config.autoCreate.id = el;
14163 this.el = dh.append(document.body,
14164 config.autoCreate, true);
14166 this.el = dh.append(document.body,
14167 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14171 el.setDisplayed(true);
14172 el.hide = this.hideAction;
14174 el.addClass("x-dlg");
14176 Roo.apply(this, config);
14178 this.proxy = el.createProxy("x-dlg-proxy");
14179 this.proxy.hide = this.hideAction;
14180 this.proxy.setOpacity(.5);
14184 el.setWidth(config.width);
14187 el.setHeight(config.height);
14189 this.size = el.getSize();
14190 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14191 this.xy = [config.x,config.y];
14193 this.xy = el.getCenterXY(true);
14195 /** The header element @type Roo.Element */
14196 this.header = el.child("> .x-dlg-hd");
14197 /** The body element @type Roo.Element */
14198 this.body = el.child("> .x-dlg-bd");
14199 /** The footer element @type Roo.Element */
14200 this.footer = el.child("> .x-dlg-ft");
14203 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14206 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14209 this.header.unselectable();
14211 this.header.update(this.title);
14213 // this element allows the dialog to be focused for keyboard event
14214 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14215 this.focusEl.swallowEvent("click", true);
14217 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14219 // wrap the body and footer for special rendering
14220 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14222 this.bwrap.dom.appendChild(this.footer.dom);
14225 this.bg = this.el.createChild({
14226 tag: "div", cls:"x-dlg-bg",
14227 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14229 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14232 if(this.autoScroll !== false && !this.autoTabs){
14233 this.body.setStyle("overflow", "auto");
14236 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14238 if(this.closable !== false){
14239 this.el.addClass("x-dlg-closable");
14240 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14241 this.close.on("click", this.closeClick, this);
14242 this.close.addClassOnOver("x-dlg-close-over");
14244 if(this.collapsible !== false){
14245 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14246 this.collapseBtn.on("click", this.collapseClick, this);
14247 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14248 this.header.on("dblclick", this.collapseClick, this);
14250 if(this.resizable !== false){
14251 this.el.addClass("x-dlg-resizable");
14252 this.resizer = new Roo.Resizable(el, {
14253 minWidth: this.minWidth || 80,
14254 minHeight:this.minHeight || 80,
14255 handles: this.resizeHandles || "all",
14258 this.resizer.on("beforeresize", this.beforeResize, this);
14259 this.resizer.on("resize", this.onResize, this);
14261 if(this.draggable !== false){
14262 el.addClass("x-dlg-draggable");
14263 if (!this.proxyDrag) {
14264 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14267 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14269 dd.setHandleElId(this.header.id);
14270 dd.endDrag = this.endMove.createDelegate(this);
14271 dd.startDrag = this.startMove.createDelegate(this);
14272 dd.onDrag = this.onDrag.createDelegate(this);
14277 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14278 this.mask.enableDisplayMode("block");
14280 this.el.addClass("x-dlg-modal");
14283 this.shadow = new Roo.Shadow({
14284 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14285 offset : this.shadowOffset
14288 this.shadowOffset = 0;
14290 if(Roo.useShims && this.shim !== false){
14291 this.shim = this.el.createShim();
14292 this.shim.hide = this.hideAction;
14300 if (this.buttons) {
14301 var bts= this.buttons;
14303 Roo.each(bts, function(b) {
14312 * Fires when a key is pressed
14313 * @param {Roo.BasicDialog} this
14314 * @param {Roo.EventObject} e
14319 * Fires when this dialog is moved by the user.
14320 * @param {Roo.BasicDialog} this
14321 * @param {Number} x The new page X
14322 * @param {Number} y The new page Y
14327 * Fires when this dialog is resized by the user.
14328 * @param {Roo.BasicDialog} this
14329 * @param {Number} width The new width
14330 * @param {Number} height The new height
14334 * @event beforehide
14335 * Fires before this dialog is hidden.
14336 * @param {Roo.BasicDialog} this
14338 "beforehide" : true,
14341 * Fires when this dialog is hidden.
14342 * @param {Roo.BasicDialog} this
14346 * @event beforeshow
14347 * Fires before this dialog is shown.
14348 * @param {Roo.BasicDialog} this
14350 "beforeshow" : true,
14353 * Fires when this dialog is shown.
14354 * @param {Roo.BasicDialog} this
14358 el.on("keydown", this.onKeyDown, this);
14359 el.on("mousedown", this.toFront, this);
14360 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14362 Roo.DialogManager.register(this);
14363 Roo.BasicDialog.superclass.constructor.call(this);
14366 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14367 shadowOffset: Roo.isIE ? 6 : 5,
14370 minButtonWidth: 75,
14371 defaultButton: null,
14372 buttonAlign: "right",
14377 * Sets the dialog title text
14378 * @param {String} text The title text to display
14379 * @return {Roo.BasicDialog} this
14381 setTitle : function(text){
14382 this.header.update(text);
14387 closeClick : function(){
14392 collapseClick : function(){
14393 this[this.collapsed ? "expand" : "collapse"]();
14397 * Collapses the dialog to its minimized state (only the title bar is visible).
14398 * Equivalent to the user clicking the collapse dialog button.
14400 collapse : function(){
14401 if(!this.collapsed){
14402 this.collapsed = true;
14403 this.el.addClass("x-dlg-collapsed");
14404 this.restoreHeight = this.el.getHeight();
14405 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14410 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14411 * clicking the expand dialog button.
14413 expand : function(){
14414 if(this.collapsed){
14415 this.collapsed = false;
14416 this.el.removeClass("x-dlg-collapsed");
14417 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14422 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14423 * @return {Roo.TabPanel} The tabs component
14425 initTabs : function(){
14426 var tabs = this.getTabs();
14427 while(tabs.getTab(0)){
14430 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14432 tabs.addTab(Roo.id(dom), dom.title);
14440 beforeResize : function(){
14441 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14445 onResize : function(){
14446 this.refreshSize();
14447 this.syncBodyHeight();
14448 this.adjustAssets();
14450 this.fireEvent("resize", this, this.size.width, this.size.height);
14454 onKeyDown : function(e){
14455 if(this.isVisible()){
14456 this.fireEvent("keydown", this, e);
14461 * Resizes the dialog.
14462 * @param {Number} width
14463 * @param {Number} height
14464 * @return {Roo.BasicDialog} this
14466 resizeTo : function(width, height){
14467 this.el.setSize(width, height);
14468 this.size = {width: width, height: height};
14469 this.syncBodyHeight();
14470 if(this.fixedcenter){
14473 if(this.isVisible()){
14474 this.constrainXY();
14475 this.adjustAssets();
14477 this.fireEvent("resize", this, width, height);
14483 * Resizes the dialog to fit the specified content size.
14484 * @param {Number} width
14485 * @param {Number} height
14486 * @return {Roo.BasicDialog} this
14488 setContentSize : function(w, h){
14489 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14490 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14491 //if(!this.el.isBorderBox()){
14492 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14493 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14496 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14497 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14499 this.resizeTo(w, h);
14504 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14505 * executed in response to a particular key being pressed while the dialog is active.
14506 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14507 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14508 * @param {Function} fn The function to call
14509 * @param {Object} scope (optional) The scope of the function
14510 * @return {Roo.BasicDialog} this
14512 addKeyListener : function(key, fn, scope){
14513 var keyCode, shift, ctrl, alt;
14514 if(typeof key == "object" && !(key instanceof Array)){
14515 keyCode = key["key"];
14516 shift = key["shift"];
14517 ctrl = key["ctrl"];
14522 var handler = function(dlg, e){
14523 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14524 var k = e.getKey();
14525 if(keyCode instanceof Array){
14526 for(var i = 0, len = keyCode.length; i < len; i++){
14527 if(keyCode[i] == k){
14528 fn.call(scope || window, dlg, k, e);
14534 fn.call(scope || window, dlg, k, e);
14539 this.on("keydown", handler);
14544 * Returns the TabPanel component (creates it if it doesn't exist).
14545 * Note: If you wish to simply check for the existence of tabs without creating them,
14546 * check for a null 'tabs' property.
14547 * @return {Roo.TabPanel} The tabs component
14549 getTabs : function(){
14551 this.el.addClass("x-dlg-auto-tabs");
14552 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14553 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14559 * Adds a button to the footer section of the dialog.
14560 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14561 * object or a valid Roo.DomHelper element config
14562 * @param {Function} handler The function called when the button is clicked
14563 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14564 * @return {Roo.Button} The new button
14566 addButton : function(config, handler, scope){
14567 var dh = Roo.DomHelper;
14569 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14571 if(!this.btnContainer){
14572 var tb = this.footer.createChild({
14574 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14575 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14577 this.btnContainer = tb.firstChild.firstChild.firstChild;
14582 minWidth: this.minButtonWidth,
14585 if(typeof config == "string"){
14586 bconfig.text = config;
14589 bconfig.dhconfig = config;
14591 Roo.apply(bconfig, config);
14595 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14596 bconfig.position = Math.max(0, bconfig.position);
14597 fc = this.btnContainer.childNodes[bconfig.position];
14600 var btn = new Roo.Button(
14602 this.btnContainer.insertBefore(document.createElement("td"),fc)
14603 : this.btnContainer.appendChild(document.createElement("td")),
14604 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14607 this.syncBodyHeight();
14610 * Array of all the buttons that have been added to this dialog via addButton
14615 this.buttons.push(btn);
14620 * Sets the default button to be focused when the dialog is displayed.
14621 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14622 * @return {Roo.BasicDialog} this
14624 setDefaultButton : function(btn){
14625 this.defaultButton = btn;
14630 getHeaderFooterHeight : function(safe){
14633 height += this.header.getHeight();
14636 var fm = this.footer.getMargins();
14637 height += (this.footer.getHeight()+fm.top+fm.bottom);
14639 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14640 height += this.centerBg.getPadding("tb");
14645 syncBodyHeight : function(){
14646 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14647 var height = this.size.height - this.getHeaderFooterHeight(false);
14648 bd.setHeight(height-bd.getMargins("tb"));
14649 var hh = this.header.getHeight();
14650 var h = this.size.height-hh;
14652 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14653 bw.setHeight(h-cb.getPadding("tb"));
14654 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14655 bd.setWidth(bw.getWidth(true));
14657 this.tabs.syncHeight();
14659 this.tabs.el.repaint();
14665 * Restores the previous state of the dialog if Roo.state is configured.
14666 * @return {Roo.BasicDialog} this
14668 restoreState : function(){
14669 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14670 if(box && box.width){
14671 this.xy = [box.x, box.y];
14672 this.resizeTo(box.width, box.height);
14678 beforeShow : function(){
14680 if(this.fixedcenter){
14681 this.xy = this.el.getCenterXY(true);
14684 Roo.get(document.body).addClass("x-body-masked");
14685 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14688 this.constrainXY();
14692 animShow : function(){
14693 var b = Roo.get(this.animateTarget).getBox();
14694 this.proxy.setSize(b.width, b.height);
14695 this.proxy.setLocation(b.x, b.y);
14697 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14698 true, .35, this.showEl.createDelegate(this));
14702 * Shows the dialog.
14703 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14704 * @return {Roo.BasicDialog} this
14706 show : function(animateTarget){
14707 if (this.fireEvent("beforeshow", this) === false){
14710 if(this.syncHeightBeforeShow){
14711 this.syncBodyHeight();
14712 }else if(this.firstShow){
14713 this.firstShow = false;
14714 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14716 this.animateTarget = animateTarget || this.animateTarget;
14717 if(!this.el.isVisible()){
14719 if(this.animateTarget && Roo.get(this.animateTarget)){
14729 showEl : function(){
14731 this.el.setXY(this.xy);
14733 this.adjustAssets(true);
14736 // IE peekaboo bug - fix found by Dave Fenwick
14740 this.fireEvent("show", this);
14744 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14745 * dialog itself will receive focus.
14747 focus : function(){
14748 if(this.defaultButton){
14749 this.defaultButton.focus();
14751 this.focusEl.focus();
14756 constrainXY : function(){
14757 if(this.constraintoviewport !== false){
14758 if(!this.viewSize){
14759 if(this.container){
14760 var s = this.container.getSize();
14761 this.viewSize = [s.width, s.height];
14763 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14766 var s = Roo.get(this.container||document).getScroll();
14768 var x = this.xy[0], y = this.xy[1];
14769 var w = this.size.width, h = this.size.height;
14770 var vw = this.viewSize[0], vh = this.viewSize[1];
14771 // only move it if it needs it
14773 // first validate right/bottom
14774 if(x + w > vw+s.left){
14778 if(y + h > vh+s.top){
14782 // then make sure top/left isn't negative
14794 if(this.isVisible()){
14795 this.el.setLocation(x, y);
14796 this.adjustAssets();
14803 onDrag : function(){
14804 if(!this.proxyDrag){
14805 this.xy = this.el.getXY();
14806 this.adjustAssets();
14811 adjustAssets : function(doShow){
14812 var x = this.xy[0], y = this.xy[1];
14813 var w = this.size.width, h = this.size.height;
14814 if(doShow === true){
14816 this.shadow.show(this.el);
14822 if(this.shadow && this.shadow.isVisible()){
14823 this.shadow.show(this.el);
14825 if(this.shim && this.shim.isVisible()){
14826 this.shim.setBounds(x, y, w, h);
14831 adjustViewport : function(w, h){
14833 w = Roo.lib.Dom.getViewWidth();
14834 h = Roo.lib.Dom.getViewHeight();
14837 this.viewSize = [w, h];
14838 if(this.modal && this.mask.isVisible()){
14839 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14840 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14842 if(this.isVisible()){
14843 this.constrainXY();
14848 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14849 * shadow, proxy, mask, etc.) Also removes all event listeners.
14850 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14852 destroy : function(removeEl){
14853 if(this.isVisible()){
14854 this.animateTarget = null;
14857 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14859 this.tabs.destroy(removeEl);
14872 for(var i = 0, len = this.buttons.length; i < len; i++){
14873 this.buttons[i].destroy();
14876 this.el.removeAllListeners();
14877 if(removeEl === true){
14878 this.el.update("");
14881 Roo.DialogManager.unregister(this);
14885 startMove : function(){
14886 if(this.proxyDrag){
14889 if(this.constraintoviewport !== false){
14890 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14895 endMove : function(){
14896 if(!this.proxyDrag){
14897 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14899 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14902 this.refreshSize();
14903 this.adjustAssets();
14905 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14909 * Brings this dialog to the front of any other visible dialogs
14910 * @return {Roo.BasicDialog} this
14912 toFront : function(){
14913 Roo.DialogManager.bringToFront(this);
14918 * Sends this dialog to the back (under) of any other visible dialogs
14919 * @return {Roo.BasicDialog} this
14921 toBack : function(){
14922 Roo.DialogManager.sendToBack(this);
14927 * Centers this dialog in the viewport
14928 * @return {Roo.BasicDialog} this
14930 center : function(){
14931 var xy = this.el.getCenterXY(true);
14932 this.moveTo(xy[0], xy[1]);
14937 * Moves the dialog's top-left corner to the specified point
14938 * @param {Number} x
14939 * @param {Number} y
14940 * @return {Roo.BasicDialog} this
14942 moveTo : function(x, y){
14944 if(this.isVisible()){
14945 this.el.setXY(this.xy);
14946 this.adjustAssets();
14952 * Aligns the dialog to the specified element
14953 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14954 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14955 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14956 * @return {Roo.BasicDialog} this
14958 alignTo : function(element, position, offsets){
14959 this.xy = this.el.getAlignToXY(element, position, offsets);
14960 if(this.isVisible()){
14961 this.el.setXY(this.xy);
14962 this.adjustAssets();
14968 * Anchors an element to another element and realigns it when the window is resized.
14969 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14970 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14971 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14972 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14973 * is a number, it is used as the buffer delay (defaults to 50ms).
14974 * @return {Roo.BasicDialog} this
14976 anchorTo : function(el, alignment, offsets, monitorScroll){
14977 var action = function(){
14978 this.alignTo(el, alignment, offsets);
14980 Roo.EventManager.onWindowResize(action, this);
14981 var tm = typeof monitorScroll;
14982 if(tm != 'undefined'){
14983 Roo.EventManager.on(window, 'scroll', action, this,
14984 {buffer: tm == 'number' ? monitorScroll : 50});
14991 * Returns true if the dialog is visible
14992 * @return {Boolean}
14994 isVisible : function(){
14995 return this.el.isVisible();
14999 animHide : function(callback){
15000 var b = Roo.get(this.animateTarget).getBox();
15002 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15004 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15005 this.hideEl.createDelegate(this, [callback]));
15009 * Hides the dialog.
15010 * @param {Function} callback (optional) Function to call when the dialog is hidden
15011 * @return {Roo.BasicDialog} this
15013 hide : function(callback){
15014 if (this.fireEvent("beforehide", this) === false){
15018 this.shadow.hide();
15023 // sometimes animateTarget seems to get set.. causing problems...
15024 // this just double checks..
15025 if(this.animateTarget && Roo.get(this.animateTarget)) {
15026 this.animHide(callback);
15029 this.hideEl(callback);
15035 hideEl : function(callback){
15039 Roo.get(document.body).removeClass("x-body-masked");
15041 this.fireEvent("hide", this);
15042 if(typeof callback == "function"){
15048 hideAction : function(){
15049 this.setLeft("-10000px");
15050 this.setTop("-10000px");
15051 this.setStyle("visibility", "hidden");
15055 refreshSize : function(){
15056 this.size = this.el.getSize();
15057 this.xy = this.el.getXY();
15058 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15062 // z-index is managed by the DialogManager and may be overwritten at any time
15063 setZIndex : function(index){
15065 this.mask.setStyle("z-index", index);
15068 this.shim.setStyle("z-index", ++index);
15071 this.shadow.setZIndex(++index);
15073 this.el.setStyle("z-index", ++index);
15075 this.proxy.setStyle("z-index", ++index);
15078 this.resizer.proxy.setStyle("z-index", ++index);
15081 this.lastZIndex = index;
15085 * Returns the element for this dialog
15086 * @return {Roo.Element} The underlying dialog Element
15088 getEl : function(){
15094 * @class Roo.DialogManager
15095 * Provides global access to BasicDialogs that have been created and
15096 * support for z-indexing (layering) multiple open dialogs.
15098 Roo.DialogManager = function(){
15100 var accessList = [];
15104 var sortDialogs = function(d1, d2){
15105 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15109 var orderDialogs = function(){
15110 accessList.sort(sortDialogs);
15111 var seed = Roo.DialogManager.zseed;
15112 for(var i = 0, len = accessList.length; i < len; i++){
15113 var dlg = accessList[i];
15115 dlg.setZIndex(seed + (i*10));
15122 * The starting z-index for BasicDialogs (defaults to 9000)
15123 * @type Number The z-index value
15128 register : function(dlg){
15129 list[dlg.id] = dlg;
15130 accessList.push(dlg);
15134 unregister : function(dlg){
15135 delete list[dlg.id];
15138 if(!accessList.indexOf){
15139 for( i = 0, len = accessList.length; i < len; i++){
15140 if(accessList[i] == dlg){
15141 accessList.splice(i, 1);
15146 i = accessList.indexOf(dlg);
15148 accessList.splice(i, 1);
15154 * Gets a registered dialog by id
15155 * @param {String/Object} id The id of the dialog or a dialog
15156 * @return {Roo.BasicDialog} this
15158 get : function(id){
15159 return typeof id == "object" ? id : list[id];
15163 * Brings the specified dialog to the front
15164 * @param {String/Object} dlg The id of the dialog or a dialog
15165 * @return {Roo.BasicDialog} this
15167 bringToFront : function(dlg){
15168 dlg = this.get(dlg);
15171 dlg._lastAccess = new Date().getTime();
15178 * Sends the specified dialog to the back
15179 * @param {String/Object} dlg The id of the dialog or a dialog
15180 * @return {Roo.BasicDialog} this
15182 sendToBack : function(dlg){
15183 dlg = this.get(dlg);
15184 dlg._lastAccess = -(new Date().getTime());
15190 * Hides all dialogs
15192 hideAll : function(){
15193 for(var id in list){
15194 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15203 * @class Roo.LayoutDialog
15204 * @extends Roo.BasicDialog
15205 * Dialog which provides adjustments for working with a layout in a Dialog.
15206 * Add your necessary layout config options to the dialog's config.<br>
15207 * Example usage (including a nested layout):
15210 dialog = new Roo.LayoutDialog("download-dlg", {
15219 // layout config merges with the dialog config
15221 tabPosition: "top",
15222 alwaysShowTabs: true
15225 dialog.addKeyListener(27, dialog.hide, dialog);
15226 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15227 dialog.addButton("Build It!", this.getDownload, this);
15229 // we can even add nested layouts
15230 var innerLayout = new Roo.BorderLayout("dl-inner", {
15240 innerLayout.beginUpdate();
15241 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15242 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15243 innerLayout.endUpdate(true);
15245 var layout = dialog.getLayout();
15246 layout.beginUpdate();
15247 layout.add("center", new Roo.ContentPanel("standard-panel",
15248 {title: "Download the Source", fitToFrame:true}));
15249 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15250 {title: "Build your own roo.js"}));
15251 layout.getRegion("center").showPanel(sp);
15252 layout.endUpdate();
15256 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15257 * @param {Object} config configuration options
15259 Roo.LayoutDialog = function(el, cfg){
15262 if (typeof(cfg) == 'undefined') {
15263 config = Roo.apply({}, el);
15264 // not sure why we use documentElement here.. - it should always be body.
15265 // IE7 borks horribly if we use documentElement.
15266 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15267 //config.autoCreate = true;
15271 config.autoTabs = false;
15272 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15273 this.body.setStyle({overflow:"hidden", position:"relative"});
15274 this.layout = new Roo.BorderLayout(this.body.dom, config);
15275 this.layout.monitorWindowResize = false;
15276 this.el.addClass("x-dlg-auto-layout");
15277 // fix case when center region overwrites center function
15278 this.center = Roo.BasicDialog.prototype.center;
15279 this.on("show", this.layout.layout, this.layout, true);
15280 if (config.items) {
15281 var xitems = config.items;
15282 delete config.items;
15283 Roo.each(xitems, this.addxtype, this);
15288 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15290 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15293 endUpdate : function(){
15294 this.layout.endUpdate();
15298 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15301 beginUpdate : function(){
15302 this.layout.beginUpdate();
15306 * Get the BorderLayout for this dialog
15307 * @return {Roo.BorderLayout}
15309 getLayout : function(){
15310 return this.layout;
15313 showEl : function(){
15314 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15316 this.layout.layout();
15321 // Use the syncHeightBeforeShow config option to control this automatically
15322 syncBodyHeight : function(){
15323 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15324 if(this.layout){this.layout.layout();}
15328 * Add an xtype element (actually adds to the layout.)
15329 * @return {Object} xdata xtype object data.
15332 addxtype : function(c) {
15333 return this.layout.addxtype(c);
15337 * Ext JS Library 1.1.1
15338 * Copyright(c) 2006-2007, Ext JS, LLC.
15340 * Originally Released Under LGPL - original licence link has changed is not relivant.
15343 * <script type="text/javascript">
15347 * @class Roo.MessageBox
15348 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15352 Roo.Msg.alert('Status', 'Changes saved successfully.');
15354 // Prompt for user data:
15355 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15357 // process text value...
15361 // Show a dialog using config options:
15363 title:'Save Changes?',
15364 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15365 buttons: Roo.Msg.YESNOCANCEL,
15372 Roo.MessageBox = function(){
15373 var dlg, opt, mask, waitTimer;
15374 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15375 var buttons, activeTextEl, bwidth;
15378 var handleButton = function(button){
15380 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15384 var handleHide = function(){
15385 if(opt && opt.cls){
15386 dlg.el.removeClass(opt.cls);
15389 Roo.TaskMgr.stop(waitTimer);
15395 var updateButtons = function(b){
15398 buttons["ok"].hide();
15399 buttons["cancel"].hide();
15400 buttons["yes"].hide();
15401 buttons["no"].hide();
15402 dlg.footer.dom.style.display = 'none';
15405 dlg.footer.dom.style.display = '';
15406 for(var k in buttons){
15407 if(typeof buttons[k] != "function"){
15410 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15411 width += buttons[k].el.getWidth()+15;
15421 var handleEsc = function(d, k, e){
15422 if(opt && opt.closable !== false){
15432 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15433 * @return {Roo.BasicDialog} The BasicDialog element
15435 getDialog : function(){
15437 dlg = new Roo.BasicDialog("x-msg-box", {
15442 constraintoviewport:false,
15444 collapsible : false,
15447 width:400, height:100,
15448 buttonAlign:"center",
15449 closeClick : function(){
15450 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15451 handleButton("no");
15453 handleButton("cancel");
15457 dlg.on("hide", handleHide);
15459 dlg.addKeyListener(27, handleEsc);
15461 var bt = this.buttonText;
15462 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15463 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15464 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15465 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15466 bodyEl = dlg.body.createChild({
15468 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>'
15470 msgEl = bodyEl.dom.firstChild;
15471 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15472 textboxEl.enableDisplayMode();
15473 textboxEl.addKeyListener([10,13], function(){
15474 if(dlg.isVisible() && opt && opt.buttons){
15475 if(opt.buttons.ok){
15476 handleButton("ok");
15477 }else if(opt.buttons.yes){
15478 handleButton("yes");
15482 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15483 textareaEl.enableDisplayMode();
15484 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15485 progressEl.enableDisplayMode();
15486 var pf = progressEl.dom.firstChild;
15488 pp = Roo.get(pf.firstChild);
15489 pp.setHeight(pf.offsetHeight);
15497 * Updates the message box body text
15498 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15499 * the XHTML-compliant non-breaking space character '&#160;')
15500 * @return {Roo.MessageBox} This message box
15502 updateText : function(text){
15503 if(!dlg.isVisible() && !opt.width){
15504 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15506 msgEl.innerHTML = text || ' ';
15507 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15508 Math.max(opt.minWidth || this.minWidth, bwidth));
15510 activeTextEl.setWidth(w);
15512 if(dlg.isVisible()){
15513 dlg.fixedcenter = false;
15515 dlg.setContentSize(w, bodyEl.getHeight());
15516 if(dlg.isVisible()){
15517 dlg.fixedcenter = true;
15523 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15524 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15525 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15526 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15527 * @return {Roo.MessageBox} This message box
15529 updateProgress : function(value, text){
15531 this.updateText(text);
15533 if (pp) { // weird bug on my firefox - for some reason this is not defined
15534 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15540 * Returns true if the message box is currently displayed
15541 * @return {Boolean} True if the message box is visible, else false
15543 isVisible : function(){
15544 return dlg && dlg.isVisible();
15548 * Hides the message box if it is displayed
15551 if(this.isVisible()){
15557 * Displays a new message box, or reinitializes an existing message box, based on the config options
15558 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15559 * The following config object properties are supported:
15561 Property Type Description
15562 ---------- --------------- ------------------------------------------------------------------------------------
15563 animEl String/Element An id or Element from which the message box should animate as it opens and
15564 closes (defaults to undefined)
15565 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15566 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15567 closable Boolean False to hide the top-right close button (defaults to true). Note that
15568 progress and wait dialogs will ignore this property and always hide the
15569 close button as they can only be closed programmatically.
15570 cls String A custom CSS class to apply to the message box element
15571 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15572 displayed (defaults to 75)
15573 fn Function A callback function to execute after closing the dialog. The arguments to the
15574 function will be btn (the name of the button that was clicked, if applicable,
15575 e.g. "ok"), and text (the value of the active text field, if applicable).
15576 Progress and wait dialogs will ignore this option since they do not respond to
15577 user actions and can only be closed programmatically, so any required function
15578 should be called by the same code after it closes the dialog.
15579 icon String A CSS class that provides a background image to be used as an icon for
15580 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15581 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15582 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15583 modal Boolean False to allow user interaction with the page while the message box is
15584 displayed (defaults to true)
15585 msg String A string that will replace the existing message box body text (defaults
15586 to the XHTML-compliant non-breaking space character ' ')
15587 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15588 progress Boolean True to display a progress bar (defaults to false)
15589 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15590 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15591 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15592 title String The title text
15593 value String The string value to set into the active textbox element if displayed
15594 wait Boolean True to display a progress bar (defaults to false)
15595 width Number The width of the dialog in pixels
15602 msg: 'Please enter your address:',
15604 buttons: Roo.MessageBox.OKCANCEL,
15607 animEl: 'addAddressBtn'
15610 * @param {Object} config Configuration options
15611 * @return {Roo.MessageBox} This message box
15613 show : function(options){
15614 if(this.isVisible()){
15617 var d = this.getDialog();
15619 d.setTitle(opt.title || " ");
15620 d.close.setDisplayed(opt.closable !== false);
15621 activeTextEl = textboxEl;
15622 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15627 textareaEl.setHeight(typeof opt.multiline == "number" ?
15628 opt.multiline : this.defaultTextHeight);
15629 activeTextEl = textareaEl;
15638 progressEl.setDisplayed(opt.progress === true);
15639 this.updateProgress(0);
15640 activeTextEl.dom.value = opt.value || "";
15642 dlg.setDefaultButton(activeTextEl);
15644 var bs = opt.buttons;
15647 db = buttons["ok"];
15648 }else if(bs && bs.yes){
15649 db = buttons["yes"];
15651 dlg.setDefaultButton(db);
15653 bwidth = updateButtons(opt.buttons);
15654 this.updateText(opt.msg);
15656 d.el.addClass(opt.cls);
15658 d.proxyDrag = opt.proxyDrag === true;
15659 d.modal = opt.modal !== false;
15660 d.mask = opt.modal !== false ? mask : false;
15661 if(!d.isVisible()){
15662 // force it to the end of the z-index stack so it gets a cursor in FF
15663 document.body.appendChild(dlg.el.dom);
15664 d.animateTarget = null;
15665 d.show(options.animEl);
15671 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15672 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15673 * and closing the message box when the process is complete.
15674 * @param {String} title The title bar text
15675 * @param {String} msg The message box body text
15676 * @return {Roo.MessageBox} This message box
15678 progress : function(title, msg){
15685 minWidth: this.minProgressWidth,
15692 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15693 * If a callback function is passed it will be called after the user clicks the button, and the
15694 * id of the button that was clicked will be passed as the only parameter to the callback
15695 * (could also be the top-right close button).
15696 * @param {String} title The title bar text
15697 * @param {String} msg The message box body text
15698 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15699 * @param {Object} scope (optional) The scope of the callback function
15700 * @return {Roo.MessageBox} This message box
15702 alert : function(title, msg, fn, scope){
15715 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15716 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15717 * You are responsible for closing the message box when the process is complete.
15718 * @param {String} msg The message box body text
15719 * @param {String} title (optional) The title bar text
15720 * @return {Roo.MessageBox} This message box
15722 wait : function(msg, title){
15733 waitTimer = Roo.TaskMgr.start({
15735 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15743 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15744 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15745 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15746 * @param {String} title The title bar text
15747 * @param {String} msg The message box body text
15748 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15749 * @param {Object} scope (optional) The scope of the callback function
15750 * @return {Roo.MessageBox} This message box
15752 confirm : function(title, msg, fn, scope){
15756 buttons: this.YESNO,
15765 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15766 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15767 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15768 * (could also be the top-right close button) and the text that was entered will be passed as the two
15769 * parameters to the callback.
15770 * @param {String} title The title bar text
15771 * @param {String} msg The message box body text
15772 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15773 * @param {Object} scope (optional) The scope of the callback function
15774 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15775 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15776 * @return {Roo.MessageBox} This message box
15778 prompt : function(title, msg, fn, scope, multiline){
15782 buttons: this.OKCANCEL,
15787 multiline: multiline,
15794 * Button config that displays a single OK button
15799 * Button config that displays Yes and No buttons
15802 YESNO : {yes:true, no:true},
15804 * Button config that displays OK and Cancel buttons
15807 OKCANCEL : {ok:true, cancel:true},
15809 * Button config that displays Yes, No and Cancel buttons
15812 YESNOCANCEL : {yes:true, no:true, cancel:true},
15815 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15818 defaultTextHeight : 75,
15820 * The maximum width in pixels of the message box (defaults to 600)
15825 * The minimum width in pixels of the message box (defaults to 100)
15830 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15831 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15834 minProgressWidth : 250,
15836 * An object containing the default button text strings that can be overriden for localized language support.
15837 * Supported properties are: ok, cancel, yes and no.
15838 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15851 * Shorthand for {@link Roo.MessageBox}
15853 Roo.Msg = Roo.MessageBox;/*
15855 * Ext JS Library 1.1.1
15856 * Copyright(c) 2006-2007, Ext JS, LLC.
15858 * Originally Released Under LGPL - original licence link has changed is not relivant.
15861 * <script type="text/javascript">
15864 * @class Roo.QuickTips
15865 * Provides attractive and customizable tooltips for any element.
15868 Roo.QuickTips = function(){
15869 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15870 var ce, bd, xy, dd;
15871 var visible = false, disabled = true, inited = false;
15872 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15874 var onOver = function(e){
15878 var t = e.getTarget();
15879 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15882 if(ce && t == ce.el){
15883 clearTimeout(hideProc);
15886 if(t && tagEls[t.id]){
15887 tagEls[t.id].el = t;
15888 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15891 var ttp, et = Roo.fly(t);
15892 var ns = cfg.namespace;
15893 if(tm.interceptTitles && t.title){
15896 t.removeAttribute("title");
15897 e.preventDefault();
15899 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15902 showProc = show.defer(tm.showDelay, tm, [{
15905 width: et.getAttributeNS(ns, cfg.width),
15906 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15907 title: et.getAttributeNS(ns, cfg.title),
15908 cls: et.getAttributeNS(ns, cfg.cls)
15913 var onOut = function(e){
15914 clearTimeout(showProc);
15915 var t = e.getTarget();
15916 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15917 hideProc = setTimeout(hide, tm.hideDelay);
15921 var onMove = function(e){
15927 if(tm.trackMouse && ce){
15932 var onDown = function(e){
15933 clearTimeout(showProc);
15934 clearTimeout(hideProc);
15936 if(tm.hideOnClick){
15939 tm.enable.defer(100, tm);
15944 var getPad = function(){
15945 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15948 var show = function(o){
15952 clearTimeout(dismissProc);
15954 if(removeCls){ // in case manually hidden
15955 el.removeClass(removeCls);
15959 el.addClass(ce.cls);
15960 removeCls = ce.cls;
15963 tipTitle.update(ce.title);
15966 tipTitle.update('');
15969 el.dom.style.width = tm.maxWidth+'px';
15970 //tipBody.dom.style.width = '';
15971 tipBodyText.update(o.text);
15972 var p = getPad(), w = ce.width;
15974 var td = tipBodyText.dom;
15975 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15976 if(aw > tm.maxWidth){
15978 }else if(aw < tm.minWidth){
15984 //tipBody.setWidth(w);
15985 el.setWidth(parseInt(w, 10) + p);
15986 if(ce.autoHide === false){
15987 close.setDisplayed(true);
15992 close.setDisplayed(false);
15998 el.avoidY = xy[1]-18;
16003 el.setStyle("visibility", "visible");
16004 el.fadeIn({callback: afterShow});
16010 var afterShow = function(){
16014 if(tm.autoDismiss && ce.autoHide !== false){
16015 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16020 var hide = function(noanim){
16021 clearTimeout(dismissProc);
16022 clearTimeout(hideProc);
16024 if(el.isVisible()){
16026 if(noanim !== true && tm.animate){
16027 el.fadeOut({callback: afterHide});
16034 var afterHide = function(){
16037 el.removeClass(removeCls);
16044 * @cfg {Number} minWidth
16045 * The minimum width of the quick tip (defaults to 40)
16049 * @cfg {Number} maxWidth
16050 * The maximum width of the quick tip (defaults to 300)
16054 * @cfg {Boolean} interceptTitles
16055 * True to automatically use the element's DOM title value if available (defaults to false)
16057 interceptTitles : false,
16059 * @cfg {Boolean} trackMouse
16060 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16062 trackMouse : false,
16064 * @cfg {Boolean} hideOnClick
16065 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16067 hideOnClick : true,
16069 * @cfg {Number} showDelay
16070 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16074 * @cfg {Number} hideDelay
16075 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16079 * @cfg {Boolean} autoHide
16080 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16081 * Used in conjunction with hideDelay.
16086 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16087 * (defaults to true). Used in conjunction with autoDismissDelay.
16089 autoDismiss : true,
16092 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16094 autoDismissDelay : 5000,
16096 * @cfg {Boolean} animate
16097 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16102 * @cfg {String} title
16103 * Title text to display (defaults to ''). This can be any valid HTML markup.
16107 * @cfg {String} text
16108 * Body text to display (defaults to ''). This can be any valid HTML markup.
16112 * @cfg {String} cls
16113 * A CSS class to apply to the base quick tip element (defaults to '').
16117 * @cfg {Number} width
16118 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16119 * minWidth or maxWidth.
16124 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16125 * or display QuickTips in a page.
16128 tm = Roo.QuickTips;
16129 cfg = tm.tagConfig;
16131 if(!Roo.isReady){ // allow calling of init() before onReady
16132 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16135 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16136 el.fxDefaults = {stopFx: true};
16137 // maximum custom styling
16138 //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>');
16139 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>');
16140 tipTitle = el.child('h3');
16141 tipTitle.enableDisplayMode("block");
16142 tipBody = el.child('div.x-tip-bd');
16143 tipBodyText = el.child('div.x-tip-bd-inner');
16144 //bdLeft = el.child('div.x-tip-bd-left');
16145 //bdRight = el.child('div.x-tip-bd-right');
16146 close = el.child('div.x-tip-close');
16147 close.enableDisplayMode("block");
16148 close.on("click", hide);
16149 var d = Roo.get(document);
16150 d.on("mousedown", onDown);
16151 d.on("mouseover", onOver);
16152 d.on("mouseout", onOut);
16153 d.on("mousemove", onMove);
16154 esc = d.addKeyListener(27, hide);
16157 dd = el.initDD("default", null, {
16158 onDrag : function(){
16162 dd.setHandleElId(tipTitle.id);
16171 * Configures a new quick tip instance and assigns it to a target element. The following config options
16174 Property Type Description
16175 ---------- --------------------- ------------------------------------------------------------------------
16176 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16178 * @param {Object} config The config object
16180 register : function(config){
16181 var cs = config instanceof Array ? config : arguments;
16182 for(var i = 0, len = cs.length; i < len; i++) {
16184 var target = c.target;
16186 if(target instanceof Array){
16187 for(var j = 0, jlen = target.length; j < jlen; j++){
16188 tagEls[target[j]] = c;
16191 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16198 * Removes this quick tip from its element and destroys it.
16199 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16201 unregister : function(el){
16202 delete tagEls[Roo.id(el)];
16206 * Enable this quick tip.
16208 enable : function(){
16209 if(inited && disabled){
16211 if(locks.length < 1){
16218 * Disable this quick tip.
16220 disable : function(){
16222 clearTimeout(showProc);
16223 clearTimeout(hideProc);
16224 clearTimeout(dismissProc);
16232 * Returns true if the quick tip is enabled, else false.
16234 isEnabled : function(){
16241 attribute : "qtip",
16251 // backwards compat
16252 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16254 * Ext JS Library 1.1.1
16255 * Copyright(c) 2006-2007, Ext JS, LLC.
16257 * Originally Released Under LGPL - original licence link has changed is not relivant.
16260 * <script type="text/javascript">
16265 * @class Roo.tree.TreePanel
16266 * @extends Roo.data.Tree
16268 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16269 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16270 * @cfg {Boolean} enableDD true to enable drag and drop
16271 * @cfg {Boolean} enableDrag true to enable just drag
16272 * @cfg {Boolean} enableDrop true to enable just drop
16273 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16274 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16275 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16276 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16277 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16278 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16279 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16280 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16281 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16282 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16283 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16284 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16285 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16286 * @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>
16287 * @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>
16290 * @param {String/HTMLElement/Element} el The container element
16291 * @param {Object} config
16293 Roo.tree.TreePanel = function(el, config){
16295 var loader = false;
16297 root = config.root;
16298 delete config.root;
16300 if (config.loader) {
16301 loader = config.loader;
16302 delete config.loader;
16305 Roo.apply(this, config);
16306 Roo.tree.TreePanel.superclass.constructor.call(this);
16307 this.el = Roo.get(el);
16308 this.el.addClass('x-tree');
16309 //console.log(root);
16311 this.setRootNode( Roo.factory(root, Roo.tree));
16314 this.loader = Roo.factory(loader, Roo.tree);
16317 * Read-only. The id of the container element becomes this TreePanel's id.
16319 this.id = this.el.id;
16322 * @event beforeload
16323 * Fires before a node is loaded, return false to cancel
16324 * @param {Node} node The node being loaded
16326 "beforeload" : true,
16329 * Fires when a node is loaded
16330 * @param {Node} node The node that was loaded
16334 * @event textchange
16335 * Fires when the text for a node is changed
16336 * @param {Node} node The node
16337 * @param {String} text The new text
16338 * @param {String} oldText The old text
16340 "textchange" : true,
16342 * @event beforeexpand
16343 * Fires before a node is expanded, return false to cancel.
16344 * @param {Node} node The node
16345 * @param {Boolean} deep
16346 * @param {Boolean} anim
16348 "beforeexpand" : true,
16350 * @event beforecollapse
16351 * Fires before a node is collapsed, return false to cancel.
16352 * @param {Node} node The node
16353 * @param {Boolean} deep
16354 * @param {Boolean} anim
16356 "beforecollapse" : true,
16359 * Fires when a node is expanded
16360 * @param {Node} node The node
16364 * @event disabledchange
16365 * Fires when the disabled status of a node changes
16366 * @param {Node} node The node
16367 * @param {Boolean} disabled
16369 "disabledchange" : true,
16372 * Fires when a node is collapsed
16373 * @param {Node} node The node
16377 * @event beforeclick
16378 * Fires before click processing on a node. Return false to cancel the default action.
16379 * @param {Node} node The node
16380 * @param {Roo.EventObject} e The event object
16382 "beforeclick":true,
16384 * @event checkchange
16385 * Fires when a node with a checkbox's checked property changes
16386 * @param {Node} this This node
16387 * @param {Boolean} checked
16389 "checkchange":true,
16392 * Fires when a node is clicked
16393 * @param {Node} node The node
16394 * @param {Roo.EventObject} e The event object
16399 * Fires when a node is double clicked
16400 * @param {Node} node The node
16401 * @param {Roo.EventObject} e The event object
16405 * @event contextmenu
16406 * Fires when a node is right clicked
16407 * @param {Node} node The node
16408 * @param {Roo.EventObject} e The event object
16410 "contextmenu":true,
16412 * @event beforechildrenrendered
16413 * Fires right before the child nodes for a node are rendered
16414 * @param {Node} node The node
16416 "beforechildrenrendered":true,
16419 * Fires when a node starts being dragged
16420 * @param {Roo.tree.TreePanel} this
16421 * @param {Roo.tree.TreeNode} node
16422 * @param {event} e The raw browser event
16424 "startdrag" : true,
16427 * Fires when a drag operation is complete
16428 * @param {Roo.tree.TreePanel} this
16429 * @param {Roo.tree.TreeNode} node
16430 * @param {event} e The raw browser event
16435 * Fires when a dragged node is dropped on a valid DD target
16436 * @param {Roo.tree.TreePanel} this
16437 * @param {Roo.tree.TreeNode} node
16438 * @param {DD} dd The dd it was dropped on
16439 * @param {event} e The raw browser event
16443 * @event beforenodedrop
16444 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16445 * passed to handlers has the following properties:<br />
16446 * <ul style="padding:5px;padding-left:16px;">
16447 * <li>tree - The TreePanel</li>
16448 * <li>target - The node being targeted for the drop</li>
16449 * <li>data - The drag data from the drag source</li>
16450 * <li>point - The point of the drop - append, above or below</li>
16451 * <li>source - The drag source</li>
16452 * <li>rawEvent - Raw mouse event</li>
16453 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16454 * to be inserted by setting them on this object.</li>
16455 * <li>cancel - Set this to true to cancel the drop.</li>
16457 * @param {Object} dropEvent
16459 "beforenodedrop" : true,
16462 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16463 * passed to handlers has the following properties:<br />
16464 * <ul style="padding:5px;padding-left:16px;">
16465 * <li>tree - The TreePanel</li>
16466 * <li>target - The node being targeted for the drop</li>
16467 * <li>data - The drag data from the drag source</li>
16468 * <li>point - The point of the drop - append, above or below</li>
16469 * <li>source - The drag source</li>
16470 * <li>rawEvent - Raw mouse event</li>
16471 * <li>dropNode - Dropped node(s).</li>
16473 * @param {Object} dropEvent
16477 * @event nodedragover
16478 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16479 * passed to handlers has the following properties:<br />
16480 * <ul style="padding:5px;padding-left:16px;">
16481 * <li>tree - The TreePanel</li>
16482 * <li>target - The node being targeted for the drop</li>
16483 * <li>data - The drag data from the drag source</li>
16484 * <li>point - The point of the drop - append, above or below</li>
16485 * <li>source - The drag source</li>
16486 * <li>rawEvent - Raw mouse event</li>
16487 * <li>dropNode - Drop node(s) provided by the source.</li>
16488 * <li>cancel - Set this to true to signal drop not allowed.</li>
16490 * @param {Object} dragOverEvent
16492 "nodedragover" : true
16495 if(this.singleExpand){
16496 this.on("beforeexpand", this.restrictExpand, this);
16499 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16500 rootVisible : true,
16501 animate: Roo.enableFx,
16504 hlDrop : Roo.enableFx,
16508 rendererTip: false,
16510 restrictExpand : function(node){
16511 var p = node.parentNode;
16513 if(p.expandedChild && p.expandedChild.parentNode == p){
16514 p.expandedChild.collapse();
16516 p.expandedChild = node;
16520 // private override
16521 setRootNode : function(node){
16522 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16523 if(!this.rootVisible){
16524 node.ui = new Roo.tree.RootTreeNodeUI(node);
16530 * Returns the container element for this TreePanel
16532 getEl : function(){
16537 * Returns the default TreeLoader for this TreePanel
16539 getLoader : function(){
16540 return this.loader;
16546 expandAll : function(){
16547 this.root.expand(true);
16551 * Collapse all nodes
16553 collapseAll : function(){
16554 this.root.collapse(true);
16558 * Returns the selection model used by this TreePanel
16560 getSelectionModel : function(){
16561 if(!this.selModel){
16562 this.selModel = new Roo.tree.DefaultSelectionModel();
16564 return this.selModel;
16568 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16569 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16570 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16573 getChecked : function(a, startNode){
16574 startNode = startNode || this.root;
16576 var f = function(){
16577 if(this.attributes.checked){
16578 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16581 startNode.cascade(f);
16586 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16587 * @param {String} path
16588 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16589 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16590 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16592 expandPath : function(path, attr, callback){
16593 attr = attr || "id";
16594 var keys = path.split(this.pathSeparator);
16595 var curNode = this.root;
16596 if(curNode.attributes[attr] != keys[1]){ // invalid root
16598 callback(false, null);
16603 var f = function(){
16604 if(++index == keys.length){
16606 callback(true, curNode);
16610 var c = curNode.findChild(attr, keys[index]);
16613 callback(false, curNode);
16618 c.expand(false, false, f);
16620 curNode.expand(false, false, f);
16624 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16625 * @param {String} path
16626 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16627 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16628 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16630 selectPath : function(path, attr, callback){
16631 attr = attr || "id";
16632 var keys = path.split(this.pathSeparator);
16633 var v = keys.pop();
16634 if(keys.length > 0){
16635 var f = function(success, node){
16636 if(success && node){
16637 var n = node.findChild(attr, v);
16643 }else if(callback){
16644 callback(false, n);
16648 callback(false, n);
16652 this.expandPath(keys.join(this.pathSeparator), attr, f);
16654 this.root.select();
16656 callback(true, this.root);
16661 getTreeEl : function(){
16666 * Trigger rendering of this TreePanel
16668 render : function(){
16669 if (this.innerCt) {
16670 return this; // stop it rendering more than once!!
16673 this.innerCt = this.el.createChild({tag:"ul",
16674 cls:"x-tree-root-ct " +
16675 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16677 if(this.containerScroll){
16678 Roo.dd.ScrollManager.register(this.el);
16680 if((this.enableDD || this.enableDrop) && !this.dropZone){
16682 * The dropZone used by this tree if drop is enabled
16683 * @type Roo.tree.TreeDropZone
16685 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16686 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16689 if((this.enableDD || this.enableDrag) && !this.dragZone){
16691 * The dragZone used by this tree if drag is enabled
16692 * @type Roo.tree.TreeDragZone
16694 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16695 ddGroup: this.ddGroup || "TreeDD",
16696 scroll: this.ddScroll
16699 this.getSelectionModel().init(this);
16701 console.log("ROOT not set in tree");
16704 this.root.render();
16705 if(!this.rootVisible){
16706 this.root.renderChildren();
16712 * Ext JS Library 1.1.1
16713 * Copyright(c) 2006-2007, Ext JS, LLC.
16715 * Originally Released Under LGPL - original licence link has changed is not relivant.
16718 * <script type="text/javascript">
16723 * @class Roo.tree.DefaultSelectionModel
16724 * @extends Roo.util.Observable
16725 * The default single selection for a TreePanel.
16727 Roo.tree.DefaultSelectionModel = function(){
16728 this.selNode = null;
16732 * @event selectionchange
16733 * Fires when the selected node changes
16734 * @param {DefaultSelectionModel} this
16735 * @param {TreeNode} node the new selection
16737 "selectionchange" : true,
16740 * @event beforeselect
16741 * Fires before the selected node changes, return false to cancel the change
16742 * @param {DefaultSelectionModel} this
16743 * @param {TreeNode} node the new selection
16744 * @param {TreeNode} node the old selection
16746 "beforeselect" : true
16750 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16751 init : function(tree){
16753 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16754 tree.on("click", this.onNodeClick, this);
16757 onNodeClick : function(node, e){
16758 if (e.ctrlKey && this.selNode == node) {
16759 this.unselect(node);
16767 * @param {TreeNode} node The node to select
16768 * @return {TreeNode} The selected node
16770 select : function(node){
16771 var last = this.selNode;
16772 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16774 last.ui.onSelectedChange(false);
16776 this.selNode = node;
16777 node.ui.onSelectedChange(true);
16778 this.fireEvent("selectionchange", this, node, last);
16785 * @param {TreeNode} node The node to unselect
16787 unselect : function(node){
16788 if(this.selNode == node){
16789 this.clearSelections();
16794 * Clear all selections
16796 clearSelections : function(){
16797 var n = this.selNode;
16799 n.ui.onSelectedChange(false);
16800 this.selNode = null;
16801 this.fireEvent("selectionchange", this, null);
16807 * Get the selected node
16808 * @return {TreeNode} The selected node
16810 getSelectedNode : function(){
16811 return this.selNode;
16815 * Returns true if the node is selected
16816 * @param {TreeNode} node The node to check
16817 * @return {Boolean}
16819 isSelected : function(node){
16820 return this.selNode == node;
16824 * Selects the node above the selected node in the tree, intelligently walking the nodes
16825 * @return TreeNode The new selection
16827 selectPrevious : function(){
16828 var s = this.selNode || this.lastSelNode;
16832 var ps = s.previousSibling;
16834 if(!ps.isExpanded() || ps.childNodes.length < 1){
16835 return this.select(ps);
16837 var lc = ps.lastChild;
16838 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16841 return this.select(lc);
16843 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16844 return this.select(s.parentNode);
16850 * Selects the node above the selected node in the tree, intelligently walking the nodes
16851 * @return TreeNode The new selection
16853 selectNext : function(){
16854 var s = this.selNode || this.lastSelNode;
16858 if(s.firstChild && s.isExpanded()){
16859 return this.select(s.firstChild);
16860 }else if(s.nextSibling){
16861 return this.select(s.nextSibling);
16862 }else if(s.parentNode){
16864 s.parentNode.bubble(function(){
16865 if(this.nextSibling){
16866 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16875 onKeyDown : function(e){
16876 var s = this.selNode || this.lastSelNode;
16877 // undesirable, but required
16882 var k = e.getKey();
16890 this.selectPrevious();
16893 e.preventDefault();
16894 if(s.hasChildNodes()){
16895 if(!s.isExpanded()){
16897 }else if(s.firstChild){
16898 this.select(s.firstChild, e);
16903 e.preventDefault();
16904 if(s.hasChildNodes() && s.isExpanded()){
16906 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16907 this.select(s.parentNode, e);
16915 * @class Roo.tree.MultiSelectionModel
16916 * @extends Roo.util.Observable
16917 * Multi selection for a TreePanel.
16919 Roo.tree.MultiSelectionModel = function(){
16920 this.selNodes = [];
16924 * @event selectionchange
16925 * Fires when the selected nodes change
16926 * @param {MultiSelectionModel} this
16927 * @param {Array} nodes Array of the selected nodes
16929 "selectionchange" : true
16933 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16934 init : function(tree){
16936 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16937 tree.on("click", this.onNodeClick, this);
16940 onNodeClick : function(node, e){
16941 this.select(node, e, e.ctrlKey);
16946 * @param {TreeNode} node The node to select
16947 * @param {EventObject} e (optional) An event associated with the selection
16948 * @param {Boolean} keepExisting True to retain existing selections
16949 * @return {TreeNode} The selected node
16951 select : function(node, e, keepExisting){
16952 if(keepExisting !== true){
16953 this.clearSelections(true);
16955 if(this.isSelected(node)){
16956 this.lastSelNode = node;
16959 this.selNodes.push(node);
16960 this.selMap[node.id] = node;
16961 this.lastSelNode = node;
16962 node.ui.onSelectedChange(true);
16963 this.fireEvent("selectionchange", this, this.selNodes);
16969 * @param {TreeNode} node The node to unselect
16971 unselect : function(node){
16972 if(this.selMap[node.id]){
16973 node.ui.onSelectedChange(false);
16974 var sn = this.selNodes;
16977 index = sn.indexOf(node);
16979 for(var i = 0, len = sn.length; i < len; i++){
16987 this.selNodes.splice(index, 1);
16989 delete this.selMap[node.id];
16990 this.fireEvent("selectionchange", this, this.selNodes);
16995 * Clear all selections
16997 clearSelections : function(suppressEvent){
16998 var sn = this.selNodes;
17000 for(var i = 0, len = sn.length; i < len; i++){
17001 sn[i].ui.onSelectedChange(false);
17003 this.selNodes = [];
17005 if(suppressEvent !== true){
17006 this.fireEvent("selectionchange", this, this.selNodes);
17012 * Returns true if the node is selected
17013 * @param {TreeNode} node The node to check
17014 * @return {Boolean}
17016 isSelected : function(node){
17017 return this.selMap[node.id] ? true : false;
17021 * Returns an array of the selected nodes
17024 getSelectedNodes : function(){
17025 return this.selNodes;
17028 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17030 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17032 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17035 * Ext JS Library 1.1.1
17036 * Copyright(c) 2006-2007, Ext JS, LLC.
17038 * Originally Released Under LGPL - original licence link has changed is not relivant.
17041 * <script type="text/javascript">
17045 * @class Roo.tree.TreeNode
17046 * @extends Roo.data.Node
17047 * @cfg {String} text The text for this node
17048 * @cfg {Boolean} expanded true to start the node expanded
17049 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17050 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17051 * @cfg {Boolean} disabled true to start the node disabled
17052 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17053 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17054 * @cfg {String} cls A css class to be added to the node
17055 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17056 * @cfg {String} href URL of the link used for the node (defaults to #)
17057 * @cfg {String} hrefTarget target frame for the link
17058 * @cfg {String} qtip An Ext QuickTip for the node
17059 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17060 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17061 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17062 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17063 * (defaults to undefined with no checkbox rendered)
17065 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17067 Roo.tree.TreeNode = function(attributes){
17068 attributes = attributes || {};
17069 if(typeof attributes == "string"){
17070 attributes = {text: attributes};
17072 this.childrenRendered = false;
17073 this.rendered = false;
17074 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17075 this.expanded = attributes.expanded === true;
17076 this.isTarget = attributes.isTarget !== false;
17077 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17078 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17081 * Read-only. The text for this node. To change it use setText().
17084 this.text = attributes.text;
17086 * True if this node is disabled.
17089 this.disabled = attributes.disabled === true;
17093 * @event textchange
17094 * Fires when the text for this node is changed
17095 * @param {Node} this This node
17096 * @param {String} text The new text
17097 * @param {String} oldText The old text
17099 "textchange" : true,
17101 * @event beforeexpand
17102 * Fires before this node is expanded, return false to cancel.
17103 * @param {Node} this This node
17104 * @param {Boolean} deep
17105 * @param {Boolean} anim
17107 "beforeexpand" : true,
17109 * @event beforecollapse
17110 * Fires before this node is collapsed, return false to cancel.
17111 * @param {Node} this This node
17112 * @param {Boolean} deep
17113 * @param {Boolean} anim
17115 "beforecollapse" : true,
17118 * Fires when this node is expanded
17119 * @param {Node} this This node
17123 * @event disabledchange
17124 * Fires when the disabled status of this node changes
17125 * @param {Node} this This node
17126 * @param {Boolean} disabled
17128 "disabledchange" : true,
17131 * Fires when this node is collapsed
17132 * @param {Node} this This node
17136 * @event beforeclick
17137 * Fires before click processing. Return false to cancel the default action.
17138 * @param {Node} this This node
17139 * @param {Roo.EventObject} e The event object
17141 "beforeclick":true,
17143 * @event checkchange
17144 * Fires when a node with a checkbox's checked property changes
17145 * @param {Node} this This node
17146 * @param {Boolean} checked
17148 "checkchange":true,
17151 * Fires when this node is clicked
17152 * @param {Node} this This node
17153 * @param {Roo.EventObject} e The event object
17158 * Fires when this node is double clicked
17159 * @param {Node} this This node
17160 * @param {Roo.EventObject} e The event object
17164 * @event contextmenu
17165 * Fires when this node is right clicked
17166 * @param {Node} this This node
17167 * @param {Roo.EventObject} e The event object
17169 "contextmenu":true,
17171 * @event beforechildrenrendered
17172 * Fires right before the child nodes for this node are rendered
17173 * @param {Node} this This node
17175 "beforechildrenrendered":true
17178 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17181 * Read-only. The UI for this node
17184 this.ui = new uiClass(this);
17186 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17187 preventHScroll: true,
17189 * Returns true if this node is expanded
17190 * @return {Boolean}
17192 isExpanded : function(){
17193 return this.expanded;
17197 * Returns the UI object for this node
17198 * @return {TreeNodeUI}
17200 getUI : function(){
17204 // private override
17205 setFirstChild : function(node){
17206 var of = this.firstChild;
17207 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17208 if(this.childrenRendered && of && node != of){
17209 of.renderIndent(true, true);
17212 this.renderIndent(true, true);
17216 // private override
17217 setLastChild : function(node){
17218 var ol = this.lastChild;
17219 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17220 if(this.childrenRendered && ol && node != ol){
17221 ol.renderIndent(true, true);
17224 this.renderIndent(true, true);
17228 // these methods are overridden to provide lazy rendering support
17229 // private override
17230 appendChild : function(){
17231 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17232 if(node && this.childrenRendered){
17235 this.ui.updateExpandIcon();
17239 // private override
17240 removeChild : function(node){
17241 this.ownerTree.getSelectionModel().unselect(node);
17242 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17243 // if it's been rendered remove dom node
17244 if(this.childrenRendered){
17247 if(this.childNodes.length < 1){
17248 this.collapse(false, false);
17250 this.ui.updateExpandIcon();
17252 if(!this.firstChild) {
17253 this.childrenRendered = false;
17258 // private override
17259 insertBefore : function(node, refNode){
17260 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17261 if(newNode && refNode && this.childrenRendered){
17264 this.ui.updateExpandIcon();
17269 * Sets the text for this node
17270 * @param {String} text
17272 setText : function(text){
17273 var oldText = this.text;
17275 this.attributes.text = text;
17276 if(this.rendered){ // event without subscribing
17277 this.ui.onTextChange(this, text, oldText);
17279 this.fireEvent("textchange", this, text, oldText);
17283 * Triggers selection of this node
17285 select : function(){
17286 this.getOwnerTree().getSelectionModel().select(this);
17290 * Triggers deselection of this node
17292 unselect : function(){
17293 this.getOwnerTree().getSelectionModel().unselect(this);
17297 * Returns true if this node is selected
17298 * @return {Boolean}
17300 isSelected : function(){
17301 return this.getOwnerTree().getSelectionModel().isSelected(this);
17305 * Expand this node.
17306 * @param {Boolean} deep (optional) True to expand all children as well
17307 * @param {Boolean} anim (optional) false to cancel the default animation
17308 * @param {Function} callback (optional) A callback to be called when
17309 * expanding this node completes (does not wait for deep expand to complete).
17310 * Called with 1 parameter, this node.
17312 expand : function(deep, anim, callback){
17313 if(!this.expanded){
17314 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17317 if(!this.childrenRendered){
17318 this.renderChildren();
17320 this.expanded = true;
17321 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17322 this.ui.animExpand(function(){
17323 this.fireEvent("expand", this);
17324 if(typeof callback == "function"){
17328 this.expandChildNodes(true);
17330 }.createDelegate(this));
17334 this.fireEvent("expand", this);
17335 if(typeof callback == "function"){
17340 if(typeof callback == "function"){
17345 this.expandChildNodes(true);
17349 isHiddenRoot : function(){
17350 return this.isRoot && !this.getOwnerTree().rootVisible;
17354 * Collapse this node.
17355 * @param {Boolean} deep (optional) True to collapse all children as well
17356 * @param {Boolean} anim (optional) false to cancel the default animation
17358 collapse : function(deep, anim){
17359 if(this.expanded && !this.isHiddenRoot()){
17360 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17363 this.expanded = false;
17364 if((this.getOwnerTree().animate && anim !== false) || anim){
17365 this.ui.animCollapse(function(){
17366 this.fireEvent("collapse", this);
17368 this.collapseChildNodes(true);
17370 }.createDelegate(this));
17373 this.ui.collapse();
17374 this.fireEvent("collapse", this);
17378 var cs = this.childNodes;
17379 for(var i = 0, len = cs.length; i < len; i++) {
17380 cs[i].collapse(true, false);
17386 delayedExpand : function(delay){
17387 if(!this.expandProcId){
17388 this.expandProcId = this.expand.defer(delay, this);
17393 cancelExpand : function(){
17394 if(this.expandProcId){
17395 clearTimeout(this.expandProcId);
17397 this.expandProcId = false;
17401 * Toggles expanded/collapsed state of the node
17403 toggle : function(){
17412 * Ensures all parent nodes are expanded
17414 ensureVisible : function(callback){
17415 var tree = this.getOwnerTree();
17416 tree.expandPath(this.parentNode.getPath(), false, function(){
17417 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17418 Roo.callback(callback);
17419 }.createDelegate(this));
17423 * Expand all child nodes
17424 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17426 expandChildNodes : function(deep){
17427 var cs = this.childNodes;
17428 for(var i = 0, len = cs.length; i < len; i++) {
17429 cs[i].expand(deep);
17434 * Collapse all child nodes
17435 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17437 collapseChildNodes : function(deep){
17438 var cs = this.childNodes;
17439 for(var i = 0, len = cs.length; i < len; i++) {
17440 cs[i].collapse(deep);
17445 * Disables this node
17447 disable : function(){
17448 this.disabled = true;
17450 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17451 this.ui.onDisableChange(this, true);
17453 this.fireEvent("disabledchange", this, true);
17457 * Enables this node
17459 enable : function(){
17460 this.disabled = false;
17461 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17462 this.ui.onDisableChange(this, false);
17464 this.fireEvent("disabledchange", this, false);
17468 renderChildren : function(suppressEvent){
17469 if(suppressEvent !== false){
17470 this.fireEvent("beforechildrenrendered", this);
17472 var cs = this.childNodes;
17473 for(var i = 0, len = cs.length; i < len; i++){
17474 cs[i].render(true);
17476 this.childrenRendered = true;
17480 sort : function(fn, scope){
17481 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17482 if(this.childrenRendered){
17483 var cs = this.childNodes;
17484 for(var i = 0, len = cs.length; i < len; i++){
17485 cs[i].render(true);
17491 render : function(bulkRender){
17492 this.ui.render(bulkRender);
17493 if(!this.rendered){
17494 this.rendered = true;
17496 this.expanded = false;
17497 this.expand(false, false);
17503 renderIndent : function(deep, refresh){
17505 this.ui.childIndent = null;
17507 this.ui.renderIndent();
17508 if(deep === true && this.childrenRendered){
17509 var cs = this.childNodes;
17510 for(var i = 0, len = cs.length; i < len; i++){
17511 cs[i].renderIndent(true, refresh);
17517 * Ext JS Library 1.1.1
17518 * Copyright(c) 2006-2007, Ext JS, LLC.
17520 * Originally Released Under LGPL - original licence link has changed is not relivant.
17523 * <script type="text/javascript">
17527 * @class Roo.tree.AsyncTreeNode
17528 * @extends Roo.tree.TreeNode
17529 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17531 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17533 Roo.tree.AsyncTreeNode = function(config){
17534 this.loaded = false;
17535 this.loading = false;
17536 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17538 * @event beforeload
17539 * Fires before this node is loaded, return false to cancel
17540 * @param {Node} this This node
17542 this.addEvents({'beforeload':true, 'load': true});
17545 * Fires when this node is loaded
17546 * @param {Node} this This node
17549 * The loader used by this node (defaults to using the tree's defined loader)
17554 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17555 expand : function(deep, anim, callback){
17556 if(this.loading){ // if an async load is already running, waiting til it's done
17558 var f = function(){
17559 if(!this.loading){ // done loading
17560 clearInterval(timer);
17561 this.expand(deep, anim, callback);
17563 }.createDelegate(this);
17564 timer = setInterval(f, 200);
17568 if(this.fireEvent("beforeload", this) === false){
17571 this.loading = true;
17572 this.ui.beforeLoad(this);
17573 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17575 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17579 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17583 * Returns true if this node is currently loading
17584 * @return {Boolean}
17586 isLoading : function(){
17587 return this.loading;
17590 loadComplete : function(deep, anim, callback){
17591 this.loading = false;
17592 this.loaded = true;
17593 this.ui.afterLoad(this);
17594 this.fireEvent("load", this);
17595 this.expand(deep, anim, callback);
17599 * Returns true if this node has been loaded
17600 * @return {Boolean}
17602 isLoaded : function(){
17603 return this.loaded;
17606 hasChildNodes : function(){
17607 if(!this.isLeaf() && !this.loaded){
17610 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17615 * Trigger a reload for this node
17616 * @param {Function} callback
17618 reload : function(callback){
17619 this.collapse(false, false);
17620 while(this.firstChild){
17621 this.removeChild(this.firstChild);
17623 this.childrenRendered = false;
17624 this.loaded = false;
17625 if(this.isHiddenRoot()){
17626 this.expanded = false;
17628 this.expand(false, false, callback);
17632 * Ext JS Library 1.1.1
17633 * Copyright(c) 2006-2007, Ext JS, LLC.
17635 * Originally Released Under LGPL - original licence link has changed is not relivant.
17638 * <script type="text/javascript">
17642 * @class Roo.tree.TreeNodeUI
17644 * @param {Object} node The node to render
17645 * The TreeNode UI implementation is separate from the
17646 * tree implementation. Unless you are customizing the tree UI,
17647 * you should never have to use this directly.
17649 Roo.tree.TreeNodeUI = function(node){
17651 this.rendered = false;
17652 this.animating = false;
17653 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17656 Roo.tree.TreeNodeUI.prototype = {
17657 removeChild : function(node){
17659 this.ctNode.removeChild(node.ui.getEl());
17663 beforeLoad : function(){
17664 this.addClass("x-tree-node-loading");
17667 afterLoad : function(){
17668 this.removeClass("x-tree-node-loading");
17671 onTextChange : function(node, text, oldText){
17673 this.textNode.innerHTML = text;
17677 onDisableChange : function(node, state){
17678 this.disabled = state;
17680 this.addClass("x-tree-node-disabled");
17682 this.removeClass("x-tree-node-disabled");
17686 onSelectedChange : function(state){
17689 this.addClass("x-tree-selected");
17692 this.removeClass("x-tree-selected");
17696 onMove : function(tree, node, oldParent, newParent, index, refNode){
17697 this.childIndent = null;
17699 var targetNode = newParent.ui.getContainer();
17700 if(!targetNode){//target not rendered
17701 this.holder = document.createElement("div");
17702 this.holder.appendChild(this.wrap);
17705 var insertBefore = refNode ? refNode.ui.getEl() : null;
17707 targetNode.insertBefore(this.wrap, insertBefore);
17709 targetNode.appendChild(this.wrap);
17711 this.node.renderIndent(true);
17715 addClass : function(cls){
17717 Roo.fly(this.elNode).addClass(cls);
17721 removeClass : function(cls){
17723 Roo.fly(this.elNode).removeClass(cls);
17727 remove : function(){
17729 this.holder = document.createElement("div");
17730 this.holder.appendChild(this.wrap);
17734 fireEvent : function(){
17735 return this.node.fireEvent.apply(this.node, arguments);
17738 initEvents : function(){
17739 this.node.on("move", this.onMove, this);
17740 var E = Roo.EventManager;
17741 var a = this.anchor;
17743 var el = Roo.fly(a, '_treeui');
17745 if(Roo.isOpera){ // opera render bug ignores the CSS
17746 el.setStyle("text-decoration", "none");
17749 el.on("click", this.onClick, this);
17750 el.on("dblclick", this.onDblClick, this);
17753 Roo.EventManager.on(this.checkbox,
17754 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17757 el.on("contextmenu", this.onContextMenu, this);
17759 var icon = Roo.fly(this.iconNode);
17760 icon.on("click", this.onClick, this);
17761 icon.on("dblclick", this.onDblClick, this);
17762 icon.on("contextmenu", this.onContextMenu, this);
17763 E.on(this.ecNode, "click", this.ecClick, this, true);
17765 if(this.node.disabled){
17766 this.addClass("x-tree-node-disabled");
17768 if(this.node.hidden){
17769 this.addClass("x-tree-node-disabled");
17771 var ot = this.node.getOwnerTree();
17772 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17773 if(dd && (!this.node.isRoot || ot.rootVisible)){
17774 Roo.dd.Registry.register(this.elNode, {
17776 handles: this.getDDHandles(),
17782 getDDHandles : function(){
17783 return [this.iconNode, this.textNode];
17788 this.wrap.style.display = "none";
17794 this.wrap.style.display = "";
17798 onContextMenu : function(e){
17799 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17800 e.preventDefault();
17802 this.fireEvent("contextmenu", this.node, e);
17806 onClick : function(e){
17811 if(this.fireEvent("beforeclick", this.node, e) !== false){
17812 if(!this.disabled && this.node.attributes.href){
17813 this.fireEvent("click", this.node, e);
17816 e.preventDefault();
17821 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17822 this.node.toggle();
17825 this.fireEvent("click", this.node, e);
17831 onDblClick : function(e){
17832 e.preventDefault();
17837 this.toggleCheck();
17839 if(!this.animating && this.node.hasChildNodes()){
17840 this.node.toggle();
17842 this.fireEvent("dblclick", this.node, e);
17845 onCheckChange : function(){
17846 var checked = this.checkbox.checked;
17847 this.node.attributes.checked = checked;
17848 this.fireEvent('checkchange', this.node, checked);
17851 ecClick : function(e){
17852 if(!this.animating && this.node.hasChildNodes()){
17853 this.node.toggle();
17857 startDrop : function(){
17858 this.dropping = true;
17861 // delayed drop so the click event doesn't get fired on a drop
17862 endDrop : function(){
17863 setTimeout(function(){
17864 this.dropping = false;
17865 }.createDelegate(this), 50);
17868 expand : function(){
17869 this.updateExpandIcon();
17870 this.ctNode.style.display = "";
17873 focus : function(){
17874 if(!this.node.preventHScroll){
17875 try{this.anchor.focus();
17877 }else if(!Roo.isIE){
17879 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17880 var l = noscroll.scrollLeft;
17881 this.anchor.focus();
17882 noscroll.scrollLeft = l;
17887 toggleCheck : function(value){
17888 var cb = this.checkbox;
17890 cb.checked = (value === undefined ? !cb.checked : value);
17896 this.anchor.blur();
17900 animExpand : function(callback){
17901 var ct = Roo.get(this.ctNode);
17903 if(!this.node.hasChildNodes()){
17904 this.updateExpandIcon();
17905 this.ctNode.style.display = "";
17906 Roo.callback(callback);
17909 this.animating = true;
17910 this.updateExpandIcon();
17913 callback : function(){
17914 this.animating = false;
17915 Roo.callback(callback);
17918 duration: this.node.ownerTree.duration || .25
17922 highlight : function(){
17923 var tree = this.node.getOwnerTree();
17924 Roo.fly(this.wrap).highlight(
17925 tree.hlColor || "C3DAF9",
17926 {endColor: tree.hlBaseColor}
17930 collapse : function(){
17931 this.updateExpandIcon();
17932 this.ctNode.style.display = "none";
17935 animCollapse : function(callback){
17936 var ct = Roo.get(this.ctNode);
17937 ct.enableDisplayMode('block');
17940 this.animating = true;
17941 this.updateExpandIcon();
17944 callback : function(){
17945 this.animating = false;
17946 Roo.callback(callback);
17949 duration: this.node.ownerTree.duration || .25
17953 getContainer : function(){
17954 return this.ctNode;
17957 getEl : function(){
17961 appendDDGhost : function(ghostNode){
17962 ghostNode.appendChild(this.elNode.cloneNode(true));
17965 getDDRepairXY : function(){
17966 return Roo.lib.Dom.getXY(this.iconNode);
17969 onRender : function(){
17973 render : function(bulkRender){
17974 var n = this.node, a = n.attributes;
17975 var targetNode = n.parentNode ?
17976 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17978 if(!this.rendered){
17979 this.rendered = true;
17981 this.renderElements(n, a, targetNode, bulkRender);
17984 if(this.textNode.setAttributeNS){
17985 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17987 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17990 this.textNode.setAttribute("ext:qtip", a.qtip);
17992 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17995 }else if(a.qtipCfg){
17996 a.qtipCfg.target = Roo.id(this.textNode);
17997 Roo.QuickTips.register(a.qtipCfg);
18000 if(!this.node.expanded){
18001 this.updateExpandIcon();
18004 if(bulkRender === true) {
18005 targetNode.appendChild(this.wrap);
18010 renderElements : function(n, a, targetNode, bulkRender){
18011 // add some indent caching, this helps performance when rendering a large tree
18012 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18013 var t = n.getOwnerTree();
18014 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18015 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18016 var cb = typeof a.checked == 'boolean';
18017 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18018 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18019 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18020 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18021 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18022 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18023 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18024 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18025 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18026 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18029 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18030 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18031 n.nextSibling.ui.getEl(), buf.join(""));
18033 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18036 this.elNode = this.wrap.childNodes[0];
18037 this.ctNode = this.wrap.childNodes[1];
18038 var cs = this.elNode.childNodes;
18039 this.indentNode = cs[0];
18040 this.ecNode = cs[1];
18041 this.iconNode = cs[2];
18044 this.checkbox = cs[3];
18047 this.anchor = cs[index];
18048 this.textNode = cs[index].firstChild;
18051 getAnchor : function(){
18052 return this.anchor;
18055 getTextEl : function(){
18056 return this.textNode;
18059 getIconEl : function(){
18060 return this.iconNode;
18063 isChecked : function(){
18064 return this.checkbox ? this.checkbox.checked : false;
18067 updateExpandIcon : function(){
18069 var n = this.node, c1, c2;
18070 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18071 var hasChild = n.hasChildNodes();
18075 c1 = "x-tree-node-collapsed";
18076 c2 = "x-tree-node-expanded";
18079 c1 = "x-tree-node-expanded";
18080 c2 = "x-tree-node-collapsed";
18083 this.removeClass("x-tree-node-leaf");
18084 this.wasLeaf = false;
18086 if(this.c1 != c1 || this.c2 != c2){
18087 Roo.fly(this.elNode).replaceClass(c1, c2);
18088 this.c1 = c1; this.c2 = c2;
18092 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18095 this.wasLeaf = true;
18098 var ecc = "x-tree-ec-icon "+cls;
18099 if(this.ecc != ecc){
18100 this.ecNode.className = ecc;
18106 getChildIndent : function(){
18107 if(!this.childIndent){
18111 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18113 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18115 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18120 this.childIndent = buf.join("");
18122 return this.childIndent;
18125 renderIndent : function(){
18128 var p = this.node.parentNode;
18130 indent = p.ui.getChildIndent();
18132 if(this.indentMarkup != indent){ // don't rerender if not required
18133 this.indentNode.innerHTML = indent;
18134 this.indentMarkup = indent;
18136 this.updateExpandIcon();
18141 Roo.tree.RootTreeNodeUI = function(){
18142 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18144 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18145 render : function(){
18146 if(!this.rendered){
18147 var targetNode = this.node.ownerTree.innerCt.dom;
18148 this.node.expanded = true;
18149 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18150 this.wrap = this.ctNode = targetNode.firstChild;
18153 collapse : function(){
18155 expand : function(){
18159 * Ext JS Library 1.1.1
18160 * Copyright(c) 2006-2007, Ext JS, LLC.
18162 * Originally Released Under LGPL - original licence link has changed is not relivant.
18165 * <script type="text/javascript">
18168 * @class Roo.tree.TreeLoader
18169 * @extends Roo.util.Observable
18170 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18171 * nodes from a specified URL. The response must be a javascript Array definition
18172 * who's elements are node definition objects. eg:
18174 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18175 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18178 * A server request is sent, and child nodes are loaded only when a node is expanded.
18179 * The loading node's id is passed to the server under the parameter name "node" to
18180 * enable the server to produce the correct child nodes.
18182 * To pass extra parameters, an event handler may be attached to the "beforeload"
18183 * event, and the parameters specified in the TreeLoader's baseParams property:
18185 myTreeLoader.on("beforeload", function(treeLoader, node) {
18186 this.baseParams.category = node.attributes.category;
18189 * This would pass an HTTP parameter called "category" to the server containing
18190 * the value of the Node's "category" attribute.
18192 * Creates a new Treeloader.
18193 * @param {Object} config A config object containing config properties.
18195 Roo.tree.TreeLoader = function(config){
18196 this.baseParams = {};
18197 this.requestMethod = "POST";
18198 Roo.apply(this, config);
18203 * @event beforeload
18204 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18205 * @param {Object} This TreeLoader object.
18206 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18207 * @param {Object} callback The callback function specified in the {@link #load} call.
18212 * Fires when the node has been successfuly loaded.
18213 * @param {Object} This TreeLoader object.
18214 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18215 * @param {Object} response The response object containing the data from the server.
18219 * @event loadexception
18220 * Fires if the network request failed.
18221 * @param {Object} This TreeLoader object.
18222 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18223 * @param {Object} response The response object containing the data from the server.
18225 loadexception : true,
18228 * Fires before a node is created, enabling you to return custom Node types
18229 * @param {Object} This TreeLoader object.
18230 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18235 Roo.tree.TreeLoader.superclass.constructor.call(this);
18238 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18240 * @cfg {String} dataUrl The URL from which to request a Json string which
18241 * specifies an array of node definition object representing the child nodes
18245 * @cfg {Object} baseParams (optional) An object containing properties which
18246 * specify HTTP parameters to be passed to each request for child nodes.
18249 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18250 * created by this loader. If the attributes sent by the server have an attribute in this object,
18251 * they take priority.
18254 * @cfg {Object} uiProviders (optional) An object containing properties which
18256 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18257 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18258 * <i>uiProvider</i> attribute of a returned child node is a string rather
18259 * than a reference to a TreeNodeUI implementation, this that string value
18260 * is used as a property name in the uiProviders object. You can define the provider named
18261 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18266 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18267 * child nodes before loading.
18269 clearOnLoad : true,
18272 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18273 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18274 * Grid query { data : [ .....] }
18279 * @cfg {String} queryParam (optional)
18280 * Name of the query as it will be passed on the querystring (defaults to 'node')
18281 * eg. the request will be ?node=[id]
18288 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18289 * This is called automatically when a node is expanded, but may be used to reload
18290 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18291 * @param {Roo.tree.TreeNode} node
18292 * @param {Function} callback
18294 load : function(node, callback){
18295 if(this.clearOnLoad){
18296 while(node.firstChild){
18297 node.removeChild(node.firstChild);
18300 if(node.attributes.children){ // preloaded json children
18301 var cs = node.attributes.children;
18302 for(var i = 0, len = cs.length; i < len; i++){
18303 node.appendChild(this.createNode(cs[i]));
18305 if(typeof callback == "function"){
18308 }else if(this.dataUrl){
18309 this.requestData(node, callback);
18313 getParams: function(node){
18314 var buf = [], bp = this.baseParams;
18315 for(var key in bp){
18316 if(typeof bp[key] != "function"){
18317 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18320 var n = this.queryParam === false ? 'node' : this.queryParam;
18321 buf.push(n + "=", encodeURIComponent(node.id));
18322 return buf.join("");
18325 requestData : function(node, callback){
18326 if(this.fireEvent("beforeload", this, node, callback) !== false){
18327 this.transId = Roo.Ajax.request({
18328 method:this.requestMethod,
18329 url: this.dataUrl||this.url,
18330 success: this.handleResponse,
18331 failure: this.handleFailure,
18333 argument: {callback: callback, node: node},
18334 params: this.getParams(node)
18337 // if the load is cancelled, make sure we notify
18338 // the node that we are done
18339 if(typeof callback == "function"){
18345 isLoading : function(){
18346 return this.transId ? true : false;
18349 abort : function(){
18350 if(this.isLoading()){
18351 Roo.Ajax.abort(this.transId);
18356 createNode : function(attr){
18357 // apply baseAttrs, nice idea Corey!
18358 if(this.baseAttrs){
18359 Roo.applyIf(attr, this.baseAttrs);
18361 if(this.applyLoader !== false){
18362 attr.loader = this;
18364 // uiProvider = depreciated..
18366 if(typeof(attr.uiProvider) == 'string'){
18367 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18368 /** eval:var:attr */ eval(attr.uiProvider);
18370 if(typeof(this.uiProviders['default']) != 'undefined') {
18371 attr.uiProvider = this.uiProviders['default'];
18374 this.fireEvent('create', this, attr);
18376 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18378 new Roo.tree.TreeNode(attr) :
18379 new Roo.tree.AsyncTreeNode(attr));
18382 processResponse : function(response, node, callback){
18383 var json = response.responseText;
18386 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18387 if (this.root !== false) {
18391 for(var i = 0, len = o.length; i < len; i++){
18392 var n = this.createNode(o[i]);
18394 node.appendChild(n);
18397 if(typeof callback == "function"){
18398 callback(this, node);
18401 this.handleFailure(response);
18405 handleResponse : function(response){
18406 this.transId = false;
18407 var a = response.argument;
18408 this.processResponse(response, a.node, a.callback);
18409 this.fireEvent("load", this, a.node, response);
18412 handleFailure : function(response){
18413 this.transId = false;
18414 var a = response.argument;
18415 this.fireEvent("loadexception", this, a.node, response);
18416 if(typeof a.callback == "function"){
18417 a.callback(this, a.node);
18422 * Ext JS Library 1.1.1
18423 * Copyright(c) 2006-2007, Ext JS, LLC.
18425 * Originally Released Under LGPL - original licence link has changed is not relivant.
18428 * <script type="text/javascript">
18432 * @class Roo.tree.TreeFilter
18433 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18434 * @param {TreePanel} tree
18435 * @param {Object} config (optional)
18437 Roo.tree.TreeFilter = function(tree, config){
18439 this.filtered = {};
18440 Roo.apply(this, config);
18443 Roo.tree.TreeFilter.prototype = {
18450 * Filter the data by a specific attribute.
18451 * @param {String/RegExp} value Either string that the attribute value
18452 * should start with or a RegExp to test against the attribute
18453 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18454 * @param {TreeNode} startNode (optional) The node to start the filter at.
18456 filter : function(value, attr, startNode){
18457 attr = attr || "text";
18459 if(typeof value == "string"){
18460 var vlen = value.length;
18461 // auto clear empty filter
18462 if(vlen == 0 && this.clearBlank){
18466 value = value.toLowerCase();
18468 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18470 }else if(value.exec){ // regex?
18472 return value.test(n.attributes[attr]);
18475 throw 'Illegal filter type, must be string or regex';
18477 this.filterBy(f, null, startNode);
18481 * Filter by a function. The passed function will be called with each
18482 * node in the tree (or from the startNode). If the function returns true, the node is kept
18483 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18484 * @param {Function} fn The filter function
18485 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18487 filterBy : function(fn, scope, startNode){
18488 startNode = startNode || this.tree.root;
18489 if(this.autoClear){
18492 var af = this.filtered, rv = this.reverse;
18493 var f = function(n){
18494 if(n == startNode){
18500 var m = fn.call(scope || n, n);
18508 startNode.cascade(f);
18511 if(typeof id != "function"){
18513 if(n && n.parentNode){
18514 n.parentNode.removeChild(n);
18522 * Clears the current filter. Note: with the "remove" option
18523 * set a filter cannot be cleared.
18525 clear : function(){
18527 var af = this.filtered;
18529 if(typeof id != "function"){
18536 this.filtered = {};
18541 * Ext JS Library 1.1.1
18542 * Copyright(c) 2006-2007, Ext JS, LLC.
18544 * Originally Released Under LGPL - original licence link has changed is not relivant.
18547 * <script type="text/javascript">
18552 * @class Roo.tree.TreeSorter
18553 * Provides sorting of nodes in a TreePanel
18555 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18556 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18557 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18558 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18559 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18560 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18562 * @param {TreePanel} tree
18563 * @param {Object} config
18565 Roo.tree.TreeSorter = function(tree, config){
18566 Roo.apply(this, config);
18567 tree.on("beforechildrenrendered", this.doSort, this);
18568 tree.on("append", this.updateSort, this);
18569 tree.on("insert", this.updateSort, this);
18571 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18572 var p = this.property || "text";
18573 var sortType = this.sortType;
18574 var fs = this.folderSort;
18575 var cs = this.caseSensitive === true;
18576 var leafAttr = this.leafAttr || 'leaf';
18578 this.sortFn = function(n1, n2){
18580 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18583 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18587 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18588 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18590 return dsc ? +1 : -1;
18592 return dsc ? -1 : +1;
18599 Roo.tree.TreeSorter.prototype = {
18600 doSort : function(node){
18601 node.sort(this.sortFn);
18604 compareNodes : function(n1, n2){
18605 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18608 updateSort : function(tree, node){
18609 if(node.childrenRendered){
18610 this.doSort.defer(1, this, [node]);
18615 * Ext JS Library 1.1.1
18616 * Copyright(c) 2006-2007, Ext JS, LLC.
18618 * Originally Released Under LGPL - original licence link has changed is not relivant.
18621 * <script type="text/javascript">
18624 if(Roo.dd.DropZone){
18626 Roo.tree.TreeDropZone = function(tree, config){
18627 this.allowParentInsert = false;
18628 this.allowContainerDrop = false;
18629 this.appendOnly = false;
18630 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18632 this.lastInsertClass = "x-tree-no-status";
18633 this.dragOverData = {};
18636 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18637 ddGroup : "TreeDD",
18639 expandDelay : 1000,
18641 expandNode : function(node){
18642 if(node.hasChildNodes() && !node.isExpanded()){
18643 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18647 queueExpand : function(node){
18648 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18651 cancelExpand : function(){
18652 if(this.expandProcId){
18653 clearTimeout(this.expandProcId);
18654 this.expandProcId = false;
18658 isValidDropPoint : function(n, pt, dd, e, data){
18659 if(!n || !data){ return false; }
18660 var targetNode = n.node;
18661 var dropNode = data.node;
18662 // default drop rules
18663 if(!(targetNode && targetNode.isTarget && pt)){
18666 if(pt == "append" && targetNode.allowChildren === false){
18669 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18672 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18675 // reuse the object
18676 var overEvent = this.dragOverData;
18677 overEvent.tree = this.tree;
18678 overEvent.target = targetNode;
18679 overEvent.data = data;
18680 overEvent.point = pt;
18681 overEvent.source = dd;
18682 overEvent.rawEvent = e;
18683 overEvent.dropNode = dropNode;
18684 overEvent.cancel = false;
18685 var result = this.tree.fireEvent("nodedragover", overEvent);
18686 return overEvent.cancel === false && result !== false;
18689 getDropPoint : function(e, n, dd){
18692 return tn.allowChildren !== false ? "append" : false; // always append for root
18694 var dragEl = n.ddel;
18695 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18696 var y = Roo.lib.Event.getPageY(e);
18697 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18699 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18700 var noAppend = tn.allowChildren === false;
18701 if(this.appendOnly || tn.parentNode.allowChildren === false){
18702 return noAppend ? false : "append";
18704 var noBelow = false;
18705 if(!this.allowParentInsert){
18706 noBelow = tn.hasChildNodes() && tn.isExpanded();
18708 var q = (b - t) / (noAppend ? 2 : 3);
18709 if(y >= t && y < (t + q)){
18711 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18718 onNodeEnter : function(n, dd, e, data){
18719 this.cancelExpand();
18722 onNodeOver : function(n, dd, e, data){
18723 var pt = this.getDropPoint(e, n, dd);
18726 // auto node expand check
18727 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18728 this.queueExpand(node);
18729 }else if(pt != "append"){
18730 this.cancelExpand();
18733 // set the insert point style on the target node
18734 var returnCls = this.dropNotAllowed;
18735 if(this.isValidDropPoint(n, pt, dd, e, data)){
18740 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18741 cls = "x-tree-drag-insert-above";
18742 }else if(pt == "below"){
18743 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18744 cls = "x-tree-drag-insert-below";
18746 returnCls = "x-tree-drop-ok-append";
18747 cls = "x-tree-drag-append";
18749 if(this.lastInsertClass != cls){
18750 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18751 this.lastInsertClass = cls;
18758 onNodeOut : function(n, dd, e, data){
18759 this.cancelExpand();
18760 this.removeDropIndicators(n);
18763 onNodeDrop : function(n, dd, e, data){
18764 var point = this.getDropPoint(e, n, dd);
18765 var targetNode = n.node;
18766 targetNode.ui.startDrop();
18767 if(!this.isValidDropPoint(n, point, dd, e, data)){
18768 targetNode.ui.endDrop();
18771 // first try to find the drop node
18772 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18775 target: targetNode,
18780 dropNode: dropNode,
18783 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18784 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18785 targetNode.ui.endDrop();
18788 // allow target changing
18789 targetNode = dropEvent.target;
18790 if(point == "append" && !targetNode.isExpanded()){
18791 targetNode.expand(false, null, function(){
18792 this.completeDrop(dropEvent);
18793 }.createDelegate(this));
18795 this.completeDrop(dropEvent);
18800 completeDrop : function(de){
18801 var ns = de.dropNode, p = de.point, t = de.target;
18802 if(!(ns instanceof Array)){
18806 for(var i = 0, len = ns.length; i < len; i++){
18809 t.parentNode.insertBefore(n, t);
18810 }else if(p == "below"){
18811 t.parentNode.insertBefore(n, t.nextSibling);
18817 if(this.tree.hlDrop){
18821 this.tree.fireEvent("nodedrop", de);
18824 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18825 if(this.tree.hlDrop){
18826 dropNode.ui.focus();
18827 dropNode.ui.highlight();
18829 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18832 getTree : function(){
18836 removeDropIndicators : function(n){
18839 Roo.fly(el).removeClass([
18840 "x-tree-drag-insert-above",
18841 "x-tree-drag-insert-below",
18842 "x-tree-drag-append"]);
18843 this.lastInsertClass = "_noclass";
18847 beforeDragDrop : function(target, e, id){
18848 this.cancelExpand();
18852 afterRepair : function(data){
18853 if(data && Roo.enableFx){
18854 data.node.ui.highlight();
18863 * Ext JS Library 1.1.1
18864 * Copyright(c) 2006-2007, Ext JS, LLC.
18866 * Originally Released Under LGPL - original licence link has changed is not relivant.
18869 * <script type="text/javascript">
18873 if(Roo.dd.DragZone){
18874 Roo.tree.TreeDragZone = function(tree, config){
18875 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18879 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18880 ddGroup : "TreeDD",
18882 onBeforeDrag : function(data, e){
18884 return n && n.draggable && !n.disabled;
18887 onInitDrag : function(e){
18888 var data = this.dragData;
18889 this.tree.getSelectionModel().select(data.node);
18890 this.proxy.update("");
18891 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18892 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18895 getRepairXY : function(e, data){
18896 return data.node.ui.getDDRepairXY();
18899 onEndDrag : function(data, e){
18900 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18903 onValidDrop : function(dd, e, id){
18904 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18908 beforeInvalidDrop : function(e, id){
18909 // this scrolls the original position back into view
18910 var sm = this.tree.getSelectionModel();
18911 sm.clearSelections();
18912 sm.select(this.dragData.node);
18917 * Ext JS Library 1.1.1
18918 * Copyright(c) 2006-2007, Ext JS, LLC.
18920 * Originally Released Under LGPL - original licence link has changed is not relivant.
18923 * <script type="text/javascript">
18926 * @class Roo.tree.TreeEditor
18927 * @extends Roo.Editor
18928 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18929 * as the editor field.
18931 * @param {TreePanel} tree
18932 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18934 Roo.tree.TreeEditor = function(tree, config){
18935 config = config || {};
18936 var field = config.events ? config : new Roo.form.TextField(config);
18937 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18941 tree.on('beforeclick', this.beforeNodeClick, this);
18942 tree.getTreeEl().on('mousedown', this.hide, this);
18943 this.on('complete', this.updateNode, this);
18944 this.on('beforestartedit', this.fitToTree, this);
18945 this.on('startedit', this.bindScroll, this, {delay:10});
18946 this.on('specialkey', this.onSpecialKey, this);
18949 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18951 * @cfg {String} alignment
18952 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18958 * @cfg {Boolean} hideEl
18959 * True to hide the bound element while the editor is displayed (defaults to false)
18963 * @cfg {String} cls
18964 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18966 cls: "x-small-editor x-tree-editor",
18968 * @cfg {Boolean} shim
18969 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18975 * @cfg {Number} maxWidth
18976 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18977 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18978 * scroll and client offsets into account prior to each edit.
18985 fitToTree : function(ed, el){
18986 var td = this.tree.getTreeEl().dom, nd = el.dom;
18987 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
18988 td.scrollLeft = nd.offsetLeft;
18992 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
18993 this.setSize(w, '');
18997 triggerEdit : function(node){
18998 this.completeEdit();
18999 this.editNode = node;
19000 this.startEdit(node.ui.textNode, node.text);
19004 bindScroll : function(){
19005 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19009 beforeNodeClick : function(node, e){
19010 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19011 this.lastClick = new Date();
19012 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19014 this.triggerEdit(node);
19020 updateNode : function(ed, value){
19021 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19022 this.editNode.setText(value);
19026 onHide : function(){
19027 Roo.tree.TreeEditor.superclass.onHide.call(this);
19029 this.editNode.ui.focus();
19034 onSpecialKey : function(field, e){
19035 var k = e.getKey();
19039 }else if(k == e.ENTER && !e.hasModifier()){
19041 this.completeEdit();
19044 });//<Script type="text/javascript">
19047 * Ext JS Library 1.1.1
19048 * Copyright(c) 2006-2007, Ext JS, LLC.
19050 * Originally Released Under LGPL - original licence link has changed is not relivant.
19053 * <script type="text/javascript">
19057 * Not documented??? - probably should be...
19060 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19061 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19063 renderElements : function(n, a, targetNode, bulkRender){
19064 //consel.log("renderElements?");
19065 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19067 var t = n.getOwnerTree();
19068 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19070 var cols = t.columns;
19071 var bw = t.borderWidth;
19073 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19074 var cb = typeof a.checked == "boolean";
19075 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19076 var colcls = 'x-t-' + tid + '-c0';
19078 '<li class="x-tree-node">',
19081 '<div class="x-tree-node-el ', a.cls,'">',
19083 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19086 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19087 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19088 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19089 (a.icon ? ' x-tree-node-inline-icon' : ''),
19090 (a.iconCls ? ' '+a.iconCls : ''),
19091 '" unselectable="on" />',
19092 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19093 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19095 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19096 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19097 '<span unselectable="on" qtip="' + tx + '">',
19101 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19102 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19104 for(var i = 1, len = cols.length; i < len; i++){
19106 colcls = 'x-t-' + tid + '-c' +i;
19107 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19108 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19109 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19115 '<div class="x-clear"></div></div>',
19116 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19119 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19120 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19121 n.nextSibling.ui.getEl(), buf.join(""));
19123 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19125 var el = this.wrap.firstChild;
19127 this.elNode = el.firstChild;
19128 this.ranchor = el.childNodes[1];
19129 this.ctNode = this.wrap.childNodes[1];
19130 var cs = el.firstChild.childNodes;
19131 this.indentNode = cs[0];
19132 this.ecNode = cs[1];
19133 this.iconNode = cs[2];
19136 this.checkbox = cs[3];
19139 this.anchor = cs[index];
19141 this.textNode = cs[index].firstChild;
19143 //el.on("click", this.onClick, this);
19144 //el.on("dblclick", this.onDblClick, this);
19147 // console.log(this);
19149 initEvents : function(){
19150 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19153 var a = this.ranchor;
19155 var el = Roo.get(a);
19157 if(Roo.isOpera){ // opera render bug ignores the CSS
19158 el.setStyle("text-decoration", "none");
19161 el.on("click", this.onClick, this);
19162 el.on("dblclick", this.onDblClick, this);
19163 el.on("contextmenu", this.onContextMenu, this);
19167 /*onSelectedChange : function(state){
19170 this.addClass("x-tree-selected");
19173 this.removeClass("x-tree-selected");
19176 addClass : function(cls){
19178 Roo.fly(this.elRow).addClass(cls);
19184 removeClass : function(cls){
19186 Roo.fly(this.elRow).removeClass(cls);
19192 });//<Script type="text/javascript">
19196 * Ext JS Library 1.1.1
19197 * Copyright(c) 2006-2007, Ext JS, LLC.
19199 * Originally Released Under LGPL - original licence link has changed is not relivant.
19202 * <script type="text/javascript">
19207 * @class Roo.tree.ColumnTree
19208 * @extends Roo.data.TreePanel
19209 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19210 * @cfg {int} borderWidth compined right/left border allowance
19212 * @param {String/HTMLElement/Element} el The container element
19213 * @param {Object} config
19215 Roo.tree.ColumnTree = function(el, config)
19217 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19221 * Fire this event on a container when it resizes
19222 * @param {int} w Width
19223 * @param {int} h Height
19227 this.on('resize', this.onResize, this);
19230 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19234 borderWidth: Roo.isBorderBox ? 0 : 2,
19237 render : function(){
19238 // add the header.....
19240 Roo.tree.ColumnTree.superclass.render.apply(this);
19242 this.el.addClass('x-column-tree');
19244 this.headers = this.el.createChild(
19245 {cls:'x-tree-headers'},this.innerCt.dom);
19247 var cols = this.columns, c;
19248 var totalWidth = 0;
19250 var len = cols.length;
19251 for(var i = 0; i < len; i++){
19253 totalWidth += c.width;
19254 this.headEls.push(this.headers.createChild({
19255 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19257 cls:'x-tree-hd-text',
19260 style:'width:'+(c.width-this.borderWidth)+'px;'
19263 this.headers.createChild({cls:'x-clear'});
19264 // prevent floats from wrapping when clipped
19265 this.headers.setWidth(totalWidth);
19266 //this.innerCt.setWidth(totalWidth);
19267 this.innerCt.setStyle({ overflow: 'auto' });
19268 this.onResize(this.width, this.height);
19272 onResize : function(w,h)
19277 this.innerCt.setWidth(this.width);
19278 this.innerCt.setHeight(this.height-20);
19281 var cols = this.columns, c;
19282 var totalWidth = 0;
19284 var len = cols.length;
19285 for(var i = 0; i < len; i++){
19287 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19288 // it's the expander..
19289 expEl = this.headEls[i];
19292 totalWidth += c.width;
19296 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19298 this.headers.setWidth(w-20);
19307 * Ext JS Library 1.1.1
19308 * Copyright(c) 2006-2007, Ext JS, LLC.
19310 * Originally Released Under LGPL - original licence link has changed is not relivant.
19313 * <script type="text/javascript">
19317 * @class Roo.menu.Menu
19318 * @extends Roo.util.Observable
19319 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19320 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19322 * Creates a new Menu
19323 * @param {Object} config Configuration options
19325 Roo.menu.Menu = function(config){
19326 Roo.apply(this, config);
19327 this.id = this.id || Roo.id();
19330 * @event beforeshow
19331 * Fires before this menu is displayed
19332 * @param {Roo.menu.Menu} this
19336 * @event beforehide
19337 * Fires before this menu is hidden
19338 * @param {Roo.menu.Menu} this
19343 * Fires after this menu is displayed
19344 * @param {Roo.menu.Menu} this
19349 * Fires after this menu is hidden
19350 * @param {Roo.menu.Menu} this
19355 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19356 * @param {Roo.menu.Menu} this
19357 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19358 * @param {Roo.EventObject} e
19363 * Fires when the mouse is hovering over this menu
19364 * @param {Roo.menu.Menu} this
19365 * @param {Roo.EventObject} e
19366 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19371 * Fires when the mouse exits this menu
19372 * @param {Roo.menu.Menu} this
19373 * @param {Roo.EventObject} e
19374 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19379 * Fires when a menu item contained in this menu is clicked
19380 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19381 * @param {Roo.EventObject} e
19385 if (this.registerMenu) {
19386 Roo.menu.MenuMgr.register(this);
19389 var mis = this.items;
19390 this.items = new Roo.util.MixedCollection();
19392 this.add.apply(this, mis);
19396 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19398 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19402 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19403 * for bottom-right shadow (defaults to "sides")
19407 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19408 * this menu (defaults to "tl-tr?")
19410 subMenuAlign : "tl-tr?",
19412 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19413 * relative to its element of origin (defaults to "tl-bl?")
19415 defaultAlign : "tl-bl?",
19417 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19419 allowOtherMenus : false,
19421 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19423 registerMenu : true,
19428 render : function(){
19432 var el = this.el = new Roo.Layer({
19434 shadow:this.shadow,
19436 parentEl: this.parentEl || document.body,
19440 this.keyNav = new Roo.menu.MenuNav(this);
19443 el.addClass("x-menu-plain");
19446 el.addClass(this.cls);
19448 // generic focus element
19449 this.focusEl = el.createChild({
19450 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19452 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19453 ul.on("click", this.onClick, this);
19454 ul.on("mouseover", this.onMouseOver, this);
19455 ul.on("mouseout", this.onMouseOut, this);
19456 this.items.each(function(item){
19457 var li = document.createElement("li");
19458 li.className = "x-menu-list-item";
19459 ul.dom.appendChild(li);
19460 item.render(li, this);
19467 autoWidth : function(){
19468 var el = this.el, ul = this.ul;
19472 var w = this.width;
19475 }else if(Roo.isIE){
19476 el.setWidth(this.minWidth);
19477 var t = el.dom.offsetWidth; // force recalc
19478 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19483 delayAutoWidth : function(){
19486 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19488 this.awTask.delay(20);
19493 findTargetItem : function(e){
19494 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19495 if(t && t.menuItemId){
19496 return this.items.get(t.menuItemId);
19501 onClick : function(e){
19503 if(t = this.findTargetItem(e)){
19505 this.fireEvent("click", this, t, e);
19510 setActiveItem : function(item, autoExpand){
19511 if(item != this.activeItem){
19512 if(this.activeItem){
19513 this.activeItem.deactivate();
19515 this.activeItem = item;
19516 item.activate(autoExpand);
19517 }else if(autoExpand){
19523 tryActivate : function(start, step){
19524 var items = this.items;
19525 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19526 var item = items.get(i);
19527 if(!item.disabled && item.canActivate){
19528 this.setActiveItem(item, false);
19536 onMouseOver : function(e){
19538 if(t = this.findTargetItem(e)){
19539 if(t.canActivate && !t.disabled){
19540 this.setActiveItem(t, true);
19543 this.fireEvent("mouseover", this, e, t);
19547 onMouseOut : function(e){
19549 if(t = this.findTargetItem(e)){
19550 if(t == this.activeItem && t.shouldDeactivate(e)){
19551 this.activeItem.deactivate();
19552 delete this.activeItem;
19555 this.fireEvent("mouseout", this, e, t);
19559 * Read-only. Returns true if the menu is currently displayed, else false.
19562 isVisible : function(){
19563 return this.el && !this.hidden;
19567 * Displays this menu relative to another element
19568 * @param {String/HTMLElement/Roo.Element} element The element to align to
19569 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19570 * the element (defaults to this.defaultAlign)
19571 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19573 show : function(el, pos, parentMenu){
19574 this.parentMenu = parentMenu;
19578 this.fireEvent("beforeshow", this);
19579 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19583 * Displays this menu at a specific xy position
19584 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19585 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19587 showAt : function(xy, parentMenu, /* private: */_e){
19588 this.parentMenu = parentMenu;
19593 this.fireEvent("beforeshow", this);
19594 xy = this.el.adjustForConstraints(xy);
19598 this.hidden = false;
19600 this.fireEvent("show", this);
19603 focus : function(){
19605 this.doFocus.defer(50, this);
19609 doFocus : function(){
19611 this.focusEl.focus();
19616 * Hides this menu and optionally all parent menus
19617 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19619 hide : function(deep){
19620 if(this.el && this.isVisible()){
19621 this.fireEvent("beforehide", this);
19622 if(this.activeItem){
19623 this.activeItem.deactivate();
19624 this.activeItem = null;
19627 this.hidden = true;
19628 this.fireEvent("hide", this);
19630 if(deep === true && this.parentMenu){
19631 this.parentMenu.hide(true);
19636 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19637 * Any of the following are valid:
19639 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19640 * <li>An HTMLElement object which will be converted to a menu item</li>
19641 * <li>A menu item config object that will be created as a new menu item</li>
19642 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19643 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19648 var menu = new Roo.menu.Menu();
19650 // Create a menu item to add by reference
19651 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19653 // Add a bunch of items at once using different methods.
19654 // Only the last item added will be returned.
19655 var item = menu.add(
19656 menuItem, // add existing item by ref
19657 'Dynamic Item', // new TextItem
19658 '-', // new separator
19659 { text: 'Config Item' } // new item by config
19662 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19663 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19666 var a = arguments, l = a.length, item;
19667 for(var i = 0; i < l; i++){
19669 if ((typeof(el) == "object") && el.xtype && el.xns) {
19670 el = Roo.factory(el, Roo.menu);
19673 if(el.render){ // some kind of Item
19674 item = this.addItem(el);
19675 }else if(typeof el == "string"){ // string
19676 if(el == "separator" || el == "-"){
19677 item = this.addSeparator();
19679 item = this.addText(el);
19681 }else if(el.tagName || el.el){ // element
19682 item = this.addElement(el);
19683 }else if(typeof el == "object"){ // must be menu item config?
19684 item = this.addMenuItem(el);
19691 * Returns this menu's underlying {@link Roo.Element} object
19692 * @return {Roo.Element} The element
19694 getEl : function(){
19702 * Adds a separator bar to the menu
19703 * @return {Roo.menu.Item} The menu item that was added
19705 addSeparator : function(){
19706 return this.addItem(new Roo.menu.Separator());
19710 * Adds an {@link Roo.Element} object to the menu
19711 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19712 * @return {Roo.menu.Item} The menu item that was added
19714 addElement : function(el){
19715 return this.addItem(new Roo.menu.BaseItem(el));
19719 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19720 * @param {Roo.menu.Item} item The menu item to add
19721 * @return {Roo.menu.Item} The menu item that was added
19723 addItem : function(item){
19724 this.items.add(item);
19726 var li = document.createElement("li");
19727 li.className = "x-menu-list-item";
19728 this.ul.dom.appendChild(li);
19729 item.render(li, this);
19730 this.delayAutoWidth();
19736 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19737 * @param {Object} config A MenuItem config object
19738 * @return {Roo.menu.Item} The menu item that was added
19740 addMenuItem : function(config){
19741 if(!(config instanceof Roo.menu.Item)){
19742 if(typeof config.checked == "boolean"){ // must be check menu item config?
19743 config = new Roo.menu.CheckItem(config);
19745 config = new Roo.menu.Item(config);
19748 return this.addItem(config);
19752 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19753 * @param {String} text The text to display in the menu item
19754 * @return {Roo.menu.Item} The menu item that was added
19756 addText : function(text){
19757 return this.addItem(new Roo.menu.TextItem({ text : text }));
19761 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19762 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19763 * @param {Roo.menu.Item} item The menu item to add
19764 * @return {Roo.menu.Item} The menu item that was added
19766 insert : function(index, item){
19767 this.items.insert(index, item);
19769 var li = document.createElement("li");
19770 li.className = "x-menu-list-item";
19771 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19772 item.render(li, this);
19773 this.delayAutoWidth();
19779 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19780 * @param {Roo.menu.Item} item The menu item to remove
19782 remove : function(item){
19783 this.items.removeKey(item.id);
19788 * Removes and destroys all items in the menu
19790 removeAll : function(){
19792 while(f = this.items.first()){
19798 // MenuNav is a private utility class used internally by the Menu
19799 Roo.menu.MenuNav = function(menu){
19800 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19801 this.scope = this.menu = menu;
19804 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19805 doRelay : function(e, h){
19806 var k = e.getKey();
19807 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19808 this.menu.tryActivate(0, 1);
19811 return h.call(this.scope || this, e, this.menu);
19814 up : function(e, m){
19815 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19816 m.tryActivate(m.items.length-1, -1);
19820 down : function(e, m){
19821 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19822 m.tryActivate(0, 1);
19826 right : function(e, m){
19828 m.activeItem.expandMenu(true);
19832 left : function(e, m){
19834 if(m.parentMenu && m.parentMenu.activeItem){
19835 m.parentMenu.activeItem.activate();
19839 enter : function(e, m){
19841 e.stopPropagation();
19842 m.activeItem.onClick(e);
19843 m.fireEvent("click", this, m.activeItem);
19849 * Ext JS Library 1.1.1
19850 * Copyright(c) 2006-2007, Ext JS, LLC.
19852 * Originally Released Under LGPL - original licence link has changed is not relivant.
19855 * <script type="text/javascript">
19859 * @class Roo.menu.MenuMgr
19860 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19863 Roo.menu.MenuMgr = function(){
19864 var menus, active, groups = {}, attached = false, lastShow = new Date();
19866 // private - called when first menu is created
19869 active = new Roo.util.MixedCollection();
19870 Roo.get(document).addKeyListener(27, function(){
19871 if(active.length > 0){
19878 function hideAll(){
19879 if(active && active.length > 0){
19880 var c = active.clone();
19881 c.each(function(m){
19888 function onHide(m){
19890 if(active.length < 1){
19891 Roo.get(document).un("mousedown", onMouseDown);
19897 function onShow(m){
19898 var last = active.last();
19899 lastShow = new Date();
19902 Roo.get(document).on("mousedown", onMouseDown);
19906 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19907 m.parentMenu.activeChild = m;
19908 }else if(last && last.isVisible()){
19909 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19914 function onBeforeHide(m){
19916 m.activeChild.hide();
19918 if(m.autoHideTimer){
19919 clearTimeout(m.autoHideTimer);
19920 delete m.autoHideTimer;
19925 function onBeforeShow(m){
19926 var pm = m.parentMenu;
19927 if(!pm && !m.allowOtherMenus){
19929 }else if(pm && pm.activeChild && active != m){
19930 pm.activeChild.hide();
19935 function onMouseDown(e){
19936 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19942 function onBeforeCheck(mi, state){
19944 var g = groups[mi.group];
19945 for(var i = 0, l = g.length; i < l; i++){
19947 g[i].setChecked(false);
19956 * Hides all menus that are currently visible
19958 hideAll : function(){
19963 register : function(menu){
19967 menus[menu.id] = menu;
19968 menu.on("beforehide", onBeforeHide);
19969 menu.on("hide", onHide);
19970 menu.on("beforeshow", onBeforeShow);
19971 menu.on("show", onShow);
19972 var g = menu.group;
19973 if(g && menu.events["checkchange"]){
19977 groups[g].push(menu);
19978 menu.on("checkchange", onCheck);
19983 * Returns a {@link Roo.menu.Menu} object
19984 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19985 * be used to generate and return a new Menu instance.
19987 get : function(menu){
19988 if(typeof menu == "string"){ // menu id
19989 return menus[menu];
19990 }else if(menu.events){ // menu instance
19992 }else if(typeof menu.length == 'number'){ // array of menu items?
19993 return new Roo.menu.Menu({items:menu});
19994 }else{ // otherwise, must be a config
19995 return new Roo.menu.Menu(menu);
20000 unregister : function(menu){
20001 delete menus[menu.id];
20002 menu.un("beforehide", onBeforeHide);
20003 menu.un("hide", onHide);
20004 menu.un("beforeshow", onBeforeShow);
20005 menu.un("show", onShow);
20006 var g = menu.group;
20007 if(g && menu.events["checkchange"]){
20008 groups[g].remove(menu);
20009 menu.un("checkchange", onCheck);
20014 registerCheckable : function(menuItem){
20015 var g = menuItem.group;
20020 groups[g].push(menuItem);
20021 menuItem.on("beforecheckchange", onBeforeCheck);
20026 unregisterCheckable : function(menuItem){
20027 var g = menuItem.group;
20029 groups[g].remove(menuItem);
20030 menuItem.un("beforecheckchange", onBeforeCheck);
20036 * Ext JS Library 1.1.1
20037 * Copyright(c) 2006-2007, Ext JS, LLC.
20039 * Originally Released Under LGPL - original licence link has changed is not relivant.
20042 * <script type="text/javascript">
20047 * @class Roo.menu.BaseItem
20048 * @extends Roo.Component
20049 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20050 * management and base configuration options shared by all menu components.
20052 * Creates a new BaseItem
20053 * @param {Object} config Configuration options
20055 Roo.menu.BaseItem = function(config){
20056 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20061 * Fires when this item is clicked
20062 * @param {Roo.menu.BaseItem} this
20063 * @param {Roo.EventObject} e
20068 * Fires when this item is activated
20069 * @param {Roo.menu.BaseItem} this
20073 * @event deactivate
20074 * Fires when this item is deactivated
20075 * @param {Roo.menu.BaseItem} this
20081 this.on("click", this.handler, this.scope, true);
20085 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20087 * @cfg {Function} handler
20088 * A function that will handle the click event of this menu item (defaults to undefined)
20091 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20093 canActivate : false,
20095 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20097 activeClass : "x-menu-item-active",
20099 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20101 hideOnClick : true,
20103 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20108 ctype: "Roo.menu.BaseItem",
20111 actionMode : "container",
20114 render : function(container, parentMenu){
20115 this.parentMenu = parentMenu;
20116 Roo.menu.BaseItem.superclass.render.call(this, container);
20117 this.container.menuItemId = this.id;
20121 onRender : function(container, position){
20122 this.el = Roo.get(this.el);
20123 container.dom.appendChild(this.el.dom);
20127 onClick : function(e){
20128 if(!this.disabled && this.fireEvent("click", this, e) !== false
20129 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20130 this.handleClick(e);
20137 activate : function(){
20141 var li = this.container;
20142 li.addClass(this.activeClass);
20143 this.region = li.getRegion().adjust(2, 2, -2, -2);
20144 this.fireEvent("activate", this);
20149 deactivate : function(){
20150 this.container.removeClass(this.activeClass);
20151 this.fireEvent("deactivate", this);
20155 shouldDeactivate : function(e){
20156 return !this.region || !this.region.contains(e.getPoint());
20160 handleClick : function(e){
20161 if(this.hideOnClick){
20162 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20167 expandMenu : function(autoActivate){
20172 hideMenu : function(){
20177 * Ext JS Library 1.1.1
20178 * Copyright(c) 2006-2007, Ext JS, LLC.
20180 * Originally Released Under LGPL - original licence link has changed is not relivant.
20183 * <script type="text/javascript">
20187 * @class Roo.menu.Adapter
20188 * @extends Roo.menu.BaseItem
20189 * A base utility class that adapts a non-menu component so that it can be wrapped by a menu item and added to a menu.
20190 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20192 * Creates a new Adapter
20193 * @param {Object} config Configuration options
20195 Roo.menu.Adapter = function(component, config){
20196 Roo.menu.Adapter.superclass.constructor.call(this, config);
20197 this.component = component;
20199 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20201 canActivate : true,
20204 onRender : function(container, position){
20205 this.component.render(container);
20206 this.el = this.component.getEl();
20210 activate : function(){
20214 this.component.focus();
20215 this.fireEvent("activate", this);
20220 deactivate : function(){
20221 this.fireEvent("deactivate", this);
20225 disable : function(){
20226 this.component.disable();
20227 Roo.menu.Adapter.superclass.disable.call(this);
20231 enable : function(){
20232 this.component.enable();
20233 Roo.menu.Adapter.superclass.enable.call(this);
20237 * Ext JS Library 1.1.1
20238 * Copyright(c) 2006-2007, Ext JS, LLC.
20240 * Originally Released Under LGPL - original licence link has changed is not relivant.
20243 * <script type="text/javascript">
20247 * @class Roo.menu.TextItem
20248 * @extends Roo.menu.BaseItem
20249 * Adds a static text string to a menu, usually used as either a heading or group separator.
20250 * Note: old style constructor with text is still supported.
20253 * Creates a new TextItem
20254 * @param {Object} cfg Configuration
20256 Roo.menu.TextItem = function(cfg){
20257 if (typeof(cfg) == 'string') {
20260 Roo.apply(this,cfg);
20263 Roo.menu.TextItem.superclass.constructor.call(this);
20266 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20268 * @cfg {Boolean} text Text to show on item.
20273 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20275 hideOnClick : false,
20277 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20279 itemCls : "x-menu-text",
20282 onRender : function(){
20283 var s = document.createElement("span");
20284 s.className = this.itemCls;
20285 s.innerHTML = this.text;
20287 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20291 * Ext JS Library 1.1.1
20292 * Copyright(c) 2006-2007, Ext JS, LLC.
20294 * Originally Released Under LGPL - original licence link has changed is not relivant.
20297 * <script type="text/javascript">
20301 * @class Roo.menu.Separator
20302 * @extends Roo.menu.BaseItem
20303 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20304 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20306 * @param {Object} config Configuration options
20308 Roo.menu.Separator = function(config){
20309 Roo.menu.Separator.superclass.constructor.call(this, config);
20312 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20314 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20316 itemCls : "x-menu-sep",
20318 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20320 hideOnClick : false,
20323 onRender : function(li){
20324 var s = document.createElement("span");
20325 s.className = this.itemCls;
20326 s.innerHTML = " ";
20328 li.addClass("x-menu-sep-li");
20329 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20333 * Ext JS Library 1.1.1
20334 * Copyright(c) 2006-2007, Ext JS, LLC.
20336 * Originally Released Under LGPL - original licence link has changed is not relivant.
20339 * <script type="text/javascript">
20342 * @class Roo.menu.Item
20343 * @extends Roo.menu.BaseItem
20344 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20345 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20346 * activation and click handling.
20348 * Creates a new Item
20349 * @param {Object} config Configuration options
20351 Roo.menu.Item = function(config){
20352 Roo.menu.Item.superclass.constructor.call(this, config);
20354 this.menu = Roo.menu.MenuMgr.get(this.menu);
20357 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20360 * @cfg {String} text
20361 * The text to show on the menu item.
20365 * @cfg {String} HTML to render in menu
20366 * The text to show on the menu item (HTML version).
20370 * @cfg {String} icon
20371 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20375 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20377 itemCls : "x-menu-item",
20379 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20381 canActivate : true,
20383 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20386 // doc'd in BaseItem
20390 ctype: "Roo.menu.Item",
20393 onRender : function(container, position){
20394 var el = document.createElement("a");
20395 el.hideFocus = true;
20396 el.unselectable = "on";
20397 el.href = this.href || "#";
20398 if(this.hrefTarget){
20399 el.target = this.hrefTarget;
20401 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20403 var html = this.html.length ? this.html : String.format('{0}',this.text);
20405 el.innerHTML = String.format(
20406 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20407 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20409 Roo.menu.Item.superclass.onRender.call(this, container, position);
20413 * Sets the text to display in this menu item
20414 * @param {String} text The text to display
20415 * @param {Boolean} isHTML true to indicate text is pure html.
20417 setText : function(text, isHTML){
20425 var html = this.html.length ? this.html : String.format('{0}',this.text);
20427 this.el.update(String.format(
20428 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20429 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20430 this.parentMenu.autoWidth();
20435 handleClick : function(e){
20436 if(!this.href){ // if no link defined, stop the event automatically
20439 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20443 activate : function(autoExpand){
20444 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20454 shouldDeactivate : function(e){
20455 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20456 if(this.menu && this.menu.isVisible()){
20457 return !this.menu.getEl().getRegion().contains(e.getPoint());
20465 deactivate : function(){
20466 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20471 expandMenu : function(autoActivate){
20472 if(!this.disabled && this.menu){
20473 clearTimeout(this.hideTimer);
20474 delete this.hideTimer;
20475 if(!this.menu.isVisible() && !this.showTimer){
20476 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20477 }else if (this.menu.isVisible() && autoActivate){
20478 this.menu.tryActivate(0, 1);
20484 deferExpand : function(autoActivate){
20485 delete this.showTimer;
20486 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20488 this.menu.tryActivate(0, 1);
20493 hideMenu : function(){
20494 clearTimeout(this.showTimer);
20495 delete this.showTimer;
20496 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20497 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20502 deferHide : function(){
20503 delete this.hideTimer;
20508 * Ext JS Library 1.1.1
20509 * Copyright(c) 2006-2007, Ext JS, LLC.
20511 * Originally Released Under LGPL - original licence link has changed is not relivant.
20514 * <script type="text/javascript">
20518 * @class Roo.menu.CheckItem
20519 * @extends Roo.menu.Item
20520 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20522 * Creates a new CheckItem
20523 * @param {Object} config Configuration options
20525 Roo.menu.CheckItem = function(config){
20526 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20529 * @event beforecheckchange
20530 * Fires before the checked value is set, providing an opportunity to cancel if needed
20531 * @param {Roo.menu.CheckItem} this
20532 * @param {Boolean} checked The new checked value that will be set
20534 "beforecheckchange" : true,
20536 * @event checkchange
20537 * Fires after the checked value has been set
20538 * @param {Roo.menu.CheckItem} this
20539 * @param {Boolean} checked The checked value that was set
20541 "checkchange" : true
20543 if(this.checkHandler){
20544 this.on('checkchange', this.checkHandler, this.scope);
20547 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20549 * @cfg {String} group
20550 * All check items with the same group name will automatically be grouped into a single-select
20551 * radio button group (defaults to '')
20554 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20556 itemCls : "x-menu-item x-menu-check-item",
20558 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20560 groupClass : "x-menu-group-item",
20563 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20564 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20565 * initialized with checked = true will be rendered as checked.
20570 ctype: "Roo.menu.CheckItem",
20573 onRender : function(c){
20574 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20576 this.el.addClass(this.groupClass);
20578 Roo.menu.MenuMgr.registerCheckable(this);
20580 this.checked = false;
20581 this.setChecked(true, true);
20586 destroy : function(){
20588 Roo.menu.MenuMgr.unregisterCheckable(this);
20590 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20594 * Set the checked state of this item
20595 * @param {Boolean} checked The new checked value
20596 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20598 setChecked : function(state, suppressEvent){
20599 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20600 if(this.container){
20601 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20603 this.checked = state;
20604 if(suppressEvent !== true){
20605 this.fireEvent("checkchange", this, state);
20611 handleClick : function(e){
20612 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20613 this.setChecked(!this.checked);
20615 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20619 * Ext JS Library 1.1.1
20620 * Copyright(c) 2006-2007, Ext JS, LLC.
20622 * Originally Released Under LGPL - original licence link has changed is not relivant.
20625 * <script type="text/javascript">
20629 * @class Roo.menu.DateItem
20630 * @extends Roo.menu.Adapter
20631 * A menu item that wraps the {@link Roo.DatPicker} component.
20633 * Creates a new DateItem
20634 * @param {Object} config Configuration options
20636 Roo.menu.DateItem = function(config){
20637 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20638 /** The Roo.DatePicker object @type Roo.DatePicker */
20639 this.picker = this.component;
20640 this.addEvents({select: true});
20642 this.picker.on("render", function(picker){
20643 picker.getEl().swallowEvent("click");
20644 picker.container.addClass("x-menu-date-item");
20647 this.picker.on("select", this.onSelect, this);
20650 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20652 onSelect : function(picker, date){
20653 this.fireEvent("select", this, date, picker);
20654 Roo.menu.DateItem.superclass.handleClick.call(this);
20658 * Ext JS Library 1.1.1
20659 * Copyright(c) 2006-2007, Ext JS, LLC.
20661 * Originally Released Under LGPL - original licence link has changed is not relivant.
20664 * <script type="text/javascript">
20668 * @class Roo.menu.ColorItem
20669 * @extends Roo.menu.Adapter
20670 * A menu item that wraps the {@link Roo.ColorPalette} component.
20672 * Creates a new ColorItem
20673 * @param {Object} config Configuration options
20675 Roo.menu.ColorItem = function(config){
20676 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20677 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20678 this.palette = this.component;
20679 this.relayEvents(this.palette, ["select"]);
20680 if(this.selectHandler){
20681 this.on('select', this.selectHandler, this.scope);
20684 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20686 * Ext JS Library 1.1.1
20687 * Copyright(c) 2006-2007, Ext JS, LLC.
20689 * Originally Released Under LGPL - original licence link has changed is not relivant.
20692 * <script type="text/javascript">
20697 * @class Roo.menu.DateMenu
20698 * @extends Roo.menu.Menu
20699 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20701 * Creates a new DateMenu
20702 * @param {Object} config Configuration options
20704 Roo.menu.DateMenu = function(config){
20705 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20707 var di = new Roo.menu.DateItem(config);
20710 * The {@link Roo.DatePicker} instance for this DateMenu
20713 this.picker = di.picker;
20716 * @param {DatePicker} picker
20717 * @param {Date} date
20719 this.relayEvents(di, ["select"]);
20721 this.on('beforeshow', function(){
20723 this.picker.hideMonthPicker(true);
20727 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20731 * Ext JS Library 1.1.1
20732 * Copyright(c) 2006-2007, Ext JS, LLC.
20734 * Originally Released Under LGPL - original licence link has changed is not relivant.
20737 * <script type="text/javascript">
20742 * @class Roo.menu.ColorMenu
20743 * @extends Roo.menu.Menu
20744 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20746 * Creates a new ColorMenu
20747 * @param {Object} config Configuration options
20749 Roo.menu.ColorMenu = function(config){
20750 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20752 var ci = new Roo.menu.ColorItem(config);
20755 * The {@link Roo.ColorPalette} instance for this ColorMenu
20756 * @type ColorPalette
20758 this.palette = ci.palette;
20761 * @param {ColorPalette} palette
20762 * @param {String} color
20764 this.relayEvents(ci, ["select"]);
20766 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20768 * Ext JS Library 1.1.1
20769 * Copyright(c) 2006-2007, Ext JS, LLC.
20771 * Originally Released Under LGPL - original licence link has changed is not relivant.
20774 * <script type="text/javascript">
20778 * @class Roo.form.Field
20779 * @extends Roo.BoxComponent
20780 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20782 * Creates a new Field
20783 * @param {Object} config Configuration options
20785 Roo.form.Field = function(config){
20786 Roo.form.Field.superclass.constructor.call(this, config);
20789 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20791 * @cfg {String} fieldLabel Label to use when rendering a form.
20794 * @cfg {String} qtip Mouse over tip
20798 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20800 invalidClass : "x-form-invalid",
20802 * @cfg {String} invalidText The error text to use when marking a field invalid and no message is provided (defaults to "The value in this field is invalid")
20804 invalidText : "The value in this field is invalid",
20806 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20808 focusClass : "x-form-focus",
20810 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20811 automatic validation (defaults to "keyup").
20813 validationEvent : "keyup",
20815 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20817 validateOnBlur : true,
20819 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20821 validationDelay : 250,
20823 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20824 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20826 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20828 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20830 fieldClass : "x-form-field",
20832 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20835 ----------- ----------------------------------------------------------------------
20836 qtip Display a quick tip when the user hovers over the field
20837 title Display a default browser title attribute popup
20838 under Add a block div beneath the field containing the error text
20839 side Add an error icon to the right of the field with a popup on hover
20840 [element id] Add the error text directly to the innerHTML of the specified element
20843 msgTarget : 'qtip',
20845 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20850 * @cfg {Boolean} readOnly True to mark the field as readOnly in HTML (defaults to false) -- Note: this only sets the element's readOnly DOM attribute.
20855 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20860 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20862 inputType : undefined,
20865 * @cfg {Number} tabIndex The tabIndex for this field. Note this only applies to fields that are rendered, not those which are built via applyTo (defaults to undefined).
20867 tabIndex : undefined,
20870 isFormField : true,
20875 * @property {Roo.Element} fieldEl
20876 * Element Containing the rendered Field (with label etc.)
20879 * @cfg {Mixed} value A value to initialize this field with.
20884 * @cfg {String} name The field's HTML name attribute.
20887 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20891 initComponent : function(){
20892 Roo.form.Field.superclass.initComponent.call(this);
20896 * Fires when this field receives input focus.
20897 * @param {Roo.form.Field} this
20902 * Fires when this field loses input focus.
20903 * @param {Roo.form.Field} this
20907 * @event specialkey
20908 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20909 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20910 * @param {Roo.form.Field} this
20911 * @param {Roo.EventObject} e The event object
20916 * Fires just before the field blurs if the field value has changed.
20917 * @param {Roo.form.Field} this
20918 * @param {Mixed} newValue The new value
20919 * @param {Mixed} oldValue The original value
20924 * Fires after the field has been marked as invalid.
20925 * @param {Roo.form.Field} this
20926 * @param {String} msg The validation message
20931 * Fires after the field has been validated with no errors.
20932 * @param {Roo.form.Field} this
20937 * Fires after the key up
20938 * @param {Roo.form.Field} this
20939 * @param {Roo.EventObject} e The event Object
20946 * Returns the name attribute of the field if available
20947 * @return {String} name The field name
20949 getName: function(){
20950 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20954 onRender : function(ct, position){
20955 Roo.form.Field.superclass.onRender.call(this, ct, position);
20957 var cfg = this.getAutoCreate();
20959 cfg.name = this.name || this.id;
20961 if(this.inputType){
20962 cfg.type = this.inputType;
20964 this.el = ct.createChild(cfg, position);
20966 var type = this.el.dom.type;
20968 if(type == 'password'){
20971 this.el.addClass('x-form-'+type);
20974 this.el.dom.readOnly = true;
20976 if(this.tabIndex !== undefined){
20977 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20980 this.el.addClass([this.fieldClass, this.cls]);
20985 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20986 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20987 * @return {Roo.form.Field} this
20989 applyTo : function(target){
20990 this.allowDomMove = false;
20991 this.el = Roo.get(target);
20992 this.render(this.el.dom.parentNode);
20997 initValue : function(){
20998 if(this.value !== undefined){
20999 this.setValue(this.value);
21000 }else if(this.el.dom.value.length > 0){
21001 this.setValue(this.el.dom.value);
21006 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21008 isDirty : function() {
21009 if(this.disabled) {
21012 return String(this.getValue()) !== String(this.originalValue);
21016 afterRender : function(){
21017 Roo.form.Field.superclass.afterRender.call(this);
21022 fireKey : function(e){
21023 //Roo.log('field ' + e.getKey());
21024 if(e.isNavKeyPress()){
21025 this.fireEvent("specialkey", this, e);
21030 * Resets the current field value to the originally loaded value and clears any validation messages
21032 reset : function(){
21033 this.setValue(this.originalValue);
21034 this.clearInvalid();
21038 initEvents : function(){
21039 // safari killled keypress - so keydown is now used..
21040 this.el.on("keydown" , this.fireKey, this);
21041 this.el.on("focus", this.onFocus, this);
21042 this.el.on("blur", this.onBlur, this);
21043 this.el.relayEvent('keyup', this);
21045 // reference to original value for reset
21046 this.originalValue = this.getValue();
21050 onFocus : function(){
21051 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21052 this.el.addClass(this.focusClass);
21054 if(!this.hasFocus){
21055 this.hasFocus = true;
21056 this.startValue = this.getValue();
21057 this.fireEvent("focus", this);
21061 beforeBlur : Roo.emptyFn,
21064 onBlur : function(){
21066 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21067 this.el.removeClass(this.focusClass);
21069 this.hasFocus = false;
21070 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21073 var v = this.getValue();
21074 if(String(v) !== String(this.startValue)){
21075 this.fireEvent('change', this, v, this.startValue);
21077 this.fireEvent("blur", this);
21081 * Returns whether or not the field value is currently valid
21082 * @param {Boolean} preventMark True to disable marking the field invalid
21083 * @return {Boolean} True if the value is valid, else false
21085 isValid : function(preventMark){
21089 var restore = this.preventMark;
21090 this.preventMark = preventMark === true;
21091 var v = this.validateValue(this.processValue(this.getRawValue()));
21092 this.preventMark = restore;
21097 * Validates the field value
21098 * @return {Boolean} True if the value is valid, else false
21100 validate : function(){
21101 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21102 this.clearInvalid();
21108 processValue : function(value){
21113 // Subclasses should provide the validation implementation by overriding this
21114 validateValue : function(value){
21119 * Mark this field as invalid
21120 * @param {String} msg The validation message
21122 markInvalid : function(msg){
21123 if(!this.rendered || this.preventMark){ // not rendered
21126 this.el.addClass(this.invalidClass);
21127 msg = msg || this.invalidText;
21128 switch(this.msgTarget){
21130 this.el.dom.qtip = msg;
21131 this.el.dom.qclass = 'x-form-invalid-tip';
21132 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21133 Roo.QuickTips.enable();
21137 this.el.dom.title = msg;
21141 var elp = this.el.findParent('.x-form-element', 5, true);
21142 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21143 this.errorEl.setWidth(elp.getWidth(true)-20);
21145 this.errorEl.update(msg);
21146 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21149 if(!this.errorIcon){
21150 var elp = this.el.findParent('.x-form-element', 5, true);
21151 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21153 this.alignErrorIcon();
21154 this.errorIcon.dom.qtip = msg;
21155 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21156 this.errorIcon.show();
21157 this.on('resize', this.alignErrorIcon, this);
21160 var t = Roo.getDom(this.msgTarget);
21162 t.style.display = this.msgDisplay;
21165 this.fireEvent('invalid', this, msg);
21169 alignErrorIcon : function(){
21170 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21174 * Clear any invalid styles/messages for this field
21176 clearInvalid : function(){
21177 if(!this.rendered || this.preventMark){ // not rendered
21180 this.el.removeClass(this.invalidClass);
21181 switch(this.msgTarget){
21183 this.el.dom.qtip = '';
21186 this.el.dom.title = '';
21190 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21194 if(this.errorIcon){
21195 this.errorIcon.dom.qtip = '';
21196 this.errorIcon.hide();
21197 this.un('resize', this.alignErrorIcon, this);
21201 var t = Roo.getDom(this.msgTarget);
21203 t.style.display = 'none';
21206 this.fireEvent('valid', this);
21210 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21211 * @return {Mixed} value The field value
21213 getRawValue : function(){
21214 var v = this.el.getValue();
21215 if(v === this.emptyText){
21222 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21223 * @return {Mixed} value The field value
21225 getValue : function(){
21226 var v = this.el.getValue();
21227 if(v === this.emptyText || v === undefined){
21234 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21235 * @param {Mixed} value The value to set
21237 setRawValue : function(v){
21238 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21242 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21243 * @param {Mixed} value The value to set
21245 setValue : function(v){
21248 this.el.dom.value = (v === null || v === undefined ? '' : v);
21253 adjustSize : function(w, h){
21254 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21255 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21259 adjustWidth : function(tag, w){
21260 tag = tag.toLowerCase();
21261 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21262 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21263 if(tag == 'input'){
21266 if(tag = 'textarea'){
21269 }else if(Roo.isOpera){
21270 if(tag == 'input'){
21273 if(tag = 'textarea'){
21283 // anything other than normal should be considered experimental
21284 Roo.form.Field.msgFx = {
21286 show: function(msgEl, f){
21287 msgEl.setDisplayed('block');
21290 hide : function(msgEl, f){
21291 msgEl.setDisplayed(false).update('');
21296 show: function(msgEl, f){
21297 msgEl.slideIn('t', {stopFx:true});
21300 hide : function(msgEl, f){
21301 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21306 show: function(msgEl, f){
21307 msgEl.fixDisplay();
21308 msgEl.alignTo(f.el, 'tl-tr');
21309 msgEl.slideIn('l', {stopFx:true});
21312 hide : function(msgEl, f){
21313 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21318 * Ext JS Library 1.1.1
21319 * Copyright(c) 2006-2007, Ext JS, LLC.
21321 * Originally Released Under LGPL - original licence link has changed is not relivant.
21324 * <script type="text/javascript">
21329 * @class Roo.form.TextField
21330 * @extends Roo.form.Field
21331 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21332 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21334 * Creates a new TextField
21335 * @param {Object} config Configuration options
21337 Roo.form.TextField = function(config){
21338 Roo.form.TextField.superclass.constructor.call(this, config);
21342 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21343 * according to the default logic, but this event provides a hook for the developer to apply additional
21344 * logic at runtime to resize the field if needed.
21345 * @param {Roo.form.Field} this This text field
21346 * @param {Number} width The new field width
21352 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21354 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21358 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21362 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21366 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21370 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21374 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21376 disableKeyFilter : false,
21378 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21382 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21386 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21388 maxLength : Number.MAX_VALUE,
21390 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21392 minLengthText : "The minimum length for this field is {0}",
21394 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21396 maxLengthText : "The maximum length for this field is {0}",
21398 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21400 selectOnFocus : false,
21402 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21404 blankText : "This field is required",
21406 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21407 * If available, this function will be called only after the basic validators all return true, and will be passed the
21408 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21412 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21413 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21414 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21418 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21422 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21426 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21427 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21429 emptyClass : 'x-form-empty-field',
21432 initEvents : function(){
21433 Roo.form.TextField.superclass.initEvents.call(this);
21434 if(this.validationEvent == 'keyup'){
21435 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21436 this.el.on('keyup', this.filterValidation, this);
21438 else if(this.validationEvent !== false){
21439 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21441 if(this.selectOnFocus || this.emptyText){
21442 this.on("focus", this.preFocus, this);
21443 if(this.emptyText){
21444 this.on('blur', this.postBlur, this);
21445 this.applyEmptyText();
21448 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21449 this.el.on("keypress", this.filterKeys, this);
21452 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21453 this.el.on("click", this.autoSize, this);
21457 processValue : function(value){
21458 if(this.stripCharsRe){
21459 var newValue = value.replace(this.stripCharsRe, '');
21460 if(newValue !== value){
21461 this.setRawValue(newValue);
21468 filterValidation : function(e){
21469 if(!e.isNavKeyPress()){
21470 this.validationTask.delay(this.validationDelay);
21475 onKeyUp : function(e){
21476 if(!e.isNavKeyPress()){
21482 * Resets the current field value to the originally-loaded value and clears any validation messages.
21483 * Also adds emptyText and emptyClass if the original value was blank.
21485 reset : function(){
21486 Roo.form.TextField.superclass.reset.call(this);
21487 this.applyEmptyText();
21490 applyEmptyText : function(){
21491 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21492 this.setRawValue(this.emptyText);
21493 this.el.addClass(this.emptyClass);
21498 preFocus : function(){
21499 if(this.emptyText){
21500 if(this.el.dom.value == this.emptyText){
21501 this.setRawValue('');
21503 this.el.removeClass(this.emptyClass);
21505 if(this.selectOnFocus){
21506 this.el.dom.select();
21511 postBlur : function(){
21512 this.applyEmptyText();
21516 filterKeys : function(e){
21517 var k = e.getKey();
21518 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21521 var c = e.getCharCode(), cc = String.fromCharCode(c);
21522 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21525 if(!this.maskRe.test(cc)){
21530 setValue : function(v){
21531 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21532 this.el.removeClass(this.emptyClass);
21534 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21535 this.applyEmptyText();
21540 * Validates a value according to the field's validation rules and marks the field as invalid
21541 * if the validation fails
21542 * @param {Mixed} value The value to validate
21543 * @return {Boolean} True if the value is valid, else false
21545 validateValue : function(value){
21546 if(value.length < 1 || value === this.emptyText){ // if it's blank
21547 if(this.allowBlank){
21548 this.clearInvalid();
21551 this.markInvalid(this.blankText);
21555 if(value.length < this.minLength){
21556 this.markInvalid(String.format(this.minLengthText, this.minLength));
21559 if(value.length > this.maxLength){
21560 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21564 var vt = Roo.form.VTypes;
21565 if(!vt[this.vtype](value, this)){
21566 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21570 if(typeof this.validator == "function"){
21571 var msg = this.validator(value);
21573 this.markInvalid(msg);
21577 if(this.regex && !this.regex.test(value)){
21578 this.markInvalid(this.regexText);
21585 * Selects text in this field
21586 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21587 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21589 selectText : function(start, end){
21590 var v = this.getRawValue();
21592 start = start === undefined ? 0 : start;
21593 end = end === undefined ? v.length : end;
21594 var d = this.el.dom;
21595 if(d.setSelectionRange){
21596 d.setSelectionRange(start, end);
21597 }else if(d.createTextRange){
21598 var range = d.createTextRange();
21599 range.moveStart("character", start);
21600 range.moveEnd("character", v.length-end);
21607 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21608 * This only takes effect if grow = true, and fires the autosize event.
21610 autoSize : function(){
21611 if(!this.grow || !this.rendered){
21615 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21618 var v = el.dom.value;
21619 var d = document.createElement('div');
21620 d.appendChild(document.createTextNode(v));
21624 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21625 this.el.setWidth(w);
21626 this.fireEvent("autosize", this, w);