4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 * @scope Roo.dd.DropTarget
3905 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3906 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3907 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3909 * IMPORTANT : it should set this.overClass and this.dropAllowed
3911 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3912 * @param {Event} e The event
3913 * @param {Object} data An object containing arbitrary data supplied by the drag source
3919 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3920 * This method will be called on every mouse movement while the drag source is over the drop target.
3921 * This default implementation simply returns the dropAllowed config value.
3923 * IMPORTANT : it should set this.dropAllowed
3925 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3926 * @param {Event} e The event
3927 * @param {Object} data An object containing arbitrary data supplied by the drag source
3933 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3934 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3935 * overClass (if any) from the drop element.
3936 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3937 * @param {Event} e The event
3938 * @param {Object} data An object containing arbitrary data supplied by the drag source
3944 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3945 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3946 * implementation that does something to process the drop event and returns true so that the drag source's
3947 * repair action does not run.
3949 * IMPORTANT : it should set this.success
3951 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3952 * @param {Event} e The event
3953 * @param {Object} data An object containing arbitrary data supplied by the drag source
3959 Roo.dd.DropTarget.superclass.constructor.call( this,
3961 this.ddGroup || this.group,
3964 listeners : config.listeners || {}
3972 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3974 * @cfg {String} overClass
3975 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3978 * @cfg {String} ddGroup
3979 * The drag drop group to handle drop events for
3983 * @cfg {String} dropAllowed
3984 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3986 dropAllowed : "x-dd-drop-ok",
3988 * @cfg {String} dropNotAllowed
3989 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3991 dropNotAllowed : "x-dd-drop-nodrop",
3993 * @cfg {boolean} success
3994 * set this after drop listener..
3998 * @cfg {boolean} valid
3999 * if the drop point is valid for over/enter..
4006 isNotifyTarget : true,
4011 notifyEnter : function(dd, e, data){
4013 this.fireEvent('enter', this, dd, e, data);
4015 this.el.addClass(this.overClass);
4017 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4023 notifyOver : function(dd, e, data){
4025 this.fireEvent('over', this, dd, e, data);
4026 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4032 notifyOut : function(dd, e, data){
4033 this.fireEvent('out', this, dd, e, data);
4035 this.el.removeClass(this.overClass);
4042 notifyDrop : function(dd, e, data){
4043 this.success = false;
4044 this.fireEvent('drop', this, dd, e, data);
4045 return this.success;
4049 * Ext JS Library 1.1.1
4050 * Copyright(c) 2006-2007, Ext JS, LLC.
4052 * Originally Released Under LGPL - original licence link has changed is not relivant.
4055 * <script type="text/javascript">
4060 * @class Roo.dd.DragZone
4061 * @extends Roo.dd.DragSource
4062 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4063 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4065 * @param {String/HTMLElement/Element} el The container element
4066 * @param {Object} config
4068 Roo.dd.DragZone = function(el, config){
4069 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4070 if(this.containerScroll){
4071 Roo.dd.ScrollManager.register(this.el);
4075 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4077 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4078 * for auto scrolling during drag operations.
4081 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4082 * method after a failed drop (defaults to "c3daf9" - light blue)
4086 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4087 * for a valid target to drag based on the mouse down. Override this method
4088 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4089 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4090 * @param {EventObject} e The mouse down event
4091 * @return {Object} The dragData
4093 getDragData : function(e){
4094 return Roo.dd.Registry.getHandleFromEvent(e);
4098 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4099 * this.dragData.ddel
4100 * @param {Number} x The x position of the click on the dragged object
4101 * @param {Number} y The y position of the click on the dragged object
4102 * @return {Boolean} true to continue the drag, false to cancel
4104 onInitDrag : function(x, y){
4105 this.proxy.update(this.dragData.ddel.cloneNode(true));
4106 this.onStartDrag(x, y);
4111 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4113 afterRepair : function(){
4115 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4117 this.dragging = false;
4121 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4122 * the XY of this.dragData.ddel
4123 * @param {EventObject} e The mouse up event
4124 * @return {Array} The xy location (e.g. [100, 200])
4126 getRepairXY : function(e){
4127 return Roo.Element.fly(this.dragData.ddel).getXY();
4131 * Ext JS Library 1.1.1
4132 * Copyright(c) 2006-2007, Ext JS, LLC.
4134 * Originally Released Under LGPL - original licence link has changed is not relivant.
4137 * <script type="text/javascript">
4140 * @class Roo.dd.DropZone
4141 * @extends Roo.dd.DropTarget
4142 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4143 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4145 * @param {String/HTMLElement/Element} el The container element
4146 * @param {Object} config
4148 Roo.dd.DropZone = function(el, config){
4149 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4152 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4154 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4155 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4156 * provide your own custom lookup.
4157 * @param {Event} e The event
4158 * @return {Object} data The custom data
4160 getTargetFromEvent : function(e){
4161 return Roo.dd.Registry.getTargetFromEvent(e);
4165 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4166 * that it has registered. This method has no default implementation and should be overridden to provide
4167 * node-specific processing if necessary.
4168 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4169 * {@link #getTargetFromEvent} for this node)
4170 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4171 * @param {Event} e The event
4172 * @param {Object} data An object containing arbitrary data supplied by the drag source
4174 onNodeEnter : function(n, dd, e, data){
4179 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4180 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4181 * overridden to provide the proper feedback.
4182 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4183 * {@link #getTargetFromEvent} for this node)
4184 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4185 * @param {Event} e The event
4186 * @param {Object} data An object containing arbitrary data supplied by the drag source
4187 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4188 * underlying {@link Roo.dd.StatusProxy} can be updated
4190 onNodeOver : function(n, dd, e, data){
4191 return this.dropAllowed;
4195 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4196 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4197 * node-specific processing if necessary.
4198 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4199 * {@link #getTargetFromEvent} for this node)
4200 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4201 * @param {Event} e The event
4202 * @param {Object} data An object containing arbitrary data supplied by the drag source
4204 onNodeOut : function(n, dd, e, data){
4209 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4210 * the drop node. The default implementation returns false, so it should be overridden to provide the
4211 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4212 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4213 * {@link #getTargetFromEvent} for this node)
4214 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4215 * @param {Event} e The event
4216 * @param {Object} data An object containing arbitrary data supplied by the drag source
4217 * @return {Boolean} True if the drop was valid, else false
4219 onNodeDrop : function(n, dd, e, data){
4224 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4225 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4226 * it should be overridden to provide the proper feedback if necessary.
4227 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4228 * @param {Event} e The event
4229 * @param {Object} data An object containing arbitrary data supplied by the drag source
4230 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4231 * underlying {@link Roo.dd.StatusProxy} can be updated
4233 onContainerOver : function(dd, e, data){
4234 return this.dropNotAllowed;
4238 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4239 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4240 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4241 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4242 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4243 * @param {Event} e The event
4244 * @param {Object} data An object containing arbitrary data supplied by the drag source
4245 * @return {Boolean} True if the drop was valid, else false
4247 onContainerDrop : function(dd, e, data){
4252 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4253 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4254 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4255 * you should override this method and provide a custom implementation.
4256 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4257 * @param {Event} e The event
4258 * @param {Object} data An object containing arbitrary data supplied by the drag source
4259 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4260 * underlying {@link Roo.dd.StatusProxy} can be updated
4262 notifyEnter : function(dd, e, data){
4263 return this.dropNotAllowed;
4267 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4268 * This method will be called on every mouse movement while the drag source is over the drop zone.
4269 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4270 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4271 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4272 * registered node, it will call {@link #onContainerOver}.
4273 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4274 * @param {Event} e The event
4275 * @param {Object} data An object containing arbitrary data supplied by the drag source
4276 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4277 * underlying {@link Roo.dd.StatusProxy} can be updated
4279 notifyOver : function(dd, e, data){
4280 var n = this.getTargetFromEvent(e);
4281 if(!n){ // not over valid drop target
4282 if(this.lastOverNode){
4283 this.onNodeOut(this.lastOverNode, dd, e, data);
4284 this.lastOverNode = null;
4286 return this.onContainerOver(dd, e, data);
4288 if(this.lastOverNode != n){
4289 if(this.lastOverNode){
4290 this.onNodeOut(this.lastOverNode, dd, e, data);
4292 this.onNodeEnter(n, dd, e, data);
4293 this.lastOverNode = n;
4295 return this.onNodeOver(n, dd, e, data);
4299 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4300 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4301 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4302 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4303 * @param {Event} e The event
4304 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4306 notifyOut : function(dd, e, data){
4307 if(this.lastOverNode){
4308 this.onNodeOut(this.lastOverNode, dd, e, data);
4309 this.lastOverNode = null;
4314 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4315 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4316 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4317 * otherwise it will call {@link #onContainerDrop}.
4318 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4319 * @param {Event} e The event
4320 * @param {Object} data An object containing arbitrary data supplied by the drag source
4321 * @return {Boolean} True if the drop was valid, else false
4323 notifyDrop : function(dd, e, data){
4324 if(this.lastOverNode){
4325 this.onNodeOut(this.lastOverNode, dd, e, data);
4326 this.lastOverNode = null;
4328 var n = this.getTargetFromEvent(e);
4330 this.onNodeDrop(n, dd, e, data) :
4331 this.onContainerDrop(dd, e, data);
4335 triggerCacheRefresh : function(){
4336 Roo.dd.DDM.refreshCache(this.groups);
4340 * Ext JS Library 1.1.1
4341 * Copyright(c) 2006-2007, Ext JS, LLC.
4343 * Originally Released Under LGPL - original licence link has changed is not relivant.
4346 * <script type="text/javascript">
4351 * @class Roo.data.SortTypes
4353 * Defines the default sorting (casting?) comparison functions used when sorting data.
4355 Roo.data.SortTypes = {
4357 * Default sort that does nothing
4358 * @param {Mixed} s The value being converted
4359 * @return {Mixed} The comparison value
4366 * The regular expression used to strip tags
4370 stripTagsRE : /<\/?[^>]+>/gi,
4373 * Strips all HTML tags to sort on text only
4374 * @param {Mixed} s The value being converted
4375 * @return {String} The comparison value
4377 asText : function(s){
4378 return String(s).replace(this.stripTagsRE, "");
4382 * Strips all HTML tags to sort on text only - Case insensitive
4383 * @param {Mixed} s The value being converted
4384 * @return {String} The comparison value
4386 asUCText : function(s){
4387 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4391 * Case insensitive string
4392 * @param {Mixed} s The value being converted
4393 * @return {String} The comparison value
4395 asUCString : function(s) {
4396 return String(s).toUpperCase();
4401 * @param {Mixed} s The value being converted
4402 * @return {Number} The comparison value
4404 asDate : function(s) {
4408 if(s instanceof Date){
4411 return Date.parse(String(s));
4416 * @param {Mixed} s The value being converted
4417 * @return {Float} The comparison value
4419 asFloat : function(s) {
4420 var val = parseFloat(String(s).replace(/,/g, ""));
4421 if(isNaN(val)) val = 0;
4427 * @param {Mixed} s The value being converted
4428 * @return {Number} The comparison value
4430 asInt : function(s) {
4431 var val = parseInt(String(s).replace(/,/g, ""));
4432 if(isNaN(val)) val = 0;
4437 * Ext JS Library 1.1.1
4438 * Copyright(c) 2006-2007, Ext JS, LLC.
4440 * Originally Released Under LGPL - original licence link has changed is not relivant.
4443 * <script type="text/javascript">
4447 * @class Roo.data.Record
4448 * Instances of this class encapsulate both record <em>definition</em> information, and record
4449 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4450 * to access Records cached in an {@link Roo.data.Store} object.<br>
4452 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4453 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4456 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4458 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4459 * {@link #create}. The parameters are the same.
4460 * @param {Array} data An associative Array of data values keyed by the field name.
4461 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4462 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4463 * not specified an integer id is generated.
4465 Roo.data.Record = function(data, id){
4466 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4471 * Generate a constructor for a specific record layout.
4472 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4473 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4474 * Each field definition object may contain the following properties: <ul>
4475 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4476 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4477 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4478 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4479 * is being used, then this is a string containing the javascript expression to reference the data relative to
4480 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4481 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4482 * this may be omitted.</p></li>
4483 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4484 * <ul><li>auto (Default, implies no conversion)</li>
4489 * <li>date</li></ul></p></li>
4490 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4491 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4492 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4493 * by the Reader into an object that will be stored in the Record. It is passed the
4494 * following parameters:<ul>
4495 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4497 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4499 * <br>usage:<br><pre><code>
4500 var TopicRecord = Roo.data.Record.create(
4501 {name: 'title', mapping: 'topic_title'},
4502 {name: 'author', mapping: 'username'},
4503 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4504 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4505 {name: 'lastPoster', mapping: 'user2'},
4506 {name: 'excerpt', mapping: 'post_text'}
4509 var myNewRecord = new TopicRecord({
4510 title: 'Do my job please',
4513 lastPost: new Date(),
4514 lastPoster: 'Animal',
4515 excerpt: 'No way dude!'
4517 myStore.add(myNewRecord);
4522 Roo.data.Record.create = function(o){
4524 f.superclass.constructor.apply(this, arguments);
4526 Roo.extend(f, Roo.data.Record);
4527 var p = f.prototype;
4528 p.fields = new Roo.util.MixedCollection(false, function(field){
4531 for(var i = 0, len = o.length; i < len; i++){
4532 p.fields.add(new Roo.data.Field(o[i]));
4534 f.getField = function(name){
4535 return p.fields.get(name);
4540 Roo.data.Record.AUTO_ID = 1000;
4541 Roo.data.Record.EDIT = 'edit';
4542 Roo.data.Record.REJECT = 'reject';
4543 Roo.data.Record.COMMIT = 'commit';
4545 Roo.data.Record.prototype = {
4547 * Readonly flag - true if this record has been modified.
4556 join : function(store){
4561 * Set the named field to the specified value.
4562 * @param {String} name The name of the field to set.
4563 * @param {Object} value The value to set the field to.
4565 set : function(name, value){
4566 if(this.data[name] == value){
4573 if(typeof this.modified[name] == 'undefined'){
4574 this.modified[name] = this.data[name];
4576 this.data[name] = value;
4578 this.store.afterEdit(this);
4583 * Get the value of the named field.
4584 * @param {String} name The name of the field to get the value of.
4585 * @return {Object} The value of the field.
4587 get : function(name){
4588 return this.data[name];
4592 beginEdit : function(){
4593 this.editing = true;
4598 cancelEdit : function(){
4599 this.editing = false;
4600 delete this.modified;
4604 endEdit : function(){
4605 this.editing = false;
4606 if(this.dirty && this.store){
4607 this.store.afterEdit(this);
4612 * Usually called by the {@link Roo.data.Store} which owns the Record.
4613 * Rejects all changes made to the Record since either creation, or the last commit operation.
4614 * Modified fields are reverted to their original values.
4616 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4617 * of reject operations.
4619 reject : function(){
4620 var m = this.modified;
4622 if(typeof m[n] != "function"){
4623 this.data[n] = m[n];
4627 delete this.modified;
4628 this.editing = false;
4630 this.store.afterReject(this);
4635 * Usually called by the {@link Roo.data.Store} which owns the Record.
4636 * Commits all changes made to the Record since either creation, or the last commit operation.
4638 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4639 * of commit operations.
4641 commit : function(){
4643 delete this.modified;
4644 this.editing = false;
4646 this.store.afterCommit(this);
4651 hasError : function(){
4652 return this.error != null;
4656 clearError : function(){
4661 * Creates a copy of this record.
4662 * @param {String} id (optional) A new record id if you don't want to use this record's id
4665 copy : function(newId) {
4666 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4670 * Ext JS Library 1.1.1
4671 * Copyright(c) 2006-2007, Ext JS, LLC.
4673 * Originally Released Under LGPL - original licence link has changed is not relivant.
4676 * <script type="text/javascript">
4682 * @class Roo.data.Store
4683 * @extends Roo.util.Observable
4684 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4685 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4687 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4688 * has no knowledge of the format of the data returned by the Proxy.<br>
4690 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4691 * instances from the data object. These records are cached and made available through accessor functions.
4693 * Creates a new Store.
4694 * @param {Object} config A config object containing the objects needed for the Store to access data,
4695 * and read the data into Records.
4697 Roo.data.Store = function(config){
4698 this.data = new Roo.util.MixedCollection(false);
4699 this.data.getKey = function(o){
4702 this.baseParams = {};
4711 if(config && config.data){
4712 this.inlineData = config.data;
4716 Roo.apply(this, config);
4718 if(this.reader){ // reader passed
4719 this.reader = Roo.factory(this.reader, Roo.data);
4720 this.reader.xmodule = this.xmodule || false;
4721 if(!this.recordType){
4722 this.recordType = this.reader.recordType;
4724 if(this.reader.onMetaChange){
4725 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4729 if(this.recordType){
4730 this.fields = this.recordType.prototype.fields;
4736 * @event datachanged
4737 * Fires when the data cache has changed, and a widget which is using this Store
4738 * as a Record cache should refresh its view.
4739 * @param {Store} this
4744 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4745 * @param {Store} this
4746 * @param {Object} meta The JSON metadata
4751 * Fires when Records have been added to the Store
4752 * @param {Store} this
4753 * @param {Roo.data.Record[]} records The array of Records added
4754 * @param {Number} index The index at which the record(s) were added
4759 * Fires when a Record has been removed from the Store
4760 * @param {Store} this
4761 * @param {Roo.data.Record} record The Record that was removed
4762 * @param {Number} index The index at which the record was removed
4767 * Fires when a Record has been updated
4768 * @param {Store} this
4769 * @param {Roo.data.Record} record The Record that was updated
4770 * @param {String} operation The update operation being performed. Value may be one of:
4772 Roo.data.Record.EDIT
4773 Roo.data.Record.REJECT
4774 Roo.data.Record.COMMIT
4780 * Fires when the data cache has been cleared.
4781 * @param {Store} this
4786 * Fires before a request is made for a new data object. If the beforeload handler returns false
4787 * the load action will be canceled.
4788 * @param {Store} this
4789 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4794 * Fires after a new set of Records has been loaded.
4795 * @param {Store} this
4796 * @param {Roo.data.Record[]} records The Records that were loaded
4797 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4801 * @event loadexception
4802 * Fires if an exception occurs in the Proxy during loading.
4803 * Called with the signature of the Proxy's "loadexception" event.
4804 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4807 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4808 * @param {Object} load options
4809 * @param {Object} jsonData from your request (normally this contains the Exception)
4811 loadexception : true
4815 this.proxy = Roo.factory(this.proxy, Roo.data);
4816 this.proxy.xmodule = this.xmodule || false;
4817 this.relayEvents(this.proxy, ["loadexception"]);
4819 this.sortToggle = {};
4821 Roo.data.Store.superclass.constructor.call(this);
4823 if(this.inlineData){
4824 this.loadData(this.inlineData);
4825 delete this.inlineData;
4828 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4830 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4831 * without a remote query - used by combo/forms at present.
4835 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4838 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4841 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4842 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4845 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4846 * on any HTTP request
4849 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4852 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4853 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4858 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4859 * loaded or when a record is removed. (defaults to false).
4861 pruneModifiedRecords : false,
4867 * Add Records to the Store and fires the add event.
4868 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4870 add : function(records){
4871 records = [].concat(records);
4872 for(var i = 0, len = records.length; i < len; i++){
4873 records[i].join(this);
4875 var index = this.data.length;
4876 this.data.addAll(records);
4877 this.fireEvent("add", this, records, index);
4881 * Remove a Record from the Store and fires the remove event.
4882 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4884 remove : function(record){
4885 var index = this.data.indexOf(record);
4886 this.data.removeAt(index);
4887 if(this.pruneModifiedRecords){
4888 this.modified.remove(record);
4890 this.fireEvent("remove", this, record, index);
4894 * Remove all Records from the Store and fires the clear event.
4896 removeAll : function(){
4898 if(this.pruneModifiedRecords){
4901 this.fireEvent("clear", this);
4905 * Inserts Records to the Store at the given index and fires the add event.
4906 * @param {Number} index The start index at which to insert the passed Records.
4907 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4909 insert : function(index, records){
4910 records = [].concat(records);
4911 for(var i = 0, len = records.length; i < len; i++){
4912 this.data.insert(index, records[i]);
4913 records[i].join(this);
4915 this.fireEvent("add", this, records, index);
4919 * Get the index within the cache of the passed Record.
4920 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4921 * @return {Number} The index of the passed Record. Returns -1 if not found.
4923 indexOf : function(record){
4924 return this.data.indexOf(record);
4928 * Get the index within the cache of the Record with the passed id.
4929 * @param {String} id The id of the Record to find.
4930 * @return {Number} The index of the Record. Returns -1 if not found.
4932 indexOfId : function(id){
4933 return this.data.indexOfKey(id);
4937 * Get the Record with the specified id.
4938 * @param {String} id The id of the Record to find.
4939 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4941 getById : function(id){
4942 return this.data.key(id);
4946 * Get the Record at the specified index.
4947 * @param {Number} index The index of the Record to find.
4948 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4950 getAt : function(index){
4951 return this.data.itemAt(index);
4955 * Returns a range of Records between specified indices.
4956 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4957 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4958 * @return {Roo.data.Record[]} An array of Records
4960 getRange : function(start, end){
4961 return this.data.getRange(start, end);
4965 storeOptions : function(o){
4966 o = Roo.apply({}, o);
4969 this.lastOptions = o;
4973 * Loads the Record cache from the configured Proxy using the configured Reader.
4975 * If using remote paging, then the first load call must specify the <em>start</em>
4976 * and <em>limit</em> properties in the options.params property to establish the initial
4977 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4979 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4980 * and this call will return before the new data has been loaded. Perform any post-processing
4981 * in a callback function, or in a "load" event handler.</strong>
4983 * @param {Object} options An object containing properties which control loading options:<ul>
4984 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4985 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4986 * passed the following arguments:<ul>
4987 * <li>r : Roo.data.Record[]</li>
4988 * <li>options: Options object from the load call</li>
4989 * <li>success: Boolean success indicator</li></ul></li>
4990 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4991 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4994 load : function(options){
4995 options = options || {};
4996 if(this.fireEvent("beforeload", this, options) !== false){
4997 this.storeOptions(options);
4998 var p = Roo.apply(options.params || {}, this.baseParams);
4999 // if meta was not loaded from remote source.. try requesting it.
5000 if (!this.reader.metaFromRemote) {
5003 if(this.sortInfo && this.remoteSort){
5004 var pn = this.paramNames;
5005 p[pn["sort"]] = this.sortInfo.field;
5006 p[pn["dir"]] = this.sortInfo.direction;
5008 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5013 * Reloads the Record cache from the configured Proxy using the configured Reader and
5014 * the options from the last load operation performed.
5015 * @param {Object} options (optional) An object containing properties which may override the options
5016 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5017 * the most recently used options are reused).
5019 reload : function(options){
5020 this.load(Roo.applyIf(options||{}, this.lastOptions));
5024 // Called as a callback by the Reader during a load operation.
5025 loadRecords : function(o, options, success){
5026 if(!o || success === false){
5027 if(success !== false){
5028 this.fireEvent("load", this, [], options);
5030 if(options.callback){
5031 options.callback.call(options.scope || this, [], options, false);
5035 // if data returned failure - throw an exception.
5036 if (o.success === false) {
5037 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5040 var r = o.records, t = o.totalRecords || r.length;
5041 if(!options || options.add !== true){
5042 if(this.pruneModifiedRecords){
5045 for(var i = 0, len = r.length; i < len; i++){
5049 this.data = this.snapshot;
5050 delete this.snapshot;
5053 this.data.addAll(r);
5054 this.totalLength = t;
5056 this.fireEvent("datachanged", this);
5058 this.totalLength = Math.max(t, this.data.length+r.length);
5061 this.fireEvent("load", this, r, options);
5062 if(options.callback){
5063 options.callback.call(options.scope || this, r, options, true);
5068 * Loads data from a passed data block. A Reader which understands the format of the data
5069 * must have been configured in the constructor.
5070 * @param {Object} data The data block from which to read the Records. The format of the data expected
5071 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5072 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5074 loadData : function(o, append){
5075 var r = this.reader.readRecords(o);
5076 this.loadRecords(r, {add: append}, true);
5080 * Gets the number of cached records.
5082 * <em>If using paging, this may not be the total size of the dataset. If the data object
5083 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5084 * the data set size</em>
5086 getCount : function(){
5087 return this.data.length || 0;
5091 * Gets the total number of records in the dataset as returned by the server.
5093 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5094 * the dataset size</em>
5096 getTotalCount : function(){
5097 return this.totalLength || 0;
5101 * Returns the sort state of the Store as an object with two properties:
5103 field {String} The name of the field by which the Records are sorted
5104 direction {String} The sort order, "ASC" or "DESC"
5107 getSortState : function(){
5108 return this.sortInfo;
5112 applySort : function(){
5113 if(this.sortInfo && !this.remoteSort){
5114 var s = this.sortInfo, f = s.field;
5115 var st = this.fields.get(f).sortType;
5116 var fn = function(r1, r2){
5117 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5118 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5120 this.data.sort(s.direction, fn);
5121 if(this.snapshot && this.snapshot != this.data){
5122 this.snapshot.sort(s.direction, fn);
5128 * Sets the default sort column and order to be used by the next load operation.
5129 * @param {String} fieldName The name of the field to sort by.
5130 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5132 setDefaultSort : function(field, dir){
5133 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5138 * If remote sorting is used, the sort is performed on the server, and the cache is
5139 * reloaded. If local sorting is used, the cache is sorted internally.
5140 * @param {String} fieldName The name of the field to sort by.
5141 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5143 sort : function(fieldName, dir){
5144 var f = this.fields.get(fieldName);
5146 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5147 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5152 this.sortToggle[f.name] = dir;
5153 this.sortInfo = {field: f.name, direction: dir};
5154 if(!this.remoteSort){
5156 this.fireEvent("datachanged", this);
5158 this.load(this.lastOptions);
5163 * Calls the specified function for each of the Records in the cache.
5164 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5165 * Returning <em>false</em> aborts and exits the iteration.
5166 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5168 each : function(fn, scope){
5169 this.data.each(fn, scope);
5173 * Gets all records modified since the last commit. Modified records are persisted across load operations
5174 * (e.g., during paging).
5175 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5177 getModifiedRecords : function(){
5178 return this.modified;
5182 createFilterFn : function(property, value, anyMatch){
5183 if(!value.exec){ // not a regex
5184 value = String(value);
5185 if(value.length == 0){
5188 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5191 return value.test(r.data[property]);
5196 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5197 * @param {String} property A field on your records
5198 * @param {Number} start The record index to start at (defaults to 0)
5199 * @param {Number} end The last record index to include (defaults to length - 1)
5200 * @return {Number} The sum
5202 sum : function(property, start, end){
5203 var rs = this.data.items, v = 0;
5205 end = (end || end === 0) ? end : rs.length-1;
5207 for(var i = start; i <= end; i++){
5208 v += (rs[i].data[property] || 0);
5214 * Filter the records by a specified property.
5215 * @param {String} field A field on your records
5216 * @param {String/RegExp} value Either a string that the field
5217 * should start with or a RegExp to test against the field
5218 * @param {Boolean} anyMatch True to match any part not just the beginning
5220 filter : function(property, value, anyMatch){
5221 var fn = this.createFilterFn(property, value, anyMatch);
5222 return fn ? this.filterBy(fn) : this.clearFilter();
5226 * Filter by a function. The specified function will be called with each
5227 * record in this data source. If the function returns true the record is included,
5228 * otherwise it is filtered.
5229 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5230 * @param {Object} scope (optional) The scope of the function (defaults to this)
5232 filterBy : function(fn, scope){
5233 this.snapshot = this.snapshot || this.data;
5234 this.data = this.queryBy(fn, scope||this);
5235 this.fireEvent("datachanged", this);
5239 * Query the records by a specified property.
5240 * @param {String} field A field on your records
5241 * @param {String/RegExp} value Either a string that the field
5242 * should start with or a RegExp to test against the field
5243 * @param {Boolean} anyMatch True to match any part not just the beginning
5244 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5246 query : function(property, value, anyMatch){
5247 var fn = this.createFilterFn(property, value, anyMatch);
5248 return fn ? this.queryBy(fn) : this.data.clone();
5252 * Query by a function. The specified function will be called with each
5253 * record in this data source. If the function returns true the record is included
5255 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5256 * @param {Object} scope (optional) The scope of the function (defaults to this)
5257 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5259 queryBy : function(fn, scope){
5260 var data = this.snapshot || this.data;
5261 return data.filterBy(fn, scope||this);
5265 * Collects unique values for a particular dataIndex from this store.
5266 * @param {String} dataIndex The property to collect
5267 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5268 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5269 * @return {Array} An array of the unique values
5271 collect : function(dataIndex, allowNull, bypassFilter){
5272 var d = (bypassFilter === true && this.snapshot) ?
5273 this.snapshot.items : this.data.items;
5274 var v, sv, r = [], l = {};
5275 for(var i = 0, len = d.length; i < len; i++){
5276 v = d[i].data[dataIndex];
5278 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5287 * Revert to a view of the Record cache with no filtering applied.
5288 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5290 clearFilter : function(suppressEvent){
5291 if(this.snapshot && this.snapshot != this.data){
5292 this.data = this.snapshot;
5293 delete this.snapshot;
5294 if(suppressEvent !== true){
5295 this.fireEvent("datachanged", this);
5301 afterEdit : function(record){
5302 if(this.modified.indexOf(record) == -1){
5303 this.modified.push(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5309 afterReject : function(record){
5310 this.modified.remove(record);
5311 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5315 afterCommit : function(record){
5316 this.modified.remove(record);
5317 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5321 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5322 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5324 commitChanges : function(){
5325 var m = this.modified.slice(0);
5327 for(var i = 0, len = m.length; i < len; i++){
5333 * Cancel outstanding changes on all changed records.
5335 rejectChanges : function(){
5336 var m = this.modified.slice(0);
5338 for(var i = 0, len = m.length; i < len; i++){
5343 onMetaChange : function(meta, rtype, o){
5344 this.recordType = rtype;
5345 this.fields = rtype.prototype.fields;
5346 delete this.snapshot;
5347 this.sortInfo = meta.sortInfo || this.sortInfo;
5349 this.fireEvent('metachange', this, this.reader.meta);
5353 * Ext JS Library 1.1.1
5354 * Copyright(c) 2006-2007, Ext JS, LLC.
5356 * Originally Released Under LGPL - original licence link has changed is not relivant.
5359 * <script type="text/javascript">
5363 * @class Roo.data.SimpleStore
5364 * @extends Roo.data.Store
5365 * Small helper class to make creating Stores from Array data easier.
5366 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5367 * @cfg {Array} fields An array of field definition objects, or field name strings.
5368 * @cfg {Array} data The multi-dimensional array of data
5370 * @param {Object} config
5372 Roo.data.SimpleStore = function(config){
5373 Roo.data.SimpleStore.superclass.constructor.call(this, {
5375 reader: new Roo.data.ArrayReader({
5378 Roo.data.Record.create(config.fields)
5380 proxy : new Roo.data.MemoryProxy(config.data)
5384 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5386 * Ext JS Library 1.1.1
5387 * Copyright(c) 2006-2007, Ext JS, LLC.
5389 * Originally Released Under LGPL - original licence link has changed is not relivant.
5392 * <script type="text/javascript">
5397 * @extends Roo.data.Store
5398 * @class Roo.data.JsonStore
5399 * Small helper class to make creating Stores for JSON data easier. <br/>
5401 var store = new Roo.data.JsonStore({
5402 url: 'get-images.php',
5404 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5407 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5408 * JsonReader and HttpProxy (unless inline data is provided).</b>
5409 * @cfg {Array} fields An array of field definition objects, or field name strings.
5411 * @param {Object} config
5413 Roo.data.JsonStore = function(c){
5414 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5415 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5416 reader: new Roo.data.JsonReader(c, c.fields)
5419 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5421 * Ext JS Library 1.1.1
5422 * Copyright(c) 2006-2007, Ext JS, LLC.
5424 * Originally Released Under LGPL - original licence link has changed is not relivant.
5427 * <script type="text/javascript">
5431 Roo.data.Field = function(config){
5432 if(typeof config == "string"){
5433 config = {name: config};
5435 Roo.apply(this, config);
5441 var st = Roo.data.SortTypes;
5442 // named sortTypes are supported, here we look them up
5443 if(typeof this.sortType == "string"){
5444 this.sortType = st[this.sortType];
5447 // set default sortType for strings and dates
5451 this.sortType = st.asUCString;
5454 this.sortType = st.asDate;
5457 this.sortType = st.none;
5462 var stripRe = /[\$,%]/g;
5464 // prebuilt conversion function for this field, instead of
5465 // switching every time we're reading a value
5467 var cv, dateFormat = this.dateFormat;
5472 cv = function(v){ return v; };
5475 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5479 return v !== undefined && v !== null && v !== '' ?
5480 parseInt(String(v).replace(stripRe, ""), 10) : '';
5485 return v !== undefined && v !== null && v !== '' ?
5486 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5491 cv = function(v){ return v === true || v === "true" || v == 1; };
5498 if(v instanceof Date){
5502 if(dateFormat == "timestamp"){
5503 return new Date(v*1000);
5505 return Date.parseDate(v, dateFormat);
5507 var parsed = Date.parse(v);
5508 return parsed ? new Date(parsed) : null;
5517 Roo.data.Field.prototype = {
5525 * Ext JS Library 1.1.1
5526 * Copyright(c) 2006-2007, Ext JS, LLC.
5528 * Originally Released Under LGPL - original licence link has changed is not relivant.
5531 * <script type="text/javascript">
5534 // Base class for reading structured data from a data source. This class is intended to be
5535 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5538 * @class Roo.data.DataReader
5539 * Base class for reading structured data from a data source. This class is intended to be
5540 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5543 Roo.data.DataReader = function(meta, recordType){
5547 this.recordType = recordType instanceof Array ?
5548 Roo.data.Record.create(recordType) : recordType;
5551 Roo.data.DataReader.prototype = {
5553 * Create an empty record
5554 * @param {Object} data (optional) - overlay some values
5555 * @return {Roo.data.Record} record created.
5557 newRow : function(d) {
5559 this.recordType.prototype.fields.each(function(c) {
5561 case 'int' : da[c.name] = 0; break;
5562 case 'date' : da[c.name] = new Date(); break;
5563 case 'float' : da[c.name] = 0.0; break;
5564 case 'boolean' : da[c.name] = false; break;
5565 default : da[c.name] = ""; break;
5569 return new this.recordType(Roo.apply(da, d));
5574 * Ext JS Library 1.1.1
5575 * Copyright(c) 2006-2007, Ext JS, LLC.
5577 * Originally Released Under LGPL - original licence link has changed is not relivant.
5580 * <script type="text/javascript">
5584 * @class Roo.data.DataProxy
5585 * @extends Roo.data.Observable
5586 * This class is an abstract base class for implementations which provide retrieval of
5587 * unformatted data objects.<br>
5589 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5590 * (of the appropriate type which knows how to parse the data object) to provide a block of
5591 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5593 * Custom implementations must implement the load method as described in
5594 * {@link Roo.data.HttpProxy#load}.
5596 Roo.data.DataProxy = function(){
5600 * Fires before a network request is made to retrieve a data object.
5601 * @param {Object} This DataProxy object.
5602 * @param {Object} params The params parameter to the load function.
5607 * Fires before the load method's callback is called.
5608 * @param {Object} This DataProxy object.
5609 * @param {Object} o The data object.
5610 * @param {Object} arg The callback argument object passed to the load function.
5614 * @event loadexception
5615 * Fires if an Exception occurs during data retrieval.
5616 * @param {Object} This DataProxy object.
5617 * @param {Object} o The data object.
5618 * @param {Object} arg The callback argument object passed to the load function.
5619 * @param {Object} e The Exception.
5621 loadexception : true
5623 Roo.data.DataProxy.superclass.constructor.call(this);
5626 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5629 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5633 * Ext JS Library 1.1.1
5634 * Copyright(c) 2006-2007, Ext JS, LLC.
5636 * Originally Released Under LGPL - original licence link has changed is not relivant.
5639 * <script type="text/javascript">
5642 * @class Roo.data.MemoryProxy
5643 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5644 * to the Reader when its load method is called.
5646 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5648 Roo.data.MemoryProxy = function(data){
5652 Roo.data.MemoryProxy.superclass.constructor.call(this);
5656 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5658 * Load data from the requested source (in this case an in-memory
5659 * data object passed to the constructor), read the data object into
5660 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5661 * process that block using the passed callback.
5662 * @param {Object} params This parameter is not used by the MemoryProxy class.
5663 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5664 * object into a block of Roo.data.Records.
5665 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5666 * The function must be passed <ul>
5667 * <li>The Record block object</li>
5668 * <li>The "arg" argument from the load function</li>
5669 * <li>A boolean success indicator</li>
5671 * @param {Object} scope The scope in which to call the callback
5672 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5674 load : function(params, reader, callback, scope, arg){
5675 params = params || {};
5678 result = reader.readRecords(this.data);
5680 this.fireEvent("loadexception", this, arg, null, e);
5681 callback.call(scope, null, arg, false);
5684 callback.call(scope, result, arg, true);
5688 update : function(params, records){
5693 * Ext JS Library 1.1.1
5694 * Copyright(c) 2006-2007, Ext JS, LLC.
5696 * Originally Released Under LGPL - original licence link has changed is not relivant.
5699 * <script type="text/javascript">
5702 * @class Roo.data.HttpProxy
5703 * @extends Roo.data.DataProxy
5704 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5705 * configured to reference a certain URL.<br><br>
5707 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5708 * from which the running page was served.<br><br>
5710 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5712 * Be aware that to enable the browser to parse an XML document, the server must set
5713 * the Content-Type header in the HTTP response to "text/xml".
5715 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5716 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5717 * will be used to make the request.
5719 Roo.data.HttpProxy = function(conn){
5720 Roo.data.HttpProxy.superclass.constructor.call(this);
5721 // is conn a conn config or a real conn?
5723 this.useAjax = !conn || !conn.events;
5727 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5728 // thse are take from connection...
5731 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5734 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5735 * extra parameters to each request made by this object. (defaults to undefined)
5738 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5739 * to each request made by this object. (defaults to undefined)
5742 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5745 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5748 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5754 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5758 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5759 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5760 * a finer-grained basis than the DataProxy events.
5762 getConnection : function(){
5763 return this.useAjax ? Roo.Ajax : this.conn;
5767 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5768 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5769 * process that block using the passed callback.
5770 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5771 * for the request to the remote server.
5772 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5773 * object into a block of Roo.data.Records.
5774 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5775 * The function must be passed <ul>
5776 * <li>The Record block object</li>
5777 * <li>The "arg" argument from the load function</li>
5778 * <li>A boolean success indicator</li>
5780 * @param {Object} scope The scope in which to call the callback
5781 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5783 load : function(params, reader, callback, scope, arg){
5784 if(this.fireEvent("beforeload", this, params) !== false){
5786 params : params || {},
5788 callback : callback,
5793 callback : this.loadResponse,
5797 Roo.applyIf(o, this.conn);
5798 if(this.activeRequest){
5799 Roo.Ajax.abort(this.activeRequest);
5801 this.activeRequest = Roo.Ajax.request(o);
5803 this.conn.request(o);
5806 callback.call(scope||this, null, arg, false);
5811 loadResponse : function(o, success, response){
5812 delete this.activeRequest;
5814 this.fireEvent("loadexception", this, o, response);
5815 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5820 result = o.reader.read(response);
5822 this.fireEvent("loadexception", this, o, response, e);
5823 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5827 this.fireEvent("load", this, o, o.request.arg);
5828 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5832 update : function(dataSet){
5837 updateResponse : function(dataSet){
5842 * Ext JS Library 1.1.1
5843 * Copyright(c) 2006-2007, Ext JS, LLC.
5845 * Originally Released Under LGPL - original licence link has changed is not relivant.
5848 * <script type="text/javascript">
5852 * @class Roo.data.ScriptTagProxy
5853 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5854 * other than the originating domain of the running page.<br><br>
5856 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5857 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5859 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5860 * source code that is used as the source inside a <script> tag.<br><br>
5862 * In order for the browser to process the returned data, the server must wrap the data object
5863 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5864 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5865 * depending on whether the callback name was passed:
5868 boolean scriptTag = false;
5869 String cb = request.getParameter("callback");
5872 response.setContentType("text/javascript");
5874 response.setContentType("application/x-json");
5876 Writer out = response.getWriter();
5878 out.write(cb + "(");
5880 out.print(dataBlock.toJsonString());
5887 * @param {Object} config A configuration object.
5889 Roo.data.ScriptTagProxy = function(config){
5890 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5891 Roo.apply(this, config);
5892 this.head = document.getElementsByTagName("head")[0];
5895 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5897 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5899 * @cfg {String} url The URL from which to request the data object.
5902 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5906 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5907 * the server the name of the callback function set up by the load call to process the returned data object.
5908 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5909 * javascript output which calls this named function passing the data object as its only parameter.
5911 callbackParam : "callback",
5913 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5914 * name to the request.
5919 * Load data from the configured URL, read the data object into
5920 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5921 * process that block using the passed callback.
5922 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5923 * for the request to the remote server.
5924 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5925 * object into a block of Roo.data.Records.
5926 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5927 * The function must be passed <ul>
5928 * <li>The Record block object</li>
5929 * <li>The "arg" argument from the load function</li>
5930 * <li>A boolean success indicator</li>
5932 * @param {Object} scope The scope in which to call the callback
5933 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5935 load : function(params, reader, callback, scope, arg){
5936 if(this.fireEvent("beforeload", this, params) !== false){
5938 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5941 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5943 url += "&_dc=" + (new Date().getTime());
5945 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5948 cb : "stcCallback"+transId,
5949 scriptId : "stcScript"+transId,
5953 callback : callback,
5959 window[trans.cb] = function(o){
5960 conn.handleResponse(o, trans);
5963 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5965 if(this.autoAbort !== false){
5969 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5971 var script = document.createElement("script");
5972 script.setAttribute("src", url);
5973 script.setAttribute("type", "text/javascript");
5974 script.setAttribute("id", trans.scriptId);
5975 this.head.appendChild(script);
5979 callback.call(scope||this, null, arg, false);
5984 isLoading : function(){
5985 return this.trans ? true : false;
5989 * Abort the current server request.
5992 if(this.isLoading()){
5993 this.destroyTrans(this.trans);
5998 destroyTrans : function(trans, isLoaded){
5999 this.head.removeChild(document.getElementById(trans.scriptId));
6000 clearTimeout(trans.timeoutId);
6002 window[trans.cb] = undefined;
6004 delete window[trans.cb];
6007 // if hasn't been loaded, wait for load to remove it to prevent script error
6008 window[trans.cb] = function(){
6009 window[trans.cb] = undefined;
6011 delete window[trans.cb];
6018 handleResponse : function(o, trans){
6020 this.destroyTrans(trans, true);
6023 result = trans.reader.readRecords(o);
6025 this.fireEvent("loadexception", this, o, trans.arg, e);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6029 this.fireEvent("load", this, o, trans.arg);
6030 trans.callback.call(trans.scope||window, result, trans.arg, true);
6034 handleFailure : function(trans){
6036 this.destroyTrans(trans, false);
6037 this.fireEvent("loadexception", this, null, trans.arg);
6038 trans.callback.call(trans.scope||window, null, trans.arg, false);
6042 * Ext JS Library 1.1.1
6043 * Copyright(c) 2006-2007, Ext JS, LLC.
6045 * Originally Released Under LGPL - original licence link has changed is not relivant.
6048 * <script type="text/javascript">
6052 * @class Roo.data.JsonReader
6053 * @extends Roo.data.DataReader
6054 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6055 * based on mappings in a provided Roo.data.Record constructor.
6057 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6058 * in the reply previously.
6063 var RecordDef = Roo.data.Record.create([
6064 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6065 {name: 'occupation'} // This field will use "occupation" as the mapping.
6067 var myReader = new Roo.data.JsonReader({
6068 totalProperty: "results", // The property which contains the total dataset size (optional)
6069 root: "rows", // The property which contains an Array of row objects
6070 id: "id" // The property within each row object that provides an ID for the record (optional)
6074 * This would consume a JSON file like this:
6076 { 'results': 2, 'rows': [
6077 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6078 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6081 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6082 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6083 * paged from the remote server.
6084 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6085 * @cfg {String} root name of the property which contains the Array of row objects.
6086 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6088 * Create a new JsonReader
6089 * @param {Object} meta Metadata configuration options
6090 * @param {Object} recordType Either an Array of field definition objects,
6091 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6093 Roo.data.JsonReader = function(meta, recordType){
6096 // set some defaults:
6098 totalProperty: 'total',
6099 successProperty : 'success',
6104 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6106 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6109 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6110 * Used by Store query builder to append _requestMeta to params.
6113 metaFromRemote : false,
6115 * This method is only used by a DataProxy which has retrieved data from a remote server.
6116 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6117 * @return {Object} data A data block which is used by an Roo.data.Store object as
6118 * a cache of Roo.data.Records.
6120 read : function(response){
6121 var json = response.responseText;
6123 var o = /* eval:var:o */ eval("("+json+")");
6125 throw {message: "JsonReader.read: Json object not found"};
6131 this.metaFromRemote = true;
6132 this.meta = o.metaData;
6133 this.recordType = Roo.data.Record.create(o.metaData.fields);
6134 this.onMetaChange(this.meta, this.recordType, o);
6136 return this.readRecords(o);
6139 // private function a store will implement
6140 onMetaChange : function(meta, recordType, o){
6147 simpleAccess: function(obj, subsc) {
6154 getJsonAccessor: function(){
6156 return function(expr) {
6158 return(re.test(expr))
6159 ? new Function("obj", "return obj." + expr)
6169 * Create a data block containing Roo.data.Records from an XML document.
6170 * @param {Object} o An object which contains an Array of row objects in the property specified
6171 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6172 * which contains the total size of the dataset.
6173 * @return {Object} data A data block which is used by an Roo.data.Store object as
6174 * a cache of Roo.data.Records.
6176 readRecords : function(o){
6178 * After any data loads, the raw JSON data is available for further custom processing.
6182 var s = this.meta, Record = this.recordType,
6183 f = Record.prototype.fields, fi = f.items, fl = f.length;
6185 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6187 if(s.totalProperty) {
6188 this.getTotal = this.getJsonAccessor(s.totalProperty);
6190 if(s.successProperty) {
6191 this.getSuccess = this.getJsonAccessor(s.successProperty);
6193 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6195 var g = this.getJsonAccessor(s.id);
6196 this.getId = function(rec) {
6198 return (r === undefined || r === "") ? null : r;
6201 this.getId = function(){return null;};
6204 for(var jj = 0; jj < fl; jj++){
6206 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6207 this.ef[jj] = this.getJsonAccessor(map);
6211 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6212 if(s.totalProperty){
6213 var vt = parseInt(this.getTotal(o), 10);
6218 if(s.successProperty){
6219 var vs = this.getSuccess(o);
6220 if(vs === false || vs === 'false'){
6225 for(var i = 0; i < c; i++){
6228 var id = this.getId(n);
6229 for(var j = 0; j < fl; j++){
6231 var v = this.ef[j](n);
6233 Roo.log('missing convert for ' + f.name);
6237 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6239 var record = new Record(values, id);
6241 records[i] = record;
6246 totalRecords : totalRecords
6251 * Ext JS Library 1.1.1
6252 * Copyright(c) 2006-2007, Ext JS, LLC.
6254 * Originally Released Under LGPL - original licence link has changed is not relivant.
6257 * <script type="text/javascript">
6261 * @class Roo.data.XmlReader
6262 * @extends Roo.data.DataReader
6263 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6264 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6266 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6267 * header in the HTTP response must be set to "text/xml".</em>
6271 var RecordDef = Roo.data.Record.create([
6272 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6273 {name: 'occupation'} // This field will use "occupation" as the mapping.
6275 var myReader = new Roo.data.XmlReader({
6276 totalRecords: "results", // The element which contains the total dataset size (optional)
6277 record: "row", // The repeated element which contains row information
6278 id: "id" // The element within the row that provides an ID for the record (optional)
6282 * This would consume an XML file like this:
6286 <results>2</results>
6289 <name>Bill</name>
6290 <occupation>Gardener</occupation>
6294 <name>Ben</name>
6295 <occupation>Horticulturalist</occupation>
6299 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6300 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6301 * paged from the remote server.
6302 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6303 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6304 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6305 * a record identifier value.
6307 * Create a new XmlReader
6308 * @param {Object} meta Metadata configuration options
6309 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6310 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6311 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6313 Roo.data.XmlReader = function(meta, recordType){
6315 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6317 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6319 * This method is only used by a DataProxy which has retrieved data from a remote server.
6320 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6321 * to contain a method called 'responseXML' that returns an XML document object.
6322 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6323 * a cache of Roo.data.Records.
6325 read : function(response){
6326 var doc = response.responseXML;
6328 throw {message: "XmlReader.read: XML Document not available"};
6330 return this.readRecords(doc);
6334 * Create a data block containing Roo.data.Records from an XML document.
6335 * @param {Object} doc A parsed XML document.
6336 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6337 * a cache of Roo.data.Records.
6339 readRecords : function(doc){
6341 * After any data loads/reads, the raw XML Document is available for further custom processing.
6345 var root = doc.documentElement || doc;
6346 var q = Roo.DomQuery;
6347 var recordType = this.recordType, fields = recordType.prototype.fields;
6348 var sid = this.meta.id;
6349 var totalRecords = 0, success = true;
6350 if(this.meta.totalRecords){
6351 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6354 if(this.meta.success){
6355 var sv = q.selectValue(this.meta.success, root, true);
6356 success = sv !== false && sv !== 'false';
6359 var ns = q.select(this.meta.record, root);
6360 for(var i = 0, len = ns.length; i < len; i++) {
6363 var id = sid ? q.selectValue(sid, n) : undefined;
6364 for(var j = 0, jlen = fields.length; j < jlen; j++){
6365 var f = fields.items[j];
6366 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6370 var record = new recordType(values, id);
6372 records[records.length] = record;
6378 totalRecords : totalRecords || records.length
6383 * Ext JS Library 1.1.1
6384 * Copyright(c) 2006-2007, Ext JS, LLC.
6386 * Originally Released Under LGPL - original licence link has changed is not relivant.
6389 * <script type="text/javascript">
6393 * @class Roo.data.ArrayReader
6394 * @extends Roo.data.DataReader
6395 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6396 * Each element of that Array represents a row of data fields. The
6397 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6398 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6402 var RecordDef = Roo.data.Record.create([
6403 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6404 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6406 var myReader = new Roo.data.ArrayReader({
6407 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6411 * This would consume an Array like this:
6413 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6415 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6417 * Create a new JsonReader
6418 * @param {Object} meta Metadata configuration options.
6419 * @param {Object} recordType Either an Array of field definition objects
6420 * as specified to {@link Roo.data.Record#create},
6421 * or an {@link Roo.data.Record} object
6422 * created using {@link Roo.data.Record#create}.
6424 Roo.data.ArrayReader = function(meta, recordType){
6425 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6428 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6430 * Create a data block containing Roo.data.Records from an XML document.
6431 * @param {Object} o An Array of row objects which represents the dataset.
6432 * @return {Object} data A data block which is used by an Roo.data.Store object as
6433 * a cache of Roo.data.Records.
6435 readRecords : function(o){
6436 var sid = this.meta ? this.meta.id : null;
6437 var recordType = this.recordType, fields = recordType.prototype.fields;
6440 for(var i = 0; i < root.length; i++){
6443 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6444 for(var j = 0, jlen = fields.length; j < jlen; j++){
6445 var f = fields.items[j];
6446 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6447 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6451 var record = new recordType(values, id);
6453 records[records.length] = record;
6457 totalRecords : records.length
6462 * Ext JS Library 1.1.1
6463 * Copyright(c) 2006-2007, Ext JS, LLC.
6465 * Originally Released Under LGPL - original licence link has changed is not relivant.
6468 * <script type="text/javascript">
6473 * @class Roo.data.Tree
6474 * @extends Roo.util.Observable
6475 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6476 * in the tree have most standard DOM functionality.
6478 * @param {Node} root (optional) The root node
6480 Roo.data.Tree = function(root){
6483 * The root node for this tree
6488 this.setRootNode(root);
6493 * Fires when a new child node is appended to a node in this tree.
6494 * @param {Tree} tree The owner tree
6495 * @param {Node} parent The parent node
6496 * @param {Node} node The newly appended node
6497 * @param {Number} index The index of the newly appended node
6502 * Fires when a child node is removed from a node in this tree.
6503 * @param {Tree} tree The owner tree
6504 * @param {Node} parent The parent node
6505 * @param {Node} node The child node removed
6510 * Fires when a node is moved to a new location in the tree
6511 * @param {Tree} tree The owner tree
6512 * @param {Node} node The node moved
6513 * @param {Node} oldParent The old parent of this node
6514 * @param {Node} newParent The new parent of this node
6515 * @param {Number} index The index it was moved to
6520 * Fires when a new child node is inserted in a node in this tree.
6521 * @param {Tree} tree The owner tree
6522 * @param {Node} parent The parent node
6523 * @param {Node} node The child node inserted
6524 * @param {Node} refNode The child node the node was inserted before
6528 * @event beforeappend
6529 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6530 * @param {Tree} tree The owner tree
6531 * @param {Node} parent The parent node
6532 * @param {Node} node The child node to be appended
6534 "beforeappend" : true,
6536 * @event beforeremove
6537 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6538 * @param {Tree} tree The owner tree
6539 * @param {Node} parent The parent node
6540 * @param {Node} node The child node to be removed
6542 "beforeremove" : true,
6545 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6546 * @param {Tree} tree The owner tree
6547 * @param {Node} node The node being moved
6548 * @param {Node} oldParent The parent of the node
6549 * @param {Node} newParent The new parent the node is moving to
6550 * @param {Number} index The index it is being moved to
6552 "beforemove" : true,
6554 * @event beforeinsert
6555 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6556 * @param {Tree} tree The owner tree
6557 * @param {Node} parent The parent node
6558 * @param {Node} node The child node to be inserted
6559 * @param {Node} refNode The child node the node is being inserted before
6561 "beforeinsert" : true
6564 Roo.data.Tree.superclass.constructor.call(this);
6567 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6570 proxyNodeEvent : function(){
6571 return this.fireEvent.apply(this, arguments);
6575 * Returns the root node for this tree.
6578 getRootNode : function(){
6583 * Sets the root node for this tree.
6584 * @param {Node} node
6587 setRootNode : function(node){
6589 node.ownerTree = this;
6591 this.registerNode(node);
6596 * Gets a node in this tree by its id.
6597 * @param {String} id
6600 getNodeById : function(id){
6601 return this.nodeHash[id];
6604 registerNode : function(node){
6605 this.nodeHash[node.id] = node;
6608 unregisterNode : function(node){
6609 delete this.nodeHash[node.id];
6612 toString : function(){
6613 return "[Tree"+(this.id?" "+this.id:"")+"]";
6618 * @class Roo.data.Node
6619 * @extends Roo.util.Observable
6620 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6621 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6623 * @param {Object} attributes The attributes/config for the node
6625 Roo.data.Node = function(attributes){
6627 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6630 this.attributes = attributes || {};
6631 this.leaf = this.attributes.leaf;
6633 * The node id. @type String
6635 this.id = this.attributes.id;
6637 this.id = Roo.id(null, "ynode-");
6638 this.attributes.id = this.id;
6641 * All child nodes of this node. @type Array
6643 this.childNodes = [];
6644 if(!this.childNodes.indexOf){ // indexOf is a must
6645 this.childNodes.indexOf = function(o){
6646 for(var i = 0, len = this.length; i < len; i++){
6655 * The parent node for this node. @type Node
6657 this.parentNode = null;
6659 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6661 this.firstChild = null;
6663 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6665 this.lastChild = null;
6667 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6669 this.previousSibling = null;
6671 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6673 this.nextSibling = null;
6678 * Fires when a new child node is appended
6679 * @param {Tree} tree The owner tree
6680 * @param {Node} this This node
6681 * @param {Node} node The newly appended node
6682 * @param {Number} index The index of the newly appended node
6687 * Fires when a child node is removed
6688 * @param {Tree} tree The owner tree
6689 * @param {Node} this This node
6690 * @param {Node} node The removed node
6695 * Fires when this node is moved to a new location in the tree
6696 * @param {Tree} tree The owner tree
6697 * @param {Node} this This node
6698 * @param {Node} oldParent The old parent of this node
6699 * @param {Node} newParent The new parent of this node
6700 * @param {Number} index The index it was moved to
6705 * Fires when a new child node is inserted.
6706 * @param {Tree} tree The owner tree
6707 * @param {Node} this This node
6708 * @param {Node} node The child node inserted
6709 * @param {Node} refNode The child node the node was inserted before
6713 * @event beforeappend
6714 * Fires before a new child is appended, return false to cancel the append.
6715 * @param {Tree} tree The owner tree
6716 * @param {Node} this This node
6717 * @param {Node} node The child node to be appended
6719 "beforeappend" : true,
6721 * @event beforeremove
6722 * Fires before a child is removed, return false to cancel the remove.
6723 * @param {Tree} tree The owner tree
6724 * @param {Node} this This node
6725 * @param {Node} node The child node to be removed
6727 "beforeremove" : true,
6730 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6731 * @param {Tree} tree The owner tree
6732 * @param {Node} this This node
6733 * @param {Node} oldParent The parent of this node
6734 * @param {Node} newParent The new parent this node is moving to
6735 * @param {Number} index The index it is being moved to
6737 "beforemove" : true,
6739 * @event beforeinsert
6740 * Fires before a new child is inserted, return false to cancel the insert.
6741 * @param {Tree} tree The owner tree
6742 * @param {Node} this This node
6743 * @param {Node} node The child node to be inserted
6744 * @param {Node} refNode The child node the node is being inserted before
6746 "beforeinsert" : true
6748 this.listeners = this.attributes.listeners;
6749 Roo.data.Node.superclass.constructor.call(this);
6752 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6753 fireEvent : function(evtName){
6754 // first do standard event for this node
6755 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6758 // then bubble it up to the tree if the event wasn't cancelled
6759 var ot = this.getOwnerTree();
6761 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6769 * Returns true if this node is a leaf
6772 isLeaf : function(){
6773 return this.leaf === true;
6777 setFirstChild : function(node){
6778 this.firstChild = node;
6782 setLastChild : function(node){
6783 this.lastChild = node;
6788 * Returns true if this node is the last child of its parent
6791 isLast : function(){
6792 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6796 * Returns true if this node is the first child of its parent
6799 isFirst : function(){
6800 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6803 hasChildNodes : function(){
6804 return !this.isLeaf() && this.childNodes.length > 0;
6808 * Insert node(s) as the last child node of this node.
6809 * @param {Node/Array} node The node or Array of nodes to append
6810 * @return {Node} The appended node if single append, or null if an array was passed
6812 appendChild : function(node){
6814 if(node instanceof Array){
6816 }else if(arguments.length > 1){
6819 // if passed an array or multiple args do them one by one
6821 for(var i = 0, len = multi.length; i < len; i++) {
6822 this.appendChild(multi[i]);
6825 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6828 var index = this.childNodes.length;
6829 var oldParent = node.parentNode;
6830 // it's a move, make sure we move it cleanly
6832 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6835 oldParent.removeChild(node);
6837 index = this.childNodes.length;
6839 this.setFirstChild(node);
6841 this.childNodes.push(node);
6842 node.parentNode = this;
6843 var ps = this.childNodes[index-1];
6845 node.previousSibling = ps;
6846 ps.nextSibling = node;
6848 node.previousSibling = null;
6850 node.nextSibling = null;
6851 this.setLastChild(node);
6852 node.setOwnerTree(this.getOwnerTree());
6853 this.fireEvent("append", this.ownerTree, this, node, index);
6855 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6862 * Removes a child node from this node.
6863 * @param {Node} node The node to remove
6864 * @return {Node} The removed node
6866 removeChild : function(node){
6867 var index = this.childNodes.indexOf(node);
6871 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6875 // remove it from childNodes collection
6876 this.childNodes.splice(index, 1);
6879 if(node.previousSibling){
6880 node.previousSibling.nextSibling = node.nextSibling;
6882 if(node.nextSibling){
6883 node.nextSibling.previousSibling = node.previousSibling;
6886 // update child refs
6887 if(this.firstChild == node){
6888 this.setFirstChild(node.nextSibling);
6890 if(this.lastChild == node){
6891 this.setLastChild(node.previousSibling);
6894 node.setOwnerTree(null);
6895 // clear any references from the node
6896 node.parentNode = null;
6897 node.previousSibling = null;
6898 node.nextSibling = null;
6899 this.fireEvent("remove", this.ownerTree, this, node);
6904 * Inserts the first node before the second node in this nodes childNodes collection.
6905 * @param {Node} node The node to insert
6906 * @param {Node} refNode The node to insert before (if null the node is appended)
6907 * @return {Node} The inserted node
6909 insertBefore : function(node, refNode){
6910 if(!refNode){ // like standard Dom, refNode can be null for append
6911 return this.appendChild(node);
6914 if(node == refNode){
6918 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6921 var index = this.childNodes.indexOf(refNode);
6922 var oldParent = node.parentNode;
6923 var refIndex = index;
6925 // when moving internally, indexes will change after remove
6926 if(oldParent == this && this.childNodes.indexOf(node) < index){
6930 // it's a move, make sure we move it cleanly
6932 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6935 oldParent.removeChild(node);
6938 this.setFirstChild(node);
6940 this.childNodes.splice(refIndex, 0, node);
6941 node.parentNode = this;
6942 var ps = this.childNodes[refIndex-1];
6944 node.previousSibling = ps;
6945 ps.nextSibling = node;
6947 node.previousSibling = null;
6949 node.nextSibling = refNode;
6950 refNode.previousSibling = node;
6951 node.setOwnerTree(this.getOwnerTree());
6952 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6954 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6960 * Returns the child node at the specified index.
6961 * @param {Number} index
6964 item : function(index){
6965 return this.childNodes[index];
6969 * Replaces one child node in this node with another.
6970 * @param {Node} newChild The replacement node
6971 * @param {Node} oldChild The node to replace
6972 * @return {Node} The replaced node
6974 replaceChild : function(newChild, oldChild){
6975 this.insertBefore(newChild, oldChild);
6976 this.removeChild(oldChild);
6981 * Returns the index of a child node
6982 * @param {Node} node
6983 * @return {Number} The index of the node or -1 if it was not found
6985 indexOf : function(child){
6986 return this.childNodes.indexOf(child);
6990 * Returns the tree this node is in.
6993 getOwnerTree : function(){
6994 // if it doesn't have one, look for one
6995 if(!this.ownerTree){
6999 this.ownerTree = p.ownerTree;
7005 return this.ownerTree;
7009 * Returns depth of this node (the root node has a depth of 0)
7012 getDepth : function(){
7015 while(p.parentNode){
7023 setOwnerTree : function(tree){
7024 // if it's move, we need to update everyone
7025 if(tree != this.ownerTree){
7027 this.ownerTree.unregisterNode(this);
7029 this.ownerTree = tree;
7030 var cs = this.childNodes;
7031 for(var i = 0, len = cs.length; i < len; i++) {
7032 cs[i].setOwnerTree(tree);
7035 tree.registerNode(this);
7041 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7042 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7043 * @return {String} The path
7045 getPath : function(attr){
7046 attr = attr || "id";
7047 var p = this.parentNode;
7048 var b = [this.attributes[attr]];
7050 b.unshift(p.attributes[attr]);
7053 var sep = this.getOwnerTree().pathSeparator;
7054 return sep + b.join(sep);
7058 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7059 * function call will be the scope provided or the current node. The arguments to the function
7060 * will be the args provided or the current node. If the function returns false at any point,
7061 * the bubble is stopped.
7062 * @param {Function} fn The function to call
7063 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7064 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7066 bubble : function(fn, scope, args){
7069 if(fn.call(scope || p, args || p) === false){
7077 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7078 * function call will be the scope provided or the current node. The arguments to the function
7079 * will be the args provided or the current node. If the function returns false at any point,
7080 * the cascade is stopped on that branch.
7081 * @param {Function} fn The function to call
7082 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7083 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7085 cascade : function(fn, scope, args){
7086 if(fn.call(scope || this, args || this) !== false){
7087 var cs = this.childNodes;
7088 for(var i = 0, len = cs.length; i < len; i++) {
7089 cs[i].cascade(fn, scope, args);
7095 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7096 * function call will be the scope provided or the current node. The arguments to the function
7097 * will be the args provided or the current node. If the function returns false at any point,
7098 * the iteration stops.
7099 * @param {Function} fn The function to call
7100 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7101 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7103 eachChild : function(fn, scope, args){
7104 var cs = this.childNodes;
7105 for(var i = 0, len = cs.length; i < len; i++) {
7106 if(fn.call(scope || this, args || cs[i]) === false){
7113 * Finds the first child that has the attribute with the specified value.
7114 * @param {String} attribute The attribute name
7115 * @param {Mixed} value The value to search for
7116 * @return {Node} The found child or null if none was found
7118 findChild : function(attribute, value){
7119 var cs = this.childNodes;
7120 for(var i = 0, len = cs.length; i < len; i++) {
7121 if(cs[i].attributes[attribute] == value){
7129 * Finds the first child by a custom function. The child matches if the function passed
7131 * @param {Function} fn
7132 * @param {Object} scope (optional)
7133 * @return {Node} The found child or null if none was found
7135 findChildBy : function(fn, scope){
7136 var cs = this.childNodes;
7137 for(var i = 0, len = cs.length; i < len; i++) {
7138 if(fn.call(scope||cs[i], cs[i]) === true){
7146 * Sorts this nodes children using the supplied sort function
7147 * @param {Function} fn
7148 * @param {Object} scope (optional)
7150 sort : function(fn, scope){
7151 var cs = this.childNodes;
7152 var len = cs.length;
7154 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7156 for(var i = 0; i < len; i++){
7158 n.previousSibling = cs[i-1];
7159 n.nextSibling = cs[i+1];
7161 this.setFirstChild(n);
7164 this.setLastChild(n);
7171 * Returns true if this node is an ancestor (at any point) of the passed node.
7172 * @param {Node} node
7175 contains : function(node){
7176 return node.isAncestor(this);
7180 * Returns true if the passed node is an ancestor (at any point) of this node.
7181 * @param {Node} node
7184 isAncestor : function(node){
7185 var p = this.parentNode;
7195 toString : function(){
7196 return "[Node"+(this.id?" "+this.id:"")+"]";
7200 * Ext JS Library 1.1.1
7201 * Copyright(c) 2006-2007, Ext JS, LLC.
7203 * Originally Released Under LGPL - original licence link has changed is not relivant.
7206 * <script type="text/javascript">
7211 * @class Roo.ComponentMgr
7212 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7215 Roo.ComponentMgr = function(){
7216 var all = new Roo.util.MixedCollection();
7220 * Registers a component.
7221 * @param {Roo.Component} c The component
7223 register : function(c){
7228 * Unregisters a component.
7229 * @param {Roo.Component} c The component
7231 unregister : function(c){
7236 * Returns a component by id
7237 * @param {String} id The component id
7244 * Registers a function that will be called when a specified component is added to ComponentMgr
7245 * @param {String} id The component id
7246 * @param {Funtction} fn The callback function
7247 * @param {Object} scope The scope of the callback
7249 onAvailable : function(id, fn, scope){
7250 all.on("add", function(index, o){
7252 fn.call(scope || o, o);
7253 all.un("add", fn, scope);
7260 * Ext JS Library 1.1.1
7261 * Copyright(c) 2006-2007, Ext JS, LLC.
7263 * Originally Released Under LGPL - original licence link has changed is not relivant.
7266 * <script type="text/javascript">
7270 * @class Roo.Component
7271 * @extends Roo.util.Observable
7272 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7273 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7274 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7275 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7276 * All visual components (widgets) that require rendering into a layout should subclass Component.
7278 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7279 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
7280 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7282 Roo.Component = function(config){
7283 config = config || {};
7284 if(config.tagName || config.dom || typeof config == "string"){ // element object
7285 config = {el: config, id: config.id || config};
7287 this.initialConfig = config;
7289 Roo.apply(this, config);
7293 * Fires after the component is disabled.
7294 * @param {Roo.Component} this
7299 * Fires after the component is enabled.
7300 * @param {Roo.Component} this
7305 * Fires before the component is shown. Return false to stop the show.
7306 * @param {Roo.Component} this
7311 * Fires after the component is shown.
7312 * @param {Roo.Component} this
7317 * Fires before the component is hidden. Return false to stop the hide.
7318 * @param {Roo.Component} this
7323 * Fires after the component is hidden.
7324 * @param {Roo.Component} this
7328 * @event beforerender
7329 * Fires before the component is rendered. Return false to stop the render.
7330 * @param {Roo.Component} this
7332 beforerender : true,
7335 * Fires after the component is rendered.
7336 * @param {Roo.Component} this
7340 * @event beforedestroy
7341 * Fires before the component is destroyed. Return false to stop the destroy.
7342 * @param {Roo.Component} this
7344 beforedestroy : true,
7347 * Fires after the component is destroyed.
7348 * @param {Roo.Component} this
7353 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7355 Roo.ComponentMgr.register(this);
7356 Roo.Component.superclass.constructor.call(this);
7357 this.initComponent();
7358 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7359 this.render(this.renderTo);
7360 delete this.renderTo;
7365 Roo.Component.AUTO_ID = 1000;
7367 Roo.extend(Roo.Component, Roo.util.Observable, {
7369 * @property {Boolean} hidden
7370 * true if this component is hidden. Read-only.
7374 * true if this component is disabled. Read-only.
7378 * true if this component has been rendered. Read-only.
7382 /** @cfg {String} disableClass
7383 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7385 disabledClass : "x-item-disabled",
7386 /** @cfg {Boolean} allowDomMove
7387 * Whether the component can move the Dom node when rendering (defaults to true).
7389 allowDomMove : true,
7390 /** @cfg {String} hideMode
7391 * How this component should hidden. Supported values are
7392 * "visibility" (css visibility), "offsets" (negative offset position) and
7393 * "display" (css display) - defaults to "display".
7395 hideMode: 'display',
7398 ctype : "Roo.Component",
7400 /** @cfg {String} actionMode
7401 * which property holds the element that used for hide() / show() / disable() / enable()
7407 getActionEl : function(){
7408 return this[this.actionMode];
7411 initComponent : Roo.emptyFn,
7413 * If this is a lazy rendering component, render it to its container element.
7414 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
7416 render : function(container, position){
7417 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7418 if(!container && this.el){
7419 this.el = Roo.get(this.el);
7420 container = this.el.dom.parentNode;
7421 this.allowDomMove = false;
7423 this.container = Roo.get(container);
7424 this.rendered = true;
7425 if(position !== undefined){
7426 if(typeof position == 'number'){
7427 position = this.container.dom.childNodes[position];
7429 position = Roo.getDom(position);
7432 this.onRender(this.container, position || null);
7434 this.el.addClass(this.cls);
7438 this.el.applyStyles(this.style);
7441 this.fireEvent("render", this);
7442 this.afterRender(this.container);
7454 // default function is not really useful
7455 onRender : function(ct, position){
7457 this.el = Roo.get(this.el);
7458 if(this.allowDomMove !== false){
7459 ct.dom.insertBefore(this.el.dom, position);
7465 getAutoCreate : function(){
7466 var cfg = typeof this.autoCreate == "object" ?
7467 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7468 if(this.id && !cfg.id){
7475 afterRender : Roo.emptyFn,
7478 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7479 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7481 destroy : function(){
7482 if(this.fireEvent("beforedestroy", this) !== false){
7483 this.purgeListeners();
7484 this.beforeDestroy();
7486 this.el.removeAllListeners();
7488 if(this.actionMode == "container"){
7489 this.container.remove();
7493 Roo.ComponentMgr.unregister(this);
7494 this.fireEvent("destroy", this);
7499 beforeDestroy : function(){
7504 onDestroy : function(){
7509 * Returns the underlying {@link Roo.Element}.
7510 * @return {Roo.Element} The element
7517 * Returns the id of this component.
7525 * Try to focus this component.
7526 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7527 * @return {Roo.Component} this
7529 focus : function(selectText){
7532 if(selectText === true){
7533 this.el.dom.select();
7548 * Disable this component.
7549 * @return {Roo.Component} this
7551 disable : function(){
7555 this.disabled = true;
7556 this.fireEvent("disable", this);
7561 onDisable : function(){
7562 this.getActionEl().addClass(this.disabledClass);
7563 this.el.dom.disabled = true;
7567 * Enable this component.
7568 * @return {Roo.Component} this
7570 enable : function(){
7574 this.disabled = false;
7575 this.fireEvent("enable", this);
7580 onEnable : function(){
7581 this.getActionEl().removeClass(this.disabledClass);
7582 this.el.dom.disabled = false;
7586 * Convenience function for setting disabled/enabled by boolean.
7587 * @param {Boolean} disabled
7589 setDisabled : function(disabled){
7590 this[disabled ? "disable" : "enable"]();
7594 * Show this component.
7595 * @return {Roo.Component} this
7598 if(this.fireEvent("beforeshow", this) !== false){
7599 this.hidden = false;
7603 this.fireEvent("show", this);
7609 onShow : function(){
7610 var ae = this.getActionEl();
7611 if(this.hideMode == 'visibility'){
7612 ae.dom.style.visibility = "visible";
7613 }else if(this.hideMode == 'offsets'){
7614 ae.removeClass('x-hidden');
7616 ae.dom.style.display = "";
7621 * Hide this component.
7622 * @return {Roo.Component} this
7625 if(this.fireEvent("beforehide", this) !== false){
7630 this.fireEvent("hide", this);
7636 onHide : function(){
7637 var ae = this.getActionEl();
7638 if(this.hideMode == 'visibility'){
7639 ae.dom.style.visibility = "hidden";
7640 }else if(this.hideMode == 'offsets'){
7641 ae.addClass('x-hidden');
7643 ae.dom.style.display = "none";
7648 * Convenience function to hide or show this component by boolean.
7649 * @param {Boolean} visible True to show, false to hide
7650 * @return {Roo.Component} this
7652 setVisible: function(visible){
7662 * Returns true if this component is visible.
7664 isVisible : function(){
7665 return this.getActionEl().isVisible();
7668 cloneConfig : function(overrides){
7669 overrides = overrides || {};
7670 var id = overrides.id || Roo.id();
7671 var cfg = Roo.applyIf(overrides, this.initialConfig);
7672 cfg.id = id; // prevent dup id
7673 return new this.constructor(cfg);
7677 * Ext JS Library 1.1.1
7678 * Copyright(c) 2006-2007, Ext JS, LLC.
7680 * Originally Released Under LGPL - original licence link has changed is not relivant.
7683 * <script type="text/javascript">
7688 * @extends Roo.Element
7689 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7690 * automatic maintaining of shadow/shim positions.
7691 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7692 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7693 * you can pass a string with a CSS class name. False turns off the shadow.
7694 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7695 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7696 * @cfg {String} cls CSS class to add to the element
7697 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7698 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7700 * @param {Object} config An object with config options.
7701 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7704 Roo.Layer = function(config, existingEl){
7705 config = config || {};
7706 var dh = Roo.DomHelper;
7707 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7709 this.dom = Roo.getDom(existingEl);
7712 var o = config.dh || {tag: "div", cls: "x-layer"};
7713 this.dom = dh.append(pel, o);
7716 this.addClass(config.cls);
7718 this.constrain = config.constrain !== false;
7719 this.visibilityMode = Roo.Element.VISIBILITY;
7721 this.id = this.dom.id = config.id;
7723 this.id = Roo.id(this.dom);
7725 this.zindex = config.zindex || this.getZIndex();
7726 this.position("absolute", this.zindex);
7728 this.shadowOffset = config.shadowOffset || 4;
7729 this.shadow = new Roo.Shadow({
7730 offset : this.shadowOffset,
7731 mode : config.shadow
7734 this.shadowOffset = 0;
7736 this.useShim = config.shim !== false && Roo.useShims;
7737 this.useDisplay = config.useDisplay;
7741 var supr = Roo.Element.prototype;
7743 // shims are shared among layer to keep from having 100 iframes
7746 Roo.extend(Roo.Layer, Roo.Element, {
7748 getZIndex : function(){
7749 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7752 getShim : function(){
7759 var shim = shims.shift();
7761 shim = this.createShim();
7762 shim.enableDisplayMode('block');
7763 shim.dom.style.display = 'none';
7764 shim.dom.style.visibility = 'visible';
7766 var pn = this.dom.parentNode;
7767 if(shim.dom.parentNode != pn){
7768 pn.insertBefore(shim.dom, this.dom);
7770 shim.setStyle('z-index', this.getZIndex()-2);
7775 hideShim : function(){
7777 this.shim.setDisplayed(false);
7778 shims.push(this.shim);
7783 disableShadow : function(){
7785 this.shadowDisabled = true;
7787 this.lastShadowOffset = this.shadowOffset;
7788 this.shadowOffset = 0;
7792 enableShadow : function(show){
7794 this.shadowDisabled = false;
7795 this.shadowOffset = this.lastShadowOffset;
7796 delete this.lastShadowOffset;
7804 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7805 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7806 sync : function(doShow){
7807 var sw = this.shadow;
7808 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7809 var sh = this.getShim();
7811 var w = this.getWidth(),
7812 h = this.getHeight();
7814 var l = this.getLeft(true),
7815 t = this.getTop(true);
7817 if(sw && !this.shadowDisabled){
7818 if(doShow && !sw.isVisible()){
7821 sw.realign(l, t, w, h);
7827 // fit the shim behind the shadow, so it is shimmed too
7828 var a = sw.adjusts, s = sh.dom.style;
7829 s.left = (Math.min(l, l+a.l))+"px";
7830 s.top = (Math.min(t, t+a.t))+"px";
7831 s.width = (w+a.w)+"px";
7832 s.height = (h+a.h)+"px";
7839 sh.setLeftTop(l, t);
7846 destroy : function(){
7851 this.removeAllListeners();
7852 var pn = this.dom.parentNode;
7854 pn.removeChild(this.dom);
7856 Roo.Element.uncache(this.id);
7859 remove : function(){
7864 beginUpdate : function(){
7865 this.updating = true;
7869 endUpdate : function(){
7870 this.updating = false;
7875 hideUnders : function(negOffset){
7883 constrainXY : function(){
7885 var vw = Roo.lib.Dom.getViewWidth(),
7886 vh = Roo.lib.Dom.getViewHeight();
7887 var s = Roo.get(document).getScroll();
7889 var xy = this.getXY();
7890 var x = xy[0], y = xy[1];
7891 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7892 // only move it if it needs it
7894 // first validate right/bottom
7895 if((x + w) > vw+s.left){
7896 x = vw - w - this.shadowOffset;
7899 if((y + h) > vh+s.top){
7900 y = vh - h - this.shadowOffset;
7903 // then make sure top/left isn't negative
7914 var ay = this.avoidY;
7915 if(y <= ay && (y+h) >= ay){
7921 supr.setXY.call(this, xy);
7927 isVisible : function(){
7928 return this.visible;
7932 showAction : function(){
7933 this.visible = true; // track visibility to prevent getStyle calls
7934 if(this.useDisplay === true){
7935 this.setDisplayed("");
7936 }else if(this.lastXY){
7937 supr.setXY.call(this, this.lastXY);
7938 }else if(this.lastLT){
7939 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7944 hideAction : function(){
7945 this.visible = false;
7946 if(this.useDisplay === true){
7947 this.setDisplayed(false);
7949 this.setLeftTop(-10000,-10000);
7953 // overridden Element method
7954 setVisible : function(v, a, d, c, e){
7959 var cb = function(){
7964 }.createDelegate(this);
7965 supr.setVisible.call(this, true, true, d, cb, e);
7968 this.hideUnders(true);
7977 }.createDelegate(this);
7979 supr.setVisible.call(this, v, a, d, cb, e);
7988 storeXY : function(xy){
7993 storeLeftTop : function(left, top){
7995 this.lastLT = [left, top];
7999 beforeFx : function(){
8000 this.beforeAction();
8001 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8005 afterFx : function(){
8006 Roo.Layer.superclass.afterFx.apply(this, arguments);
8007 this.sync(this.isVisible());
8011 beforeAction : function(){
8012 if(!this.updating && this.shadow){
8017 // overridden Element method
8018 setLeft : function(left){
8019 this.storeLeftTop(left, this.getTop(true));
8020 supr.setLeft.apply(this, arguments);
8024 setTop : function(top){
8025 this.storeLeftTop(this.getLeft(true), top);
8026 supr.setTop.apply(this, arguments);
8030 setLeftTop : function(left, top){
8031 this.storeLeftTop(left, top);
8032 supr.setLeftTop.apply(this, arguments);
8036 setXY : function(xy, a, d, c, e){
8038 this.beforeAction();
8040 var cb = this.createCB(c);
8041 supr.setXY.call(this, xy, a, d, cb, e);
8048 createCB : function(c){
8059 // overridden Element method
8060 setX : function(x, a, d, c, e){
8061 this.setXY([x, this.getY()], a, d, c, e);
8064 // overridden Element method
8065 setY : function(y, a, d, c, e){
8066 this.setXY([this.getX(), y], a, d, c, e);
8069 // overridden Element method
8070 setSize : function(w, h, a, d, c, e){
8071 this.beforeAction();
8072 var cb = this.createCB(c);
8073 supr.setSize.call(this, w, h, a, d, cb, e);
8079 // overridden Element method
8080 setWidth : function(w, a, d, c, e){
8081 this.beforeAction();
8082 var cb = this.createCB(c);
8083 supr.setWidth.call(this, w, a, d, cb, e);
8089 // overridden Element method
8090 setHeight : function(h, a, d, c, e){
8091 this.beforeAction();
8092 var cb = this.createCB(c);
8093 supr.setHeight.call(this, h, a, d, cb, e);
8099 // overridden Element method
8100 setBounds : function(x, y, w, h, a, d, c, e){
8101 this.beforeAction();
8102 var cb = this.createCB(c);
8104 this.storeXY([x, y]);
8105 supr.setXY.call(this, [x, y]);
8106 supr.setSize.call(this, w, h, a, d, cb, e);
8109 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8115 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8116 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8117 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8118 * @param {Number} zindex The new z-index to set
8119 * @return {this} The Layer
8121 setZIndex : function(zindex){
8122 this.zindex = zindex;
8123 this.setStyle("z-index", zindex + 2);
8125 this.shadow.setZIndex(zindex + 1);
8128 this.shim.setStyle("z-index", zindex);
8134 * Ext JS Library 1.1.1
8135 * Copyright(c) 2006-2007, Ext JS, LLC.
8137 * Originally Released Under LGPL - original licence link has changed is not relivant.
8140 * <script type="text/javascript">
8146 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8147 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8148 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8150 * Create a new Shadow
8151 * @param {Object} config The config object
8153 Roo.Shadow = function(config){
8154 Roo.apply(this, config);
8155 if(typeof this.mode != "string"){
8156 this.mode = this.defaultMode;
8158 var o = this.offset, a = {h: 0};
8159 var rad = Math.floor(this.offset/2);
8160 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8166 a.l -= this.offset + rad;
8167 a.t -= this.offset + rad;
8178 a.l -= (this.offset - rad);
8179 a.t -= this.offset + rad;
8181 a.w -= (this.offset - rad)*2;
8192 a.l -= (this.offset - rad);
8193 a.t -= (this.offset - rad);
8195 a.w -= (this.offset + rad + 1);
8196 a.h -= (this.offset + rad);
8205 Roo.Shadow.prototype = {
8207 * @cfg {String} mode
8208 * The shadow display mode. Supports the following options:<br />
8209 * sides: Shadow displays on both sides and bottom only<br />
8210 * frame: Shadow displays equally on all four sides<br />
8211 * drop: Traditional bottom-right drop shadow (default)
8214 * @cfg {String} offset
8215 * The number of pixels to offset the shadow from the element (defaults to 4)
8220 defaultMode: "drop",
8223 * Displays the shadow under the target element
8224 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8226 show : function(target){
8227 target = Roo.get(target);
8229 this.el = Roo.Shadow.Pool.pull();
8230 if(this.el.dom.nextSibling != target.dom){
8231 this.el.insertBefore(target);
8234 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8236 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8239 target.getLeft(true),
8240 target.getTop(true),
8244 this.el.dom.style.display = "block";
8248 * Returns true if the shadow is visible, else false
8250 isVisible : function(){
8251 return this.el ? true : false;
8255 * Direct alignment when values are already available. Show must be called at least once before
8256 * calling this method to ensure it is initialized.
8257 * @param {Number} left The target element left position
8258 * @param {Number} top The target element top position
8259 * @param {Number} width The target element width
8260 * @param {Number} height The target element height
8262 realign : function(l, t, w, h){
8266 var a = this.adjusts, d = this.el.dom, s = d.style;
8268 s.left = (l+a.l)+"px";
8269 s.top = (t+a.t)+"px";
8270 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8272 if(s.width != sws || s.height != shs){
8276 var cn = d.childNodes;
8277 var sww = Math.max(0, (sw-12))+"px";
8278 cn[0].childNodes[1].style.width = sww;
8279 cn[1].childNodes[1].style.width = sww;
8280 cn[2].childNodes[1].style.width = sww;
8281 cn[1].style.height = Math.max(0, (sh-12))+"px";
8291 this.el.dom.style.display = "none";
8292 Roo.Shadow.Pool.push(this.el);
8298 * Adjust the z-index of this shadow
8299 * @param {Number} zindex The new z-index
8301 setZIndex : function(z){
8304 this.el.setStyle("z-index", z);
8309 // Private utility class that manages the internal Shadow cache
8310 Roo.Shadow.Pool = function(){
8312 var markup = Roo.isIE ?
8313 '<div class="x-ie-shadow"></div>' :
8314 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
8319 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8320 sh.autoBoxAdjust = false;
8325 push : function(sh){
8331 * Ext JS Library 1.1.1
8332 * Copyright(c) 2006-2007, Ext JS, LLC.
8334 * Originally Released Under LGPL - original licence link has changed is not relivant.
8337 * <script type="text/javascript">
8341 * @class Roo.BoxComponent
8342 * @extends Roo.Component
8343 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8344 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8345 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8346 * layout containers.
8348 * @param {Roo.Element/String/Object} config The configuration options.
8350 Roo.BoxComponent = function(config){
8351 Roo.Component.call(this, config);
8355 * Fires after the component is resized.
8356 * @param {Roo.Component} this
8357 * @param {Number} adjWidth The box-adjusted width that was set
8358 * @param {Number} adjHeight The box-adjusted height that was set
8359 * @param {Number} rawWidth The width that was originally specified
8360 * @param {Number} rawHeight The height that was originally specified
8365 * Fires after the component is moved.
8366 * @param {Roo.Component} this
8367 * @param {Number} x The new x position
8368 * @param {Number} y The new y position
8374 Roo.extend(Roo.BoxComponent, Roo.Component, {
8375 // private, set in afterRender to signify that the component has been rendered
8377 // private, used to defer height settings to subclasses
8379 /** @cfg {Number} width
8380 * width (optional) size of component
8382 /** @cfg {Number} height
8383 * height (optional) size of component
8387 * Sets the width and height of the component. This method fires the resize event. This method can accept
8388 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8389 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8390 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8391 * @return {Roo.BoxComponent} this
8393 setSize : function(w, h){
8394 // support for standard size objects
8395 if(typeof w == 'object'){
8406 // prevent recalcs when not needed
8407 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8410 this.lastSize = {width: w, height: h};
8412 var adj = this.adjustSize(w, h);
8413 var aw = adj.width, ah = adj.height;
8414 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8415 var rz = this.getResizeEl();
8416 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8418 }else if(!this.deferHeight && ah !== undefined){
8420 }else if(aw !== undefined){
8423 this.onResize(aw, ah, w, h);
8424 this.fireEvent('resize', this, aw, ah, w, h);
8430 * Gets the current size of the component's underlying element.
8431 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8433 getSize : function(){
8434 return this.el.getSize();
8438 * Gets the current XY position of the component's underlying element.
8439 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8440 * @return {Array} The XY position of the element (e.g., [100, 200])
8442 getPosition : function(local){
8444 return [this.el.getLeft(true), this.el.getTop(true)];
8446 return this.xy || this.el.getXY();
8450 * Gets the current box measurements of the component's underlying element.
8451 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8452 * @returns {Object} box An object in the format {x, y, width, height}
8454 getBox : function(local){
8455 var s = this.el.getSize();
8457 s.x = this.el.getLeft(true);
8458 s.y = this.el.getTop(true);
8460 var xy = this.xy || this.el.getXY();
8468 * Sets the current box measurements of the component's underlying element.
8469 * @param {Object} box An object in the format {x, y, width, height}
8470 * @returns {Roo.BoxComponent} this
8472 updateBox : function(box){
8473 this.setSize(box.width, box.height);
8474 this.setPagePosition(box.x, box.y);
8479 getResizeEl : function(){
8480 return this.resizeEl || this.el;
8484 getPositionEl : function(){
8485 return this.positionEl || this.el;
8489 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8490 * This method fires the move event.
8491 * @param {Number} left The new left
8492 * @param {Number} top The new top
8493 * @returns {Roo.BoxComponent} this
8495 setPosition : function(x, y){
8501 var adj = this.adjustPosition(x, y);
8502 var ax = adj.x, ay = adj.y;
8504 var el = this.getPositionEl();
8505 if(ax !== undefined || ay !== undefined){
8506 if(ax !== undefined && ay !== undefined){
8507 el.setLeftTop(ax, ay);
8508 }else if(ax !== undefined){
8510 }else if(ay !== undefined){
8513 this.onPosition(ax, ay);
8514 this.fireEvent('move', this, ax, ay);
8520 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8521 * This method fires the move event.
8522 * @param {Number} x The new x position
8523 * @param {Number} y The new y position
8524 * @returns {Roo.BoxComponent} this
8526 setPagePosition : function(x, y){
8532 if(x === undefined || y === undefined){ // cannot translate undefined points
8535 var p = this.el.translatePoints(x, y);
8536 this.setPosition(p.left, p.top);
8541 onRender : function(ct, position){
8542 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8544 this.resizeEl = Roo.get(this.resizeEl);
8546 if(this.positionEl){
8547 this.positionEl = Roo.get(this.positionEl);
8552 afterRender : function(){
8553 Roo.BoxComponent.superclass.afterRender.call(this);
8554 this.boxReady = true;
8555 this.setSize(this.width, this.height);
8556 if(this.x || this.y){
8557 this.setPosition(this.x, this.y);
8559 if(this.pageX || this.pageY){
8560 this.setPagePosition(this.pageX, this.pageY);
8565 * Force the component's size to recalculate based on the underlying element's current height and width.
8566 * @returns {Roo.BoxComponent} this
8568 syncSize : function(){
8569 delete this.lastSize;
8570 this.setSize(this.el.getWidth(), this.el.getHeight());
8575 * Called after the component is resized, this method is empty by default but can be implemented by any
8576 * subclass that needs to perform custom logic after a resize occurs.
8577 * @param {Number} adjWidth The box-adjusted width that was set
8578 * @param {Number} adjHeight The box-adjusted height that was set
8579 * @param {Number} rawWidth The width that was originally specified
8580 * @param {Number} rawHeight The height that was originally specified
8582 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8587 * Called after the component is moved, this method is empty by default but can be implemented by any
8588 * subclass that needs to perform custom logic after a move occurs.
8589 * @param {Number} x The new x position
8590 * @param {Number} y The new y position
8592 onPosition : function(x, y){
8597 adjustSize : function(w, h){
8601 if(this.autoHeight){
8604 return {width : w, height: h};
8608 adjustPosition : function(x, y){
8609 return {x : x, y: y};
8613 * Ext JS Library 1.1.1
8614 * Copyright(c) 2006-2007, Ext JS, LLC.
8616 * Originally Released Under LGPL - original licence link has changed is not relivant.
8619 * <script type="text/javascript">
8624 * @class Roo.SplitBar
8625 * @extends Roo.util.Observable
8626 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8630 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8631 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8632 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8633 split.minSize = 100;
8634 split.maxSize = 600;
8635 split.animate = true;
8636 split.on('moved', splitterMoved);
8639 * Create a new SplitBar
8640 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8641 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8642 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8643 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8644 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8645 position of the SplitBar).
8647 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8650 this.el = Roo.get(dragElement, true);
8651 this.el.dom.unselectable = "on";
8653 this.resizingEl = Roo.get(resizingElement, true);
8657 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8658 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8661 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8664 * The minimum size of the resizing element. (Defaults to 0)
8670 * The maximum size of the resizing element. (Defaults to 2000)
8673 this.maxSize = 2000;
8676 * Whether to animate the transition to the new size
8679 this.animate = false;
8682 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8685 this.useShim = false;
8692 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8694 this.proxy = Roo.get(existingProxy).dom;
8697 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8700 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8703 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8706 this.dragSpecs = {};
8709 * @private The adapter to use to positon and resize elements
8711 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8712 this.adapter.init(this);
8714 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8716 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8717 this.el.addClass("x-splitbar-h");
8720 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8721 this.el.addClass("x-splitbar-v");
8727 * Fires when the splitter is moved (alias for {@link #event-moved})
8728 * @param {Roo.SplitBar} this
8729 * @param {Number} newSize the new width or height
8734 * Fires when the splitter is moved
8735 * @param {Roo.SplitBar} this
8736 * @param {Number} newSize the new width or height
8740 * @event beforeresize
8741 * Fires before the splitter is dragged
8742 * @param {Roo.SplitBar} this
8744 "beforeresize" : true,
8746 "beforeapply" : true
8749 Roo.util.Observable.call(this);
8752 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8753 onStartProxyDrag : function(x, y){
8754 this.fireEvent("beforeresize", this);
8756 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8758 o.enableDisplayMode("block");
8759 // all splitbars share the same overlay
8760 Roo.SplitBar.prototype.overlay = o;
8762 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8763 this.overlay.show();
8764 Roo.get(this.proxy).setDisplayed("block");
8765 var size = this.adapter.getElementSize(this);
8766 this.activeMinSize = this.getMinimumSize();;
8767 this.activeMaxSize = this.getMaximumSize();;
8768 var c1 = size - this.activeMinSize;
8769 var c2 = Math.max(this.activeMaxSize - size, 0);
8770 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8771 this.dd.resetConstraints();
8772 this.dd.setXConstraint(
8773 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8774 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8776 this.dd.setYConstraint(0, 0);
8778 this.dd.resetConstraints();
8779 this.dd.setXConstraint(0, 0);
8780 this.dd.setYConstraint(
8781 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8782 this.placement == Roo.SplitBar.TOP ? c2 : c1
8785 this.dragSpecs.startSize = size;
8786 this.dragSpecs.startPoint = [x, y];
8787 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8791 * @private Called after the drag operation by the DDProxy
8793 onEndProxyDrag : function(e){
8794 Roo.get(this.proxy).setDisplayed(false);
8795 var endPoint = Roo.lib.Event.getXY(e);
8797 this.overlay.hide();
8800 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8801 newSize = this.dragSpecs.startSize +
8802 (this.placement == Roo.SplitBar.LEFT ?
8803 endPoint[0] - this.dragSpecs.startPoint[0] :
8804 this.dragSpecs.startPoint[0] - endPoint[0]
8807 newSize = this.dragSpecs.startSize +
8808 (this.placement == Roo.SplitBar.TOP ?
8809 endPoint[1] - this.dragSpecs.startPoint[1] :
8810 this.dragSpecs.startPoint[1] - endPoint[1]
8813 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8814 if(newSize != this.dragSpecs.startSize){
8815 if(this.fireEvent('beforeapply', this, newSize) !== false){
8816 this.adapter.setElementSize(this, newSize);
8817 this.fireEvent("moved", this, newSize);
8818 this.fireEvent("resize", this, newSize);
8824 * Get the adapter this SplitBar uses
8825 * @return The adapter object
8827 getAdapter : function(){
8828 return this.adapter;
8832 * Set the adapter this SplitBar uses
8833 * @param {Object} adapter A SplitBar adapter object
8835 setAdapter : function(adapter){
8836 this.adapter = adapter;
8837 this.adapter.init(this);
8841 * Gets the minimum size for the resizing element
8842 * @return {Number} The minimum size
8844 getMinimumSize : function(){
8845 return this.minSize;
8849 * Sets the minimum size for the resizing element
8850 * @param {Number} minSize The minimum size
8852 setMinimumSize : function(minSize){
8853 this.minSize = minSize;
8857 * Gets the maximum size for the resizing element
8858 * @return {Number} The maximum size
8860 getMaximumSize : function(){
8861 return this.maxSize;
8865 * Sets the maximum size for the resizing element
8866 * @param {Number} maxSize The maximum size
8868 setMaximumSize : function(maxSize){
8869 this.maxSize = maxSize;
8873 * Sets the initialize size for the resizing element
8874 * @param {Number} size The initial size
8876 setCurrentSize : function(size){
8877 var oldAnimate = this.animate;
8878 this.animate = false;
8879 this.adapter.setElementSize(this, size);
8880 this.animate = oldAnimate;
8884 * Destroy this splitbar.
8885 * @param {Boolean} removeEl True to remove the element
8887 destroy : function(removeEl){
8892 this.proxy.parentNode.removeChild(this.proxy);
8900 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
8902 Roo.SplitBar.createProxy = function(dir){
8903 var proxy = new Roo.Element(document.createElement("div"));
8904 proxy.unselectable();
8905 var cls = 'x-splitbar-proxy';
8906 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8907 document.body.appendChild(proxy.dom);
8912 * @class Roo.SplitBar.BasicLayoutAdapter
8913 * Default Adapter. It assumes the splitter and resizing element are not positioned
8914 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8916 Roo.SplitBar.BasicLayoutAdapter = function(){
8919 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8920 // do nothing for now
8925 * Called before drag operations to get the current size of the resizing element.
8926 * @param {Roo.SplitBar} s The SplitBar using this adapter
8928 getElementSize : function(s){
8929 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8930 return s.resizingEl.getWidth();
8932 return s.resizingEl.getHeight();
8937 * Called after drag operations to set the size of the resizing element.
8938 * @param {Roo.SplitBar} s The SplitBar using this adapter
8939 * @param {Number} newSize The new size to set
8940 * @param {Function} onComplete A function to be invoked when resizing is complete
8942 setElementSize : function(s, newSize, onComplete){
8943 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8945 s.resizingEl.setWidth(newSize);
8947 onComplete(s, newSize);
8950 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8955 s.resizingEl.setHeight(newSize);
8957 onComplete(s, newSize);
8960 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8967 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8968 * @extends Roo.SplitBar.BasicLayoutAdapter
8969 * Adapter that moves the splitter element to align with the resized sizing element.
8970 * Used with an absolute positioned SplitBar.
8971 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8972 * document.body, make sure you assign an id to the body element.
8974 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8975 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8976 this.container = Roo.get(container);
8979 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8984 getElementSize : function(s){
8985 return this.basic.getElementSize(s);
8988 setElementSize : function(s, newSize, onComplete){
8989 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8992 moveSplitter : function(s){
8993 var yes = Roo.SplitBar;
8994 switch(s.placement){
8996 s.el.setX(s.resizingEl.getRight());
8999 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9002 s.el.setY(s.resizingEl.getBottom());
9005 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9012 * Orientation constant - Create a vertical SplitBar
9016 Roo.SplitBar.VERTICAL = 1;
9019 * Orientation constant - Create a horizontal SplitBar
9023 Roo.SplitBar.HORIZONTAL = 2;
9026 * Placement constant - The resizing element is to the left of the splitter element
9030 Roo.SplitBar.LEFT = 1;
9033 * Placement constant - The resizing element is to the right of the splitter element
9037 Roo.SplitBar.RIGHT = 2;
9040 * Placement constant - The resizing element is positioned above the splitter element
9044 Roo.SplitBar.TOP = 3;
9047 * Placement constant - The resizing element is positioned under splitter element
9051 Roo.SplitBar.BOTTOM = 4;
9054 * Ext JS Library 1.1.1
9055 * Copyright(c) 2006-2007, Ext JS, LLC.
9057 * Originally Released Under LGPL - original licence link has changed is not relivant.
9060 * <script type="text/javascript">
9065 * @extends Roo.util.Observable
9066 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9067 * This class also supports single and multi selection modes. <br>
9068 * Create a data model bound view:
9070 var store = new Roo.data.Store(...);
9072 var view = new Roo.View({
9074 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9077 selectedClass: "ydataview-selected",
9081 // listen for node click?
9082 view.on("click", function(vw, index, node, e){
9083 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9087 dataModel.load("foobar.xml");
9089 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9091 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9092 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9094 * Note: old style constructor is still suported (container, template, config)
9098 * @param {Object} config The config object
9101 Roo.View = function(config, depreciated_tpl, depreciated_config){
9103 if (typeof(depreciated_tpl) == 'undefined') {
9104 // new way.. - universal constructor.
9105 Roo.apply(this, config);
9106 this.el = Roo.get(this.el);
9109 this.el = Roo.get(config);
9110 this.tpl = depreciated_tpl;
9111 Roo.apply(this, depreciated_config);
9115 if(typeof(this.tpl) == "string"){
9116 this.tpl = new Roo.Template(this.tpl);
9118 // support xtype ctors..
9119 this.tpl = new Roo.factory(this.tpl, Roo);
9130 * @event beforeclick
9131 * Fires before a click is processed. Returns false to cancel the default action.
9132 * @param {Roo.View} this
9133 * @param {Number} index The index of the target node
9134 * @param {HTMLElement} node The target node
9135 * @param {Roo.EventObject} e The raw event object
9137 "beforeclick" : true,
9140 * Fires when a template node is clicked.
9141 * @param {Roo.View} this
9142 * @param {Number} index The index of the target node
9143 * @param {HTMLElement} node The target node
9144 * @param {Roo.EventObject} e The raw event object
9149 * Fires when a template node is double clicked.
9150 * @param {Roo.View} this
9151 * @param {Number} index The index of the target node
9152 * @param {HTMLElement} node The target node
9153 * @param {Roo.EventObject} e The raw event object
9157 * @event contextmenu
9158 * Fires when a template node is right clicked.
9159 * @param {Roo.View} this
9160 * @param {Number} index The index of the target node
9161 * @param {HTMLElement} node The target node
9162 * @param {Roo.EventObject} e The raw event object
9164 "contextmenu" : true,
9166 * @event selectionchange
9167 * Fires when the selected nodes change.
9168 * @param {Roo.View} this
9169 * @param {Array} selections Array of the selected nodes
9171 "selectionchange" : true,
9174 * @event beforeselect
9175 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9176 * @param {Roo.View} this
9177 * @param {HTMLElement} node The node to be selected
9178 * @param {Array} selections Array of currently selected nodes
9180 "beforeselect" : true
9184 "click": this.onClick,
9185 "dblclick": this.onDblClick,
9186 "contextmenu": this.onContextMenu,
9190 this.selections = [];
9192 this.cmp = new Roo.CompositeElementLite([]);
9194 this.store = Roo.factory(this.store, Roo.data);
9195 this.setStore(this.store, true);
9197 Roo.View.superclass.constructor.call(this);
9200 Roo.extend(Roo.View, Roo.util.Observable, {
9203 * @cfg {Roo.data.Store} store Data store to load data from.
9208 * @cfg {String|Roo.Element} el The container element.
9213 * @cfg {String|Roo.Template} tpl The template used by this View
9218 * @cfg {String} selectedClass The css class to add to selected nodes
9220 selectedClass : "x-view-selected",
9222 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9226 * @cfg {Boolean} multiSelect Allow multiple selection
9229 multiSelect : false,
9231 * @cfg {Boolean} singleSelect Allow single selection
9233 singleSelect: false,
9236 * Returns the element this view is bound to.
9237 * @return {Roo.Element}
9244 * Refreshes the view.
9246 refresh : function(){
9248 this.clearSelections();
9251 var records = this.store.getRange();
9252 if(records.length < 1){
9253 this.el.update(this.emptyText);
9256 for(var i = 0, len = records.length; i < len; i++){
9257 var data = this.prepareData(records[i].data, i, records[i]);
9258 html[html.length] = t.apply(data);
9260 this.el.update(html.join(""));
9261 this.nodes = this.el.dom.childNodes;
9262 this.updateIndexes(0);
9266 * Function to override to reformat the data that is sent to
9267 * the template for each node.
9268 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9269 * a JSON object for an UpdateManager bound view).
9271 prepareData : function(data){
9275 onUpdate : function(ds, record){
9276 this.clearSelections();
9277 var index = this.store.indexOf(record);
9278 var n = this.nodes[index];
9279 this.tpl.insertBefore(n, this.prepareData(record.data));
9280 n.parentNode.removeChild(n);
9281 this.updateIndexes(index, index);
9284 onAdd : function(ds, records, index){
9285 this.clearSelections();
9286 if(this.nodes.length == 0){
9290 var n = this.nodes[index];
9291 for(var i = 0, len = records.length; i < len; i++){
9292 var d = this.prepareData(records[i].data);
9294 this.tpl.insertBefore(n, d);
9296 this.tpl.append(this.el, d);
9299 this.updateIndexes(index);
9302 onRemove : function(ds, record, index){
9303 this.clearSelections();
9304 this.el.dom.removeChild(this.nodes[index]);
9305 this.updateIndexes(index);
9309 * Refresh an individual node.
9310 * @param {Number} index
9312 refreshNode : function(index){
9313 this.onUpdate(this.store, this.store.getAt(index));
9316 updateIndexes : function(startIndex, endIndex){
9317 var ns = this.nodes;
9318 startIndex = startIndex || 0;
9319 endIndex = endIndex || ns.length - 1;
9320 for(var i = startIndex; i <= endIndex; i++){
9321 ns[i].nodeIndex = i;
9326 * Changes the data store this view uses and refresh the view.
9327 * @param {Store} store
9329 setStore : function(store, initial){
9330 if(!initial && this.store){
9331 this.store.un("datachanged", this.refresh);
9332 this.store.un("add", this.onAdd);
9333 this.store.un("remove", this.onRemove);
9334 this.store.un("update", this.onUpdate);
9335 this.store.un("clear", this.refresh);
9339 store.on("datachanged", this.refresh, this);
9340 store.on("add", this.onAdd, this);
9341 store.on("remove", this.onRemove, this);
9342 store.on("update", this.onUpdate, this);
9343 store.on("clear", this.refresh, this);
9352 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9353 * @param {HTMLElement} node
9354 * @return {HTMLElement} The template node
9356 findItemFromChild : function(node){
9357 var el = this.el.dom;
9358 if(!node || node.parentNode == el){
9361 var p = node.parentNode;
9362 while(p && p != el){
9363 if(p.parentNode == el){
9372 onClick : function(e){
9373 var item = this.findItemFromChild(e.getTarget());
9375 var index = this.indexOf(item);
9376 if(this.onItemClick(item, index, e) !== false){
9377 this.fireEvent("click", this, index, item, e);
9380 this.clearSelections();
9385 onContextMenu : function(e){
9386 var item = this.findItemFromChild(e.getTarget());
9388 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9393 onDblClick : function(e){
9394 var item = this.findItemFromChild(e.getTarget());
9396 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9400 onItemClick : function(item, index, e){
9401 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9404 if(this.multiSelect || this.singleSelect){
9405 if(this.multiSelect && e.shiftKey && this.lastSelection){
9406 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9408 this.select(item, this.multiSelect && e.ctrlKey);
9409 this.lastSelection = item;
9417 * Get the number of selected nodes.
9420 getSelectionCount : function(){
9421 return this.selections.length;
9425 * Get the currently selected nodes.
9426 * @return {Array} An array of HTMLElements
9428 getSelectedNodes : function(){
9429 return this.selections;
9433 * Get the indexes of the selected nodes.
9436 getSelectedIndexes : function(){
9437 var indexes = [], s = this.selections;
9438 for(var i = 0, len = s.length; i < len; i++){
9439 indexes.push(s[i].nodeIndex);
9445 * Clear all selections
9446 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9448 clearSelections : function(suppressEvent){
9449 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9450 this.cmp.elements = this.selections;
9451 this.cmp.removeClass(this.selectedClass);
9452 this.selections = [];
9454 this.fireEvent("selectionchange", this, this.selections);
9460 * Returns true if the passed node is selected
9461 * @param {HTMLElement/Number} node The node or node index
9464 isSelected : function(node){
9465 var s = this.selections;
9469 node = this.getNode(node);
9470 return s.indexOf(node) !== -1;
9475 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
9476 * @param {Boolean} keepExisting (optional) true to keep existing selections
9477 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9479 select : function(nodeInfo, keepExisting, suppressEvent){
9480 if(nodeInfo instanceof Array){
9482 this.clearSelections(true);
9484 for(var i = 0, len = nodeInfo.length; i < len; i++){
9485 this.select(nodeInfo[i], true, true);
9488 var node = this.getNode(nodeInfo);
9489 if(node && !this.isSelected(node)){
9491 this.clearSelections(true);
9493 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9494 Roo.fly(node).addClass(this.selectedClass);
9495 this.selections.push(node);
9497 this.fireEvent("selectionchange", this, this.selections);
9505 * Gets a template node.
9506 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9507 * @return {HTMLElement} The node or null if it wasn't found
9509 getNode : function(nodeInfo){
9510 if(typeof nodeInfo == "string"){
9511 return document.getElementById(nodeInfo);
9512 }else if(typeof nodeInfo == "number"){
9513 return this.nodes[nodeInfo];
9519 * Gets a range template nodes.
9520 * @param {Number} startIndex
9521 * @param {Number} endIndex
9522 * @return {Array} An array of nodes
9524 getNodes : function(start, end){
9525 var ns = this.nodes;
9527 end = typeof end == "undefined" ? ns.length - 1 : end;
9530 for(var i = start; i <= end; i++){
9534 for(var i = start; i >= end; i--){
9542 * Finds the index of the passed node
9543 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9544 * @return {Number} The index of the node or -1
9546 indexOf : function(node){
9547 node = this.getNode(node);
9548 if(typeof node.nodeIndex == "number"){
9549 return node.nodeIndex;
9551 var ns = this.nodes;
9552 for(var i = 0, len = ns.length; i < len; i++){
9562 * Ext JS Library 1.1.1
9563 * Copyright(c) 2006-2007, Ext JS, LLC.
9565 * Originally Released Under LGPL - original licence link has changed is not relivant.
9568 * <script type="text/javascript">
9572 * @class Roo.JsonView
9574 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9576 var view = new Roo.JsonView({
9577 container: "my-element",
9578 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9583 // listen for node click?
9584 view.on("click", function(vw, index, node, e){
9585 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9588 // direct load of JSON data
9589 view.load("foobar.php");
9591 // Example from my blog list
9592 var tpl = new Roo.Template(
9593 '<div class="entry">' +
9594 '<a class="entry-title" href="{link}">{title}</a>' +
9595 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9596 "</div><hr />"
9599 var moreView = new Roo.JsonView({
9600 container : "entry-list",
9604 moreView.on("beforerender", this.sortEntries, this);
9606 url: "/blog/get-posts.php",
9607 params: "allposts=true",
9608 text: "Loading Blog Entries..."
9612 * Note: old code is supported with arguments : (container, template, config)
9616 * Create a new JsonView
9618 * @param {Object} config The config object
9621 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9624 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9626 var um = this.el.getUpdateManager();
9627 um.setRenderer(this);
9628 um.on("update", this.onLoad, this);
9629 um.on("failure", this.onLoadException, this);
9632 * @event beforerender
9633 * Fires before rendering of the downloaded JSON data.
9634 * @param {Roo.JsonView} this
9635 * @param {Object} data The JSON data loaded
9639 * Fires when data is loaded.
9640 * @param {Roo.JsonView} this
9641 * @param {Object} data The JSON data loaded
9642 * @param {Object} response The raw Connect response object
9645 * @event loadexception
9646 * Fires when loading fails.
9647 * @param {Roo.JsonView} this
9648 * @param {Object} response The raw Connect response object
9651 'beforerender' : true,
9653 'loadexception' : true
9656 Roo.extend(Roo.JsonView, Roo.View, {
9658 * @type {String} The root property in the loaded JSON object that contains the data
9663 * Refreshes the view.
9665 refresh : function(){
9666 this.clearSelections();
9669 var o = this.jsonData;
9670 if(o && o.length > 0){
9671 for(var i = 0, len = o.length; i < len; i++){
9672 var data = this.prepareData(o[i], i, o);
9673 html[html.length] = this.tpl.apply(data);
9676 html.push(this.emptyText);
9678 this.el.update(html.join(""));
9679 this.nodes = this.el.dom.childNodes;
9680 this.updateIndexes(0);
9684 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
9685 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
9688 url: "your-url.php",
9689 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9690 callback: yourFunction,
9691 scope: yourObject, //(optional scope)
9699 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9700 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
9701 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
9702 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9703 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
9706 var um = this.el.getUpdateManager();
9707 um.update.apply(um, arguments);
9710 render : function(el, response){
9711 this.clearSelections();
9715 o = Roo.util.JSON.decode(response.responseText);
9718 o = o[this.jsonRoot];
9723 * The current JSON data or null
9726 this.beforeRender();
9731 * Get the number of records in the current JSON dataset
9734 getCount : function(){
9735 return this.jsonData ? this.jsonData.length : 0;
9739 * Returns the JSON object for the specified node(s)
9740 * @param {HTMLElement/Array} node The node or an array of nodes
9741 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9742 * you get the JSON object for the node
9744 getNodeData : function(node){
9745 if(node instanceof Array){
9747 for(var i = 0, len = node.length; i < len; i++){
9748 data.push(this.getNodeData(node[i]));
9752 return this.jsonData[this.indexOf(node)] || null;
9755 beforeRender : function(){
9756 this.snapshot = this.jsonData;
9758 this.sort.apply(this, this.sortInfo);
9760 this.fireEvent("beforerender", this, this.jsonData);
9763 onLoad : function(el, o){
9764 this.fireEvent("load", this, this.jsonData, o);
9767 onLoadException : function(el, o){
9768 this.fireEvent("loadexception", this, o);
9772 * Filter the data by a specific property.
9773 * @param {String} property A property on your JSON objects
9774 * @param {String/RegExp} value Either string that the property values
9775 * should start with, or a RegExp to test against the property
9777 filter : function(property, value){
9780 var ss = this.snapshot;
9781 if(typeof value == "string"){
9782 var vlen = value.length;
9787 value = value.toLowerCase();
9788 for(var i = 0, len = ss.length; i < len; i++){
9790 if(o[property].substr(0, vlen).toLowerCase() == value){
9794 } else if(value.exec){ // regex?
9795 for(var i = 0, len = ss.length; i < len; i++){
9797 if(value.test(o[property])){
9804 this.jsonData = data;
9810 * Filter by a function. The passed function will be called with each
9811 * object in the current dataset. If the function returns true the value is kept,
9812 * otherwise it is filtered.
9813 * @param {Function} fn
9814 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9816 filterBy : function(fn, scope){
9819 var ss = this.snapshot;
9820 for(var i = 0, len = ss.length; i < len; i++){
9822 if(fn.call(scope || this, o)){
9826 this.jsonData = data;
9832 * Clears the current filter.
9834 clearFilter : function(){
9835 if(this.snapshot && this.jsonData != this.snapshot){
9836 this.jsonData = this.snapshot;
9843 * Sorts the data for this view and refreshes it.
9844 * @param {String} property A property on your JSON objects to sort on
9845 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9846 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9848 sort : function(property, dir, sortType){
9849 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9852 var dsc = dir && dir.toLowerCase() == "desc";
9853 var f = function(o1, o2){
9854 var v1 = sortType ? sortType(o1[p]) : o1[p];
9855 var v2 = sortType ? sortType(o2[p]) : o2[p];
9858 return dsc ? +1 : -1;
9860 return dsc ? -1 : +1;
9865 this.jsonData.sort(f);
9867 if(this.jsonData != this.snapshot){
9868 this.snapshot.sort(f);
9874 * Ext JS Library 1.1.1
9875 * Copyright(c) 2006-2007, Ext JS, LLC.
9877 * Originally Released Under LGPL - original licence link has changed is not relivant.
9880 * <script type="text/javascript">
9885 * @class Roo.ColorPalette
9886 * @extends Roo.Component
9887 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9888 * Here's an example of typical usage:
9890 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9891 cp.render('my-div');
9893 cp.on('select', function(palette, selColor){
9894 // do something with selColor
9898 * Create a new ColorPalette
9899 * @param {Object} config The config object
9901 Roo.ColorPalette = function(config){
9902 Roo.ColorPalette.superclass.constructor.call(this, config);
9906 * Fires when a color is selected
9907 * @param {ColorPalette} this
9908 * @param {String} color The 6-digit color hex code (without the # symbol)
9914 this.on("select", this.handler, this.scope, true);
9917 Roo.extend(Roo.ColorPalette, Roo.Component, {
9919 * @cfg {String} itemCls
9920 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9922 itemCls : "x-color-palette",
9924 * @cfg {String} value
9925 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9926 * the hex codes are case-sensitive.
9931 ctype: "Roo.ColorPalette",
9934 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9936 allowReselect : false,
9939 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9940 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9941 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9942 * of colors with the width setting until the box is symmetrical.</p>
9943 * <p>You can override individual colors if needed:</p>
9945 var cp = new Roo.ColorPalette();
9946 cp.colors[0] = "FF0000"; // change the first box to red
9949 Or you can provide a custom array of your own for complete control:
9951 var cp = new Roo.ColorPalette();
9952 cp.colors = ["000000", "993300", "333300"];
9957 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9958 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9959 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9960 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9961 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9965 onRender : function(container, position){
9966 var t = new Roo.MasterTemplate(
9967 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9969 var c = this.colors;
9970 for(var i = 0, len = c.length; i < len; i++){
9973 var el = document.createElement("div");
9974 el.className = this.itemCls;
9976 container.dom.insertBefore(el, position);
9977 this.el = Roo.get(el);
9978 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9979 if(this.clickEvent != 'click'){
9980 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9985 afterRender : function(){
9986 Roo.ColorPalette.superclass.afterRender.call(this);
9995 handleClick : function(e, t){
9998 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9999 this.select(c.toUpperCase());
10004 * Selects the specified color in the palette (fires the select event)
10005 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10007 select : function(color){
10008 color = color.replace("#", "");
10009 if(color != this.value || this.allowReselect){
10012 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10014 el.child("a.color-"+color).addClass("x-color-palette-sel");
10015 this.value = color;
10016 this.fireEvent("select", this, color);
10021 * Ext JS Library 1.1.1
10022 * Copyright(c) 2006-2007, Ext JS, LLC.
10024 * Originally Released Under LGPL - original licence link has changed is not relivant.
10027 * <script type="text/javascript">
10031 * @class Roo.DatePicker
10032 * @extends Roo.Component
10033 * Simple date picker class.
10035 * Create a new DatePicker
10036 * @param {Object} config The config object
10038 Roo.DatePicker = function(config){
10039 Roo.DatePicker.superclass.constructor.call(this, config);
10041 this.value = config && config.value ?
10042 config.value.clearTime() : new Date().clearTime();
10047 * Fires when a date is selected
10048 * @param {DatePicker} this
10049 * @param {Date} date The selected date
10055 this.on("select", this.handler, this.scope || this);
10057 // build the disabledDatesRE
10058 if(!this.disabledDatesRE && this.disabledDates){
10059 var dd = this.disabledDates;
10061 for(var i = 0; i < dd.length; i++){
10063 if(i != dd.length-1) re += "|";
10065 this.disabledDatesRE = new RegExp(re + ")");
10069 Roo.extend(Roo.DatePicker, Roo.Component, {
10071 * @cfg {String} todayText
10072 * The text to display on the button that selects the current date (defaults to "Today")
10074 todayText : "Today",
10076 * @cfg {String} okText
10077 * The text to display on the ok button
10079 okText : " OK ", //   to give the user extra clicking room
10081 * @cfg {String} cancelText
10082 * The text to display on the cancel button
10084 cancelText : "Cancel",
10086 * @cfg {String} todayTip
10087 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10089 todayTip : "{0} (Spacebar)",
10091 * @cfg {Date} minDate
10092 * Minimum allowable date (JavaScript date object, defaults to null)
10096 * @cfg {Date} maxDate
10097 * Maximum allowable date (JavaScript date object, defaults to null)
10101 * @cfg {String} minText
10102 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10104 minText : "This date is before the minimum date",
10106 * @cfg {String} maxText
10107 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10109 maxText : "This date is after the maximum date",
10111 * @cfg {String} format
10112 * The default date format string which can be overriden for localization support. The format must be
10113 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10117 * @cfg {Array} disabledDays
10118 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10120 disabledDays : null,
10122 * @cfg {String} disabledDaysText
10123 * The tooltip to display when the date falls on a disabled day (defaults to "")
10125 disabledDaysText : "",
10127 * @cfg {RegExp} disabledDatesRE
10128 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10130 disabledDatesRE : null,
10132 * @cfg {String} disabledDatesText
10133 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10135 disabledDatesText : "",
10137 * @cfg {Boolean} constrainToViewport
10138 * True to constrain the date picker to the viewport (defaults to true)
10140 constrainToViewport : true,
10142 * @cfg {Array} monthNames
10143 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10145 monthNames : Date.monthNames,
10147 * @cfg {Array} dayNames
10148 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10150 dayNames : Date.dayNames,
10152 * @cfg {String} nextText
10153 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10155 nextText: 'Next Month (Control+Right)',
10157 * @cfg {String} prevText
10158 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10160 prevText: 'Previous Month (Control+Left)',
10162 * @cfg {String} monthYearText
10163 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10165 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10167 * @cfg {Number} startDay
10168 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10172 * @cfg {Bool} showClear
10173 * Show a clear button (usefull for date form elements that can be blank.)
10179 * Sets the value of the date field
10180 * @param {Date} value The date to set
10182 setValue : function(value){
10183 var old = this.value;
10184 this.value = value.clearTime(true);
10186 this.update(this.value);
10191 * Gets the current selected value of the date field
10192 * @return {Date} The selected date
10194 getValue : function(){
10199 focus : function(){
10201 this.update(this.activeDate);
10206 onRender : function(container, position){
10208 '<table cellspacing="0">',
10209 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
10210 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10211 var dn = this.dayNames;
10212 for(var i = 0; i < 7; i++){
10213 var d = this.startDay+i;
10217 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10219 m[m.length] = "</tr></thead><tbody><tr>";
10220 for(var i = 0; i < 42; i++) {
10221 if(i % 7 == 0 && i != 0){
10222 m[m.length] = "</tr><tr>";
10224 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10226 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10227 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10229 var el = document.createElement("div");
10230 el.className = "x-date-picker";
10231 el.innerHTML = m.join("");
10233 container.dom.insertBefore(el, position);
10235 this.el = Roo.get(el);
10236 this.eventEl = Roo.get(el.firstChild);
10238 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10239 handler: this.showPrevMonth,
10241 preventDefault:true,
10245 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10246 handler: this.showNextMonth,
10248 preventDefault:true,
10252 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10254 this.monthPicker = this.el.down('div.x-date-mp');
10255 this.monthPicker.enableDisplayMode('block');
10257 var kn = new Roo.KeyNav(this.eventEl, {
10258 "left" : function(e){
10260 this.showPrevMonth() :
10261 this.update(this.activeDate.add("d", -1));
10264 "right" : function(e){
10266 this.showNextMonth() :
10267 this.update(this.activeDate.add("d", 1));
10270 "up" : function(e){
10272 this.showNextYear() :
10273 this.update(this.activeDate.add("d", -7));
10276 "down" : function(e){
10278 this.showPrevYear() :
10279 this.update(this.activeDate.add("d", 7));
10282 "pageUp" : function(e){
10283 this.showNextMonth();
10286 "pageDown" : function(e){
10287 this.showPrevMonth();
10290 "enter" : function(e){
10291 e.stopPropagation();
10298 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10300 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10302 this.el.unselectable();
10304 this.cells = this.el.select("table.x-date-inner tbody td");
10305 this.textNodes = this.el.query("table.x-date-inner tbody span");
10307 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10309 tooltip: this.monthYearText
10312 this.mbtn.on('click', this.showMonthPicker, this);
10313 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10316 var today = (new Date()).dateFormat(this.format);
10318 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10319 if (this.showClear) {
10320 baseTb.add( new Roo.Toolbar.Fill());
10323 text: String.format(this.todayText, today),
10324 tooltip: String.format(this.todayTip, today),
10325 handler: this.selectToday,
10329 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10332 if (this.showClear) {
10334 baseTb.add( new Roo.Toolbar.Fill());
10337 cls: 'x-btn-icon x-btn-clear',
10338 handler: function() {
10340 this.fireEvent("select", this, '');
10350 this.update(this.value);
10353 createMonthPicker : function(){
10354 if(!this.monthPicker.dom.firstChild){
10355 var buf = ['<table border="0" cellspacing="0">'];
10356 for(var i = 0; i < 6; i++){
10358 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10359 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10361 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
10362 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10366 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10368 '</button><button type="button" class="x-date-mp-cancel">',
10370 '</button></td></tr>',
10373 this.monthPicker.update(buf.join(''));
10374 this.monthPicker.on('click', this.onMonthClick, this);
10375 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10377 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10378 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10380 this.mpMonths.each(function(m, a, i){
10383 m.dom.xmonth = 5 + Math.round(i * .5);
10385 m.dom.xmonth = Math.round((i-1) * .5);
10391 showMonthPicker : function(){
10392 this.createMonthPicker();
10393 var size = this.el.getSize();
10394 this.monthPicker.setSize(size);
10395 this.monthPicker.child('table').setSize(size);
10397 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10398 this.updateMPMonth(this.mpSelMonth);
10399 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10400 this.updateMPYear(this.mpSelYear);
10402 this.monthPicker.slideIn('t', {duration:.2});
10405 updateMPYear : function(y){
10407 var ys = this.mpYears.elements;
10408 for(var i = 1; i <= 10; i++){
10409 var td = ys[i-1], y2;
10411 y2 = y + Math.round(i * .5);
10412 td.firstChild.innerHTML = y2;
10415 y2 = y - (5-Math.round(i * .5));
10416 td.firstChild.innerHTML = y2;
10419 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10423 updateMPMonth : function(sm){
10424 this.mpMonths.each(function(m, a, i){
10425 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10429 selectMPMonth: function(m){
10433 onMonthClick : function(e, t){
10435 var el = new Roo.Element(t), pn;
10436 if(el.is('button.x-date-mp-cancel')){
10437 this.hideMonthPicker();
10439 else if(el.is('button.x-date-mp-ok')){
10440 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10441 this.hideMonthPicker();
10443 else if(pn = el.up('td.x-date-mp-month', 2)){
10444 this.mpMonths.removeClass('x-date-mp-sel');
10445 pn.addClass('x-date-mp-sel');
10446 this.mpSelMonth = pn.dom.xmonth;
10448 else if(pn = el.up('td.x-date-mp-year', 2)){
10449 this.mpYears.removeClass('x-date-mp-sel');
10450 pn.addClass('x-date-mp-sel');
10451 this.mpSelYear = pn.dom.xyear;
10453 else if(el.is('a.x-date-mp-prev')){
10454 this.updateMPYear(this.mpyear-10);
10456 else if(el.is('a.x-date-mp-next')){
10457 this.updateMPYear(this.mpyear+10);
10461 onMonthDblClick : function(e, t){
10463 var el = new Roo.Element(t), pn;
10464 if(pn = el.up('td.x-date-mp-month', 2)){
10465 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10466 this.hideMonthPicker();
10468 else if(pn = el.up('td.x-date-mp-year', 2)){
10469 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10470 this.hideMonthPicker();
10474 hideMonthPicker : function(disableAnim){
10475 if(this.monthPicker){
10476 if(disableAnim === true){
10477 this.monthPicker.hide();
10479 this.monthPicker.slideOut('t', {duration:.2});
10485 showPrevMonth : function(e){
10486 this.update(this.activeDate.add("mo", -1));
10490 showNextMonth : function(e){
10491 this.update(this.activeDate.add("mo", 1));
10495 showPrevYear : function(){
10496 this.update(this.activeDate.add("y", -1));
10500 showNextYear : function(){
10501 this.update(this.activeDate.add("y", 1));
10505 handleMouseWheel : function(e){
10506 var delta = e.getWheelDelta();
10508 this.showPrevMonth();
10510 } else if(delta < 0){
10511 this.showNextMonth();
10517 handleDateClick : function(e, t){
10519 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10520 this.setValue(new Date(t.dateValue));
10521 this.fireEvent("select", this, this.value);
10526 selectToday : function(){
10527 this.setValue(new Date().clearTime());
10528 this.fireEvent("select", this, this.value);
10532 update : function(date){
10533 var vd = this.activeDate;
10534 this.activeDate = date;
10536 var t = date.getTime();
10537 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10538 this.cells.removeClass("x-date-selected");
10539 this.cells.each(function(c){
10540 if(c.dom.firstChild.dateValue == t){
10541 c.addClass("x-date-selected");
10542 setTimeout(function(){
10543 try{c.dom.firstChild.focus();}catch(e){}
10551 var days = date.getDaysInMonth();
10552 var firstOfMonth = date.getFirstDateOfMonth();
10553 var startingPos = firstOfMonth.getDay()-this.startDay;
10555 if(startingPos <= this.startDay){
10559 var pm = date.add("mo", -1);
10560 var prevStart = pm.getDaysInMonth()-startingPos;
10562 var cells = this.cells.elements;
10563 var textEls = this.textNodes;
10564 days += startingPos;
10566 // convert everything to numbers so it's fast
10567 var day = 86400000;
10568 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10569 var today = new Date().clearTime().getTime();
10570 var sel = date.clearTime().getTime();
10571 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10572 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10573 var ddMatch = this.disabledDatesRE;
10574 var ddText = this.disabledDatesText;
10575 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10576 var ddaysText = this.disabledDaysText;
10577 var format = this.format;
10579 var setCellClass = function(cal, cell){
10581 var t = d.getTime();
10582 cell.firstChild.dateValue = t;
10584 cell.className += " x-date-today";
10585 cell.title = cal.todayText;
10588 cell.className += " x-date-selected";
10589 setTimeout(function(){
10590 try{cell.firstChild.focus();}catch(e){}
10595 cell.className = " x-date-disabled";
10596 cell.title = cal.minText;
10600 cell.className = " x-date-disabled";
10601 cell.title = cal.maxText;
10605 if(ddays.indexOf(d.getDay()) != -1){
10606 cell.title = ddaysText;
10607 cell.className = " x-date-disabled";
10610 if(ddMatch && format){
10611 var fvalue = d.dateFormat(format);
10612 if(ddMatch.test(fvalue)){
10613 cell.title = ddText.replace("%0", fvalue);
10614 cell.className = " x-date-disabled";
10620 for(; i < startingPos; i++) {
10621 textEls[i].innerHTML = (++prevStart);
10622 d.setDate(d.getDate()+1);
10623 cells[i].className = "x-date-prevday";
10624 setCellClass(this, cells[i]);
10626 for(; i < days; i++){
10627 intDay = i - startingPos + 1;
10628 textEls[i].innerHTML = (intDay);
10629 d.setDate(d.getDate()+1);
10630 cells[i].className = "x-date-active";
10631 setCellClass(this, cells[i]);
10634 for(; i < 42; i++) {
10635 textEls[i].innerHTML = (++extraDays);
10636 d.setDate(d.getDate()+1);
10637 cells[i].className = "x-date-nextday";
10638 setCellClass(this, cells[i]);
10641 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10643 if(!this.internalRender){
10644 var main = this.el.dom.firstChild;
10645 var w = main.offsetWidth;
10646 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10647 Roo.fly(main).setWidth(w);
10648 this.internalRender = true;
10649 // opera does not respect the auto grow header center column
10650 // then, after it gets a width opera refuses to recalculate
10651 // without a second pass
10652 if(Roo.isOpera && !this.secondPass){
10653 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10654 this.secondPass = true;
10655 this.update.defer(10, this, [date]);
10661 * Ext JS Library 1.1.1
10662 * Copyright(c) 2006-2007, Ext JS, LLC.
10664 * Originally Released Under LGPL - original licence link has changed is not relivant.
10667 * <script type="text/javascript">
10670 * @class Roo.TabPanel
10671 * @extends Roo.util.Observable
10672 * A lightweight tab container.
10676 // basic tabs 1, built from existing content
10677 var tabs = new Roo.TabPanel("tabs1");
10678 tabs.addTab("script", "View Script");
10679 tabs.addTab("markup", "View Markup");
10680 tabs.activate("script");
10682 // more advanced tabs, built from javascript
10683 var jtabs = new Roo.TabPanel("jtabs");
10684 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10686 // set up the UpdateManager
10687 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10688 var updater = tab2.getUpdateManager();
10689 updater.setDefaultUrl("ajax1.htm");
10690 tab2.on('activate', updater.refresh, updater, true);
10692 // Use setUrl for Ajax loading
10693 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10694 tab3.setUrl("ajax2.htm", null, true);
10697 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10700 jtabs.activate("jtabs-1");
10703 * Create a new TabPanel.
10704 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10705 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10707 Roo.TabPanel = function(container, config){
10709 * The container element for this TabPanel.
10710 * @type Roo.Element
10712 this.el = Roo.get(container, true);
10714 if(typeof config == "boolean"){
10715 this.tabPosition = config ? "bottom" : "top";
10717 Roo.apply(this, config);
10720 if(this.tabPosition == "bottom"){
10721 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10722 this.el.addClass("x-tabs-bottom");
10724 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10725 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10726 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10728 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10730 if(this.tabPosition != "bottom"){
10731 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10732 * @type Roo.Element
10734 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10735 this.el.addClass("x-tabs-top");
10739 this.bodyEl.setStyle("position", "relative");
10741 this.active = null;
10742 this.activateDelegate = this.activate.createDelegate(this);
10747 * Fires when the active tab changes
10748 * @param {Roo.TabPanel} this
10749 * @param {Roo.TabPanelItem} activePanel The new active tab
10753 * @event beforetabchange
10754 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10755 * @param {Roo.TabPanel} this
10756 * @param {Object} e Set cancel to true on this object to cancel the tab change
10757 * @param {Roo.TabPanelItem} tab The tab being changed to
10759 "beforetabchange" : true
10762 Roo.EventManager.onWindowResize(this.onResize, this);
10763 this.cpad = this.el.getPadding("lr");
10764 this.hiddenCount = 0;
10766 Roo.TabPanel.superclass.constructor.call(this);
10769 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10771 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10773 tabPosition : "top",
10775 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10777 currentTabWidth : 0,
10779 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10783 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10787 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10789 preferredTabWidth : 175,
10791 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10793 resizeTabs : false,
10795 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10797 monitorResize : true,
10800 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10801 * @param {String} id The id of the div to use <b>or create</b>
10802 * @param {String} text The text for the tab
10803 * @param {String} content (optional) Content to put in the TabPanelItem body
10804 * @param {Boolean} closable (optional) True to create a close icon on the tab
10805 * @return {Roo.TabPanelItem} The created TabPanelItem
10807 addTab : function(id, text, content, closable){
10808 var item = new Roo.TabPanelItem(this, id, text, closable);
10809 this.addTabItem(item);
10811 item.setContent(content);
10817 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10818 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10819 * @return {Roo.TabPanelItem}
10821 getTab : function(id){
10822 return this.items[id];
10826 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10827 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10829 hideTab : function(id){
10830 var t = this.items[id];
10833 this.hiddenCount++;
10834 this.autoSizeTabs();
10839 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10840 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10842 unhideTab : function(id){
10843 var t = this.items[id];
10845 t.setHidden(false);
10846 this.hiddenCount--;
10847 this.autoSizeTabs();
10852 * Adds an existing {@link Roo.TabPanelItem}.
10853 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10855 addTabItem : function(item){
10856 this.items[item.id] = item;
10857 this.items.push(item);
10858 if(this.resizeTabs){
10859 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10860 this.autoSizeTabs();
10867 * Removes a {@link Roo.TabPanelItem}.
10868 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10870 removeTab : function(id){
10871 var items = this.items;
10872 var tab = items[id];
10873 if(!tab) { return; }
10874 var index = items.indexOf(tab);
10875 if(this.active == tab && items.length > 1){
10876 var newTab = this.getNextAvailable(index);
10881 this.stripEl.dom.removeChild(tab.pnode.dom);
10882 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10883 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10885 items.splice(index, 1);
10886 delete this.items[tab.id];
10887 tab.fireEvent("close", tab);
10888 tab.purgeListeners();
10889 this.autoSizeTabs();
10892 getNextAvailable : function(start){
10893 var items = this.items;
10895 // look for a next tab that will slide over to
10896 // replace the one being removed
10897 while(index < items.length){
10898 var item = items[++index];
10899 if(item && !item.isHidden()){
10903 // if one isn't found select the previous tab (on the left)
10906 var item = items[--index];
10907 if(item && !item.isHidden()){
10915 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10916 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10918 disableTab : function(id){
10919 var tab = this.items[id];
10920 if(tab && this.active != tab){
10926 * Enables a {@link Roo.TabPanelItem} that is disabled.
10927 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10929 enableTab : function(id){
10930 var tab = this.items[id];
10935 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10936 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10937 * @return {Roo.TabPanelItem} The TabPanelItem.
10939 activate : function(id){
10940 var tab = this.items[id];
10944 if(tab == this.active || tab.disabled){
10948 this.fireEvent("beforetabchange", this, e, tab);
10949 if(e.cancel !== true && !tab.disabled){
10951 this.active.hide();
10953 this.active = this.items[id];
10954 this.active.show();
10955 this.fireEvent("tabchange", this, this.active);
10961 * Gets the active {@link Roo.TabPanelItem}.
10962 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10964 getActiveTab : function(){
10965 return this.active;
10969 * Updates the tab body element to fit the height of the container element
10970 * for overflow scrolling
10971 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10973 syncHeight : function(targetHeight){
10974 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10975 var bm = this.bodyEl.getMargins();
10976 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10977 this.bodyEl.setHeight(newHeight);
10981 onResize : function(){
10982 if(this.monitorResize){
10983 this.autoSizeTabs();
10988 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10990 beginUpdate : function(){
10991 this.updating = true;
10995 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10997 endUpdate : function(){
10998 this.updating = false;
10999 this.autoSizeTabs();
11003 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11005 autoSizeTabs : function(){
11006 var count = this.items.length;
11007 var vcount = count - this.hiddenCount;
11008 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11009 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11010 var availWidth = Math.floor(w / vcount);
11011 var b = this.stripBody;
11012 if(b.getWidth() > w){
11013 var tabs = this.items;
11014 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11015 if(availWidth < this.minTabWidth){
11016 /*if(!this.sleft){ // incomplete scrolling code
11017 this.createScrollButtons();
11020 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11023 if(this.currentTabWidth < this.preferredTabWidth){
11024 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11030 * Returns the number of tabs in this TabPanel.
11033 getCount : function(){
11034 return this.items.length;
11038 * Resizes all the tabs to the passed width
11039 * @param {Number} The new width
11041 setTabWidth : function(width){
11042 this.currentTabWidth = width;
11043 for(var i = 0, len = this.items.length; i < len; i++) {
11044 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11049 * Destroys this TabPanel
11050 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11052 destroy : function(removeEl){
11053 Roo.EventManager.removeResizeListener(this.onResize, this);
11054 for(var i = 0, len = this.items.length; i < len; i++){
11055 this.items[i].purgeListeners();
11057 if(removeEl === true){
11058 this.el.update("");
11065 * @class Roo.TabPanelItem
11066 * @extends Roo.util.Observable
11067 * Represents an individual item (tab plus body) in a TabPanel.
11068 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11069 * @param {String} id The id of this TabPanelItem
11070 * @param {String} text The text for the tab of this TabPanelItem
11071 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11073 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11075 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11076 * @type Roo.TabPanel
11078 this.tabPanel = tabPanel;
11080 * The id for this TabPanelItem
11085 this.disabled = false;
11089 this.loaded = false;
11090 this.closable = closable;
11093 * The body element for this TabPanelItem.
11094 * @type Roo.Element
11096 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11097 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11098 this.bodyEl.setStyle("display", "block");
11099 this.bodyEl.setStyle("zoom", "1");
11102 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11104 this.el = Roo.get(els.el, true);
11105 this.inner = Roo.get(els.inner, true);
11106 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11107 this.pnode = Roo.get(els.el.parentNode, true);
11108 this.el.on("mousedown", this.onTabMouseDown, this);
11109 this.el.on("click", this.onTabClick, this);
11112 var c = Roo.get(els.close, true);
11113 c.dom.title = this.closeText;
11114 c.addClassOnOver("close-over");
11115 c.on("click", this.closeClick, this);
11121 * Fires when this tab becomes the active tab.
11122 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11123 * @param {Roo.TabPanelItem} this
11127 * @event beforeclose
11128 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11129 * @param {Roo.TabPanelItem} this
11130 * @param {Object} e Set cancel to true on this object to cancel the close.
11132 "beforeclose": true,
11135 * Fires when this tab is closed.
11136 * @param {Roo.TabPanelItem} this
11140 * @event deactivate
11141 * Fires when this tab is no longer the active tab.
11142 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11143 * @param {Roo.TabPanelItem} this
11145 "deactivate" : true
11147 this.hidden = false;
11149 Roo.TabPanelItem.superclass.constructor.call(this);
11152 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11153 purgeListeners : function(){
11154 Roo.util.Observable.prototype.purgeListeners.call(this);
11155 this.el.removeAllListeners();
11158 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11161 this.pnode.addClass("on");
11164 this.tabPanel.stripWrap.repaint();
11166 this.fireEvent("activate", this.tabPanel, this);
11170 * Returns true if this tab is the active tab.
11171 * @return {Boolean}
11173 isActive : function(){
11174 return this.tabPanel.getActiveTab() == this;
11178 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11181 this.pnode.removeClass("on");
11183 this.fireEvent("deactivate", this.tabPanel, this);
11186 hideAction : function(){
11187 this.bodyEl.hide();
11188 this.bodyEl.setStyle("position", "absolute");
11189 this.bodyEl.setLeft("-20000px");
11190 this.bodyEl.setTop("-20000px");
11193 showAction : function(){
11194 this.bodyEl.setStyle("position", "relative");
11195 this.bodyEl.setTop("");
11196 this.bodyEl.setLeft("");
11197 this.bodyEl.show();
11201 * Set the tooltip for the tab.
11202 * @param {String} tooltip The tab's tooltip
11204 setTooltip : function(text){
11205 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11206 this.textEl.dom.qtip = text;
11207 this.textEl.dom.removeAttribute('title');
11209 this.textEl.dom.title = text;
11213 onTabClick : function(e){
11214 e.preventDefault();
11215 this.tabPanel.activate(this.id);
11218 onTabMouseDown : function(e){
11219 e.preventDefault();
11220 this.tabPanel.activate(this.id);
11223 getWidth : function(){
11224 return this.inner.getWidth();
11227 setWidth : function(width){
11228 var iwidth = width - this.pnode.getPadding("lr");
11229 this.inner.setWidth(iwidth);
11230 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11231 this.pnode.setWidth(width);
11235 * Show or hide the tab
11236 * @param {Boolean} hidden True to hide or false to show.
11238 setHidden : function(hidden){
11239 this.hidden = hidden;
11240 this.pnode.setStyle("display", hidden ? "none" : "");
11244 * Returns true if this tab is "hidden"
11245 * @return {Boolean}
11247 isHidden : function(){
11248 return this.hidden;
11252 * Returns the text for this tab
11255 getText : function(){
11259 autoSize : function(){
11260 //this.el.beginMeasure();
11261 this.textEl.setWidth(1);
11262 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11263 //this.el.endMeasure();
11267 * Sets the text for the tab (Note: this also sets the tooltip text)
11268 * @param {String} text The tab's text and tooltip
11270 setText : function(text){
11272 this.textEl.update(text);
11273 this.setTooltip(text);
11274 if(!this.tabPanel.resizeTabs){
11279 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11281 activate : function(){
11282 this.tabPanel.activate(this.id);
11286 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11288 disable : function(){
11289 if(this.tabPanel.active != this){
11290 this.disabled = true;
11291 this.pnode.addClass("disabled");
11296 * Enables this TabPanelItem if it was previously disabled.
11298 enable : function(){
11299 this.disabled = false;
11300 this.pnode.removeClass("disabled");
11304 * Sets the content for this TabPanelItem.
11305 * @param {String} content The content
11306 * @param {Boolean} loadScripts true to look for and load scripts
11308 setContent : function(content, loadScripts){
11309 this.bodyEl.update(content, loadScripts);
11313 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11314 * @return {Roo.UpdateManager} The UpdateManager
11316 getUpdateManager : function(){
11317 return this.bodyEl.getUpdateManager();
11321 * Set a URL to be used to load the content for this TabPanelItem.
11322 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11323 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
11324 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
11325 * @return {Roo.UpdateManager} The UpdateManager
11327 setUrl : function(url, params, loadOnce){
11328 if(this.refreshDelegate){
11329 this.un('activate', this.refreshDelegate);
11331 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11332 this.on("activate", this.refreshDelegate);
11333 return this.bodyEl.getUpdateManager();
11337 _handleRefresh : function(url, params, loadOnce){
11338 if(!loadOnce || !this.loaded){
11339 var updater = this.bodyEl.getUpdateManager();
11340 updater.update(url, params, this._setLoaded.createDelegate(this));
11345 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11346 * Will fail silently if the setUrl method has not been called.
11347 * This does not activate the panel, just updates its content.
11349 refresh : function(){
11350 if(this.refreshDelegate){
11351 this.loaded = false;
11352 this.refreshDelegate();
11357 _setLoaded : function(){
11358 this.loaded = true;
11362 closeClick : function(e){
11365 this.fireEvent("beforeclose", this, o);
11366 if(o.cancel !== true){
11367 this.tabPanel.removeTab(this.id);
11371 * The text displayed in the tooltip for the close icon.
11374 closeText : "Close this tab"
11378 Roo.TabPanel.prototype.createStrip = function(container){
11379 var strip = document.createElement("div");
11380 strip.className = "x-tabs-wrap";
11381 container.appendChild(strip);
11385 Roo.TabPanel.prototype.createStripList = function(strip){
11386 // div wrapper for retard IE
11387 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11388 return strip.firstChild.firstChild.firstChild.firstChild;
11391 Roo.TabPanel.prototype.createBody = function(container){
11392 var body = document.createElement("div");
11393 Roo.id(body, "tab-body");
11394 Roo.fly(body).addClass("x-tabs-body");
11395 container.appendChild(body);
11399 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11400 var body = Roo.getDom(id);
11402 body = document.createElement("div");
11405 Roo.fly(body).addClass("x-tabs-item-body");
11406 bodyEl.insertBefore(body, bodyEl.firstChild);
11410 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11411 var td = document.createElement("td");
11412 stripEl.appendChild(td);
11414 td.className = "x-tabs-closable";
11415 if(!this.closeTpl){
11416 this.closeTpl = new Roo.Template(
11417 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11418 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11419 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11422 var el = this.closeTpl.overwrite(td, {"text": text});
11423 var close = el.getElementsByTagName("div")[0];
11424 var inner = el.getElementsByTagName("em")[0];
11425 return {"el": el, "close": close, "inner": inner};
11428 this.tabTpl = new Roo.Template(
11429 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11430 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11433 var el = this.tabTpl.overwrite(td, {"text": text});
11434 var inner = el.getElementsByTagName("em")[0];
11435 return {"el": el, "inner": inner};
11439 * Ext JS Library 1.1.1
11440 * Copyright(c) 2006-2007, Ext JS, LLC.
11442 * Originally Released Under LGPL - original licence link has changed is not relivant.
11445 * <script type="text/javascript">
11449 * @class Roo.Button
11450 * @extends Roo.util.Observable
11451 * Simple Button class
11452 * @cfg {String} text The button text
11453 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11454 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11455 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11456 * @cfg {Object} scope The scope of the handler
11457 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11458 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11459 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11460 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11461 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11462 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11463 applies if enableToggle = true)
11464 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11465 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11466 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11468 * Create a new button
11469 * @param {Object} config The config object
11471 Roo.Button = function(renderTo, config)
11475 renderTo = config.renderTo || false;
11478 Roo.apply(this, config);
11482 * Fires when this button is clicked
11483 * @param {Button} this
11484 * @param {EventObject} e The click event
11489 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11490 * @param {Button} this
11491 * @param {Boolean} pressed
11496 * Fires when the mouse hovers over the button
11497 * @param {Button} this
11498 * @param {Event} e The event object
11500 'mouseover' : true,
11503 * Fires when the mouse exits the button
11504 * @param {Button} this
11505 * @param {Event} e The event object
11510 * Fires when the button is rendered
11511 * @param {Button} this
11516 this.menu = Roo.menu.MenuMgr.get(this.menu);
11518 // register listeners first!! - so render can be captured..
11519 Roo.util.Observable.call(this);
11521 this.render(renderTo);
11527 Roo.extend(Roo.Button, Roo.util.Observable, {
11533 * Read-only. True if this button is hidden
11538 * Read-only. True if this button is disabled
11543 * Read-only. True if this button is pressed (only if enableToggle = true)
11549 * @cfg {Number} tabIndex
11550 * The DOM tabIndex for this button (defaults to undefined)
11552 tabIndex : undefined,
11555 * @cfg {Boolean} enableToggle
11556 * True to enable pressed/not pressed toggling (defaults to false)
11558 enableToggle: false,
11560 * @cfg {Mixed} menu
11561 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11565 * @cfg {String} menuAlign
11566 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11568 menuAlign : "tl-bl?",
11571 * @cfg {String} iconCls
11572 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11574 iconCls : undefined,
11576 * @cfg {String} type
11577 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11582 menuClassTarget: 'tr',
11585 * @cfg {String} clickEvent
11586 * The type of event to map to the button's event handler (defaults to 'click')
11588 clickEvent : 'click',
11591 * @cfg {Boolean} handleMouseEvents
11592 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11594 handleMouseEvents : true,
11597 * @cfg {String} tooltipType
11598 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11600 tooltipType : 'qtip',
11603 * @cfg {String} cls
11604 * A CSS class to apply to the button's main element.
11608 * @cfg {Roo.Template} template (Optional)
11609 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11610 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11611 * require code modifications if required elements (e.g. a button) aren't present.
11615 render : function(renderTo){
11617 if(this.hideParent){
11618 this.parentEl = Roo.get(renderTo);
11620 if(!this.dhconfig){
11621 if(!this.template){
11622 if(!Roo.Button.buttonTemplate){
11623 // hideous table template
11624 Roo.Button.buttonTemplate = new Roo.Template(
11625 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11626 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
11627 "</tr></tbody></table>");
11629 this.template = Roo.Button.buttonTemplate;
11631 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11632 var btnEl = btn.child("button:first");
11633 btnEl.on('focus', this.onFocus, this);
11634 btnEl.on('blur', this.onBlur, this);
11636 btn.addClass(this.cls);
11639 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11642 btnEl.addClass(this.iconCls);
11644 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11647 if(this.tabIndex !== undefined){
11648 btnEl.dom.tabIndex = this.tabIndex;
11651 if(typeof this.tooltip == 'object'){
11652 Roo.QuickTips.tips(Roo.apply({
11656 btnEl.dom[this.tooltipType] = this.tooltip;
11660 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11664 this.el.dom.id = this.el.id = this.id;
11667 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11668 this.menu.on("show", this.onMenuShow, this);
11669 this.menu.on("hide", this.onMenuHide, this);
11671 btn.addClass("x-btn");
11672 if(Roo.isIE && !Roo.isIE7){
11673 this.autoWidth.defer(1, this);
11677 if(this.handleMouseEvents){
11678 btn.on("mouseover", this.onMouseOver, this);
11679 btn.on("mouseout", this.onMouseOut, this);
11680 btn.on("mousedown", this.onMouseDown, this);
11682 btn.on(this.clickEvent, this.onClick, this);
11683 //btn.on("mouseup", this.onMouseUp, this);
11690 Roo.ButtonToggleMgr.register(this);
11692 this.el.addClass("x-btn-pressed");
11695 var repeater = new Roo.util.ClickRepeater(btn,
11696 typeof this.repeat == "object" ? this.repeat : {}
11698 repeater.on("click", this.onClick, this);
11701 this.fireEvent('render', this);
11705 * Returns the button's underlying element
11706 * @return {Roo.Element} The element
11708 getEl : function(){
11713 * Destroys this Button and removes any listeners.
11715 destroy : function(){
11716 Roo.ButtonToggleMgr.unregister(this);
11717 this.el.removeAllListeners();
11718 this.purgeListeners();
11723 autoWidth : function(){
11725 this.el.setWidth("auto");
11726 if(Roo.isIE7 && Roo.isStrict){
11727 var ib = this.el.child('button');
11728 if(ib && ib.getWidth() > 20){
11730 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11735 this.el.beginMeasure();
11737 if(this.el.getWidth() < this.minWidth){
11738 this.el.setWidth(this.minWidth);
11741 this.el.endMeasure();
11748 * Assigns this button's click handler
11749 * @param {Function} handler The function to call when the button is clicked
11750 * @param {Object} scope (optional) Scope for the function passed in
11752 setHandler : function(handler, scope){
11753 this.handler = handler;
11754 this.scope = scope;
11758 * Sets this button's text
11759 * @param {String} text The button text
11761 setText : function(text){
11764 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11770 * Gets the text for this button
11771 * @return {String} The button text
11773 getText : function(){
11781 this.hidden = false;
11783 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11791 this.hidden = true;
11793 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11798 * Convenience function for boolean show/hide
11799 * @param {Boolean} visible True to show, false to hide
11801 setVisible: function(visible){
11810 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11811 * @param {Boolean} state (optional) Force a particular state
11813 toggle : function(state){
11814 state = state === undefined ? !this.pressed : state;
11815 if(state != this.pressed){
11817 this.el.addClass("x-btn-pressed");
11818 this.pressed = true;
11819 this.fireEvent("toggle", this, true);
11821 this.el.removeClass("x-btn-pressed");
11822 this.pressed = false;
11823 this.fireEvent("toggle", this, false);
11825 if(this.toggleHandler){
11826 this.toggleHandler.call(this.scope || this, this, state);
11834 focus : function(){
11835 this.el.child('button:first').focus();
11839 * Disable this button
11841 disable : function(){
11843 this.el.addClass("x-btn-disabled");
11845 this.disabled = true;
11849 * Enable this button
11851 enable : function(){
11853 this.el.removeClass("x-btn-disabled");
11855 this.disabled = false;
11859 * Convenience function for boolean enable/disable
11860 * @param {Boolean} enabled True to enable, false to disable
11862 setDisabled : function(v){
11863 this[v !== true ? "enable" : "disable"]();
11867 onClick : function(e){
11869 e.preventDefault();
11874 if(!this.disabled){
11875 if(this.enableToggle){
11878 if(this.menu && !this.menu.isVisible()){
11879 this.menu.show(this.el, this.menuAlign);
11881 this.fireEvent("click", this, e);
11883 this.el.removeClass("x-btn-over");
11884 this.handler.call(this.scope || this, this, e);
11889 onMouseOver : function(e){
11890 if(!this.disabled){
11891 this.el.addClass("x-btn-over");
11892 this.fireEvent('mouseover', this, e);
11896 onMouseOut : function(e){
11897 if(!e.within(this.el, true)){
11898 this.el.removeClass("x-btn-over");
11899 this.fireEvent('mouseout', this, e);
11903 onFocus : function(e){
11904 if(!this.disabled){
11905 this.el.addClass("x-btn-focus");
11909 onBlur : function(e){
11910 this.el.removeClass("x-btn-focus");
11913 onMouseDown : function(e){
11914 if(!this.disabled && e.button == 0){
11915 this.el.addClass("x-btn-click");
11916 Roo.get(document).on('mouseup', this.onMouseUp, this);
11920 onMouseUp : function(e){
11922 this.el.removeClass("x-btn-click");
11923 Roo.get(document).un('mouseup', this.onMouseUp, this);
11927 onMenuShow : function(e){
11928 this.el.addClass("x-btn-menu-active");
11931 onMenuHide : function(e){
11932 this.el.removeClass("x-btn-menu-active");
11936 // Private utility class used by Button
11937 Roo.ButtonToggleMgr = function(){
11940 function toggleGroup(btn, state){
11942 var g = groups[btn.toggleGroup];
11943 for(var i = 0, l = g.length; i < l; i++){
11945 g[i].toggle(false);
11952 register : function(btn){
11953 if(!btn.toggleGroup){
11956 var g = groups[btn.toggleGroup];
11958 g = groups[btn.toggleGroup] = [];
11961 btn.on("toggle", toggleGroup);
11964 unregister : function(btn){
11965 if(!btn.toggleGroup){
11968 var g = groups[btn.toggleGroup];
11971 btn.un("toggle", toggleGroup);
11977 * Ext JS Library 1.1.1
11978 * Copyright(c) 2006-2007, Ext JS, LLC.
11980 * Originally Released Under LGPL - original licence link has changed is not relivant.
11983 * <script type="text/javascript">
11987 * @class Roo.SplitButton
11988 * @extends Roo.Button
11989 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11990 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11991 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11992 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11993 * @cfg {String} arrowTooltip The title attribute of the arrow
11995 * Create a new menu button
11996 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11997 * @param {Object} config The config object
11999 Roo.SplitButton = function(renderTo, config){
12000 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12002 * @event arrowclick
12003 * Fires when this button's arrow is clicked
12004 * @param {SplitButton} this
12005 * @param {EventObject} e The click event
12007 this.addEvents({"arrowclick":true});
12010 Roo.extend(Roo.SplitButton, Roo.Button, {
12011 render : function(renderTo){
12012 // this is one sweet looking template!
12013 var tpl = new Roo.Template(
12014 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12015 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12016 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
12017 "</tbody></table></td><td>",
12018 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12019 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
12020 "</tbody></table></td></tr></table>"
12022 var btn = tpl.append(renderTo, [this.text, this.type], true);
12023 var btnEl = btn.child("button");
12025 btn.addClass(this.cls);
12028 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12031 btnEl.addClass(this.iconCls);
12033 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12037 if(this.handleMouseEvents){
12038 btn.on("mouseover", this.onMouseOver, this);
12039 btn.on("mouseout", this.onMouseOut, this);
12040 btn.on("mousedown", this.onMouseDown, this);
12041 btn.on("mouseup", this.onMouseUp, this);
12043 btn.on(this.clickEvent, this.onClick, this);
12045 if(typeof this.tooltip == 'object'){
12046 Roo.QuickTips.tips(Roo.apply({
12050 btnEl.dom[this.tooltipType] = this.tooltip;
12053 if(this.arrowTooltip){
12054 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12063 this.el.addClass("x-btn-pressed");
12065 if(Roo.isIE && !Roo.isIE7){
12066 this.autoWidth.defer(1, this);
12071 this.menu.on("show", this.onMenuShow, this);
12072 this.menu.on("hide", this.onMenuHide, this);
12074 this.fireEvent('render', this);
12078 autoWidth : function(){
12080 var tbl = this.el.child("table:first");
12081 var tbl2 = this.el.child("table:last");
12082 this.el.setWidth("auto");
12083 tbl.setWidth("auto");
12084 if(Roo.isIE7 && Roo.isStrict){
12085 var ib = this.el.child('button:first');
12086 if(ib && ib.getWidth() > 20){
12088 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12093 this.el.beginMeasure();
12095 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12096 tbl.setWidth(this.minWidth-tbl2.getWidth());
12099 this.el.endMeasure();
12102 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12106 * Sets this button's click handler
12107 * @param {Function} handler The function to call when the button is clicked
12108 * @param {Object} scope (optional) Scope for the function passed above
12110 setHandler : function(handler, scope){
12111 this.handler = handler;
12112 this.scope = scope;
12116 * Sets this button's arrow click handler
12117 * @param {Function} handler The function to call when the arrow is clicked
12118 * @param {Object} scope (optional) Scope for the function passed above
12120 setArrowHandler : function(handler, scope){
12121 this.arrowHandler = handler;
12122 this.scope = scope;
12128 focus : function(){
12130 this.el.child("button:first").focus();
12135 onClick : function(e){
12136 e.preventDefault();
12137 if(!this.disabled){
12138 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12139 if(this.menu && !this.menu.isVisible()){
12140 this.menu.show(this.el, this.menuAlign);
12142 this.fireEvent("arrowclick", this, e);
12143 if(this.arrowHandler){
12144 this.arrowHandler.call(this.scope || this, this, e);
12147 this.fireEvent("click", this, e);
12149 this.handler.call(this.scope || this, this, e);
12155 onMouseDown : function(e){
12156 if(!this.disabled){
12157 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12161 onMouseUp : function(e){
12162 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12167 // backwards compat
12168 Roo.MenuButton = Roo.SplitButton;/*
12170 * Ext JS Library 1.1.1
12171 * Copyright(c) 2006-2007, Ext JS, LLC.
12173 * Originally Released Under LGPL - original licence link has changed is not relivant.
12176 * <script type="text/javascript">
12180 * @class Roo.Toolbar
12181 * Basic Toolbar class.
12183 * Creates a new Toolbar
12184 * @param {Object} config The config object
12186 Roo.Toolbar = function(container, buttons, config)
12188 /// old consturctor format still supported..
12189 if(container instanceof Array){ // omit the container for later rendering
12190 buttons = container;
12194 if (typeof(container) == 'object' && container.xtype) {
12195 config = container;
12196 container = config.container;
12197 buttons = config.buttons; // not really - use items!!
12200 if (config && config.items) {
12201 xitems = config.items;
12202 delete config.items;
12204 Roo.apply(this, config);
12205 this.buttons = buttons;
12208 this.render(container);
12210 Roo.each(xitems, function(b) {
12216 Roo.Toolbar.prototype = {
12218 * @cfg {Roo.data.Store} items
12219 * array of button configs or elements to add
12223 * @cfg {String/HTMLElement/Element} container
12224 * The id or element that will contain the toolbar
12227 render : function(ct){
12228 this.el = Roo.get(ct);
12230 this.el.addClass(this.cls);
12232 // using a table allows for vertical alignment
12233 // 100% width is needed by Safari...
12234 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12235 this.tr = this.el.child("tr", true);
12237 this.items = new Roo.util.MixedCollection(false, function(o){
12238 return o.id || ("item" + (++autoId));
12241 this.add.apply(this, this.buttons);
12242 delete this.buttons;
12247 * Adds element(s) to the toolbar -- this function takes a variable number of
12248 * arguments of mixed type and adds them to the toolbar.
12249 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12251 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12252 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12253 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12254 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12255 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12256 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12257 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12258 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12259 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12261 * @param {Mixed} arg2
12262 * @param {Mixed} etc.
12265 var a = arguments, l = a.length;
12266 for(var i = 0; i < l; i++){
12271 _add : function(el) {
12274 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12277 if (el.applyTo){ // some kind of form field
12278 return this.addField(el);
12280 if (el.render){ // some kind of Toolbar.Item
12281 return this.addItem(el);
12283 if (typeof el == "string"){ // string
12284 if(el == "separator" || el == "-"){
12285 return this.addSeparator();
12288 return this.addSpacer();
12291 return this.addFill();
12293 return this.addText(el);
12296 if(el.tagName){ // element
12297 return this.addElement(el);
12299 if(typeof el == "object"){ // must be button config?
12300 return this.addButton(el);
12302 // and now what?!?!
12308 * Add an Xtype element
12309 * @param {Object} xtype Xtype Object
12310 * @return {Object} created Object
12312 addxtype : function(e){
12313 return this.add(e);
12317 * Returns the Element for this toolbar.
12318 * @return {Roo.Element}
12320 getEl : function(){
12326 * @return {Roo.Toolbar.Item} The separator item
12328 addSeparator : function(){
12329 return this.addItem(new Roo.Toolbar.Separator());
12333 * Adds a spacer element
12334 * @return {Roo.Toolbar.Spacer} The spacer item
12336 addSpacer : function(){
12337 return this.addItem(new Roo.Toolbar.Spacer());
12341 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12342 * @return {Roo.Toolbar.Fill} The fill item
12344 addFill : function(){
12345 return this.addItem(new Roo.Toolbar.Fill());
12349 * Adds any standard HTML element to the toolbar
12350 * @param {String/HTMLElement/Element} el The element or id of the element to add
12351 * @return {Roo.Toolbar.Item} The element's item
12353 addElement : function(el){
12354 return this.addItem(new Roo.Toolbar.Item(el));
12357 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12358 * @type Roo.util.MixedCollection
12363 * Adds any Toolbar.Item or subclass
12364 * @param {Roo.Toolbar.Item} item
12365 * @return {Roo.Toolbar.Item} The item
12367 addItem : function(item){
12368 var td = this.nextBlock();
12370 this.items.add(item);
12375 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12376 * @param {Object/Array} config A button config or array of configs
12377 * @return {Roo.Toolbar.Button/Array}
12379 addButton : function(config){
12380 if(config instanceof Array){
12382 for(var i = 0, len = config.length; i < len; i++) {
12383 buttons.push(this.addButton(config[i]));
12388 if(!(config instanceof Roo.Toolbar.Button)){
12390 new Roo.Toolbar.SplitButton(config) :
12391 new Roo.Toolbar.Button(config);
12393 var td = this.nextBlock();
12400 * Adds text to the toolbar
12401 * @param {String} text The text to add
12402 * @return {Roo.Toolbar.Item} The element's item
12404 addText : function(text){
12405 return this.addItem(new Roo.Toolbar.TextItem(text));
12409 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12410 * @param {Number} index The index where the item is to be inserted
12411 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12412 * @return {Roo.Toolbar.Button/Item}
12414 insertButton : function(index, item){
12415 if(item instanceof Array){
12417 for(var i = 0, len = item.length; i < len; i++) {
12418 buttons.push(this.insertButton(index + i, item[i]));
12422 if (!(item instanceof Roo.Toolbar.Button)){
12423 item = new Roo.Toolbar.Button(item);
12425 var td = document.createElement("td");
12426 this.tr.insertBefore(td, this.tr.childNodes[index]);
12428 this.items.insert(index, item);
12433 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12434 * @param {Object} config
12435 * @return {Roo.Toolbar.Item} The element's item
12437 addDom : function(config, returnEl){
12438 var td = this.nextBlock();
12439 Roo.DomHelper.overwrite(td, config);
12440 var ti = new Roo.Toolbar.Item(td.firstChild);
12442 this.items.add(ti);
12447 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12448 * @type Roo.util.MixedCollection
12453 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12454 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12455 * @param {Roo.form.Field} field
12456 * @return {Roo.ToolbarItem}
12460 addField : function(field) {
12461 if (!this.fields) {
12463 this.fields = new Roo.util.MixedCollection(false, function(o){
12464 return o.id || ("item" + (++autoId));
12469 var td = this.nextBlock();
12471 var ti = new Roo.Toolbar.Item(td.firstChild);
12473 this.items.add(ti);
12474 this.fields.add(field);
12485 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12486 this.el.child('div').hide();
12494 this.el.child('div').show();
12498 nextBlock : function(){
12499 var td = document.createElement("td");
12500 this.tr.appendChild(td);
12505 destroy : function(){
12506 if(this.items){ // rendered?
12507 Roo.destroy.apply(Roo, this.items.items);
12509 if(this.fields){ // rendered?
12510 Roo.destroy.apply(Roo, this.fields.items);
12512 Roo.Element.uncache(this.el, this.tr);
12517 * @class Roo.Toolbar.Item
12518 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12520 * Creates a new Item
12521 * @param {HTMLElement} el
12523 Roo.Toolbar.Item = function(el){
12524 this.el = Roo.getDom(el);
12525 this.id = Roo.id(this.el);
12526 this.hidden = false;
12529 Roo.Toolbar.Item.prototype = {
12532 * Get this item's HTML Element
12533 * @return {HTMLElement}
12535 getEl : function(){
12540 render : function(td){
12542 td.appendChild(this.el);
12546 * Removes and destroys this item.
12548 destroy : function(){
12549 this.td.parentNode.removeChild(this.td);
12556 this.hidden = false;
12557 this.td.style.display = "";
12564 this.hidden = true;
12565 this.td.style.display = "none";
12569 * Convenience function for boolean show/hide.
12570 * @param {Boolean} visible true to show/false to hide
12572 setVisible: function(visible){
12581 * Try to focus this item.
12583 focus : function(){
12584 Roo.fly(this.el).focus();
12588 * Disables this item.
12590 disable : function(){
12591 Roo.fly(this.td).addClass("x-item-disabled");
12592 this.disabled = true;
12593 this.el.disabled = true;
12597 * Enables this item.
12599 enable : function(){
12600 Roo.fly(this.td).removeClass("x-item-disabled");
12601 this.disabled = false;
12602 this.el.disabled = false;
12608 * @class Roo.Toolbar.Separator
12609 * @extends Roo.Toolbar.Item
12610 * A simple toolbar separator class
12612 * Creates a new Separator
12614 Roo.Toolbar.Separator = function(){
12615 var s = document.createElement("span");
12616 s.className = "ytb-sep";
12617 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12619 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12620 enable:Roo.emptyFn,
12621 disable:Roo.emptyFn,
12626 * @class Roo.Toolbar.Spacer
12627 * @extends Roo.Toolbar.Item
12628 * A simple element that adds extra horizontal space to a toolbar.
12630 * Creates a new Spacer
12632 Roo.Toolbar.Spacer = function(){
12633 var s = document.createElement("div");
12634 s.className = "ytb-spacer";
12635 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12637 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12638 enable:Roo.emptyFn,
12639 disable:Roo.emptyFn,
12644 * @class Roo.Toolbar.Fill
12645 * @extends Roo.Toolbar.Spacer
12646 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12648 * Creates a new Spacer
12650 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12652 render : function(td){
12653 td.style.width = '100%';
12654 Roo.Toolbar.Fill.superclass.render.call(this, td);
12659 * @class Roo.Toolbar.TextItem
12660 * @extends Roo.Toolbar.Item
12661 * A simple class that renders text directly into a toolbar.
12663 * Creates a new TextItem
12664 * @param {String} text
12666 Roo.Toolbar.TextItem = function(text){
12667 if (typeof(text) == 'object') {
12670 var s = document.createElement("span");
12671 s.className = "ytb-text";
12672 s.innerHTML = text;
12673 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12675 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12676 enable:Roo.emptyFn,
12677 disable:Roo.emptyFn,
12682 * @class Roo.Toolbar.Button
12683 * @extends Roo.Button
12684 * A button that renders into a toolbar.
12686 * Creates a new Button
12687 * @param {Object} config A standard {@link Roo.Button} config object
12689 Roo.Toolbar.Button = function(config){
12690 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12692 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12693 render : function(td){
12695 Roo.Toolbar.Button.superclass.render.call(this, td);
12699 * Removes and destroys this button
12701 destroy : function(){
12702 Roo.Toolbar.Button.superclass.destroy.call(this);
12703 this.td.parentNode.removeChild(this.td);
12707 * Shows this button
12710 this.hidden = false;
12711 this.td.style.display = "";
12715 * Hides this button
12718 this.hidden = true;
12719 this.td.style.display = "none";
12723 * Disables this item
12725 disable : function(){
12726 Roo.fly(this.td).addClass("x-item-disabled");
12727 this.disabled = true;
12731 * Enables this item
12733 enable : function(){
12734 Roo.fly(this.td).removeClass("x-item-disabled");
12735 this.disabled = false;
12738 // backwards compat
12739 Roo.ToolbarButton = Roo.Toolbar.Button;
12742 * @class Roo.Toolbar.SplitButton
12743 * @extends Roo.SplitButton
12744 * A menu button that renders into a toolbar.
12746 * Creates a new SplitButton
12747 * @param {Object} config A standard {@link Roo.SplitButton} config object
12749 Roo.Toolbar.SplitButton = function(config){
12750 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12752 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12753 render : function(td){
12755 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12759 * Removes and destroys this button
12761 destroy : function(){
12762 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12763 this.td.parentNode.removeChild(this.td);
12767 * Shows this button
12770 this.hidden = false;
12771 this.td.style.display = "";
12775 * Hides this button
12778 this.hidden = true;
12779 this.td.style.display = "none";
12783 // backwards compat
12784 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12786 * Ext JS Library 1.1.1
12787 * Copyright(c) 2006-2007, Ext JS, LLC.
12789 * Originally Released Under LGPL - original licence link has changed is not relivant.
12792 * <script type="text/javascript">
12796 * @class Roo.PagingToolbar
12797 * @extends Roo.Toolbar
12798 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12800 * Create a new PagingToolbar
12801 * @param {Object} config The config object
12803 Roo.PagingToolbar = function(el, ds, config)
12805 // old args format still supported... - xtype is prefered..
12806 if (typeof(el) == 'object' && el.xtype) {
12807 // created from xtype...
12809 ds = el.dataSource;
12810 el = config.container;
12813 if (config.items) {
12814 items = config.items;
12818 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12821 this.renderButtons(this.el);
12824 // supprot items array.
12826 Roo.each(items, function(e) {
12827 this.add(Roo.factory(e));
12832 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12834 * @cfg {Roo.data.Store} dataSource
12835 * The underlying data store providing the paged data
12838 * @cfg {String/HTMLElement/Element} container
12839 * container The id or element that will contain the toolbar
12842 * @cfg {Boolean} displayInfo
12843 * True to display the displayMsg (defaults to false)
12846 * @cfg {Number} pageSize
12847 * The number of records to display per page (defaults to 20)
12851 * @cfg {String} displayMsg
12852 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12854 displayMsg : 'Displaying {0} - {1} of {2}',
12856 * @cfg {String} emptyMsg
12857 * The message to display when no records are found (defaults to "No data to display")
12859 emptyMsg : 'No data to display',
12861 * Customizable piece of the default paging text (defaults to "Page")
12864 beforePageText : "Page",
12866 * Customizable piece of the default paging text (defaults to "of %0")
12869 afterPageText : "of {0}",
12871 * Customizable piece of the default paging text (defaults to "First Page")
12874 firstText : "First Page",
12876 * Customizable piece of the default paging text (defaults to "Previous Page")
12879 prevText : "Previous Page",
12881 * Customizable piece of the default paging text (defaults to "Next Page")
12884 nextText : "Next Page",
12886 * Customizable piece of the default paging text (defaults to "Last Page")
12889 lastText : "Last Page",
12891 * Customizable piece of the default paging text (defaults to "Refresh")
12894 refreshText : "Refresh",
12897 renderButtons : function(el){
12898 Roo.PagingToolbar.superclass.render.call(this, el);
12899 this.first = this.addButton({
12900 tooltip: this.firstText,
12901 cls: "x-btn-icon x-grid-page-first",
12903 handler: this.onClick.createDelegate(this, ["first"])
12905 this.prev = this.addButton({
12906 tooltip: this.prevText,
12907 cls: "x-btn-icon x-grid-page-prev",
12909 handler: this.onClick.createDelegate(this, ["prev"])
12911 //this.addSeparator();
12912 this.add(this.beforePageText);
12913 this.field = Roo.get(this.addDom({
12918 cls: "x-grid-page-number"
12920 this.field.on("keydown", this.onPagingKeydown, this);
12921 this.field.on("focus", function(){this.dom.select();});
12922 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12923 this.field.setHeight(18);
12924 //this.addSeparator();
12925 this.next = this.addButton({
12926 tooltip: this.nextText,
12927 cls: "x-btn-icon x-grid-page-next",
12929 handler: this.onClick.createDelegate(this, ["next"])
12931 this.last = this.addButton({
12932 tooltip: this.lastText,
12933 cls: "x-btn-icon x-grid-page-last",
12935 handler: this.onClick.createDelegate(this, ["last"])
12937 //this.addSeparator();
12938 this.loading = this.addButton({
12939 tooltip: this.refreshText,
12940 cls: "x-btn-icon x-grid-loading",
12941 handler: this.onClick.createDelegate(this, ["refresh"])
12944 if(this.displayInfo){
12945 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12950 updateInfo : function(){
12951 if(this.displayEl){
12952 var count = this.ds.getCount();
12953 var msg = count == 0 ?
12957 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12959 this.displayEl.update(msg);
12964 onLoad : function(ds, r, o){
12965 this.cursor = o.params ? o.params.start : 0;
12966 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12968 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12969 this.field.dom.value = ap;
12970 this.first.setDisabled(ap == 1);
12971 this.prev.setDisabled(ap == 1);
12972 this.next.setDisabled(ap == ps);
12973 this.last.setDisabled(ap == ps);
12974 this.loading.enable();
12979 getPageData : function(){
12980 var total = this.ds.getTotalCount();
12983 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12984 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12989 onLoadError : function(){
12990 this.loading.enable();
12994 onPagingKeydown : function(e){
12995 var k = e.getKey();
12996 var d = this.getPageData();
12998 var v = this.field.dom.value, pageNum;
12999 if(!v || isNaN(pageNum = parseInt(v, 10))){
13000 this.field.dom.value = d.activePage;
13003 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13004 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13007 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
13009 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13010 this.field.dom.value = pageNum;
13011 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13014 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13016 var v = this.field.dom.value, pageNum;
13017 var increment = (e.shiftKey) ? 10 : 1;
13018 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13020 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13021 this.field.dom.value = d.activePage;
13024 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13026 this.field.dom.value = parseInt(v, 10) + increment;
13027 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13028 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13035 beforeLoad : function(){
13037 this.loading.disable();
13042 onClick : function(which){
13046 ds.load({params:{start: 0, limit: this.pageSize}});
13049 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13052 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13055 var total = ds.getTotalCount();
13056 var extra = total % this.pageSize;
13057 var lastStart = extra ? (total - extra) : total-this.pageSize;
13058 ds.load({params:{start: lastStart, limit: this.pageSize}});
13061 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13067 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13068 * @param {Roo.data.Store} store The data store to unbind
13070 unbind : function(ds){
13071 ds.un("beforeload", this.beforeLoad, this);
13072 ds.un("load", this.onLoad, this);
13073 ds.un("loadexception", this.onLoadError, this);
13074 ds.un("remove", this.updateInfo, this);
13075 ds.un("add", this.updateInfo, this);
13076 this.ds = undefined;
13080 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13081 * @param {Roo.data.Store} store The data store to bind
13083 bind : function(ds){
13084 ds.on("beforeload", this.beforeLoad, this);
13085 ds.on("load", this.onLoad, this);
13086 ds.on("loadexception", this.onLoadError, this);
13087 ds.on("remove", this.updateInfo, this);
13088 ds.on("add", this.updateInfo, this);
13093 * Ext JS Library 1.1.1
13094 * Copyright(c) 2006-2007, Ext JS, LLC.
13096 * Originally Released Under LGPL - original licence link has changed is not relivant.
13099 * <script type="text/javascript">
13103 * @class Roo.Resizable
13104 * @extends Roo.util.Observable
13105 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13106 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13107 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
13108 * the element will be wrapped for you automatically.</p>
13109 * <p>Here is the list of valid resize handles:</p>
13112 ------ -------------------
13121 'hd' horizontal drag
13124 * <p>Here's an example showing the creation of a typical Resizable:</p>
13126 var resizer = new Roo.Resizable("element-id", {
13134 resizer.on("resize", myHandler);
13136 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13137 * resizer.east.setDisplayed(false);</p>
13138 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13139 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13140 * resize operation's new size (defaults to [0, 0])
13141 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13142 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13143 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13144 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13145 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13146 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13147 * @cfg {Number} width The width of the element in pixels (defaults to null)
13148 * @cfg {Number} height The height of the element in pixels (defaults to null)
13149 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13150 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13151 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13152 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13153 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13154 * in favor of the handles config option (defaults to false)
13155 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13156 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13157 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13158 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13159 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13160 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13161 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13162 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13163 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13164 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13165 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13167 * Create a new resizable component
13168 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13169 * @param {Object} config configuration options
13171 Roo.Resizable = function(el, config)
13173 this.el = Roo.get(el);
13175 if(config && config.wrap){
13176 config.resizeChild = this.el;
13177 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13178 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13179 this.el.setStyle("overflow", "hidden");
13180 this.el.setPositioning(config.resizeChild.getPositioning());
13181 config.resizeChild.clearPositioning();
13182 if(!config.width || !config.height){
13183 var csize = config.resizeChild.getSize();
13184 this.el.setSize(csize.width, csize.height);
13186 if(config.pinned && !config.adjustments){
13187 config.adjustments = "auto";
13191 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13192 this.proxy.unselectable();
13193 this.proxy.enableDisplayMode('block');
13195 Roo.apply(this, config);
13198 this.disableTrackOver = true;
13199 this.el.addClass("x-resizable-pinned");
13201 // if the element isn't positioned, make it relative
13202 var position = this.el.getStyle("position");
13203 if(position != "absolute" && position != "fixed"){
13204 this.el.setStyle("position", "relative");
13206 if(!this.handles){ // no handles passed, must be legacy style
13207 this.handles = 's,e,se';
13208 if(this.multiDirectional){
13209 this.handles += ',n,w';
13212 if(this.handles == "all"){
13213 this.handles = "n s e w ne nw se sw";
13215 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13216 var ps = Roo.Resizable.positions;
13217 for(var i = 0, len = hs.length; i < len; i++){
13218 if(hs[i] && ps[hs[i]]){
13219 var pos = ps[hs[i]];
13220 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13224 this.corner = this.southeast;
13226 // updateBox = the box can move..
13227 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13228 this.updateBox = true;
13231 this.activeHandle = null;
13233 if(this.resizeChild){
13234 if(typeof this.resizeChild == "boolean"){
13235 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13237 this.resizeChild = Roo.get(this.resizeChild, true);
13241 if(this.adjustments == "auto"){
13242 var rc = this.resizeChild;
13243 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13244 if(rc && (hw || hn)){
13245 rc.position("relative");
13246 rc.setLeft(hw ? hw.el.getWidth() : 0);
13247 rc.setTop(hn ? hn.el.getHeight() : 0);
13249 this.adjustments = [
13250 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13251 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13255 if(this.draggable){
13256 this.dd = this.dynamic ?
13257 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13258 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13264 * @event beforeresize
13265 * Fired before resize is allowed. Set enabled to false to cancel resize.
13266 * @param {Roo.Resizable} this
13267 * @param {Roo.EventObject} e The mousedown event
13269 "beforeresize" : true,
13272 * Fired after a resize.
13273 * @param {Roo.Resizable} this
13274 * @param {Number} width The new width
13275 * @param {Number} height The new height
13276 * @param {Roo.EventObject} e The mouseup event
13281 if(this.width !== null && this.height !== null){
13282 this.resizeTo(this.width, this.height);
13284 this.updateChildSize();
13287 this.el.dom.style.zoom = 1;
13289 Roo.Resizable.superclass.constructor.call(this);
13292 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13293 resizeChild : false,
13294 adjustments : [0, 0],
13304 multiDirectional : false,
13305 disableTrackOver : false,
13306 easing : 'easeOutStrong',
13307 widthIncrement : 0,
13308 heightIncrement : 0,
13312 preserveRatio : false,
13313 transparent: false,
13319 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13321 constrainTo: undefined,
13323 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13325 resizeRegion: undefined,
13329 * Perform a manual resize
13330 * @param {Number} width
13331 * @param {Number} height
13333 resizeTo : function(width, height){
13334 this.el.setSize(width, height);
13335 this.updateChildSize();
13336 this.fireEvent("resize", this, width, height, null);
13340 startSizing : function(e, handle){
13341 this.fireEvent("beforeresize", this, e);
13342 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13345 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13346 this.overlay.unselectable();
13347 this.overlay.enableDisplayMode("block");
13348 this.overlay.on("mousemove", this.onMouseMove, this);
13349 this.overlay.on("mouseup", this.onMouseUp, this);
13351 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13353 this.resizing = true;
13354 this.startBox = this.el.getBox();
13355 this.startPoint = e.getXY();
13356 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13357 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13359 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13360 this.overlay.show();
13362 if(this.constrainTo) {
13363 var ct = Roo.get(this.constrainTo);
13364 this.resizeRegion = ct.getRegion().adjust(
13365 ct.getFrameWidth('t'),
13366 ct.getFrameWidth('l'),
13367 -ct.getFrameWidth('b'),
13368 -ct.getFrameWidth('r')
13372 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13374 this.proxy.setBox(this.startBox);
13376 this.proxy.setStyle('visibility', 'visible');
13382 onMouseDown : function(handle, e){
13385 this.activeHandle = handle;
13386 this.startSizing(e, handle);
13391 onMouseUp : function(e){
13392 var size = this.resizeElement();
13393 this.resizing = false;
13395 this.overlay.hide();
13397 this.fireEvent("resize", this, size.width, size.height, e);
13401 updateChildSize : function(){
13402 if(this.resizeChild){
13404 var child = this.resizeChild;
13405 var adj = this.adjustments;
13406 if(el.dom.offsetWidth){
13407 var b = el.getSize(true);
13408 child.setSize(b.width+adj[0], b.height+adj[1]);
13410 // Second call here for IE
13411 // The first call enables instant resizing and
13412 // the second call corrects scroll bars if they
13415 setTimeout(function(){
13416 if(el.dom.offsetWidth){
13417 var b = el.getSize(true);
13418 child.setSize(b.width+adj[0], b.height+adj[1]);
13426 snap : function(value, inc, min){
13427 if(!inc || !value) return value;
13428 var newValue = value;
13429 var m = value % inc;
13432 newValue = value + (inc-m);
13434 newValue = value - m;
13437 return Math.max(min, newValue);
13441 resizeElement : function(){
13442 var box = this.proxy.getBox();
13443 if(this.updateBox){
13444 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13446 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13448 this.updateChildSize();
13456 constrain : function(v, diff, m, mx){
13459 }else if(v - diff > mx){
13466 onMouseMove : function(e){
13468 try{// try catch so if something goes wrong the user doesn't get hung
13470 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13474 //var curXY = this.startPoint;
13475 var curSize = this.curSize || this.startBox;
13476 var x = this.startBox.x, y = this.startBox.y;
13477 var ox = x, oy = y;
13478 var w = curSize.width, h = curSize.height;
13479 var ow = w, oh = h;
13480 var mw = this.minWidth, mh = this.minHeight;
13481 var mxw = this.maxWidth, mxh = this.maxHeight;
13482 var wi = this.widthIncrement;
13483 var hi = this.heightIncrement;
13485 var eventXY = e.getXY();
13486 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13487 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13489 var pos = this.activeHandle.position;
13494 w = Math.min(Math.max(mw, w), mxw);
13499 h = Math.min(Math.max(mh, h), mxh);
13504 w = Math.min(Math.max(mw, w), mxw);
13505 h = Math.min(Math.max(mh, h), mxh);
13508 diffY = this.constrain(h, diffY, mh, mxh);
13515 var adiffX = Math.abs(diffX);
13516 var sub = (adiffX % wi); // how much
13517 if (sub > (wi/2)) { // far enough to snap
13518 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13520 // remove difference..
13521 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13525 x = Math.max(this.minX, x);
13528 diffX = this.constrain(w, diffX, mw, mxw);
13534 w = Math.min(Math.max(mw, w), mxw);
13535 diffY = this.constrain(h, diffY, mh, mxh);
13540 diffX = this.constrain(w, diffX, mw, mxw);
13541 diffY = this.constrain(h, diffY, mh, mxh);
13548 diffX = this.constrain(w, diffX, mw, mxw);
13550 h = Math.min(Math.max(mh, h), mxh);
13556 var sw = this.snap(w, wi, mw);
13557 var sh = this.snap(h, hi, mh);
13558 if(sw != w || sh != h){
13581 if(this.preserveRatio){
13586 h = Math.min(Math.max(mh, h), mxh);
13591 w = Math.min(Math.max(mw, w), mxw);
13596 w = Math.min(Math.max(mw, w), mxw);
13602 w = Math.min(Math.max(mw, w), mxw);
13608 h = Math.min(Math.max(mh, h), mxh);
13616 h = Math.min(Math.max(mh, h), mxh);
13626 h = Math.min(Math.max(mh, h), mxh);
13634 if (pos == 'hdrag') {
13637 this.proxy.setBounds(x, y, w, h);
13639 this.resizeElement();
13646 handleOver : function(){
13648 this.el.addClass("x-resizable-over");
13653 handleOut : function(){
13654 if(!this.resizing){
13655 this.el.removeClass("x-resizable-over");
13660 * Returns the element this component is bound to.
13661 * @return {Roo.Element}
13663 getEl : function(){
13668 * Returns the resizeChild element (or null).
13669 * @return {Roo.Element}
13671 getResizeChild : function(){
13672 return this.resizeChild;
13676 * Destroys this resizable. If the element was wrapped and
13677 * removeEl is not true then the element remains.
13678 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13680 destroy : function(removeEl){
13681 this.proxy.remove();
13683 this.overlay.removeAllListeners();
13684 this.overlay.remove();
13686 var ps = Roo.Resizable.positions;
13688 if(typeof ps[k] != "function" && this[ps[k]]){
13689 var h = this[ps[k]];
13690 h.el.removeAllListeners();
13695 this.el.update("");
13702 // hash to map config positions to true positions
13703 Roo.Resizable.positions = {
13704 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13709 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13711 // only initialize the template if resizable is used
13712 var tpl = Roo.DomHelper.createTemplate(
13713 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13716 Roo.Resizable.Handle.prototype.tpl = tpl;
13718 this.position = pos;
13720 // show north drag fro topdra
13721 var handlepos = pos == 'hdrag' ? 'north' : pos;
13723 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13724 if (pos == 'hdrag') {
13725 this.el.setStyle('cursor', 'pointer');
13727 this.el.unselectable();
13729 this.el.setOpacity(0);
13731 this.el.on("mousedown", this.onMouseDown, this);
13732 if(!disableTrackOver){
13733 this.el.on("mouseover", this.onMouseOver, this);
13734 this.el.on("mouseout", this.onMouseOut, this);
13739 Roo.Resizable.Handle.prototype = {
13740 afterResize : function(rz){
13744 onMouseDown : function(e){
13745 this.rz.onMouseDown(this, e);
13748 onMouseOver : function(e){
13749 this.rz.handleOver(this, e);
13752 onMouseOut : function(e){
13753 this.rz.handleOut(this, e);
13757 * Ext JS Library 1.1.1
13758 * Copyright(c) 2006-2007, Ext JS, LLC.
13760 * Originally Released Under LGPL - original licence link has changed is not relivant.
13763 * <script type="text/javascript">
13767 * @class Roo.Editor
13768 * @extends Roo.Component
13769 * A base editor field that handles displaying/hiding on demand and has some built-in sizing and event handling logic.
13771 * Create a new Editor
13772 * @param {Roo.form.Field} field The Field object (or descendant)
13773 * @param {Object} config The config object
13775 Roo.Editor = function(field, config){
13776 Roo.Editor.superclass.constructor.call(this, config);
13777 this.field = field;
13780 * @event beforestartedit
13781 * Fires when editing is initiated, but before the value changes. Editing can be canceled by returning
13782 * false from the handler of this event.
13783 * @param {Editor} this
13784 * @param {Roo.Element} boundEl The underlying element bound to this editor
13785 * @param {Mixed} value The field value being set
13787 "beforestartedit" : true,
13790 * Fires when this editor is displayed
13791 * @param {Roo.Element} boundEl The underlying element bound to this editor
13792 * @param {Mixed} value The starting field value
13794 "startedit" : true,
13796 * @event beforecomplete
13797 * Fires after a change has been made to the field, but before the change is reflected in the underlying
13798 * field. Saving the change to the field can be canceled by returning false from the handler of this event.
13799 * Note that if the value has not changed and ignoreNoChange = true, the editing will still end but this
13800 * event will not fire since no edit actually occurred.
13801 * @param {Editor} this
13802 * @param {Mixed} value The current field value
13803 * @param {Mixed} startValue The original field value
13805 "beforecomplete" : true,
13808 * Fires after editing is complete and any changed value has been written to the underlying field.
13809 * @param {Editor} this
13810 * @param {Mixed} value The current field value
13811 * @param {Mixed} startValue The original field value
13815 * @event specialkey
13816 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
13817 * {@link Roo.EventObject#getKey} to determine which key was pressed.
13818 * @param {Roo.form.Field} this
13819 * @param {Roo.EventObject} e The event object
13821 "specialkey" : true
13825 Roo.extend(Roo.Editor, Roo.Component, {
13827 * @cfg {Boolean/String} autosize
13828 * True for the editor to automatically adopt the size of the underlying field, "width" to adopt the width only,
13829 * or "height" to adopt the height only (defaults to false)
13832 * @cfg {Boolean} revertInvalid
13833 * True to automatically revert the field value and cancel the edit when the user completes an edit and the field
13834 * validation fails (defaults to true)
13837 * @cfg {Boolean} ignoreNoChange
13838 * True to skip the the edit completion process (no save, no events fired) if the user completes an edit and
13839 * the value has not changed (defaults to false). Applies only to string values - edits for other data types
13840 * will never be ignored.
13843 * @cfg {Boolean} hideEl
13844 * False to keep the bound element visible while the editor is displayed (defaults to true)
13847 * @cfg {Mixed} value
13848 * The data value of the underlying field (defaults to "")
13852 * @cfg {String} alignment
13853 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "c-c?").
13857 * @cfg {Boolean/String} shadow "sides" for sides/bottom only, "frame" for 4-way shadow, and "drop"
13858 * for bottom-right shadow (defaults to "frame")
13862 * @cfg {Boolean} constrain True to constrain the editor to the viewport
13866 * @cfg {Boolean} completeOnEnter True to complete the edit when the enter key is pressed (defaults to false)
13868 completeOnEnter : false,
13870 * @cfg {Boolean} cancelOnEsc True to cancel the edit when the escape key is pressed (defaults to false)
13872 cancelOnEsc : false,
13874 * @cfg {Boolean} updateEl True to update the innerHTML of the bound element when the update completes (defaults to false)
13879 onRender : function(ct, position){
13880 this.el = new Roo.Layer({
13881 shadow: this.shadow,
13887 constrain: this.constrain
13889 this.el.setStyle("overflow", Roo.isGecko ? "auto" : "hidden");
13890 if(this.field.msgTarget != 'title'){
13891 this.field.msgTarget = 'qtip';
13893 this.field.render(this.el);
13895 this.field.el.dom.setAttribute('autocomplete', 'off');
13897 this.field.on("specialkey", this.onSpecialKey, this);
13898 if(this.swallowKeys){
13899 this.field.el.swallowEvent(['keydown','keypress']);
13902 this.field.on("blur", this.onBlur, this);
13903 if(this.field.grow){
13904 this.field.on("autosize", this.el.sync, this.el, {delay:1});
13908 onSpecialKey : function(field, e){
13909 //Roo.log('editor onSpecialKey');
13910 if(this.completeOnEnter && e.getKey() == e.ENTER){
13912 this.completeEdit();
13913 }else if(this.cancelOnEsc && e.getKey() == e.ESC){
13916 this.fireEvent('specialkey', field, e);
13921 * Starts the editing process and shows the editor.
13922 * @param {String/HTMLElement/Element} el The element to edit
13923 * @param {String} value (optional) A value to initialize the editor with. If a value is not provided, it defaults
13924 * to the innerHTML of el.
13926 startEdit : function(el, value){
13928 this.completeEdit();
13930 this.boundEl = Roo.get(el);
13931 var v = value !== undefined ? value : this.boundEl.dom.innerHTML;
13932 if(!this.rendered){
13933 this.render(this.parentEl || document.body);
13935 if(this.fireEvent("beforestartedit", this, this.boundEl, v) === false){
13938 this.startValue = v;
13939 this.field.setValue(v);
13941 var sz = this.boundEl.getSize();
13942 switch(this.autoSize){
13944 this.setSize(sz.width, "");
13947 this.setSize("", sz.height);
13950 this.setSize(sz.width, sz.height);
13953 this.el.alignTo(this.boundEl, this.alignment);
13954 this.editing = true;
13956 Roo.QuickTips.disable();
13962 * Sets the height and width of this editor.
13963 * @param {Number} width The new width
13964 * @param {Number} height The new height
13966 setSize : function(w, h){
13967 this.field.setSize(w, h);
13974 * Realigns the editor to the bound field based on the current alignment config value.
13976 realign : function(){
13977 this.el.alignTo(this.boundEl, this.alignment);
13981 * Ends the editing process, persists the changed value to the underlying field, and hides the editor.
13982 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after edit (defaults to false)
13984 completeEdit : function(remainVisible){
13988 var v = this.getValue();
13989 if(this.revertInvalid !== false && !this.field.isValid()){
13990 v = this.startValue;
13991 this.cancelEdit(true);
13993 if(String(v) === String(this.startValue) && this.ignoreNoChange){
13994 this.editing = false;
13998 if(this.fireEvent("beforecomplete", this, v, this.startValue) !== false){
13999 this.editing = false;
14000 if(this.updateEl && this.boundEl){
14001 this.boundEl.update(v);
14003 if(remainVisible !== true){
14006 this.fireEvent("complete", this, v, this.startValue);
14011 onShow : function(){
14013 if(this.hideEl !== false){
14014 this.boundEl.hide();
14017 if(Roo.isIE && !this.fixIEFocus){ // IE has problems with focusing the first time
14018 this.fixIEFocus = true;
14019 this.deferredFocus.defer(50, this);
14021 this.field.focus();
14023 this.fireEvent("startedit", this.boundEl, this.startValue);
14026 deferredFocus : function(){
14028 this.field.focus();
14033 * Cancels the editing process and hides the editor without persisting any changes. The field value will be
14034 * reverted to the original starting value.
14035 * @param {Boolean} remainVisible Override the default behavior and keep the editor visible after
14036 * cancel (defaults to false)
14038 cancelEdit : function(remainVisible){
14040 this.setValue(this.startValue);
14041 if(remainVisible !== true){
14048 onBlur : function(){
14049 if(this.allowBlur !== true && this.editing){
14050 this.completeEdit();
14055 onHide : function(){
14057 this.completeEdit();
14061 if(this.field.collapse){
14062 this.field.collapse();
14065 if(this.hideEl !== false){
14066 this.boundEl.show();
14069 Roo.QuickTips.enable();
14074 * Sets the data value of the editor
14075 * @param {Mixed} value Any valid value supported by the underlying field
14077 setValue : function(v){
14078 this.field.setValue(v);
14082 * Gets the data value of the editor
14083 * @return {Mixed} The data value
14085 getValue : function(){
14086 return this.field.getValue();
14090 * Ext JS Library 1.1.1
14091 * Copyright(c) 2006-2007, Ext JS, LLC.
14093 * Originally Released Under LGPL - original licence link has changed is not relivant.
14096 * <script type="text/javascript">
14100 * @class Roo.BasicDialog
14101 * @extends Roo.util.Observable
14102 * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup:
14104 var dlg = new Roo.BasicDialog("my-dlg", {
14113 dlg.addKeyListener(27, dlg.hide, dlg); // ESC can also close the dialog
14114 dlg.addButton('OK', dlg.hide, dlg); // Could call a save function instead of hiding
14115 dlg.addButton('Cancel', dlg.hide, dlg);
14118 <b>A Dialog should always be a direct child of the body element.</b>
14119 * @cfg {Boolean/DomHelper} autoCreate True to auto create from scratch, or using a DomHelper Object (defaults to false)
14120 * @cfg {String} title Default text to display in the title bar (defaults to null)
14121 * @cfg {Number} width Width of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14122 * @cfg {Number} height Height of the dialog in pixels (can also be set via CSS). Determined by browser if unspecified.
14123 * @cfg {Number} x The default left page coordinate of the dialog (defaults to center screen)
14124 * @cfg {Number} y The default top page coordinate of the dialog (defaults to center screen)
14125 * @cfg {String/Element} animateTarget Id or element from which the dialog should animate while opening
14126 * (defaults to null with no animation)
14127 * @cfg {Boolean} resizable False to disable manual dialog resizing (defaults to true)
14128 * @cfg {String} resizeHandles Which resize handles to display - see the {@link Roo.Resizable} handles config
14129 * property for valid values (defaults to 'all')
14130 * @cfg {Number} minHeight The minimum allowable height for a resizable dialog (defaults to 80)
14131 * @cfg {Number} minWidth The minimum allowable width for a resizable dialog (defaults to 200)
14132 * @cfg {Boolean} modal True to show the dialog modally, preventing user interaction with the rest of the page (defaults to false)
14133 * @cfg {Boolean} autoScroll True to allow the dialog body contents to overflow and display scrollbars (defaults to false)
14134 * @cfg {Boolean} closable False to remove the built-in top-right corner close button (defaults to true)
14135 * @cfg {Boolean} collapsible False to remove the built-in top-right corner collapse button (defaults to true)
14136 * @cfg {Boolean} constraintoviewport True to keep the dialog constrained within the visible viewport boundaries (defaults to true)
14137 * @cfg {Boolean} syncHeightBeforeShow True to cause the dimensions to be recalculated before the dialog is shown (defaults to false)
14138 * @cfg {Boolean} draggable False to disable dragging of the dialog within the viewport (defaults to true)
14139 * @cfg {Boolean} autoTabs If true, all elements with class 'x-dlg-tab' will get automatically converted to tabs (defaults to false)
14140 * @cfg {String} tabTag The tag name of tab elements, used when autoTabs = true (defaults to 'div')
14141 * @cfg {Boolean} proxyDrag True to drag a lightweight proxy element rather than the dialog itself, used when
14142 * draggable = true (defaults to false)
14143 * @cfg {Boolean} fixedcenter True to ensure that anytime the dialog is shown or resized it gets centered (defaults to false)
14144 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
14145 * shadow (defaults to false)
14146 * @cfg {Number} shadowOffset The number of pixels to offset the shadow if displayed (defaults to 5)
14147 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "right")
14148 * @cfg {Number} minButtonWidth Minimum width of all dialog buttons (defaults to 75)
14149 * @cfg {Array} buttons Array of buttons
14150 * @cfg {Boolean} shim True to create an iframe shim that prevents selects from showing through (defaults to false)
14152 * Create a new BasicDialog.
14153 * @param {String/HTMLElement/Roo.Element} el The container element or DOM node, or its id
14154 * @param {Object} config Configuration options
14156 Roo.BasicDialog = function(el, config){
14157 this.el = Roo.get(el);
14158 var dh = Roo.DomHelper;
14159 if(!this.el && config && config.autoCreate){
14160 if(typeof config.autoCreate == "object"){
14161 if(!config.autoCreate.id){
14162 config.autoCreate.id = el;
14164 this.el = dh.append(document.body,
14165 config.autoCreate, true);
14167 this.el = dh.append(document.body,
14168 {tag: "div", id: el, style:'visibility:hidden;'}, true);
14172 el.setDisplayed(true);
14173 el.hide = this.hideAction;
14175 el.addClass("x-dlg");
14177 Roo.apply(this, config);
14179 this.proxy = el.createProxy("x-dlg-proxy");
14180 this.proxy.hide = this.hideAction;
14181 this.proxy.setOpacity(.5);
14185 el.setWidth(config.width);
14188 el.setHeight(config.height);
14190 this.size = el.getSize();
14191 if(typeof config.x != "undefined" && typeof config.y != "undefined"){
14192 this.xy = [config.x,config.y];
14194 this.xy = el.getCenterXY(true);
14196 /** The header element @type Roo.Element */
14197 this.header = el.child("> .x-dlg-hd");
14198 /** The body element @type Roo.Element */
14199 this.body = el.child("> .x-dlg-bd");
14200 /** The footer element @type Roo.Element */
14201 this.footer = el.child("> .x-dlg-ft");
14204 this.header = el.createChild({tag: "div", cls:"x-dlg-hd", html: " "}, this.body ? this.body.dom : null);
14207 this.body = el.createChild({tag: "div", cls:"x-dlg-bd"});
14210 this.header.unselectable();
14212 this.header.update(this.title);
14214 // this element allows the dialog to be focused for keyboard event
14215 this.focusEl = el.createChild({tag: "a", href:"#", cls:"x-dlg-focus", tabIndex:"-1"});
14216 this.focusEl.swallowEvent("click", true);
14218 this.header.wrap({cls:"x-dlg-hd-right"}).wrap({cls:"x-dlg-hd-left"}, true);
14220 // wrap the body and footer for special rendering
14221 this.bwrap = this.body.wrap({tag: "div", cls:"x-dlg-dlg-body"});
14223 this.bwrap.dom.appendChild(this.footer.dom);
14226 this.bg = this.el.createChild({
14227 tag: "div", cls:"x-dlg-bg",
14228 html: '<div class="x-dlg-bg-left"><div class="x-dlg-bg-right"><div class="x-dlg-bg-center"> </div></div></div>'
14230 this.centerBg = this.bg.child("div.x-dlg-bg-center");
14233 if(this.autoScroll !== false && !this.autoTabs){
14234 this.body.setStyle("overflow", "auto");
14237 this.toolbox = this.el.createChild({cls: "x-dlg-toolbox"});
14239 if(this.closable !== false){
14240 this.el.addClass("x-dlg-closable");
14241 this.close = this.toolbox.createChild({cls:"x-dlg-close"});
14242 this.close.on("click", this.closeClick, this);
14243 this.close.addClassOnOver("x-dlg-close-over");
14245 if(this.collapsible !== false){
14246 this.collapseBtn = this.toolbox.createChild({cls:"x-dlg-collapse"});
14247 this.collapseBtn.on("click", this.collapseClick, this);
14248 this.collapseBtn.addClassOnOver("x-dlg-collapse-over");
14249 this.header.on("dblclick", this.collapseClick, this);
14251 if(this.resizable !== false){
14252 this.el.addClass("x-dlg-resizable");
14253 this.resizer = new Roo.Resizable(el, {
14254 minWidth: this.minWidth || 80,
14255 minHeight:this.minHeight || 80,
14256 handles: this.resizeHandles || "all",
14259 this.resizer.on("beforeresize", this.beforeResize, this);
14260 this.resizer.on("resize", this.onResize, this);
14262 if(this.draggable !== false){
14263 el.addClass("x-dlg-draggable");
14264 if (!this.proxyDrag) {
14265 var dd = new Roo.dd.DD(el.dom.id, "WindowDrag");
14268 var dd = new Roo.dd.DDProxy(el.dom.id, "WindowDrag", {dragElId: this.proxy.id});
14270 dd.setHandleElId(this.header.id);
14271 dd.endDrag = this.endMove.createDelegate(this);
14272 dd.startDrag = this.startMove.createDelegate(this);
14273 dd.onDrag = this.onDrag.createDelegate(this);
14278 this.mask = dh.append(document.body, {tag: "div", cls:"x-dlg-mask"}, true);
14279 this.mask.enableDisplayMode("block");
14281 this.el.addClass("x-dlg-modal");
14284 this.shadow = new Roo.Shadow({
14285 mode : typeof this.shadow == "string" ? this.shadow : "sides",
14286 offset : this.shadowOffset
14289 this.shadowOffset = 0;
14291 if(Roo.useShims && this.shim !== false){
14292 this.shim = this.el.createShim();
14293 this.shim.hide = this.hideAction;
14301 if (this.buttons) {
14302 var bts= this.buttons;
14304 Roo.each(bts, function(b) {
14313 * Fires when a key is pressed
14314 * @param {Roo.BasicDialog} this
14315 * @param {Roo.EventObject} e
14320 * Fires when this dialog is moved by the user.
14321 * @param {Roo.BasicDialog} this
14322 * @param {Number} x The new page X
14323 * @param {Number} y The new page Y
14328 * Fires when this dialog is resized by the user.
14329 * @param {Roo.BasicDialog} this
14330 * @param {Number} width The new width
14331 * @param {Number} height The new height
14335 * @event beforehide
14336 * Fires before this dialog is hidden.
14337 * @param {Roo.BasicDialog} this
14339 "beforehide" : true,
14342 * Fires when this dialog is hidden.
14343 * @param {Roo.BasicDialog} this
14347 * @event beforeshow
14348 * Fires before this dialog is shown.
14349 * @param {Roo.BasicDialog} this
14351 "beforeshow" : true,
14354 * Fires when this dialog is shown.
14355 * @param {Roo.BasicDialog} this
14359 el.on("keydown", this.onKeyDown, this);
14360 el.on("mousedown", this.toFront, this);
14361 Roo.EventManager.onWindowResize(this.adjustViewport, this, true);
14363 Roo.DialogManager.register(this);
14364 Roo.BasicDialog.superclass.constructor.call(this);
14367 Roo.extend(Roo.BasicDialog, Roo.util.Observable, {
14368 shadowOffset: Roo.isIE ? 6 : 5,
14371 minButtonWidth: 75,
14372 defaultButton: null,
14373 buttonAlign: "right",
14378 * Sets the dialog title text
14379 * @param {String} text The title text to display
14380 * @return {Roo.BasicDialog} this
14382 setTitle : function(text){
14383 this.header.update(text);
14388 closeClick : function(){
14393 collapseClick : function(){
14394 this[this.collapsed ? "expand" : "collapse"]();
14398 * Collapses the dialog to its minimized state (only the title bar is visible).
14399 * Equivalent to the user clicking the collapse dialog button.
14401 collapse : function(){
14402 if(!this.collapsed){
14403 this.collapsed = true;
14404 this.el.addClass("x-dlg-collapsed");
14405 this.restoreHeight = this.el.getHeight();
14406 this.resizeTo(this.el.getWidth(), this.header.getHeight());
14411 * Expands a collapsed dialog back to its normal state. Equivalent to the user
14412 * clicking the expand dialog button.
14414 expand : function(){
14415 if(this.collapsed){
14416 this.collapsed = false;
14417 this.el.removeClass("x-dlg-collapsed");
14418 this.resizeTo(this.el.getWidth(), this.restoreHeight);
14423 * Reinitializes the tabs component, clearing out old tabs and finding new ones.
14424 * @return {Roo.TabPanel} The tabs component
14426 initTabs : function(){
14427 var tabs = this.getTabs();
14428 while(tabs.getTab(0)){
14431 this.el.select(this.tabTag+'.x-dlg-tab').each(function(el){
14433 tabs.addTab(Roo.id(dom), dom.title);
14441 beforeResize : function(){
14442 this.resizer.minHeight = Math.max(this.minHeight, this.getHeaderFooterHeight(true)+40);
14446 onResize : function(){
14447 this.refreshSize();
14448 this.syncBodyHeight();
14449 this.adjustAssets();
14451 this.fireEvent("resize", this, this.size.width, this.size.height);
14455 onKeyDown : function(e){
14456 if(this.isVisible()){
14457 this.fireEvent("keydown", this, e);
14462 * Resizes the dialog.
14463 * @param {Number} width
14464 * @param {Number} height
14465 * @return {Roo.BasicDialog} this
14467 resizeTo : function(width, height){
14468 this.el.setSize(width, height);
14469 this.size = {width: width, height: height};
14470 this.syncBodyHeight();
14471 if(this.fixedcenter){
14474 if(this.isVisible()){
14475 this.constrainXY();
14476 this.adjustAssets();
14478 this.fireEvent("resize", this, width, height);
14484 * Resizes the dialog to fit the specified content size.
14485 * @param {Number} width
14486 * @param {Number} height
14487 * @return {Roo.BasicDialog} this
14489 setContentSize : function(w, h){
14490 h += this.getHeaderFooterHeight() + this.body.getMargins("tb");
14491 w += this.body.getMargins("lr") + this.bwrap.getMargins("lr") + this.centerBg.getPadding("lr");
14492 //if(!this.el.isBorderBox()){
14493 h += this.body.getPadding("tb") + this.bwrap.getBorderWidth("tb") + this.body.getBorderWidth("tb") + this.el.getBorderWidth("tb");
14494 w += this.body.getPadding("lr") + this.bwrap.getBorderWidth("lr") + this.body.getBorderWidth("lr") + this.bwrap.getPadding("lr") + this.el.getBorderWidth("lr");
14497 h += this.tabs.stripWrap.getHeight() + this.tabs.bodyEl.getMargins("tb") + this.tabs.bodyEl.getPadding("tb");
14498 w += this.tabs.bodyEl.getMargins("lr") + this.tabs.bodyEl.getPadding("lr");
14500 this.resizeTo(w, h);
14505 * Adds a key listener for when this dialog is displayed. This allows you to hook in a function that will be
14506 * executed in response to a particular key being pressed while the dialog is active.
14507 * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the following options:
14508 * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14509 * @param {Function} fn The function to call
14510 * @param {Object} scope (optional) The scope of the function
14511 * @return {Roo.BasicDialog} this
14513 addKeyListener : function(key, fn, scope){
14514 var keyCode, shift, ctrl, alt;
14515 if(typeof key == "object" && !(key instanceof Array)){
14516 keyCode = key["key"];
14517 shift = key["shift"];
14518 ctrl = key["ctrl"];
14523 var handler = function(dlg, e){
14524 if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) && (!alt || e.altKey)){
14525 var k = e.getKey();
14526 if(keyCode instanceof Array){
14527 for(var i = 0, len = keyCode.length; i < len; i++){
14528 if(keyCode[i] == k){
14529 fn.call(scope || window, dlg, k, e);
14535 fn.call(scope || window, dlg, k, e);
14540 this.on("keydown", handler);
14545 * Returns the TabPanel component (creates it if it doesn't exist).
14546 * Note: If you wish to simply check for the existence of tabs without creating them,
14547 * check for a null 'tabs' property.
14548 * @return {Roo.TabPanel} The tabs component
14550 getTabs : function(){
14552 this.el.addClass("x-dlg-auto-tabs");
14553 this.body.addClass(this.tabPosition == "bottom" ? "x-tabs-bottom" : "x-tabs-top");
14554 this.tabs = new Roo.TabPanel(this.body.dom, this.tabPosition == "bottom");
14560 * Adds a button to the footer section of the dialog.
14561 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
14562 * object or a valid Roo.DomHelper element config
14563 * @param {Function} handler The function called when the button is clicked
14564 * @param {Object} scope (optional) The scope of the handler function (accepts position as a property)
14565 * @return {Roo.Button} The new button
14567 addButton : function(config, handler, scope){
14568 var dh = Roo.DomHelper;
14570 this.footer = dh.append(this.bwrap, {tag: "div", cls:"x-dlg-ft"}, true);
14572 if(!this.btnContainer){
14573 var tb = this.footer.createChild({
14575 cls:"x-dlg-btns x-dlg-btns-"+this.buttonAlign,
14576 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
14578 this.btnContainer = tb.firstChild.firstChild.firstChild;
14583 minWidth: this.minButtonWidth,
14586 if(typeof config == "string"){
14587 bconfig.text = config;
14590 bconfig.dhconfig = config;
14592 Roo.apply(bconfig, config);
14596 if ((typeof(bconfig.position) != 'undefined') && bconfig.position < this.btnContainer.childNodes.length-1) {
14597 bconfig.position = Math.max(0, bconfig.position);
14598 fc = this.btnContainer.childNodes[bconfig.position];
14601 var btn = new Roo.Button(
14603 this.btnContainer.insertBefore(document.createElement("td"),fc)
14604 : this.btnContainer.appendChild(document.createElement("td")),
14605 //Roo.get(this.btnContainer).createChild( { tag: 'td'}, fc ),
14608 this.syncBodyHeight();
14611 * Array of all the buttons that have been added to this dialog via addButton
14616 this.buttons.push(btn);
14621 * Sets the default button to be focused when the dialog is displayed.
14622 * @param {Roo.BasicDialog.Button} btn The button object returned by {@link #addButton}
14623 * @return {Roo.BasicDialog} this
14625 setDefaultButton : function(btn){
14626 this.defaultButton = btn;
14631 getHeaderFooterHeight : function(safe){
14634 height += this.header.getHeight();
14637 var fm = this.footer.getMargins();
14638 height += (this.footer.getHeight()+fm.top+fm.bottom);
14640 height += this.bwrap.getPadding("tb")+this.bwrap.getBorderWidth("tb");
14641 height += this.centerBg.getPadding("tb");
14646 syncBodyHeight : function(){
14647 var bd = this.body, cb = this.centerBg, bw = this.bwrap;
14648 var height = this.size.height - this.getHeaderFooterHeight(false);
14649 bd.setHeight(height-bd.getMargins("tb"));
14650 var hh = this.header.getHeight();
14651 var h = this.size.height-hh;
14653 bw.setLeftTop(cb.getPadding("l"), hh+cb.getPadding("t"));
14654 bw.setHeight(h-cb.getPadding("tb"));
14655 bw.setWidth(this.el.getWidth(true)-cb.getPadding("lr"));
14656 bd.setWidth(bw.getWidth(true));
14658 this.tabs.syncHeight();
14660 this.tabs.el.repaint();
14666 * Restores the previous state of the dialog if Roo.state is configured.
14667 * @return {Roo.BasicDialog} this
14669 restoreState : function(){
14670 var box = Roo.state.Manager.get(this.stateId || (this.el.id + "-state"));
14671 if(box && box.width){
14672 this.xy = [box.x, box.y];
14673 this.resizeTo(box.width, box.height);
14679 beforeShow : function(){
14681 if(this.fixedcenter){
14682 this.xy = this.el.getCenterXY(true);
14685 Roo.get(document.body).addClass("x-body-masked");
14686 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14689 this.constrainXY();
14693 animShow : function(){
14694 var b = Roo.get(this.animateTarget).getBox();
14695 this.proxy.setSize(b.width, b.height);
14696 this.proxy.setLocation(b.x, b.y);
14698 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height,
14699 true, .35, this.showEl.createDelegate(this));
14703 * Shows the dialog.
14704 * @param {String/HTMLElement/Roo.Element} animateTarget (optional) Reset the animation target
14705 * @return {Roo.BasicDialog} this
14707 show : function(animateTarget){
14708 if (this.fireEvent("beforeshow", this) === false){
14711 if(this.syncHeightBeforeShow){
14712 this.syncBodyHeight();
14713 }else if(this.firstShow){
14714 this.firstShow = false;
14715 this.syncBodyHeight(); // sync the height on the first show instead of in the constructor
14717 this.animateTarget = animateTarget || this.animateTarget;
14718 if(!this.el.isVisible()){
14720 if(this.animateTarget && Roo.get(this.animateTarget)){
14730 showEl : function(){
14732 this.el.setXY(this.xy);
14734 this.adjustAssets(true);
14737 // IE peekaboo bug - fix found by Dave Fenwick
14741 this.fireEvent("show", this);
14745 * Focuses the dialog. If a defaultButton is set, it will receive focus, otherwise the
14746 * dialog itself will receive focus.
14748 focus : function(){
14749 if(this.defaultButton){
14750 this.defaultButton.focus();
14752 this.focusEl.focus();
14757 constrainXY : function(){
14758 if(this.constraintoviewport !== false){
14759 if(!this.viewSize){
14760 if(this.container){
14761 var s = this.container.getSize();
14762 this.viewSize = [s.width, s.height];
14764 this.viewSize = [Roo.lib.Dom.getViewWidth(),Roo.lib.Dom.getViewHeight()];
14767 var s = Roo.get(this.container||document).getScroll();
14769 var x = this.xy[0], y = this.xy[1];
14770 var w = this.size.width, h = this.size.height;
14771 var vw = this.viewSize[0], vh = this.viewSize[1];
14772 // only move it if it needs it
14774 // first validate right/bottom
14775 if(x + w > vw+s.left){
14779 if(y + h > vh+s.top){
14783 // then make sure top/left isn't negative
14795 if(this.isVisible()){
14796 this.el.setLocation(x, y);
14797 this.adjustAssets();
14804 onDrag : function(){
14805 if(!this.proxyDrag){
14806 this.xy = this.el.getXY();
14807 this.adjustAssets();
14812 adjustAssets : function(doShow){
14813 var x = this.xy[0], y = this.xy[1];
14814 var w = this.size.width, h = this.size.height;
14815 if(doShow === true){
14817 this.shadow.show(this.el);
14823 if(this.shadow && this.shadow.isVisible()){
14824 this.shadow.show(this.el);
14826 if(this.shim && this.shim.isVisible()){
14827 this.shim.setBounds(x, y, w, h);
14832 adjustViewport : function(w, h){
14834 w = Roo.lib.Dom.getViewWidth();
14835 h = Roo.lib.Dom.getViewHeight();
14838 this.viewSize = [w, h];
14839 if(this.modal && this.mask.isVisible()){
14840 this.mask.setSize(w, h); // first make sure the mask isn't causing overflow
14841 this.mask.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
14843 if(this.isVisible()){
14844 this.constrainXY();
14849 * Destroys this dialog and all its supporting elements (including any tabs, shim,
14850 * shadow, proxy, mask, etc.) Also removes all event listeners.
14851 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
14853 destroy : function(removeEl){
14854 if(this.isVisible()){
14855 this.animateTarget = null;
14858 Roo.EventManager.removeResizeListener(this.adjustViewport, this);
14860 this.tabs.destroy(removeEl);
14873 for(var i = 0, len = this.buttons.length; i < len; i++){
14874 this.buttons[i].destroy();
14877 this.el.removeAllListeners();
14878 if(removeEl === true){
14879 this.el.update("");
14882 Roo.DialogManager.unregister(this);
14886 startMove : function(){
14887 if(this.proxyDrag){
14890 if(this.constraintoviewport !== false){
14891 this.dd.constrainTo(document.body, {right: this.shadowOffset, bottom: this.shadowOffset});
14896 endMove : function(){
14897 if(!this.proxyDrag){
14898 Roo.dd.DD.prototype.endDrag.apply(this.dd, arguments);
14900 Roo.dd.DDProxy.prototype.endDrag.apply(this.dd, arguments);
14903 this.refreshSize();
14904 this.adjustAssets();
14906 this.fireEvent("move", this, this.xy[0], this.xy[1]);
14910 * Brings this dialog to the front of any other visible dialogs
14911 * @return {Roo.BasicDialog} this
14913 toFront : function(){
14914 Roo.DialogManager.bringToFront(this);
14919 * Sends this dialog to the back (under) of any other visible dialogs
14920 * @return {Roo.BasicDialog} this
14922 toBack : function(){
14923 Roo.DialogManager.sendToBack(this);
14928 * Centers this dialog in the viewport
14929 * @return {Roo.BasicDialog} this
14931 center : function(){
14932 var xy = this.el.getCenterXY(true);
14933 this.moveTo(xy[0], xy[1]);
14938 * Moves the dialog's top-left corner to the specified point
14939 * @param {Number} x
14940 * @param {Number} y
14941 * @return {Roo.BasicDialog} this
14943 moveTo : function(x, y){
14945 if(this.isVisible()){
14946 this.el.setXY(this.xy);
14947 this.adjustAssets();
14953 * Aligns the dialog to the specified element
14954 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14955 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details).
14956 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14957 * @return {Roo.BasicDialog} this
14959 alignTo : function(element, position, offsets){
14960 this.xy = this.el.getAlignToXY(element, position, offsets);
14961 if(this.isVisible()){
14962 this.el.setXY(this.xy);
14963 this.adjustAssets();
14969 * Anchors an element to another element and realigns it when the window is resized.
14970 * @param {String/HTMLElement/Roo.Element} element The element to align to.
14971 * @param {String} position The position to align to (see {@link Roo.Element#alignTo} for more details)
14972 * @param {Array} offsets (optional) Offset the positioning by [x, y]
14973 * @param {Boolean/Number} monitorScroll (optional) true to monitor body scroll and reposition. If this parameter
14974 * is a number, it is used as the buffer delay (defaults to 50ms).
14975 * @return {Roo.BasicDialog} this
14977 anchorTo : function(el, alignment, offsets, monitorScroll){
14978 var action = function(){
14979 this.alignTo(el, alignment, offsets);
14981 Roo.EventManager.onWindowResize(action, this);
14982 var tm = typeof monitorScroll;
14983 if(tm != 'undefined'){
14984 Roo.EventManager.on(window, 'scroll', action, this,
14985 {buffer: tm == 'number' ? monitorScroll : 50});
14992 * Returns true if the dialog is visible
14993 * @return {Boolean}
14995 isVisible : function(){
14996 return this.el.isVisible();
15000 animHide : function(callback){
15001 var b = Roo.get(this.animateTarget).getBox();
15003 this.proxy.setBounds(this.xy[0], this.xy[1], this.size.width, this.size.height);
15005 this.proxy.setBounds(b.x, b.y, b.width, b.height, true, .35,
15006 this.hideEl.createDelegate(this, [callback]));
15010 * Hides the dialog.
15011 * @param {Function} callback (optional) Function to call when the dialog is hidden
15012 * @return {Roo.BasicDialog} this
15014 hide : function(callback){
15015 if (this.fireEvent("beforehide", this) === false){
15019 this.shadow.hide();
15024 // sometimes animateTarget seems to get set.. causing problems...
15025 // this just double checks..
15026 if(this.animateTarget && Roo.get(this.animateTarget)) {
15027 this.animHide(callback);
15030 this.hideEl(callback);
15036 hideEl : function(callback){
15040 Roo.get(document.body).removeClass("x-body-masked");
15042 this.fireEvent("hide", this);
15043 if(typeof callback == "function"){
15049 hideAction : function(){
15050 this.setLeft("-10000px");
15051 this.setTop("-10000px");
15052 this.setStyle("visibility", "hidden");
15056 refreshSize : function(){
15057 this.size = this.el.getSize();
15058 this.xy = this.el.getXY();
15059 Roo.state.Manager.set(this.stateId || this.el.id + "-state", this.el.getBox());
15063 // z-index is managed by the DialogManager and may be overwritten at any time
15064 setZIndex : function(index){
15066 this.mask.setStyle("z-index", index);
15069 this.shim.setStyle("z-index", ++index);
15072 this.shadow.setZIndex(++index);
15074 this.el.setStyle("z-index", ++index);
15076 this.proxy.setStyle("z-index", ++index);
15079 this.resizer.proxy.setStyle("z-index", ++index);
15082 this.lastZIndex = index;
15086 * Returns the element for this dialog
15087 * @return {Roo.Element} The underlying dialog Element
15089 getEl : function(){
15095 * @class Roo.DialogManager
15096 * Provides global access to BasicDialogs that have been created and
15097 * support for z-indexing (layering) multiple open dialogs.
15099 Roo.DialogManager = function(){
15101 var accessList = [];
15105 var sortDialogs = function(d1, d2){
15106 return (!d1._lastAccess || d1._lastAccess < d2._lastAccess) ? -1 : 1;
15110 var orderDialogs = function(){
15111 accessList.sort(sortDialogs);
15112 var seed = Roo.DialogManager.zseed;
15113 for(var i = 0, len = accessList.length; i < len; i++){
15114 var dlg = accessList[i];
15116 dlg.setZIndex(seed + (i*10));
15123 * The starting z-index for BasicDialogs (defaults to 9000)
15124 * @type Number The z-index value
15129 register : function(dlg){
15130 list[dlg.id] = dlg;
15131 accessList.push(dlg);
15135 unregister : function(dlg){
15136 delete list[dlg.id];
15139 if(!accessList.indexOf){
15140 for( i = 0, len = accessList.length; i < len; i++){
15141 if(accessList[i] == dlg){
15142 accessList.splice(i, 1);
15147 i = accessList.indexOf(dlg);
15149 accessList.splice(i, 1);
15155 * Gets a registered dialog by id
15156 * @param {String/Object} id The id of the dialog or a dialog
15157 * @return {Roo.BasicDialog} this
15159 get : function(id){
15160 return typeof id == "object" ? id : list[id];
15164 * Brings the specified dialog to the front
15165 * @param {String/Object} dlg The id of the dialog or a dialog
15166 * @return {Roo.BasicDialog} this
15168 bringToFront : function(dlg){
15169 dlg = this.get(dlg);
15172 dlg._lastAccess = new Date().getTime();
15179 * Sends the specified dialog to the back
15180 * @param {String/Object} dlg The id of the dialog or a dialog
15181 * @return {Roo.BasicDialog} this
15183 sendToBack : function(dlg){
15184 dlg = this.get(dlg);
15185 dlg._lastAccess = -(new Date().getTime());
15191 * Hides all dialogs
15193 hideAll : function(){
15194 for(var id in list){
15195 if(list[id] && typeof list[id] != "function" && list[id].isVisible()){
15204 * @class Roo.LayoutDialog
15205 * @extends Roo.BasicDialog
15206 * Dialog which provides adjustments for working with a layout in a Dialog.
15207 * Add your necessary layout config options to the dialog's config.<br>
15208 * Example usage (including a nested layout):
15211 dialog = new Roo.LayoutDialog("download-dlg", {
15220 // layout config merges with the dialog config
15222 tabPosition: "top",
15223 alwaysShowTabs: true
15226 dialog.addKeyListener(27, dialog.hide, dialog);
15227 dialog.setDefaultButton(dialog.addButton("Close", dialog.hide, dialog));
15228 dialog.addButton("Build It!", this.getDownload, this);
15230 // we can even add nested layouts
15231 var innerLayout = new Roo.BorderLayout("dl-inner", {
15241 innerLayout.beginUpdate();
15242 innerLayout.add("east", new Roo.ContentPanel("dl-details"));
15243 innerLayout.add("center", new Roo.ContentPanel("selection-panel"));
15244 innerLayout.endUpdate(true);
15246 var layout = dialog.getLayout();
15247 layout.beginUpdate();
15248 layout.add("center", new Roo.ContentPanel("standard-panel",
15249 {title: "Download the Source", fitToFrame:true}));
15250 layout.add("center", new Roo.NestedLayoutPanel(innerLayout,
15251 {title: "Build your own roo.js"}));
15252 layout.getRegion("center").showPanel(sp);
15253 layout.endUpdate();
15257 * @param {String/HTMLElement/Roo.Element} el The id of or container element, or config
15258 * @param {Object} config configuration options
15260 Roo.LayoutDialog = function(el, cfg){
15263 if (typeof(cfg) == 'undefined') {
15264 config = Roo.apply({}, el);
15265 // not sure why we use documentElement here.. - it should always be body.
15266 // IE7 borks horribly if we use documentElement.
15267 el = Roo.get( Roo.isIE ? (document.body || document.documentElement) : (document.documentElement || document.body) ).createChild();
15268 //config.autoCreate = true;
15272 config.autoTabs = false;
15273 Roo.LayoutDialog.superclass.constructor.call(this, el, config);
15274 this.body.setStyle({overflow:"hidden", position:"relative"});
15275 this.layout = new Roo.BorderLayout(this.body.dom, config);
15276 this.layout.monitorWindowResize = false;
15277 this.el.addClass("x-dlg-auto-layout");
15278 // fix case when center region overwrites center function
15279 this.center = Roo.BasicDialog.prototype.center;
15280 this.on("show", this.layout.layout, this.layout, true);
15281 if (config.items) {
15282 var xitems = config.items;
15283 delete config.items;
15284 Roo.each(xitems, this.addxtype, this);
15289 Roo.extend(Roo.LayoutDialog, Roo.BasicDialog, {
15291 * Ends update of the layout <strike>and resets display to none</strike>. Use standard beginUpdate/endUpdate on the layout.
15294 endUpdate : function(){
15295 this.layout.endUpdate();
15299 * Begins an update of the layout <strike>and sets display to block and visibility to hidden</strike>. Use standard beginUpdate/endUpdate on the layout.
15302 beginUpdate : function(){
15303 this.layout.beginUpdate();
15307 * Get the BorderLayout for this dialog
15308 * @return {Roo.BorderLayout}
15310 getLayout : function(){
15311 return this.layout;
15314 showEl : function(){
15315 Roo.LayoutDialog.superclass.showEl.apply(this, arguments);
15317 this.layout.layout();
15322 // Use the syncHeightBeforeShow config option to control this automatically
15323 syncBodyHeight : function(){
15324 Roo.LayoutDialog.superclass.syncBodyHeight.call(this);
15325 if(this.layout){this.layout.layout();}
15329 * Add an xtype element (actually adds to the layout.)
15330 * @return {Object} xdata xtype object data.
15333 addxtype : function(c) {
15334 return this.layout.addxtype(c);
15338 * Ext JS Library 1.1.1
15339 * Copyright(c) 2006-2007, Ext JS, LLC.
15341 * Originally Released Under LGPL - original licence link has changed is not relivant.
15344 * <script type="text/javascript">
15348 * @class Roo.MessageBox
15349 * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used.
15353 Roo.Msg.alert('Status', 'Changes saved successfully.');
15355 // Prompt for user data:
15356 Roo.Msg.prompt('Name', 'Please enter your name:', function(btn, text){
15358 // process text value...
15362 // Show a dialog using config options:
15364 title:'Save Changes?',
15365 msg: 'Your are closing a tab that has unsaved changes. Would you like to save your changes?',
15366 buttons: Roo.Msg.YESNOCANCEL,
15373 Roo.MessageBox = function(){
15374 var dlg, opt, mask, waitTimer;
15375 var bodyEl, msgEl, textboxEl, textareaEl, progressEl, pp;
15376 var buttons, activeTextEl, bwidth;
15379 var handleButton = function(button){
15381 Roo.callback(opt.fn, opt.scope||window, [button, activeTextEl.dom.value], 1);
15385 var handleHide = function(){
15386 if(opt && opt.cls){
15387 dlg.el.removeClass(opt.cls);
15390 Roo.TaskMgr.stop(waitTimer);
15396 var updateButtons = function(b){
15399 buttons["ok"].hide();
15400 buttons["cancel"].hide();
15401 buttons["yes"].hide();
15402 buttons["no"].hide();
15403 dlg.footer.dom.style.display = 'none';
15406 dlg.footer.dom.style.display = '';
15407 for(var k in buttons){
15408 if(typeof buttons[k] != "function"){
15411 buttons[k].setText(typeof b[k] == "string" ? b[k] : Roo.MessageBox.buttonText[k]);
15412 width += buttons[k].el.getWidth()+15;
15422 var handleEsc = function(d, k, e){
15423 if(opt && opt.closable !== false){
15433 * Returns a reference to the underlying {@link Roo.BasicDialog} element
15434 * @return {Roo.BasicDialog} The BasicDialog element
15436 getDialog : function(){
15438 dlg = new Roo.BasicDialog("x-msg-box", {
15443 constraintoviewport:false,
15445 collapsible : false,
15448 width:400, height:100,
15449 buttonAlign:"center",
15450 closeClick : function(){
15451 if(opt && opt.buttons && opt.buttons.no && !opt.buttons.cancel){
15452 handleButton("no");
15454 handleButton("cancel");
15458 dlg.on("hide", handleHide);
15460 dlg.addKeyListener(27, handleEsc);
15462 var bt = this.buttonText;
15463 buttons["ok"] = dlg.addButton(bt["ok"], handleButton.createCallback("ok"));
15464 buttons["yes"] = dlg.addButton(bt["yes"], handleButton.createCallback("yes"));
15465 buttons["no"] = dlg.addButton(bt["no"], handleButton.createCallback("no"));
15466 buttons["cancel"] = dlg.addButton(bt["cancel"], handleButton.createCallback("cancel"));
15467 bodyEl = dlg.body.createChild({
15469 html:'<span class="roo-mb-text"></span><br /><input type="text" class="roo-mb-input" /><textarea class="roo-mb-textarea"></textarea><div class="roo-mb-progress-wrap"><div class="roo-mb-progress"><div class="roo-mb-progress-bar"> </div></div></div>'
15471 msgEl = bodyEl.dom.firstChild;
15472 textboxEl = Roo.get(bodyEl.dom.childNodes[2]);
15473 textboxEl.enableDisplayMode();
15474 textboxEl.addKeyListener([10,13], function(){
15475 if(dlg.isVisible() && opt && opt.buttons){
15476 if(opt.buttons.ok){
15477 handleButton("ok");
15478 }else if(opt.buttons.yes){
15479 handleButton("yes");
15483 textareaEl = Roo.get(bodyEl.dom.childNodes[3]);
15484 textareaEl.enableDisplayMode();
15485 progressEl = Roo.get(bodyEl.dom.childNodes[4]);
15486 progressEl.enableDisplayMode();
15487 var pf = progressEl.dom.firstChild;
15489 pp = Roo.get(pf.firstChild);
15490 pp.setHeight(pf.offsetHeight);
15498 * Updates the message box body text
15499 * @param {String} text (optional) Replaces the message box element's innerHTML with the specified string (defaults to
15500 * the XHTML-compliant non-breaking space character '&#160;')
15501 * @return {Roo.MessageBox} This message box
15503 updateText : function(text){
15504 if(!dlg.isVisible() && !opt.width){
15505 dlg.resizeTo(this.maxWidth, 100); // resize first so content is never clipped from previous shows
15507 msgEl.innerHTML = text || ' ';
15508 var w = Math.max(Math.min(opt.width || msgEl.offsetWidth, this.maxWidth),
15509 Math.max(opt.minWidth || this.minWidth, bwidth));
15511 activeTextEl.setWidth(w);
15513 if(dlg.isVisible()){
15514 dlg.fixedcenter = false;
15516 dlg.setContentSize(w, bodyEl.getHeight());
15517 if(dlg.isVisible()){
15518 dlg.fixedcenter = true;
15524 * Updates a progress-style message box's text and progress bar. Only relevant on message boxes
15525 * initiated via {@link Roo.MessageBox#progress} or by calling {@link Roo.MessageBox#show} with progress: true.
15526 * @param {Number} value Any number between 0 and 1 (e.g., .5)
15527 * @param {String} text (optional) If defined, the message box's body text is replaced with the specified string (defaults to undefined)
15528 * @return {Roo.MessageBox} This message box
15530 updateProgress : function(value, text){
15532 this.updateText(text);
15534 if (pp) { // weird bug on my firefox - for some reason this is not defined
15535 pp.setWidth(Math.floor(value*progressEl.dom.firstChild.offsetWidth));
15541 * Returns true if the message box is currently displayed
15542 * @return {Boolean} True if the message box is visible, else false
15544 isVisible : function(){
15545 return dlg && dlg.isVisible();
15549 * Hides the message box if it is displayed
15552 if(this.isVisible()){
15558 * Displays a new message box, or reinitializes an existing message box, based on the config options
15559 * passed in. All functions (e.g. prompt, alert, etc) on MessageBox call this function internally.
15560 * The following config object properties are supported:
15562 Property Type Description
15563 ---------- --------------- ------------------------------------------------------------------------------------
15564 animEl String/Element An id or Element from which the message box should animate as it opens and
15565 closes (defaults to undefined)
15566 buttons Object/Boolean A button config object (e.g., Roo.MessageBox.OKCANCEL or {ok:'Foo',
15567 cancel:'Bar'}), or false to not show any buttons (defaults to false)
15568 closable Boolean False to hide the top-right close button (defaults to true). Note that
15569 progress and wait dialogs will ignore this property and always hide the
15570 close button as they can only be closed programmatically.
15571 cls String A custom CSS class to apply to the message box element
15572 defaultTextHeight Number The default height in pixels of the message box's multiline textarea if
15573 displayed (defaults to 75)
15574 fn Function A callback function to execute after closing the dialog. The arguments to the
15575 function will be btn (the name of the button that was clicked, if applicable,
15576 e.g. "ok"), and text (the value of the active text field, if applicable).
15577 Progress and wait dialogs will ignore this option since they do not respond to
15578 user actions and can only be closed programmatically, so any required function
15579 should be called by the same code after it closes the dialog.
15580 icon String A CSS class that provides a background image to be used as an icon for
15581 the dialog (e.g., Roo.MessageBox.WARNING or 'custom-class', defaults to '')
15582 maxWidth Number The maximum width in pixels of the message box (defaults to 600)
15583 minWidth Number The minimum width in pixels of the message box (defaults to 100)
15584 modal Boolean False to allow user interaction with the page while the message box is
15585 displayed (defaults to true)
15586 msg String A string that will replace the existing message box body text (defaults
15587 to the XHTML-compliant non-breaking space character ' ')
15588 multiline Boolean True to prompt the user to enter multi-line text (defaults to false)
15589 progress Boolean True to display a progress bar (defaults to false)
15590 progressText String The text to display inside the progress bar if progress = true (defaults to '')
15591 prompt Boolean True to prompt the user to enter single-line text (defaults to false)
15592 proxyDrag Boolean True to display a lightweight proxy while dragging (defaults to false)
15593 title String The title text
15594 value String The string value to set into the active textbox element if displayed
15595 wait Boolean True to display a progress bar (defaults to false)
15596 width Number The width of the dialog in pixels
15603 msg: 'Please enter your address:',
15605 buttons: Roo.MessageBox.OKCANCEL,
15608 animEl: 'addAddressBtn'
15611 * @param {Object} config Configuration options
15612 * @return {Roo.MessageBox} This message box
15614 show : function(options){
15615 if(this.isVisible()){
15618 var d = this.getDialog();
15620 d.setTitle(opt.title || " ");
15621 d.close.setDisplayed(opt.closable !== false);
15622 activeTextEl = textboxEl;
15623 opt.prompt = opt.prompt || (opt.multiline ? true : false);
15628 textareaEl.setHeight(typeof opt.multiline == "number" ?
15629 opt.multiline : this.defaultTextHeight);
15630 activeTextEl = textareaEl;
15639 progressEl.setDisplayed(opt.progress === true);
15640 this.updateProgress(0);
15641 activeTextEl.dom.value = opt.value || "";
15643 dlg.setDefaultButton(activeTextEl);
15645 var bs = opt.buttons;
15648 db = buttons["ok"];
15649 }else if(bs && bs.yes){
15650 db = buttons["yes"];
15652 dlg.setDefaultButton(db);
15654 bwidth = updateButtons(opt.buttons);
15655 this.updateText(opt.msg);
15657 d.el.addClass(opt.cls);
15659 d.proxyDrag = opt.proxyDrag === true;
15660 d.modal = opt.modal !== false;
15661 d.mask = opt.modal !== false ? mask : false;
15662 if(!d.isVisible()){
15663 // force it to the end of the z-index stack so it gets a cursor in FF
15664 document.body.appendChild(dlg.el.dom);
15665 d.animateTarget = null;
15666 d.show(options.animEl);
15672 * Displays a message box with a progress bar. This message box has no buttons and is not closeable by
15673 * the user. You are responsible for updating the progress bar as needed via {@link Roo.MessageBox#updateProgress}
15674 * and closing the message box when the process is complete.
15675 * @param {String} title The title bar text
15676 * @param {String} msg The message box body text
15677 * @return {Roo.MessageBox} This message box
15679 progress : function(title, msg){
15686 minWidth: this.minProgressWidth,
15693 * Displays a standard read-only message box with an OK button (comparable to the basic JavaScript Window.alert).
15694 * If a callback function is passed it will be called after the user clicks the button, and the
15695 * id of the button that was clicked will be passed as the only parameter to the callback
15696 * (could also be the top-right close button).
15697 * @param {String} title The title bar text
15698 * @param {String} msg The message box body text
15699 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15700 * @param {Object} scope (optional) The scope of the callback function
15701 * @return {Roo.MessageBox} This message box
15703 alert : function(title, msg, fn, scope){
15716 * Displays a message box with an infinitely auto-updating progress bar. This can be used to block user
15717 * interaction while waiting for a long-running process to complete that does not have defined intervals.
15718 * You are responsible for closing the message box when the process is complete.
15719 * @param {String} msg The message box body text
15720 * @param {String} title (optional) The title bar text
15721 * @return {Roo.MessageBox} This message box
15723 wait : function(msg, title){
15734 waitTimer = Roo.TaskMgr.start({
15736 Roo.MessageBox.updateProgress(((((i+20)%20)+1)*5)*.01);
15744 * Displays a confirmation message box with Yes and No buttons (comparable to JavaScript's Window.confirm).
15745 * If a callback function is passed it will be called after the user clicks either button, and the id of the
15746 * button that was clicked will be passed as the only parameter to the callback (could also be the top-right close button).
15747 * @param {String} title The title bar text
15748 * @param {String} msg The message box body text
15749 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15750 * @param {Object} scope (optional) The scope of the callback function
15751 * @return {Roo.MessageBox} This message box
15753 confirm : function(title, msg, fn, scope){
15757 buttons: this.YESNO,
15766 * Displays a message box with OK and Cancel buttons prompting the user to enter some text (comparable to
15767 * JavaScript's Window.prompt). The prompt can be a single-line or multi-line textbox. If a callback function
15768 * is passed it will be called after the user clicks either button, and the id of the button that was clicked
15769 * (could also be the top-right close button) and the text that was entered will be passed as the two
15770 * parameters to the callback.
15771 * @param {String} title The title bar text
15772 * @param {String} msg The message box body text
15773 * @param {Function} fn (optional) The callback function invoked after the message box is closed
15774 * @param {Object} scope (optional) The scope of the callback function
15775 * @param {Boolean/Number} multiline (optional) True to create a multiline textbox using the defaultTextHeight
15776 * property, or the height in pixels to create the textbox (defaults to false / single-line)
15777 * @return {Roo.MessageBox} This message box
15779 prompt : function(title, msg, fn, scope, multiline){
15783 buttons: this.OKCANCEL,
15788 multiline: multiline,
15795 * Button config that displays a single OK button
15800 * Button config that displays Yes and No buttons
15803 YESNO : {yes:true, no:true},
15805 * Button config that displays OK and Cancel buttons
15808 OKCANCEL : {ok:true, cancel:true},
15810 * Button config that displays Yes, No and Cancel buttons
15813 YESNOCANCEL : {yes:true, no:true, cancel:true},
15816 * The default height in pixels of the message box's multiline textarea if displayed (defaults to 75)
15819 defaultTextHeight : 75,
15821 * The maximum width in pixels of the message box (defaults to 600)
15826 * The minimum width in pixels of the message box (defaults to 100)
15831 * The minimum width in pixels of the message box if it is a progress-style dialog. This is useful
15832 * for setting a different minimum width than text-only dialogs may need (defaults to 250)
15835 minProgressWidth : 250,
15837 * An object containing the default button text strings that can be overriden for localized language support.
15838 * Supported properties are: ok, cancel, yes and no.
15839 * Customize the default text like so: Roo.MessageBox.buttonText.yes = "S?";
15852 * Shorthand for {@link Roo.MessageBox}
15854 Roo.Msg = Roo.MessageBox;/*
15856 * Ext JS Library 1.1.1
15857 * Copyright(c) 2006-2007, Ext JS, LLC.
15859 * Originally Released Under LGPL - original licence link has changed is not relivant.
15862 * <script type="text/javascript">
15865 * @class Roo.QuickTips
15866 * Provides attractive and customizable tooltips for any element.
15869 Roo.QuickTips = function(){
15870 var el, tipBody, tipBodyText, tipTitle, tm, cfg, close, tagEls = {}, esc, removeCls = null, bdLeft, bdRight;
15871 var ce, bd, xy, dd;
15872 var visible = false, disabled = true, inited = false;
15873 var showProc = 1, hideProc = 1, dismissProc = 1, locks = [];
15875 var onOver = function(e){
15879 var t = e.getTarget();
15880 if(!t || t.nodeType !== 1 || t == document || t == document.body){
15883 if(ce && t == ce.el){
15884 clearTimeout(hideProc);
15887 if(t && tagEls[t.id]){
15888 tagEls[t.id].el = t;
15889 showProc = show.defer(tm.showDelay, tm, [tagEls[t.id]]);
15892 var ttp, et = Roo.fly(t);
15893 var ns = cfg.namespace;
15894 if(tm.interceptTitles && t.title){
15897 t.removeAttribute("title");
15898 e.preventDefault();
15900 ttp = t.qtip || et.getAttributeNS(ns, cfg.attribute);
15903 showProc = show.defer(tm.showDelay, tm, [{
15906 width: et.getAttributeNS(ns, cfg.width),
15907 autoHide: et.getAttributeNS(ns, cfg.hide) != "user",
15908 title: et.getAttributeNS(ns, cfg.title),
15909 cls: et.getAttributeNS(ns, cfg.cls)
15914 var onOut = function(e){
15915 clearTimeout(showProc);
15916 var t = e.getTarget();
15917 if(t && ce && ce.el == t && (tm.autoHide && ce.autoHide !== false)){
15918 hideProc = setTimeout(hide, tm.hideDelay);
15922 var onMove = function(e){
15928 if(tm.trackMouse && ce){
15933 var onDown = function(e){
15934 clearTimeout(showProc);
15935 clearTimeout(hideProc);
15937 if(tm.hideOnClick){
15940 tm.enable.defer(100, tm);
15945 var getPad = function(){
15946 return 2;//bdLeft.getPadding('l')+bdRight.getPadding('r');
15949 var show = function(o){
15953 clearTimeout(dismissProc);
15955 if(removeCls){ // in case manually hidden
15956 el.removeClass(removeCls);
15960 el.addClass(ce.cls);
15961 removeCls = ce.cls;
15964 tipTitle.update(ce.title);
15967 tipTitle.update('');
15970 el.dom.style.width = tm.maxWidth+'px';
15971 //tipBody.dom.style.width = '';
15972 tipBodyText.update(o.text);
15973 var p = getPad(), w = ce.width;
15975 var td = tipBodyText.dom;
15976 var aw = Math.max(td.offsetWidth, td.clientWidth, td.scrollWidth);
15977 if(aw > tm.maxWidth){
15979 }else if(aw < tm.minWidth){
15985 //tipBody.setWidth(w);
15986 el.setWidth(parseInt(w, 10) + p);
15987 if(ce.autoHide === false){
15988 close.setDisplayed(true);
15993 close.setDisplayed(false);
15999 el.avoidY = xy[1]-18;
16004 el.setStyle("visibility", "visible");
16005 el.fadeIn({callback: afterShow});
16011 var afterShow = function(){
16015 if(tm.autoDismiss && ce.autoHide !== false){
16016 dismissProc = setTimeout(hide, tm.autoDismissDelay);
16021 var hide = function(noanim){
16022 clearTimeout(dismissProc);
16023 clearTimeout(hideProc);
16025 if(el.isVisible()){
16027 if(noanim !== true && tm.animate){
16028 el.fadeOut({callback: afterHide});
16035 var afterHide = function(){
16038 el.removeClass(removeCls);
16045 * @cfg {Number} minWidth
16046 * The minimum width of the quick tip (defaults to 40)
16050 * @cfg {Number} maxWidth
16051 * The maximum width of the quick tip (defaults to 300)
16055 * @cfg {Boolean} interceptTitles
16056 * True to automatically use the element's DOM title value if available (defaults to false)
16058 interceptTitles : false,
16060 * @cfg {Boolean} trackMouse
16061 * True to have the quick tip follow the mouse as it moves over the target element (defaults to false)
16063 trackMouse : false,
16065 * @cfg {Boolean} hideOnClick
16066 * True to hide the quick tip if the user clicks anywhere in the document (defaults to true)
16068 hideOnClick : true,
16070 * @cfg {Number} showDelay
16071 * Delay in milliseconds before the quick tip displays after the mouse enters the target element (defaults to 500)
16075 * @cfg {Number} hideDelay
16076 * Delay in milliseconds before the quick tip hides when autoHide = true (defaults to 200)
16080 * @cfg {Boolean} autoHide
16081 * True to automatically hide the quick tip after the mouse exits the target element (defaults to true).
16082 * Used in conjunction with hideDelay.
16087 * True to automatically hide the quick tip after a set period of time, regardless of the user's actions
16088 * (defaults to true). Used in conjunction with autoDismissDelay.
16090 autoDismiss : true,
16093 * Delay in milliseconds before the quick tip hides when autoDismiss = true (defaults to 5000)
16095 autoDismissDelay : 5000,
16097 * @cfg {Boolean} animate
16098 * True to turn on fade animation. Defaults to false (ClearType/scrollbar flicker issues in IE7).
16103 * @cfg {String} title
16104 * Title text to display (defaults to ''). This can be any valid HTML markup.
16108 * @cfg {String} text
16109 * Body text to display (defaults to ''). This can be any valid HTML markup.
16113 * @cfg {String} cls
16114 * A CSS class to apply to the base quick tip element (defaults to '').
16118 * @cfg {Number} width
16119 * Width in pixels of the quick tip (defaults to auto). Width will be ignored if it exceeds the bounds of
16120 * minWidth or maxWidth.
16125 * Initialize and enable QuickTips for first use. This should be called once before the first attempt to access
16126 * or display QuickTips in a page.
16129 tm = Roo.QuickTips;
16130 cfg = tm.tagConfig;
16132 if(!Roo.isReady){ // allow calling of init() before onReady
16133 Roo.onReady(Roo.QuickTips.init, Roo.QuickTips);
16136 el = new Roo.Layer({cls:"x-tip", shadow:"drop", shim: true, constrain:true, shadowOffset:4});
16137 el.fxDefaults = {stopFx: true};
16138 // maximum custom styling
16139 //el.update('<div class="x-tip-top-left"><div class="x-tip-top-right"><div class="x-tip-top"></div></div></div><div class="x-tip-bd-left"><div class="x-tip-bd-right"><div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div></div></div><div class="x-tip-ft-left"><div class="x-tip-ft-right"><div class="x-tip-ft"></div></div></div>');
16140 el.update('<div class="x-tip-bd"><div class="x-tip-close"></div><h3></h3><div class="x-tip-bd-inner"></div><div class="x-clear"></div></div>');
16141 tipTitle = el.child('h3');
16142 tipTitle.enableDisplayMode("block");
16143 tipBody = el.child('div.x-tip-bd');
16144 tipBodyText = el.child('div.x-tip-bd-inner');
16145 //bdLeft = el.child('div.x-tip-bd-left');
16146 //bdRight = el.child('div.x-tip-bd-right');
16147 close = el.child('div.x-tip-close');
16148 close.enableDisplayMode("block");
16149 close.on("click", hide);
16150 var d = Roo.get(document);
16151 d.on("mousedown", onDown);
16152 d.on("mouseover", onOver);
16153 d.on("mouseout", onOut);
16154 d.on("mousemove", onMove);
16155 esc = d.addKeyListener(27, hide);
16158 dd = el.initDD("default", null, {
16159 onDrag : function(){
16163 dd.setHandleElId(tipTitle.id);
16172 * Configures a new quick tip instance and assigns it to a target element. The following config options
16175 Property Type Description
16176 ---------- --------------------- ------------------------------------------------------------------------
16177 target Element/String/Array An Element, id or array of ids that this quick tip should be tied to
16179 * @param {Object} config The config object
16181 register : function(config){
16182 var cs = config instanceof Array ? config : arguments;
16183 for(var i = 0, len = cs.length; i < len; i++) {
16185 var target = c.target;
16187 if(target instanceof Array){
16188 for(var j = 0, jlen = target.length; j < jlen; j++){
16189 tagEls[target[j]] = c;
16192 tagEls[typeof target == 'string' ? target : Roo.id(target)] = c;
16199 * Removes this quick tip from its element and destroys it.
16200 * @param {String/HTMLElement/Element} el The element from which the quick tip is to be removed.
16202 unregister : function(el){
16203 delete tagEls[Roo.id(el)];
16207 * Enable this quick tip.
16209 enable : function(){
16210 if(inited && disabled){
16212 if(locks.length < 1){
16219 * Disable this quick tip.
16221 disable : function(){
16223 clearTimeout(showProc);
16224 clearTimeout(hideProc);
16225 clearTimeout(dismissProc);
16233 * Returns true if the quick tip is enabled, else false.
16235 isEnabled : function(){
16242 attribute : "qtip",
16252 // backwards compat
16253 Roo.QuickTips.tips = Roo.QuickTips.register;/*
16255 * Ext JS Library 1.1.1
16256 * Copyright(c) 2006-2007, Ext JS, LLC.
16258 * Originally Released Under LGPL - original licence link has changed is not relivant.
16261 * <script type="text/javascript">
16266 * @class Roo.tree.TreePanel
16267 * @extends Roo.data.Tree
16269 * @cfg {Boolean} rootVisible false to hide the root node (defaults to true)
16270 * @cfg {Boolean} lines false to disable tree lines (defaults to true)
16271 * @cfg {Boolean} enableDD true to enable drag and drop
16272 * @cfg {Boolean} enableDrag true to enable just drag
16273 * @cfg {Boolean} enableDrop true to enable just drop
16274 * @cfg {Object} dragConfig Custom config to pass to the {@link Roo.tree.TreeDragZone} instance
16275 * @cfg {Object} dropConfig Custom config to pass to the {@link Roo.tree.TreeDropZone} instance
16276 * @cfg {String} ddGroup The DD group this TreePanel belongs to
16277 * @cfg {String} ddAppendOnly True if the tree should only allow append drops (use for trees which are sorted)
16278 * @cfg {Boolean} ddScroll true to enable YUI body scrolling
16279 * @cfg {Boolean} containerScroll true to register this container with ScrollManager
16280 * @cfg {Boolean} hlDrop false to disable node highlight on drop (defaults to the value of Roo.enableFx)
16281 * @cfg {String} hlColor The color of the node highlight (defaults to C3DAF9)
16282 * @cfg {Boolean} animate true to enable animated expand/collapse (defaults to the value of Roo.enableFx)
16283 * @cfg {Boolean} singleExpand true if only 1 node per branch may be expanded
16284 * @cfg {Boolean} selModel A tree selection model to use with this TreePanel (defaults to a {@link Roo.tree.DefaultSelectionModel})
16285 * @cfg {Boolean} loader A TreeLoader for use with this TreePanel
16286 * @cfg {String} pathSeparator The token used to separate sub-paths in path strings (defaults to '/')
16287 * @cfg {Function} renderer Sets the rendering (formatting) function for the nodes. to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16288 * @cfg {Function} rendererTip Sets the rendering (formatting) function for the nodes hovertip to return HTML markup for the tree view. The render function is called with the following parameters:<ul><li>The {Object} The data for the node.</li></ul>
16291 * @param {String/HTMLElement/Element} el The container element
16292 * @param {Object} config
16294 Roo.tree.TreePanel = function(el, config){
16296 var loader = false;
16298 root = config.root;
16299 delete config.root;
16301 if (config.loader) {
16302 loader = config.loader;
16303 delete config.loader;
16306 Roo.apply(this, config);
16307 Roo.tree.TreePanel.superclass.constructor.call(this);
16308 this.el = Roo.get(el);
16309 this.el.addClass('x-tree');
16310 //console.log(root);
16312 this.setRootNode( Roo.factory(root, Roo.tree));
16315 this.loader = Roo.factory(loader, Roo.tree);
16318 * Read-only. The id of the container element becomes this TreePanel's id.
16320 this.id = this.el.id;
16323 * @event beforeload
16324 * Fires before a node is loaded, return false to cancel
16325 * @param {Node} node The node being loaded
16327 "beforeload" : true,
16330 * Fires when a node is loaded
16331 * @param {Node} node The node that was loaded
16335 * @event textchange
16336 * Fires when the text for a node is changed
16337 * @param {Node} node The node
16338 * @param {String} text The new text
16339 * @param {String} oldText The old text
16341 "textchange" : true,
16343 * @event beforeexpand
16344 * Fires before a node is expanded, return false to cancel.
16345 * @param {Node} node The node
16346 * @param {Boolean} deep
16347 * @param {Boolean} anim
16349 "beforeexpand" : true,
16351 * @event beforecollapse
16352 * Fires before a node is collapsed, return false to cancel.
16353 * @param {Node} node The node
16354 * @param {Boolean} deep
16355 * @param {Boolean} anim
16357 "beforecollapse" : true,
16360 * Fires when a node is expanded
16361 * @param {Node} node The node
16365 * @event disabledchange
16366 * Fires when the disabled status of a node changes
16367 * @param {Node} node The node
16368 * @param {Boolean} disabled
16370 "disabledchange" : true,
16373 * Fires when a node is collapsed
16374 * @param {Node} node The node
16378 * @event beforeclick
16379 * Fires before click processing on a node. Return false to cancel the default action.
16380 * @param {Node} node The node
16381 * @param {Roo.EventObject} e The event object
16383 "beforeclick":true,
16385 * @event checkchange
16386 * Fires when a node with a checkbox's checked property changes
16387 * @param {Node} this This node
16388 * @param {Boolean} checked
16390 "checkchange":true,
16393 * Fires when a node is clicked
16394 * @param {Node} node The node
16395 * @param {Roo.EventObject} e The event object
16400 * Fires when a node is double clicked
16401 * @param {Node} node The node
16402 * @param {Roo.EventObject} e The event object
16406 * @event contextmenu
16407 * Fires when a node is right clicked
16408 * @param {Node} node The node
16409 * @param {Roo.EventObject} e The event object
16411 "contextmenu":true,
16413 * @event beforechildrenrendered
16414 * Fires right before the child nodes for a node are rendered
16415 * @param {Node} node The node
16417 "beforechildrenrendered":true,
16420 * Fires when a node starts being dragged
16421 * @param {Roo.tree.TreePanel} this
16422 * @param {Roo.tree.TreeNode} node
16423 * @param {event} e The raw browser event
16425 "startdrag" : true,
16428 * Fires when a drag operation is complete
16429 * @param {Roo.tree.TreePanel} this
16430 * @param {Roo.tree.TreeNode} node
16431 * @param {event} e The raw browser event
16436 * Fires when a dragged node is dropped on a valid DD target
16437 * @param {Roo.tree.TreePanel} this
16438 * @param {Roo.tree.TreeNode} node
16439 * @param {DD} dd The dd it was dropped on
16440 * @param {event} e The raw browser event
16444 * @event beforenodedrop
16445 * Fires when a DD object is dropped on a node in this tree for preprocessing. Return false to cancel the drop. The dropEvent
16446 * passed to handlers has the following properties:<br />
16447 * <ul style="padding:5px;padding-left:16px;">
16448 * <li>tree - The TreePanel</li>
16449 * <li>target - The node being targeted for the drop</li>
16450 * <li>data - The drag data from the drag source</li>
16451 * <li>point - The point of the drop - append, above or below</li>
16452 * <li>source - The drag source</li>
16453 * <li>rawEvent - Raw mouse event</li>
16454 * <li>dropNode - Drop node(s) provided by the source <b>OR</b> you can supply node(s)
16455 * to be inserted by setting them on this object.</li>
16456 * <li>cancel - Set this to true to cancel the drop.</li>
16458 * @param {Object} dropEvent
16460 "beforenodedrop" : true,
16463 * Fires after a DD object is dropped on a node in this tree. The dropEvent
16464 * passed to handlers has the following properties:<br />
16465 * <ul style="padding:5px;padding-left:16px;">
16466 * <li>tree - The TreePanel</li>
16467 * <li>target - The node being targeted for the drop</li>
16468 * <li>data - The drag data from the drag source</li>
16469 * <li>point - The point of the drop - append, above or below</li>
16470 * <li>source - The drag source</li>
16471 * <li>rawEvent - Raw mouse event</li>
16472 * <li>dropNode - Dropped node(s).</li>
16474 * @param {Object} dropEvent
16478 * @event nodedragover
16479 * Fires when a tree node is being targeted for a drag drop, return false to signal drop not allowed. The dragOverEvent
16480 * passed to handlers has the following properties:<br />
16481 * <ul style="padding:5px;padding-left:16px;">
16482 * <li>tree - The TreePanel</li>
16483 * <li>target - The node being targeted for the drop</li>
16484 * <li>data - The drag data from the drag source</li>
16485 * <li>point - The point of the drop - append, above or below</li>
16486 * <li>source - The drag source</li>
16487 * <li>rawEvent - Raw mouse event</li>
16488 * <li>dropNode - Drop node(s) provided by the source.</li>
16489 * <li>cancel - Set this to true to signal drop not allowed.</li>
16491 * @param {Object} dragOverEvent
16493 "nodedragover" : true
16496 if(this.singleExpand){
16497 this.on("beforeexpand", this.restrictExpand, this);
16500 Roo.extend(Roo.tree.TreePanel, Roo.data.Tree, {
16501 rootVisible : true,
16502 animate: Roo.enableFx,
16505 hlDrop : Roo.enableFx,
16509 rendererTip: false,
16511 restrictExpand : function(node){
16512 var p = node.parentNode;
16514 if(p.expandedChild && p.expandedChild.parentNode == p){
16515 p.expandedChild.collapse();
16517 p.expandedChild = node;
16521 // private override
16522 setRootNode : function(node){
16523 Roo.tree.TreePanel.superclass.setRootNode.call(this, node);
16524 if(!this.rootVisible){
16525 node.ui = new Roo.tree.RootTreeNodeUI(node);
16531 * Returns the container element for this TreePanel
16533 getEl : function(){
16538 * Returns the default TreeLoader for this TreePanel
16540 getLoader : function(){
16541 return this.loader;
16547 expandAll : function(){
16548 this.root.expand(true);
16552 * Collapse all nodes
16554 collapseAll : function(){
16555 this.root.collapse(true);
16559 * Returns the selection model used by this TreePanel
16561 getSelectionModel : function(){
16562 if(!this.selModel){
16563 this.selModel = new Roo.tree.DefaultSelectionModel();
16565 return this.selModel;
16569 * Retrieve an array of checked nodes, or an array of a specific attribute of checked nodes (e.g. "id")
16570 * @param {String} attribute (optional) Defaults to null (return the actual nodes)
16571 * @param {TreeNode} startNode (optional) The node to start from, defaults to the root
16574 getChecked : function(a, startNode){
16575 startNode = startNode || this.root;
16577 var f = function(){
16578 if(this.attributes.checked){
16579 r.push(!a ? this : (a == 'id' ? this.id : this.attributes[a]));
16582 startNode.cascade(f);
16587 * Expands a specified path in this TreePanel. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16588 * @param {String} path
16589 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16590 * @param {Function} callback (optional) The callback to call when the expand is complete. The callback will be called with
16591 * (bSuccess, oLastNode) where bSuccess is if the expand was successful and oLastNode is the last node that was expanded.
16593 expandPath : function(path, attr, callback){
16594 attr = attr || "id";
16595 var keys = path.split(this.pathSeparator);
16596 var curNode = this.root;
16597 if(curNode.attributes[attr] != keys[1]){ // invalid root
16599 callback(false, null);
16604 var f = function(){
16605 if(++index == keys.length){
16607 callback(true, curNode);
16611 var c = curNode.findChild(attr, keys[index]);
16614 callback(false, curNode);
16619 c.expand(false, false, f);
16621 curNode.expand(false, false, f);
16625 * Selects the node in this tree at the specified path. A path can be retrieved from a node with {@link Roo.data.Node#getPath}
16626 * @param {String} path
16627 * @param {String} attr (optional) The attribute used in the path (see {@link Roo.data.Node#getPath} for more info)
16628 * @param {Function} callback (optional) The callback to call when the selection is complete. The callback will be called with
16629 * (bSuccess, oSelNode) where bSuccess is if the selection was successful and oSelNode is the selected node.
16631 selectPath : function(path, attr, callback){
16632 attr = attr || "id";
16633 var keys = path.split(this.pathSeparator);
16634 var v = keys.pop();
16635 if(keys.length > 0){
16636 var f = function(success, node){
16637 if(success && node){
16638 var n = node.findChild(attr, v);
16644 }else if(callback){
16645 callback(false, n);
16649 callback(false, n);
16653 this.expandPath(keys.join(this.pathSeparator), attr, f);
16655 this.root.select();
16657 callback(true, this.root);
16662 getTreeEl : function(){
16667 * Trigger rendering of this TreePanel
16669 render : function(){
16670 if (this.innerCt) {
16671 return this; // stop it rendering more than once!!
16674 this.innerCt = this.el.createChild({tag:"ul",
16675 cls:"x-tree-root-ct " +
16676 (this.lines ? "x-tree-lines" : "x-tree-no-lines")});
16678 if(this.containerScroll){
16679 Roo.dd.ScrollManager.register(this.el);
16681 if((this.enableDD || this.enableDrop) && !this.dropZone){
16683 * The dropZone used by this tree if drop is enabled
16684 * @type Roo.tree.TreeDropZone
16686 this.dropZone = new Roo.tree.TreeDropZone(this, this.dropConfig || {
16687 ddGroup: this.ddGroup || "TreeDD", appendOnly: this.ddAppendOnly === true
16690 if((this.enableDD || this.enableDrag) && !this.dragZone){
16692 * The dragZone used by this tree if drag is enabled
16693 * @type Roo.tree.TreeDragZone
16695 this.dragZone = new Roo.tree.TreeDragZone(this, this.dragConfig || {
16696 ddGroup: this.ddGroup || "TreeDD",
16697 scroll: this.ddScroll
16700 this.getSelectionModel().init(this);
16702 console.log("ROOT not set in tree");
16705 this.root.render();
16706 if(!this.rootVisible){
16707 this.root.renderChildren();
16713 * Ext JS Library 1.1.1
16714 * Copyright(c) 2006-2007, Ext JS, LLC.
16716 * Originally Released Under LGPL - original licence link has changed is not relivant.
16719 * <script type="text/javascript">
16724 * @class Roo.tree.DefaultSelectionModel
16725 * @extends Roo.util.Observable
16726 * The default single selection for a TreePanel.
16728 Roo.tree.DefaultSelectionModel = function(){
16729 this.selNode = null;
16733 * @event selectionchange
16734 * Fires when the selected node changes
16735 * @param {DefaultSelectionModel} this
16736 * @param {TreeNode} node the new selection
16738 "selectionchange" : true,
16741 * @event beforeselect
16742 * Fires before the selected node changes, return false to cancel the change
16743 * @param {DefaultSelectionModel} this
16744 * @param {TreeNode} node the new selection
16745 * @param {TreeNode} node the old selection
16747 "beforeselect" : true
16751 Roo.extend(Roo.tree.DefaultSelectionModel, Roo.util.Observable, {
16752 init : function(tree){
16754 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16755 tree.on("click", this.onNodeClick, this);
16758 onNodeClick : function(node, e){
16759 if (e.ctrlKey && this.selNode == node) {
16760 this.unselect(node);
16768 * @param {TreeNode} node The node to select
16769 * @return {TreeNode} The selected node
16771 select : function(node){
16772 var last = this.selNode;
16773 if(last != node && this.fireEvent('beforeselect', this, node, last) !== false){
16775 last.ui.onSelectedChange(false);
16777 this.selNode = node;
16778 node.ui.onSelectedChange(true);
16779 this.fireEvent("selectionchange", this, node, last);
16786 * @param {TreeNode} node The node to unselect
16788 unselect : function(node){
16789 if(this.selNode == node){
16790 this.clearSelections();
16795 * Clear all selections
16797 clearSelections : function(){
16798 var n = this.selNode;
16800 n.ui.onSelectedChange(false);
16801 this.selNode = null;
16802 this.fireEvent("selectionchange", this, null);
16808 * Get the selected node
16809 * @return {TreeNode} The selected node
16811 getSelectedNode : function(){
16812 return this.selNode;
16816 * Returns true if the node is selected
16817 * @param {TreeNode} node The node to check
16818 * @return {Boolean}
16820 isSelected : function(node){
16821 return this.selNode == node;
16825 * Selects the node above the selected node in the tree, intelligently walking the nodes
16826 * @return TreeNode The new selection
16828 selectPrevious : function(){
16829 var s = this.selNode || this.lastSelNode;
16833 var ps = s.previousSibling;
16835 if(!ps.isExpanded() || ps.childNodes.length < 1){
16836 return this.select(ps);
16838 var lc = ps.lastChild;
16839 while(lc && lc.isExpanded() && lc.childNodes.length > 0){
16842 return this.select(lc);
16844 } else if(s.parentNode && (this.tree.rootVisible || !s.parentNode.isRoot)){
16845 return this.select(s.parentNode);
16851 * Selects the node above the selected node in the tree, intelligently walking the nodes
16852 * @return TreeNode The new selection
16854 selectNext : function(){
16855 var s = this.selNode || this.lastSelNode;
16859 if(s.firstChild && s.isExpanded()){
16860 return this.select(s.firstChild);
16861 }else if(s.nextSibling){
16862 return this.select(s.nextSibling);
16863 }else if(s.parentNode){
16865 s.parentNode.bubble(function(){
16866 if(this.nextSibling){
16867 newS = this.getOwnerTree().selModel.select(this.nextSibling);
16876 onKeyDown : function(e){
16877 var s = this.selNode || this.lastSelNode;
16878 // undesirable, but required
16883 var k = e.getKey();
16891 this.selectPrevious();
16894 e.preventDefault();
16895 if(s.hasChildNodes()){
16896 if(!s.isExpanded()){
16898 }else if(s.firstChild){
16899 this.select(s.firstChild, e);
16904 e.preventDefault();
16905 if(s.hasChildNodes() && s.isExpanded()){
16907 }else if(s.parentNode && (this.tree.rootVisible || s.parentNode != this.tree.getRootNode())){
16908 this.select(s.parentNode, e);
16916 * @class Roo.tree.MultiSelectionModel
16917 * @extends Roo.util.Observable
16918 * Multi selection for a TreePanel.
16920 Roo.tree.MultiSelectionModel = function(){
16921 this.selNodes = [];
16925 * @event selectionchange
16926 * Fires when the selected nodes change
16927 * @param {MultiSelectionModel} this
16928 * @param {Array} nodes Array of the selected nodes
16930 "selectionchange" : true
16934 Roo.extend(Roo.tree.MultiSelectionModel, Roo.util.Observable, {
16935 init : function(tree){
16937 tree.getTreeEl().on("keydown", this.onKeyDown, this);
16938 tree.on("click", this.onNodeClick, this);
16941 onNodeClick : function(node, e){
16942 this.select(node, e, e.ctrlKey);
16947 * @param {TreeNode} node The node to select
16948 * @param {EventObject} e (optional) An event associated with the selection
16949 * @param {Boolean} keepExisting True to retain existing selections
16950 * @return {TreeNode} The selected node
16952 select : function(node, e, keepExisting){
16953 if(keepExisting !== true){
16954 this.clearSelections(true);
16956 if(this.isSelected(node)){
16957 this.lastSelNode = node;
16960 this.selNodes.push(node);
16961 this.selMap[node.id] = node;
16962 this.lastSelNode = node;
16963 node.ui.onSelectedChange(true);
16964 this.fireEvent("selectionchange", this, this.selNodes);
16970 * @param {TreeNode} node The node to unselect
16972 unselect : function(node){
16973 if(this.selMap[node.id]){
16974 node.ui.onSelectedChange(false);
16975 var sn = this.selNodes;
16978 index = sn.indexOf(node);
16980 for(var i = 0, len = sn.length; i < len; i++){
16988 this.selNodes.splice(index, 1);
16990 delete this.selMap[node.id];
16991 this.fireEvent("selectionchange", this, this.selNodes);
16996 * Clear all selections
16998 clearSelections : function(suppressEvent){
16999 var sn = this.selNodes;
17001 for(var i = 0, len = sn.length; i < len; i++){
17002 sn[i].ui.onSelectedChange(false);
17004 this.selNodes = [];
17006 if(suppressEvent !== true){
17007 this.fireEvent("selectionchange", this, this.selNodes);
17013 * Returns true if the node is selected
17014 * @param {TreeNode} node The node to check
17015 * @return {Boolean}
17017 isSelected : function(node){
17018 return this.selMap[node.id] ? true : false;
17022 * Returns an array of the selected nodes
17025 getSelectedNodes : function(){
17026 return this.selNodes;
17029 onKeyDown : Roo.tree.DefaultSelectionModel.prototype.onKeyDown,
17031 selectNext : Roo.tree.DefaultSelectionModel.prototype.selectNext,
17033 selectPrevious : Roo.tree.DefaultSelectionModel.prototype.selectPrevious
17036 * Ext JS Library 1.1.1
17037 * Copyright(c) 2006-2007, Ext JS, LLC.
17039 * Originally Released Under LGPL - original licence link has changed is not relivant.
17042 * <script type="text/javascript">
17046 * @class Roo.tree.TreeNode
17047 * @extends Roo.data.Node
17048 * @cfg {String} text The text for this node
17049 * @cfg {Boolean} expanded true to start the node expanded
17050 * @cfg {Boolean} allowDrag false to make this node undraggable if DD is on (defaults to true)
17051 * @cfg {Boolean} allowDrop false if this node cannot be drop on
17052 * @cfg {Boolean} disabled true to start the node disabled
17053 * @cfg {String} icon The path to an icon for the node. The preferred way to do this
17054 * is to use the cls or iconCls attributes and add the icon via a CSS background image.
17055 * @cfg {String} cls A css class to be added to the node
17056 * @cfg {String} iconCls A css class to be added to the nodes icon element for applying css background images
17057 * @cfg {String} href URL of the link used for the node (defaults to #)
17058 * @cfg {String} hrefTarget target frame for the link
17059 * @cfg {String} qtip An Ext QuickTip for the node
17060 * @cfg {String} qtipCfg An Ext QuickTip config for the node (used instead of qtip)
17061 * @cfg {Boolean} singleClickExpand True for single click expand on this node
17062 * @cfg {Function} uiProvider A UI <b>class</b> to use for this node (defaults to Roo.tree.TreeNodeUI)
17063 * @cfg {Boolean} checked True to render a checked checkbox for this node, false to render an unchecked checkbox
17064 * (defaults to undefined with no checkbox rendered)
17066 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17068 Roo.tree.TreeNode = function(attributes){
17069 attributes = attributes || {};
17070 if(typeof attributes == "string"){
17071 attributes = {text: attributes};
17073 this.childrenRendered = false;
17074 this.rendered = false;
17075 Roo.tree.TreeNode.superclass.constructor.call(this, attributes);
17076 this.expanded = attributes.expanded === true;
17077 this.isTarget = attributes.isTarget !== false;
17078 this.draggable = attributes.draggable !== false && attributes.allowDrag !== false;
17079 this.allowChildren = attributes.allowChildren !== false && attributes.allowDrop !== false;
17082 * Read-only. The text for this node. To change it use setText().
17085 this.text = attributes.text;
17087 * True if this node is disabled.
17090 this.disabled = attributes.disabled === true;
17094 * @event textchange
17095 * Fires when the text for this node is changed
17096 * @param {Node} this This node
17097 * @param {String} text The new text
17098 * @param {String} oldText The old text
17100 "textchange" : true,
17102 * @event beforeexpand
17103 * Fires before this node is expanded, return false to cancel.
17104 * @param {Node} this This node
17105 * @param {Boolean} deep
17106 * @param {Boolean} anim
17108 "beforeexpand" : true,
17110 * @event beforecollapse
17111 * Fires before this node is collapsed, return false to cancel.
17112 * @param {Node} this This node
17113 * @param {Boolean} deep
17114 * @param {Boolean} anim
17116 "beforecollapse" : true,
17119 * Fires when this node is expanded
17120 * @param {Node} this This node
17124 * @event disabledchange
17125 * Fires when the disabled status of this node changes
17126 * @param {Node} this This node
17127 * @param {Boolean} disabled
17129 "disabledchange" : true,
17132 * Fires when this node is collapsed
17133 * @param {Node} this This node
17137 * @event beforeclick
17138 * Fires before click processing. Return false to cancel the default action.
17139 * @param {Node} this This node
17140 * @param {Roo.EventObject} e The event object
17142 "beforeclick":true,
17144 * @event checkchange
17145 * Fires when a node with a checkbox's checked property changes
17146 * @param {Node} this This node
17147 * @param {Boolean} checked
17149 "checkchange":true,
17152 * Fires when this node is clicked
17153 * @param {Node} this This node
17154 * @param {Roo.EventObject} e The event object
17159 * Fires when this node is double clicked
17160 * @param {Node} this This node
17161 * @param {Roo.EventObject} e The event object
17165 * @event contextmenu
17166 * Fires when this node is right clicked
17167 * @param {Node} this This node
17168 * @param {Roo.EventObject} e The event object
17170 "contextmenu":true,
17172 * @event beforechildrenrendered
17173 * Fires right before the child nodes for this node are rendered
17174 * @param {Node} this This node
17176 "beforechildrenrendered":true
17179 var uiClass = this.attributes.uiProvider || Roo.tree.TreeNodeUI;
17182 * Read-only. The UI for this node
17185 this.ui = new uiClass(this);
17187 Roo.extend(Roo.tree.TreeNode, Roo.data.Node, {
17188 preventHScroll: true,
17190 * Returns true if this node is expanded
17191 * @return {Boolean}
17193 isExpanded : function(){
17194 return this.expanded;
17198 * Returns the UI object for this node
17199 * @return {TreeNodeUI}
17201 getUI : function(){
17205 // private override
17206 setFirstChild : function(node){
17207 var of = this.firstChild;
17208 Roo.tree.TreeNode.superclass.setFirstChild.call(this, node);
17209 if(this.childrenRendered && of && node != of){
17210 of.renderIndent(true, true);
17213 this.renderIndent(true, true);
17217 // private override
17218 setLastChild : function(node){
17219 var ol = this.lastChild;
17220 Roo.tree.TreeNode.superclass.setLastChild.call(this, node);
17221 if(this.childrenRendered && ol && node != ol){
17222 ol.renderIndent(true, true);
17225 this.renderIndent(true, true);
17229 // these methods are overridden to provide lazy rendering support
17230 // private override
17231 appendChild : function(){
17232 var node = Roo.tree.TreeNode.superclass.appendChild.apply(this, arguments);
17233 if(node && this.childrenRendered){
17236 this.ui.updateExpandIcon();
17240 // private override
17241 removeChild : function(node){
17242 this.ownerTree.getSelectionModel().unselect(node);
17243 Roo.tree.TreeNode.superclass.removeChild.apply(this, arguments);
17244 // if it's been rendered remove dom node
17245 if(this.childrenRendered){
17248 if(this.childNodes.length < 1){
17249 this.collapse(false, false);
17251 this.ui.updateExpandIcon();
17253 if(!this.firstChild) {
17254 this.childrenRendered = false;
17259 // private override
17260 insertBefore : function(node, refNode){
17261 var newNode = Roo.tree.TreeNode.superclass.insertBefore.apply(this, arguments);
17262 if(newNode && refNode && this.childrenRendered){
17265 this.ui.updateExpandIcon();
17270 * Sets the text for this node
17271 * @param {String} text
17273 setText : function(text){
17274 var oldText = this.text;
17276 this.attributes.text = text;
17277 if(this.rendered){ // event without subscribing
17278 this.ui.onTextChange(this, text, oldText);
17280 this.fireEvent("textchange", this, text, oldText);
17284 * Triggers selection of this node
17286 select : function(){
17287 this.getOwnerTree().getSelectionModel().select(this);
17291 * Triggers deselection of this node
17293 unselect : function(){
17294 this.getOwnerTree().getSelectionModel().unselect(this);
17298 * Returns true if this node is selected
17299 * @return {Boolean}
17301 isSelected : function(){
17302 return this.getOwnerTree().getSelectionModel().isSelected(this);
17306 * Expand this node.
17307 * @param {Boolean} deep (optional) True to expand all children as well
17308 * @param {Boolean} anim (optional) false to cancel the default animation
17309 * @param {Function} callback (optional) A callback to be called when
17310 * expanding this node completes (does not wait for deep expand to complete).
17311 * Called with 1 parameter, this node.
17313 expand : function(deep, anim, callback){
17314 if(!this.expanded){
17315 if(this.fireEvent("beforeexpand", this, deep, anim) === false){
17318 if(!this.childrenRendered){
17319 this.renderChildren();
17321 this.expanded = true;
17322 if(!this.isHiddenRoot() && (this.getOwnerTree().animate && anim !== false) || anim){
17323 this.ui.animExpand(function(){
17324 this.fireEvent("expand", this);
17325 if(typeof callback == "function"){
17329 this.expandChildNodes(true);
17331 }.createDelegate(this));
17335 this.fireEvent("expand", this);
17336 if(typeof callback == "function"){
17341 if(typeof callback == "function"){
17346 this.expandChildNodes(true);
17350 isHiddenRoot : function(){
17351 return this.isRoot && !this.getOwnerTree().rootVisible;
17355 * Collapse this node.
17356 * @param {Boolean} deep (optional) True to collapse all children as well
17357 * @param {Boolean} anim (optional) false to cancel the default animation
17359 collapse : function(deep, anim){
17360 if(this.expanded && !this.isHiddenRoot()){
17361 if(this.fireEvent("beforecollapse", this, deep, anim) === false){
17364 this.expanded = false;
17365 if((this.getOwnerTree().animate && anim !== false) || anim){
17366 this.ui.animCollapse(function(){
17367 this.fireEvent("collapse", this);
17369 this.collapseChildNodes(true);
17371 }.createDelegate(this));
17374 this.ui.collapse();
17375 this.fireEvent("collapse", this);
17379 var cs = this.childNodes;
17380 for(var i = 0, len = cs.length; i < len; i++) {
17381 cs[i].collapse(true, false);
17387 delayedExpand : function(delay){
17388 if(!this.expandProcId){
17389 this.expandProcId = this.expand.defer(delay, this);
17394 cancelExpand : function(){
17395 if(this.expandProcId){
17396 clearTimeout(this.expandProcId);
17398 this.expandProcId = false;
17402 * Toggles expanded/collapsed state of the node
17404 toggle : function(){
17413 * Ensures all parent nodes are expanded
17415 ensureVisible : function(callback){
17416 var tree = this.getOwnerTree();
17417 tree.expandPath(this.parentNode.getPath(), false, function(){
17418 tree.getTreeEl().scrollChildIntoView(this.ui.anchor);
17419 Roo.callback(callback);
17420 }.createDelegate(this));
17424 * Expand all child nodes
17425 * @param {Boolean} deep (optional) true if the child nodes should also expand their child nodes
17427 expandChildNodes : function(deep){
17428 var cs = this.childNodes;
17429 for(var i = 0, len = cs.length; i < len; i++) {
17430 cs[i].expand(deep);
17435 * Collapse all child nodes
17436 * @param {Boolean} deep (optional) true if the child nodes should also collapse their child nodes
17438 collapseChildNodes : function(deep){
17439 var cs = this.childNodes;
17440 for(var i = 0, len = cs.length; i < len; i++) {
17441 cs[i].collapse(deep);
17446 * Disables this node
17448 disable : function(){
17449 this.disabled = true;
17451 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17452 this.ui.onDisableChange(this, true);
17454 this.fireEvent("disabledchange", this, true);
17458 * Enables this node
17460 enable : function(){
17461 this.disabled = false;
17462 if(this.rendered && this.ui.onDisableChange){ // event without subscribing
17463 this.ui.onDisableChange(this, false);
17465 this.fireEvent("disabledchange", this, false);
17469 renderChildren : function(suppressEvent){
17470 if(suppressEvent !== false){
17471 this.fireEvent("beforechildrenrendered", this);
17473 var cs = this.childNodes;
17474 for(var i = 0, len = cs.length; i < len; i++){
17475 cs[i].render(true);
17477 this.childrenRendered = true;
17481 sort : function(fn, scope){
17482 Roo.tree.TreeNode.superclass.sort.apply(this, arguments);
17483 if(this.childrenRendered){
17484 var cs = this.childNodes;
17485 for(var i = 0, len = cs.length; i < len; i++){
17486 cs[i].render(true);
17492 render : function(bulkRender){
17493 this.ui.render(bulkRender);
17494 if(!this.rendered){
17495 this.rendered = true;
17497 this.expanded = false;
17498 this.expand(false, false);
17504 renderIndent : function(deep, refresh){
17506 this.ui.childIndent = null;
17508 this.ui.renderIndent();
17509 if(deep === true && this.childrenRendered){
17510 var cs = this.childNodes;
17511 for(var i = 0, len = cs.length; i < len; i++){
17512 cs[i].renderIndent(true, refresh);
17518 * Ext JS Library 1.1.1
17519 * Copyright(c) 2006-2007, Ext JS, LLC.
17521 * Originally Released Under LGPL - original licence link has changed is not relivant.
17524 * <script type="text/javascript">
17528 * @class Roo.tree.AsyncTreeNode
17529 * @extends Roo.tree.TreeNode
17530 * @cfg {TreeLoader} loader A TreeLoader to be used by this node (defaults to the loader defined on the tree)
17532 * @param {Object/String} attributes The attributes/config for the node or just a string with the text for the node
17534 Roo.tree.AsyncTreeNode = function(config){
17535 this.loaded = false;
17536 this.loading = false;
17537 Roo.tree.AsyncTreeNode.superclass.constructor.apply(this, arguments);
17539 * @event beforeload
17540 * Fires before this node is loaded, return false to cancel
17541 * @param {Node} this This node
17543 this.addEvents({'beforeload':true, 'load': true});
17546 * Fires when this node is loaded
17547 * @param {Node} this This node
17550 * The loader used by this node (defaults to using the tree's defined loader)
17555 Roo.extend(Roo.tree.AsyncTreeNode, Roo.tree.TreeNode, {
17556 expand : function(deep, anim, callback){
17557 if(this.loading){ // if an async load is already running, waiting til it's done
17559 var f = function(){
17560 if(!this.loading){ // done loading
17561 clearInterval(timer);
17562 this.expand(deep, anim, callback);
17564 }.createDelegate(this);
17565 timer = setInterval(f, 200);
17569 if(this.fireEvent("beforeload", this) === false){
17572 this.loading = true;
17573 this.ui.beforeLoad(this);
17574 var loader = this.loader || this.attributes.loader || this.getOwnerTree().getLoader();
17576 loader.load(this, this.loadComplete.createDelegate(this, [deep, anim, callback]));
17580 Roo.tree.AsyncTreeNode.superclass.expand.call(this, deep, anim, callback);
17584 * Returns true if this node is currently loading
17585 * @return {Boolean}
17587 isLoading : function(){
17588 return this.loading;
17591 loadComplete : function(deep, anim, callback){
17592 this.loading = false;
17593 this.loaded = true;
17594 this.ui.afterLoad(this);
17595 this.fireEvent("load", this);
17596 this.expand(deep, anim, callback);
17600 * Returns true if this node has been loaded
17601 * @return {Boolean}
17603 isLoaded : function(){
17604 return this.loaded;
17607 hasChildNodes : function(){
17608 if(!this.isLeaf() && !this.loaded){
17611 return Roo.tree.AsyncTreeNode.superclass.hasChildNodes.call(this);
17616 * Trigger a reload for this node
17617 * @param {Function} callback
17619 reload : function(callback){
17620 this.collapse(false, false);
17621 while(this.firstChild){
17622 this.removeChild(this.firstChild);
17624 this.childrenRendered = false;
17625 this.loaded = false;
17626 if(this.isHiddenRoot()){
17627 this.expanded = false;
17629 this.expand(false, false, callback);
17633 * Ext JS Library 1.1.1
17634 * Copyright(c) 2006-2007, Ext JS, LLC.
17636 * Originally Released Under LGPL - original licence link has changed is not relivant.
17639 * <script type="text/javascript">
17643 * @class Roo.tree.TreeNodeUI
17645 * @param {Object} node The node to render
17646 * The TreeNode UI implementation is separate from the
17647 * tree implementation. Unless you are customizing the tree UI,
17648 * you should never have to use this directly.
17650 Roo.tree.TreeNodeUI = function(node){
17652 this.rendered = false;
17653 this.animating = false;
17654 this.emptyIcon = Roo.BLANK_IMAGE_URL;
17657 Roo.tree.TreeNodeUI.prototype = {
17658 removeChild : function(node){
17660 this.ctNode.removeChild(node.ui.getEl());
17664 beforeLoad : function(){
17665 this.addClass("x-tree-node-loading");
17668 afterLoad : function(){
17669 this.removeClass("x-tree-node-loading");
17672 onTextChange : function(node, text, oldText){
17674 this.textNode.innerHTML = text;
17678 onDisableChange : function(node, state){
17679 this.disabled = state;
17681 this.addClass("x-tree-node-disabled");
17683 this.removeClass("x-tree-node-disabled");
17687 onSelectedChange : function(state){
17690 this.addClass("x-tree-selected");
17693 this.removeClass("x-tree-selected");
17697 onMove : function(tree, node, oldParent, newParent, index, refNode){
17698 this.childIndent = null;
17700 var targetNode = newParent.ui.getContainer();
17701 if(!targetNode){//target not rendered
17702 this.holder = document.createElement("div");
17703 this.holder.appendChild(this.wrap);
17706 var insertBefore = refNode ? refNode.ui.getEl() : null;
17708 targetNode.insertBefore(this.wrap, insertBefore);
17710 targetNode.appendChild(this.wrap);
17712 this.node.renderIndent(true);
17716 addClass : function(cls){
17718 Roo.fly(this.elNode).addClass(cls);
17722 removeClass : function(cls){
17724 Roo.fly(this.elNode).removeClass(cls);
17728 remove : function(){
17730 this.holder = document.createElement("div");
17731 this.holder.appendChild(this.wrap);
17735 fireEvent : function(){
17736 return this.node.fireEvent.apply(this.node, arguments);
17739 initEvents : function(){
17740 this.node.on("move", this.onMove, this);
17741 var E = Roo.EventManager;
17742 var a = this.anchor;
17744 var el = Roo.fly(a, '_treeui');
17746 if(Roo.isOpera){ // opera render bug ignores the CSS
17747 el.setStyle("text-decoration", "none");
17750 el.on("click", this.onClick, this);
17751 el.on("dblclick", this.onDblClick, this);
17754 Roo.EventManager.on(this.checkbox,
17755 Roo.isIE ? 'click' : 'change', this.onCheckChange, this);
17758 el.on("contextmenu", this.onContextMenu, this);
17760 var icon = Roo.fly(this.iconNode);
17761 icon.on("click", this.onClick, this);
17762 icon.on("dblclick", this.onDblClick, this);
17763 icon.on("contextmenu", this.onContextMenu, this);
17764 E.on(this.ecNode, "click", this.ecClick, this, true);
17766 if(this.node.disabled){
17767 this.addClass("x-tree-node-disabled");
17769 if(this.node.hidden){
17770 this.addClass("x-tree-node-disabled");
17772 var ot = this.node.getOwnerTree();
17773 var dd = ot.enableDD || ot.enableDrag || ot.enableDrop;
17774 if(dd && (!this.node.isRoot || ot.rootVisible)){
17775 Roo.dd.Registry.register(this.elNode, {
17777 handles: this.getDDHandles(),
17783 getDDHandles : function(){
17784 return [this.iconNode, this.textNode];
17789 this.wrap.style.display = "none";
17795 this.wrap.style.display = "";
17799 onContextMenu : function(e){
17800 if (this.node.hasListener("contextmenu") || this.node.getOwnerTree().hasListener("contextmenu")) {
17801 e.preventDefault();
17803 this.fireEvent("contextmenu", this.node, e);
17807 onClick : function(e){
17812 if(this.fireEvent("beforeclick", this.node, e) !== false){
17813 if(!this.disabled && this.node.attributes.href){
17814 this.fireEvent("click", this.node, e);
17817 e.preventDefault();
17822 if(this.node.attributes.singleClickExpand && !this.animating && this.node.hasChildNodes()){
17823 this.node.toggle();
17826 this.fireEvent("click", this.node, e);
17832 onDblClick : function(e){
17833 e.preventDefault();
17838 this.toggleCheck();
17840 if(!this.animating && this.node.hasChildNodes()){
17841 this.node.toggle();
17843 this.fireEvent("dblclick", this.node, e);
17846 onCheckChange : function(){
17847 var checked = this.checkbox.checked;
17848 this.node.attributes.checked = checked;
17849 this.fireEvent('checkchange', this.node, checked);
17852 ecClick : function(e){
17853 if(!this.animating && this.node.hasChildNodes()){
17854 this.node.toggle();
17858 startDrop : function(){
17859 this.dropping = true;
17862 // delayed drop so the click event doesn't get fired on a drop
17863 endDrop : function(){
17864 setTimeout(function(){
17865 this.dropping = false;
17866 }.createDelegate(this), 50);
17869 expand : function(){
17870 this.updateExpandIcon();
17871 this.ctNode.style.display = "";
17874 focus : function(){
17875 if(!this.node.preventHScroll){
17876 try{this.anchor.focus();
17878 }else if(!Roo.isIE){
17880 var noscroll = this.node.getOwnerTree().getTreeEl().dom;
17881 var l = noscroll.scrollLeft;
17882 this.anchor.focus();
17883 noscroll.scrollLeft = l;
17888 toggleCheck : function(value){
17889 var cb = this.checkbox;
17891 cb.checked = (value === undefined ? !cb.checked : value);
17897 this.anchor.blur();
17901 animExpand : function(callback){
17902 var ct = Roo.get(this.ctNode);
17904 if(!this.node.hasChildNodes()){
17905 this.updateExpandIcon();
17906 this.ctNode.style.display = "";
17907 Roo.callback(callback);
17910 this.animating = true;
17911 this.updateExpandIcon();
17914 callback : function(){
17915 this.animating = false;
17916 Roo.callback(callback);
17919 duration: this.node.ownerTree.duration || .25
17923 highlight : function(){
17924 var tree = this.node.getOwnerTree();
17925 Roo.fly(this.wrap).highlight(
17926 tree.hlColor || "C3DAF9",
17927 {endColor: tree.hlBaseColor}
17931 collapse : function(){
17932 this.updateExpandIcon();
17933 this.ctNode.style.display = "none";
17936 animCollapse : function(callback){
17937 var ct = Roo.get(this.ctNode);
17938 ct.enableDisplayMode('block');
17941 this.animating = true;
17942 this.updateExpandIcon();
17945 callback : function(){
17946 this.animating = false;
17947 Roo.callback(callback);
17950 duration: this.node.ownerTree.duration || .25
17954 getContainer : function(){
17955 return this.ctNode;
17958 getEl : function(){
17962 appendDDGhost : function(ghostNode){
17963 ghostNode.appendChild(this.elNode.cloneNode(true));
17966 getDDRepairXY : function(){
17967 return Roo.lib.Dom.getXY(this.iconNode);
17970 onRender : function(){
17974 render : function(bulkRender){
17975 var n = this.node, a = n.attributes;
17976 var targetNode = n.parentNode ?
17977 n.parentNode.ui.getContainer() : n.ownerTree.innerCt.dom;
17979 if(!this.rendered){
17980 this.rendered = true;
17982 this.renderElements(n, a, targetNode, bulkRender);
17985 if(this.textNode.setAttributeNS){
17986 this.textNode.setAttributeNS("ext", "qtip", a.qtip);
17988 this.textNode.setAttributeNS("ext", "qtitle", a.qtipTitle);
17991 this.textNode.setAttribute("ext:qtip", a.qtip);
17993 this.textNode.setAttribute("ext:qtitle", a.qtipTitle);
17996 }else if(a.qtipCfg){
17997 a.qtipCfg.target = Roo.id(this.textNode);
17998 Roo.QuickTips.register(a.qtipCfg);
18001 if(!this.node.expanded){
18002 this.updateExpandIcon();
18005 if(bulkRender === true) {
18006 targetNode.appendChild(this.wrap);
18011 renderElements : function(n, a, targetNode, bulkRender){
18012 // add some indent caching, this helps performance when rendering a large tree
18013 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
18014 var t = n.getOwnerTree();
18015 var txt = t.renderer ? t.renderer(n.attributes) : Roo.util.Format.htmlEncode(n.text);
18016 var tip = t.rendererTip ? t.rendererTip(n.attributes) : txt;
18017 var cb = typeof a.checked == 'boolean';
18018 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
18019 var buf = ['<li class="x-tree-node"><div class="x-tree-node-el ', a.cls,'">',
18020 '<span class="x-tree-node-indent">',this.indentMarkup,"</span>",
18021 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon" />',
18022 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',(a.icon ? " x-tree-node-inline-icon" : ""),(a.iconCls ? " "+a.iconCls : ""),'" unselectable="on" />',
18023 cb ? ('<input class="x-tree-node-cb" type="checkbox" ' + (a.checked ? 'checked="checked" />' : ' />')) : '',
18024 '<a hidefocus="on" href="',href,'" tabIndex="1" ',
18025 a.hrefTarget ? ' target="'+a.hrefTarget+'"' : "",
18026 '><span unselectable="on" qtip="' , tip ,'">',txt,"</span></a></div>",
18027 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
18030 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
18031 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
18032 n.nextSibling.ui.getEl(), buf.join(""));
18034 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
18037 this.elNode = this.wrap.childNodes[0];
18038 this.ctNode = this.wrap.childNodes[1];
18039 var cs = this.elNode.childNodes;
18040 this.indentNode = cs[0];
18041 this.ecNode = cs[1];
18042 this.iconNode = cs[2];
18045 this.checkbox = cs[3];
18048 this.anchor = cs[index];
18049 this.textNode = cs[index].firstChild;
18052 getAnchor : function(){
18053 return this.anchor;
18056 getTextEl : function(){
18057 return this.textNode;
18060 getIconEl : function(){
18061 return this.iconNode;
18064 isChecked : function(){
18065 return this.checkbox ? this.checkbox.checked : false;
18068 updateExpandIcon : function(){
18070 var n = this.node, c1, c2;
18071 var cls = n.isLast() ? "x-tree-elbow-end" : "x-tree-elbow";
18072 var hasChild = n.hasChildNodes();
18076 c1 = "x-tree-node-collapsed";
18077 c2 = "x-tree-node-expanded";
18080 c1 = "x-tree-node-expanded";
18081 c2 = "x-tree-node-collapsed";
18084 this.removeClass("x-tree-node-leaf");
18085 this.wasLeaf = false;
18087 if(this.c1 != c1 || this.c2 != c2){
18088 Roo.fly(this.elNode).replaceClass(c1, c2);
18089 this.c1 = c1; this.c2 = c2;
18093 Roo.fly(this.elNode).replaceClass("x-tree-node-expanded", "x-tree-node-leaf");
18096 this.wasLeaf = true;
18099 var ecc = "x-tree-ec-icon "+cls;
18100 if(this.ecc != ecc){
18101 this.ecNode.className = ecc;
18107 getChildIndent : function(){
18108 if(!this.childIndent){
18112 if(!p.isRoot || (p.isRoot && p.ownerTree.rootVisible)){
18114 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-elbow-line" />');
18116 buf.unshift('<img src="'+this.emptyIcon+'" class="x-tree-icon" />');
18121 this.childIndent = buf.join("");
18123 return this.childIndent;
18126 renderIndent : function(){
18129 var p = this.node.parentNode;
18131 indent = p.ui.getChildIndent();
18133 if(this.indentMarkup != indent){ // don't rerender if not required
18134 this.indentNode.innerHTML = indent;
18135 this.indentMarkup = indent;
18137 this.updateExpandIcon();
18142 Roo.tree.RootTreeNodeUI = function(){
18143 Roo.tree.RootTreeNodeUI.superclass.constructor.apply(this, arguments);
18145 Roo.extend(Roo.tree.RootTreeNodeUI, Roo.tree.TreeNodeUI, {
18146 render : function(){
18147 if(!this.rendered){
18148 var targetNode = this.node.ownerTree.innerCt.dom;
18149 this.node.expanded = true;
18150 targetNode.innerHTML = '<div class="x-tree-root-node"></div>';
18151 this.wrap = this.ctNode = targetNode.firstChild;
18154 collapse : function(){
18156 expand : function(){
18160 * Ext JS Library 1.1.1
18161 * Copyright(c) 2006-2007, Ext JS, LLC.
18163 * Originally Released Under LGPL - original licence link has changed is not relivant.
18166 * <script type="text/javascript">
18169 * @class Roo.tree.TreeLoader
18170 * @extends Roo.util.Observable
18171 * A TreeLoader provides for lazy loading of an {@link Roo.tree.TreeNode}'s child
18172 * nodes from a specified URL. The response must be a javascript Array definition
18173 * who's elements are node definition objects. eg:
18175 [{ 'id': 1, 'text': 'A folder Node', 'leaf': false },
18176 { 'id': 2, 'text': 'A leaf Node', 'leaf': true }]
18179 * A server request is sent, and child nodes are loaded only when a node is expanded.
18180 * The loading node's id is passed to the server under the parameter name "node" to
18181 * enable the server to produce the correct child nodes.
18183 * To pass extra parameters, an event handler may be attached to the "beforeload"
18184 * event, and the parameters specified in the TreeLoader's baseParams property:
18186 myTreeLoader.on("beforeload", function(treeLoader, node) {
18187 this.baseParams.category = node.attributes.category;
18190 * This would pass an HTTP parameter called "category" to the server containing
18191 * the value of the Node's "category" attribute.
18193 * Creates a new Treeloader.
18194 * @param {Object} config A config object containing config properties.
18196 Roo.tree.TreeLoader = function(config){
18197 this.baseParams = {};
18198 this.requestMethod = "POST";
18199 Roo.apply(this, config);
18204 * @event beforeload
18205 * Fires before a network request is made to retrieve the Json text which specifies a node's children.
18206 * @param {Object} This TreeLoader object.
18207 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18208 * @param {Object} callback The callback function specified in the {@link #load} call.
18213 * Fires when the node has been successfuly loaded.
18214 * @param {Object} This TreeLoader object.
18215 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18216 * @param {Object} response The response object containing the data from the server.
18220 * @event loadexception
18221 * Fires if the network request failed.
18222 * @param {Object} This TreeLoader object.
18223 * @param {Object} node The {@link Roo.tree.TreeNode} object being loaded.
18224 * @param {Object} response The response object containing the data from the server.
18226 loadexception : true,
18229 * Fires before a node is created, enabling you to return custom Node types
18230 * @param {Object} This TreeLoader object.
18231 * @param {Object} attr - the data returned from the AJAX call (modify it to suit)
18236 Roo.tree.TreeLoader.superclass.constructor.call(this);
18239 Roo.extend(Roo.tree.TreeLoader, Roo.util.Observable, {
18241 * @cfg {String} dataUrl The URL from which to request a Json string which
18242 * specifies an array of node definition object representing the child nodes
18246 * @cfg {Object} baseParams (optional) An object containing properties which
18247 * specify HTTP parameters to be passed to each request for child nodes.
18250 * @cfg {Object} baseAttrs (optional) An object containing attributes to be added to all nodes
18251 * created by this loader. If the attributes sent by the server have an attribute in this object,
18252 * they take priority.
18255 * @cfg {Object} uiProviders (optional) An object containing properties which
18257 * DEPRECIATED - use 'create' event handler to modify attributes - which affect creation.
18258 * specify custom {@link Roo.tree.TreeNodeUI} implementations. If the optional
18259 * <i>uiProvider</i> attribute of a returned child node is a string rather
18260 * than a reference to a TreeNodeUI implementation, this that string value
18261 * is used as a property name in the uiProviders object. You can define the provider named
18262 * 'default' , and this will be used for all nodes (if no uiProvider is delivered by the node data)
18267 * @cfg {Boolean} clearOnLoad (optional) Default to true. Remove previously existing
18268 * child nodes before loading.
18270 clearOnLoad : true,
18273 * @cfg {String} root (optional) Default to false. Use this to read data from an object
18274 * property on loading, rather than expecting an array. (eg. more compatible to a standard
18275 * Grid query { data : [ .....] }
18280 * @cfg {String} queryParam (optional)
18281 * Name of the query as it will be passed on the querystring (defaults to 'node')
18282 * eg. the request will be ?node=[id]
18289 * Load an {@link Roo.tree.TreeNode} from the URL specified in the constructor.
18290 * This is called automatically when a node is expanded, but may be used to reload
18291 * a node (or append new children if the {@link #clearOnLoad} option is false.)
18292 * @param {Roo.tree.TreeNode} node
18293 * @param {Function} callback
18295 load : function(node, callback){
18296 if(this.clearOnLoad){
18297 while(node.firstChild){
18298 node.removeChild(node.firstChild);
18301 if(node.attributes.children){ // preloaded json children
18302 var cs = node.attributes.children;
18303 for(var i = 0, len = cs.length; i < len; i++){
18304 node.appendChild(this.createNode(cs[i]));
18306 if(typeof callback == "function"){
18309 }else if(this.dataUrl){
18310 this.requestData(node, callback);
18314 getParams: function(node){
18315 var buf = [], bp = this.baseParams;
18316 for(var key in bp){
18317 if(typeof bp[key] != "function"){
18318 buf.push(encodeURIComponent(key), "=", encodeURIComponent(bp[key]), "&");
18321 var n = this.queryParam === false ? 'node' : this.queryParam;
18322 buf.push(n + "=", encodeURIComponent(node.id));
18323 return buf.join("");
18326 requestData : function(node, callback){
18327 if(this.fireEvent("beforeload", this, node, callback) !== false){
18328 this.transId = Roo.Ajax.request({
18329 method:this.requestMethod,
18330 url: this.dataUrl||this.url,
18331 success: this.handleResponse,
18332 failure: this.handleFailure,
18334 argument: {callback: callback, node: node},
18335 params: this.getParams(node)
18338 // if the load is cancelled, make sure we notify
18339 // the node that we are done
18340 if(typeof callback == "function"){
18346 isLoading : function(){
18347 return this.transId ? true : false;
18350 abort : function(){
18351 if(this.isLoading()){
18352 Roo.Ajax.abort(this.transId);
18357 createNode : function(attr){
18358 // apply baseAttrs, nice idea Corey!
18359 if(this.baseAttrs){
18360 Roo.applyIf(attr, this.baseAttrs);
18362 if(this.applyLoader !== false){
18363 attr.loader = this;
18365 // uiProvider = depreciated..
18367 if(typeof(attr.uiProvider) == 'string'){
18368 attr.uiProvider = this.uiProviders[attr.uiProvider] ||
18369 /** eval:var:attr */ eval(attr.uiProvider);
18371 if(typeof(this.uiProviders['default']) != 'undefined') {
18372 attr.uiProvider = this.uiProviders['default'];
18375 this.fireEvent('create', this, attr);
18377 attr.leaf = typeof(attr.leaf) == 'string' ? attr.leaf * 1 : attr.leaf;
18379 new Roo.tree.TreeNode(attr) :
18380 new Roo.tree.AsyncTreeNode(attr));
18383 processResponse : function(response, node, callback){
18384 var json = response.responseText;
18387 var o = /** eval:var:zzzzzzzzzz */ eval("("+json+")");
18388 if (this.root !== false) {
18392 for(var i = 0, len = o.length; i < len; i++){
18393 var n = this.createNode(o[i]);
18395 node.appendChild(n);
18398 if(typeof callback == "function"){
18399 callback(this, node);
18402 this.handleFailure(response);
18406 handleResponse : function(response){
18407 this.transId = false;
18408 var a = response.argument;
18409 this.processResponse(response, a.node, a.callback);
18410 this.fireEvent("load", this, a.node, response);
18413 handleFailure : function(response){
18414 this.transId = false;
18415 var a = response.argument;
18416 this.fireEvent("loadexception", this, a.node, response);
18417 if(typeof a.callback == "function"){
18418 a.callback(this, a.node);
18423 * Ext JS Library 1.1.1
18424 * Copyright(c) 2006-2007, Ext JS, LLC.
18426 * Originally Released Under LGPL - original licence link has changed is not relivant.
18429 * <script type="text/javascript">
18433 * @class Roo.tree.TreeFilter
18434 * Note this class is experimental and doesn't update the indent (lines) or expand collapse icons of the nodes
18435 * @param {TreePanel} tree
18436 * @param {Object} config (optional)
18438 Roo.tree.TreeFilter = function(tree, config){
18440 this.filtered = {};
18441 Roo.apply(this, config);
18444 Roo.tree.TreeFilter.prototype = {
18451 * Filter the data by a specific attribute.
18452 * @param {String/RegExp} value Either string that the attribute value
18453 * should start with or a RegExp to test against the attribute
18454 * @param {String} attr (optional) The attribute passed in your node's attributes collection. Defaults to "text".
18455 * @param {TreeNode} startNode (optional) The node to start the filter at.
18457 filter : function(value, attr, startNode){
18458 attr = attr || "text";
18460 if(typeof value == "string"){
18461 var vlen = value.length;
18462 // auto clear empty filter
18463 if(vlen == 0 && this.clearBlank){
18467 value = value.toLowerCase();
18469 return n.attributes[attr].substr(0, vlen).toLowerCase() == value;
18471 }else if(value.exec){ // regex?
18473 return value.test(n.attributes[attr]);
18476 throw 'Illegal filter type, must be string or regex';
18478 this.filterBy(f, null, startNode);
18482 * Filter by a function. The passed function will be called with each
18483 * node in the tree (or from the startNode). If the function returns true, the node is kept
18484 * otherwise it is filtered. If a node is filtered, its children are also filtered.
18485 * @param {Function} fn The filter function
18486 * @param {Object} scope (optional) The scope of the function (defaults to the current node)
18488 filterBy : function(fn, scope, startNode){
18489 startNode = startNode || this.tree.root;
18490 if(this.autoClear){
18493 var af = this.filtered, rv = this.reverse;
18494 var f = function(n){
18495 if(n == startNode){
18501 var m = fn.call(scope || n, n);
18509 startNode.cascade(f);
18512 if(typeof id != "function"){
18514 if(n && n.parentNode){
18515 n.parentNode.removeChild(n);
18523 * Clears the current filter. Note: with the "remove" option
18524 * set a filter cannot be cleared.
18526 clear : function(){
18528 var af = this.filtered;
18530 if(typeof id != "function"){
18537 this.filtered = {};
18542 * Ext JS Library 1.1.1
18543 * Copyright(c) 2006-2007, Ext JS, LLC.
18545 * Originally Released Under LGPL - original licence link has changed is not relivant.
18548 * <script type="text/javascript">
18553 * @class Roo.tree.TreeSorter
18554 * Provides sorting of nodes in a TreePanel
18556 * @cfg {Boolean} folderSort True to sort leaf nodes under non leaf nodes
18557 * @cfg {String} property The named attribute on the node to sort by (defaults to text)
18558 * @cfg {String} dir The direction to sort (asc or desc) (defaults to asc)
18559 * @cfg {String} leafAttr The attribute used to determine leaf nodes in folder sort (defaults to "leaf")
18560 * @cfg {Boolean} caseSensitive true for case sensitive sort (defaults to false)
18561 * @cfg {Function} sortType A custom "casting" function used to convert node values before sorting
18563 * @param {TreePanel} tree
18564 * @param {Object} config
18566 Roo.tree.TreeSorter = function(tree, config){
18567 Roo.apply(this, config);
18568 tree.on("beforechildrenrendered", this.doSort, this);
18569 tree.on("append", this.updateSort, this);
18570 tree.on("insert", this.updateSort, this);
18572 var dsc = this.dir && this.dir.toLowerCase() == "desc";
18573 var p = this.property || "text";
18574 var sortType = this.sortType;
18575 var fs = this.folderSort;
18576 var cs = this.caseSensitive === true;
18577 var leafAttr = this.leafAttr || 'leaf';
18579 this.sortFn = function(n1, n2){
18581 if(n1.attributes[leafAttr] && !n2.attributes[leafAttr]){
18584 if(!n1.attributes[leafAttr] && n2.attributes[leafAttr]){
18588 var v1 = sortType ? sortType(n1) : (cs ? n1.attributes[p] : n1.attributes[p].toUpperCase());
18589 var v2 = sortType ? sortType(n2) : (cs ? n2.attributes[p] : n2.attributes[p].toUpperCase());
18591 return dsc ? +1 : -1;
18593 return dsc ? -1 : +1;
18600 Roo.tree.TreeSorter.prototype = {
18601 doSort : function(node){
18602 node.sort(this.sortFn);
18605 compareNodes : function(n1, n2){
18606 return (n1.text.toUpperCase() > n2.text.toUpperCase() ? 1 : -1);
18609 updateSort : function(tree, node){
18610 if(node.childrenRendered){
18611 this.doSort.defer(1, this, [node]);
18616 * Ext JS Library 1.1.1
18617 * Copyright(c) 2006-2007, Ext JS, LLC.
18619 * Originally Released Under LGPL - original licence link has changed is not relivant.
18622 * <script type="text/javascript">
18625 if(Roo.dd.DropZone){
18627 Roo.tree.TreeDropZone = function(tree, config){
18628 this.allowParentInsert = false;
18629 this.allowContainerDrop = false;
18630 this.appendOnly = false;
18631 Roo.tree.TreeDropZone.superclass.constructor.call(this, tree.innerCt, config);
18633 this.lastInsertClass = "x-tree-no-status";
18634 this.dragOverData = {};
18637 Roo.extend(Roo.tree.TreeDropZone, Roo.dd.DropZone, {
18638 ddGroup : "TreeDD",
18640 expandDelay : 1000,
18642 expandNode : function(node){
18643 if(node.hasChildNodes() && !node.isExpanded()){
18644 node.expand(false, null, this.triggerCacheRefresh.createDelegate(this));
18648 queueExpand : function(node){
18649 this.expandProcId = this.expandNode.defer(this.expandDelay, this, [node]);
18652 cancelExpand : function(){
18653 if(this.expandProcId){
18654 clearTimeout(this.expandProcId);
18655 this.expandProcId = false;
18659 isValidDropPoint : function(n, pt, dd, e, data){
18660 if(!n || !data){ return false; }
18661 var targetNode = n.node;
18662 var dropNode = data.node;
18663 // default drop rules
18664 if(!(targetNode && targetNode.isTarget && pt)){
18667 if(pt == "append" && targetNode.allowChildren === false){
18670 if((pt == "above" || pt == "below") && (targetNode.parentNode && targetNode.parentNode.allowChildren === false)){
18673 if(dropNode && (targetNode == dropNode || dropNode.contains(targetNode))){
18676 // reuse the object
18677 var overEvent = this.dragOverData;
18678 overEvent.tree = this.tree;
18679 overEvent.target = targetNode;
18680 overEvent.data = data;
18681 overEvent.point = pt;
18682 overEvent.source = dd;
18683 overEvent.rawEvent = e;
18684 overEvent.dropNode = dropNode;
18685 overEvent.cancel = false;
18686 var result = this.tree.fireEvent("nodedragover", overEvent);
18687 return overEvent.cancel === false && result !== false;
18690 getDropPoint : function(e, n, dd){
18693 return tn.allowChildren !== false ? "append" : false; // always append for root
18695 var dragEl = n.ddel;
18696 var t = Roo.lib.Dom.getY(dragEl), b = t + dragEl.offsetHeight;
18697 var y = Roo.lib.Event.getPageY(e);
18698 //var noAppend = tn.allowChildren === false || tn.isLeaf();
18700 // we may drop nodes anywhere, as long as allowChildren has not been set to false..
18701 var noAppend = tn.allowChildren === false;
18702 if(this.appendOnly || tn.parentNode.allowChildren === false){
18703 return noAppend ? false : "append";
18705 var noBelow = false;
18706 if(!this.allowParentInsert){
18707 noBelow = tn.hasChildNodes() && tn.isExpanded();
18709 var q = (b - t) / (noAppend ? 2 : 3);
18710 if(y >= t && y < (t + q)){
18712 }else if(!noBelow && (noAppend || y >= b-q && y <= b)){
18719 onNodeEnter : function(n, dd, e, data){
18720 this.cancelExpand();
18723 onNodeOver : function(n, dd, e, data){
18724 var pt = this.getDropPoint(e, n, dd);
18727 // auto node expand check
18728 if(!this.expandProcId && pt == "append" && node.hasChildNodes() && !n.node.isExpanded()){
18729 this.queueExpand(node);
18730 }else if(pt != "append"){
18731 this.cancelExpand();
18734 // set the insert point style on the target node
18735 var returnCls = this.dropNotAllowed;
18736 if(this.isValidDropPoint(n, pt, dd, e, data)){
18741 returnCls = n.node.isFirst() ? "x-tree-drop-ok-above" : "x-tree-drop-ok-between";
18742 cls = "x-tree-drag-insert-above";
18743 }else if(pt == "below"){
18744 returnCls = n.node.isLast() ? "x-tree-drop-ok-below" : "x-tree-drop-ok-between";
18745 cls = "x-tree-drag-insert-below";
18747 returnCls = "x-tree-drop-ok-append";
18748 cls = "x-tree-drag-append";
18750 if(this.lastInsertClass != cls){
18751 Roo.fly(el).replaceClass(this.lastInsertClass, cls);
18752 this.lastInsertClass = cls;
18759 onNodeOut : function(n, dd, e, data){
18760 this.cancelExpand();
18761 this.removeDropIndicators(n);
18764 onNodeDrop : function(n, dd, e, data){
18765 var point = this.getDropPoint(e, n, dd);
18766 var targetNode = n.node;
18767 targetNode.ui.startDrop();
18768 if(!this.isValidDropPoint(n, point, dd, e, data)){
18769 targetNode.ui.endDrop();
18772 // first try to find the drop node
18773 var dropNode = data.node || (dd.getTreeNode ? dd.getTreeNode(data, targetNode, point, e) : null);
18776 target: targetNode,
18781 dropNode: dropNode,
18784 var retval = this.tree.fireEvent("beforenodedrop", dropEvent);
18785 if(retval === false || dropEvent.cancel === true || !dropEvent.dropNode){
18786 targetNode.ui.endDrop();
18789 // allow target changing
18790 targetNode = dropEvent.target;
18791 if(point == "append" && !targetNode.isExpanded()){
18792 targetNode.expand(false, null, function(){
18793 this.completeDrop(dropEvent);
18794 }.createDelegate(this));
18796 this.completeDrop(dropEvent);
18801 completeDrop : function(de){
18802 var ns = de.dropNode, p = de.point, t = de.target;
18803 if(!(ns instanceof Array)){
18807 for(var i = 0, len = ns.length; i < len; i++){
18810 t.parentNode.insertBefore(n, t);
18811 }else if(p == "below"){
18812 t.parentNode.insertBefore(n, t.nextSibling);
18818 if(this.tree.hlDrop){
18822 this.tree.fireEvent("nodedrop", de);
18825 afterNodeMoved : function(dd, data, e, targetNode, dropNode){
18826 if(this.tree.hlDrop){
18827 dropNode.ui.focus();
18828 dropNode.ui.highlight();
18830 this.tree.fireEvent("nodedrop", this.tree, targetNode, data, dd, e);
18833 getTree : function(){
18837 removeDropIndicators : function(n){
18840 Roo.fly(el).removeClass([
18841 "x-tree-drag-insert-above",
18842 "x-tree-drag-insert-below",
18843 "x-tree-drag-append"]);
18844 this.lastInsertClass = "_noclass";
18848 beforeDragDrop : function(target, e, id){
18849 this.cancelExpand();
18853 afterRepair : function(data){
18854 if(data && Roo.enableFx){
18855 data.node.ui.highlight();
18864 * Ext JS Library 1.1.1
18865 * Copyright(c) 2006-2007, Ext JS, LLC.
18867 * Originally Released Under LGPL - original licence link has changed is not relivant.
18870 * <script type="text/javascript">
18874 if(Roo.dd.DragZone){
18875 Roo.tree.TreeDragZone = function(tree, config){
18876 Roo.tree.TreeDragZone.superclass.constructor.call(this, tree.getTreeEl(), config);
18880 Roo.extend(Roo.tree.TreeDragZone, Roo.dd.DragZone, {
18881 ddGroup : "TreeDD",
18883 onBeforeDrag : function(data, e){
18885 return n && n.draggable && !n.disabled;
18888 onInitDrag : function(e){
18889 var data = this.dragData;
18890 this.tree.getSelectionModel().select(data.node);
18891 this.proxy.update("");
18892 data.node.ui.appendDDGhost(this.proxy.ghost.dom);
18893 this.tree.fireEvent("startdrag", this.tree, data.node, e);
18896 getRepairXY : function(e, data){
18897 return data.node.ui.getDDRepairXY();
18900 onEndDrag : function(data, e){
18901 this.tree.fireEvent("enddrag", this.tree, data.node, e);
18904 onValidDrop : function(dd, e, id){
18905 this.tree.fireEvent("dragdrop", this.tree, this.dragData.node, dd, e);
18909 beforeInvalidDrop : function(e, id){
18910 // this scrolls the original position back into view
18911 var sm = this.tree.getSelectionModel();
18912 sm.clearSelections();
18913 sm.select(this.dragData.node);
18918 * Ext JS Library 1.1.1
18919 * Copyright(c) 2006-2007, Ext JS, LLC.
18921 * Originally Released Under LGPL - original licence link has changed is not relivant.
18924 * <script type="text/javascript">
18927 * @class Roo.tree.TreeEditor
18928 * @extends Roo.Editor
18929 * Provides editor functionality for inline tree node editing. Any valid {@link Roo.form.Field} can be used
18930 * as the editor field.
18932 * @param {TreePanel} tree
18933 * @param {Object} config Either a prebuilt {@link Roo.form.Field} instance or a Field config object
18935 Roo.tree.TreeEditor = function(tree, config){
18936 config = config || {};
18937 var field = config.events ? config : new Roo.form.TextField(config);
18938 Roo.tree.TreeEditor.superclass.constructor.call(this, field);
18942 tree.on('beforeclick', this.beforeNodeClick, this);
18943 tree.getTreeEl().on('mousedown', this.hide, this);
18944 this.on('complete', this.updateNode, this);
18945 this.on('beforestartedit', this.fitToTree, this);
18946 this.on('startedit', this.bindScroll, this, {delay:10});
18947 this.on('specialkey', this.onSpecialKey, this);
18950 Roo.extend(Roo.tree.TreeEditor, Roo.Editor, {
18952 * @cfg {String} alignment
18953 * The position to align to (see {@link Roo.Element#alignTo} for more details, defaults to "l-l").
18959 * @cfg {Boolean} hideEl
18960 * True to hide the bound element while the editor is displayed (defaults to false)
18964 * @cfg {String} cls
18965 * CSS class to apply to the editor (defaults to "x-small-editor x-tree-editor")
18967 cls: "x-small-editor x-tree-editor",
18969 * @cfg {Boolean} shim
18970 * True to shim the editor if selects/iframes could be displayed beneath it (defaults to false)
18976 * @cfg {Number} maxWidth
18977 * The maximum width in pixels of the editor field (defaults to 250). Note that if the maxWidth would exceed
18978 * the containing tree element's size, it will be automatically limited for you to the container width, taking
18979 * scroll and client offsets into account prior to each edit.
18986 fitToTree : function(ed, el){
18987 var td = this.tree.getTreeEl().dom, nd = el.dom;
18988 if(td.scrollLeft > nd.offsetLeft){ // ensure the node left point is visible
18989 td.scrollLeft = nd.offsetLeft;
18993 (td.clientWidth > 20 ? td.clientWidth : td.offsetWidth) - Math.max(0, nd.offsetLeft-td.scrollLeft) - /*cushion*/5);
18994 this.setSize(w, '');
18998 triggerEdit : function(node){
18999 this.completeEdit();
19000 this.editNode = node;
19001 this.startEdit(node.ui.textNode, node.text);
19005 bindScroll : function(){
19006 this.tree.getTreeEl().on('scroll', this.cancelEdit, this);
19010 beforeNodeClick : function(node, e){
19011 var sinceLast = (this.lastClick ? this.lastClick.getElapsed() : 0);
19012 this.lastClick = new Date();
19013 if(sinceLast > this.editDelay && this.tree.getSelectionModel().isSelected(node)){
19015 this.triggerEdit(node);
19021 updateNode : function(ed, value){
19022 this.tree.getTreeEl().un('scroll', this.cancelEdit, this);
19023 this.editNode.setText(value);
19027 onHide : function(){
19028 Roo.tree.TreeEditor.superclass.onHide.call(this);
19030 this.editNode.ui.focus();
19035 onSpecialKey : function(field, e){
19036 var k = e.getKey();
19040 }else if(k == e.ENTER && !e.hasModifier()){
19042 this.completeEdit();
19045 });//<Script type="text/javascript">
19048 * Ext JS Library 1.1.1
19049 * Copyright(c) 2006-2007, Ext JS, LLC.
19051 * Originally Released Under LGPL - original licence link has changed is not relivant.
19054 * <script type="text/javascript">
19058 * Not documented??? - probably should be...
19061 Roo.tree.ColumnNodeUI = Roo.extend(Roo.tree.TreeNodeUI, {
19062 //focus: Roo.emptyFn, // prevent odd scrolling behavior
19064 renderElements : function(n, a, targetNode, bulkRender){
19065 //consel.log("renderElements?");
19066 this.indentMarkup = n.parentNode ? n.parentNode.ui.getChildIndent() : '';
19068 var t = n.getOwnerTree();
19069 var tid = Pman.Tab.Document_TypesTree.tree.el.id;
19071 var cols = t.columns;
19072 var bw = t.borderWidth;
19074 var href = a.href ? a.href : Roo.isGecko ? "" : "#";
19075 var cb = typeof a.checked == "boolean";
19076 var tx = String.format('{0}',n.text || (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19077 var colcls = 'x-t-' + tid + '-c0';
19079 '<li class="x-tree-node">',
19082 '<div class="x-tree-node-el ', a.cls,'">',
19084 '<div class="x-tree-col ', colcls, '" style="width:', c.width-bw, 'px;">',
19087 '<span class="x-tree-node-indent">',this.indentMarkup,'</span>',
19088 '<img src="', this.emptyIcon, '" class="x-tree-ec-icon " />',
19089 '<img src="', a.icon || this.emptyIcon, '" class="x-tree-node-icon',
19090 (a.icon ? ' x-tree-node-inline-icon' : ''),
19091 (a.iconCls ? ' '+a.iconCls : ''),
19092 '" unselectable="on" />',
19093 (cb ? ('<input class="x-tree-node-cb" type="checkbox" ' +
19094 (a.checked ? 'checked="checked" />' : ' />')) : ''),
19096 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19097 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>',
19098 '<span unselectable="on" qtip="' + tx + '">',
19102 '<a class="x-tree-node-anchor" hidefocus="on" href="',href,'" tabIndex="1" ',
19103 (a.hrefTarget ? ' target="' +a.hrefTarget + '"' : ''), '>'
19105 for(var i = 1, len = cols.length; i < len; i++){
19107 colcls = 'x-t-' + tid + '-c' +i;
19108 tx = String.format('{0}', (c.renderer ? c.renderer(a[c.dataIndex], n, a) : a[c.dataIndex]));
19109 buf.push('<div class="x-tree-col ', colcls, ' ' ,(c.cls?c.cls:''),'" style="width:',c.width-bw,'px;">',
19110 '<div class="x-tree-col-text" qtip="' + tx +'">',tx,"</div>",
19116 '<div class="x-clear"></div></div>',
19117 '<ul class="x-tree-node-ct" style="display:none;"></ul>',
19120 if(bulkRender !== true && n.nextSibling && n.nextSibling.ui.getEl()){
19121 this.wrap = Roo.DomHelper.insertHtml("beforeBegin",
19122 n.nextSibling.ui.getEl(), buf.join(""));
19124 this.wrap = Roo.DomHelper.insertHtml("beforeEnd", targetNode, buf.join(""));
19126 var el = this.wrap.firstChild;
19128 this.elNode = el.firstChild;
19129 this.ranchor = el.childNodes[1];
19130 this.ctNode = this.wrap.childNodes[1];
19131 var cs = el.firstChild.childNodes;
19132 this.indentNode = cs[0];
19133 this.ecNode = cs[1];
19134 this.iconNode = cs[2];
19137 this.checkbox = cs[3];
19140 this.anchor = cs[index];
19142 this.textNode = cs[index].firstChild;
19144 //el.on("click", this.onClick, this);
19145 //el.on("dblclick", this.onDblClick, this);
19148 // console.log(this);
19150 initEvents : function(){
19151 Roo.tree.ColumnNodeUI.superclass.initEvents.call(this);
19154 var a = this.ranchor;
19156 var el = Roo.get(a);
19158 if(Roo.isOpera){ // opera render bug ignores the CSS
19159 el.setStyle("text-decoration", "none");
19162 el.on("click", this.onClick, this);
19163 el.on("dblclick", this.onDblClick, this);
19164 el.on("contextmenu", this.onContextMenu, this);
19168 /*onSelectedChange : function(state){
19171 this.addClass("x-tree-selected");
19174 this.removeClass("x-tree-selected");
19177 addClass : function(cls){
19179 Roo.fly(this.elRow).addClass(cls);
19185 removeClass : function(cls){
19187 Roo.fly(this.elRow).removeClass(cls);
19193 });//<Script type="text/javascript">
19197 * Ext JS Library 1.1.1
19198 * Copyright(c) 2006-2007, Ext JS, LLC.
19200 * Originally Released Under LGPL - original licence link has changed is not relivant.
19203 * <script type="text/javascript">
19208 * @class Roo.tree.ColumnTree
19209 * @extends Roo.data.TreePanel
19210 * @cfg {Object} columns Including width, header, renderer, cls, dataIndex
19211 * @cfg {int} borderWidth compined right/left border allowance
19213 * @param {String/HTMLElement/Element} el The container element
19214 * @param {Object} config
19216 Roo.tree.ColumnTree = function(el, config)
19218 Roo.tree.ColumnTree.superclass.constructor.call(this, el , config);
19222 * Fire this event on a container when it resizes
19223 * @param {int} w Width
19224 * @param {int} h Height
19228 this.on('resize', this.onResize, this);
19231 Roo.extend(Roo.tree.ColumnTree, Roo.tree.TreePanel, {
19235 borderWidth: Roo.isBorderBox ? 0 : 2,
19238 render : function(){
19239 // add the header.....
19241 Roo.tree.ColumnTree.superclass.render.apply(this);
19243 this.el.addClass('x-column-tree');
19245 this.headers = this.el.createChild(
19246 {cls:'x-tree-headers'},this.innerCt.dom);
19248 var cols = this.columns, c;
19249 var totalWidth = 0;
19251 var len = cols.length;
19252 for(var i = 0; i < len; i++){
19254 totalWidth += c.width;
19255 this.headEls.push(this.headers.createChild({
19256 cls:'x-tree-hd ' + (c.cls?c.cls+'-hd':''),
19258 cls:'x-tree-hd-text',
19261 style:'width:'+(c.width-this.borderWidth)+'px;'
19264 this.headers.createChild({cls:'x-clear'});
19265 // prevent floats from wrapping when clipped
19266 this.headers.setWidth(totalWidth);
19267 //this.innerCt.setWidth(totalWidth);
19268 this.innerCt.setStyle({ overflow: 'auto' });
19269 this.onResize(this.width, this.height);
19273 onResize : function(w,h)
19278 this.innerCt.setWidth(this.width);
19279 this.innerCt.setHeight(this.height-20);
19282 var cols = this.columns, c;
19283 var totalWidth = 0;
19285 var len = cols.length;
19286 for(var i = 0; i < len; i++){
19288 if (this.autoExpandColumn !== false && c.dataIndex == this.autoExpandColumn) {
19289 // it's the expander..
19290 expEl = this.headEls[i];
19293 totalWidth += c.width;
19297 expEl.setWidth( ((w - totalWidth)-this.borderWidth - 20));
19299 this.headers.setWidth(w-20);
19308 * Ext JS Library 1.1.1
19309 * Copyright(c) 2006-2007, Ext JS, LLC.
19311 * Originally Released Under LGPL - original licence link has changed is not relivant.
19314 * <script type="text/javascript">
19318 * @class Roo.menu.Menu
19319 * @extends Roo.util.Observable
19320 * A menu object. This is the container to which you add all other menu items. Menu can also serve a as a base class
19321 * when you want a specialzed menu based off of another component (like {@link Roo.menu.DateMenu} for example).
19323 * Creates a new Menu
19324 * @param {Object} config Configuration options
19326 Roo.menu.Menu = function(config){
19327 Roo.apply(this, config);
19328 this.id = this.id || Roo.id();
19331 * @event beforeshow
19332 * Fires before this menu is displayed
19333 * @param {Roo.menu.Menu} this
19337 * @event beforehide
19338 * Fires before this menu is hidden
19339 * @param {Roo.menu.Menu} this
19344 * Fires after this menu is displayed
19345 * @param {Roo.menu.Menu} this
19350 * Fires after this menu is hidden
19351 * @param {Roo.menu.Menu} this
19356 * Fires when this menu is clicked (or when the enter key is pressed while it is active)
19357 * @param {Roo.menu.Menu} this
19358 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19359 * @param {Roo.EventObject} e
19364 * Fires when the mouse is hovering over this menu
19365 * @param {Roo.menu.Menu} this
19366 * @param {Roo.EventObject} e
19367 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19372 * Fires when the mouse exits this menu
19373 * @param {Roo.menu.Menu} this
19374 * @param {Roo.EventObject} e
19375 * @param {Roo.menu.Item} menuItem The menu item that was clicked
19380 * Fires when a menu item contained in this menu is clicked
19381 * @param {Roo.menu.BaseItem} baseItem The BaseItem that was clicked
19382 * @param {Roo.EventObject} e
19386 if (this.registerMenu) {
19387 Roo.menu.MenuMgr.register(this);
19390 var mis = this.items;
19391 this.items = new Roo.util.MixedCollection();
19393 this.add.apply(this, mis);
19397 Roo.extend(Roo.menu.Menu, Roo.util.Observable, {
19399 * @cfg {Number} minWidth The minimum width of the menu in pixels (defaults to 120)
19403 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop"
19404 * for bottom-right shadow (defaults to "sides")
19408 * @cfg {String} subMenuAlign The {@link Roo.Element#alignTo} anchor position value to use for submenus of
19409 * this menu (defaults to "tl-tr?")
19411 subMenuAlign : "tl-tr?",
19413 * @cfg {String} defaultAlign The default {@link Roo.Element#alignTo) anchor position value for this menu
19414 * relative to its element of origin (defaults to "tl-bl?")
19416 defaultAlign : "tl-bl?",
19418 * @cfg {Boolean} allowOtherMenus True to allow multiple menus to be displayed at the same time (defaults to false)
19420 allowOtherMenus : false,
19422 * @cfg {Boolean} registerMenu True (default) - means that clicking on screen etc. hides it.
19424 registerMenu : true,
19429 render : function(){
19433 var el = this.el = new Roo.Layer({
19435 shadow:this.shadow,
19437 parentEl: this.parentEl || document.body,
19441 this.keyNav = new Roo.menu.MenuNav(this);
19444 el.addClass("x-menu-plain");
19447 el.addClass(this.cls);
19449 // generic focus element
19450 this.focusEl = el.createChild({
19451 tag: "a", cls: "x-menu-focus", href: "#", onclick: "return false;", tabIndex:"-1"
19453 var ul = el.createChild({tag: "ul", cls: "x-menu-list"});
19454 ul.on("click", this.onClick, this);
19455 ul.on("mouseover", this.onMouseOver, this);
19456 ul.on("mouseout", this.onMouseOut, this);
19457 this.items.each(function(item){
19458 var li = document.createElement("li");
19459 li.className = "x-menu-list-item";
19460 ul.dom.appendChild(li);
19461 item.render(li, this);
19468 autoWidth : function(){
19469 var el = this.el, ul = this.ul;
19473 var w = this.width;
19476 }else if(Roo.isIE){
19477 el.setWidth(this.minWidth);
19478 var t = el.dom.offsetWidth; // force recalc
19479 el.setWidth(ul.getWidth()+el.getFrameWidth("lr"));
19484 delayAutoWidth : function(){
19487 this.awTask = new Roo.util.DelayedTask(this.autoWidth, this);
19489 this.awTask.delay(20);
19494 findTargetItem : function(e){
19495 var t = e.getTarget(".x-menu-list-item", this.ul, true);
19496 if(t && t.menuItemId){
19497 return this.items.get(t.menuItemId);
19502 onClick : function(e){
19504 if(t = this.findTargetItem(e)){
19506 this.fireEvent("click", this, t, e);
19511 setActiveItem : function(item, autoExpand){
19512 if(item != this.activeItem){
19513 if(this.activeItem){
19514 this.activeItem.deactivate();
19516 this.activeItem = item;
19517 item.activate(autoExpand);
19518 }else if(autoExpand){
19524 tryActivate : function(start, step){
19525 var items = this.items;
19526 for(var i = start, len = items.length; i >= 0 && i < len; i+= step){
19527 var item = items.get(i);
19528 if(!item.disabled && item.canActivate){
19529 this.setActiveItem(item, false);
19537 onMouseOver : function(e){
19539 if(t = this.findTargetItem(e)){
19540 if(t.canActivate && !t.disabled){
19541 this.setActiveItem(t, true);
19544 this.fireEvent("mouseover", this, e, t);
19548 onMouseOut : function(e){
19550 if(t = this.findTargetItem(e)){
19551 if(t == this.activeItem && t.shouldDeactivate(e)){
19552 this.activeItem.deactivate();
19553 delete this.activeItem;
19556 this.fireEvent("mouseout", this, e, t);
19560 * Read-only. Returns true if the menu is currently displayed, else false.
19563 isVisible : function(){
19564 return this.el && !this.hidden;
19568 * Displays this menu relative to another element
19569 * @param {String/HTMLElement/Roo.Element} element The element to align to
19570 * @param {String} position (optional) The {@link Roo.Element#alignTo} anchor position to use in aligning to
19571 * the element (defaults to this.defaultAlign)
19572 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19574 show : function(el, pos, parentMenu){
19575 this.parentMenu = parentMenu;
19579 this.fireEvent("beforeshow", this);
19580 this.showAt(this.el.getAlignToXY(el, pos || this.defaultAlign), parentMenu, false);
19584 * Displays this menu at a specific xy position
19585 * @param {Array} xyPosition Contains X & Y [x, y] values for the position at which to show the menu (coordinates are page-based)
19586 * @param {Roo.menu.Menu} parentMenu (optional) This menu's parent menu, if applicable (defaults to undefined)
19588 showAt : function(xy, parentMenu, /* private: */_e){
19589 this.parentMenu = parentMenu;
19594 this.fireEvent("beforeshow", this);
19595 xy = this.el.adjustForConstraints(xy);
19599 this.hidden = false;
19601 this.fireEvent("show", this);
19604 focus : function(){
19606 this.doFocus.defer(50, this);
19610 doFocus : function(){
19612 this.focusEl.focus();
19617 * Hides this menu and optionally all parent menus
19618 * @param {Boolean} deep (optional) True to hide all parent menus recursively, if any (defaults to false)
19620 hide : function(deep){
19621 if(this.el && this.isVisible()){
19622 this.fireEvent("beforehide", this);
19623 if(this.activeItem){
19624 this.activeItem.deactivate();
19625 this.activeItem = null;
19628 this.hidden = true;
19629 this.fireEvent("hide", this);
19631 if(deep === true && this.parentMenu){
19632 this.parentMenu.hide(true);
19637 * Addds one or more items of any type supported by the Menu class, or that can be converted into menu items.
19638 * Any of the following are valid:
19640 * <li>Any menu item object based on {@link Roo.menu.Item}</li>
19641 * <li>An HTMLElement object which will be converted to a menu item</li>
19642 * <li>A menu item config object that will be created as a new menu item</li>
19643 * <li>A string, which can either be '-' or 'separator' to add a menu separator, otherwise
19644 * it will be converted into a {@link Roo.menu.TextItem} and added</li>
19649 var menu = new Roo.menu.Menu();
19651 // Create a menu item to add by reference
19652 var menuItem = new Roo.menu.Item({ text: 'New Item!' });
19654 // Add a bunch of items at once using different methods.
19655 // Only the last item added will be returned.
19656 var item = menu.add(
19657 menuItem, // add existing item by ref
19658 'Dynamic Item', // new TextItem
19659 '-', // new separator
19660 { text: 'Config Item' } // new item by config
19663 * @param {Mixed} args One or more menu items, menu item configs or other objects that can be converted to menu items
19664 * @return {Roo.menu.Item} The menu item that was added, or the last one if multiple items were added
19667 var a = arguments, l = a.length, item;
19668 for(var i = 0; i < l; i++){
19670 if ((typeof(el) == "object") && el.xtype && el.xns) {
19671 el = Roo.factory(el, Roo.menu);
19674 if(el.render){ // some kind of Item
19675 item = this.addItem(el);
19676 }else if(typeof el == "string"){ // string
19677 if(el == "separator" || el == "-"){
19678 item = this.addSeparator();
19680 item = this.addText(el);
19682 }else if(el.tagName || el.el){ // element
19683 item = this.addElement(el);
19684 }else if(typeof el == "object"){ // must be menu item config?
19685 item = this.addMenuItem(el);
19692 * Returns this menu's underlying {@link Roo.Element} object
19693 * @return {Roo.Element} The element
19695 getEl : function(){
19703 * Adds a separator bar to the menu
19704 * @return {Roo.menu.Item} The menu item that was added
19706 addSeparator : function(){
19707 return this.addItem(new Roo.menu.Separator());
19711 * Adds an {@link Roo.Element} object to the menu
19712 * @param {String/HTMLElement/Roo.Element} el The element or DOM node to add, or its id
19713 * @return {Roo.menu.Item} The menu item that was added
19715 addElement : function(el){
19716 return this.addItem(new Roo.menu.BaseItem(el));
19720 * Adds an existing object based on {@link Roo.menu.Item} to the menu
19721 * @param {Roo.menu.Item} item The menu item to add
19722 * @return {Roo.menu.Item} The menu item that was added
19724 addItem : function(item){
19725 this.items.add(item);
19727 var li = document.createElement("li");
19728 li.className = "x-menu-list-item";
19729 this.ul.dom.appendChild(li);
19730 item.render(li, this);
19731 this.delayAutoWidth();
19737 * Creates a new {@link Roo.menu.Item} based an the supplied config object and adds it to the menu
19738 * @param {Object} config A MenuItem config object
19739 * @return {Roo.menu.Item} The menu item that was added
19741 addMenuItem : function(config){
19742 if(!(config instanceof Roo.menu.Item)){
19743 if(typeof config.checked == "boolean"){ // must be check menu item config?
19744 config = new Roo.menu.CheckItem(config);
19746 config = new Roo.menu.Item(config);
19749 return this.addItem(config);
19753 * Creates a new {@link Roo.menu.TextItem} with the supplied text and adds it to the menu
19754 * @param {String} text The text to display in the menu item
19755 * @return {Roo.menu.Item} The menu item that was added
19757 addText : function(text){
19758 return this.addItem(new Roo.menu.TextItem({ text : text }));
19762 * Inserts an existing object based on {@link Roo.menu.Item} to the menu at a specified index
19763 * @param {Number} index The index in the menu's list of current items where the new item should be inserted
19764 * @param {Roo.menu.Item} item The menu item to add
19765 * @return {Roo.menu.Item} The menu item that was added
19767 insert : function(index, item){
19768 this.items.insert(index, item);
19770 var li = document.createElement("li");
19771 li.className = "x-menu-list-item";
19772 this.ul.dom.insertBefore(li, this.ul.dom.childNodes[index]);
19773 item.render(li, this);
19774 this.delayAutoWidth();
19780 * Removes an {@link Roo.menu.Item} from the menu and destroys the object
19781 * @param {Roo.menu.Item} item The menu item to remove
19783 remove : function(item){
19784 this.items.removeKey(item.id);
19789 * Removes and destroys all items in the menu
19791 removeAll : function(){
19793 while(f = this.items.first()){
19799 // MenuNav is a private utility class used internally by the Menu
19800 Roo.menu.MenuNav = function(menu){
19801 Roo.menu.MenuNav.superclass.constructor.call(this, menu.el);
19802 this.scope = this.menu = menu;
19805 Roo.extend(Roo.menu.MenuNav, Roo.KeyNav, {
19806 doRelay : function(e, h){
19807 var k = e.getKey();
19808 if(!this.menu.activeItem && e.isNavKeyPress() && k != e.SPACE && k != e.RETURN){
19809 this.menu.tryActivate(0, 1);
19812 return h.call(this.scope || this, e, this.menu);
19815 up : function(e, m){
19816 if(!m.tryActivate(m.items.indexOf(m.activeItem)-1, -1)){
19817 m.tryActivate(m.items.length-1, -1);
19821 down : function(e, m){
19822 if(!m.tryActivate(m.items.indexOf(m.activeItem)+1, 1)){
19823 m.tryActivate(0, 1);
19827 right : function(e, m){
19829 m.activeItem.expandMenu(true);
19833 left : function(e, m){
19835 if(m.parentMenu && m.parentMenu.activeItem){
19836 m.parentMenu.activeItem.activate();
19840 enter : function(e, m){
19842 e.stopPropagation();
19843 m.activeItem.onClick(e);
19844 m.fireEvent("click", this, m.activeItem);
19850 * Ext JS Library 1.1.1
19851 * Copyright(c) 2006-2007, Ext JS, LLC.
19853 * Originally Released Under LGPL - original licence link has changed is not relivant.
19856 * <script type="text/javascript">
19860 * @class Roo.menu.MenuMgr
19861 * Provides a common registry of all menu items on a page so that they can be easily accessed by id.
19864 Roo.menu.MenuMgr = function(){
19865 var menus, active, groups = {}, attached = false, lastShow = new Date();
19867 // private - called when first menu is created
19870 active = new Roo.util.MixedCollection();
19871 Roo.get(document).addKeyListener(27, function(){
19872 if(active.length > 0){
19879 function hideAll(){
19880 if(active && active.length > 0){
19881 var c = active.clone();
19882 c.each(function(m){
19889 function onHide(m){
19891 if(active.length < 1){
19892 Roo.get(document).un("mousedown", onMouseDown);
19898 function onShow(m){
19899 var last = active.last();
19900 lastShow = new Date();
19903 Roo.get(document).on("mousedown", onMouseDown);
19907 m.getEl().setZIndex(parseInt(m.parentMenu.getEl().getStyle("z-index"), 10) + 3);
19908 m.parentMenu.activeChild = m;
19909 }else if(last && last.isVisible()){
19910 m.getEl().setZIndex(parseInt(last.getEl().getStyle("z-index"), 10) + 3);
19915 function onBeforeHide(m){
19917 m.activeChild.hide();
19919 if(m.autoHideTimer){
19920 clearTimeout(m.autoHideTimer);
19921 delete m.autoHideTimer;
19926 function onBeforeShow(m){
19927 var pm = m.parentMenu;
19928 if(!pm && !m.allowOtherMenus){
19930 }else if(pm && pm.activeChild && active != m){
19931 pm.activeChild.hide();
19936 function onMouseDown(e){
19937 if(lastShow.getElapsed() > 50 && active.length > 0 && !e.getTarget(".x-menu")){
19943 function onBeforeCheck(mi, state){
19945 var g = groups[mi.group];
19946 for(var i = 0, l = g.length; i < l; i++){
19948 g[i].setChecked(false);
19957 * Hides all menus that are currently visible
19959 hideAll : function(){
19964 register : function(menu){
19968 menus[menu.id] = menu;
19969 menu.on("beforehide", onBeforeHide);
19970 menu.on("hide", onHide);
19971 menu.on("beforeshow", onBeforeShow);
19972 menu.on("show", onShow);
19973 var g = menu.group;
19974 if(g && menu.events["checkchange"]){
19978 groups[g].push(menu);
19979 menu.on("checkchange", onCheck);
19984 * Returns a {@link Roo.menu.Menu} object
19985 * @param {String/Object} menu The string menu id, an existing menu object reference, or a Menu config that will
19986 * be used to generate and return a new Menu instance.
19988 get : function(menu){
19989 if(typeof menu == "string"){ // menu id
19990 return menus[menu];
19991 }else if(menu.events){ // menu instance
19993 }else if(typeof menu.length == 'number'){ // array of menu items?
19994 return new Roo.menu.Menu({items:menu});
19995 }else{ // otherwise, must be a config
19996 return new Roo.menu.Menu(menu);
20001 unregister : function(menu){
20002 delete menus[menu.id];
20003 menu.un("beforehide", onBeforeHide);
20004 menu.un("hide", onHide);
20005 menu.un("beforeshow", onBeforeShow);
20006 menu.un("show", onShow);
20007 var g = menu.group;
20008 if(g && menu.events["checkchange"]){
20009 groups[g].remove(menu);
20010 menu.un("checkchange", onCheck);
20015 registerCheckable : function(menuItem){
20016 var g = menuItem.group;
20021 groups[g].push(menuItem);
20022 menuItem.on("beforecheckchange", onBeforeCheck);
20027 unregisterCheckable : function(menuItem){
20028 var g = menuItem.group;
20030 groups[g].remove(menuItem);
20031 menuItem.un("beforecheckchange", onBeforeCheck);
20037 * Ext JS Library 1.1.1
20038 * Copyright(c) 2006-2007, Ext JS, LLC.
20040 * Originally Released Under LGPL - original licence link has changed is not relivant.
20043 * <script type="text/javascript">
20048 * @class Roo.menu.BaseItem
20049 * @extends Roo.Component
20050 * The base class for all items that render into menus. BaseItem provides default rendering, activated state
20051 * management and base configuration options shared by all menu components.
20053 * Creates a new BaseItem
20054 * @param {Object} config Configuration options
20056 Roo.menu.BaseItem = function(config){
20057 Roo.menu.BaseItem.superclass.constructor.call(this, config);
20062 * Fires when this item is clicked
20063 * @param {Roo.menu.BaseItem} this
20064 * @param {Roo.EventObject} e
20069 * Fires when this item is activated
20070 * @param {Roo.menu.BaseItem} this
20074 * @event deactivate
20075 * Fires when this item is deactivated
20076 * @param {Roo.menu.BaseItem} this
20082 this.on("click", this.handler, this.scope, true);
20086 Roo.extend(Roo.menu.BaseItem, Roo.Component, {
20088 * @cfg {Function} handler
20089 * A function that will handle the click event of this menu item (defaults to undefined)
20092 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to false)
20094 canActivate : false,
20096 * @cfg {String} activeClass The CSS class to use when the item becomes activated (defaults to "x-menu-item-active")
20098 activeClass : "x-menu-item-active",
20100 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to true)
20102 hideOnClick : true,
20104 * @cfg {Number} hideDelay Length of time in milliseconds to wait before hiding after a click (defaults to 100)
20109 ctype: "Roo.menu.BaseItem",
20112 actionMode : "container",
20115 render : function(container, parentMenu){
20116 this.parentMenu = parentMenu;
20117 Roo.menu.BaseItem.superclass.render.call(this, container);
20118 this.container.menuItemId = this.id;
20122 onRender : function(container, position){
20123 this.el = Roo.get(this.el);
20124 container.dom.appendChild(this.el.dom);
20128 onClick : function(e){
20129 if(!this.disabled && this.fireEvent("click", this, e) !== false
20130 && this.parentMenu.fireEvent("itemclick", this, e) !== false){
20131 this.handleClick(e);
20138 activate : function(){
20142 var li = this.container;
20143 li.addClass(this.activeClass);
20144 this.region = li.getRegion().adjust(2, 2, -2, -2);
20145 this.fireEvent("activate", this);
20150 deactivate : function(){
20151 this.container.removeClass(this.activeClass);
20152 this.fireEvent("deactivate", this);
20156 shouldDeactivate : function(e){
20157 return !this.region || !this.region.contains(e.getPoint());
20161 handleClick : function(e){
20162 if(this.hideOnClick){
20163 this.parentMenu.hide.defer(this.hideDelay, this.parentMenu, [true]);
20168 expandMenu : function(autoActivate){
20173 hideMenu : function(){
20178 * Ext JS Library 1.1.1
20179 * Copyright(c) 2006-2007, Ext JS, LLC.
20181 * Originally Released Under LGPL - original licence link has changed is not relivant.
20184 * <script type="text/javascript">
20188 * @class Roo.menu.Adapter
20189 * @extends Roo.menu.BaseItem
20190 * 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.
20191 * It provides basic rendering, activation management and enable/disable logic required to work in menus.
20193 * Creates a new Adapter
20194 * @param {Object} config Configuration options
20196 Roo.menu.Adapter = function(component, config){
20197 Roo.menu.Adapter.superclass.constructor.call(this, config);
20198 this.component = component;
20200 Roo.extend(Roo.menu.Adapter, Roo.menu.BaseItem, {
20202 canActivate : true,
20205 onRender : function(container, position){
20206 this.component.render(container);
20207 this.el = this.component.getEl();
20211 activate : function(){
20215 this.component.focus();
20216 this.fireEvent("activate", this);
20221 deactivate : function(){
20222 this.fireEvent("deactivate", this);
20226 disable : function(){
20227 this.component.disable();
20228 Roo.menu.Adapter.superclass.disable.call(this);
20232 enable : function(){
20233 this.component.enable();
20234 Roo.menu.Adapter.superclass.enable.call(this);
20238 * Ext JS Library 1.1.1
20239 * Copyright(c) 2006-2007, Ext JS, LLC.
20241 * Originally Released Under LGPL - original licence link has changed is not relivant.
20244 * <script type="text/javascript">
20248 * @class Roo.menu.TextItem
20249 * @extends Roo.menu.BaseItem
20250 * Adds a static text string to a menu, usually used as either a heading or group separator.
20251 * Note: old style constructor with text is still supported.
20254 * Creates a new TextItem
20255 * @param {Object} cfg Configuration
20257 Roo.menu.TextItem = function(cfg){
20258 if (typeof(cfg) == 'string') {
20261 Roo.apply(this,cfg);
20264 Roo.menu.TextItem.superclass.constructor.call(this);
20267 Roo.extend(Roo.menu.TextItem, Roo.menu.BaseItem, {
20269 * @cfg {Boolean} text Text to show on item.
20274 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20276 hideOnClick : false,
20278 * @cfg {String} itemCls The default CSS class to use for text items (defaults to "x-menu-text")
20280 itemCls : "x-menu-text",
20283 onRender : function(){
20284 var s = document.createElement("span");
20285 s.className = this.itemCls;
20286 s.innerHTML = this.text;
20288 Roo.menu.TextItem.superclass.onRender.apply(this, arguments);
20292 * Ext JS Library 1.1.1
20293 * Copyright(c) 2006-2007, Ext JS, LLC.
20295 * Originally Released Under LGPL - original licence link has changed is not relivant.
20298 * <script type="text/javascript">
20302 * @class Roo.menu.Separator
20303 * @extends Roo.menu.BaseItem
20304 * Adds a separator bar to a menu, used to divide logical groups of menu items. Generally you will
20305 * add one of these by using "-" in you call to add() or in your items config rather than creating one directly.
20307 * @param {Object} config Configuration options
20309 Roo.menu.Separator = function(config){
20310 Roo.menu.Separator.superclass.constructor.call(this, config);
20313 Roo.extend(Roo.menu.Separator, Roo.menu.BaseItem, {
20315 * @cfg {String} itemCls The default CSS class to use for separators (defaults to "x-menu-sep")
20317 itemCls : "x-menu-sep",
20319 * @cfg {Boolean} hideOnClick True to hide the containing menu after this item is clicked (defaults to false)
20321 hideOnClick : false,
20324 onRender : function(li){
20325 var s = document.createElement("span");
20326 s.className = this.itemCls;
20327 s.innerHTML = " ";
20329 li.addClass("x-menu-sep-li");
20330 Roo.menu.Separator.superclass.onRender.apply(this, arguments);
20334 * Ext JS Library 1.1.1
20335 * Copyright(c) 2006-2007, Ext JS, LLC.
20337 * Originally Released Under LGPL - original licence link has changed is not relivant.
20340 * <script type="text/javascript">
20343 * @class Roo.menu.Item
20344 * @extends Roo.menu.BaseItem
20345 * A base class for all menu items that require menu-related functionality (like sub-menus) and are not static
20346 * display items. Item extends the base functionality of {@link Roo.menu.BaseItem} by adding menu-specific
20347 * activation and click handling.
20349 * Creates a new Item
20350 * @param {Object} config Configuration options
20352 Roo.menu.Item = function(config){
20353 Roo.menu.Item.superclass.constructor.call(this, config);
20355 this.menu = Roo.menu.MenuMgr.get(this.menu);
20358 Roo.extend(Roo.menu.Item, Roo.menu.BaseItem, {
20361 * @cfg {String} text
20362 * The text to show on the menu item.
20366 * @cfg {String} HTML to render in menu
20367 * The text to show on the menu item (HTML version).
20371 * @cfg {String} icon
20372 * The path to an icon to display in this menu item (defaults to Roo.BLANK_IMAGE_URL)
20376 * @cfg {String} itemCls The default CSS class to use for menu items (defaults to "x-menu-item")
20378 itemCls : "x-menu-item",
20380 * @cfg {Boolean} canActivate True if this item can be visually activated (defaults to true)
20382 canActivate : true,
20384 * @cfg {Number} showDelay Length of time in milliseconds to wait before showing this item (defaults to 200)
20387 // doc'd in BaseItem
20391 ctype: "Roo.menu.Item",
20394 onRender : function(container, position){
20395 var el = document.createElement("a");
20396 el.hideFocus = true;
20397 el.unselectable = "on";
20398 el.href = this.href || "#";
20399 if(this.hrefTarget){
20400 el.target = this.hrefTarget;
20402 el.className = this.itemCls + (this.menu ? " x-menu-item-arrow" : "") + (this.cls ? " " + this.cls : "");
20404 var html = this.html.length ? this.html : String.format('{0}',this.text);
20406 el.innerHTML = String.format(
20407 '<img src="{0}" class="x-menu-item-icon {1}" />' + html,
20408 this.icon || Roo.BLANK_IMAGE_URL, this.iconCls || '');
20410 Roo.menu.Item.superclass.onRender.call(this, container, position);
20414 * Sets the text to display in this menu item
20415 * @param {String} text The text to display
20416 * @param {Boolean} isHTML true to indicate text is pure html.
20418 setText : function(text, isHTML){
20426 var html = this.html.length ? this.html : String.format('{0}',this.text);
20428 this.el.update(String.format(
20429 '<img src="{0}" class="x-menu-item-icon {2}">' + html,
20430 this.icon || Roo.BLANK_IMAGE_URL, this.text, this.iconCls || ''));
20431 this.parentMenu.autoWidth();
20436 handleClick : function(e){
20437 if(!this.href){ // if no link defined, stop the event automatically
20440 Roo.menu.Item.superclass.handleClick.apply(this, arguments);
20444 activate : function(autoExpand){
20445 if(Roo.menu.Item.superclass.activate.apply(this, arguments)){
20455 shouldDeactivate : function(e){
20456 if(Roo.menu.Item.superclass.shouldDeactivate.call(this, e)){
20457 if(this.menu && this.menu.isVisible()){
20458 return !this.menu.getEl().getRegion().contains(e.getPoint());
20466 deactivate : function(){
20467 Roo.menu.Item.superclass.deactivate.apply(this, arguments);
20472 expandMenu : function(autoActivate){
20473 if(!this.disabled && this.menu){
20474 clearTimeout(this.hideTimer);
20475 delete this.hideTimer;
20476 if(!this.menu.isVisible() && !this.showTimer){
20477 this.showTimer = this.deferExpand.defer(this.showDelay, this, [autoActivate]);
20478 }else if (this.menu.isVisible() && autoActivate){
20479 this.menu.tryActivate(0, 1);
20485 deferExpand : function(autoActivate){
20486 delete this.showTimer;
20487 this.menu.show(this.container, this.parentMenu.subMenuAlign || "tl-tr?", this.parentMenu);
20489 this.menu.tryActivate(0, 1);
20494 hideMenu : function(){
20495 clearTimeout(this.showTimer);
20496 delete this.showTimer;
20497 if(!this.hideTimer && this.menu && this.menu.isVisible()){
20498 this.hideTimer = this.deferHide.defer(this.hideDelay, this);
20503 deferHide : function(){
20504 delete this.hideTimer;
20509 * Ext JS Library 1.1.1
20510 * Copyright(c) 2006-2007, Ext JS, LLC.
20512 * Originally Released Under LGPL - original licence link has changed is not relivant.
20515 * <script type="text/javascript">
20519 * @class Roo.menu.CheckItem
20520 * @extends Roo.menu.Item
20521 * Adds a menu item that contains a checkbox by default, but can also be part of a radio group.
20523 * Creates a new CheckItem
20524 * @param {Object} config Configuration options
20526 Roo.menu.CheckItem = function(config){
20527 Roo.menu.CheckItem.superclass.constructor.call(this, config);
20530 * @event beforecheckchange
20531 * Fires before the checked value is set, providing an opportunity to cancel if needed
20532 * @param {Roo.menu.CheckItem} this
20533 * @param {Boolean} checked The new checked value that will be set
20535 "beforecheckchange" : true,
20537 * @event checkchange
20538 * Fires after the checked value has been set
20539 * @param {Roo.menu.CheckItem} this
20540 * @param {Boolean} checked The checked value that was set
20542 "checkchange" : true
20544 if(this.checkHandler){
20545 this.on('checkchange', this.checkHandler, this.scope);
20548 Roo.extend(Roo.menu.CheckItem, Roo.menu.Item, {
20550 * @cfg {String} group
20551 * All check items with the same group name will automatically be grouped into a single-select
20552 * radio button group (defaults to '')
20555 * @cfg {String} itemCls The default CSS class to use for check items (defaults to "x-menu-item x-menu-check-item")
20557 itemCls : "x-menu-item x-menu-check-item",
20559 * @cfg {String} groupClass The default CSS class to use for radio group check items (defaults to "x-menu-group-item")
20561 groupClass : "x-menu-group-item",
20564 * @cfg {Boolean} checked True to initialize this checkbox as checked (defaults to false). Note that
20565 * if this checkbox is part of a radio group (group = true) only the last item in the group that is
20566 * initialized with checked = true will be rendered as checked.
20571 ctype: "Roo.menu.CheckItem",
20574 onRender : function(c){
20575 Roo.menu.CheckItem.superclass.onRender.apply(this, arguments);
20577 this.el.addClass(this.groupClass);
20579 Roo.menu.MenuMgr.registerCheckable(this);
20581 this.checked = false;
20582 this.setChecked(true, true);
20587 destroy : function(){
20589 Roo.menu.MenuMgr.unregisterCheckable(this);
20591 Roo.menu.CheckItem.superclass.destroy.apply(this, arguments);
20595 * Set the checked state of this item
20596 * @param {Boolean} checked The new checked value
20597 * @param {Boolean} suppressEvent (optional) True to prevent the checkchange event from firing (defaults to false)
20599 setChecked : function(state, suppressEvent){
20600 if(this.checked != state && this.fireEvent("beforecheckchange", this, state) !== false){
20601 if(this.container){
20602 this.container[state ? "addClass" : "removeClass"]("x-menu-item-checked");
20604 this.checked = state;
20605 if(suppressEvent !== true){
20606 this.fireEvent("checkchange", this, state);
20612 handleClick : function(e){
20613 if(!this.disabled && !(this.checked && this.group)){// disable unselect on radio item
20614 this.setChecked(!this.checked);
20616 Roo.menu.CheckItem.superclass.handleClick.apply(this, arguments);
20620 * Ext JS Library 1.1.1
20621 * Copyright(c) 2006-2007, Ext JS, LLC.
20623 * Originally Released Under LGPL - original licence link has changed is not relivant.
20626 * <script type="text/javascript">
20630 * @class Roo.menu.DateItem
20631 * @extends Roo.menu.Adapter
20632 * A menu item that wraps the {@link Roo.DatPicker} component.
20634 * Creates a new DateItem
20635 * @param {Object} config Configuration options
20637 Roo.menu.DateItem = function(config){
20638 Roo.menu.DateItem.superclass.constructor.call(this, new Roo.DatePicker(config), config);
20639 /** The Roo.DatePicker object @type Roo.DatePicker */
20640 this.picker = this.component;
20641 this.addEvents({select: true});
20643 this.picker.on("render", function(picker){
20644 picker.getEl().swallowEvent("click");
20645 picker.container.addClass("x-menu-date-item");
20648 this.picker.on("select", this.onSelect, this);
20651 Roo.extend(Roo.menu.DateItem, Roo.menu.Adapter, {
20653 onSelect : function(picker, date){
20654 this.fireEvent("select", this, date, picker);
20655 Roo.menu.DateItem.superclass.handleClick.call(this);
20659 * Ext JS Library 1.1.1
20660 * Copyright(c) 2006-2007, Ext JS, LLC.
20662 * Originally Released Under LGPL - original licence link has changed is not relivant.
20665 * <script type="text/javascript">
20669 * @class Roo.menu.ColorItem
20670 * @extends Roo.menu.Adapter
20671 * A menu item that wraps the {@link Roo.ColorPalette} component.
20673 * Creates a new ColorItem
20674 * @param {Object} config Configuration options
20676 Roo.menu.ColorItem = function(config){
20677 Roo.menu.ColorItem.superclass.constructor.call(this, new Roo.ColorPalette(config), config);
20678 /** The Roo.ColorPalette object @type Roo.ColorPalette */
20679 this.palette = this.component;
20680 this.relayEvents(this.palette, ["select"]);
20681 if(this.selectHandler){
20682 this.on('select', this.selectHandler, this.scope);
20685 Roo.extend(Roo.menu.ColorItem, Roo.menu.Adapter);/*
20687 * Ext JS Library 1.1.1
20688 * Copyright(c) 2006-2007, Ext JS, LLC.
20690 * Originally Released Under LGPL - original licence link has changed is not relivant.
20693 * <script type="text/javascript">
20698 * @class Roo.menu.DateMenu
20699 * @extends Roo.menu.Menu
20700 * A menu containing a {@link Roo.menu.DateItem} component (which provides a date picker).
20702 * Creates a new DateMenu
20703 * @param {Object} config Configuration options
20705 Roo.menu.DateMenu = function(config){
20706 Roo.menu.DateMenu.superclass.constructor.call(this, config);
20708 var di = new Roo.menu.DateItem(config);
20711 * The {@link Roo.DatePicker} instance for this DateMenu
20714 this.picker = di.picker;
20717 * @param {DatePicker} picker
20718 * @param {Date} date
20720 this.relayEvents(di, ["select"]);
20722 this.on('beforeshow', function(){
20724 this.picker.hideMonthPicker(true);
20728 Roo.extend(Roo.menu.DateMenu, Roo.menu.Menu, {
20732 * Ext JS Library 1.1.1
20733 * Copyright(c) 2006-2007, Ext JS, LLC.
20735 * Originally Released Under LGPL - original licence link has changed is not relivant.
20738 * <script type="text/javascript">
20743 * @class Roo.menu.ColorMenu
20744 * @extends Roo.menu.Menu
20745 * A menu containing a {@link Roo.menu.ColorItem} component (which provides a basic color picker).
20747 * Creates a new ColorMenu
20748 * @param {Object} config Configuration options
20750 Roo.menu.ColorMenu = function(config){
20751 Roo.menu.ColorMenu.superclass.constructor.call(this, config);
20753 var ci = new Roo.menu.ColorItem(config);
20756 * The {@link Roo.ColorPalette} instance for this ColorMenu
20757 * @type ColorPalette
20759 this.palette = ci.palette;
20762 * @param {ColorPalette} palette
20763 * @param {String} color
20765 this.relayEvents(ci, ["select"]);
20767 Roo.extend(Roo.menu.ColorMenu, Roo.menu.Menu);/*
20769 * Ext JS Library 1.1.1
20770 * Copyright(c) 2006-2007, Ext JS, LLC.
20772 * Originally Released Under LGPL - original licence link has changed is not relivant.
20775 * <script type="text/javascript">
20779 * @class Roo.form.Field
20780 * @extends Roo.BoxComponent
20781 * Base class for form fields that provides default event handling, sizing, value handling and other functionality.
20783 * Creates a new Field
20784 * @param {Object} config Configuration options
20786 Roo.form.Field = function(config){
20787 Roo.form.Field.superclass.constructor.call(this, config);
20790 Roo.extend(Roo.form.Field, Roo.BoxComponent, {
20792 * @cfg {String} fieldLabel Label to use when rendering a form.
20795 * @cfg {String} qtip Mouse over tip
20799 * @cfg {String} invalidClass The CSS class to use when marking a field invalid (defaults to "x-form-invalid")
20801 invalidClass : "x-form-invalid",
20803 * @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")
20805 invalidText : "The value in this field is invalid",
20807 * @cfg {String} focusClass The CSS class to use when the field receives focus (defaults to "x-form-focus")
20809 focusClass : "x-form-focus",
20811 * @cfg {String/Boolean} validationEvent The event that should initiate field validation. Set to false to disable
20812 automatic validation (defaults to "keyup").
20814 validationEvent : "keyup",
20816 * @cfg {Boolean} validateOnBlur Whether the field should validate when it loses focus (defaults to true).
20818 validateOnBlur : true,
20820 * @cfg {Number} validationDelay The length of time in milliseconds after user input begins until validation is initiated (defaults to 250)
20822 validationDelay : 250,
20824 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
20825 * {tag: "input", type: "text", size: "20", autocomplete: "off"})
20827 defaultAutoCreate : {tag: "input", type: "text", size: "20", autocomplete: "off"},
20829 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field")
20831 fieldClass : "x-form-field",
20833 * @cfg {String} msgTarget The location where error text should display. Should be one of the following values (defaults to 'qtip'):
20836 ----------- ----------------------------------------------------------------------
20837 qtip Display a quick tip when the user hovers over the field
20838 title Display a default browser title attribute popup
20839 under Add a block div beneath the field containing the error text
20840 side Add an error icon to the right of the field with a popup on hover
20841 [element id] Add the error text directly to the innerHTML of the specified element
20844 msgTarget : 'qtip',
20846 * @cfg {String} msgFx <b>Experimental</b> The effect used when displaying a validation message under the field (defaults to 'normal').
20851 * @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.
20856 * @cfg {Boolean} disabled True to disable the field (defaults to false).
20861 * @cfg {String} inputType The type attribute for input fields -- e.g. radio, text, password (defaults to "text").
20863 inputType : undefined,
20866 * @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).
20868 tabIndex : undefined,
20871 isFormField : true,
20876 * @property {Roo.Element} fieldEl
20877 * Element Containing the rendered Field (with label etc.)
20880 * @cfg {Mixed} value A value to initialize this field with.
20885 * @cfg {String} name The field's HTML name attribute.
20888 * @cfg {String} cls A CSS class to apply to the field's underlying element.
20892 initComponent : function(){
20893 Roo.form.Field.superclass.initComponent.call(this);
20897 * Fires when this field receives input focus.
20898 * @param {Roo.form.Field} this
20903 * Fires when this field loses input focus.
20904 * @param {Roo.form.Field} this
20908 * @event specialkey
20909 * Fires when any key related to navigation (arrows, tab, enter, esc, etc.) is pressed. You can check
20910 * {@link Roo.EventObject#getKey} to determine which key was pressed.
20911 * @param {Roo.form.Field} this
20912 * @param {Roo.EventObject} e The event object
20917 * Fires just before the field blurs if the field value has changed.
20918 * @param {Roo.form.Field} this
20919 * @param {Mixed} newValue The new value
20920 * @param {Mixed} oldValue The original value
20925 * Fires after the field has been marked as invalid.
20926 * @param {Roo.form.Field} this
20927 * @param {String} msg The validation message
20932 * Fires after the field has been validated with no errors.
20933 * @param {Roo.form.Field} this
20938 * Fires after the key up
20939 * @param {Roo.form.Field} this
20940 * @param {Roo.EventObject} e The event Object
20947 * Returns the name attribute of the field if available
20948 * @return {String} name The field name
20950 getName: function(){
20951 return this.rendered && this.el.dom.name ? this.el.dom.name : (this.hiddenName || '');
20955 onRender : function(ct, position){
20956 Roo.form.Field.superclass.onRender.call(this, ct, position);
20958 var cfg = this.getAutoCreate();
20960 cfg.name = this.name || this.id;
20962 if(this.inputType){
20963 cfg.type = this.inputType;
20965 this.el = ct.createChild(cfg, position);
20967 var type = this.el.dom.type;
20969 if(type == 'password'){
20972 this.el.addClass('x-form-'+type);
20975 this.el.dom.readOnly = true;
20977 if(this.tabIndex !== undefined){
20978 this.el.dom.setAttribute('tabIndex', this.tabIndex);
20981 this.el.addClass([this.fieldClass, this.cls]);
20986 * Apply the behaviors of this component to an existing element. <b>This is used instead of render().</b>
20987 * @param {String/HTMLElement/Element} el The id of the node, a DOM node or an existing Element
20988 * @return {Roo.form.Field} this
20990 applyTo : function(target){
20991 this.allowDomMove = false;
20992 this.el = Roo.get(target);
20993 this.render(this.el.dom.parentNode);
20998 initValue : function(){
20999 if(this.value !== undefined){
21000 this.setValue(this.value);
21001 }else if(this.el.dom.value.length > 0){
21002 this.setValue(this.el.dom.value);
21007 * Returns true if this field has been changed since it was originally loaded and is not disabled.
21009 isDirty : function() {
21010 if(this.disabled) {
21013 return String(this.getValue()) !== String(this.originalValue);
21017 afterRender : function(){
21018 Roo.form.Field.superclass.afterRender.call(this);
21023 fireKey : function(e){
21024 //Roo.log('field ' + e.getKey());
21025 if(e.isNavKeyPress()){
21026 this.fireEvent("specialkey", this, e);
21031 * Resets the current field value to the originally loaded value and clears any validation messages
21033 reset : function(){
21034 this.setValue(this.originalValue);
21035 this.clearInvalid();
21039 initEvents : function(){
21040 // safari killled keypress - so keydown is now used..
21041 this.el.on("keydown" , this.fireKey, this);
21042 this.el.on("focus", this.onFocus, this);
21043 this.el.on("blur", this.onBlur, this);
21044 this.el.relayEvent('keyup', this);
21046 // reference to original value for reset
21047 this.originalValue = this.getValue();
21051 onFocus : function(){
21052 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21053 this.el.addClass(this.focusClass);
21055 if(!this.hasFocus){
21056 this.hasFocus = true;
21057 this.startValue = this.getValue();
21058 this.fireEvent("focus", this);
21062 beforeBlur : Roo.emptyFn,
21065 onBlur : function(){
21067 if(!Roo.isOpera && this.focusClass){ // don't touch in Opera
21068 this.el.removeClass(this.focusClass);
21070 this.hasFocus = false;
21071 if(this.validationEvent !== false && this.validateOnBlur && this.validationEvent != "blur"){
21074 var v = this.getValue();
21075 if(String(v) !== String(this.startValue)){
21076 this.fireEvent('change', this, v, this.startValue);
21078 this.fireEvent("blur", this);
21082 * Returns whether or not the field value is currently valid
21083 * @param {Boolean} preventMark True to disable marking the field invalid
21084 * @return {Boolean} True if the value is valid, else false
21086 isValid : function(preventMark){
21090 var restore = this.preventMark;
21091 this.preventMark = preventMark === true;
21092 var v = this.validateValue(this.processValue(this.getRawValue()));
21093 this.preventMark = restore;
21098 * Validates the field value
21099 * @return {Boolean} True if the value is valid, else false
21101 validate : function(){
21102 if(this.disabled || this.validateValue(this.processValue(this.getRawValue()))){
21103 this.clearInvalid();
21109 processValue : function(value){
21114 // Subclasses should provide the validation implementation by overriding this
21115 validateValue : function(value){
21120 * Mark this field as invalid
21121 * @param {String} msg The validation message
21123 markInvalid : function(msg){
21124 if(!this.rendered || this.preventMark){ // not rendered
21127 this.el.addClass(this.invalidClass);
21128 msg = msg || this.invalidText;
21129 switch(this.msgTarget){
21131 this.el.dom.qtip = msg;
21132 this.el.dom.qclass = 'x-form-invalid-tip';
21133 if(Roo.QuickTips){ // fix for floating editors interacting with DND
21134 Roo.QuickTips.enable();
21138 this.el.dom.title = msg;
21142 var elp = this.el.findParent('.x-form-element', 5, true);
21143 this.errorEl = elp.createChild({cls:'x-form-invalid-msg'});
21144 this.errorEl.setWidth(elp.getWidth(true)-20);
21146 this.errorEl.update(msg);
21147 Roo.form.Field.msgFx[this.msgFx].show(this.errorEl, this);
21150 if(!this.errorIcon){
21151 var elp = this.el.findParent('.x-form-element', 5, true);
21152 this.errorIcon = elp.createChild({cls:'x-form-invalid-icon'});
21154 this.alignErrorIcon();
21155 this.errorIcon.dom.qtip = msg;
21156 this.errorIcon.dom.qclass = 'x-form-invalid-tip';
21157 this.errorIcon.show();
21158 this.on('resize', this.alignErrorIcon, this);
21161 var t = Roo.getDom(this.msgTarget);
21163 t.style.display = this.msgDisplay;
21166 this.fireEvent('invalid', this, msg);
21170 alignErrorIcon : function(){
21171 this.errorIcon.alignTo(this.el, 'tl-tr', [2, 0]);
21175 * Clear any invalid styles/messages for this field
21177 clearInvalid : function(){
21178 if(!this.rendered || this.preventMark){ // not rendered
21181 this.el.removeClass(this.invalidClass);
21182 switch(this.msgTarget){
21184 this.el.dom.qtip = '';
21187 this.el.dom.title = '';
21191 Roo.form.Field.msgFx[this.msgFx].hide(this.errorEl, this);
21195 if(this.errorIcon){
21196 this.errorIcon.dom.qtip = '';
21197 this.errorIcon.hide();
21198 this.un('resize', this.alignErrorIcon, this);
21202 var t = Roo.getDom(this.msgTarget);
21204 t.style.display = 'none';
21207 this.fireEvent('valid', this);
21211 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
21212 * @return {Mixed} value The field value
21214 getRawValue : function(){
21215 var v = this.el.getValue();
21216 if(v === this.emptyText){
21223 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
21224 * @return {Mixed} value The field value
21226 getValue : function(){
21227 var v = this.el.getValue();
21228 if(v === this.emptyText || v === undefined){
21235 * Sets the underlying DOM field's value directly, bypassing validation. To set the value with validation see {@link #setValue}.
21236 * @param {Mixed} value The value to set
21238 setRawValue : function(v){
21239 return this.el.dom.value = (v === null || v === undefined ? '' : v);
21243 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
21244 * @param {Mixed} value The value to set
21246 setValue : function(v){
21249 this.el.dom.value = (v === null || v === undefined ? '' : v);
21254 adjustSize : function(w, h){
21255 var s = Roo.form.Field.superclass.adjustSize.call(this, w, h);
21256 s.width = this.adjustWidth(this.el.dom.tagName, s.width);
21260 adjustWidth : function(tag, w){
21261 tag = tag.toLowerCase();
21262 if(typeof w == 'number' && Roo.isStrict && !Roo.isSafari){
21263 if(Roo.isIE && (tag == 'input' || tag == 'textarea')){
21264 if(tag == 'input'){
21267 if(tag = 'textarea'){
21270 }else if(Roo.isOpera){
21271 if(tag == 'input'){
21274 if(tag = 'textarea'){
21284 // anything other than normal should be considered experimental
21285 Roo.form.Field.msgFx = {
21287 show: function(msgEl, f){
21288 msgEl.setDisplayed('block');
21291 hide : function(msgEl, f){
21292 msgEl.setDisplayed(false).update('');
21297 show: function(msgEl, f){
21298 msgEl.slideIn('t', {stopFx:true});
21301 hide : function(msgEl, f){
21302 msgEl.slideOut('t', {stopFx:true,useDisplay:true});
21307 show: function(msgEl, f){
21308 msgEl.fixDisplay();
21309 msgEl.alignTo(f.el, 'tl-tr');
21310 msgEl.slideIn('l', {stopFx:true});
21313 hide : function(msgEl, f){
21314 msgEl.slideOut('l', {stopFx:true,useDisplay:true});
21319 * Ext JS Library 1.1.1
21320 * Copyright(c) 2006-2007, Ext JS, LLC.
21322 * Originally Released Under LGPL - original licence link has changed is not relivant.
21325 * <script type="text/javascript">
21330 * @class Roo.form.TextField
21331 * @extends Roo.form.Field
21332 * Basic text field. Can be used as a direct replacement for traditional text inputs, or as the base
21333 * class for more sophisticated input controls (like {@link Roo.form.TextArea} and {@link Roo.form.ComboBox}).
21335 * Creates a new TextField
21336 * @param {Object} config Configuration options
21338 Roo.form.TextField = function(config){
21339 Roo.form.TextField.superclass.constructor.call(this, config);
21343 * Fires when the autosize function is triggered. The field may or may not have actually changed size
21344 * according to the default logic, but this event provides a hook for the developer to apply additional
21345 * logic at runtime to resize the field if needed.
21346 * @param {Roo.form.Field} this This text field
21347 * @param {Number} width The new field width
21353 Roo.extend(Roo.form.TextField, Roo.form.Field, {
21355 * @cfg {Boolean} grow True if this field should automatically grow and shrink to its content
21359 * @cfg {Number} growMin The minimum width to allow when grow = true (defaults to 30)
21363 * @cfg {Number} growMax The maximum width to allow when grow = true (defaults to 800)
21367 * @cfg {String} vtype A validation type name as defined in {@link Roo.form.VTypes} (defaults to null)
21371 * @cfg {String} maskRe An input mask regular expression that will be used to filter keystrokes that don't match (defaults to null)
21375 * @cfg {Boolean} disableKeyFilter True to disable input keystroke filtering (defaults to false)
21377 disableKeyFilter : false,
21379 * @cfg {Boolean} allowBlank False to validate that the value length > 0 (defaults to true)
21383 * @cfg {Number} minLength Minimum input field length required (defaults to 0)
21387 * @cfg {Number} maxLength Maximum input field length allowed (defaults to Number.MAX_VALUE)
21389 maxLength : Number.MAX_VALUE,
21391 * @cfg {String} minLengthText Error text to display if the minimum length validation fails (defaults to "The minimum length for this field is {minLength}")
21393 minLengthText : "The minimum length for this field is {0}",
21395 * @cfg {String} maxLengthText Error text to display if the maximum length validation fails (defaults to "The maximum length for this field is {maxLength}")
21397 maxLengthText : "The maximum length for this field is {0}",
21399 * @cfg {Boolean} selectOnFocus True to automatically select any existing field text when the field receives input focus (defaults to false)
21401 selectOnFocus : false,
21403 * @cfg {String} blankText Error text to display if the allow blank validation fails (defaults to "This field is required")
21405 blankText : "This field is required",
21407 * @cfg {Function} validator A custom validation function to be called during field validation (defaults to null).
21408 * If available, this function will be called only after the basic validators all return true, and will be passed the
21409 * current field value and expected to return boolean true if the value is valid or a string error message if invalid.
21413 * @cfg {RegExp} regex A JavaScript RegExp object to be tested against the field value during validation (defaults to null).
21414 * If available, this regex will be evaluated only after the basic validators all return true, and will be passed the
21415 * current field value. If the test fails, the field will be marked invalid using {@link #regexText}.
21419 * @cfg {String} regexText The error text to display if {@link #regex} is used and the test fails during validation (defaults to "")
21423 * @cfg {String} emptyText The default text to display in an empty field (defaults to null).
21427 * @cfg {String} emptyClass The CSS class to apply to an empty field to style the {@link #emptyText} (defaults to
21428 * 'x-form-empty-field'). This class is automatically added and removed as needed depending on the current field value.
21430 emptyClass : 'x-form-empty-field',
21433 initEvents : function(){
21434 Roo.form.TextField.superclass.initEvents.call(this);
21435 if(this.validationEvent == 'keyup'){
21436 this.validationTask = new Roo.util.DelayedTask(this.validate, this);
21437 this.el.on('keyup', this.filterValidation, this);
21439 else if(this.validationEvent !== false){
21440 this.el.on(this.validationEvent, this.validate, this, {buffer: this.validationDelay});
21442 if(this.selectOnFocus || this.emptyText){
21443 this.on("focus", this.preFocus, this);
21444 if(this.emptyText){
21445 this.on('blur', this.postBlur, this);
21446 this.applyEmptyText();
21449 if(this.maskRe || (this.vtype && this.disableKeyFilter !== true && (this.maskRe = Roo.form.VTypes[this.vtype+'Mask']))){
21450 this.el.on("keypress", this.filterKeys, this);
21453 this.el.on("keyup", this.onKeyUp, this, {buffer:50});
21454 this.el.on("click", this.autoSize, this);
21458 processValue : function(value){
21459 if(this.stripCharsRe){
21460 var newValue = value.replace(this.stripCharsRe, '');
21461 if(newValue !== value){
21462 this.setRawValue(newValue);
21469 filterValidation : function(e){
21470 if(!e.isNavKeyPress()){
21471 this.validationTask.delay(this.validationDelay);
21476 onKeyUp : function(e){
21477 if(!e.isNavKeyPress()){
21483 * Resets the current field value to the originally-loaded value and clears any validation messages.
21484 * Also adds emptyText and emptyClass if the original value was blank.
21486 reset : function(){
21487 Roo.form.TextField.superclass.reset.call(this);
21488 this.applyEmptyText();
21491 applyEmptyText : function(){
21492 if(this.rendered && this.emptyText && this.getRawValue().length < 1){
21493 this.setRawValue(this.emptyText);
21494 this.el.addClass(this.emptyClass);
21499 preFocus : function(){
21500 if(this.emptyText){
21501 if(this.el.dom.value == this.emptyText){
21502 this.setRawValue('');
21504 this.el.removeClass(this.emptyClass);
21506 if(this.selectOnFocus){
21507 this.el.dom.select();
21512 postBlur : function(){
21513 this.applyEmptyText();
21517 filterKeys : function(e){
21518 var k = e.getKey();
21519 if(!Roo.isIE && (e.isNavKeyPress() || k == e.BACKSPACE || (k == e.DELETE && e.button == -1))){
21522 var c = e.getCharCode(), cc = String.fromCharCode(c);
21523 if(Roo.isIE && (e.isSpecialKey() || !cc)){
21526 if(!this.maskRe.test(cc)){
21531 setValue : function(v){
21532 if(this.emptyText && this.el && v !== undefined && v !== null && v !== ''){
21533 this.el.removeClass(this.emptyClass);
21535 Roo.form.TextField.superclass.setValue.apply(this, arguments);
21536 this.applyEmptyText();
21541 * Validates a value according to the field's validation rules and marks the field as invalid
21542 * if the validation fails
21543 * @param {Mixed} value The value to validate
21544 * @return {Boolean} True if the value is valid, else false
21546 validateValue : function(value){
21547 if(value.length < 1 || value === this.emptyText){ // if it's blank
21548 if(this.allowBlank){
21549 this.clearInvalid();
21552 this.markInvalid(this.blankText);
21556 if(value.length < this.minLength){
21557 this.markInvalid(String.format(this.minLengthText, this.minLength));
21560 if(value.length > this.maxLength){
21561 this.markInvalid(String.format(this.maxLengthText, this.maxLength));
21565 var vt = Roo.form.VTypes;
21566 if(!vt[this.vtype](value, this)){
21567 this.markInvalid(this.vtypeText || vt[this.vtype +'Text']);
21571 if(typeof this.validator == "function"){
21572 var msg = this.validator(value);
21574 this.markInvalid(msg);
21578 if(this.regex && !this.regex.test(value)){
21579 this.markInvalid(this.regexText);
21586 * Selects text in this field
21587 * @param {Number} start (optional) The index where the selection should start (defaults to 0)
21588 * @param {Number} end (optional) The index where the selection should end (defaults to the text length)
21590 selectText : function(start, end){
21591 var v = this.getRawValue();
21593 start = start === undefined ? 0 : start;
21594 end = end === undefined ? v.length : end;
21595 var d = this.el.dom;
21596 if(d.setSelectionRange){
21597 d.setSelectionRange(start, end);
21598 }else if(d.createTextRange){
21599 var range = d.createTextRange();
21600 range.moveStart("character", start);
21601 range.moveEnd("character", v.length-end);
21608 * Automatically grows the field to accomodate the width of the text up to the maximum field width allowed.
21609 * This only takes effect if grow = true, and fires the autosize event.
21611 autoSize : function(){
21612 if(!this.grow || !this.rendered){
21616 this.metrics = Roo.util.TextMetrics.createInstance(this.el);
21619 var v = el.dom.value;
21620 var d = document.createElement('div');
21621 d.appendChild(document.createTextNode(v));
21625 var w = Math.min(this.growMax, Math.max(this.metrics.getWidth(v) + /* add extra padding */ 10, this.growMin));
21626 this.el.setWidth(w);
21627 this.fireEvent("autosize", this, w);
21631 * Ext JS Library 1.1.1
21632 * Copyright(c) 2006-2007, Ext JS, LLC.
21634 * Originally Released Under LGPL - original licence link has changed is not relivant.
21637 * <script type="text/javascript">
21641 * @class Roo.form.Hidden
21642 * @extends Roo.form.TextField
21643 * Simple Hidden element used on forms
21645 * usage: form.add(new Roo.form.HiddenField({ 'name' : 'test1' }));
21648 * Creates a new Hidden form element.
21649 * @param {Object} config Configuration options
21654 // easy hidden field...
21655 Roo.form.Hidden = function(config){
21656 Roo.form.Hidden.superclass.constructor.call(this, config);
21659 Roo.extend(Roo.form.Hidden, Roo.form.TextField, {
21661 inputType: 'hidden',
21664 labelSeparator: '',
21666 itemCls : 'x-form-item-display-none'
21674 * Ext JS Library 1.1.1
21675 * Copyright(c) 2006-2007, Ext JS, LLC.
21677 * Originally Released Under LGPL - original licence link has changed is not relivant.
21680 * <script type="text/javascript">
21684 * @class Roo.form.TriggerField
21685 * @extends Roo.form.TextField
21686 * Provides a convenient wrapper for TextFields that adds a clickable trigger button (looks like a combobox by default).
21687 * The trigger has no default action, so you must assign a function to implement the trigger click handler by
21688 * overriding {@link #onTriggerClick}. You can create a TriggerField directly, as it renders exactly like a combobox
21689 * for which you can provide a custom implementation. For example:
21691 var trigger = new Roo.form.TriggerField();
21692 trigger.onTriggerClick = myTriggerFn;
21693 trigger.applyTo('my-field');
21696 * However, in general you will most likely want to use TriggerField as the base class for a reusable component.
21697 * {@link Roo.form.DateField} and {@link Roo.form.ComboBox} are perfect examples of this.
21698 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
21699 * class 'x-form-trigger' by default and triggerClass will be <b>appended</b> if specified.
21701 * Create a new TriggerField.
21702 * @param {Object} config Configuration options (valid {@Roo.form.TextField} config options will also be applied
21703 * to the base TextField)
21705 Roo.form.TriggerField = function(config){
21706 this.mimicing = false;
21707 Roo.form.TriggerField.superclass.constructor.call(this, config);
21710 Roo.extend(Roo.form.TriggerField, Roo.form.TextField, {
21712 * @cfg {String} triggerClass A CSS class to apply to the trigger
21715 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21716 * {tag: "input", type: "text", size: "16", autocomplete: "off"})
21718 defaultAutoCreate : {tag: "input", type: "text", size: "16", autocomplete: "off"},
21720 * @cfg {Boolean} hideTrigger True to hide the trigger element and display only the base text field (defaults to false)
21724 /** @cfg {Boolean} grow @hide */
21725 /** @cfg {Number} growMin @hide */
21726 /** @cfg {Number} growMax @hide */
21732 autoSize: Roo.emptyFn,
21736 deferHeight : true,
21739 actionMode : 'wrap',
21741 onResize : function(w, h){
21742 Roo.form.TriggerField.superclass.onResize.apply(this, arguments);
21743 if(typeof w == 'number'){
21744 var x = w - this.trigger.getWidth();
21745 this.el.setWidth(this.adjustWidth('input', x));
21746 this.trigger.setStyle('left', x+'px');
21751 adjustSize : Roo.BoxComponent.prototype.adjustSize,
21754 getResizeEl : function(){
21759 getPositionEl : function(){
21764 alignErrorIcon : function(){
21765 this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
21769 onRender : function(ct, position){
21770 Roo.form.TriggerField.superclass.onRender.call(this, ct, position);
21771 this.wrap = this.el.wrap({cls: "x-form-field-wrap"});
21772 this.trigger = this.wrap.createChild(this.triggerConfig ||
21773 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.triggerClass});
21774 if(this.hideTrigger){
21775 this.trigger.setDisplayed(false);
21777 this.initTrigger();
21779 this.wrap.setWidth(this.el.getWidth()+this.trigger.getWidth());
21784 initTrigger : function(){
21785 this.trigger.on("click", this.onTriggerClick, this, {preventDefault:true});
21786 this.trigger.addClassOnOver('x-form-trigger-over');
21787 this.trigger.addClassOnClick('x-form-trigger-click');
21791 onDestroy : function(){
21793 this.trigger.removeAllListeners();
21794 this.trigger.remove();
21797 this.wrap.remove();
21799 Roo.form.TriggerField.superclass.onDestroy.call(this);
21803 onFocus : function(){
21804 Roo.form.TriggerField.superclass.onFocus.call(this);
21805 if(!this.mimicing){
21806 this.wrap.addClass('x-trigger-wrap-focus');
21807 this.mimicing = true;
21808 Roo.get(Roo.isIE ? document.body : document).on("mousedown", this.mimicBlur, this);
21809 if(this.monitorTab){
21810 this.el.on("keydown", this.checkTab, this);
21816 checkTab : function(e){
21817 if(e.getKey() == e.TAB){
21818 this.triggerBlur();
21823 onBlur : function(){
21828 mimicBlur : function(e, t){
21829 if(!this.wrap.contains(t) && this.validateBlur()){
21830 this.triggerBlur();
21835 triggerBlur : function(){
21836 this.mimicing = false;
21837 Roo.get(Roo.isIE ? document.body : document).un("mousedown", this.mimicBlur);
21838 if(this.monitorTab){
21839 this.el.un("keydown", this.checkTab, this);
21841 this.wrap.removeClass('x-trigger-wrap-focus');
21842 Roo.form.TriggerField.superclass.onBlur.call(this);
21846 // This should be overriden by any subclass that needs to check whether or not the field can be blurred.
21847 validateBlur : function(e, t){
21852 onDisable : function(){
21853 Roo.form.TriggerField.superclass.onDisable.call(this);
21855 this.wrap.addClass('x-item-disabled');
21860 onEnable : function(){
21861 Roo.form.TriggerField.superclass.onEnable.call(this);
21863 this.wrap.removeClass('x-item-disabled');
21868 onShow : function(){
21869 var ae = this.getActionEl();
21872 ae.dom.style.display = '';
21873 ae.dom.style.visibility = 'visible';
21879 onHide : function(){
21880 var ae = this.getActionEl();
21881 ae.dom.style.display = 'none';
21885 * The function that should handle the trigger's click event. This method does nothing by default until overridden
21886 * by an implementing function.
21888 * @param {EventObject} e
21890 onTriggerClick : Roo.emptyFn
21893 // TwinTriggerField is not a public class to be used directly. It is meant as an abstract base class
21894 // to be extended by an implementing class. For an example of implementing this class, see the custom
21895 // SearchField implementation here: http://extjs.com/deploy/ext/examples/form/custom.html
21896 Roo.form.TwinTriggerField = Roo.extend(Roo.form.TriggerField, {
21897 initComponent : function(){
21898 Roo.form.TwinTriggerField.superclass.initComponent.call(this);
21900 this.triggerConfig = {
21901 tag:'span', cls:'x-form-twin-triggers', cn:[
21902 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger1Class},
21903 {tag: "img", src: Roo.BLANK_IMAGE_URL, cls: "x-form-trigger " + this.trigger2Class}
21907 getTrigger : function(index){
21908 return this.triggers[index];
21911 initTrigger : function(){
21912 var ts = this.trigger.select('.x-form-trigger', true);
21913 this.wrap.setStyle('overflow', 'hidden');
21914 var triggerField = this;
21915 ts.each(function(t, all, index){
21916 t.hide = function(){
21917 var w = triggerField.wrap.getWidth();
21918 this.dom.style.display = 'none';
21919 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21921 t.show = function(){
21922 var w = triggerField.wrap.getWidth();
21923 this.dom.style.display = '';
21924 triggerField.el.setWidth(w-triggerField.trigger.getWidth());
21926 var triggerIndex = 'Trigger'+(index+1);
21928 if(this['hide'+triggerIndex]){
21929 t.dom.style.display = 'none';
21931 t.on("click", this['on'+triggerIndex+'Click'], this, {preventDefault:true});
21932 t.addClassOnOver('x-form-trigger-over');
21933 t.addClassOnClick('x-form-trigger-click');
21935 this.triggers = ts.elements;
21938 onTrigger1Click : Roo.emptyFn,
21939 onTrigger2Click : Roo.emptyFn
21942 * Ext JS Library 1.1.1
21943 * Copyright(c) 2006-2007, Ext JS, LLC.
21945 * Originally Released Under LGPL - original licence link has changed is not relivant.
21948 * <script type="text/javascript">
21952 * @class Roo.form.TextArea
21953 * @extends Roo.form.TextField
21954 * Multiline text field. Can be used as a direct replacement for traditional textarea fields, plus adds
21955 * support for auto-sizing.
21957 * Creates a new TextArea
21958 * @param {Object} config Configuration options
21960 Roo.form.TextArea = function(config){
21961 Roo.form.TextArea.superclass.constructor.call(this, config);
21962 // these are provided exchanges for backwards compat
21963 // minHeight/maxHeight were replaced by growMin/growMax to be
21964 // compatible with TextField growing config values
21965 if(this.minHeight !== undefined){
21966 this.growMin = this.minHeight;
21968 if(this.maxHeight !== undefined){
21969 this.growMax = this.maxHeight;
21973 Roo.extend(Roo.form.TextArea, Roo.form.TextField, {
21975 * @cfg {Number} growMin The minimum height to allow when grow = true (defaults to 60)
21979 * @cfg {Number} growMax The maximum height to allow when grow = true (defaults to 1000)
21983 * @cfg {Boolean} preventScrollbars True to prevent scrollbars from appearing regardless of how much text is
21984 * in the field (equivalent to setting overflow: hidden, defaults to false)
21986 preventScrollbars: false,
21988 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
21989 * {tag: "textarea", style: "width:300px;height:60px;", autocomplete: "off"})
21993 onRender : function(ct, position){
21995 this.defaultAutoCreate = {
21997 style:"width:300px;height:60px;",
21998 autocomplete: "off"
22001 Roo.form.TextArea.superclass.onRender.call(this, ct, position);
22003 this.textSizeEl = Roo.DomHelper.append(document.body, {
22004 tag: "pre", cls: "x-form-grow-sizer"
22006 if(this.preventScrollbars){
22007 this.el.setStyle("overflow", "hidden");
22009 this.el.setHeight(this.growMin);
22013 onDestroy : function(){
22014 if(this.textSizeEl){
22015 this.textSizeEl.parentNode.removeChild(this.textSizeEl);
22017 Roo.form.TextArea.superclass.onDestroy.call(this);
22021 onKeyUp : function(e){
22022 if(!e.isNavKeyPress() || e.getKey() == e.ENTER){
22028 * Automatically grows the field to accomodate the height of the text up to the maximum field height allowed.
22029 * This only takes effect if grow = true, and fires the autosize event if the height changes.
22031 autoSize : function(){
22032 if(!this.grow || !this.textSizeEl){
22036 var v = el.dom.value;
22037 var ts = this.textSizeEl;
22040 ts.appendChild(document.createTextNode(v));
22043 Roo.fly(ts).setWidth(this.el.getWidth());
22045 v = "  ";
22048 v = v.replace(/\n/g, '<p> </p>');
22050 v += " \n ";
22053 var h = Math.min(this.growMax, Math.max(ts.offsetHeight, this.growMin));
22054 if(h != this.lastHeight){
22055 this.lastHeight = h;
22056 this.el.setHeight(h);
22057 this.fireEvent("autosize", this, h);
22062 * Ext JS Library 1.1.1
22063 * Copyright(c) 2006-2007, Ext JS, LLC.
22065 * Originally Released Under LGPL - original licence link has changed is not relivant.
22068 * <script type="text/javascript">
22073 * @class Roo.form.NumberField
22074 * @extends Roo.form.TextField
22075 * Numeric text field that provides automatic keystroke filtering and numeric validation.
22077 * Creates a new NumberField
22078 * @param {Object} config Configuration options
22080 Roo.form.NumberField = function(config){
22081 Roo.form.NumberField.superclass.constructor.call(this, config);
22084 Roo.extend(Roo.form.NumberField, Roo.form.TextField, {
22086 * @cfg {String} fieldClass The default CSS class for the field (defaults to "x-form-field x-form-num-field")
22088 fieldClass: "x-form-field x-form-num-field",
22090 * @cfg {Boolean} allowDecimals False to disallow decimal values (defaults to true)
22092 allowDecimals : true,
22094 * @cfg {String} decimalSeparator Character(s) to allow as the decimal separator (defaults to '.')
22096 decimalSeparator : ".",
22098 * @cfg {Number} decimalPrecision The maximum precision to display after the decimal separator (defaults to 2)
22100 decimalPrecision : 2,
22102 * @cfg {Boolean} allowNegative False to prevent entering a negative sign (defaults to true)
22104 allowNegative : true,
22106 * @cfg {Number} minValue The minimum allowed value (defaults to Number.NEGATIVE_INFINITY)
22108 minValue : Number.NEGATIVE_INFINITY,
22110 * @cfg {Number} maxValue The maximum allowed value (defaults to Number.MAX_VALUE)
22112 maxValue : Number.MAX_VALUE,
22114 * @cfg {String} minText Error text to display if the minimum value validation fails (defaults to "The minimum value for this field is {minValue}")
22116 minText : "The minimum value for this field is {0}",
22118 * @cfg {String} maxText Error text to display if the maximum value validation fails (defaults to "The maximum value for this field is {maxValue}")
22120 maxText : "The maximum value for this field is {0}",
22122 * @cfg {String} nanText Error text to display if the value is not a valid number. For example, this can happen
22123 * if a valid character like '.' or '-' is left in the field with no number (defaults to "{value} is not a valid number")
22125 nanText : "{0} is not a valid number",
22128 initEvents : function(){
22129 Roo.form.NumberField.superclass.initEvents.call(this);
22130 var allowed = "0123456789";
22131 if(this.allowDecimals){
22132 allowed += this.decimalSeparator;
22134 if(this.allowNegative){
22137 this.stripCharsRe = new RegExp('[^'+allowed+']', 'gi');
22138 var keyPress = function(e){
22139 var k = e.getKey();
22140 if(!Roo.isIE && (e.isSpecialKey() || k == e.BACKSPACE || k == e.DELETE)){
22143 var c = e.getCharCode();
22144 if(allowed.indexOf(String.fromCharCode(c)) === -1){
22148 this.el.on("keypress", keyPress, this);
22152 validateValue : function(value){
22153 if(!Roo.form.NumberField.superclass.validateValue.call(this, value)){
22156 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22159 var num = this.parseValue(value);
22161 this.markInvalid(String.format(this.nanText, value));
22164 if(num < this.minValue){
22165 this.markInvalid(String.format(this.minText, this.minValue));
22168 if(num > this.maxValue){
22169 this.markInvalid(String.format(this.maxText, this.maxValue));
22175 getValue : function(){
22176 return this.fixPrecision(this.parseValue(Roo.form.NumberField.superclass.getValue.call(this)));
22180 parseValue : function(value){
22181 value = parseFloat(String(value).replace(this.decimalSeparator, "."));
22182 return isNaN(value) ? '' : value;
22186 fixPrecision : function(value){
22187 var nan = isNaN(value);
22188 if(!this.allowDecimals || this.decimalPrecision == -1 || nan || !value){
22189 return nan ? '' : value;
22191 return parseFloat(value).toFixed(this.decimalPrecision);
22194 setValue : function(v){
22195 Roo.form.NumberField.superclass.setValue.call(this, String(v).replace(".", this.decimalSeparator));
22199 decimalPrecisionFcn : function(v){
22200 return Math.floor(v);
22203 beforeBlur : function(){
22204 var v = this.parseValue(this.getRawValue());
22206 this.setValue(this.fixPrecision(v));
22211 * Ext JS Library 1.1.1
22212 * Copyright(c) 2006-2007, Ext JS, LLC.
22214 * Originally Released Under LGPL - original licence link has changed is not relivant.
22217 * <script type="text/javascript">
22221 * @class Roo.form.DateField
22222 * @extends Roo.form.TriggerField
22223 * Provides a date input field with a {@link Roo.DatePicker} dropdown and automatic date validation.
22225 * Create a new DateField
22226 * @param {Object} config
22228 Roo.form.DateField = function(config){
22229 Roo.form.DateField.superclass.constructor.call(this, config);
22235 * Fires when a date is selected
22236 * @param {Roo.form.DateField} combo This combo box
22237 * @param {Date} date The date selected
22244 if(typeof this.minValue == "string") this.minValue = this.parseDate(this.minValue);
22245 if(typeof this.maxValue == "string") this.maxValue = this.parseDate(this.maxValue);
22246 this.ddMatch = null;
22247 if(this.disabledDates){
22248 var dd = this.disabledDates;
22250 for(var i = 0; i < dd.length; i++){
22252 if(i != dd.length-1) re += "|";
22254 this.ddMatch = new RegExp(re + ")");
22258 Roo.extend(Roo.form.DateField, Roo.form.TriggerField, {
22260 * @cfg {String} format
22261 * The default date format string which can be overriden for localization support. The format must be
22262 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
22266 * @cfg {String} altFormats
22267 * Multiple date formats separated by "|" to try when parsing a user input value and it doesn't match the defined
22268 * format (defaults to 'm/d/Y|m-d-y|m-d-Y|m/d|m-d|d').
22270 altFormats : "m/d/Y|m-d-y|m-d-Y|m/d|m-d|md|mdy|mdY|d",
22272 * @cfg {Array} disabledDays
22273 * An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
22275 disabledDays : null,
22277 * @cfg {String} disabledDaysText
22278 * The tooltip to display when the date falls on a disabled day (defaults to 'Disabled')
22280 disabledDaysText : "Disabled",
22282 * @cfg {Array} disabledDates
22283 * An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular
22284 * expression so they are very powerful. Some examples:
22286 * <li>["03/08/2003", "09/16/2003"] would disable those exact dates</li>
22287 * <li>["03/08", "09/16"] would disable those days for every year</li>
22288 * <li>["^03/08"] would only match the beginning (useful if you are using short years)</li>
22289 * <li>["03/../2006"] would disable every day in March 2006</li>
22290 * <li>["^03"] would disable every day in every March</li>
22292 * In order to support regular expressions, if you are using a date format that has "." in it, you will have to
22293 * escape the dot when restricting dates. For example: ["03\\.08\\.03"].
22295 disabledDates : null,
22297 * @cfg {String} disabledDatesText
22298 * The tooltip text to display when the date falls on a disabled date (defaults to 'Disabled')
22300 disabledDatesText : "Disabled",
22302 * @cfg {Date/String} minValue
22303 * The minimum allowed date. Can be either a Javascript date object or a string date in a
22304 * valid format (defaults to null).
22308 * @cfg {Date/String} maxValue
22309 * The maximum allowed date. Can be either a Javascript date object or a string date in a
22310 * valid format (defaults to null).
22314 * @cfg {String} minText
22315 * The error text to display when the date in the cell is before minValue (defaults to
22316 * 'The date in this field must be after {minValue}').
22318 minText : "The date in this field must be equal to or after {0}",
22320 * @cfg {String} maxText
22321 * The error text to display when the date in the cell is after maxValue (defaults to
22322 * 'The date in this field must be before {maxValue}').
22324 maxText : "The date in this field must be equal to or before {0}",
22326 * @cfg {String} invalidText
22327 * The error text to display when the date in the field is invalid (defaults to
22328 * '{value} is not a valid date - it must be in the format {format}').
22330 invalidText : "{0} is not a valid date - it must be in the format {1}",
22332 * @cfg {String} triggerClass
22333 * An additional CSS class used to style the trigger button. The trigger will always get the
22334 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-date-trigger'
22335 * which displays a calendar icon).
22337 triggerClass : 'x-form-date-trigger',
22341 * @cfg {bool} useIso
22342 * if enabled, then the date field will use a hidden field to store the
22343 * real value as iso formated date. default (false)
22347 * @cfg {String/Object} autoCreate
22348 * A DomHelper element spec, or true for a default element spec (defaults to
22349 * {tag: "input", type: "text", size: "10", autocomplete: "off"})
22352 defaultAutoCreate : {tag: "input", type: "text", size: "10", autocomplete: "off"},
22355 hiddenField: false,
22357 onRender : function(ct, position)
22359 Roo.form.DateField.superclass.onRender.call(this, ct, position);
22361 this.el.dom.removeAttribute('name');
22362 this.hiddenField = this.el.insertSibling({ tag:'input', type:'hidden', name: this.name },
22364 this.hiddenField.value = this.formatDate(this.value, 'Y-m-d');
22365 // prevent input submission
22366 this.hiddenName = this.name;
22373 validateValue : function(value)
22375 value = this.formatDate(value);
22376 if(!Roo.form.DateField.superclass.validateValue.call(this, value)){
22379 if(value.length < 1){ // if it's blank and textfield didn't flag it then it's valid
22382 var svalue = value;
22383 value = this.parseDate(value);
22385 this.markInvalid(String.format(this.invalidText, svalue, this.format));
22388 var time = value.getTime();
22389 if(this.minValue && time < this.minValue.getTime()){
22390 this.markInvalid(String.format(this.minText, this.formatDate(this.minValue)));
22393 if(this.maxValue && time > this.maxValue.getTime()){
22394 this.markInvalid(String.format(this.maxText, this.formatDate(this.maxValue)));
22397 if(this.disabledDays){
22398 var day = value.getDay();
22399 for(var i = 0; i < this.disabledDays.length; i++) {
22400 if(day === this.disabledDays[i]){
22401 this.markInvalid(this.disabledDaysText);
22406 var fvalue = this.formatDate(value);
22407 if(this.ddMatch && this.ddMatch.test(fvalue)){
22408 this.markInvalid(String.format(this.disabledDatesText, fvalue));
22415 // Provides logic to override the default TriggerField.validateBlur which just returns true
22416 validateBlur : function(){
22417 return !this.menu || !this.menu.isVisible();
22421 * Returns the current date value of the date field.
22422 * @return {Date} The date value
22424 getValue : function(){
22426 return this.hiddenField ? this.hiddenField.value : this.parseDate(Roo.form.DateField.superclass.getValue.call(this)) || "";
22430 * Sets the value of the date field. You can pass a date object or any string that can be parsed into a valid
22431 * date, using DateField.format as the date format, according to the same rules as {@link Date#parseDate}
22432 * (the default format used is "m/d/y").
22435 //All of these calls set the same date value (May 4, 2006)
22437 //Pass a date object:
22438 var dt = new Date('5/4/06');
22439 dateField.setValue(dt);
22441 //Pass a date string (default format):
22442 dateField.setValue('5/4/06');
22444 //Pass a date string (custom format):
22445 dateField.format = 'Y-m-d';
22446 dateField.setValue('2006-5-4');
22448 * @param {String/Date} date The date or valid date string
22450 setValue : function(date){
22451 if (this.hiddenField) {
22452 this.hiddenField.value = this.formatDate(this.parseDate(date), 'Y-m-d');
22454 Roo.form.DateField.superclass.setValue.call(this, this.formatDate(this.parseDate(date)));
22458 parseDate : function(value){
22459 if(!value || value instanceof Date){
22462 var v = Date.parseDate(value, this.format);
22463 if(!v && this.altFormats){
22464 if(!this.altFormatsArray){
22465 this.altFormatsArray = this.altFormats.split("|");
22467 for(var i = 0, len = this.altFormatsArray.length; i < len && !v; i++){
22468 v = Date.parseDate(value, this.altFormatsArray[i]);
22475 formatDate : function(date, fmt){
22476 return (!date || !(date instanceof Date)) ?
22477 date : date.dateFormat(fmt || this.format);
22482 select: function(m, d){
22484 this.fireEvent('select', this, d);
22486 show : function(){ // retain focus styling
22490 this.focus.defer(10, this);
22491 var ml = this.menuListeners;
22492 this.menu.un("select", ml.select, this);
22493 this.menu.un("show", ml.show, this);
22494 this.menu.un("hide", ml.hide, this);
22499 // Implements the default empty TriggerField.onTriggerClick function to display the DatePicker
22500 onTriggerClick : function(){
22504 if(this.menu == null){
22505 this.menu = new Roo.menu.DateMenu();
22507 Roo.apply(this.menu.picker, {
22508 showClear: this.allowBlank,
22509 minDate : this.minValue,
22510 maxDate : this.maxValue,
22511 disabledDatesRE : this.ddMatch,
22512 disabledDatesText : this.disabledDatesText,
22513 disabledDays : this.disabledDays,
22514 disabledDaysText : this.disabledDaysText,
22515 format : this.format,
22516 minText : String.format(this.minText, this.formatDate(this.minValue)),
22517 maxText : String.format(this.maxText, this.formatDate(this.maxValue))
22519 this.menu.on(Roo.apply({}, this.menuListeners, {
22522 this.menu.picker.setValue(this.getValue() || new Date());
22523 this.menu.show(this.el, "tl-bl?");
22526 beforeBlur : function(){
22527 var v = this.parseDate(this.getRawValue());
22533 /** @cfg {Boolean} grow @hide */
22534 /** @cfg {Number} growMin @hide */
22535 /** @cfg {Number} growMax @hide */
22542 * Ext JS Library 1.1.1
22543 * Copyright(c) 2006-2007, Ext JS, LLC.
22545 * Originally Released Under LGPL - original licence link has changed is not relivant.
22548 * <script type="text/javascript">
22553 * @class Roo.form.ComboBox
22554 * @extends Roo.form.TriggerField
22555 * A combobox control with support for autocomplete, remote-loading, paging and many other features.
22557 * Create a new ComboBox.
22558 * @param {Object} config Configuration options
22560 Roo.form.ComboBox = function(config){
22561 Roo.form.ComboBox.superclass.constructor.call(this, config);
22565 * Fires when the dropdown list is expanded
22566 * @param {Roo.form.ComboBox} combo This combo box
22571 * Fires when the dropdown list is collapsed
22572 * @param {Roo.form.ComboBox} combo This combo box
22576 * @event beforeselect
22577 * Fires before a list item is selected. Return false to cancel the selection.
22578 * @param {Roo.form.ComboBox} combo This combo box
22579 * @param {Roo.data.Record} record The data record returned from the underlying store
22580 * @param {Number} index The index of the selected item in the dropdown list
22582 'beforeselect' : true,
22585 * Fires when a list item is selected
22586 * @param {Roo.form.ComboBox} combo This combo box
22587 * @param {Roo.data.Record} record The data record returned from the underlying store (or false on clear)
22588 * @param {Number} index The index of the selected item in the dropdown list
22592 * @event beforequery
22593 * Fires before all queries are processed. Return false to cancel the query or set cancel to true.
22594 * The event object passed has these properties:
22595 * @param {Roo.form.ComboBox} combo This combo box
22596 * @param {String} query The query
22597 * @param {Boolean} forceAll true to force "all" query
22598 * @param {Boolean} cancel true to cancel the query
22599 * @param {Object} e The query event object
22601 'beforequery': true,
22604 * Fires when the 'add' icon is pressed (add a listener to enable add button)
22605 * @param {Roo.form.ComboBox} combo This combo box
22610 * Fires when the 'edit' icon is pressed (add a listener to enable add button)
22611 * @param {Roo.form.ComboBox} combo This combo box
22612 * @param {Roo.data.Record|false} record The data record returned from the underlying store (or false on nothing selected)
22618 if(this.transform){
22619 this.allowDomMove = false;
22620 var s = Roo.getDom(this.transform);
22621 if(!this.hiddenName){
22622 this.hiddenName = s.name;
22625 this.mode = 'local';
22626 var d = [], opts = s.options;
22627 for(var i = 0, len = opts.length;i < len; i++){
22629 var value = (Roo.isIE ? o.getAttributeNode('value').specified : o.hasAttribute('value')) ? o.value : o.text;
22631 this.value = value;
22633 d.push([value, o.text]);
22635 this.store = new Roo.data.SimpleStore({
22637 fields: ['value', 'text'],
22640 this.valueField = 'value';
22641 this.displayField = 'text';
22643 s.name = Roo.id(); // wipe out the name in case somewhere else they have a reference
22644 if(!this.lazyRender){
22645 this.target = true;
22646 this.el = Roo.DomHelper.insertBefore(s, this.autoCreate || this.defaultAutoCreate);
22647 s.parentNode.removeChild(s); // remove it
22648 this.render(this.el.parentNode);
22650 s.parentNode.removeChild(s); // remove it
22655 this.store = Roo.factory(this.store, Roo.data);
22658 this.selectedIndex = -1;
22659 if(this.mode == 'local'){
22660 if(config.queryDelay === undefined){
22661 this.queryDelay = 10;
22663 if(config.minChars === undefined){
22669 Roo.extend(Roo.form.ComboBox, Roo.form.TriggerField, {
22671 * @cfg {String/HTMLElement/Element} transform The id, DOM node or element of an existing select to convert to a ComboBox
22674 * @cfg {Boolean} lazyRender True to prevent the ComboBox from rendering until requested (should always be used when
22675 * rendering into an Roo.Editor, defaults to false)
22678 * @cfg {Boolean/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to:
22679 * {tag: "input", type: "text", size: "24", autocomplete: "off"})
22682 * @cfg {Roo.data.Store} store The data store to which this combo is bound (defaults to undefined)
22685 * @cfg {String} title If supplied, a header element is created containing this text and added into the top of
22686 * the dropdown list (defaults to undefined, with no header element)
22690 * @cfg {String/Roo.Template} tpl The template to use to render the output
22694 defaultAutoCreate : {tag: "input", type: "text", size: "24", autocomplete: "off"},
22696 * @cfg {Number} listWidth The width in pixels of the dropdown list (defaults to the width of the ComboBox field)
22698 listWidth: undefined,
22700 * @cfg {String} displayField The underlying data field name to bind to this CombBox (defaults to undefined if
22701 * mode = 'remote' or 'text' if mode = 'local')
22703 displayField: undefined,
22705 * @cfg {String} valueField The underlying data value name to bind to this CombBox (defaults to undefined if
22706 * mode = 'remote' or 'value' if mode = 'local').
22707 * Note: use of a valueField requires the user make a selection
22708 * in order for a value to be mapped.
22710 valueField: undefined,
22712 * @cfg {String} hiddenName If specified, a hidden form field with this name is dynamically generated to store the
22713 * field's data value (defaults to the underlying DOM element's name)
22715 hiddenName: undefined,
22717 * @cfg {String} listClass CSS class to apply to the dropdown list element (defaults to '')
22721 * @cfg {String} selectedClass CSS class to apply to the selected item in the dropdown list (defaults to 'x-combo-selected')
22723 selectedClass: 'x-combo-selected',
22725 * @cfg {String} triggerClass An additional CSS class used to style the trigger button. The trigger will always get the
22726 * class 'x-form-trigger' and triggerClass will be <b>appended</b> if specified (defaults to 'x-form-arrow-trigger'
22727 * which displays a downward arrow icon).
22729 triggerClass : 'x-form-arrow-trigger',
22731 * @cfg {Boolean/String} shadow True or "sides" for the default effect, "frame" for 4-way shadow, and "drop" for bottom-right
22735 * @cfg {String} listAlign A valid anchor position value. See {@link Roo.Element#alignTo} for details on supported
22736 * anchor positions (defaults to 'tl-bl')
22738 listAlign: 'tl-bl?',
22740 * @cfg {Number} maxHeight The maximum height in pixels of the dropdown list before scrollbars are shown (defaults to 300)
22744 * @cfg {String} triggerAction The action to execute when the trigger field is activated. Use 'all' to run the
22745 * query specified by the allQuery config option (defaults to 'query')
22747 triggerAction: 'query',
22749 * @cfg {Number} minChars The minimum number of characters the user must type before autocomplete and typeahead activate
22750 * (defaults to 4, does not apply if editable = false)
22754 * @cfg {Boolean} typeAhead True to populate and autoselect the remainder of the text being typed after a configurable
22755 * delay (typeAheadDelay) if it matches a known value (defaults to false)
22759 * @cfg {Number} queryDelay The length of time in milliseconds to delay between the start of typing and sending the
22760 * query to filter the dropdown list (defaults to 500 if mode = 'remote' or 10 if mode = 'local')
22764 * @cfg {Number} pageSize If greater than 0, a paging toolbar is displayed in the footer of the dropdown list and the
22765 * filter queries will execute with page start and limit parameters. Only applies when mode = 'remote' (defaults to 0)
22769 * @cfg {Boolean} selectOnFocus True to select any existing text in the field immediately on focus. Only applies
22770 * when editable = true (defaults to false)
22772 selectOnFocus:false,
22774 * @cfg {String} queryParam Name of the query as it will be passed on the querystring (defaults to 'query')
22776 queryParam: 'query',
22778 * @cfg {String} loadingText The text to display in the dropdown list while data is loading. Only applies
22779 * when mode = 'remote' (defaults to 'Loading...')
22781 loadingText: 'Loading...',
22783 * @cfg {Boolean} resizable True to add a resize handle to the bottom of the dropdown list (defaults to false)
22787 * @cfg {Number} handleHeight The height in pixels of the dropdown list resize handle if resizable = true (defaults to 8)
22791 * @cfg {Boolean} editable False to prevent the user from typing text directly into the field, just like a
22792 * traditional select (defaults to true)
22796 * @cfg {String} allQuery The text query to send to the server to return all records for the list with no filtering (defaults to '')
22800 * @cfg {String} mode Set to 'local' if the ComboBox loads local data (defaults to 'remote' which loads from the server)
22804 * @cfg {Number} minListWidth The minimum width of the dropdown list in pixels (defaults to 70, will be ignored if
22805 * listWidth has a higher value)
22809 * @cfg {Boolean} forceSelection True to restrict the selected value to one of the values in the list, false to
22810 * allow the user to set arbitrary text into the field (defaults to false)
22812 forceSelection:false,
22814 * @cfg {Number} typeAheadDelay The length of time in milliseconds to wait until the typeahead text is displayed
22815 * if typeAhead = true (defaults to 250)
22817 typeAheadDelay : 250,
22819 * @cfg {String} valueNotFoundText When using a name/value combo, if the value passed to setValue is not found in
22820 * the store, valueNotFoundText will be displayed as the field text if defined (defaults to undefined)
22822 valueNotFoundText : undefined,
22824 * @cfg {Boolean} blockFocus Prevents all focus calls, so it can work with things like HTML edtor bar
22826 blockFocus : false,
22829 * @cfg {Boolean} disableClear Disable showing of clear button.
22831 disableClear : false,
22833 * @cfg {Boolean} alwaysQuery Disable caching of results, and always send query
22835 alwaysQuery : false,
22843 onRender : function(ct, position){
22844 Roo.form.ComboBox.superclass.onRender.call(this, ct, position);
22845 if(this.hiddenName){
22846 this.hiddenField = this.el.insertSibling({tag:'input', type:'hidden', name: this.hiddenName, id: (this.hiddenId||this.hiddenName)},
22848 this.hiddenField.value =
22849 this.hiddenValue !== undefined ? this.hiddenValue :
22850 this.value !== undefined ? this.value : '';
22852 // prevent input submission
22853 this.el.dom.removeAttribute('name');
22856 this.el.dom.setAttribute('autocomplete', 'off');
22859 var cls = 'x-combo-list';
22861 this.list = new Roo.Layer({
22862 shadow: this.shadow, cls: [cls, this.listClass].join(' '), constrain:false
22865 var lw = this.listWidth || Math.max(this.wrap.getWidth(), this.minListWidth);
22866 this.list.setWidth(lw);
22867 this.list.swallowEvent('mousewheel');
22868 this.assetHeight = 0;
22871 this.header = this.list.createChild({cls:cls+'-hd', html: this.title});
22872 this.assetHeight += this.header.getHeight();
22875 this.innerList = this.list.createChild({cls:cls+'-inner'});
22876 this.innerList.on('mouseover', this.onViewOver, this);
22877 this.innerList.on('mousemove', this.onViewMove, this);
22878 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
22880 if(this.allowBlank && !this.pageSize && !this.disableClear){
22881 this.footer = this.list.createChild({cls:cls+'-ft'});
22882 this.pageTb = new Roo.Toolbar(this.footer);
22886 this.footer = this.list.createChild({cls:cls+'-ft'});
22887 this.pageTb = new Roo.PagingToolbar(this.footer, this.store,
22888 {pageSize: this.pageSize});
22892 if (this.pageTb && this.allowBlank && !this.disableClear) {
22894 this.pageTb.add(new Roo.Toolbar.Fill(), {
22895 cls: 'x-btn-icon x-btn-clear',
22897 handler: function()
22900 _this.clearValue();
22901 _this.onSelect(false, -1);
22906 this.assetHeight += this.footer.getHeight();
22911 this.tpl = '<div class="'+cls+'-item">{' + this.displayField + '}</div>';
22914 this.view = new Roo.View(this.innerList, this.tpl, {
22915 singleSelect:true, store: this.store, selectedClass: this.selectedClass
22918 this.view.on('click', this.onViewClick, this);
22920 this.store.on('beforeload', this.onBeforeLoad, this);
22921 this.store.on('load', this.onLoad, this);
22922 this.store.on('loadexception', this.collapse, this);
22924 if(this.resizable){
22925 this.resizer = new Roo.Resizable(this.list, {
22926 pinned:true, handles:'se'
22928 this.resizer.on('resize', function(r, w, h){
22929 this.maxHeight = h-this.handleHeight-this.list.getFrameWidth('tb')-this.assetHeight;
22930 this.listWidth = w;
22931 this.innerList.setWidth(w - this.list.getFrameWidth('lr'));
22932 this.restrictHeight();
22934 this[this.pageSize?'footer':'innerList'].setStyle('margin-bottom', this.handleHeight+'px');
22936 if(!this.editable){
22937 this.editable = true;
22938 this.setEditable(false);
22942 if (typeof(this.events.add.listeners) != 'undefined') {
22944 this.addicon = this.wrap.createChild(
22945 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-add' });
22947 this.addicon.on('click', function(e) {
22948 this.fireEvent('add', this);
22951 if (typeof(this.events.edit.listeners) != 'undefined') {
22953 this.editicon = this.wrap.createChild(
22954 {tag: 'img', src: Roo.BLANK_IMAGE_URL, cls: 'x-form-combo-edit' });
22955 if (this.addicon) {
22956 this.editicon.setStyle('margin-left', '40px');
22958 this.editicon.on('click', function(e) {
22960 // we fire even if inothing is selected..
22961 this.fireEvent('edit', this, this.lastData );
22971 initEvents : function(){
22972 Roo.form.ComboBox.superclass.initEvents.call(this);
22974 this.keyNav = new Roo.KeyNav(this.el, {
22975 "up" : function(e){
22976 this.inKeyMode = true;
22980 "down" : function(e){
22981 if(!this.isExpanded()){
22982 this.onTriggerClick();
22984 this.inKeyMode = true;
22989 "enter" : function(e){
22990 this.onViewClick();
22994 "esc" : function(e){
22998 "tab" : function(e){
22999 this.onViewClick(false);
23005 doRelay : function(foo, bar, hname){
23006 if(hname == 'down' || this.scope.isExpanded()){
23007 return Roo.KeyNav.prototype.doRelay.apply(this, arguments);
23014 this.queryDelay = Math.max(this.queryDelay || 10,
23015 this.mode == 'local' ? 10 : 250);
23016 this.dqTask = new Roo.util.DelayedTask(this.initQuery, this);
23017 if(this.typeAhead){
23018 this.taTask = new Roo.util.DelayedTask(this.onTypeAhead, this);
23020 if(this.editable !== false){
23021 this.el.on("keyup", this.onKeyUp, this);
23023 if(this.forceSelection){
23024 this.on('blur', this.doForce, this);
23028 onDestroy : function(){
23030 this.view.setStore(null);
23031 this.view.el.removeAllListeners();
23032 this.view.el.remove();
23033 this.view.purgeListeners();
23036 this.list.destroy();
23039 this.store.un('beforeload', this.onBeforeLoad, this);
23040 this.store.un('load', this.onLoad, this);
23041 this.store.un('loadexception', this.collapse, this);
23043 Roo.form.ComboBox.superclass.onDestroy.call(this);
23047 fireKey : function(e){
23048 if(e.isNavKeyPress() && !this.list.isVisible()){
23049 this.fireEvent("specialkey", this, e);
23054 onResize: function(w, h){
23055 Roo.form.ComboBox.superclass.onResize.apply(this, arguments);
23057 if(typeof w != 'number'){
23058 // we do not handle it!?!?
23061 var tw = this.trigger.getWidth();
23062 tw += this.addicon ? this.addicon.getWidth() : 0;
23063 tw += this.editicon ? this.editicon.getWidth() : 0;
23065 this.el.setWidth( this.adjustWidth('input', x));
23067 this.trigger.setStyle('left', x+'px');
23069 if(this.list && this.listWidth === undefined){
23070 var lw = Math.max(x + this.trigger.getWidth(), this.minListWidth);
23071 this.list.setWidth(lw);
23072 this.innerList.setWidth(lw - this.list.getFrameWidth('lr'));
23080 * Allow or prevent the user from directly editing the field text. If false is passed,
23081 * the user will only be able to select from the items defined in the dropdown list. This method
23082 * is the runtime equivalent of setting the 'editable' config option at config time.
23083 * @param {Boolean} value True to allow the user to directly edit the field text
23085 setEditable : function(value){
23086 if(value == this.editable){
23089 this.editable = value;
23091 this.el.dom.setAttribute('readOnly', true);
23092 this.el.on('mousedown', this.onTriggerClick, this);
23093 this.el.addClass('x-combo-noedit');
23095 this.el.dom.setAttribute('readOnly', false);
23096 this.el.un('mousedown', this.onTriggerClick, this);
23097 this.el.removeClass('x-combo-noedit');
23102 onBeforeLoad : function(){
23103 if(!this.hasFocus){
23106 this.innerList.update(this.loadingText ?
23107 '<div class="loading-indicator">'+this.loadingText+'</div>' : '');
23108 this.restrictHeight();
23109 this.selectedIndex = -1;
23113 onLoad : function(){
23114 if(!this.hasFocus){
23117 if(this.store.getCount() > 0){
23119 this.restrictHeight();
23120 if(this.lastQuery == this.allQuery){
23122 this.el.dom.select();
23124 if(!this.selectByValue(this.value, true)){
23125 this.select(0, true);
23129 if(this.typeAhead && this.lastKey != Roo.EventObject.BACKSPACE && this.lastKey != Roo.EventObject.DELETE){
23130 this.taTask.delay(this.typeAheadDelay);
23134 this.onEmptyResults();
23140 onTypeAhead : function(){
23141 if(this.store.getCount() > 0){
23142 var r = this.store.getAt(0);
23143 var newValue = r.data[this.displayField];
23144 var len = newValue.length;
23145 var selStart = this.getRawValue().length;
23146 if(selStart != len){
23147 this.setRawValue(newValue);
23148 this.selectText(selStart, newValue.length);
23154 onSelect : function(record, index){
23155 if(this.fireEvent('beforeselect', this, record, index) !== false){
23156 this.setFromData(index > -1 ? record.data : false);
23158 this.fireEvent('select', this, record, index);
23163 * Returns the currently selected field value or empty string if no value is set.
23164 * @return {String} value The selected value
23166 getValue : function(){
23167 if(this.valueField){
23168 return typeof this.value != 'undefined' ? this.value : '';
23170 return Roo.form.ComboBox.superclass.getValue.call(this);
23175 * Clears any text/value currently set in the field
23177 clearValue : function(){
23178 if(this.hiddenField){
23179 this.hiddenField.value = '';
23182 this.setRawValue('');
23183 this.lastSelectionText = '';
23184 this.applyEmptyText();
23188 * Sets the specified value into the field. If the value finds a match, the corresponding record text
23189 * will be displayed in the field. If the value does not match the data value of an existing item,
23190 * and the valueNotFoundText config option is defined, it will be displayed as the default field text.
23191 * Otherwise the field will be blank (although the value will still be set).
23192 * @param {String} value The value to match
23194 setValue : function(v){
23196 if(this.valueField){
23197 var r = this.findRecord(this.valueField, v);
23199 text = r.data[this.displayField];
23200 }else if(this.valueNotFoundText !== undefined){
23201 text = this.valueNotFoundText;
23204 this.lastSelectionText = text;
23205 if(this.hiddenField){
23206 this.hiddenField.value = v;
23208 Roo.form.ComboBox.superclass.setValue.call(this, text);
23212 * @property {Object} the last set data for the element
23217 * Sets the value of the field based on a object which is related to the record format for the store.
23218 * @param {Object} value the value to set as. or false on reset?
23220 setFromData : function(o){
23221 var dv = ''; // display value
23222 var vv = ''; // value value..
23224 if (this.displayField) {
23225 dv = !o || typeof(o[this.displayField]) == 'undefined' ? '' : o[this.displayField];
23227 // this is an error condition!!!
23228 Roo.log('no displayField value set for '+ (this.name ? this.name : this.id));
23231 if(this.valueField){
23232 vv = !o || typeof(o[this.valueField]) == 'undefined' ? dv : o[this.valueField];
23234 if(this.hiddenField){
23235 this.hiddenField.value = vv;
23237 this.lastSelectionText = dv;
23238 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23242 // no hidden field.. - we store the value in 'value', but still display
23243 // display field!!!!
23244 this.lastSelectionText = dv;
23245 Roo.form.ComboBox.superclass.setValue.call(this, dv);
23251 reset : function(){
23252 // overridden so that last data is reset..
23253 this.setValue(this.originalValue);
23254 this.clearInvalid();
23255 this.lastData = false;
23258 findRecord : function(prop, value){
23260 if(this.store.getCount() > 0){
23261 this.store.each(function(r){
23262 if(r.data[prop] == value){
23272 onViewMove : function(e, t){
23273 this.inKeyMode = false;
23277 onViewOver : function(e, t){
23278 if(this.inKeyMode){ // prevent key nav and mouse over conflicts
23281 var item = this.view.findItemFromChild(t);
23283 var index = this.view.indexOf(item);
23284 this.select(index, false);
23289 onViewClick : function(doFocus){
23290 var index = this.view.getSelectedIndexes()[0];
23291 var r = this.store.getAt(index);
23293 this.onSelect(r, index);
23295 if(doFocus !== false && !this.blockFocus){
23301 restrictHeight : function(){
23302 this.innerList.dom.style.height = '';
23303 var inner = this.innerList.dom;
23304 var h = Math.max(inner.clientHeight, inner.offsetHeight, inner.scrollHeight);
23305 this.innerList.setHeight(h < this.maxHeight ? 'auto' : this.maxHeight);
23306 this.list.beginUpdate();
23307 this.list.setHeight(this.innerList.getHeight()+this.list.getFrameWidth('tb')+(this.resizable?this.handleHeight:0)+this.assetHeight);
23308 this.list.alignTo(this.el, this.listAlign);
23309 this.list.endUpdate();
23313 onEmptyResults : function(){
23318 * Returns true if the dropdown list is expanded, else false.
23320 isExpanded : function(){
23321 return this.list.isVisible();
23325 * Select an item in the dropdown list by its data value. This function does NOT cause the select event to fire.
23326 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23327 * @param {String} value The data value of the item to select
23328 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23329 * selected item if it is not currently in view (defaults to true)
23330 * @return {Boolean} True if the value matched an item in the list, else false
23332 selectByValue : function(v, scrollIntoView){
23333 if(v !== undefined && v !== null){
23334 var r = this.findRecord(this.valueField || this.displayField, v);
23336 this.select(this.store.indexOf(r), scrollIntoView);
23344 * Select an item in the dropdown list by its numeric index in the list. This function does NOT cause the select event to fire.
23345 * The store must be loaded and the list expanded for this function to work, otherwise use setValue.
23346 * @param {Number} index The zero-based index of the list item to select
23347 * @param {Boolean} scrollIntoView False to prevent the dropdown list from autoscrolling to display the
23348 * selected item if it is not currently in view (defaults to true)
23350 select : function(index, scrollIntoView){
23351 this.selectedIndex = index;
23352 this.view.select(index);
23353 if(scrollIntoView !== false){
23354 var el = this.view.getNode(index);
23356 this.innerList.scrollChildIntoView(el, false);
23362 selectNext : function(){
23363 var ct = this.store.getCount();
23365 if(this.selectedIndex == -1){
23367 }else if(this.selectedIndex < ct-1){
23368 this.select(this.selectedIndex+1);
23374 selectPrev : function(){
23375 var ct = this.store.getCount();
23377 if(this.selectedIndex == -1){
23379 }else if(this.selectedIndex != 0){
23380 this.select(this.selectedIndex-1);
23386 onKeyUp : function(e){
23387 if(this.editable !== false && !e.isSpecialKey()){
23388 this.lastKey = e.getKey();
23389 this.dqTask.delay(this.queryDelay);
23394 validateBlur : function(){
23395 return !this.list || !this.list.isVisible();
23399 initQuery : function(){
23400 this.doQuery(this.getRawValue());
23404 doForce : function(){
23405 if(this.el.dom.value.length > 0){
23406 this.el.dom.value =
23407 this.lastSelectionText === undefined ? '' : this.lastSelectionText;
23408 this.applyEmptyText();
23413 * Execute a query to filter the dropdown list. Fires the beforequery event prior to performing the
23414 * query allowing the query action to be canceled if needed.
23415 * @param {String} query The SQL query to execute
23416 * @param {Boolean} forceAll True to force the query to execute even if there are currently fewer characters
23417 * in the field than the minimum specified by the minChars config option. It also clears any filter previously
23418 * saved in the current store (defaults to false)
23420 doQuery : function(q, forceAll){
23421 if(q === undefined || q === null){
23426 forceAll: forceAll,
23430 if(this.fireEvent('beforequery', qe)===false || qe.cancel){
23434 forceAll = qe.forceAll;
23435 if(forceAll === true || (q.length >= this.minChars)){
23436 if(this.lastQuery != q || this.alwaysQuery){
23437 this.lastQuery = q;
23438 if(this.mode == 'local'){
23439 this.selectedIndex = -1;
23441 this.store.clearFilter();
23443 this.store.filter(this.displayField, q);
23447 this.store.baseParams[this.queryParam] = q;
23449 params: this.getParams(q)
23454 this.selectedIndex = -1;
23461 getParams : function(q){
23463 //p[this.queryParam] = q;
23466 p.limit = this.pageSize;
23472 * Hides the dropdown list if it is currently expanded. Fires the 'collapse' event on completion.
23474 collapse : function(){
23475 if(!this.isExpanded()){
23479 Roo.get(document).un('mousedown', this.collapseIf, this);
23480 Roo.get(document).un('mousewheel', this.collapseIf, this);
23481 if (!this.editable) {
23482 Roo.get(document).un('keydown', this.listKeyPress, this);
23484 this.fireEvent('collapse', this);
23488 collapseIf : function(e){
23489 if(!e.within(this.wrap) && !e.within(this.list)){
23495 * Expands the dropdown list if it is currently hidden. Fires the 'expand' event on completion.
23497 expand : function(){
23498 if(this.isExpanded() || !this.hasFocus){
23501 this.list.alignTo(this.el, this.listAlign);
23503 Roo.get(document).on('mousedown', this.collapseIf, this);
23504 Roo.get(document).on('mousewheel', this.collapseIf, this);
23505 if (!this.editable) {
23506 Roo.get(document).on('keydown', this.listKeyPress, this);
23509 this.fireEvent('expand', this);
23513 // Implements the default empty TriggerField.onTriggerClick function
23514 onTriggerClick : function(){
23518 if(this.isExpanded()){
23520 if (!this.blockFocus) {
23525 this.hasFocus = true;
23526 if(this.triggerAction == 'all') {
23527 this.doQuery(this.allQuery, true);
23529 this.doQuery(this.getRawValue());
23531 if (!this.blockFocus) {
23536 listKeyPress : function(e)
23538 //Roo.log('listkeypress');
23539 // scroll to first matching element based on key pres..
23540 if (e.isSpecialKey()) {
23543 var k = String.fromCharCode(e.getKey()).toUpperCase();
23546 var csel = this.view.getSelectedNodes();
23547 var cselitem = false;
23549 var ix = this.view.indexOf(csel[0]);
23550 cselitem = this.store.getAt(ix);
23551 if (!cselitem.get(this.displayField) || cselitem.get(this.displayField).substring(0,1).toUpperCase() != k) {
23557 this.store.each(function(v) {
23559 // start at existing selection.
23560 if (cselitem.id == v.id) {
23566 if (v.get(this.displayField) && v.get(this.displayField).substring(0,1).toUpperCase() == k) {
23567 match = this.store.indexOf(v);
23572 if (match === false) {
23573 return true; // no more action?
23576 this.view.select(match);
23577 var sn = Roo.get(this.view.getSelectedNodes()[0])
23578 sn.scrollIntoView(sn.dom.parentNode, false);
23582 * @cfg {Boolean} grow
23586 * @cfg {Number} growMin
23590 * @cfg {Number} growMax
23599 * Ext JS Library 1.1.1
23600 * Copyright(c) 2006-2007, Ext JS, LLC.
23602 * Originally Released Under LGPL - original licence link has changed is not relivant.
23605 * <script type="text/javascript">
23608 * @class Roo.form.Checkbox
23609 * @extends Roo.form.Field
23610 * Single checkbox field. Can be used as a direct replacement for traditional checkbox fields.
23612 * Creates a new Checkbox
23613 * @param {Object} config Configuration options
23615 Roo.form.Checkbox = function(config){
23616 Roo.form.Checkbox.superclass.constructor.call(this, config);
23620 * Fires when the checkbox is checked or unchecked.
23621 * @param {Roo.form.Checkbox} this This checkbox
23622 * @param {Boolean} checked The new checked value
23628 Roo.extend(Roo.form.Checkbox, Roo.form.Field, {
23630 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
23632 focusClass : undefined,
23634 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
23636 fieldClass: "x-form-field",
23638 * @cfg {Boolean} checked True if the the checkbox should render already checked (defaults to false)
23642 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
23643 * {tag: "input", type: "checkbox", autocomplete: "off"})
23645 defaultAutoCreate : { tag: "input", type: 'hidden', autocomplete: "off"},
23647 * @cfg {String} boxLabel The text that appears beside the checkbox
23651 * @cfg {String} inputValue The value that should go into the generated input element's value attribute
23655 * @cfg {String} valueOff The value that should go into the generated input element's value when unchecked.
23657 valueOff: '0', // value when not checked..
23659 actionMode : 'viewEl',
23662 itemCls : 'x-menu-check-item x-form-item',
23663 groupClass : 'x-menu-group-item',
23664 inputType : 'hidden',
23667 inSetChecked: false, // check that we are not calling self...
23669 inputElement: false, // real input element?
23670 basedOn: false, // ????
23672 isFormField: true, // not sure where this is needed!!!!
23674 onResize : function(){
23675 Roo.form.Checkbox.superclass.onResize.apply(this, arguments);
23676 if(!this.boxLabel){
23677 this.el.alignTo(this.wrap, 'c-c');
23681 initEvents : function(){
23682 Roo.form.Checkbox.superclass.initEvents.call(this);
23683 this.el.on("click", this.onClick, this);
23684 this.el.on("change", this.onClick, this);
23688 getResizeEl : function(){
23692 getPositionEl : function(){
23697 onRender : function(ct, position){
23698 Roo.form.Checkbox.superclass.onRender.call(this, ct, position);
23700 if(this.inputValue !== undefined){
23701 this.el.dom.value = this.inputValue;
23704 //this.wrap = this.el.wrap({cls: "x-form-check-wrap"});
23705 this.wrap = this.el.wrap({cls: 'x-menu-check-item '});
23706 var viewEl = this.wrap.createChild({
23707 tag: 'img', cls: 'x-menu-item-icon', style: 'margin: 0px;' ,src : Roo.BLANK_IMAGE_URL });
23708 this.viewEl = viewEl;
23709 this.wrap.on('click', this.onClick, this);
23711 this.el.on('DOMAttrModified', this.setFromHidden, this); //ff
23712 this.el.on('propertychange', this.setFromHidden, this); //ie
23717 this.wrap.createChild({tag: 'label', htmlFor: this.el.id, cls: 'x-form-cb-label', html: this.boxLabel});
23718 // viewEl.on('click', this.onClick, this);
23720 //if(this.checked){
23721 this.setChecked(this.checked);
23723 //this.checked = this.el.dom;
23729 initValue : Roo.emptyFn,
23732 * Returns the checked state of the checkbox.
23733 * @return {Boolean} True if checked, else false
23735 getValue : function(){
23737 return String(this.el.dom.value) == String(this.inputValue ) ? this.inputValue : this.valueOff;
23739 return this.valueOff;
23744 onClick : function(){
23745 this.setChecked(!this.checked);
23747 //if(this.el.dom.checked != this.checked){
23748 // this.setValue(this.el.dom.checked);
23753 * Sets the checked state of the checkbox.
23754 * On is always based on a string comparison between inputValue and the param.
23755 * @param {Boolean/String} value - the value to set
23756 * @param {Boolean/String} suppressEvent - whether to suppress the checkchange event.
23758 setValue : function(v,suppressEvent){
23761 //this.checked = (v === true || v === 'true' || v == '1' || String(v).toLowerCase() == 'on');
23762 //if(this.el && this.el.dom){
23763 // this.el.dom.checked = this.checked;
23764 // this.el.dom.defaultChecked = this.checked;
23766 this.setChecked(String(v) === String(this.inputValue), suppressEvent);
23767 //this.fireEvent("check", this, this.checked);
23770 setChecked : function(state,suppressEvent)
23772 if (this.inSetChecked) {
23773 this.checked = state;
23779 this.wrap[state ? 'addClass' : 'removeClass']('x-menu-item-checked');
23781 this.checked = state;
23782 if(suppressEvent !== true){
23783 this.fireEvent('check', this, state);
23785 this.inSetChecked = true;
23786 this.el.dom.value = state ? this.inputValue : this.valueOff;
23787 this.inSetChecked = false;
23790 // handle setting of hidden value by some other method!!?!?
23791 setFromHidden: function()
23796 //console.log("SET FROM HIDDEN");
23797 //alert('setFrom hidden');
23798 this.setValue(this.el.dom.value);
23801 onDestroy : function()
23804 Roo.get(this.viewEl).remove();
23807 Roo.form.Checkbox.superclass.onDestroy.call(this);
23812 * Ext JS Library 1.1.1
23813 * Copyright(c) 2006-2007, Ext JS, LLC.
23815 * Originally Released Under LGPL - original licence link has changed is not relivant.
23818 * <script type="text/javascript">
23822 * @class Roo.form.Radio
23823 * @extends Roo.form.Checkbox
23824 * Single radio field. Same as Checkbox, but provided as a convenience for automatically setting the input type.
23825 * Radio grouping is handled automatically by the browser if you give each radio in a group the same name.
23827 * Creates a new Radio
23828 * @param {Object} config Configuration options
23830 Roo.form.Radio = function(){
23831 Roo.form.Radio.superclass.constructor.apply(this, arguments);
23833 Roo.extend(Roo.form.Radio, Roo.form.Checkbox, {
23834 inputType: 'radio',
23837 * If this radio is part of a group, it will return the selected value
23840 getGroupValue : function(){
23841 return this.el.up('form').child('input[name='+this.el.dom.name+']:checked', true).value;
23843 });//<script type="text/javascript">
23846 * Ext JS Library 1.1.1
23847 * Copyright(c) 2006-2007, Ext JS, LLC.
23848 * licensing@extjs.com
23850 * http://www.extjs.com/license
23856 * Default CSS appears to render it as fixed text by default (should really be Sans-Serif)
23857 * - IE ? - no idea how much works there.
23865 * @class Ext.form.HtmlEditor
23866 * @extends Ext.form.Field
23867 * Provides a lightweight HTML Editor component.
23868 * WARNING - THIS CURRENTlY ONLY WORKS ON FIREFOX - USE FCKeditor for a cross platform version
23870 * <br><br><b>Note: The focus/blur and validation marking functionality inherited from Ext.form.Field is NOT
23871 * supported by this editor.</b><br/><br/>
23872 * An Editor is a sensitive component that can't be used in all spots standard fields can be used. Putting an Editor within
23873 * any element that has display set to 'none' can cause problems in Safari and Firefox.<br/><br/>
23875 Roo.form.HtmlEditor = Roo.extend(Roo.form.Field, {
23877 * @cfg {Array} toolbars Array of toolbars. - defaults to just the Standard one
23881 * @cfg {String} createLinkText The default text for the create link prompt
23883 createLinkText : 'Please enter the URL for the link:',
23885 * @cfg {String} defaultLinkValue The default value for the create link prompt (defaults to http:/ /)
23887 defaultLinkValue : 'http:/'+'/',
23893 // private properties
23894 validationEvent : false,
23896 initialized : false,
23898 sourceEditMode : false,
23899 onFocus : Roo.emptyFn,
23901 hideMode:'offsets',
23902 defaultAutoCreate : {
23904 style:"width:500px;height:300px;",
23905 autocomplete: "off"
23909 initComponent : function(){
23912 * @event initialize
23913 * Fires when the editor is fully initialized (including the iframe)
23914 * @param {HtmlEditor} this
23919 * Fires when the editor is first receives the focus. Any insertion must wait
23920 * until after this event.
23921 * @param {HtmlEditor} this
23925 * @event beforesync
23926 * Fires before the textarea is updated with content from the editor iframe. Return false
23927 * to cancel the sync.
23928 * @param {HtmlEditor} this
23929 * @param {String} html
23933 * @event beforepush
23934 * Fires before the iframe editor is updated with content from the textarea. Return false
23935 * to cancel the push.
23936 * @param {HtmlEditor} this
23937 * @param {String} html
23942 * Fires when the textarea is updated with content from the editor iframe.
23943 * @param {HtmlEditor} this
23944 * @param {String} html
23949 * Fires when the iframe editor is updated with content from the textarea.
23950 * @param {HtmlEditor} this
23951 * @param {String} html
23955 * @event editmodechange
23956 * Fires when the editor switches edit modes
23957 * @param {HtmlEditor} this
23958 * @param {Boolean} sourceEdit True if source edit, false if standard editing.
23960 editmodechange: true,
23962 * @event editorevent
23963 * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks.
23964 * @param {HtmlEditor} this
23971 * Protected method that will not generally be called directly. It
23972 * is called when the editor creates its toolbar. Override this method if you need to
23973 * add custom toolbar buttons.
23974 * @param {HtmlEditor} editor
23976 createToolbar : function(editor){
23977 if (!editor.toolbars || !editor.toolbars.length) {
23978 editor.toolbars = [ new Roo.form.HtmlEditor.ToolbarStandard() ]; // can be empty?
23981 for (var i =0 ; i < editor.toolbars.length;i++) {
23982 editor.toolbars[i] = Roo.factory(editor.toolbars[i], Roo.form.HtmlEditor);
23983 editor.toolbars[i].init(editor);
23990 * Protected method that will not generally be called directly. It
23991 * is called when the editor initializes the iframe with HTML contents. Override this method if you
23992 * want to change the initialization markup of the iframe (e.g. to add stylesheets).
23994 getDocMarkup : function(){
23995 return '<html><head><style type="text/css">body{border:0;margin:0;padding:3px;height:98%;cursor:text;}</style></head><body></body></html>';
23999 onRender : function(ct, position){
24000 Roo.form.HtmlEditor.superclass.onRender.call(this, ct, position);
24001 this.el.dom.style.border = '0 none';
24002 this.el.dom.setAttribute('tabIndex', -1);
24003 this.el.addClass('x-hidden');
24004 if(Roo.isIE){ // fix IE 1px bogus margin
24005 this.el.applyStyles('margin-top:-1px;margin-bottom:-1px;')
24007 this.wrap = this.el.wrap({
24008 cls:'x-html-editor-wrap', cn:{cls:'x-html-editor-tb'}
24011 this.frameId = Roo.id();
24012 this.createToolbar(this);
24019 var iframe = this.wrap.createChild({
24022 name: this.frameId,
24023 frameBorder : 'no',
24024 'src' : Roo.SSL_SECURE_URL ? Roo.SSL_SECURE_URL : "javascript:false"
24027 // console.log(iframe);
24028 //this.wrap.dom.appendChild(iframe);
24030 this.iframe = iframe.dom;
24032 this.assignDocWin();
24034 this.doc.designMode = 'on';
24037 this.doc.write(this.getDocMarkup());
24041 var task = { // must defer to wait for browser to be ready
24043 //console.log("run task?" + this.doc.readyState);
24044 this.assignDocWin();
24045 if(this.doc.body || this.doc.readyState == 'complete'){
24047 this.doc.designMode="on";
24051 Roo.TaskMgr.stop(task);
24052 this.initEditor.defer(10, this);
24059 Roo.TaskMgr.start(task);
24062 this.setSize(this.el.getSize());
24067 onResize : function(w, h){
24068 Roo.form.HtmlEditor.superclass.onResize.apply(this, arguments);
24069 if(this.el && this.iframe){
24070 if(typeof w == 'number'){
24071 var aw = w - this.wrap.getFrameWidth('lr');
24072 this.el.setWidth(this.adjustWidth('textarea', aw));
24073 this.iframe.style.width = aw + 'px';
24075 if(typeof h == 'number'){
24077 for (var i =0; i < this.toolbars.length;i++) {
24078 // fixme - ask toolbars for heights?
24079 tbh += this.toolbars[i].tb.el.getHeight();
24085 var ah = h - this.wrap.getFrameWidth('tb') - tbh;// this.tb.el.getHeight();
24086 this.el.setHeight(this.adjustWidth('textarea', ah));
24087 this.iframe.style.height = ah + 'px';
24089 (this.doc.body || this.doc.documentElement).style.height = (ah - (this.iframePad*2)) + 'px';
24096 * Toggles the editor between standard and source edit mode.
24097 * @param {Boolean} sourceEdit (optional) True for source edit, false for standard
24099 toggleSourceEdit : function(sourceEditMode){
24101 this.sourceEditMode = sourceEditMode === true;
24103 if(this.sourceEditMode){
24106 this.iframe.className = 'x-hidden';
24107 this.el.removeClass('x-hidden');
24108 this.el.dom.removeAttribute('tabIndex');
24113 this.iframe.className = '';
24114 this.el.addClass('x-hidden');
24115 this.el.dom.setAttribute('tabIndex', -1);
24118 this.setSize(this.wrap.getSize());
24119 this.fireEvent('editmodechange', this, this.sourceEditMode);
24122 // private used internally
24123 createLink : function(){
24124 var url = prompt(this.createLinkText, this.defaultLinkValue);
24125 if(url && url != 'http:/'+'/'){
24126 this.relayCmd('createlink', url);
24130 // private (for BoxComponent)
24131 adjustSize : Roo.BoxComponent.prototype.adjustSize,
24133 // private (for BoxComponent)
24134 getResizeEl : function(){
24138 // private (for BoxComponent)
24139 getPositionEl : function(){
24144 initEvents : function(){
24145 this.originalValue = this.getValue();
24149 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24152 markInvalid : Roo.emptyFn,
24154 * Overridden and disabled. The editor element does not support standard valid/invalid marking. @hide
24157 clearInvalid : Roo.emptyFn,
24159 setValue : function(v){
24160 Roo.form.HtmlEditor.superclass.setValue.call(this, v);
24165 * Protected method that will not generally be called directly. If you need/want
24166 * custom HTML cleanup, this is the method you should override.
24167 * @param {String} html The HTML to be cleaned
24168 * return {String} The cleaned HTML
24170 cleanHtml : function(html){
24171 html = String(html);
24172 if(html.length > 5){
24173 if(Roo.isSafari){ // strip safari nonsense
24174 html = html.replace(/\sclass="(?:Apple-style-span|khtml-block-placeholder)"/gi, '');
24177 if(html == ' '){
24184 * Protected method that will not generally be called directly. Syncs the contents
24185 * of the editor iframe with the textarea.
24187 syncValue : function(){
24188 if(this.initialized){
24189 var bd = (this.doc.body || this.doc.documentElement);
24190 var html = bd.innerHTML;
24192 var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element!
24193 var m = bs.match(/text-align:(.*?);/i);
24195 html = '<div style="'+m[0]+'">' + html + '</div>';
24198 html = this.cleanHtml(html);
24199 if(this.fireEvent('beforesync', this, html) !== false){
24200 this.el.dom.value = html;
24201 this.fireEvent('sync', this, html);
24207 * Protected method that will not generally be called directly. Pushes the value of the textarea
24208 * into the iframe editor.
24210 pushValue : function(){
24211 if(this.initialized){
24212 var v = this.el.dom.value;
24216 if(this.fireEvent('beforepush', this, v) !== false){
24217 (this.doc.body || this.doc.documentElement).innerHTML = v;
24218 this.fireEvent('push', this, v);
24224 deferFocus : function(){
24225 this.focus.defer(10, this);
24229 focus : function(){
24230 if(this.win && !this.sourceEditMode){
24237 assignDocWin: function()
24239 var iframe = this.iframe;
24242 this.doc = iframe.contentWindow.document;
24243 this.win = iframe.contentWindow;
24245 if (!Roo.get(this.frameId)) {
24248 this.doc = (iframe.contentDocument || Roo.get(this.frameId).dom.document);
24249 this.win = Roo.get(this.frameId).dom.contentWindow;
24254 initEditor : function(){
24255 //console.log("INIT EDITOR");
24256 this.assignDocWin();
24260 this.doc.designMode="on";
24262 this.doc.write(this.getDocMarkup());
24265 var dbody = (this.doc.body || this.doc.documentElement);
24266 //var ss = this.el.getStyles('font-size', 'font-family', 'background-image', 'background-repeat');
24267 // this copies styles from the containing element into thsi one..
24268 // not sure why we need all of this..
24269 var ss = this.el.getStyles('font-size', 'background-image', 'background-repeat');
24270 ss['background-attachment'] = 'fixed'; // w3c
24271 dbody.bgProperties = 'fixed'; // ie
24272 Roo.DomHelper.applyStyles(dbody, ss);
24273 Roo.EventManager.on(this.doc, {
24274 'mousedown': this.onEditorEvent,
24275 'dblclick': this.onEditorEvent,
24276 'click': this.onEditorEvent,
24277 'keyup': this.onEditorEvent,
24282 Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this);
24284 if(Roo.isIE || Roo.isSafari || Roo.isOpera){
24285 Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this);
24287 this.initialized = true;
24289 this.fireEvent('initialize', this);
24294 onDestroy : function(){
24300 for (var i =0; i < this.toolbars.length;i++) {
24301 // fixme - ask toolbars for heights?
24302 this.toolbars[i].onDestroy();
24305 this.wrap.dom.innerHTML = '';
24306 this.wrap.remove();
24311 onFirstFocus : function(){
24313 this.assignDocWin();
24316 this.activated = true;
24317 for (var i =0; i < this.toolbars.length;i++) {
24318 this.toolbars[i].onFirstFocus();
24321 if(Roo.isGecko){ // prevent silly gecko errors
24323 var s = this.win.getSelection();
24324 if(!s.focusNode || s.focusNode.nodeType != 3){
24325 var r = s.getRangeAt(0);
24326 r.selectNodeContents((this.doc.body || this.doc.documentElement));
24331 this.execCmd('useCSS', true);
24332 this.execCmd('styleWithCSS', false);
24335 this.fireEvent('activate', this);
24339 adjustFont: function(btn){
24340 var adjust = btn.cmd == 'increasefontsize' ? 1 : -1;
24341 //if(Roo.isSafari){ // safari
24344 var v = parseInt(this.doc.queryCommandValue('FontSize')|| 3, 10);
24345 if(Roo.isSafari){ // safari
24346 var sm = { 10 : 1, 13: 2, 16:3, 18:4, 24: 5, 32:6, 48: 7 };
24347 v = (v < 10) ? 10 : v;
24348 v = (v > 48) ? 48 : v;
24349 v = typeof(sm[v]) == 'undefined' ? 1 : sm[v];
24354 v = Math.max(1, v+adjust);
24356 this.execCmd('FontSize', v );
24359 onEditorEvent : function(e){
24360 this.fireEvent('editorevent', this, e);
24361 // this.updateToolbar();
24365 insertTag : function(tg)
24367 // could be a bit smarter... -> wrap the current selected tRoo..
24369 this.execCmd("formatblock", tg);
24373 insertText : function(txt)
24377 range = this.createRange();
24378 range.deleteContents();
24379 //alert(Sender.getAttribute('label'));
24381 range.insertNode(this.doc.createTextNode(txt));
24385 relayBtnCmd : function(btn){
24386 this.relayCmd(btn.cmd);
24390 * Executes a Midas editor command on the editor document and performs necessary focus and
24391 * toolbar updates. <b>This should only be called after the editor is initialized.</b>
24392 * @param {String} cmd The Midas command
24393 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24395 relayCmd : function(cmd, value){
24397 this.execCmd(cmd, value);
24398 this.fireEvent('editorevent', this);
24399 //this.updateToolbar();
24404 * Executes a Midas editor command directly on the editor document.
24405 * For visual commands, you should use {@link #relayCmd} instead.
24406 * <b>This should only be called after the editor is initialized.</b>
24407 * @param {String} cmd The Midas command
24408 * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null)
24410 execCmd : function(cmd, value){
24411 this.doc.execCommand(cmd, false, value === undefined ? null : value);
24417 * Inserts the passed text at the current cursor position. Note: the editor must be initialized and activated
24419 * @param {String} text
24421 insertAtCursor : function(text){
24422 if(!this.activated){
24427 var r = this.doc.selection.createRange();
24434 }else if(Roo.isGecko || Roo.isOpera || Roo.isSafari){
24436 this.execCmd('InsertHTML', text);
24441 mozKeyPress : function(e){
24443 var c = e.getCharCode(), cmd;
24446 c = String.fromCharCode(c).toLowerCase();
24457 this.cleanUpPaste.defer(100, this);
24465 e.preventDefault();
24473 fixKeys : function(){ // load time branching for fastest keydown performance
24475 return function(e){
24476 var k = e.getKey(), r;
24479 r = this.doc.selection.createRange();
24482 r.pasteHTML('    ');
24489 r = this.doc.selection.createRange();
24491 var target = r.parentElement();
24492 if(!target || target.tagName.toLowerCase() != 'li'){
24494 r.pasteHTML('<br />');
24500 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24501 this.cleanUpPaste.defer(100, this);
24507 }else if(Roo.isOpera){
24508 return function(e){
24509 var k = e.getKey();
24513 this.execCmd('InsertHTML','    ');
24516 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24517 this.cleanUpPaste.defer(100, this);
24522 }else if(Roo.isSafari){
24523 return function(e){
24524 var k = e.getKey();
24528 this.execCmd('InsertText','\t');
24532 if (String.fromCharCode(k).toLowerCase() == 'v') { // paste
24533 this.cleanUpPaste.defer(100, this);
24541 getAllAncestors: function()
24543 var p = this.getSelectedNode();
24546 a.push(p); // push blank onto stack..
24547 p = this.getParentElement();
24551 while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
24555 a.push(this.doc.body);
24559 lastSelNode : false,
24562 getSelection : function()
24564 this.assignDocWin();
24565 return Roo.isIE ? this.doc.selection : this.win.getSelection();
24568 getSelectedNode: function()
24570 // this may only work on Gecko!!!
24572 // should we cache this!!!!
24577 var range = this.createRange(this.getSelection());
24580 var parent = range.parentElement();
24582 var testRange = range.duplicate();
24583 testRange.moveToElementText(parent);
24584 if (testRange.inRange(range)) {
24587 if ((parent.nodeType != 1) || (parent.tagName.toLowerCase() == 'body')) {
24590 parent = parent.parentElement;
24596 var ar = range.endContainer.childNodes;
24598 ar = range.commonAncestorContainer.childNodes;
24599 //alert(ar.length);
24602 var other_nodes = [];
24603 var has_other_nodes = false;
24604 for (var i=0;i<ar.length;i++) {
24605 if ((ar[i].nodeType == 3) && (!ar[i].data.length)) { // empty text ?
24608 // fullly contained node.
24610 if (this.rangeIntersectsNode(range,ar[i]) && this.rangeCompareNode(range,ar[i]) == 3) {
24615 // probably selected..
24616 if ((ar[i].nodeType == 1) && this.rangeIntersectsNode(range,ar[i]) && (this.rangeCompareNode(range,ar[i]) > 0)) {
24617 other_nodes.push(ar[i]);
24620 if (!this.rangeIntersectsNode(range,ar[i])|| (this.rangeCompareNode(range,ar[i]) == 0)) {
24625 has_other_nodes = true;
24627 if (!nodes.length && other_nodes.length) {
24628 nodes= other_nodes;
24630 if (has_other_nodes || !nodes.length || (nodes.length > 1)) {
24636 createRange: function(sel)
24638 // this has strange effects when using with
24639 // top toolbar - not sure if it's a great idea.
24640 //this.editor.contentWindow.focus();
24641 if (typeof sel != "undefined") {
24643 return sel.getRangeAt ? sel.getRangeAt(0) : sel.createRange();
24645 return this.doc.createRange();
24648 return this.doc.createRange();
24651 getParentElement: function()
24654 this.assignDocWin();
24655 var sel = Roo.isIE ? this.doc.selection : this.win.getSelection();
24657 var range = this.createRange(sel);
24660 var p = range.commonAncestorContainer;
24661 while (p.nodeType == 3) { // text node
24673 // BC Hacks - cause I cant work out what i was trying to do..
24674 rangeIntersectsNode : function(range, node)
24676 var nodeRange = node.ownerDocument.createRange();
24678 nodeRange.selectNode(node);
24681 nodeRange.selectNodeContents(node);
24684 return range.compareBoundaryPoints(Range.END_TO_START, nodeRange) == -1 &&
24685 range.compareBoundaryPoints(Range.START_TO_END, nodeRange) == 1;
24687 rangeCompareNode : function(range, node) {
24688 var nodeRange = node.ownerDocument.createRange();
24690 nodeRange.selectNode(node);
24692 nodeRange.selectNodeContents(node);
24694 var nodeIsBefore = range.compareBoundaryPoints(Range.START_TO_START, nodeRange) == 1;
24695 var nodeIsAfter = range.compareBoundaryPoints(Range.END_TO_END, nodeRange) == -1;
24697 if (nodeIsBefore && !nodeIsAfter)
24699 if (!nodeIsBefore && nodeIsAfter)
24701 if (nodeIsBefore && nodeIsAfter)
24707 // private? - in a new class?
24708 cleanUpPaste : function()
24710 // cleans up the whole document..
24711 // console.log('cleanuppaste');
24712 this.cleanUpChildren(this.doc.body)
24716 cleanUpChildren : function (n)
24718 if (!n.childNodes.length) {
24721 for (var i = n.childNodes.length-1; i > -1 ; i--) {
24722 this.cleanUpChild(n.childNodes[i]);
24729 cleanUpChild : function (node)
24731 //console.log(node);
24732 if (node.nodeName == "#text") {
24733 // clean up silly Windows -- stuff?
24736 if (node.nodeName == "#comment") {
24737 node.parentNode.removeChild(node);
24738 // clean up silly Windows -- stuff?
24742 if (Roo.form.HtmlEditor.black.indexOf(node.tagName.toLowerCase()) > -1) {
24744 node.parentNode.removeChild(node);
24748 if (!node.attributes || !node.attributes.length) {
24749 this.cleanUpChildren(node);
24753 function cleanAttr(n,v)
24756 if (v.match(/^\./) || v.match(/^\//)) {
24759 if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/)) {
24762 Roo.log("(REMOVE)"+ node.tagName +'.' + n + '=' + v);
24763 node.removeAttribute(n);
24767 function cleanStyle(n,v)
24769 if (v.match(/expression/)) { //XSS?? should we even bother..
24770 node.removeAttribute(n);
24775 var parts = v.split(/;/);
24776 Roo.each(parts, function(p) {
24777 p = p.replace(/\s+/g,'');
24781 var l = p.split(':').shift().replace(/\s+/g,'');
24783 if (Roo.form.HtmlEditor.cwhite.indexOf(l) < 0) {
24784 Roo.log('(REMOVE)' + node.tagName +'.' + n + ':'+l + '=' + v);
24785 node.removeAttribute(n);
24794 for (var i = node.attributes.length-1; i > -1 ; i--) {
24795 var a = node.attributes[i];
24797 if (Roo.form.HtmlEditor.ablack.indexOf(a.name.toLowerCase()) > -1) {
24798 node.removeAttribute(a.name);
24801 if (Roo.form.HtmlEditor.aclean.indexOf(a.name.toLowerCase()) > -1) {
24802 cleanAttr(a.name,a.value); // fixme..
24805 if (a.name == 'style') {
24806 cleanStyle(a.name,a.value);
24808 /// clean up MS crap..
24809 if (a.name == 'class') {
24810 if (a.value.match(/^Mso/)) {
24811 node.className = '';
24821 this.cleanUpChildren(node);
24827 // hide stuff that is not compatible
24841 * @event specialkey
24845 * @cfg {String} fieldClass @hide
24848 * @cfg {String} focusClass @hide
24851 * @cfg {String} autoCreate @hide
24854 * @cfg {String} inputType @hide
24857 * @cfg {String} invalidClass @hide
24860 * @cfg {String} invalidText @hide
24863 * @cfg {String} msgFx @hide
24866 * @cfg {String} validateOnBlur @hide
24870 Roo.form.HtmlEditor.white = [
24871 'area', 'br', 'img', 'input', 'hr', 'wbr',
24873 'address', 'blockquote', 'center', 'dd', 'dir', 'div',
24874 'dl', 'dt', 'h1', 'h2', 'h3', 'h4',
24875 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee',
24876 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre',
24877 'table', 'ul', 'xmp',
24879 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th',
24882 'dir', 'menu', 'ol', 'ul', 'dl',
24888 Roo.form.HtmlEditor.black = [
24889 // 'embed', 'object', // enable - backend responsiblity to clean thiese
24891 'base', 'basefont', 'bgsound', 'blink', 'body',
24892 'frame', 'frameset', 'head', 'html', 'ilayer',
24893 'iframe', 'layer', 'link', 'meta', 'object',
24894 'script', 'style' ,'title', 'xml' // clean later..
24896 Roo.form.HtmlEditor.clean = [
24897 'script', 'style', 'title', 'xml'
24902 Roo.form.HtmlEditor.ablack = [
24906 Roo.form.HtmlEditor.aclean = [
24907 'action', 'background', 'codebase', 'dynsrc', 'href', 'lowsrc'
24911 Roo.form.HtmlEditor.pwhite= [
24912 'http', 'https', 'mailto'
24915 Roo.form.HtmlEditor.cwhite= [
24920 // <script type="text/javascript">
24923 * Ext JS Library 1.1.1
24924 * Copyright(c) 2006-2007, Ext JS, LLC.
24930 * @class Roo.form.HtmlEditorToolbar1
24935 new Roo.form.HtmlEditor({
24938 new Roo.form.HtmlEditorToolbar1({
24939 disable : { fonts: 1 , format: 1, ..., ... , ...],
24945 * @cfg {Object} disable List of elements to disable..
24946 * @cfg {Array} btns List of additional buttons.
24950 * .x-html-editor-tb .x-edit-none .x-btn-text { background: none; }
24953 Roo.form.HtmlEditor.ToolbarStandard = function(config)
24956 Roo.apply(this, config);
24957 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
24958 // dont call parent... till later.
24961 Roo.apply(Roo.form.HtmlEditor.ToolbarStandard.prototype, {
24969 * @cfg {Object} disable List of toolbar elements to disable
24974 * @cfg {Array} fontFamilies An array of available font families
24992 // "á" , ?? a acute?
24997 "°" // , // degrees
24999 // "é" , // e ecute
25000 // "ú" , // u ecute?
25003 "form", "input:text", "input:hidden", "input:checkbox", "input:radio", "input:password",
25004 "input:submit", "input:button", "select", "textarea", "label" ],
25007 ["h1"],["h2"],["h3"],["h4"],["h5"],["h6"],
25009 ["abbr"],[ "acronym"],[ "address"],[ "cite"],[ "samp"],[ "var"]
25012 * @cfg {String} defaultFont default font to use.
25014 defaultFont: 'tahoma',
25016 fontSelect : false,
25019 formatCombo : false,
25021 init : function(editor)
25023 this.editor = editor;
25026 var fid = editor.frameId;
25028 function btn(id, toggle, handler){
25029 var xid = fid + '-'+ id ;
25033 cls : 'x-btn-icon x-edit-'+id,
25034 enableToggle:toggle !== false,
25035 scope: editor, // was editor...
25036 handler:handler||editor.relayBtnCmd,
25037 clickEvent:'mousedown',
25038 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25045 var tb = new Roo.Toolbar(editor.wrap.dom.firstChild);
25047 // stop form submits
25048 tb.el.on('click', function(e){
25049 e.preventDefault(); // what does this do?
25052 if(!this.disable.font && !Roo.isSafari){
25053 /* why no safari for fonts
25054 editor.fontSelect = tb.el.createChild({
25057 cls:'x-font-select',
25058 html: editor.createFontOptions()
25060 editor.fontSelect.on('change', function(){
25061 var font = editor.fontSelect.dom.value;
25062 editor.relayCmd('fontname', font);
25063 editor.deferFocus();
25066 editor.fontSelect.dom,
25071 if(!this.disable.formats){
25072 this.formatCombo = new Roo.form.ComboBox({
25073 store: new Roo.data.SimpleStore({
25076 data : this.formats // from states.js
25079 //autoCreate : {tag: "div", size: "20"},
25080 displayField:'tag',
25084 triggerAction: 'all',
25085 emptyText:'Add tag',
25086 selectOnFocus:true,
25089 'select': function(c, r, i) {
25090 editor.insertTag(r.get('tag'));
25096 tb.addField(this.formatCombo);
25100 if(!this.disable.format){
25107 if(!this.disable.fontSize){
25112 btn('increasefontsize', false, editor.adjustFont),
25113 btn('decreasefontsize', false, editor.adjustFont)
25118 if(this.disable.colors){
25121 id:editor.frameId +'-forecolor',
25122 cls:'x-btn-icon x-edit-forecolor',
25123 clickEvent:'mousedown',
25124 tooltip: this.buttonTips['forecolor'] || undefined,
25126 menu : new Roo.menu.ColorMenu({
25127 allowReselect: true,
25128 focus: Roo.emptyFn,
25131 selectHandler: function(cp, color){
25132 editor.execCmd('forecolor', Roo.isSafari || Roo.isIE ? '#'+color : color);
25133 editor.deferFocus();
25136 clickEvent:'mousedown'
25139 id:editor.frameId +'backcolor',
25140 cls:'x-btn-icon x-edit-backcolor',
25141 clickEvent:'mousedown',
25142 tooltip: this.buttonTips['backcolor'] || undefined,
25144 menu : new Roo.menu.ColorMenu({
25145 focus: Roo.emptyFn,
25148 allowReselect: true,
25149 selectHandler: function(cp, color){
25151 editor.execCmd('useCSS', false);
25152 editor.execCmd('hilitecolor', color);
25153 editor.execCmd('useCSS', true);
25154 editor.deferFocus();
25156 editor.execCmd(Roo.isOpera ? 'hilitecolor' : 'backcolor',
25157 Roo.isSafari || Roo.isIE ? '#'+color : color);
25158 editor.deferFocus();
25162 clickEvent:'mousedown'
25167 // now add all the items...
25170 if(!this.disable.alignments){
25173 btn('justifyleft'),
25174 btn('justifycenter'),
25175 btn('justifyright')
25179 //if(!Roo.isSafari){
25180 if(!this.disable.links){
25183 btn('createlink', false, editor.createLink) /// MOVE TO HERE?!!?!?!?!
25187 if(!this.disable.lists){
25190 btn('insertorderedlist'),
25191 btn('insertunorderedlist')
25194 if(!this.disable.sourceEdit){
25197 btn('sourceedit', true, function(btn){
25198 this.toggleSourceEdit(btn.pressed);
25205 // special menu.. - needs to be tidied up..
25206 if (!this.disable.special) {
25209 cls: 'x-edit-none',
25214 for (var i =0; i < this.specialChars.length; i++) {
25215 smenu.menu.items.push({
25217 html: this.specialChars[i],
25218 handler: function(a,b) {
25219 editor.insertAtCursor(String.fromCharCode(a.html.replace('&#','').replace(';', '')));
25232 for(var i =0; i< this.btns.length;i++) {
25233 var b = this.btns[i];
25234 b.cls = 'x-edit-none';
25243 // disable everything...
25245 this.tb.items.each(function(item){
25246 if(item.id != editor.frameId+ '-sourceedit'){
25250 this.rendered = true;
25252 // the all the btns;
25253 editor.on('editorevent', this.updateToolbar, this);
25254 // other toolbars need to implement this..
25255 //editor.on('editmodechange', this.updateToolbar, this);
25261 * Protected method that will not generally be called directly. It triggers
25262 * a toolbar update by reading the markup state of the current selection in the editor.
25264 updateToolbar: function(){
25266 if(!this.editor.activated){
25267 this.editor.onFirstFocus();
25271 var btns = this.tb.items.map,
25272 doc = this.editor.doc,
25273 frameId = this.editor.frameId;
25275 if(!this.disable.font && !Roo.isSafari){
25277 var name = (doc.queryCommandValue('FontName')||this.editor.defaultFont).toLowerCase();
25278 if(name != this.fontSelect.dom.value){
25279 this.fontSelect.dom.value = name;
25283 if(!this.disable.format){
25284 btns[frameId + '-bold'].toggle(doc.queryCommandState('bold'));
25285 btns[frameId + '-italic'].toggle(doc.queryCommandState('italic'));
25286 btns[frameId + '-underline'].toggle(doc.queryCommandState('underline'));
25288 if(!this.disable.alignments){
25289 btns[frameId + '-justifyleft'].toggle(doc.queryCommandState('justifyleft'));
25290 btns[frameId + '-justifycenter'].toggle(doc.queryCommandState('justifycenter'));
25291 btns[frameId + '-justifyright'].toggle(doc.queryCommandState('justifyright'));
25293 if(!Roo.isSafari && !this.disable.lists){
25294 btns[frameId + '-insertorderedlist'].toggle(doc.queryCommandState('insertorderedlist'));
25295 btns[frameId + '-insertunorderedlist'].toggle(doc.queryCommandState('insertunorderedlist'));
25298 var ans = this.editor.getAllAncestors();
25299 if (this.formatCombo) {
25302 var store = this.formatCombo.store;
25303 this.formatCombo.setValue("");
25304 for (var i =0; i < ans.length;i++) {
25305 if (ans[i] && store.query('tag',ans[i].tagName.toLowerCase(), false).length) {
25307 this.formatCombo.setValue(ans[i].tagName.toLowerCase());
25315 // hides menus... - so this cant be on a menu...
25316 Roo.menu.MenuMgr.hideAll();
25318 //this.editorsyncValue();
25322 createFontOptions : function(){
25323 var buf = [], fs = this.fontFamilies, ff, lc;
25324 for(var i = 0, len = fs.length; i< len; i++){
25326 lc = ff.toLowerCase();
25328 '<option value="',lc,'" style="font-family:',ff,';"',
25329 (this.defaultFont == lc ? ' selected="true">' : '>'),
25334 return buf.join('');
25337 toggleSourceEdit : function(sourceEditMode){
25338 if(sourceEditMode === undefined){
25339 sourceEditMode = !this.sourceEditMode;
25341 this.sourceEditMode = sourceEditMode === true;
25342 var btn = this.tb.items.get(this.editor.frameId +'-sourceedit');
25343 // just toggle the button?
25344 if(btn.pressed !== this.editor.sourceEditMode){
25345 btn.toggle(this.editor.sourceEditMode);
25349 if(this.sourceEditMode){
25350 this.tb.items.each(function(item){
25351 if(item.cmd != 'sourceedit'){
25357 if(this.initialized){
25358 this.tb.items.each(function(item){
25364 // tell the editor that it's been pressed..
25365 this.editor.toggleSourceEdit(sourceEditMode);
25369 * Object collection of toolbar tooltips for the buttons in the editor. The key
25370 * is the command id associated with that button and the value is a valid QuickTips object.
25375 title: 'Bold (Ctrl+B)',
25376 text: 'Make the selected text bold.',
25377 cls: 'x-html-editor-tip'
25380 title: 'Italic (Ctrl+I)',
25381 text: 'Make the selected text italic.',
25382 cls: 'x-html-editor-tip'
25390 title: 'Bold (Ctrl+B)',
25391 text: 'Make the selected text bold.',
25392 cls: 'x-html-editor-tip'
25395 title: 'Italic (Ctrl+I)',
25396 text: 'Make the selected text italic.',
25397 cls: 'x-html-editor-tip'
25400 title: 'Underline (Ctrl+U)',
25401 text: 'Underline the selected text.',
25402 cls: 'x-html-editor-tip'
25404 increasefontsize : {
25405 title: 'Grow Text',
25406 text: 'Increase the font size.',
25407 cls: 'x-html-editor-tip'
25409 decreasefontsize : {
25410 title: 'Shrink Text',
25411 text: 'Decrease the font size.',
25412 cls: 'x-html-editor-tip'
25415 title: 'Text Highlight Color',
25416 text: 'Change the background color of the selected text.',
25417 cls: 'x-html-editor-tip'
25420 title: 'Font Color',
25421 text: 'Change the color of the selected text.',
25422 cls: 'x-html-editor-tip'
25425 title: 'Align Text Left',
25426 text: 'Align text to the left.',
25427 cls: 'x-html-editor-tip'
25430 title: 'Center Text',
25431 text: 'Center text in the editor.',
25432 cls: 'x-html-editor-tip'
25435 title: 'Align Text Right',
25436 text: 'Align text to the right.',
25437 cls: 'x-html-editor-tip'
25439 insertunorderedlist : {
25440 title: 'Bullet List',
25441 text: 'Start a bulleted list.',
25442 cls: 'x-html-editor-tip'
25444 insertorderedlist : {
25445 title: 'Numbered List',
25446 text: 'Start a numbered list.',
25447 cls: 'x-html-editor-tip'
25450 title: 'Hyperlink',
25451 text: 'Make the selected text a hyperlink.',
25452 cls: 'x-html-editor-tip'
25455 title: 'Source Edit',
25456 text: 'Switch to source editing mode.',
25457 cls: 'x-html-editor-tip'
25461 onDestroy : function(){
25464 this.tb.items.each(function(item){
25466 item.menu.removeAll();
25468 item.menu.el.destroy();
25476 onFirstFocus: function() {
25477 this.tb.items.each(function(item){
25486 // <script type="text/javascript">
25489 * Ext JS Library 1.1.1
25490 * Copyright(c) 2006-2007, Ext JS, LLC.
25497 * @class Roo.form.HtmlEditor.ToolbarContext
25502 new Roo.form.HtmlEditor({
25505 new Roo.form.HtmlEditor.ToolbarStandard(),
25506 new Roo.form.HtmlEditor.ToolbarContext()
25511 * @config : {Object} disable List of elements to disable.. (not done yet.)
25516 Roo.form.HtmlEditor.ToolbarContext = function(config)
25519 Roo.apply(this, config);
25520 //Roo.form.HtmlEditorToolbar1.superclass.constructor.call(this, editor.wrap.dom.firstChild, [], config);
25521 // dont call parent... till later.
25523 Roo.form.HtmlEditor.ToolbarContext.types = {
25535 opts : [ [""],[ "left"],[ "right"],[ "center"],[ "top"]],
25597 opts : [[""],[ "left"],[ "center"],[ "right"],[ "justify"],[ "char"]],
25602 opts : [[""],[ "top"],[ "middle"],[ "bottom"],[ "baseline"]],
25666 Roo.apply(Roo.form.HtmlEditor.ToolbarContext.prototype, {
25674 * @cfg {Object} disable List of toolbar elements to disable
25683 init : function(editor)
25685 this.editor = editor;
25688 var fid = editor.frameId;
25690 function btn(id, toggle, handler){
25691 var xid = fid + '-'+ id ;
25695 cls : 'x-btn-icon x-edit-'+id,
25696 enableToggle:toggle !== false,
25697 scope: editor, // was editor...
25698 handler:handler||editor.relayBtnCmd,
25699 clickEvent:'mousedown',
25700 tooltip: etb.buttonTips[id] || undefined, ///tips ???
25704 // create a new element.
25705 var wdiv = editor.wrap.createChild({
25707 }, editor.wrap.dom.firstChild.nextSibling, true);
25709 // can we do this more than once??
25711 // stop form submits
25714 // disable everything...
25715 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25716 this.toolbars = {};
25718 for (var i in ty) {
25720 this.toolbars[i] = this.buildToolbar(ty[i],i);
25722 this.tb = this.toolbars.BODY;
25726 this.rendered = true;
25728 // the all the btns;
25729 editor.on('editorevent', this.updateToolbar, this);
25730 // other toolbars need to implement this..
25731 //editor.on('editmodechange', this.updateToolbar, this);
25737 * Protected method that will not generally be called directly. It triggers
25738 * a toolbar update by reading the markup state of the current selection in the editor.
25740 updateToolbar: function(){
25742 if(!this.editor.activated){
25743 this.editor.onFirstFocus();
25748 var ans = this.editor.getAllAncestors();
25751 var ty= Roo.form.HtmlEditor.ToolbarContext.types;
25752 var sel = ans.length ? (ans[0] ? ans[0] : ans[1]) : this.editor.doc.body;
25753 sel = sel ? sel : this.editor.doc.body;
25754 sel = sel.tagName.length ? sel : this.editor.doc.body;
25755 var tn = sel.tagName.toUpperCase();
25756 sel = typeof(ty[tn]) != 'undefined' ? sel : this.editor.doc.body;
25757 tn = sel.tagName.toUpperCase();
25758 if (this.tb.name == tn) {
25759 return; // no change
25762 ///console.log("show: " + tn);
25763 this.tb = this.toolbars[tn];
25765 this.tb.fields.each(function(e) {
25766 e.setValue(sel.getAttribute(e.name));
25768 this.tb.selectedNode = sel;
25771 Roo.menu.MenuMgr.hideAll();
25773 //this.editorsyncValue();
25778 onDestroy : function(){
25781 this.tb.items.each(function(item){
25783 item.menu.removeAll();
25785 item.menu.el.destroy();
25793 onFirstFocus: function() {
25794 // need to do this for all the toolbars..
25795 this.tb.items.each(function(item){
25799 buildToolbar: function(tlist, nm)
25801 var editor = this.editor;
25802 // create a new element.
25803 var wdiv = editor.wrap.createChild({
25805 }, editor.wrap.dom.firstChild.nextSibling, true);
25808 var tb = new Roo.Toolbar(wdiv);
25809 tb.add(nm+ ": ");
25810 for (var i in tlist) {
25811 var item = tlist[i];
25812 tb.add(item.title + ": ");
25817 tb.addField( new Roo.form.ComboBox({
25818 store: new Roo.data.SimpleStore({
25821 data : item.opts // from states.js
25824 displayField:'val',
25828 triggerAction: 'all',
25829 emptyText:'Select',
25830 selectOnFocus:true,
25831 width: item.width ? item.width : 130,
25833 'select': function(c, r, i) {
25834 tb.selectedNode.setAttribute(c.name, r.get('val'));
25845 tb.addField( new Roo.form.TextField({
25848 //allowBlank:false,
25853 tb.addField( new Roo.form.TextField({
25859 'change' : function(f, nv, ov) {
25860 tb.selectedNode.setAttribute(f.name, nv);
25866 tb.el.on('click', function(e){
25867 e.preventDefault(); // what does this do?
25869 tb.el.setVisibilityMode( Roo.Element.DISPLAY);
25872 // dont need to disable them... as they will get hidden
25889 * Ext JS Library 1.1.1
25890 * Copyright(c) 2006-2007, Ext JS, LLC.
25892 * Originally Released Under LGPL - original licence link has changed is not relivant.
25895 * <script type="text/javascript">
25899 * @class Roo.form.BasicForm
25900 * @extends Roo.util.Observable
25901 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
25903 * @param {String/HTMLElement/Roo.Element} el The form element or its id
25904 * @param {Object} config Configuration options
25906 Roo.form.BasicForm = function(el, config){
25907 this.allItems = [];
25908 this.childForms = [];
25909 Roo.apply(this, config);
25911 * The Roo.form.Field items in this form.
25912 * @type MixedCollection
25916 this.items = new Roo.util.MixedCollection(false, function(o){
25917 return o.id || (o.id = Roo.id());
25921 * @event beforeaction
25922 * Fires before any action is performed. Return false to cancel the action.
25923 * @param {Form} this
25924 * @param {Action} action The action to be performed
25926 beforeaction: true,
25928 * @event actionfailed
25929 * Fires when an action fails.
25930 * @param {Form} this
25931 * @param {Action} action The action that failed
25933 actionfailed : true,
25935 * @event actioncomplete
25936 * Fires when an action is completed.
25937 * @param {Form} this
25938 * @param {Action} action The action that completed
25940 actioncomplete : true
25945 Roo.form.BasicForm.superclass.constructor.call(this);
25948 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
25950 * @cfg {String} method
25951 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
25954 * @cfg {DataReader} reader
25955 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
25956 * This is optional as there is built-in support for processing JSON.
25959 * @cfg {DataReader} errorReader
25960 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
25961 * This is completely optional as there is built-in support for processing JSON.
25964 * @cfg {String} url
25965 * The URL to use for form actions if one isn't supplied in the action options.
25968 * @cfg {Boolean} fileUpload
25969 * Set to true if this form is a file upload.
25972 * @cfg {Object} baseParams
25973 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
25976 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
25981 activeAction : null,
25984 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
25985 * or setValues() data instead of when the form was first created.
25987 trackResetOnLoad : false,
25991 * childForms - used for multi-tab forms
25994 childForms : false,
25997 * allItems - full list of fields.
26003 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
26004 * element by passing it or its id or mask the form itself by passing in true.
26007 waitMsgTarget : undefined,
26010 initEl : function(el){
26011 this.el = Roo.get(el);
26012 this.id = this.el.id || Roo.id();
26013 this.el.on('submit', this.onSubmit, this);
26014 this.el.addClass('x-form');
26018 onSubmit : function(e){
26023 * Returns true if client-side validation on the form is successful.
26026 isValid : function(){
26028 this.items.each(function(f){
26037 * Returns true if any fields in this form have changed since their original load.
26040 isDirty : function(){
26042 this.items.each(function(f){
26052 * Performs a predefined action (submit or load) or custom actions you define on this form.
26053 * @param {String} actionName The name of the action type
26054 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
26055 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
26056 * accept other config options):
26058 Property Type Description
26059 ---------------- --------------- ----------------------------------------------------------------------------------
26060 url String The url for the action (defaults to the form's url)
26061 method String The form method to use (defaults to the form's method, or POST if not defined)
26062 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
26063 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
26064 validate the form on the client (defaults to false)
26066 * @return {BasicForm} this
26068 doAction : function(action, options){
26069 if(typeof action == 'string'){
26070 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
26072 if(this.fireEvent('beforeaction', this, action) !== false){
26073 this.beforeAction(action);
26074 action.run.defer(100, action);
26080 * Shortcut to do a submit action.
26081 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26082 * @return {BasicForm} this
26084 submit : function(options){
26085 this.doAction('submit', options);
26090 * Shortcut to do a load action.
26091 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
26092 * @return {BasicForm} this
26094 load : function(options){
26095 this.doAction('load', options);
26100 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
26101 * @param {Record} record The record to edit
26102 * @return {BasicForm} this
26104 updateRecord : function(record){
26105 record.beginEdit();
26106 var fs = record.fields;
26107 fs.each(function(f){
26108 var field = this.findField(f.name);
26110 record.set(f.name, field.getValue());
26118 * Loads an Roo.data.Record into this form.
26119 * @param {Record} record The record to load
26120 * @return {BasicForm} this
26122 loadRecord : function(record){
26123 this.setValues(record.data);
26128 beforeAction : function(action){
26129 var o = action.options;
26131 if(this.waitMsgTarget === true){
26132 this.el.mask(o.waitMsg, 'x-mask-loading');
26133 }else if(this.waitMsgTarget){
26134 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
26135 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
26137 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
26143 afterAction : function(action, success){
26144 this.activeAction = null;
26145 var o = action.options;
26147 if(this.waitMsgTarget === true){
26149 }else if(this.waitMsgTarget){
26150 this.waitMsgTarget.unmask();
26152 Roo.MessageBox.updateProgress(1);
26153 Roo.MessageBox.hide();
26160 Roo.callback(o.success, o.scope, [this, action]);
26161 this.fireEvent('actioncomplete', this, action);
26163 Roo.callback(o.failure, o.scope, [this, action]);
26164 this.fireEvent('actionfailed', this, action);
26169 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
26170 * @param {String} id The value to search for
26173 findField : function(id){
26174 var field = this.items.get(id);
26176 this.items.each(function(f){
26177 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
26183 return field || null;
26187 * Add a secondary form to this one,
26188 * Used to provide tabbed forms. One form is primary, with hidden values
26189 * which mirror the elements from the other forms.
26191 * @param {Roo.form.Form} form to add.
26194 addForm : function(form)
26197 if (this.childForms.indexOf(form) > -1) {
26201 this.childForms.push(form);
26203 Roo.each(form.allItems, function (fe) {
26205 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
26206 if (this.findField(n)) { // already added..
26209 var add = new Roo.form.Hidden({
26212 add.render(this.el);
26219 * Mark fields in this form invalid in bulk.
26220 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
26221 * @return {BasicForm} this
26223 markInvalid : function(errors){
26224 if(errors instanceof Array){
26225 for(var i = 0, len = errors.length; i < len; i++){
26226 var fieldError = errors[i];
26227 var f = this.findField(fieldError.id);
26229 f.markInvalid(fieldError.msg);
26235 if(typeof errors[id] != 'function' && (field = this.findField(id))){
26236 field.markInvalid(errors[id]);
26240 Roo.each(this.childForms || [], function (f) {
26241 f.markInvalid(errors);
26248 * Set values for fields in this form in bulk.
26249 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
26250 * @return {BasicForm} this
26252 setValues : function(values){
26253 if(values instanceof Array){ // array of objects
26254 for(var i = 0, len = values.length; i < len; i++){
26256 var f = this.findField(v.id);
26258 f.setValue(v.value);
26259 if(this.trackResetOnLoad){
26260 f.originalValue = f.getValue();
26264 }else{ // object hash
26267 if(typeof values[id] != 'function' && (field = this.findField(id))){
26269 if (field.setFromData &&
26270 field.valueField &&
26271 field.displayField &&
26272 // combos' with local stores can
26273 // be queried via setValue()
26274 // to set their value..
26275 (field.store && !field.store.isLocal)
26279 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
26280 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
26281 field.setFromData(sd);
26284 field.setValue(values[id]);
26288 if(this.trackResetOnLoad){
26289 field.originalValue = field.getValue();
26295 Roo.each(this.childForms || [], function (f) {
26296 f.setValues(values);
26303 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
26304 * they are returned as an array.
26305 * @param {Boolean} asString
26308 getValues : function(asString){
26309 if (this.childForms) {
26310 // copy values from the child forms
26311 Roo.each(this.childForms, function (f) {
26312 this.setValues(f.getValues());
26318 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
26319 if(asString === true){
26322 return Roo.urlDecode(fs);
26326 * Returns the fields in this form as an object with key/value pairs.
26327 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
26330 getFieldValues : function()
26332 if (this.childForms) {
26333 // copy values from the child forms
26334 Roo.each(this.childForms, function (f) {
26335 this.setValues(f.getValues());
26340 this.items.each(function(f){
26341 if (!f.getName()) {
26344 var v = f.getValue();
26345 if ((typeof(v) == 'object') && f.getRawValue) {
26346 v = f.getRawValue() ; // dates..
26348 ret[f.getName()] = v;
26355 * Clears all invalid messages in this form.
26356 * @return {BasicForm} this
26358 clearInvalid : function(){
26359 this.items.each(function(f){
26363 Roo.each(this.childForms || [], function (f) {
26372 * Resets this form.
26373 * @return {BasicForm} this
26375 reset : function(){
26376 this.items.each(function(f){
26380 Roo.each(this.childForms || [], function (f) {
26389 * Add Roo.form components to this form.
26390 * @param {Field} field1
26391 * @param {Field} field2 (optional)
26392 * @param {Field} etc (optional)
26393 * @return {BasicForm} this
26396 this.items.addAll(Array.prototype.slice.call(arguments, 0));
26402 * Removes a field from the items collection (does NOT remove its markup).
26403 * @param {Field} field
26404 * @return {BasicForm} this
26406 remove : function(field){
26407 this.items.remove(field);
26412 * Looks at the fields in this form, checks them for an id attribute,
26413 * and calls applyTo on the existing dom element with that id.
26414 * @return {BasicForm} this
26416 render : function(){
26417 this.items.each(function(f){
26418 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
26426 * Calls {@link Ext#apply} for all fields in this form with the passed object.
26427 * @param {Object} values
26428 * @return {BasicForm} this
26430 applyToFields : function(o){
26431 this.items.each(function(f){
26438 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
26439 * @param {Object} values
26440 * @return {BasicForm} this
26442 applyIfToFields : function(o){
26443 this.items.each(function(f){
26451 Roo.BasicForm = Roo.form.BasicForm;/*
26453 * Ext JS Library 1.1.1
26454 * Copyright(c) 2006-2007, Ext JS, LLC.
26456 * Originally Released Under LGPL - original licence link has changed is not relivant.
26459 * <script type="text/javascript">
26463 * @class Roo.form.Form
26464 * @extends Roo.form.BasicForm
26465 * Adds the ability to dynamically render forms with JavaScript to {@link Roo.form.BasicForm}.
26467 * @param {Object} config Configuration options
26469 Roo.form.Form = function(config){
26471 if (config.items) {
26472 xitems = config.items;
26473 delete config.items;
26477 Roo.form.Form.superclass.constructor.call(this, null, config);
26478 this.url = this.url || this.action;
26480 this.root = new Roo.form.Layout(Roo.applyIf({
26484 this.active = this.root;
26486 * Array of all the buttons that have been added to this form via {@link addButton}
26490 this.allItems = [];
26493 * @event clientvalidation
26494 * If the monitorValid config option is true, this event fires repetitively to notify of valid state
26495 * @param {Form} this
26496 * @param {Boolean} valid true if the form has passed client-side validation
26498 clientvalidation: true,
26501 * Fires when the form is rendered
26502 * @param {Roo.form.Form} form
26507 if (this.progressUrl) {
26508 // push a hidden field onto the list of fields..
26512 name : 'UPLOAD_IDENTIFIER'
26517 Roo.each(xitems, this.addxtype, this);
26523 Roo.extend(Roo.form.Form, Roo.form.BasicForm, {
26525 * @cfg {Number} labelWidth The width of labels. This property cascades to child containers.
26528 * @cfg {String} itemCls A css class to apply to the x-form-item of fields. This property cascades to child containers.
26531 * @cfg {String} buttonAlign Valid values are "left," "center" and "right" (defaults to "center")
26533 buttonAlign:'center',
26536 * @cfg {Number} minButtonWidth Minimum width of all buttons in pixels (defaults to 75)
26541 * @cfg {String} labelAlign Valid values are "left," "top" and "right" (defaults to "left").
26542 * This property cascades to child containers if not set.
26547 * @cfg {Boolean} monitorValid If true the form monitors its valid state <b>client-side</b> and
26548 * fires a looping event with that state. This is required to bind buttons to the valid
26549 * state using the config value formBind:true on the button.
26551 monitorValid : false,
26554 * @cfg {Number} monitorPoll The milliseconds to poll valid state, ignored if monitorValid is not true (defaults to 200)
26559 * @cfg {String} progressUrl - Url to return progress data
26562 progressUrl : false,
26565 * Opens a new {@link Roo.form.Column} container in the layout stack. If fields are passed after the config, the
26566 * fields are added and the column is closed. If no fields are passed the column remains open
26567 * until end() is called.
26568 * @param {Object} config The config to pass to the column
26569 * @param {Field} field1 (optional)
26570 * @param {Field} field2 (optional)
26571 * @param {Field} etc (optional)
26572 * @return Column The column container object
26574 column : function(c){
26575 var col = new Roo.form.Column(c);
26577 if(arguments.length > 1){ // duplicate code required because of Opera
26578 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26585 * Opens a new {@link Roo.form.FieldSet} container in the layout stack. If fields are passed after the config, the
26586 * fields are added and the fieldset is closed. If no fields are passed the fieldset remains open
26587 * until end() is called.
26588 * @param {Object} config The config to pass to the fieldset
26589 * @param {Field} field1 (optional)
26590 * @param {Field} field2 (optional)
26591 * @param {Field} etc (optional)
26592 * @return FieldSet The fieldset container object
26594 fieldset : function(c){
26595 var fs = new Roo.form.FieldSet(c);
26597 if(arguments.length > 1){ // duplicate code required because of Opera
26598 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26605 * Opens a new {@link Roo.form.Layout} container in the layout stack. If fields are passed after the config, the
26606 * fields are added and the container is closed. If no fields are passed the container remains open
26607 * until end() is called.
26608 * @param {Object} config The config to pass to the Layout
26609 * @param {Field} field1 (optional)
26610 * @param {Field} field2 (optional)
26611 * @param {Field} etc (optional)
26612 * @return Layout The container object
26614 container : function(c){
26615 var l = new Roo.form.Layout(c);
26617 if(arguments.length > 1){ // duplicate code required because of Opera
26618 this.add.apply(this, Array.prototype.slice.call(arguments, 1));
26625 * Opens the passed container in the layout stack. The container can be any {@link Roo.form.Layout} or subclass.
26626 * @param {Object} container A Roo.form.Layout or subclass of Layout
26627 * @return {Form} this
26629 start : function(c){
26630 // cascade label info
26631 Roo.applyIf(c, {'labelAlign': this.active.labelAlign, 'labelWidth': this.active.labelWidth, 'itemCls': this.active.itemCls});
26632 this.active.stack.push(c);
26633 c.ownerCt = this.active;
26639 * Closes the current open container
26640 * @return {Form} this
26643 if(this.active == this.root){
26646 this.active = this.active.ownerCt;
26651 * Add Roo.form components to the current open container (e.g. column, fieldset, etc.). Fields added via this method
26652 * can also be passed with an additional property of fieldLabel, which if supplied, will provide the text to display
26653 * as the label of the field.
26654 * @param {Field} field1
26655 * @param {Field} field2 (optional)
26656 * @param {Field} etc. (optional)
26657 * @return {Form} this
26660 this.active.stack.push.apply(this.active.stack, arguments);
26661 this.allItems.push.apply(this.allItems,arguments);
26663 for(var i = 0, a = arguments, len = a.length; i < len; i++) {
26664 if(a[i].isFormField){
26669 Roo.form.Form.superclass.add.apply(this, r);
26679 * Find any element that has been added to a form, using it's ID or name
26680 * This can include framesets, columns etc. along with regular fields..
26681 * @param {String} id - id or name to find.
26683 * @return {Element} e - or false if nothing found.
26685 findbyId : function(id)
26691 Ext.each(this.allItems, function(f){
26692 if (f.id == id || f.name == id ){
26703 * Render this form into the passed container. This should only be called once!
26704 * @param {String/HTMLElement/Element} container The element this component should be rendered into
26705 * @return {Form} this
26707 render : function(ct)
26713 var o = this.autoCreate || {
26715 method : this.method || 'POST',
26716 id : this.id || Roo.id()
26718 this.initEl(ct.createChild(o));
26720 this.root.render(this.el);
26724 this.items.each(function(f){
26725 f.render('x-form-el-'+f.id);
26728 if(this.buttons.length > 0){
26729 // tables are required to maintain order and for correct IE layout
26730 var tb = this.el.createChild({cls:'x-form-btns-ct', cn: {
26731 cls:"x-form-btns x-form-btns-"+this.buttonAlign,
26732 html:'<table cellspacing="0"><tbody><tr></tr></tbody></table><div class="x-clear"></div>'
26734 var tr = tb.getElementsByTagName('tr')[0];
26735 for(var i = 0, len = this.buttons.length; i < len; i++) {
26736 var b = this.buttons[i];
26737 var td = document.createElement('td');
26738 td.className = 'x-form-btn-td';
26739 b.render(tr.appendChild(td));
26742 if(this.monitorValid){ // initialize after render
26743 this.startMonitoring();
26745 this.fireEvent('rendered', this);
26750 * Adds a button to the footer of the form - this <b>must</b> be called before the form is rendered.
26751 * @param {String/Object} config A string becomes the button text, an object can either be a Button config
26752 * object or a valid Roo.DomHelper element config
26753 * @param {Function} handler The function called when the button is clicked
26754 * @param {Object} scope (optional) The scope of the handler function
26755 * @return {Roo.Button}
26757 addButton : function(config, handler, scope){
26761 minWidth: this.minButtonWidth,
26764 if(typeof config == "string"){
26767 Roo.apply(bc, config);
26769 var btn = new Roo.Button(null, bc);
26770 this.buttons.push(btn);
26775 * Adds a series of form elements (using the xtype property as the factory method.
26776 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column, (and 'end' to close a block)
26777 * @param {Object} config
26780 addxtype : function()
26782 var ar = Array.prototype.slice.call(arguments, 0);
26784 for(var i = 0; i < ar.length; i++) {
26786 continue; // skip -- if this happends something invalid got sent, we
26787 // should ignore it, as basically that interface element will not show up
26788 // and that should be pretty obvious!!
26791 if (Roo.form[ar[i].xtype]) {
26793 var fe = Roo.factory(ar[i], Roo.form);
26799 fe.store.form = this;
26804 this.allItems.push(fe);
26805 if (fe.items && fe.addxtype) {
26806 fe.addxtype.apply(fe, fe.items);
26816 // console.log('adding ' + ar[i].xtype);
26818 if (ar[i].xtype == 'Button') {
26819 //console.log('adding button');
26820 //console.log(ar[i]);
26821 this.addButton(ar[i]);
26822 this.allItems.push(fe);
26826 if (ar[i].xtype == 'end') { // so we can add fieldsets... / layout etc.
26827 alert('end is not supported on xtype any more, use items');
26829 // //console.log('adding end');
26837 * Starts monitoring of the valid state of this form. Usually this is done by passing the config
26838 * option "monitorValid"
26840 startMonitoring : function(){
26843 Roo.TaskMgr.start({
26844 run : this.bindHandler,
26845 interval : this.monitorPoll || 200,
26852 * Stops monitoring of the valid state of this form
26854 stopMonitoring : function(){
26855 this.bound = false;
26859 bindHandler : function(){
26861 return false; // stops binding
26864 this.items.each(function(f){
26865 if(!f.isValid(true)){
26870 for(var i = 0, len = this.buttons.length; i < len; i++){
26871 var btn = this.buttons[i];
26872 if(btn.formBind === true && btn.disabled === valid){
26873 btn.setDisabled(!valid);
26876 this.fireEvent('clientvalidation', this, valid);
26890 Roo.Form = Roo.form.Form;
26893 * Ext JS Library 1.1.1
26894 * Copyright(c) 2006-2007, Ext JS, LLC.
26896 * Originally Released Under LGPL - original licence link has changed is not relivant.
26899 * <script type="text/javascript">
26903 * @class Roo.form.Action
26904 * Internal Class used to handle form actions
26906 * @param {Roo.form.BasicForm} el The form element or its id
26907 * @param {Object} config Configuration options
26911 // define the action interface
26912 Roo.form.Action = function(form, options){
26914 this.options = options || {};
26917 * Client Validation Failed
26920 Roo.form.Action.CLIENT_INVALID = 'client';
26922 * Server Validation Failed
26925 Roo.form.Action.SERVER_INVALID = 'server';
26927 * Connect to Server Failed
26930 Roo.form.Action.CONNECT_FAILURE = 'connect';
26932 * Reading Data from Server Failed
26935 Roo.form.Action.LOAD_FAILURE = 'load';
26937 Roo.form.Action.prototype = {
26939 failureType : undefined,
26940 response : undefined,
26941 result : undefined,
26943 // interface method
26944 run : function(options){
26948 // interface method
26949 success : function(response){
26953 // interface method
26954 handleResponse : function(response){
26958 // default connection failure
26959 failure : function(response){
26960 this.response = response;
26961 this.failureType = Roo.form.Action.CONNECT_FAILURE;
26962 this.form.afterAction(this, false);
26965 processResponse : function(response){
26966 this.response = response;
26967 if(!response.responseText){
26970 this.result = this.handleResponse(response);
26971 return this.result;
26974 // utility functions used internally
26975 getUrl : function(appendParams){
26976 var url = this.options.url || this.form.url || this.form.el.dom.action;
26978 var p = this.getParams();
26980 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
26986 getMethod : function(){
26987 return (this.options.method || this.form.method || this.form.el.dom.method || 'POST').toUpperCase();
26990 getParams : function(){
26991 var bp = this.form.baseParams;
26992 var p = this.options.params;
26994 if(typeof p == "object"){
26995 p = Roo.urlEncode(Roo.applyIf(p, bp));
26996 }else if(typeof p == 'string' && bp){
26997 p += '&' + Roo.urlEncode(bp);
27000 p = Roo.urlEncode(bp);
27005 createCallback : function(){
27007 success: this.success,
27008 failure: this.failure,
27010 timeout: (this.form.timeout*1000),
27011 upload: this.form.fileUpload ? this.success : undefined
27016 Roo.form.Action.Submit = function(form, options){
27017 Roo.form.Action.Submit.superclass.constructor.call(this, form, options);
27020 Roo.extend(Roo.form.Action.Submit, Roo.form.Action, {
27023 haveProgress : false,
27024 uploadComplete : false,
27026 // uploadProgress indicator.
27027 uploadProgress : function()
27029 if (!this.form.progressUrl) {
27033 if (!this.haveProgress) {
27034 Roo.MessageBox.progress("Uploading", "Uploading");
27036 if (this.uploadComplete) {
27037 Roo.MessageBox.hide();
27041 this.haveProgress = true;
27043 var uid = this.form.findField('UPLOAD_IDENTIFIER').getValue();
27045 var c = new Roo.data.Connection();
27047 url : this.form.progressUrl,
27052 success : function(req){
27053 //console.log(data);
27057 rdata = Roo.decode(req.responseText)
27059 Roo.log("Invalid data from server..");
27063 if (!rdata || !rdata.success) {
27067 var data = rdata.data;
27069 if (this.uploadComplete) {
27070 Roo.MessageBox.hide();
27075 Roo.MessageBox.updateProgress(data.bytes_uploaded/data.bytes_total,
27076 Math.floor((data.bytes_total - data.bytes_uploaded)/1000) + 'k remaining'
27079 this.uploadProgress.defer(2000,this);
27082 failure: function(data) {
27083 Roo.log('progress url failed ');
27094 // run get Values on the form, so it syncs any secondary forms.
27095 this.form.getValues();
27097 var o = this.options;
27098 var method = this.getMethod();
27099 var isPost = method == 'POST';
27100 if(o.clientValidation === false || this.form.isValid()){
27102 if (this.form.progressUrl) {
27103 this.form.findField('UPLOAD_IDENTIFIER').setValue(
27104 (new Date() * 1) + '' + Math.random());
27108 Roo.Ajax.request(Roo.apply(this.createCallback(), {
27109 form:this.form.el.dom,
27110 url:this.getUrl(!isPost),
27112 params:isPost ? this.getParams() : null,
27113 isUpload: this.form.fileUpload
27116 this.uploadProgress();
27118 }else if (o.clientValidation !== false){ // client validation failed
27119 this.failureType = Roo.form.Action.CLIENT_INVALID;
27120 this.form.afterAction(this, false);
27124 success : function(response)
27126 this.uploadComplete= true;
27127 if (this.haveProgress) {
27128 Roo.MessageBox.hide();
27131 var result = this.processResponse(response);
27132 if(result === true || result.success){
27133 this.form.afterAction(this, true);
27137 this.form.markInvalid(result.errors);
27138 this.failureType = Roo.form.Action.SERVER_INVALID;
27140 this.form.afterAction(this, false);
27142 failure : function(response)
27144 this.uploadComplete= true;
27145 if (this.haveProgress) {
27146 Roo.MessageBox.hide();
27149 this.response = response;
27150 this.failureType = Roo.form.Action.CONNECT_FAILURE;
27151 this.form.afterAction(this, false);
27154 handleResponse : function(response){
27155 if(this.form.errorReader){
27156 var rs = this.form.errorReader.read(response);
27159 for(var i = 0, len = rs.records.length; i < len; i++) {
27160 var r = rs.records[i];
27161 errors[i] = r.data;
27164 if(errors.length < 1){
27168 success : rs.success,
27174 ret = Roo.decode(response.responseText);
27178 errorMsg: "Failed to read server message: " + (response ? response.responseText : ' - no message'),
27188 Roo.form.Action.Load = function(form, options){
27189 Roo.form.Action.Load.superclass.constructor.call(this, form, options);
27190 this.reader = this.form.reader;
27193 Roo.extend(Roo.form.Action.Load, Roo.form.Action, {
27197 Roo.Ajax.request(Roo.apply(
27198 this.createCallback(), {
27199 method:this.getMethod(),
27200 url:this.getUrl(false),
27201 params:this.getParams()
27205 success : function(response){
27206 var result = this.processResponse(response);
27207 if(result === true || !result.success || !result.data){
27208 this.failureType = Roo.form.Action.LOAD_FAILURE;
27209 this.form.afterAction(this, false);
27212 this.form.clearInvalid();
27213 this.form.setValues(result.data);
27214 this.form.afterAction(this, true);
27217 handleResponse : function(response){
27218 if(this.form.reader){
27219 var rs = this.form.reader.read(response);
27220 var data = rs.records && rs.records[0] ? rs.records[0].data : null;
27222 success : rs.success,
27226 return Roo.decode(response.responseText);
27230 Roo.form.Action.ACTION_TYPES = {
27231 'load' : Roo.form.Action.Load,
27232 'submit' : Roo.form.Action.Submit
27235 * Ext JS Library 1.1.1
27236 * Copyright(c) 2006-2007, Ext JS, LLC.
27238 * Originally Released Under LGPL - original licence link has changed is not relivant.
27241 * <script type="text/javascript">
27245 * @class Roo.form.Layout
27246 * @extends Roo.Component
27247 * Creates a container for layout and rendering of fields in an {@link Roo.form.Form}.
27249 * @param {Object} config Configuration options
27251 Roo.form.Layout = function(config){
27253 if (config.items) {
27254 xitems = config.items;
27255 delete config.items;
27257 Roo.form.Layout.superclass.constructor.call(this, config);
27259 Roo.each(xitems, this.addxtype, this);
27263 Roo.extend(Roo.form.Layout, Roo.Component, {
27265 * @cfg {String/Object} autoCreate
27266 * A DomHelper element spec used to autocreate the layout (defaults to {tag: 'div', cls: 'x-form-ct'})
27269 * @cfg {String/Object/Function} style
27270 * A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
27271 * a function which returns such a specification.
27274 * @cfg {String} labelAlign
27275 * Valid values are "left," "top" and "right" (defaults to "left")
27278 * @cfg {Number} labelWidth
27279 * Fixed width in pixels of all field labels (defaults to undefined)
27282 * @cfg {Boolean} clear
27283 * True to add a clearing element at the end of this layout, equivalent to CSS clear: both (defaults to true)
27287 * @cfg {String} labelSeparator
27288 * The separator to use after field labels (defaults to ':')
27290 labelSeparator : ':',
27292 * @cfg {Boolean} hideLabels
27293 * True to suppress the display of field labels in this layout (defaults to false)
27295 hideLabels : false,
27298 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct'},
27303 onRender : function(ct, position){
27304 if(this.el){ // from markup
27305 this.el = Roo.get(this.el);
27306 }else { // generate
27307 var cfg = this.getAutoCreate();
27308 this.el = ct.createChild(cfg, position);
27311 this.el.applyStyles(this.style);
27313 if(this.labelAlign){
27314 this.el.addClass('x-form-label-'+this.labelAlign);
27316 if(this.hideLabels){
27317 this.labelStyle = "display:none";
27318 this.elementStyle = "padding-left:0;";
27320 if(typeof this.labelWidth == 'number'){
27321 this.labelStyle = "width:"+this.labelWidth+"px;";
27322 this.elementStyle = "padding-left:"+((this.labelWidth+(typeof this.labelPad == 'number' ? this.labelPad : 5))+'px')+";";
27324 if(this.labelAlign == 'top'){
27325 this.labelStyle = "width:auto;";
27326 this.elementStyle = "padding-left:0;";
27329 var stack = this.stack;
27330 var slen = stack.length;
27332 if(!this.fieldTpl){
27333 var t = new Roo.Template(
27334 '<div class="x-form-item {5}">',
27335 '<label for="{0}" style="{2}">{1}{4}</label>',
27336 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27338 '</div><div class="x-form-clear-left"></div>'
27340 t.disableFormats = true;
27342 Roo.form.Layout.prototype.fieldTpl = t;
27344 for(var i = 0; i < slen; i++) {
27345 if(stack[i].isFormField){
27346 this.renderField(stack[i]);
27348 this.renderComponent(stack[i]);
27353 this.el.createChild({cls:'x-form-clear'});
27358 renderField : function(f){
27359 f.fieldEl = Roo.get(this.fieldTpl.append(this.el, [
27362 f.labelStyle||this.labelStyle||'', //2
27363 this.elementStyle||'', //3
27364 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator, //4
27365 f.itemCls||this.itemCls||'' //5
27366 ], true).getPrevSibling());
27370 renderComponent : function(c){
27371 c.render(c.isLayout ? this.el : this.el.createChild());
27374 * Adds a object form elements (using the xtype property as the factory method.)
27375 * Valid xtypes are: TextField, TextArea .... Button, Layout, FieldSet, Column
27376 * @param {Object} config
27378 addxtype : function(o)
27380 // create the lement.
27381 o.form = this.form;
27382 var fe = Roo.factory(o, Roo.form);
27383 this.form.allItems.push(fe);
27384 this.stack.push(fe);
27386 if (fe.isFormField) {
27387 this.form.items.add(fe);
27395 * @class Roo.form.Column
27396 * @extends Roo.form.Layout
27397 * Creates a column container for layout and rendering of fields in an {@link Roo.form.Form}.
27399 * @param {Object} config Configuration options
27401 Roo.form.Column = function(config){
27402 Roo.form.Column.superclass.constructor.call(this, config);
27405 Roo.extend(Roo.form.Column, Roo.form.Layout, {
27407 * @cfg {Number/String} width
27408 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27411 * @cfg {String/Object} autoCreate
27412 * A DomHelper element spec used to autocreate the column (defaults to {tag: 'div', cls: 'x-form-ct x-form-column'})
27416 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-column'},
27419 onRender : function(ct, position){
27420 Roo.form.Column.superclass.onRender.call(this, ct, position);
27422 this.el.setWidth(this.width);
27429 * @class Roo.form.Row
27430 * @extends Roo.form.Layout
27431 * Creates a row container for layout and rendering of fields in an {@link Roo.form.Form}.
27433 * @param {Object} config Configuration options
27437 Roo.form.Row = function(config){
27438 Roo.form.Row.superclass.constructor.call(this, config);
27441 Roo.extend(Roo.form.Row, Roo.form.Layout, {
27443 * @cfg {Number/String} width
27444 * The fixed width of the column in pixels or CSS value (defaults to "auto")
27447 * @cfg {Number/String} height
27448 * The fixed height of the column in pixels or CSS value (defaults to "auto")
27450 defaultAutoCreate : {tag: 'div', cls: 'x-form-ct x-form-row'},
27454 onRender : function(ct, position){
27455 //console.log('row render');
27457 var t = new Roo.Template(
27458 '<div class="x-form-item {5}" style="float:left;width:{6}px">',
27459 '<label for="{0}" style="{2}">{1}{4}</label>',
27460 '<div class="x-form-element" id="x-form-el-{0}" style="{3}">',
27464 t.disableFormats = true;
27466 Roo.form.Layout.prototype.rowTpl = t;
27468 this.fieldTpl = this.rowTpl;
27470 //console.log('lw' + this.labelWidth +', la:' + this.labelAlign);
27471 var labelWidth = 100;
27473 if ((this.labelAlign != 'top')) {
27474 if (typeof this.labelWidth == 'number') {
27475 labelWidth = this.labelWidth
27477 this.padWidth = 20 + labelWidth;
27481 Roo.form.Column.superclass.onRender.call(this, ct, position);
27483 this.el.setWidth(this.width);
27486 this.el.setHeight(this.height);
27491 renderField : function(f){
27492 f.fieldEl = this.fieldTpl.append(this.el, [
27493 f.id, f.fieldLabel,
27494 f.labelStyle||this.labelStyle||'',
27495 this.elementStyle||'',
27496 typeof f.labelSeparator == 'undefined' ? this.labelSeparator : f.labelSeparator,
27497 f.itemCls||this.itemCls||'',
27498 f.width ? f.width + this.padWidth : 160 + this.padWidth
27505 * @class Roo.form.FieldSet
27506 * @extends Roo.form.Layout
27507 * Creates a fieldset container for layout and rendering of fields in an {@link Roo.form.Form}.
27509 * @param {Object} config Configuration options
27511 Roo.form.FieldSet = function(config){
27512 Roo.form.FieldSet.superclass.constructor.call(this, config);
27515 Roo.extend(Roo.form.FieldSet, Roo.form.Layout, {
27517 * @cfg {String} legend
27518 * The text to display as the legend for the FieldSet (defaults to '')
27521 * @cfg {String/Object} autoCreate
27522 * A DomHelper element spec used to autocreate the fieldset (defaults to {tag: 'fieldset', cn: {tag:'legend'}})
27526 defaultAutoCreate : {tag: 'fieldset', cn: {tag:'legend'}},
27529 onRender : function(ct, position){
27530 Roo.form.FieldSet.superclass.onRender.call(this, ct, position);
27532 this.setLegend(this.legend);
27537 setLegend : function(text){
27539 this.el.child('legend').update(text);
27544 * Ext JS Library 1.1.1
27545 * Copyright(c) 2006-2007, Ext JS, LLC.
27547 * Originally Released Under LGPL - original licence link has changed is not relivant.
27550 * <script type="text/javascript">
27553 * @class Roo.form.VTypes
27554 * Overridable validation definitions. The validations provided are basic and intended to be easily customizable and extended.
27557 Roo.form.VTypes = function(){
27558 // closure these in so they are only created once.
27559 var alpha = /^[a-zA-Z_]+$/;
27560 var alphanum = /^[a-zA-Z0-9_]+$/;
27561 var email = /^([\w]+)(.[\w]+)*@([\w-]+\.){1,5}([A-Za-z]){2,4}$/;
27562 var url = /(((https?)|(ftp)):\/\/([\-\w]+\.)+\w{2,3}(\/[%\-\w]+(\.\w{2,})?)*(([\w\-\.\?\\\/+@&#;`~=%!]*)(\.\w{2,})?)*\/?)/i;
27564 // All these messages and functions are configurable
27567 * The function used to validate email addresses
27568 * @param {String} value The email address
27570 'email' : function(v){
27571 return email.test(v);
27574 * The error text to display when the email validation function returns false
27577 'emailText' : 'This field should be an e-mail address in the format "user@domain.com"',
27579 * The keystroke filter mask to be applied on email input
27582 'emailMask' : /[a-z0-9_\.\-@]/i,
27585 * The function used to validate URLs
27586 * @param {String} value The URL
27588 'url' : function(v){
27589 return url.test(v);
27592 * The error text to display when the url validation function returns false
27595 'urlText' : 'This field should be a URL in the format "http:/'+'/www.domain.com"',
27598 * The function used to validate alpha values
27599 * @param {String} value The value
27601 'alpha' : function(v){
27602 return alpha.test(v);
27605 * The error text to display when the alpha validation function returns false
27608 'alphaText' : 'This field should only contain letters and _',
27610 * The keystroke filter mask to be applied on alpha input
27613 'alphaMask' : /[a-z_]/i,
27616 * The function used to validate alphanumeric values
27617 * @param {String} value The value
27619 'alphanum' : function(v){
27620 return alphanum.test(v);
27623 * The error text to display when the alphanumeric validation function returns false
27626 'alphanumText' : 'This field should only contain letters, numbers and _',
27628 * The keystroke filter mask to be applied on alphanumeric input
27631 'alphanumMask' : /[a-z0-9_]/i
27633 }();//<script type="text/javascript">
27636 * @class Roo.form.FCKeditor
27637 * @extends Roo.form.TextArea
27638 * Wrapper around the FCKEditor http://www.fckeditor.net
27640 * Creates a new FCKeditor
27641 * @param {Object} config Configuration options
27643 Roo.form.FCKeditor = function(config){
27644 Roo.form.FCKeditor.superclass.constructor.call(this, config);
27647 * @event editorinit
27648 * Fired when the editor is initialized - you can add extra handlers here..
27649 * @param {FCKeditor} this
27650 * @param {Object} the FCK object.
27657 Roo.form.FCKeditor.editors = { };
27658 Roo.extend(Roo.form.FCKeditor, Roo.form.TextArea,
27660 //defaultAutoCreate : {
27661 // tag : "textarea",style : "width:100px;height:60px;" ,autocomplete : "off"
27665 * @cfg {Object} fck options - see fck manual for details.
27670 * @cfg {Object} fck toolbar set (Basic or Default)
27672 toolbarSet : 'Basic',
27674 * @cfg {Object} fck BasePath
27676 basePath : '/fckeditor/',
27684 onRender : function(ct, position)
27687 this.defaultAutoCreate = {
27689 style:"width:300px;height:60px;",
27690 autocomplete: "off"
27693 Roo.form.FCKeditor.superclass.onRender.call(this, ct, position);
27696 this.textSizeEl = Roo.DomHelper.append(document.body, {tag: "pre", cls: "x-form-grow-sizer"});
27697 if(this.preventScrollbars){
27698 this.el.setStyle("overflow", "hidden");
27700 this.el.setHeight(this.growMin);
27703 //console.log('onrender' + this.getId() );
27704 Roo.form.FCKeditor.editors[this.getId()] = this;
27707 this.replaceTextarea() ;
27711 getEditor : function() {
27712 return this.fckEditor;
27715 * Sets a data value into the field and validates it. To set the value directly without validation see {@link #setRawValue}.
27716 * @param {Mixed} value The value to set
27720 setValue : function(value)
27722 //console.log('setValue: ' + value);
27724 if(typeof(value) == 'undefined') { // not sure why this is happending...
27727 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27729 //if(!this.el || !this.getEditor()) {
27730 // this.value = value;
27731 //this.setValue.defer(100,this,[value]);
27735 if(!this.getEditor()) {
27739 this.getEditor().SetData(value);
27746 * Returns the normalized data value (undefined or emptyText will be returned as ''). To return the raw value see {@link #getRawValue}.
27747 * @return {Mixed} value The field value
27749 getValue : function()
27752 if (this.frame && this.frame.dom.style.display == 'none') {
27753 return Roo.form.FCKeditor.superclass.getValue.call(this);
27756 if(!this.el || !this.getEditor()) {
27758 // this.getValue.defer(100,this);
27763 var value=this.getEditor().GetData();
27764 Roo.form.FCKeditor.superclass.setValue.apply(this,[value]);
27765 return Roo.form.FCKeditor.superclass.getValue.call(this);
27771 * Returns the raw data value which may or may not be a valid, defined value. To return a normalized value see {@link #getValue}.
27772 * @return {Mixed} value The field value
27774 getRawValue : function()
27776 if (this.frame && this.frame.dom.style.display == 'none') {
27777 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27780 if(!this.el || !this.getEditor()) {
27781 //this.getRawValue.defer(100,this);
27788 var value=this.getEditor().GetData();
27789 Roo.form.FCKeditor.superclass.setRawValue.apply(this,[value]);
27790 return Roo.form.FCKeditor.superclass.getRawValue.call(this);
27794 setSize : function(w,h) {
27798 //if (this.frame && this.frame.dom.style.display == 'none') {
27799 // Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27802 //if(!this.el || !this.getEditor()) {
27803 // this.setSize.defer(100,this, [w,h]);
27809 Roo.form.FCKeditor.superclass.setSize.apply(this, [w, h]);
27811 this.frame.dom.setAttribute('width', w);
27812 this.frame.dom.setAttribute('height', h);
27813 this.frame.setSize(w,h);
27817 toggleSourceEdit : function(value) {
27821 this.el.dom.style.display = value ? '' : 'none';
27822 this.frame.dom.style.display = value ? 'none' : '';
27827 focus: function(tag)
27829 if (this.frame.dom.style.display == 'none') {
27830 return Roo.form.FCKeditor.superclass.focus.call(this);
27832 if(!this.el || !this.getEditor()) {
27833 this.focus.defer(100,this, [tag]);
27840 var tgs = this.getEditor().EditorDocument.getElementsByTagName(tag);
27841 this.getEditor().Focus();
27843 if (!this.getEditor().Selection.GetSelection()) {
27844 this.focus.defer(100,this, [tag]);
27849 var r = this.getEditor().EditorDocument.createRange();
27850 r.setStart(tgs[0],0);
27851 r.setEnd(tgs[0],0);
27852 this.getEditor().Selection.GetSelection().removeAllRanges();
27853 this.getEditor().Selection.GetSelection().addRange(r);
27854 this.getEditor().Focus();
27861 replaceTextarea : function()
27863 if ( document.getElementById( this.getId() + '___Frame' ) )
27865 //if ( !this.checkBrowser || this._isCompatibleBrowser() )
27867 // We must check the elements firstly using the Id and then the name.
27868 var oTextarea = document.getElementById( this.getId() );
27870 var colElementsByName = document.getElementsByName( this.getId() ) ;
27872 oTextarea.style.display = 'none' ;
27874 if ( oTextarea.tabIndex ) {
27875 this.TabIndex = oTextarea.tabIndex ;
27878 this._insertHtmlBefore( this._getConfigHtml(), oTextarea ) ;
27879 this._insertHtmlBefore( this._getIFrameHtml(), oTextarea ) ;
27880 this.frame = Roo.get(this.getId() + '___Frame')
27883 _getConfigHtml : function()
27887 for ( var o in this.fckconfig ) {
27888 sConfig += sConfig.length > 0 ? '&' : '';
27889 sConfig += encodeURIComponent( o ) + '=' + encodeURIComponent( this.fckconfig[o] ) ;
27892 return '<input type="hidden" id="' + this.getId() + '___Config" value="' + sConfig + '" style="display:none" />' ;
27896 _getIFrameHtml : function()
27898 var sFile = 'fckeditor.html' ;
27899 /* no idea what this is about..
27902 if ( (/fcksource=true/i).test( window.top.location.search ) )
27903 sFile = 'fckeditor.original.html' ;
27908 var sLink = this.basePath + 'editor/' + sFile + '?InstanceName=' + encodeURIComponent( this.getId() ) ;
27909 sLink += this.toolbarSet ? ( '&Toolbar=' + this.toolbarSet) : '';
27912 var html = '<iframe id="' + this.getId() +
27913 '___Frame" src="' + sLink +
27914 '" width="' + this.width +
27915 '" height="' + this.height + '"' +
27916 (this.tabIndex ? ' tabindex="' + this.tabIndex + '"' :'' ) +
27917 ' frameborder="0" scrolling="no"></iframe>' ;
27922 _insertHtmlBefore : function( html, element )
27924 if ( element.insertAdjacentHTML ) {
27926 element.insertAdjacentHTML( 'beforeBegin', html ) ;
27928 var oRange = document.createRange() ;
27929 oRange.setStartBefore( element ) ;
27930 var oFragment = oRange.createContextualFragment( html );
27931 element.parentNode.insertBefore( oFragment, element ) ;
27944 //Roo.reg('fckeditor', Roo.form.FCKeditor);
27946 function FCKeditor_OnComplete(editorInstance){
27947 var f = Roo.form.FCKeditor.editors[editorInstance.Name];
27948 f.fckEditor = editorInstance;
27949 //console.log("loaded");
27950 f.fireEvent('editorinit', f, editorInstance);
27970 //<script type="text/javascript">
27972 * @class Roo.form.GridField
27973 * @extends Roo.form.Field
27974 * Embed a grid (or editable grid into a form)
27977 * This embeds a grid in a form, the value of the field should be the json encoded array of rows
27979 * xgrid.store = Roo.data.Store
27980 * xgrid.store.proxy = Roo.data.MemoryProxy (data = [] )
27981 * xgrid.store.reader = Roo.data.JsonReader
27985 * Creates a new GridField
27986 * @param {Object} config Configuration options
27988 Roo.form.GridField = function(config){
27989 Roo.form.GridField.superclass.constructor.call(this, config);
27993 Roo.extend(Roo.form.GridField, Roo.form.Field, {
27995 * @cfg {Number} width - used to restrict width of grid..
27999 * @cfg {Number} height - used to restrict height of grid..
28003 * @cfg {Object} xgrid (xtype'd description of grid) { xtype : 'Grid', dataSource: .... }
28009 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28010 * {tag: "input", type: "checkbox", autocomplete: "off"})
28012 // defaultAutoCreate : { tag: 'div' },
28013 defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28015 * @cfg {String} addTitle Text to include for adding a title.
28019 onResize : function(){
28020 Roo.form.Field.superclass.onResize.apply(this, arguments);
28023 initEvents : function(){
28024 // Roo.form.Checkbox.superclass.initEvents.call(this);
28025 // has no events...
28030 getResizeEl : function(){
28034 getPositionEl : function(){
28039 onRender : function(ct, position){
28041 this.style = this.style || 'overflow: hidden; border:1px solid #c3daf9;';
28042 var style = this.style;
28045 Roo.form.GridField.superclass.onRender.call(this, ct, position);
28046 this.wrap = this.el.wrap({cls: ''}); // not sure why ive done thsi...
28047 this.viewEl = this.wrap.createChild({ tag: 'div' });
28049 this.viewEl.applyStyles(style);
28052 this.viewEl.setWidth(this.width);
28055 this.viewEl.setHeight(this.height);
28057 //if(this.inputValue !== undefined){
28058 //this.setValue(this.value);
28061 this.grid = new Roo.grid[this.xgrid.xtype](this.viewEl, this.xgrid);
28064 this.grid.render();
28065 this.grid.getDataSource().on('remove', this.refreshValue, this);
28066 this.grid.getDataSource().on('update', this.refreshValue, this);
28067 this.grid.on('afteredit', this.refreshValue, this);
28073 * Sets the value of the item.
28074 * @param {String} either an object or a string..
28076 setValue : function(v){
28078 v = v || []; // empty set..
28079 // this does not seem smart - it really only affects memoryproxy grids..
28080 if (this.grid && this.grid.getDataSource() && typeof(v) != 'undefined') {
28081 var ds = this.grid.getDataSource();
28082 // assumes a json reader..
28084 data[ds.reader.meta.root ] = typeof(v) == 'string' ? Roo.decode(v) : v;
28085 ds.loadData( data);
28087 Roo.form.GridField.superclass.setValue.call(this, v);
28088 this.refreshValue();
28089 // should load data in the grid really....
28093 refreshValue: function() {
28095 this.grid.getDataSource().each(function(r) {
28098 this.el.dom.value = Roo.encode(val);
28106 * Ext JS Library 1.1.1
28107 * Copyright(c) 2006-2007, Ext JS, LLC.
28109 * Originally Released Under LGPL - original licence link has changed is not relivant.
28112 * <script type="text/javascript">
28115 * @class Roo.form.DisplayField
28116 * @extends Roo.form.Field
28117 * A generic Field to display non-editable data.
28119 * Creates a new Display Field item.
28120 * @param {Object} config Configuration options
28122 Roo.form.DisplayField = function(config){
28123 Roo.form.DisplayField.superclass.constructor.call(this, config);
28127 Roo.extend(Roo.form.DisplayField, Roo.form.TextField, {
28128 inputType: 'hidden',
28134 * @cfg {String} focusClass The CSS class to use when the checkbox receives focus (defaults to undefined)
28136 focusClass : undefined,
28138 * @cfg {String} fieldClass The default CSS class for the checkbox (defaults to "x-form-field")
28140 fieldClass: 'x-form-field',
28143 * @cfg {Function} valueRenderer The renderer for the field (so you can reformat output). should return raw HTML
28145 valueRenderer: undefined,
28149 * @cfg {String/Object} autoCreate A DomHelper element spec, or true for a default element spec (defaults to
28150 * {tag: "input", type: "checkbox", autocomplete: "off"})
28153 // defaultAutoCreate : { tag: 'input', type: 'hidden', autocomplete: 'off'},
28155 onResize : function(){
28156 Roo.form.DisplayField.superclass.onResize.apply(this, arguments);
28160 initEvents : function(){
28161 // Roo.form.Checkbox.superclass.initEvents.call(this);
28162 // has no events...
28167 getResizeEl : function(){
28171 getPositionEl : function(){
28176 onRender : function(ct, position){
28178 Roo.form.DisplayField.superclass.onRender.call(this, ct, position);
28179 //if(this.inputValue !== undefined){
28180 this.wrap = this.el.wrap();
28182 this.viewEl = this.wrap.createChild({ tag: 'div'});
28184 if (this.bodyStyle) {
28185 this.viewEl.applyStyles(this.bodyStyle);
28187 //this.viewEl.setStyle('padding', '2px');
28189 this.setValue(this.value);
28194 initValue : Roo.emptyFn,
28199 onClick : function(){
28204 * Sets the checked state of the checkbox.
28205 * @param {Boolean/String} checked True, 'true', '1', or 'on' to check the checkbox, any other value will uncheck it.
28207 setValue : function(v){
28209 var html = this.valueRenderer ? this.valueRenderer(v) : String.format('{0}', v);
28210 // this might be called before we have a dom element..
28211 if (!this.viewEl) {
28214 this.viewEl.dom.innerHTML = html;
28215 Roo.form.DisplayField.superclass.setValue.call(this, v);
28218 });//<script type="text/javasscript">
28222 * @class Roo.DDView
28223 * A DnD enabled version of Roo.View.
28224 * @param {Element/String} container The Element in which to create the View.
28225 * @param {String} tpl The template string used to create the markup for each element of the View
28226 * @param {Object} config The configuration properties. These include all the config options of
28227 * {@link Roo.View} plus some specific to this class.<br>
28229 * Drag/drop is implemented by adding {@link Roo.data.Record}s to the target DDView. If copying is
28230 * not being performed, the original {@link Roo.data.Record} is removed from the source DDView.<br>
28232 * The following extra CSS rules are needed to provide insertion point highlighting:<pre><code>
28233 .x-view-drag-insert-above {
28234 border-top:1px dotted #3366cc;
28236 .x-view-drag-insert-below {
28237 border-bottom:1px dotted #3366cc;
28243 Roo.DDView = function(container, tpl, config) {
28244 Roo.DDView.superclass.constructor.apply(this, arguments);
28245 this.getEl().setStyle("outline", "0px none");
28246 this.getEl().unselectable();
28247 if (this.dragGroup) {
28248 this.setDraggable(this.dragGroup.split(","));
28250 if (this.dropGroup) {
28251 this.setDroppable(this.dropGroup.split(","));
28253 if (this.deletable) {
28254 this.setDeletable();
28256 this.isDirtyFlag = false;
28262 Roo.extend(Roo.DDView, Roo.View, {
28263 /** @cfg {String/Array} dragGroup The ddgroup name(s) for the View's DragZone. */
28264 /** @cfg {String/Array} dropGroup The ddgroup name(s) for the View's DropZone. */
28265 /** @cfg {Boolean} copy Causes drag operations to copy nodes rather than move. */
28266 /** @cfg {Boolean} allowCopy Causes ctrl/drag operations to copy nodes rather than move. */
28270 reset: Roo.emptyFn,
28272 clearInvalid: Roo.form.Field.prototype.clearInvalid,
28274 validate: function() {
28278 destroy: function() {
28279 this.purgeListeners();
28280 this.getEl.removeAllListeners();
28281 this.getEl().remove();
28282 if (this.dragZone) {
28283 if (this.dragZone.destroy) {
28284 this.dragZone.destroy();
28287 if (this.dropZone) {
28288 if (this.dropZone.destroy) {
28289 this.dropZone.destroy();
28294 /** Allows this class to be an Roo.form.Field so it can be found using {@link Roo.form.BasicForm#findField}. */
28295 getName: function() {
28299 /** Loads the View from a JSON string representing the Records to put into the Store. */
28300 setValue: function(v) {
28302 throw "DDView.setValue(). DDView must be constructed with a valid Store";
28305 data[this.store.reader.meta.root] = v ? [].concat(v) : [];
28306 this.store.proxy = new Roo.data.MemoryProxy(data);
28310 /** @return {String} a parenthesised list of the ids of the Records in the View. */
28311 getValue: function() {
28313 this.store.each(function(rec) {
28314 result += rec.id + ',';
28316 return result.substr(0, result.length - 1) + ')';
28319 getIds: function() {
28320 var i = 0, result = new Array(this.store.getCount());
28321 this.store.each(function(rec) {
28322 result[i++] = rec.id;
28327 isDirty: function() {
28328 return this.isDirtyFlag;
28332 * Part of the Roo.dd.DropZone interface. If no target node is found, the
28333 * whole Element becomes the target, and this causes the drop gesture to append.
28335 getTargetFromEvent : function(e) {
28336 var target = e.getTarget();
28337 while ((target !== null) && (target.parentNode != this.el.dom)) {
28338 target = target.parentNode;
28341 target = this.el.dom.lastChild || this.el.dom;
28347 * Create the drag data which consists of an object which has the property "ddel" as
28348 * the drag proxy element.
28350 getDragData : function(e) {
28351 var target = this.findItemFromChild(e.getTarget());
28353 this.handleSelection(e);
28354 var selNodes = this.getSelectedNodes();
28357 copy: this.copy || (this.allowCopy && e.ctrlKey),
28361 var selectedIndices = this.getSelectedIndexes();
28362 for (var i = 0; i < selectedIndices.length; i++) {
28363 dragData.records.push(this.store.getAt(selectedIndices[i]));
28365 if (selNodes.length == 1) {
28366 dragData.ddel = target.cloneNode(true); // the div element
28368 var div = document.createElement('div'); // create the multi element drag "ghost"
28369 div.className = 'multi-proxy';
28370 for (var i = 0, len = selNodes.length; i < len; i++) {
28371 div.appendChild(selNodes[i].cloneNode(true));
28373 dragData.ddel = div;
28375 //console.log(dragData)
28376 //console.log(dragData.ddel.innerHTML)
28379 //console.log('nodragData')
28383 /** Specify to which ddGroup items in this DDView may be dragged. */
28384 setDraggable: function(ddGroup) {
28385 if (ddGroup instanceof Array) {
28386 Roo.each(ddGroup, this.setDraggable, this);
28389 if (this.dragZone) {
28390 this.dragZone.addToGroup(ddGroup);
28392 this.dragZone = new Roo.dd.DragZone(this.getEl(), {
28393 containerScroll: true,
28397 // Draggability implies selection. DragZone's mousedown selects the element.
28398 if (!this.multiSelect) { this.singleSelect = true; }
28400 // Wire the DragZone's handlers up to methods in *this*
28401 this.dragZone.getDragData = this.getDragData.createDelegate(this);
28405 /** Specify from which ddGroup this DDView accepts drops. */
28406 setDroppable: function(ddGroup) {
28407 if (ddGroup instanceof Array) {
28408 Roo.each(ddGroup, this.setDroppable, this);
28411 if (this.dropZone) {
28412 this.dropZone.addToGroup(ddGroup);
28414 this.dropZone = new Roo.dd.DropZone(this.getEl(), {
28415 containerScroll: true,
28419 // Wire the DropZone's handlers up to methods in *this*
28420 this.dropZone.getTargetFromEvent = this.getTargetFromEvent.createDelegate(this);
28421 this.dropZone.onNodeEnter = this.onNodeEnter.createDelegate(this);
28422 this.dropZone.onNodeOver = this.onNodeOver.createDelegate(this);
28423 this.dropZone.onNodeOut = this.onNodeOut.createDelegate(this);
28424 this.dropZone.onNodeDrop = this.onNodeDrop.createDelegate(this);
28428 /** Decide whether to drop above or below a View node. */
28429 getDropPoint : function(e, n, dd){
28430 if (n == this.el.dom) { return "above"; }
28431 var t = Roo.lib.Dom.getY(n), b = t + n.offsetHeight;
28432 var c = t + (b - t) / 2;
28433 var y = Roo.lib.Event.getPageY(e);
28441 onNodeEnter : function(n, dd, e, data){
28445 onNodeOver : function(n, dd, e, data){
28446 var pt = this.getDropPoint(e, n, dd);
28447 // set the insert point style on the target node
28448 var dragElClass = this.dropNotAllowed;
28451 if (pt == "above"){
28452 dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
28453 targetElClass = "x-view-drag-insert-above";
28455 dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
28456 targetElClass = "x-view-drag-insert-below";
28458 if (this.lastInsertClass != targetElClass){
28459 Roo.fly(n).replaceClass(this.lastInsertClass, targetElClass);
28460 this.lastInsertClass = targetElClass;
28463 return dragElClass;
28466 onNodeOut : function(n, dd, e, data){
28467 this.removeDropIndicators(n);
28470 onNodeDrop : function(n, dd, e, data){
28471 if (this.fireEvent("drop", this, n, dd, e, data) === false) {
28474 var pt = this.getDropPoint(e, n, dd);
28475 var insertAt = (n == this.el.dom) ? this.nodes.length : n.nodeIndex;
28476 if (pt == "below") { insertAt++; }
28477 for (var i = 0; i < data.records.length; i++) {
28478 var r = data.records[i];
28479 var dup = this.store.getById(r.id);
28480 if (dup && (dd != this.dragZone)) {
28481 Roo.fly(this.getNode(this.store.indexOf(dup))).frame("red", 1);
28484 this.store.insert(insertAt++, r.copy());
28486 data.source.isDirtyFlag = true;
28488 this.store.insert(insertAt++, r);
28490 this.isDirtyFlag = true;
28493 this.dragZone.cachedTarget = null;
28497 removeDropIndicators : function(n){
28499 Roo.fly(n).removeClass([
28500 "x-view-drag-insert-above",
28501 "x-view-drag-insert-below"]);
28502 this.lastInsertClass = "_noclass";
28507 * Utility method. Add a delete option to the DDView's context menu.
28508 * @param {String} imageUrl The URL of the "delete" icon image.
28510 setDeletable: function(imageUrl) {
28511 if (!this.singleSelect && !this.multiSelect) {
28512 this.singleSelect = true;
28514 var c = this.getContextMenu();
28515 this.contextMenu.on("itemclick", function(item) {
28518 this.remove(this.getSelectedIndexes());
28522 this.contextMenu.add({
28529 /** Return the context menu for this DDView. */
28530 getContextMenu: function() {
28531 if (!this.contextMenu) {
28532 // Create the View's context menu
28533 this.contextMenu = new Roo.menu.Menu({
28534 id: this.id + "-contextmenu"
28536 this.el.on("contextmenu", this.showContextMenu, this);
28538 return this.contextMenu;
28541 disableContextMenu: function() {
28542 if (this.contextMenu) {
28543 this.el.un("contextmenu", this.showContextMenu, this);
28547 showContextMenu: function(e, item) {
28548 item = this.findItemFromChild(e.getTarget());
28551 this.select(this.getNode(item), this.multiSelect && e.ctrlKey, true);
28552 this.contextMenu.showAt(e.getXY());
28557 * Remove {@link Roo.data.Record}s at the specified indices.
28558 * @param {Array/Number} selectedIndices The index (or Array of indices) of Records to remove.
28560 remove: function(selectedIndices) {
28561 selectedIndices = [].concat(selectedIndices);
28562 for (var i = 0; i < selectedIndices.length; i++) {
28563 var rec = this.store.getAt(selectedIndices[i]);
28564 this.store.remove(rec);
28569 * Double click fires the event, but also, if this is draggable, and there is only one other
28570 * related DropZone, it transfers the selected node.
28572 onDblClick : function(e){
28573 var item = this.findItemFromChild(e.getTarget());
28575 if (this.fireEvent("dblclick", this, this.indexOf(item), item, e) === false) {
28578 if (this.dragGroup) {
28579 var targets = Roo.dd.DragDropMgr.getRelated(this.dragZone, true);
28580 while (targets.indexOf(this.dropZone) > -1) {
28581 targets.remove(this.dropZone);
28583 if (targets.length == 1) {
28584 this.dragZone.cachedTarget = null;
28585 var el = Roo.get(targets[0].getEl());
28586 var box = el.getBox(true);
28587 targets[0].onNodeDrop(el.dom, {
28589 xy: [box.x, box.y + box.height - 1]
28590 }, null, this.getDragData(e));
28596 handleSelection: function(e) {
28597 this.dragZone.cachedTarget = null;
28598 var item = this.findItemFromChild(e.getTarget());
28600 this.clearSelections(true);
28603 if (item && (this.multiSelect || this.singleSelect)){
28604 if(this.multiSelect && e.shiftKey && (!e.ctrlKey) && this.lastSelection){
28605 this.select(this.getNodes(this.indexOf(this.lastSelection), item.nodeIndex), false);
28606 }else if (this.isSelected(this.getNode(item)) && e.ctrlKey){
28607 this.unselect(item);
28609 this.select(item, this.multiSelect && e.ctrlKey);
28610 this.lastSelection = item;
28615 onItemClick : function(item, index, e){
28616 if(this.fireEvent("beforeclick", this, index, item, e) === false){
28622 unselect : function(nodeInfo, suppressEvent){
28623 var node = this.getNode(nodeInfo);
28624 if(node && this.isSelected(node)){
28625 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
28626 Roo.fly(node).removeClass(this.selectedClass);
28627 this.selections.remove(node);
28628 if(!suppressEvent){
28629 this.fireEvent("selectionchange", this, this.selections);
28637 * Ext JS Library 1.1.1
28638 * Copyright(c) 2006-2007, Ext JS, LLC.
28640 * Originally Released Under LGPL - original licence link has changed is not relivant.
28643 * <script type="text/javascript">
28647 * @class Roo.LayoutManager
28648 * @extends Roo.util.Observable
28649 * Base class for layout managers.
28651 Roo.LayoutManager = function(container, config){
28652 Roo.LayoutManager.superclass.constructor.call(this);
28653 this.el = Roo.get(container);
28654 // ie scrollbar fix
28655 if(this.el.dom == document.body && Roo.isIE && !config.allowScroll){
28656 document.body.scroll = "no";
28657 }else if(this.el.dom != document.body && this.el.getStyle('position') == 'static'){
28658 this.el.position('relative');
28660 this.id = this.el.id;
28661 this.el.addClass("x-layout-container");
28662 /** false to disable window resize monitoring @type Boolean */
28663 this.monitorWindowResize = true;
28668 * Fires when a layout is performed.
28669 * @param {Roo.LayoutManager} this
28673 * @event regionresized
28674 * Fires when the user resizes a region.
28675 * @param {Roo.LayoutRegion} region The resized region
28676 * @param {Number} newSize The new size (width for east/west, height for north/south)
28678 "regionresized" : true,
28680 * @event regioncollapsed
28681 * Fires when a region is collapsed.
28682 * @param {Roo.LayoutRegion} region The collapsed region
28684 "regioncollapsed" : true,
28686 * @event regionexpanded
28687 * Fires when a region is expanded.
28688 * @param {Roo.LayoutRegion} region The expanded region
28690 "regionexpanded" : true
28692 this.updating = false;
28693 Roo.EventManager.onWindowResize(this.onWindowResize, this, true);
28696 Roo.extend(Roo.LayoutManager, Roo.util.Observable, {
28698 * Returns true if this layout is currently being updated
28699 * @return {Boolean}
28701 isUpdating : function(){
28702 return this.updating;
28706 * Suspend the LayoutManager from doing auto-layouts while
28707 * making multiple add or remove calls
28709 beginUpdate : function(){
28710 this.updating = true;
28714 * Restore auto-layouts and optionally disable the manager from performing a layout
28715 * @param {Boolean} noLayout true to disable a layout update
28717 endUpdate : function(noLayout){
28718 this.updating = false;
28724 layout: function(){
28728 onRegionResized : function(region, newSize){
28729 this.fireEvent("regionresized", region, newSize);
28733 onRegionCollapsed : function(region){
28734 this.fireEvent("regioncollapsed", region);
28737 onRegionExpanded : function(region){
28738 this.fireEvent("regionexpanded", region);
28742 * Returns the size of the current view. This method normalizes document.body and element embedded layouts and
28743 * performs box-model adjustments.
28744 * @return {Object} The size as an object {width: (the width), height: (the height)}
28746 getViewSize : function(){
28748 if(this.el.dom != document.body){
28749 size = this.el.getSize();
28751 size = {width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
28753 size.width -= this.el.getBorderWidth("lr")-this.el.getPadding("lr");
28754 size.height -= this.el.getBorderWidth("tb")-this.el.getPadding("tb");
28759 * Returns the Element this layout is bound to.
28760 * @return {Roo.Element}
28762 getEl : function(){
28767 * Returns the specified region.
28768 * @param {String} target The region key ('center', 'north', 'south', 'east' or 'west')
28769 * @return {Roo.LayoutRegion}
28771 getRegion : function(target){
28772 return this.regions[target.toLowerCase()];
28775 onWindowResize : function(){
28776 if(this.monitorWindowResize){
28782 * Ext JS Library 1.1.1
28783 * Copyright(c) 2006-2007, Ext JS, LLC.
28785 * Originally Released Under LGPL - original licence link has changed is not relivant.
28788 * <script type="text/javascript">
28791 * @class Roo.BorderLayout
28792 * @extends Roo.LayoutManager
28793 * This class represents a common layout manager used in desktop applications. For screenshots and more details,
28794 * please see: <br><br>
28795 * <a href="http://www.jackslocum.com/yui/2006/10/19/cross-browser-web-20-layouts-with-yahoo-ui/">Cross Browser Layouts - Part 1</a><br>
28796 * <a href="http://www.jackslocum.com/yui/2006/10/28/cross-browser-web-20-layouts-part-2-ajax-feed-viewer-20/">Cross Browser Layouts - Part 2</a><br><br>
28799 var layout = new Roo.BorderLayout(document.body, {
28833 preferredTabWidth: 150
28838 var CP = Roo.ContentPanel;
28840 layout.beginUpdate();
28841 layout.add("north", new CP("north", "North"));
28842 layout.add("south", new CP("south", {title: "South", closable: true}));
28843 layout.add("west", new CP("west", {title: "West"}));
28844 layout.add("east", new CP("autoTabs", {title: "Auto Tabs", closable: true}));
28845 layout.add("center", new CP("center1", {title: "Close Me", closable: true}));
28846 layout.add("center", new CP("center2", {title: "Center Panel", closable: false}));
28847 layout.getRegion("center").showPanel("center1");
28848 layout.endUpdate();
28851 <b>The container the layout is rendered into can be either the body element or any other element.
28852 If it is not the body element, the container needs to either be an absolute positioned element,
28853 or you will need to add "position:relative" to the css of the container. You will also need to specify
28854 the container size if it is not the body element.</b>
28857 * Create a new BorderLayout
28858 * @param {String/HTMLElement/Element} container The container this layout is bound to
28859 * @param {Object} config Configuration options
28861 Roo.BorderLayout = function(container, config){
28862 config = config || {};
28863 Roo.BorderLayout.superclass.constructor.call(this, container, config);
28864 this.factory = config.factory || Roo.BorderLayout.RegionFactory;
28865 for(var i = 0, len = this.factory.validRegions.length; i < len; i++) {
28866 var target = this.factory.validRegions[i];
28867 if(config[target]){
28868 this.addRegion(target, config[target]);
28873 Roo.extend(Roo.BorderLayout, Roo.LayoutManager, {
28875 * Creates and adds a new region if it doesn't already exist.
28876 * @param {String} target The target region key (north, south, east, west or center).
28877 * @param {Object} config The regions config object
28878 * @return {BorderLayoutRegion} The new region
28880 addRegion : function(target, config){
28881 if(!this.regions[target]){
28882 var r = this.factory.create(target, this, config);
28883 this.bindRegion(target, r);
28885 return this.regions[target];
28889 bindRegion : function(name, r){
28890 this.regions[name] = r;
28891 r.on("visibilitychange", this.layout, this);
28892 r.on("paneladded", this.layout, this);
28893 r.on("panelremoved", this.layout, this);
28894 r.on("invalidated", this.layout, this);
28895 r.on("resized", this.onRegionResized, this);
28896 r.on("collapsed", this.onRegionCollapsed, this);
28897 r.on("expanded", this.onRegionExpanded, this);
28901 * Performs a layout update.
28903 layout : function(){
28904 if(this.updating) return;
28905 var size = this.getViewSize();
28906 var w = size.width;
28907 var h = size.height;
28912 //var x = 0, y = 0;
28914 var rs = this.regions;
28915 var north = rs["north"];
28916 var south = rs["south"];
28917 var west = rs["west"];
28918 var east = rs["east"];
28919 var center = rs["center"];
28920 //if(this.hideOnLayout){ // not supported anymore
28921 //c.el.setStyle("display", "none");
28923 if(north && north.isVisible()){
28924 var b = north.getBox();
28925 var m = north.getMargins();
28926 b.width = w - (m.left+m.right);
28929 centerY = b.height + b.y + m.bottom;
28930 centerH -= centerY;
28931 north.updateBox(this.safeBox(b));
28933 if(south && south.isVisible()){
28934 var b = south.getBox();
28935 var m = south.getMargins();
28936 b.width = w - (m.left+m.right);
28938 var totalHeight = (b.height + m.top + m.bottom);
28939 b.y = h - totalHeight + m.top;
28940 centerH -= totalHeight;
28941 south.updateBox(this.safeBox(b));
28943 if(west && west.isVisible()){
28944 var b = west.getBox();
28945 var m = west.getMargins();
28946 b.height = centerH - (m.top+m.bottom);
28948 b.y = centerY + m.top;
28949 var totalWidth = (b.width + m.left + m.right);
28950 centerX += totalWidth;
28951 centerW -= totalWidth;
28952 west.updateBox(this.safeBox(b));
28954 if(east && east.isVisible()){
28955 var b = east.getBox();
28956 var m = east.getMargins();
28957 b.height = centerH - (m.top+m.bottom);
28958 var totalWidth = (b.width + m.left + m.right);
28959 b.x = w - totalWidth + m.left;
28960 b.y = centerY + m.top;
28961 centerW -= totalWidth;
28962 east.updateBox(this.safeBox(b));
28965 var m = center.getMargins();
28967 x: centerX + m.left,
28968 y: centerY + m.top,
28969 width: centerW - (m.left+m.right),
28970 height: centerH - (m.top+m.bottom)
28972 //if(this.hideOnLayout){
28973 //center.el.setStyle("display", "block");
28975 center.updateBox(this.safeBox(centerBox));
28978 this.fireEvent("layout", this);
28982 safeBox : function(box){
28983 box.width = Math.max(0, box.width);
28984 box.height = Math.max(0, box.height);
28989 * Adds a ContentPanel (or subclass) to this layout.
28990 * @param {String} target The target region key (north, south, east, west or center).
28991 * @param {Roo.ContentPanel} panel The panel to add
28992 * @return {Roo.ContentPanel} The added panel
28994 add : function(target, panel){
28996 target = target.toLowerCase();
28997 return this.regions[target].add(panel);
29001 * Remove a ContentPanel (or subclass) to this layout.
29002 * @param {String} target The target region key (north, south, east, west or center).
29003 * @param {Number/String/Roo.ContentPanel} panel The index, id or panel to remove
29004 * @return {Roo.ContentPanel} The removed panel
29006 remove : function(target, panel){
29007 target = target.toLowerCase();
29008 return this.regions[target].remove(panel);
29012 * Searches all regions for a panel with the specified id
29013 * @param {String} panelId
29014 * @return {Roo.ContentPanel} The panel or null if it wasn't found
29016 findPanel : function(panelId){
29017 var rs = this.regions;
29018 for(var target in rs){
29019 if(typeof rs[target] != "function"){
29020 var p = rs[target].getPanel(panelId);
29030 * Searches all regions for a panel with the specified id and activates (shows) it.
29031 * @param {String/ContentPanel} panelId The panels id or the panel itself
29032 * @return {Roo.ContentPanel} The shown panel or null
29034 showPanel : function(panelId) {
29035 var rs = this.regions;
29036 for(var target in rs){
29037 var r = rs[target];
29038 if(typeof r != "function"){
29039 if(r.hasPanel(panelId)){
29040 return r.showPanel(panelId);
29048 * Restores this layout's state using Roo.state.Manager or the state provided by the passed provider.
29049 * @param {Roo.state.Provider} provider (optional) An alternate state provider
29051 restoreState : function(provider){
29053 provider = Roo.state.Manager;
29055 var sm = new Roo.LayoutStateManager();
29056 sm.init(this, provider);
29060 * Adds a batch of multiple ContentPanels dynamically by passing a special regions config object. This config
29061 * object should contain properties for each region to add ContentPanels to, and each property's value should be
29062 * a valid ContentPanel config object. Example:
29064 // Create the main layout
29065 var layout = new Roo.BorderLayout('main-ct', {
29076 // Create and add multiple ContentPanels at once via configs
29079 id: 'source-files',
29081 title:'Ext Source Files',
29094 * @param {Object} regions An object containing ContentPanel configs by region name
29096 batchAdd : function(regions){
29097 this.beginUpdate();
29098 for(var rname in regions){
29099 var lr = this.regions[rname];
29101 this.addTypedPanels(lr, regions[rname]);
29108 addTypedPanels : function(lr, ps){
29109 if(typeof ps == 'string'){
29110 lr.add(new Roo.ContentPanel(ps));
29112 else if(ps instanceof Array){
29113 for(var i =0, len = ps.length; i < len; i++){
29114 this.addTypedPanels(lr, ps[i]);
29117 else if(!ps.events){ // raw config?
29119 delete ps.el; // prevent conflict
29120 lr.add(new Roo.ContentPanel(el || Roo.id(), ps));
29122 else { // panel object assumed!
29127 * Adds a xtype elements to the layout.
29131 xtype : 'ContentPanel',
29138 xtype : 'NestedLayoutPanel',
29144 items : [ ... list of content panels or nested layout panels.. ]
29148 * @param {Object} cfg Xtype definition of item to add.
29150 addxtype : function(cfg)
29152 // basically accepts a pannel...
29153 // can accept a layout region..!?!?
29154 // console.log('BorderLayout add ' + cfg.xtype)
29156 if (!cfg.xtype.match(/Panel$/)) {
29160 var region = cfg.region;
29166 xitems = cfg.items;
29173 case 'ContentPanel': // ContentPanel (el, cfg)
29174 case 'ScrollPanel': // ContentPanel (el, cfg)
29175 if(cfg.autoCreate) {
29176 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29178 var el = this.el.createChild();
29179 ret = new Roo[cfg.xtype](el, cfg); // new panel!!!!!
29182 this.add(region, ret);
29186 case 'TreePanel': // our new panel!
29187 cfg.el = this.el.createChild();
29188 ret = new Roo[cfg.xtype](cfg); // new panel!!!!!
29189 this.add(region, ret);
29192 case 'NestedLayoutPanel':
29193 // create a new Layout (which is a Border Layout...
29194 var el = this.el.createChild();
29195 var clayout = cfg.layout;
29197 clayout.items = clayout.items || [];
29198 // replace this exitems with the clayout ones..
29199 xitems = clayout.items;
29202 if (region == 'center' && this.active && this.getRegion('center').panels.length < 1) {
29203 cfg.background = false;
29205 var layout = new Roo.BorderLayout(el, clayout);
29207 ret = new Roo[cfg.xtype](layout, cfg); // new panel!!!!!
29208 //console.log('adding nested layout panel ' + cfg.toSource());
29209 this.add(region, ret);
29215 // needs grid and region
29217 //var el = this.getRegion(region).el.createChild();
29218 var el = this.el.createChild();
29219 // create the grid first...
29221 var grid = new Roo.grid[cfg.grid.xtype](el, cfg.grid);
29223 if (region == 'center' && this.active ) {
29224 cfg.background = false;
29226 ret = new Roo[cfg.xtype](grid, cfg); // new panel!!!!!
29228 this.add(region, ret);
29229 if (cfg.background) {
29230 ret.on('activate', function(gp) {
29231 if (!gp.grid.rendered) {
29244 alert("Can not add '" + cfg.xtype + "' to BorderLayout");
29246 // GridPanel (grid, cfg)
29249 this.beginUpdate();
29251 Roo.each(xitems, function(i) {
29261 * Shortcut for creating a new BorderLayout object and adding one or more ContentPanels to it in a single step, handling
29262 * the beginUpdate and endUpdate calls internally. The key to this method is the <b>panels</b> property that can be
29263 * provided with each region config, which allows you to add ContentPanel configs in addition to the region configs
29264 * during creation. The following code is equivalent to the constructor-based example at the beginning of this class:
29267 var CP = Roo.ContentPanel;
29269 var layout = Roo.BorderLayout.create({
29273 panels: [new CP("north", "North")]
29282 panels: [new CP("west", {title: "West"})]
29291 panels: [new CP("autoTabs", {title: "Auto Tabs", closable: true})]
29300 panels: [new CP("south", {title: "South", closable: true})]
29307 preferredTabWidth: 150,
29309 new CP("center1", {title: "Close Me", closable: true}),
29310 new CP("center2", {title: "Center Panel", closable: false})
29315 layout.getRegion("center").showPanel("center1");
29320 Roo.BorderLayout.create = function(config, targetEl){
29321 var layout = new Roo.BorderLayout(targetEl || document.body, config);
29322 layout.beginUpdate();
29323 var regions = Roo.BorderLayout.RegionFactory.validRegions;
29324 for(var j = 0, jlen = regions.length; j < jlen; j++){
29325 var lr = regions[j];
29326 if(layout.regions[lr] && config[lr].panels){
29327 var r = layout.regions[lr];
29328 var ps = config[lr].panels;
29329 layout.addTypedPanels(r, ps);
29332 layout.endUpdate();
29337 Roo.BorderLayout.RegionFactory = {
29339 validRegions : ["north","south","east","west","center"],
29342 create : function(target, mgr, config){
29343 target = target.toLowerCase();
29344 if(config.lightweight || config.basic){
29345 return new Roo.BasicLayoutRegion(mgr, config, target);
29349 return new Roo.NorthLayoutRegion(mgr, config);
29351 return new Roo.SouthLayoutRegion(mgr, config);
29353 return new Roo.EastLayoutRegion(mgr, config);
29355 return new Roo.WestLayoutRegion(mgr, config);
29357 return new Roo.CenterLayoutRegion(mgr, config);
29359 throw 'Layout region "'+target+'" not supported.';
29363 * Ext JS Library 1.1.1
29364 * Copyright(c) 2006-2007, Ext JS, LLC.
29366 * Originally Released Under LGPL - original licence link has changed is not relivant.
29369 * <script type="text/javascript">
29373 * @class Roo.BasicLayoutRegion
29374 * @extends Roo.util.Observable
29375 * This class represents a lightweight region in a layout manager. This region does not move dom nodes
29376 * and does not have a titlebar, tabs or any other features. All it does is size and position
29377 * panels. To create a BasicLayoutRegion, add lightweight:true or basic:true to your regions config.
29379 Roo.BasicLayoutRegion = function(mgr, config, pos, skipConfig){
29381 this.position = pos;
29384 * @scope Roo.BasicLayoutRegion
29388 * @event beforeremove
29389 * Fires before a panel is removed (or closed). To cancel the removal set "e.cancel = true" on the event argument.
29390 * @param {Roo.LayoutRegion} this
29391 * @param {Roo.ContentPanel} panel The panel
29392 * @param {Object} e The cancel event object
29394 "beforeremove" : true,
29396 * @event invalidated
29397 * Fires when the layout for this region is changed.
29398 * @param {Roo.LayoutRegion} this
29400 "invalidated" : true,
29402 * @event visibilitychange
29403 * Fires when this region is shown or hidden
29404 * @param {Roo.LayoutRegion} this
29405 * @param {Boolean} visibility true or false
29407 "visibilitychange" : true,
29409 * @event paneladded
29410 * Fires when a panel is added.
29411 * @param {Roo.LayoutRegion} this
29412 * @param {Roo.ContentPanel} panel The panel
29414 "paneladded" : true,
29416 * @event panelremoved
29417 * Fires when a panel is removed.
29418 * @param {Roo.LayoutRegion} this
29419 * @param {Roo.ContentPanel} panel The panel
29421 "panelremoved" : true,
29424 * Fires when this region is collapsed.
29425 * @param {Roo.LayoutRegion} this
29427 "collapsed" : true,
29430 * Fires when this region is expanded.
29431 * @param {Roo.LayoutRegion} this
29436 * Fires when this region is slid into view.
29437 * @param {Roo.LayoutRegion} this
29439 "slideshow" : true,
29442 * Fires when this region slides out of view.
29443 * @param {Roo.LayoutRegion} this
29445 "slidehide" : true,
29447 * @event panelactivated
29448 * Fires when a panel is activated.
29449 * @param {Roo.LayoutRegion} this
29450 * @param {Roo.ContentPanel} panel The activated panel
29452 "panelactivated" : true,
29455 * Fires when the user resizes this region.
29456 * @param {Roo.LayoutRegion} this
29457 * @param {Number} newSize The new size (width for east/west, height for north/south)
29461 /** A collection of panels in this region. @type Roo.util.MixedCollection */
29462 this.panels = new Roo.util.MixedCollection();
29463 this.panels.getKey = this.getPanelId.createDelegate(this);
29465 this.activePanel = null;
29466 // ensure listeners are added...
29468 if (config.listeners || config.events) {
29469 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
29470 listeners : config.listeners || {},
29471 events : config.events || {}
29475 if(skipConfig !== true){
29476 this.applyConfig(config);
29480 Roo.extend(Roo.BasicLayoutRegion, Roo.util.Observable, {
29481 getPanelId : function(p){
29485 applyConfig : function(config){
29486 this.margins = config.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29487 this.config = config;
29492 * Resizes the region to the specified size. For vertical regions (west, east) this adjusts
29493 * the width, for horizontal (north, south) the height.
29494 * @param {Number} newSize The new width or height
29496 resizeTo : function(newSize){
29497 var el = this.el ? this.el :
29498 (this.activePanel ? this.activePanel.getEl() : null);
29500 switch(this.position){
29503 el.setWidth(newSize);
29504 this.fireEvent("resized", this, newSize);
29508 el.setHeight(newSize);
29509 this.fireEvent("resized", this, newSize);
29515 getBox : function(){
29516 return this.activePanel ? this.activePanel.getEl().getBox(false, true) : null;
29519 getMargins : function(){
29520 return this.margins;
29523 updateBox : function(box){
29525 var el = this.activePanel.getEl();
29526 el.dom.style.left = box.x + "px";
29527 el.dom.style.top = box.y + "px";
29528 this.activePanel.setSize(box.width, box.height);
29532 * Returns the container element for this region.
29533 * @return {Roo.Element}
29535 getEl : function(){
29536 return this.activePanel;
29540 * Returns true if this region is currently visible.
29541 * @return {Boolean}
29543 isVisible : function(){
29544 return this.activePanel ? true : false;
29547 setActivePanel : function(panel){
29548 panel = this.getPanel(panel);
29549 if(this.activePanel && this.activePanel != panel){
29550 this.activePanel.setActiveState(false);
29551 this.activePanel.getEl().setLeftTop(-10000,-10000);
29553 this.activePanel = panel;
29554 panel.setActiveState(true);
29556 panel.setSize(this.box.width, this.box.height);
29558 this.fireEvent("panelactivated", this, panel);
29559 this.fireEvent("invalidated");
29563 * Show the specified panel.
29564 * @param {Number/String/ContentPanel} panelId The panels index, id or the panel itself
29565 * @return {Roo.ContentPanel} The shown panel or null
29567 showPanel : function(panel){
29568 if(panel = this.getPanel(panel)){
29569 this.setActivePanel(panel);
29575 * Get the active panel for this region.
29576 * @return {Roo.ContentPanel} The active panel or null
29578 getActivePanel : function(){
29579 return this.activePanel;
29583 * Add the passed ContentPanel(s)
29584 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
29585 * @return {Roo.ContentPanel} The panel added (if only one was added)
29587 add : function(panel){
29588 if(arguments.length > 1){
29589 for(var i = 0, len = arguments.length; i < len; i++) {
29590 this.add(arguments[i]);
29594 if(this.hasPanel(panel)){
29595 this.showPanel(panel);
29598 var el = panel.getEl();
29599 if(el.dom.parentNode != this.mgr.el.dom){
29600 this.mgr.el.dom.appendChild(el.dom);
29602 if(panel.setRegion){
29603 panel.setRegion(this);
29605 this.panels.add(panel);
29606 el.setStyle("position", "absolute");
29607 if(!panel.background){
29608 this.setActivePanel(panel);
29609 if(this.config.initialSize && this.panels.getCount()==1){
29610 this.resizeTo(this.config.initialSize);
29613 this.fireEvent("paneladded", this, panel);
29618 * Returns true if the panel is in this region.
29619 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29620 * @return {Boolean}
29622 hasPanel : function(panel){
29623 if(typeof panel == "object"){ // must be panel obj
29624 panel = panel.getId();
29626 return this.getPanel(panel) ? true : false;
29630 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
29631 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29632 * @param {Boolean} preservePanel Overrides the config preservePanel option
29633 * @return {Roo.ContentPanel} The panel that was removed
29635 remove : function(panel, preservePanel){
29636 panel = this.getPanel(panel);
29641 this.fireEvent("beforeremove", this, panel, e);
29642 if(e.cancel === true){
29645 var panelId = panel.getId();
29646 this.panels.removeKey(panelId);
29651 * Returns the panel specified or null if it's not in this region.
29652 * @param {Number/String/ContentPanel} panel The panels index, id or the panel itself
29653 * @return {Roo.ContentPanel}
29655 getPanel : function(id){
29656 if(typeof id == "object"){ // must be panel obj
29659 return this.panels.get(id);
29663 * Returns this regions position (north/south/east/west/center).
29666 getPosition: function(){
29667 return this.position;
29671 * Ext JS Library 1.1.1
29672 * Copyright(c) 2006-2007, Ext JS, LLC.
29674 * Originally Released Under LGPL - original licence link has changed is not relivant.
29677 * <script type="text/javascript">
29681 * @class Roo.LayoutRegion
29682 * @extends Roo.BasicLayoutRegion
29683 * This class represents a region in a layout manager.
29684 * @cfg {Boolean} collapsible False to disable collapsing (defaults to true)
29685 * @cfg {Boolean} collapsed True to set the initial display to collapsed (defaults to false)
29686 * @cfg {Boolean} floatable False to disable floating (defaults to true)
29687 * @cfg {Object} margins Margins for the element (defaults to {top: 0, left: 0, right:0, bottom: 0})
29688 * @cfg {Object} cmargins Margins for the element when collapsed (defaults to: north/south {top: 2, left: 0, right:0, bottom: 2} or east/west {top: 0, left: 2, right:2, bottom: 0})
29689 * @cfg {String} tabPosition "top" or "bottom" (defaults to "bottom")
29690 * @cfg {String} collapsedTitle Optional string message to display in the collapsed block of a north or south region
29691 * @cfg {Boolean} alwaysShowTabs True to always display tabs even when there is only 1 panel (defaults to false)
29692 * @cfg {Boolean} autoScroll True to enable overflow scrolling (defaults to false)
29693 * @cfg {Boolean} titlebar True to display a title bar (defaults to true)
29694 * @cfg {String} title The title for the region (overrides panel titles)
29695 * @cfg {Boolean} animate True to animate expand/collapse (defaults to false)
29696 * @cfg {Boolean} autoHide False to disable auto hiding when the mouse leaves the "floated" region (defaults to true)
29697 * @cfg {Boolean} preservePanels True to preserve removed panels so they can be readded later (defaults to false)
29698 * @cfg {Boolean} closeOnTab True to place the close icon on the tabs instead of the region titlebar (defaults to false)
29699 * @cfg {Boolean} hideTabs True to hide the tab strip (defaults to false)
29700 * @cfg {Boolean} resizeTabs True to enable automatic tab resizing. This will resize the tabs so they are all the same size and fit within
29701 * the space available, similar to FireFox 1.5 tabs (defaults to false)
29702 * @cfg {Number} minTabWidth The minimum tab width (defaults to 40)
29703 * @cfg {Number} preferredTabWidth The preferred tab width (defaults to 150)
29704 * @cfg {Boolean} showPin True to show a pin button
29705 * @cfg {Boolean} hidden True to start the region hidden (defaults to false)
29706 * @cfg {Boolean} hideWhenEmpty True to hide the region when it has no panels
29707 * @cfg {Boolean} disableTabTips True to disable tab tooltips
29708 * @cfg {Number} width For East/West panels
29709 * @cfg {Number} height For North/South panels
29710 * @cfg {Boolean} split To show the splitter
29712 Roo.LayoutRegion = function(mgr, config, pos){
29713 Roo.LayoutRegion.superclass.constructor.call(this, mgr, config, pos, true);
29714 var dh = Roo.DomHelper;
29715 /** This region's container element
29716 * @type Roo.Element */
29717 this.el = dh.append(mgr.el.dom, {tag: "div", cls: "x-layout-panel x-layout-panel-" + this.position}, true);
29718 /** This region's title element
29719 * @type Roo.Element */
29721 this.titleEl = dh.append(this.el.dom, {tag: "div", unselectable: "on", cls: "x-unselectable x-layout-panel-hd x-layout-title-"+this.position, children:[
29722 {tag: "span", cls: "x-unselectable x-layout-panel-hd-text", unselectable: "on", html: " "},
29723 {tag: "div", cls: "x-unselectable x-layout-panel-hd-tools", unselectable: "on"}
29725 this.titleEl.enableDisplayMode();
29726 /** This region's title text element
29727 * @type HTMLElement */
29728 this.titleTextEl = this.titleEl.dom.firstChild;
29729 this.tools = Roo.get(this.titleEl.dom.childNodes[1], true);
29730 this.closeBtn = this.createTool(this.tools.dom, "x-layout-close");
29731 this.closeBtn.enableDisplayMode();
29732 this.closeBtn.on("click", this.closeClicked, this);
29733 this.closeBtn.hide();
29735 this.createBody(config);
29736 this.visible = true;
29737 this.collapsed = false;
29739 if(config.hideWhenEmpty){
29741 this.on("paneladded", this.validateVisibility, this);
29742 this.on("panelremoved", this.validateVisibility, this);
29744 this.applyConfig(config);
29747 Roo.extend(Roo.LayoutRegion, Roo.BasicLayoutRegion, {
29749 createBody : function(){
29750 /** This region's body element
29751 * @type Roo.Element */
29752 this.bodyEl = this.el.createChild({tag: "div", cls: "x-layout-panel-body"});
29755 applyConfig : function(c){
29756 if(c.collapsible && this.position != "center" && !this.collapsedEl){
29757 var dh = Roo.DomHelper;
29758 if(c.titlebar !== false){
29759 this.collapseBtn = this.createTool(this.tools.dom, "x-layout-collapse-"+this.position);
29760 this.collapseBtn.on("click", this.collapse, this);
29761 this.collapseBtn.enableDisplayMode();
29763 if(c.showPin === true || this.showPin){
29764 this.stickBtn = this.createTool(this.tools.dom, "x-layout-stick");
29765 this.stickBtn.enableDisplayMode();
29766 this.stickBtn.on("click", this.expand, this);
29767 this.stickBtn.hide();
29770 /** This region's collapsed element
29771 * @type Roo.Element */
29772 this.collapsedEl = dh.append(this.mgr.el.dom, {cls: "x-layout-collapsed x-layout-collapsed-"+this.position, children:[
29773 {cls: "x-layout-collapsed-tools", children:[{cls: "x-layout-ctools-inner"}]}
29775 if(c.floatable !== false){
29776 this.collapsedEl.addClassOnOver("x-layout-collapsed-over");
29777 this.collapsedEl.on("click", this.collapseClick, this);
29780 if(c.collapsedTitle && (this.position == "north" || this.position== "south")) {
29781 this.collapsedTitleTextEl = dh.append(this.collapsedEl.dom, {tag: "div", cls: "x-unselectable x-layout-panel-hd-text",
29782 id: "message", unselectable: "on", style:{"float":"left"}});
29783 this.collapsedTitleTextEl.innerHTML = c.collapsedTitle;
29785 this.expandBtn = this.createTool(this.collapsedEl.dom.firstChild.firstChild, "x-layout-expand-"+this.position);
29786 this.expandBtn.on("click", this.expand, this);
29788 if(this.collapseBtn){
29789 this.collapseBtn.setVisible(c.collapsible == true);
29791 this.cmargins = c.cmargins || this.cmargins ||
29792 (this.position == "west" || this.position == "east" ?
29793 {top: 0, left: 2, right:2, bottom: 0} :
29794 {top: 2, left: 0, right:0, bottom: 2});
29795 this.margins = c.margins || this.margins || {top: 0, left: 0, right:0, bottom: 0};
29796 this.bottomTabs = c.tabPosition != "top";
29797 this.autoScroll = c.autoScroll || false;
29798 if(this.autoScroll){
29799 this.bodyEl.setStyle("overflow", "auto");
29801 this.bodyEl.setStyle("overflow", "hidden");
29803 //if(c.titlebar !== false){
29804 if((!c.titlebar && !c.title) || c.titlebar === false){
29805 this.titleEl.hide();
29807 this.titleEl.show();
29809 this.titleTextEl.innerHTML = c.title;
29813 this.duration = c.duration || .30;
29814 this.slideDuration = c.slideDuration || .45;
29817 this.collapse(true);
29824 * Returns true if this region is currently visible.
29825 * @return {Boolean}
29827 isVisible : function(){
29828 return this.visible;
29832 * Updates the title for collapsed north/south regions (used with {@link #collapsedTitle} config option)
29833 * @param {String} title (optional) The title text (accepts HTML markup, defaults to the numeric character reference for a non-breaking space, "&#160;")
29835 setCollapsedTitle : function(title){
29836 title = title || " ";
29837 if(this.collapsedTitleTextEl){
29838 this.collapsedTitleTextEl.innerHTML = title;
29842 getBox : function(){
29844 if(!this.collapsed){
29845 b = this.el.getBox(false, true);
29847 b = this.collapsedEl.getBox(false, true);
29852 getMargins : function(){
29853 return this.collapsed ? this.cmargins : this.margins;
29856 highlight : function(){
29857 this.el.addClass("x-layout-panel-dragover");
29860 unhighlight : function(){
29861 this.el.removeClass("x-layout-panel-dragover");
29864 updateBox : function(box){
29866 if(!this.collapsed){
29867 this.el.dom.style.left = box.x + "px";
29868 this.el.dom.style.top = box.y + "px";
29869 this.updateBody(box.width, box.height);
29871 this.collapsedEl.dom.style.left = box.x + "px";
29872 this.collapsedEl.dom.style.top = box.y + "px";
29873 this.collapsedEl.setSize(box.width, box.height);
29876 this.tabs.autoSizeTabs();
29880 updateBody : function(w, h){
29882 this.el.setWidth(w);
29883 w -= this.el.getBorderWidth("rl");
29884 if(this.config.adjustments){
29885 w += this.config.adjustments[0];
29889 this.el.setHeight(h);
29890 h = this.titleEl && this.titleEl.isDisplayed() ? h - (this.titleEl.getHeight()||0) : h;
29891 h -= this.el.getBorderWidth("tb");
29892 if(this.config.adjustments){
29893 h += this.config.adjustments[1];
29895 this.bodyEl.setHeight(h);
29897 h = this.tabs.syncHeight(h);
29900 if(this.panelSize){
29901 w = w !== null ? w : this.panelSize.width;
29902 h = h !== null ? h : this.panelSize.height;
29904 if(this.activePanel){
29905 var el = this.activePanel.getEl();
29906 w = w !== null ? w : el.getWidth();
29907 h = h !== null ? h : el.getHeight();
29908 this.panelSize = {width: w, height: h};
29909 this.activePanel.setSize(w, h);
29911 if(Roo.isIE && this.tabs){
29912 this.tabs.el.repaint();
29917 * Returns the container element for this region.
29918 * @return {Roo.Element}
29920 getEl : function(){
29925 * Hides this region.
29928 if(!this.collapsed){
29929 this.el.dom.style.left = "-2000px";
29932 this.collapsedEl.dom.style.left = "-2000px";
29933 this.collapsedEl.hide();
29935 this.visible = false;
29936 this.fireEvent("visibilitychange", this, false);
29940 * Shows this region if it was previously hidden.
29943 if(!this.collapsed){
29946 this.collapsedEl.show();
29948 this.visible = true;
29949 this.fireEvent("visibilitychange", this, true);
29952 closeClicked : function(){
29953 if(this.activePanel){
29954 this.remove(this.activePanel);
29958 collapseClick : function(e){
29960 e.stopPropagation();
29963 e.stopPropagation();
29969 * Collapses this region.
29970 * @param {Boolean} skipAnim (optional) true to collapse the element without animation (if animate is true)
29972 collapse : function(skipAnim){
29973 if(this.collapsed) return;
29974 this.collapsed = true;
29976 this.split.el.hide();
29978 if(this.config.animate && skipAnim !== true){
29979 this.fireEvent("invalidated", this);
29980 this.animateCollapse();
29982 this.el.setLocation(-20000,-20000);
29984 this.collapsedEl.show();
29985 this.fireEvent("collapsed", this);
29986 this.fireEvent("invalidated", this);
29990 animateCollapse : function(){
29995 * Expands this region if it was previously collapsed.
29996 * @param {Roo.EventObject} e The event that triggered the expand (or null if calling manually)
29997 * @param {Boolean} skipAnim (optional) true to expand the element without animation (if animate is true)
29999 expand : function(e, skipAnim){
30000 if(e) e.stopPropagation();
30001 if(!this.collapsed || this.el.hasActiveFx()) return;
30003 this.afterSlideIn();
30006 this.collapsed = false;
30007 if(this.config.animate && skipAnim !== true){
30008 this.animateExpand();
30012 this.split.el.show();
30014 this.collapsedEl.setLocation(-2000,-2000);
30015 this.collapsedEl.hide();
30016 this.fireEvent("invalidated", this);
30017 this.fireEvent("expanded", this);
30021 animateExpand : function(){
30025 initTabs : function(){
30026 this.bodyEl.setStyle("overflow", "hidden");
30027 var ts = new Roo.TabPanel(this.bodyEl.dom, {
30028 tabPosition: this.bottomTabs ? 'bottom' : 'top',
30029 disableTooltips: this.config.disableTabTips
30031 if(this.config.hideTabs){
30032 ts.stripWrap.setDisplayed(false);
30035 ts.resizeTabs = this.config.resizeTabs === true;
30036 ts.minTabWidth = this.config.minTabWidth || 40;
30037 ts.maxTabWidth = this.config.maxTabWidth || 250;
30038 ts.preferredTabWidth = this.config.preferredTabWidth || 150;
30039 ts.monitorResize = false;
30040 ts.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30041 ts.bodyEl.addClass('x-layout-tabs-body');
30042 this.panels.each(this.initPanelAsTab, this);
30045 initPanelAsTab : function(panel){
30046 var ti = this.tabs.addTab(panel.getEl().id, panel.getTitle(), null,
30047 this.config.closeOnTab && panel.isClosable());
30048 if(panel.tabTip !== undefined){
30049 ti.setTooltip(panel.tabTip);
30051 ti.on("activate", function(){
30052 this.setActivePanel(panel);
30054 if(this.config.closeOnTab){
30055 ti.on("beforeclose", function(t, e){
30057 this.remove(panel);
30063 updatePanelTitle : function(panel, title){
30064 if(this.activePanel == panel){
30065 this.updateTitle(title);
30068 var ti = this.tabs.getTab(panel.getEl().id);
30070 if(panel.tabTip !== undefined){
30071 ti.setTooltip(panel.tabTip);
30076 updateTitle : function(title){
30077 if(this.titleTextEl && !this.config.title){
30078 this.titleTextEl.innerHTML = (typeof title != "undefined" && title.length > 0 ? title : " ");
30082 setActivePanel : function(panel){
30083 panel = this.getPanel(panel);
30084 if(this.activePanel && this.activePanel != panel){
30085 this.activePanel.setActiveState(false);
30087 this.activePanel = panel;
30088 panel.setActiveState(true);
30089 if(this.panelSize){
30090 panel.setSize(this.panelSize.width, this.panelSize.height);
30093 this.closeBtn.setVisible(!this.config.closeOnTab && !this.isSlid && panel.isClosable());
30095 this.updateTitle(panel.getTitle());
30097 this.fireEvent("invalidated", this);
30099 this.fireEvent("panelactivated", this, panel);
30103 * Shows the specified panel.
30104 * @param {Number/String/ContentPanel} panelId The panel's index, id or the panel itself
30105 * @return {Roo.ContentPanel} The shown panel, or null if a panel could not be found from panelId
30107 showPanel : function(panel){
30108 if(panel = this.getPanel(panel)){
30110 var tab = this.tabs.getTab(panel.getEl().id);
30111 if(tab.isHidden()){
30112 this.tabs.unhideTab(tab.id);
30116 this.setActivePanel(panel);
30123 * Get the active panel for this region.
30124 * @return {Roo.ContentPanel} The active panel or null
30126 getActivePanel : function(){
30127 return this.activePanel;
30130 validateVisibility : function(){
30131 if(this.panels.getCount() < 1){
30132 this.updateTitle(" ");
30133 this.closeBtn.hide();
30136 if(!this.isVisible()){
30143 * Adds the passed ContentPanel(s) to this region.
30144 * @param {ContentPanel...} panel The ContentPanel(s) to add (you can pass more than one)
30145 * @return {Roo.ContentPanel} The panel added (if only one was added; null otherwise)
30147 add : function(panel){
30148 if(arguments.length > 1){
30149 for(var i = 0, len = arguments.length; i < len; i++) {
30150 this.add(arguments[i]);
30154 if(this.hasPanel(panel)){
30155 this.showPanel(panel);
30158 panel.setRegion(this);
30159 this.panels.add(panel);
30160 if(this.panels.getCount() == 1 && !this.config.alwaysShowTabs){
30161 this.bodyEl.dom.appendChild(panel.getEl().dom);
30162 if(panel.background !== true){
30163 this.setActivePanel(panel);
30165 this.fireEvent("paneladded", this, panel);
30171 this.initPanelAsTab(panel);
30173 if(panel.background !== true){
30174 this.tabs.activate(panel.getEl().id);
30176 this.fireEvent("paneladded", this, panel);
30181 * Hides the tab for the specified panel.
30182 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30184 hidePanel : function(panel){
30185 if(this.tabs && (panel = this.getPanel(panel))){
30186 this.tabs.hideTab(panel.getEl().id);
30191 * Unhides the tab for a previously hidden panel.
30192 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30194 unhidePanel : function(panel){
30195 if(this.tabs && (panel = this.getPanel(panel))){
30196 this.tabs.unhideTab(panel.getEl().id);
30200 clearPanels : function(){
30201 while(this.panels.getCount() > 0){
30202 this.remove(this.panels.first());
30207 * Removes the specified panel. If preservePanel is not true (either here or in the config), the panel is destroyed.
30208 * @param {Number/String/ContentPanel} panel The panel's index, id or the panel itself
30209 * @param {Boolean} preservePanel Overrides the config preservePanel option
30210 * @return {Roo.ContentPanel} The panel that was removed
30212 remove : function(panel, preservePanel){
30213 panel = this.getPanel(panel);
30218 this.fireEvent("beforeremove", this, panel, e);
30219 if(e.cancel === true){
30222 preservePanel = (typeof preservePanel != "undefined" ? preservePanel : (this.config.preservePanels === true || panel.preserve === true));
30223 var panelId = panel.getId();
30224 this.panels.removeKey(panelId);
30226 document.body.appendChild(panel.getEl().dom);
30229 this.tabs.removeTab(panel.getEl().id);
30230 }else if (!preservePanel){
30231 this.bodyEl.dom.removeChild(panel.getEl().dom);
30233 if(this.panels.getCount() == 1 && this.tabs && !this.config.alwaysShowTabs){
30234 var p = this.panels.first();
30235 var tempEl = document.createElement("div"); // temp holder to keep IE from deleting the node
30236 tempEl.appendChild(p.getEl().dom);
30237 this.bodyEl.update("");
30238 this.bodyEl.dom.appendChild(p.getEl().dom);
30240 this.updateTitle(p.getTitle());
30242 this.bodyEl.setStyle("overflow", this.config.autoScroll ? "auto" : "hidden");
30243 this.setActivePanel(p);
30245 panel.setRegion(null);
30246 if(this.activePanel == panel){
30247 this.activePanel = null;
30249 if(this.config.autoDestroy !== false && preservePanel !== true){
30250 try{panel.destroy();}catch(e){}
30252 this.fireEvent("panelremoved", this, panel);
30257 * Returns the TabPanel component used by this region
30258 * @return {Roo.TabPanel}
30260 getTabs : function(){
30264 createTool : function(parentEl, className){
30265 var btn = Roo.DomHelper.append(parentEl, {tag: "div", cls: "x-layout-tools-button",
30266 children: [{tag: "div", cls: "x-layout-tools-button-inner " + className, html: " "}]}, true);
30267 btn.addClassOnOver("x-layout-tools-button-over");