4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
75 if (config.listeners || config.events) {
76 Roo.BasicLayoutRegion.superclass.constructor.call(this, {
77 listeners : config.listeners || {},
78 events : config.events || {}
83 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
86 * The id of the element associated with this object. This is what we
87 * refer to as the "linked element" because the size and position of
88 * this element is used to determine when the drag and drop objects have
96 * Configuration attributes passed into the constructor
103 * The id of the element that will be dragged. By default this is same
104 * as the linked element , but could be changed to another element. Ex:
113 * the id of the element that initiates the drag operation. By default
114 * this is the linked element, but could be changed to be a child of this
115 * element. This lets us do things like only starting the drag when the
116 * header element within the linked html element is clicked.
117 * @property handleElId
124 * An associative array of HTML tags that will be ignored if clicked.
125 * @property invalidHandleTypes
126 * @type {string: string}
128 invalidHandleTypes: null,
131 * An associative array of ids for elements that will be ignored if clicked
132 * @property invalidHandleIds
133 * @type {string: string}
135 invalidHandleIds: null,
138 * An indexted array of css class names for elements that will be ignored
140 * @property invalidHandleClasses
143 invalidHandleClasses: null,
146 * The linked element's absolute X position at the time the drag was
148 * @property startPageX
155 * The linked element's absolute X position at the time the drag was
157 * @property startPageY
164 * The group defines a logical collection of DragDrop objects that are
165 * related. Instances only get events when interacting with other
166 * DragDrop object in the same group. This lets us define multiple
167 * groups using a single DragDrop subclass if we want.
169 * @type {string: string}
174 * Individual drag/drop instances can be locked. This will prevent
175 * onmousedown start drag.
186 lock: function() { this.locked = true; },
189 * Unlock this instace
192 unlock: function() { this.locked = false; },
195 * By default, all insances can be a drop target. This can be disabled by
196 * setting isTarget to false.
203 * The padding configured for this drag and drop object for calculating
204 * the drop zone intersection with this object.
211 * Cached reference to the linked element
218 * Internal typeof flag
219 * @property __ygDragDrop
225 * Set to true when horizontal contraints are applied
226 * @property constrainX
233 * Set to true when vertical contraints are applied
234 * @property constrainY
241 * The left constraint
249 * The right constraint
266 * The down constraint
274 * Maintain offsets when we resetconstraints. Set to true when you want
275 * the position of the element relative to its parent to stay the same
276 * when the page changes
278 * @property maintainOffset
281 maintainOffset: false,
284 * Array of pixel locations the element will snap to if we specified a
285 * horizontal graduation/interval. This array is generated automatically
286 * when you define a tick interval.
293 * Array of pixel locations the element will snap to if we specified a
294 * vertical graduation/interval. This array is generated automatically
295 * when you define a tick interval.
302 * By default the drag and drop instance will only respond to the primary
303 * button click (left button for a right-handed mouse). Set to true to
304 * allow drag and drop to start with any mouse click that is propogated
306 * @property primaryButtonOnly
309 primaryButtonOnly: true,
312 * The availabe property is false until the linked dom element is accessible.
313 * @property available
319 * By default, drags can only be initiated if the mousedown occurs in the
320 * region the linked element is. This is done in part to work around a
321 * bug in some browsers that mis-report the mousedown if the previous
322 * mouseup happened outside of the window. This property is set to true
323 * if outer handles are defined.
325 * @property hasOuterHandles
329 hasOuterHandles: false,
332 * Code that executes immediately before the startDrag event
333 * @method b4StartDrag
336 b4StartDrag: function(x, y) { },
339 * Abstract method called after a drag/drop object is clicked
340 * and the drag or mousedown time thresholds have beeen met.
342 * @param {int} X click location
343 * @param {int} Y click location
345 startDrag: function(x, y) { /* override this */ },
348 * Code that executes immediately before the onDrag event
352 b4Drag: function(e) { },
355 * Abstract method called during the onMouseMove event while dragging an
358 * @param {Event} e the mousemove event
360 onDrag: function(e) { /* override this */ },
363 * Abstract method called when this element fist begins hovering over
364 * another DragDrop obj
365 * @method onDragEnter
366 * @param {Event} e the mousemove event
367 * @param {String|DragDrop[]} id In POINT mode, the element
368 * id this is hovering over. In INTERSECT mode, an array of one or more
369 * dragdrop items being hovered over.
371 onDragEnter: function(e, id) { /* override this */ },
374 * Code that executes immediately before the onDragOver event
378 b4DragOver: function(e) { },
381 * Abstract method called when this element is hovering over another
384 * @param {Event} e the mousemove event
385 * @param {String|DragDrop[]} id In POINT mode, the element
386 * id this is hovering over. In INTERSECT mode, an array of dd items
387 * being hovered over.
389 onDragOver: function(e, id) { /* override this */ },
392 * Code that executes immediately before the onDragOut event
396 b4DragOut: function(e) { },
399 * Abstract method called when we are no longer hovering over an element
401 * @param {Event} e the mousemove event
402 * @param {String|DragDrop[]} id In POINT mode, the element
403 * id this was hovering over. In INTERSECT mode, an array of dd items
404 * that the mouse is no longer over.
406 onDragOut: function(e, id) { /* override this */ },
409 * Code that executes immediately before the onDragDrop event
413 b4DragDrop: function(e) { },
416 * Abstract method called when this item is dropped on another DragDrop
419 * @param {Event} e the mouseup event
420 * @param {String|DragDrop[]} id In POINT mode, the element
421 * id this was dropped on. In INTERSECT mode, an array of dd items this
424 onDragDrop: function(e, id) { /* override this */ },
427 * Abstract method called when this item is dropped on an area with no
429 * @method onInvalidDrop
430 * @param {Event} e the mouseup event
432 onInvalidDrop: function(e) { /* override this */ },
435 * Code that executes immediately before the endDrag event
439 b4EndDrag: function(e) { },
442 * Fired when we are done dragging the object
444 * @param {Event} e the mouseup event
446 endDrag: function(e) { /* override this */ },
449 * Code executed immediately before the onMouseDown event
450 * @method b4MouseDown
451 * @param {Event} e the mousedown event
454 b4MouseDown: function(e) { },
457 * Event handler that fires when a drag/drop obj gets a mousedown
458 * @method onMouseDown
459 * @param {Event} e the mousedown event
461 onMouseDown: function(e) { /* override this */ },
464 * Event handler that fires when a drag/drop obj gets a mouseup
466 * @param {Event} e the mouseup event
468 onMouseUp: function(e) { /* override this */ },
471 * Override the onAvailable method to do what is needed after the initial
472 * position was determined.
473 * @method onAvailable
475 onAvailable: function () {
479 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
482 defaultPadding : {left:0, right:0, top:0, bottom:0},
485 * Initializes the drag drop object's constraints to restrict movement to a certain element.
489 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
490 { dragElId: "existingProxyDiv" });
491 dd.startDrag = function(){
492 this.constrainTo("parent-id");
495 * Or you can initalize it using the {@link Roo.Element} object:
497 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
498 startDrag : function(){
499 this.constrainTo("parent-id");
503 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
504 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
505 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
506 * an object containing the sides to pad. For example: {right:10, bottom:10}
507 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
509 constrainTo : function(constrainTo, pad, inContent){
510 if(typeof pad == "number"){
511 pad = {left: pad, right:pad, top:pad, bottom:pad};
513 pad = pad || this.defaultPadding;
514 var b = Roo.get(this.getEl()).getBox();
515 var ce = Roo.get(constrainTo);
516 var s = ce.getScroll();
518 if(cd == document.body){
519 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
522 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
526 var topSpace = b.y - c.y;
527 var leftSpace = b.x - c.x;
529 this.resetConstraints();
530 this.setXConstraint(leftSpace - (pad.left||0), // left
531 c.width - leftSpace - b.width - (pad.right||0) //right
533 this.setYConstraint(topSpace - (pad.top||0), //top
534 c.height - topSpace - b.height - (pad.bottom||0) //bottom
539 * Returns a reference to the linked element
541 * @return {HTMLElement} the html element
545 this._domRef = Roo.getDom(this.id);
552 * Returns a reference to the actual element to drag. By default this is
553 * the same as the html element, but it can be assigned to another
554 * element. An example of this can be found in Roo.dd.DDProxy
556 * @return {HTMLElement} the html element
558 getDragEl: function() {
559 return Roo.getDom(this.dragElId);
563 * Sets up the DragDrop object. Must be called in the constructor of any
564 * Roo.dd.DragDrop subclass
566 * @param id the id of the linked element
567 * @param {String} sGroup the group of related items
568 * @param {object} config configuration attributes
570 init: function(id, sGroup, config) {
571 this.initTarget(id, sGroup, config);
572 Event.on(this.id, "mousedown", this.handleMouseDown, this);
573 // Event.on(this.id, "selectstart", Event.preventDefault);
577 * Initializes Targeting functionality only... the object does not
578 * get a mousedown handler.
580 * @param id the id of the linked element
581 * @param {String} sGroup the group of related items
582 * @param {object} config configuration attributes
584 initTarget: function(id, sGroup, config) {
586 // configuration attributes
587 this.config = config || {};
589 // create a local reference to the drag and drop manager
590 this.DDM = Roo.dd.DDM;
591 // initialize the groups array
594 // assume that we have an element reference instead of an id if the
595 // parameter is not a string
596 if (typeof id !== "string") {
603 // add to an interaction group
604 this.addToGroup((sGroup) ? sGroup : "default");
606 // We don't want to register this as the handle with the manager
607 // so we just set the id rather than calling the setter.
608 this.handleElId = id;
610 // the linked element is the element that gets dragged by default
611 this.setDragElId(id);
613 // by default, clicked anchors will not start drag operations.
614 this.invalidHandleTypes = { A: "A" };
615 this.invalidHandleIds = {};
616 this.invalidHandleClasses = [];
620 this.handleOnAvailable();
624 * Applies the configuration parameters that were passed into the constructor.
625 * This is supposed to happen at each level through the inheritance chain. So
626 * a DDProxy implentation will execute apply config on DDProxy, DD, and
627 * DragDrop in order to get all of the parameters that are available in
629 * @method applyConfig
631 applyConfig: function() {
633 // configurable properties:
634 // padding, isTarget, maintainOffset, primaryButtonOnly
635 this.padding = this.config.padding || [0, 0, 0, 0];
636 this.isTarget = (this.config.isTarget !== false);
637 this.maintainOffset = (this.config.maintainOffset);
638 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
643 * Executed when the linked element is available
644 * @method handleOnAvailable
647 handleOnAvailable: function() {
648 this.available = true;
649 this.resetConstraints();
654 * Configures the padding for the target zone in px. Effectively expands
655 * (or reduces) the virtual object size for targeting calculations.
656 * Supports css-style shorthand; if only one parameter is passed, all sides
657 * will have that padding, and if only two are passed, the top and bottom
658 * will have the first param, the left and right the second.
660 * @param {int} iTop Top pad
661 * @param {int} iRight Right pad
662 * @param {int} iBot Bot pad
663 * @param {int} iLeft Left pad
665 setPadding: function(iTop, iRight, iBot, iLeft) {
666 // this.padding = [iLeft, iRight, iTop, iBot];
667 if (!iRight && 0 !== iRight) {
668 this.padding = [iTop, iTop, iTop, iTop];
669 } else if (!iBot && 0 !== iBot) {
670 this.padding = [iTop, iRight, iTop, iRight];
672 this.padding = [iTop, iRight, iBot, iLeft];
677 * Stores the initial placement of the linked element.
678 * @method setInitialPosition
679 * @param {int} diffX the X offset, default 0
680 * @param {int} diffY the Y offset, default 0
682 setInitPosition: function(diffX, diffY) {
683 var el = this.getEl();
685 if (!this.DDM.verifyEl(el)) {
692 var p = Dom.getXY( el );
694 this.initPageX = p[0] - dx;
695 this.initPageY = p[1] - dy;
697 this.lastPageX = p[0];
698 this.lastPageY = p[1];
701 this.setStartPosition(p);
705 * Sets the start position of the element. This is set when the obj
706 * is initialized, the reset when a drag is started.
707 * @method setStartPosition
708 * @param pos current position (from previous lookup)
711 setStartPosition: function(pos) {
712 var p = pos || Dom.getXY( this.getEl() );
713 this.deltaSetXY = null;
715 this.startPageX = p[0];
716 this.startPageY = p[1];
720 * Add this instance to a group of related drag/drop objects. All
721 * instances belong to at least one group, and can belong to as many
724 * @param sGroup {string} the name of the group
726 addToGroup: function(sGroup) {
727 this.groups[sGroup] = true;
728 this.DDM.regDragDrop(this, sGroup);
732 * Remove's this instance from the supplied interaction group
733 * @method removeFromGroup
734 * @param {string} sGroup The group to drop
736 removeFromGroup: function(sGroup) {
737 if (this.groups[sGroup]) {
738 delete this.groups[sGroup];
741 this.DDM.removeDDFromGroup(this, sGroup);
745 * Allows you to specify that an element other than the linked element
746 * will be moved with the cursor during a drag
747 * @method setDragElId
748 * @param id {string} the id of the element that will be used to initiate the drag
750 setDragElId: function(id) {
755 * Allows you to specify a child of the linked element that should be
756 * used to initiate the drag operation. An example of this would be if
757 * you have a content div with text and links. Clicking anywhere in the
758 * content area would normally start the drag operation. Use this method
759 * to specify that an element inside of the content div is the element
760 * that starts the drag operation.
761 * @method setHandleElId
762 * @param id {string} the id of the element that will be used to
765 setHandleElId: function(id) {
766 if (typeof id !== "string") {
769 this.handleElId = id;
770 this.DDM.regHandle(this.id, id);
774 * Allows you to set an element outside of the linked element as a drag
776 * @method setOuterHandleElId
777 * @param id the id of the element that will be used to initiate the drag
779 setOuterHandleElId: function(id) {
780 if (typeof id !== "string") {
783 Event.on(id, "mousedown",
784 this.handleMouseDown, this);
785 this.setHandleElId(id);
787 this.hasOuterHandles = true;
791 * Remove all drag and drop hooks for this element
795 Event.un(this.id, "mousedown",
796 this.handleMouseDown);
798 this.DDM._remove(this);
801 destroy : function(){
806 * Returns true if this instance is locked, or the drag drop mgr is locked
807 * (meaning that all drag/drop is disabled on the page.)
809 * @return {boolean} true if this obj or all drag/drop is locked, else
812 isLocked: function() {
813 return (this.DDM.isLocked() || this.locked);
817 * Fired when this object is clicked
818 * @method handleMouseDown
820 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
823 handleMouseDown: function(e, oDD){
824 if (this.primaryButtonOnly && e.button != 0) {
828 if (this.isLocked()) {
832 this.DDM.refreshCache(this.groups);
834 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
835 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
837 if (this.clickValidator(e)) {
839 // set the initial element position
840 this.setStartPosition();
846 this.DDM.handleMouseDown(e, this);
848 this.DDM.stopEvent(e);
856 clickValidator: function(e) {
857 var target = e.getTarget();
858 return ( this.isValidHandleChild(target) &&
859 (this.id == this.handleElId ||
860 this.DDM.handleWasClicked(target, this.id)) );
864 * Allows you to specify a tag name that should not start a drag operation
865 * when clicked. This is designed to facilitate embedding links within a
866 * drag handle that do something other than start the drag.
867 * @method addInvalidHandleType
868 * @param {string} tagName the type of element to exclude
870 addInvalidHandleType: function(tagName) {
871 var type = tagName.toUpperCase();
872 this.invalidHandleTypes[type] = type;
876 * Lets you to specify an element id for a child of a drag handle
877 * that should not initiate a drag
878 * @method addInvalidHandleId
879 * @param {string} id the element id of the element you wish to ignore
881 addInvalidHandleId: function(id) {
882 if (typeof id !== "string") {
885 this.invalidHandleIds[id] = id;
889 * Lets you specify a css class of elements that will not initiate a drag
890 * @method addInvalidHandleClass
891 * @param {string} cssClass the class of the elements you wish to ignore
893 addInvalidHandleClass: function(cssClass) {
894 this.invalidHandleClasses.push(cssClass);
898 * Unsets an excluded tag name set by addInvalidHandleType
899 * @method removeInvalidHandleType
900 * @param {string} tagName the type of element to unexclude
902 removeInvalidHandleType: function(tagName) {
903 var type = tagName.toUpperCase();
904 // this.invalidHandleTypes[type] = null;
905 delete this.invalidHandleTypes[type];
909 * Unsets an invalid handle id
910 * @method removeInvalidHandleId
911 * @param {string} id the id of the element to re-enable
913 removeInvalidHandleId: function(id) {
914 if (typeof id !== "string") {
917 delete this.invalidHandleIds[id];
921 * Unsets an invalid css class
922 * @method removeInvalidHandleClass
923 * @param {string} cssClass the class of the element(s) you wish to
926 removeInvalidHandleClass: function(cssClass) {
927 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
928 if (this.invalidHandleClasses[i] == cssClass) {
929 delete this.invalidHandleClasses[i];
935 * Checks the tag exclusion list to see if this click should be ignored
936 * @method isValidHandleChild
937 * @param {HTMLElement} node the HTMLElement to evaluate
938 * @return {boolean} true if this is a valid tag type, false if not
940 isValidHandleChild: function(node) {
943 // var n = (node.nodeName == "#text") ? node.parentNode : node;
946 nodeName = node.nodeName.toUpperCase();
948 nodeName = node.nodeName;
950 valid = valid && !this.invalidHandleTypes[nodeName];
951 valid = valid && !this.invalidHandleIds[node.id];
953 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
954 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
963 * Create the array of horizontal tick marks if an interval was specified
964 * in setXConstraint().
968 setXTicks: function(iStartX, iTickSize) {
970 this.xTickSize = iTickSize;
974 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
976 this.xTicks[this.xTicks.length] = i;
981 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
983 this.xTicks[this.xTicks.length] = i;
988 this.xTicks.sort(this.DDM.numericSort) ;
992 * Create the array of vertical tick marks if an interval was specified in
997 setYTicks: function(iStartY, iTickSize) {
999 this.yTickSize = iTickSize;
1003 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1005 this.yTicks[this.yTicks.length] = i;
1010 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1012 this.yTicks[this.yTicks.length] = i;
1017 this.yTicks.sort(this.DDM.numericSort) ;
1021 * By default, the element can be dragged any place on the screen. Use
1022 * this method to limit the horizontal travel of the element. Pass in
1023 * 0,0 for the parameters if you want to lock the drag to the y axis.
1024 * @method setXConstraint
1025 * @param {int} iLeft the number of pixels the element can move to the left
1026 * @param {int} iRight the number of pixels the element can move to the
1028 * @param {int} iTickSize optional parameter for specifying that the
1030 * should move iTickSize pixels at a time.
1032 setXConstraint: function(iLeft, iRight, iTickSize) {
1033 this.leftConstraint = iLeft;
1034 this.rightConstraint = iRight;
1036 this.minX = this.initPageX - iLeft;
1037 this.maxX = this.initPageX + iRight;
1038 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1040 this.constrainX = true;
1044 * Clears any constraints applied to this instance. Also clears ticks
1045 * since they can't exist independent of a constraint at this time.
1046 * @method clearConstraints
1048 clearConstraints: function() {
1049 this.constrainX = false;
1050 this.constrainY = false;
1055 * Clears any tick interval defined for this instance
1056 * @method clearTicks
1058 clearTicks: function() {
1066 * By default, the element can be dragged any place on the screen. Set
1067 * this to limit the vertical travel of the element. Pass in 0,0 for the
1068 * parameters if you want to lock the drag to the x axis.
1069 * @method setYConstraint
1070 * @param {int} iUp the number of pixels the element can move up
1071 * @param {int} iDown the number of pixels the element can move down
1072 * @param {int} iTickSize optional parameter for specifying that the
1073 * element should move iTickSize pixels at a time.
1075 setYConstraint: function(iUp, iDown, iTickSize) {
1076 this.topConstraint = iUp;
1077 this.bottomConstraint = iDown;
1079 this.minY = this.initPageY - iUp;
1080 this.maxY = this.initPageY + iDown;
1081 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1083 this.constrainY = true;
1088 * resetConstraints must be called if you manually reposition a dd element.
1089 * @method resetConstraints
1090 * @param {boolean} maintainOffset
1092 resetConstraints: function() {
1095 // Maintain offsets if necessary
1096 if (this.initPageX || this.initPageX === 0) {
1097 // figure out how much this thing has moved
1098 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1099 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1101 this.setInitPosition(dx, dy);
1103 // This is the first time we have detected the element's position
1105 this.setInitPosition();
1108 if (this.constrainX) {
1109 this.setXConstraint( this.leftConstraint,
1110 this.rightConstraint,
1114 if (this.constrainY) {
1115 this.setYConstraint( this.topConstraint,
1116 this.bottomConstraint,
1122 * Normally the drag element is moved pixel by pixel, but we can specify
1123 * that it move a number of pixels at a time. This method resolves the
1124 * location when we have it set up like this.
1126 * @param {int} val where we want to place the object
1127 * @param {int[]} tickArray sorted array of valid points
1128 * @return {int} the closest tick
1131 getTick: function(val, tickArray) {
1134 // If tick interval is not defined, it is effectively 1 pixel,
1135 // so we return the value passed to us.
1137 } else if (tickArray[0] >= val) {
1138 // The value is lower than the first tick, so we return the first
1140 return tickArray[0];
1142 for (var i=0, len=tickArray.length; i<len; ++i) {
1144 if (tickArray[next] && tickArray[next] >= val) {
1145 var diff1 = val - tickArray[i];
1146 var diff2 = tickArray[next] - val;
1147 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1151 // The value is larger than the last tick, so we return the last
1153 return tickArray[tickArray.length - 1];
1160 * @return {string} string representation of the dd obj
1162 toString: function() {
1163 return ("DragDrop " + this.id);
1171 * Ext JS Library 1.1.1
1172 * Copyright(c) 2006-2007, Ext JS, LLC.
1174 * Originally Released Under LGPL - original licence link has changed is not relivant.
1177 * <script type="text/javascript">
1182 * The drag and drop utility provides a framework for building drag and drop
1183 * applications. In addition to enabling drag and drop for specific elements,
1184 * the drag and drop elements are tracked by the manager class, and the
1185 * interactions between the various elements are tracked during the drag and
1186 * the implementing code is notified about these important moments.
1189 // Only load the library once. Rewriting the manager class would orphan
1190 // existing drag and drop instances.
1191 if (!Roo.dd.DragDropMgr) {
1194 * @class Roo.dd.DragDropMgr
1195 * DragDropMgr is a singleton that tracks the element interaction for
1196 * all DragDrop items in the window. Generally, you will not call
1197 * this class directly, but it does have helper methods that could
1198 * be useful in your DragDrop implementations.
1201 Roo.dd.DragDropMgr = function() {
1203 var Event = Roo.EventManager;
1208 * Two dimensional Array of registered DragDrop objects. The first
1209 * dimension is the DragDrop item group, the second the DragDrop
1212 * @type {string: string}
1219 * Array of element ids defined as drag handles. Used to determine
1220 * if the element that generated the mousedown event is actually the
1221 * handle and not the html element itself.
1222 * @property handleIds
1223 * @type {string: string}
1230 * the DragDrop object that is currently being dragged
1231 * @property dragCurrent
1239 * the DragDrop object(s) that are being hovered over
1240 * @property dragOvers
1248 * the X distance between the cursor and the object being dragged
1257 * the Y distance between the cursor and the object being dragged
1266 * Flag to determine if we should prevent the default behavior of the
1267 * events we define. By default this is true, but this can be set to
1268 * false if you need the default behavior (not recommended)
1269 * @property preventDefault
1273 preventDefault: true,
1276 * Flag to determine if we should stop the propagation of the events
1277 * we generate. This is true by default but you may want to set it to
1278 * false if the html element contains other features that require the
1280 * @property stopPropagation
1284 stopPropagation: true,
1287 * Internal flag that is set to true when drag and drop has been
1289 * @property initialized
1296 * All drag and drop can be disabled.
1304 * Called the first time an element is registered.
1310 this.initialized = true;
1314 * In point mode, drag and drop interaction is defined by the
1315 * location of the cursor during the drag/drop
1323 * In intersect mode, drag and drop interactio nis defined by the
1324 * overlap of two or more drag and drop objects.
1325 * @property INTERSECT
1332 * The current drag and drop mode. Default: POINT
1340 * Runs method on all drag and drop objects
1341 * @method _execOnAll
1345 _execOnAll: function(sMethod, args) {
1346 for (var i in this.ids) {
1347 for (var j in this.ids[i]) {
1348 var oDD = this.ids[i][j];
1349 if (! this.isTypeOfDD(oDD)) {
1352 oDD[sMethod].apply(oDD, args);
1358 * Drag and drop initialization. Sets up the global event handlers
1363 _onLoad: function() {
1368 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1369 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1370 Event.on(window, "unload", this._onUnload, this, true);
1371 Event.on(window, "resize", this._onResize, this, true);
1372 // Event.on(window, "mouseout", this._test);
1377 * Reset constraints on all drag and drop objs
1382 _onResize: function(e) {
1383 this._execOnAll("resetConstraints", []);
1387 * Lock all drag and drop functionality
1391 lock: function() { this.locked = true; },
1394 * Unlock all drag and drop functionality
1398 unlock: function() { this.locked = false; },
1401 * Is drag and drop locked?
1403 * @return {boolean} True if drag and drop is locked, false otherwise.
1406 isLocked: function() { return this.locked; },
1409 * Location cache that is set for all drag drop objects when a drag is
1410 * initiated, cleared when the drag is finished.
1411 * @property locationCache
1418 * Set useCache to false if you want to force object the lookup of each
1419 * drag and drop linked element constantly during a drag.
1420 * @property useCache
1427 * The number of pixels that the mouse needs to move after the
1428 * mousedown before the drag is initiated. Default=3;
1429 * @property clickPixelThresh
1433 clickPixelThresh: 3,
1436 * The number of milliseconds after the mousedown event to initiate the
1437 * drag if we don't get a mouseup event. Default=1000
1438 * @property clickTimeThresh
1442 clickTimeThresh: 350,
1445 * Flag that indicates that either the drag pixel threshold or the
1446 * mousdown time threshold has been met
1447 * @property dragThreshMet
1452 dragThreshMet: false,
1455 * Timeout used for the click time threshold
1456 * @property clickTimeout
1464 * The X position of the mousedown event stored for later use when a
1465 * drag threshold is met.
1474 * The Y position of the mousedown event stored for later use when a
1475 * drag threshold is met.
1484 * Each DragDrop instance must be registered with the DragDropMgr.
1485 * This is executed in DragDrop.init()
1486 * @method regDragDrop
1487 * @param {DragDrop} oDD the DragDrop object to register
1488 * @param {String} sGroup the name of the group this element belongs to
1491 regDragDrop: function(oDD, sGroup) {
1492 if (!this.initialized) { this.init(); }
1494 if (!this.ids[sGroup]) {
1495 this.ids[sGroup] = {};
1497 this.ids[sGroup][oDD.id] = oDD;
1501 * Removes the supplied dd instance from the supplied group. Executed
1502 * by DragDrop.removeFromGroup, so don't call this function directly.
1503 * @method removeDDFromGroup
1507 removeDDFromGroup: function(oDD, sGroup) {
1508 if (!this.ids[sGroup]) {
1509 this.ids[sGroup] = {};
1512 var obj = this.ids[sGroup];
1513 if (obj && obj[oDD.id]) {
1519 * Unregisters a drag and drop item. This is executed in
1520 * DragDrop.unreg, use that method instead of calling this directly.
1525 _remove: function(oDD) {
1526 for (var g in oDD.groups) {
1527 if (g && this.ids[g][oDD.id]) {
1528 delete this.ids[g][oDD.id];
1531 delete this.handleIds[oDD.id];
1535 * Each DragDrop handle element must be registered. This is done
1536 * automatically when executing DragDrop.setHandleElId()
1538 * @param {String} sDDId the DragDrop id this element is a handle for
1539 * @param {String} sHandleId the id of the element that is the drag
1543 regHandle: function(sDDId, sHandleId) {
1544 if (!this.handleIds[sDDId]) {
1545 this.handleIds[sDDId] = {};
1547 this.handleIds[sDDId][sHandleId] = sHandleId;
1551 * Utility function to determine if a given element has been
1552 * registered as a drag drop item.
1553 * @method isDragDrop
1554 * @param {String} id the element id to check
1555 * @return {boolean} true if this element is a DragDrop item,
1559 isDragDrop: function(id) {
1560 return ( this.getDDById(id) ) ? true : false;
1564 * Returns the drag and drop instances that are in all groups the
1565 * passed in instance belongs to.
1566 * @method getRelated
1567 * @param {DragDrop} p_oDD the obj to get related data for
1568 * @param {boolean} bTargetsOnly if true, only return targetable objs
1569 * @return {DragDrop[]} the related instances
1572 getRelated: function(p_oDD, bTargetsOnly) {
1574 for (var i in p_oDD.groups) {
1575 for (j in this.ids[i]) {
1576 var dd = this.ids[i][j];
1577 if (! this.isTypeOfDD(dd)) {
1580 if (!bTargetsOnly || dd.isTarget) {
1581 oDDs[oDDs.length] = dd;
1590 * Returns true if the specified dd target is a legal target for
1591 * the specifice drag obj
1592 * @method isLegalTarget
1593 * @param {DragDrop} the drag obj
1594 * @param {DragDrop} the target
1595 * @return {boolean} true if the target is a legal target for the
1599 isLegalTarget: function (oDD, oTargetDD) {
1600 var targets = this.getRelated(oDD, true);
1601 for (var i=0, len=targets.length;i<len;++i) {
1602 if (targets[i].id == oTargetDD.id) {
1611 * My goal is to be able to transparently determine if an object is
1612 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1613 * returns "object", oDD.constructor.toString() always returns
1614 * "DragDrop" and not the name of the subclass. So for now it just
1615 * evaluates a well-known variable in DragDrop.
1616 * @method isTypeOfDD
1617 * @param {Object} the object to evaluate
1618 * @return {boolean} true if typeof oDD = DragDrop
1621 isTypeOfDD: function (oDD) {
1622 return (oDD && oDD.__ygDragDrop);
1626 * Utility function to determine if a given element has been
1627 * registered as a drag drop handle for the given Drag Drop object.
1629 * @param {String} id the element id to check
1630 * @return {boolean} true if this element is a DragDrop handle, false
1634 isHandle: function(sDDId, sHandleId) {
1635 return ( this.handleIds[sDDId] &&
1636 this.handleIds[sDDId][sHandleId] );
1640 * Returns the DragDrop instance for a given id
1642 * @param {String} id the id of the DragDrop object
1643 * @return {DragDrop} the drag drop object, null if it is not found
1646 getDDById: function(id) {
1647 for (var i in this.ids) {
1648 if (this.ids[i][id]) {
1649 return this.ids[i][id];
1656 * Fired after a registered DragDrop object gets the mousedown event.
1657 * Sets up the events required to track the object being dragged
1658 * @method handleMouseDown
1659 * @param {Event} e the event
1660 * @param oDD the DragDrop object being dragged
1664 handleMouseDown: function(e, oDD) {
1666 Roo.QuickTips.disable();
1668 this.currentTarget = e.getTarget();
1670 this.dragCurrent = oDD;
1672 var el = oDD.getEl();
1674 // track start position
1675 this.startX = e.getPageX();
1676 this.startY = e.getPageY();
1678 this.deltaX = this.startX - el.offsetLeft;
1679 this.deltaY = this.startY - el.offsetTop;
1681 this.dragThreshMet = false;
1683 this.clickTimeout = setTimeout(
1685 var DDM = Roo.dd.DDM;
1686 DDM.startDrag(DDM.startX, DDM.startY);
1688 this.clickTimeThresh );
1692 * Fired when either the drag pixel threshol or the mousedown hold
1693 * time threshold has been met.
1695 * @param x {int} the X position of the original mousedown
1696 * @param y {int} the Y position of the original mousedown
1699 startDrag: function(x, y) {
1700 clearTimeout(this.clickTimeout);
1701 if (this.dragCurrent) {
1702 this.dragCurrent.b4StartDrag(x, y);
1703 this.dragCurrent.startDrag(x, y);
1705 this.dragThreshMet = true;
1709 * Internal function to handle the mouseup event. Will be invoked
1710 * from the context of the document.
1711 * @method handleMouseUp
1712 * @param {Event} e the event
1716 handleMouseUp: function(e) {
1719 Roo.QuickTips.enable();
1721 if (! this.dragCurrent) {
1725 clearTimeout(this.clickTimeout);
1727 if (this.dragThreshMet) {
1728 this.fireEvents(e, true);
1738 * Utility to stop event propagation and event default, if these
1739 * features are turned on.
1741 * @param {Event} e the event as returned by this.getEvent()
1744 stopEvent: function(e){
1745 if(this.stopPropagation) {
1746 e.stopPropagation();
1749 if (this.preventDefault) {
1755 * Internal function to clean up event handlers after the drag
1756 * operation is complete
1758 * @param {Event} e the event
1762 stopDrag: function(e) {
1763 // Fire the drag end event for the item that was dragged
1764 if (this.dragCurrent) {
1765 if (this.dragThreshMet) {
1766 this.dragCurrent.b4EndDrag(e);
1767 this.dragCurrent.endDrag(e);
1770 this.dragCurrent.onMouseUp(e);
1773 this.dragCurrent = null;
1774 this.dragOvers = {};
1778 * Internal function to handle the mousemove event. Will be invoked
1779 * from the context of the html element.
1781 * @TODO figure out what we can do about mouse events lost when the
1782 * user drags objects beyond the window boundary. Currently we can
1783 * detect this in internet explorer by verifying that the mouse is
1784 * down during the mousemove event. Firefox doesn't give us the
1785 * button state on the mousemove event.
1786 * @method handleMouseMove
1787 * @param {Event} e the event
1791 handleMouseMove: function(e) {
1792 if (! this.dragCurrent) {
1796 // var button = e.which || e.button;
1798 // check for IE mouseup outside of page boundary
1799 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1801 return this.handleMouseUp(e);
1804 if (!this.dragThreshMet) {
1805 var diffX = Math.abs(this.startX - e.getPageX());
1806 var diffY = Math.abs(this.startY - e.getPageY());
1807 if (diffX > this.clickPixelThresh ||
1808 diffY > this.clickPixelThresh) {
1809 this.startDrag(this.startX, this.startY);
1813 if (this.dragThreshMet) {
1814 this.dragCurrent.b4Drag(e);
1815 this.dragCurrent.onDrag(e);
1816 if(!this.dragCurrent.moveOnly){
1817 this.fireEvents(e, false);
1827 * Iterates over all of the DragDrop elements to find ones we are
1828 * hovering over or dropping on
1829 * @method fireEvents
1830 * @param {Event} e the event
1831 * @param {boolean} isDrop is this a drop op or a mouseover op?
1835 fireEvents: function(e, isDrop) {
1836 var dc = this.dragCurrent;
1838 // If the user did the mouse up outside of the window, we could
1839 // get here even though we have ended the drag.
1840 if (!dc || dc.isLocked()) {
1844 var pt = e.getPoint();
1846 // cache the previous dragOver array
1854 // Check to see if the object(s) we were hovering over is no longer
1855 // being hovered over so we can fire the onDragOut event
1856 for (var i in this.dragOvers) {
1858 var ddo = this.dragOvers[i];
1860 if (! this.isTypeOfDD(ddo)) {
1864 if (! this.isOverTarget(pt, ddo, this.mode)) {
1865 outEvts.push( ddo );
1869 delete this.dragOvers[i];
1872 for (var sGroup in dc.groups) {
1874 if ("string" != typeof sGroup) {
1878 for (i in this.ids[sGroup]) {
1879 var oDD = this.ids[sGroup][i];
1880 if (! this.isTypeOfDD(oDD)) {
1884 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1885 if (this.isOverTarget(pt, oDD, this.mode)) {
1886 // look for drop interactions
1888 dropEvts.push( oDD );
1889 // look for drag enter and drag over interactions
1892 // initial drag over: dragEnter fires
1893 if (!oldOvers[oDD.id]) {
1894 enterEvts.push( oDD );
1895 // subsequent drag overs: dragOver fires
1897 overEvts.push( oDD );
1900 this.dragOvers[oDD.id] = oDD;
1908 if (outEvts.length) {
1909 dc.b4DragOut(e, outEvts);
1910 dc.onDragOut(e, outEvts);
1913 if (enterEvts.length) {
1914 dc.onDragEnter(e, enterEvts);
1917 if (overEvts.length) {
1918 dc.b4DragOver(e, overEvts);
1919 dc.onDragOver(e, overEvts);
1922 if (dropEvts.length) {
1923 dc.b4DragDrop(e, dropEvts);
1924 dc.onDragDrop(e, dropEvts);
1928 // fire dragout events
1930 for (i=0, len=outEvts.length; i<len; ++i) {
1931 dc.b4DragOut(e, outEvts[i].id);
1932 dc.onDragOut(e, outEvts[i].id);
1935 // fire enter events
1936 for (i=0,len=enterEvts.length; i<len; ++i) {
1937 // dc.b4DragEnter(e, oDD.id);
1938 dc.onDragEnter(e, enterEvts[i].id);
1942 for (i=0,len=overEvts.length; i<len; ++i) {
1943 dc.b4DragOver(e, overEvts[i].id);
1944 dc.onDragOver(e, overEvts[i].id);
1948 for (i=0, len=dropEvts.length; i<len; ++i) {
1949 dc.b4DragDrop(e, dropEvts[i].id);
1950 dc.onDragDrop(e, dropEvts[i].id);
1955 // notify about a drop that did not find a target
1956 if (isDrop && !dropEvts.length) {
1957 dc.onInvalidDrop(e);
1963 * Helper function for getting the best match from the list of drag
1964 * and drop objects returned by the drag and drop events when we are
1965 * in INTERSECT mode. It returns either the first object that the
1966 * cursor is over, or the object that has the greatest overlap with
1967 * the dragged element.
1968 * @method getBestMatch
1969 * @param {DragDrop[]} dds The array of drag and drop objects
1971 * @return {DragDrop} The best single match
1974 getBestMatch: function(dds) {
1976 // Return null if the input is not what we expect
1977 //if (!dds || !dds.length || dds.length == 0) {
1979 // If there is only one item, it wins
1980 //} else if (dds.length == 1) {
1982 var len = dds.length;
1987 // Loop through the targeted items
1988 for (var i=0; i<len; ++i) {
1990 // If the cursor is over the object, it wins. If the
1991 // cursor is over multiple matches, the first one we come
1993 if (dd.cursorIsOver) {
1996 // Otherwise the object with the most overlap wins
1999 winner.overlap.getArea() < dd.overlap.getArea()) {
2010 * Refreshes the cache of the top-left and bottom-right points of the
2011 * drag and drop objects in the specified group(s). This is in the
2012 * format that is stored in the drag and drop instance, so typical
2015 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2019 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2021 * @TODO this really should be an indexed array. Alternatively this
2022 * method could accept both.
2023 * @method refreshCache
2024 * @param {Object} groups an associative array of groups to refresh
2027 refreshCache: function(groups) {
2028 for (var sGroup in groups) {
2029 if ("string" != typeof sGroup) {
2032 for (var i in this.ids[sGroup]) {
2033 var oDD = this.ids[sGroup][i];
2035 if (this.isTypeOfDD(oDD)) {
2036 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2037 var loc = this.getLocation(oDD);
2039 this.locationCache[oDD.id] = loc;
2041 delete this.locationCache[oDD.id];
2042 // this will unregister the drag and drop object if
2043 // the element is not in a usable state
2052 * This checks to make sure an element exists and is in the DOM. The
2053 * main purpose is to handle cases where innerHTML is used to remove
2054 * drag and drop objects from the DOM. IE provides an 'unspecified
2055 * error' when trying to access the offsetParent of such an element
2057 * @param {HTMLElement} el the element to check
2058 * @return {boolean} true if the element looks usable
2061 verifyEl: function(el) {
2066 parent = el.offsetParent;
2069 parent = el.offsetParent;
2080 * Returns a Region object containing the drag and drop element's position
2081 * and size, including the padding configured for it
2082 * @method getLocation
2083 * @param {DragDrop} oDD the drag and drop object to get the
2085 * @return {Roo.lib.Region} a Region object representing the total area
2086 * the element occupies, including any padding
2087 * the instance is configured for.
2090 getLocation: function(oDD) {
2091 if (! this.isTypeOfDD(oDD)) {
2095 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2098 pos= Roo.lib.Dom.getXY(el);
2106 x2 = x1 + el.offsetWidth;
2108 y2 = y1 + el.offsetHeight;
2110 t = y1 - oDD.padding[0];
2111 r = x2 + oDD.padding[1];
2112 b = y2 + oDD.padding[2];
2113 l = x1 - oDD.padding[3];
2115 return new Roo.lib.Region( t, r, b, l );
2119 * Checks the cursor location to see if it over the target
2120 * @method isOverTarget
2121 * @param {Roo.lib.Point} pt The point to evaluate
2122 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2123 * @return {boolean} true if the mouse is over the target
2127 isOverTarget: function(pt, oTarget, intersect) {
2128 // use cache if available
2129 var loc = this.locationCache[oTarget.id];
2130 if (!loc || !this.useCache) {
2131 loc = this.getLocation(oTarget);
2132 this.locationCache[oTarget.id] = loc;
2140 oTarget.cursorIsOver = loc.contains( pt );
2142 // DragDrop is using this as a sanity check for the initial mousedown
2143 // in this case we are done. In POINT mode, if the drag obj has no
2144 // contraints, we are also done. Otherwise we need to evaluate the
2145 // location of the target as related to the actual location of the
2147 var dc = this.dragCurrent;
2148 if (!dc || !dc.getTargetCoord ||
2149 (!intersect && !dc.constrainX && !dc.constrainY)) {
2150 return oTarget.cursorIsOver;
2153 oTarget.overlap = null;
2155 // Get the current location of the drag element, this is the
2156 // location of the mouse event less the delta that represents
2157 // where the original mousedown happened on the element. We
2158 // need to consider constraints and ticks as well.
2159 var pos = dc.getTargetCoord(pt.x, pt.y);
2161 var el = dc.getDragEl();
2162 var curRegion = new Roo.lib.Region( pos.y,
2163 pos.x + el.offsetWidth,
2164 pos.y + el.offsetHeight,
2167 var overlap = curRegion.intersect(loc);
2170 oTarget.overlap = overlap;
2171 return (intersect) ? true : oTarget.cursorIsOver;
2178 * unload event handler
2183 _onUnload: function(e, me) {
2184 Roo.dd.DragDropMgr.unregAll();
2188 * Cleans up the drag and drop events and objects.
2193 unregAll: function() {
2195 if (this.dragCurrent) {
2197 this.dragCurrent = null;
2200 this._execOnAll("unreg", []);
2202 for (i in this.elementCache) {
2203 delete this.elementCache[i];
2206 this.elementCache = {};
2211 * A cache of DOM elements
2212 * @property elementCache
2219 * Get the wrapper for the DOM element specified
2220 * @method getElWrapper
2221 * @param {String} id the id of the element to get
2222 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2224 * @deprecated This wrapper isn't that useful
2227 getElWrapper: function(id) {
2228 var oWrapper = this.elementCache[id];
2229 if (!oWrapper || !oWrapper.el) {
2230 oWrapper = this.elementCache[id] =
2231 new this.ElementWrapper(Roo.getDom(id));
2237 * Returns the actual DOM element
2238 * @method getElement
2239 * @param {String} id the id of the elment to get
2240 * @return {Object} The element
2241 * @deprecated use Roo.getDom instead
2244 getElement: function(id) {
2245 return Roo.getDom(id);
2249 * Returns the style property for the DOM element (i.e.,
2250 * document.getElById(id).style)
2252 * @param {String} id the id of the elment to get
2253 * @return {Object} The style property of the element
2254 * @deprecated use Roo.getDom instead
2257 getCss: function(id) {
2258 var el = Roo.getDom(id);
2259 return (el) ? el.style : null;
2263 * Inner class for cached elements
2264 * @class DragDropMgr.ElementWrapper
2269 ElementWrapper: function(el) {
2274 this.el = el || null;
2279 this.id = this.el && el.id;
2281 * A reference to the style property
2284 this.css = this.el && el.style;
2288 * Returns the X position of an html element
2290 * @param el the element for which to get the position
2291 * @return {int} the X coordinate
2293 * @deprecated use Roo.lib.Dom.getX instead
2296 getPosX: function(el) {
2297 return Roo.lib.Dom.getX(el);
2301 * Returns the Y position of an html element
2303 * @param el the element for which to get the position
2304 * @return {int} the Y coordinate
2305 * @deprecated use Roo.lib.Dom.getY instead
2308 getPosY: function(el) {
2309 return Roo.lib.Dom.getY(el);
2313 * Swap two nodes. In IE, we use the native method, for others we
2314 * emulate the IE behavior
2316 * @param n1 the first node to swap
2317 * @param n2 the other node to swap
2320 swapNode: function(n1, n2) {
2324 var p = n2.parentNode;
2325 var s = n2.nextSibling;
2328 p.insertBefore(n1, n2);
2329 } else if (n2 == n1.nextSibling) {
2330 p.insertBefore(n2, n1);
2332 n1.parentNode.replaceChild(n2, n1);
2333 p.insertBefore(n1, s);
2339 * Returns the current scroll position
2344 getScroll: function () {
2345 var t, l, dde=document.documentElement, db=document.body;
2346 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2355 return { top: t, left: l };
2359 * Returns the specified element style property
2361 * @param {HTMLElement} el the element
2362 * @param {string} styleProp the style property
2363 * @return {string} The value of the style property
2364 * @deprecated use Roo.lib.Dom.getStyle
2367 getStyle: function(el, styleProp) {
2368 return Roo.fly(el).getStyle(styleProp);
2372 * Gets the scrollTop
2373 * @method getScrollTop
2374 * @return {int} the document's scrollTop
2377 getScrollTop: function () { return this.getScroll().top; },
2380 * Gets the scrollLeft
2381 * @method getScrollLeft
2382 * @return {int} the document's scrollTop
2385 getScrollLeft: function () { return this.getScroll().left; },
2388 * Sets the x/y position of an element to the location of the
2391 * @param {HTMLElement} moveEl The element to move
2392 * @param {HTMLElement} targetEl The position reference element
2395 moveToEl: function (moveEl, targetEl) {
2396 var aCoord = Roo.lib.Dom.getXY(targetEl);
2397 Roo.lib.Dom.setXY(moveEl, aCoord);
2401 * Numeric array sort function
2402 * @method numericSort
2405 numericSort: function(a, b) { return (a - b); },
2409 * @property _timeoutCount
2416 * Trying to make the load order less important. Without this we get
2417 * an error if this file is loaded before the Event Utility.
2418 * @method _addListeners
2422 _addListeners: function() {
2423 var DDM = Roo.dd.DDM;
2424 if ( Roo.lib.Event && document ) {
2427 if (DDM._timeoutCount > 2000) {
2429 setTimeout(DDM._addListeners, 10);
2430 if (document && document.body) {
2431 DDM._timeoutCount += 1;
2438 * Recursively searches the immediate parent and all child nodes for
2439 * the handle element in order to determine wheter or not it was
2441 * @method handleWasClicked
2442 * @param node the html element to inspect
2445 handleWasClicked: function(node, id) {
2446 if (this.isHandle(id, node.id)) {
2449 // check to see if this is a text node child of the one we want
2450 var p = node.parentNode;
2453 if (this.isHandle(id, p.id)) {
2468 // shorter alias, save a few bytes
2469 Roo.dd.DDM = Roo.dd.DragDropMgr;
2470 Roo.dd.DDM._addListeners();
2474 * Ext JS Library 1.1.1
2475 * Copyright(c) 2006-2007, Ext JS, LLC.
2477 * Originally Released Under LGPL - original licence link has changed is not relivant.
2480 * <script type="text/javascript">
2485 * A DragDrop implementation where the linked element follows the
2486 * mouse cursor during a drag.
2487 * @extends Roo.dd.DragDrop
2489 * @param {String} id the id of the linked element
2490 * @param {String} sGroup the group of related DragDrop items
2491 * @param {object} config an object containing configurable attributes
2492 * Valid properties for DD:
2495 Roo.dd.DD = function(id, sGroup, config) {
2497 this.init(id, sGroup, config);
2501 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2504 * When set to true, the utility automatically tries to scroll the browser
2505 * window wehn a drag and drop element is dragged near the viewport boundary.
2513 * Sets the pointer offset to the distance between the linked element's top
2514 * left corner and the location the element was clicked
2515 * @method autoOffset
2516 * @param {int} iPageX the X coordinate of the click
2517 * @param {int} iPageY the Y coordinate of the click
2519 autoOffset: function(iPageX, iPageY) {
2520 var x = iPageX - this.startPageX;
2521 var y = iPageY - this.startPageY;
2522 this.setDelta(x, y);
2526 * Sets the pointer offset. You can call this directly to force the
2527 * offset to be in a particular location (e.g., pass in 0,0 to set it
2528 * to the center of the object)
2530 * @param {int} iDeltaX the distance from the left
2531 * @param {int} iDeltaY the distance from the top
2533 setDelta: function(iDeltaX, iDeltaY) {
2534 this.deltaX = iDeltaX;
2535 this.deltaY = iDeltaY;
2539 * Sets the drag element to the location of the mousedown or click event,
2540 * maintaining the cursor location relative to the location on the element
2541 * that was clicked. Override this if you want to place the element in a
2542 * location other than where the cursor is.
2543 * @method setDragElPos
2544 * @param {int} iPageX the X coordinate of the mousedown or drag event
2545 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2547 setDragElPos: function(iPageX, iPageY) {
2548 // the first time we do this, we are going to check to make sure
2549 // the element has css positioning
2551 var el = this.getDragEl();
2552 this.alignElWithMouse(el, iPageX, iPageY);
2556 * Sets the element to the location of the mousedown or click event,
2557 * maintaining the cursor location relative to the location on the element
2558 * that was clicked. Override this if you want to place the element in a
2559 * location other than where the cursor is.
2560 * @method alignElWithMouse
2561 * @param {HTMLElement} el the element to move
2562 * @param {int} iPageX the X coordinate of the mousedown or drag event
2563 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2565 alignElWithMouse: function(el, iPageX, iPageY) {
2566 var oCoord = this.getTargetCoord(iPageX, iPageY);
2567 var fly = el.dom ? el : Roo.fly(el);
2568 if (!this.deltaSetXY) {
2569 var aCoord = [oCoord.x, oCoord.y];
2571 var newLeft = fly.getLeft(true);
2572 var newTop = fly.getTop(true);
2573 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2575 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2578 this.cachePosition(oCoord.x, oCoord.y);
2579 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2584 * Saves the most recent position so that we can reset the constraints and
2585 * tick marks on-demand. We need to know this so that we can calculate the
2586 * number of pixels the element is offset from its original position.
2587 * @method cachePosition
2588 * @param iPageX the current x position (optional, this just makes it so we
2589 * don't have to look it up again)
2590 * @param iPageY the current y position (optional, this just makes it so we
2591 * don't have to look it up again)
2593 cachePosition: function(iPageX, iPageY) {
2595 this.lastPageX = iPageX;
2596 this.lastPageY = iPageY;
2598 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2599 this.lastPageX = aCoord[0];
2600 this.lastPageY = aCoord[1];
2605 * Auto-scroll the window if the dragged object has been moved beyond the
2606 * visible window boundary.
2607 * @method autoScroll
2608 * @param {int} x the drag element's x position
2609 * @param {int} y the drag element's y position
2610 * @param {int} h the height of the drag element
2611 * @param {int} w the width of the drag element
2614 autoScroll: function(x, y, h, w) {
2617 // The client height
2618 var clientH = Roo.lib.Dom.getViewWidth();
2621 var clientW = Roo.lib.Dom.getViewHeight();
2623 // The amt scrolled down
2624 var st = this.DDM.getScrollTop();
2626 // The amt scrolled right
2627 var sl = this.DDM.getScrollLeft();
2629 // Location of the bottom of the element
2632 // Location of the right of the element
2635 // The distance from the cursor to the bottom of the visible area,
2636 // adjusted so that we don't scroll if the cursor is beyond the
2637 // element drag constraints
2638 var toBot = (clientH + st - y - this.deltaY);
2640 // The distance from the cursor to the right of the visible area
2641 var toRight = (clientW + sl - x - this.deltaX);
2644 // How close to the edge the cursor must be before we scroll
2645 // var thresh = (document.all) ? 100 : 40;
2648 // How many pixels to scroll per autoscroll op. This helps to reduce
2649 // clunky scrolling. IE is more sensitive about this ... it needs this
2650 // value to be higher.
2651 var scrAmt = (document.all) ? 80 : 30;
2653 // Scroll down if we are near the bottom of the visible page and the
2654 // obj extends below the crease
2655 if ( bot > clientH && toBot < thresh ) {
2656 window.scrollTo(sl, st + scrAmt);
2659 // Scroll up if the window is scrolled down and the top of the object
2660 // goes above the top border
2661 if ( y < st && st > 0 && y - st < thresh ) {
2662 window.scrollTo(sl, st - scrAmt);
2665 // Scroll right if the obj is beyond the right border and the cursor is
2667 if ( right > clientW && toRight < thresh ) {
2668 window.scrollTo(sl + scrAmt, st);
2671 // Scroll left if the window has been scrolled to the right and the obj
2672 // extends past the left border
2673 if ( x < sl && sl > 0 && x - sl < thresh ) {
2674 window.scrollTo(sl - scrAmt, st);
2680 * Finds the location the element should be placed if we want to move
2681 * it to where the mouse location less the click offset would place us.
2682 * @method getTargetCoord
2683 * @param {int} iPageX the X coordinate of the click
2684 * @param {int} iPageY the Y coordinate of the click
2685 * @return an object that contains the coordinates (Object.x and Object.y)
2688 getTargetCoord: function(iPageX, iPageY) {
2691 var x = iPageX - this.deltaX;
2692 var y = iPageY - this.deltaY;
2694 if (this.constrainX) {
2695 if (x < this.minX) { x = this.minX; }
2696 if (x > this.maxX) { x = this.maxX; }
2699 if (this.constrainY) {
2700 if (y < this.minY) { y = this.minY; }
2701 if (y > this.maxY) { y = this.maxY; }
2704 x = this.getTick(x, this.xTicks);
2705 y = this.getTick(y, this.yTicks);
2712 * Sets up config options specific to this class. Overrides
2713 * Roo.dd.DragDrop, but all versions of this method through the
2714 * inheritance chain are called
2716 applyConfig: function() {
2717 Roo.dd.DD.superclass.applyConfig.call(this);
2718 this.scroll = (this.config.scroll !== false);
2722 * Event that fires prior to the onMouseDown event. Overrides
2725 b4MouseDown: function(e) {
2726 // this.resetConstraints();
2727 this.autoOffset(e.getPageX(),
2732 * Event that fires prior to the onDrag event. Overrides
2735 b4Drag: function(e) {
2736 this.setDragElPos(e.getPageX(),
2740 toString: function() {
2741 return ("DD " + this.id);
2744 //////////////////////////////////////////////////////////////////////////
2745 // Debugging ygDragDrop events that can be overridden
2746 //////////////////////////////////////////////////////////////////////////
2748 startDrag: function(x, y) {
2751 onDrag: function(e) {
2754 onDragEnter: function(e, id) {
2757 onDragOver: function(e, id) {
2760 onDragOut: function(e, id) {
2763 onDragDrop: function(e, id) {
2766 endDrag: function(e) {
2773 * Ext JS Library 1.1.1
2774 * Copyright(c) 2006-2007, Ext JS, LLC.
2776 * Originally Released Under LGPL - original licence link has changed is not relivant.
2779 * <script type="text/javascript">
2783 * @class Roo.dd.DDProxy
2784 * A DragDrop implementation that inserts an empty, bordered div into
2785 * the document that follows the cursor during drag operations. At the time of
2786 * the click, the frame div is resized to the dimensions of the linked html
2787 * element, and moved to the exact location of the linked element.
2789 * References to the "frame" element refer to the single proxy element that
2790 * was created to be dragged in place of all DDProxy elements on the
2793 * @extends Roo.dd.DD
2795 * @param {String} id the id of the linked html element
2796 * @param {String} sGroup the group of related DragDrop objects
2797 * @param {object} config an object containing configurable attributes
2798 * Valid properties for DDProxy in addition to those in DragDrop:
2799 * resizeFrame, centerFrame, dragElId
2801 Roo.dd.DDProxy = function(id, sGroup, config) {
2803 this.init(id, sGroup, config);
2809 * The default drag frame div id
2810 * @property Roo.dd.DDProxy.dragElId
2814 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2816 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2819 * By default we resize the drag frame to be the same size as the element
2820 * we want to drag (this is to get the frame effect). We can turn it off
2821 * if we want a different behavior.
2822 * @property resizeFrame
2828 * By default the frame is positioned exactly where the drag element is, so
2829 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2830 * you do not have constraints on the obj is to have the drag frame centered
2831 * around the cursor. Set centerFrame to true for this effect.
2832 * @property centerFrame
2838 * Creates the proxy element if it does not yet exist
2839 * @method createFrame
2841 createFrame: function() {
2843 var body = document.body;
2845 if (!body || !body.firstChild) {
2846 setTimeout( function() { self.createFrame(); }, 50 );
2850 var div = this.getDragEl();
2853 div = document.createElement("div");
2854 div.id = this.dragElId;
2857 s.position = "absolute";
2858 s.visibility = "hidden";
2860 s.border = "2px solid #aaa";
2863 // appendChild can blow up IE if invoked prior to the window load event
2864 // while rendering a table. It is possible there are other scenarios
2865 // that would cause this to happen as well.
2866 body.insertBefore(div, body.firstChild);
2871 * Initialization for the drag frame element. Must be called in the
2872 * constructor of all subclasses
2875 initFrame: function() {
2879 applyConfig: function() {
2880 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2882 this.resizeFrame = (this.config.resizeFrame !== false);
2883 this.centerFrame = (this.config.centerFrame);
2884 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2888 * Resizes the drag frame to the dimensions of the clicked object, positions
2889 * it over the object, and finally displays it
2891 * @param {int} iPageX X click position
2892 * @param {int} iPageY Y click position
2895 showFrame: function(iPageX, iPageY) {
2896 var el = this.getEl();
2897 var dragEl = this.getDragEl();
2898 var s = dragEl.style;
2900 this._resizeProxy();
2902 if (this.centerFrame) {
2903 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2904 Math.round(parseInt(s.height, 10)/2) );
2907 this.setDragElPos(iPageX, iPageY);
2909 Roo.fly(dragEl).show();
2913 * The proxy is automatically resized to the dimensions of the linked
2914 * element when a drag is initiated, unless resizeFrame is set to false
2915 * @method _resizeProxy
2918 _resizeProxy: function() {
2919 if (this.resizeFrame) {
2920 var el = this.getEl();
2921 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2925 // overrides Roo.dd.DragDrop
2926 b4MouseDown: function(e) {
2927 var x = e.getPageX();
2928 var y = e.getPageY();
2929 this.autoOffset(x, y);
2930 this.setDragElPos(x, y);
2933 // overrides Roo.dd.DragDrop
2934 b4StartDrag: function(x, y) {
2935 // show the drag frame
2936 this.showFrame(x, y);
2939 // overrides Roo.dd.DragDrop
2940 b4EndDrag: function(e) {
2941 Roo.fly(this.getDragEl()).hide();
2944 // overrides Roo.dd.DragDrop
2945 // By default we try to move the element to the last location of the frame.
2946 // This is so that the default behavior mirrors that of Roo.dd.DD.
2947 endDrag: function(e) {
2949 var lel = this.getEl();
2950 var del = this.getDragEl();
2952 // Show the drag frame briefly so we can get its position
2953 del.style.visibility = "";
2956 // Hide the linked element before the move to get around a Safari
2958 lel.style.visibility = "hidden";
2959 Roo.dd.DDM.moveToEl(lel, del);
2960 del.style.visibility = "hidden";
2961 lel.style.visibility = "";
2966 beforeMove : function(){
2970 afterDrag : function(){
2974 toString: function() {
2975 return ("DDProxy " + this.id);
2981 * Ext JS Library 1.1.1
2982 * Copyright(c) 2006-2007, Ext JS, LLC.
2984 * Originally Released Under LGPL - original licence link has changed is not relivant.
2987 * <script type="text/javascript">
2991 * @class Roo.dd.DDTarget
2992 * A DragDrop implementation that does not move, but can be a drop
2993 * target. You would get the same result by simply omitting implementation
2994 * for the event callbacks, but this way we reduce the processing cost of the
2995 * event listener and the callbacks.
2996 * @extends Roo.dd.DragDrop
2998 * @param {String} id the id of the element that is a drop target
2999 * @param {String} sGroup the group of related DragDrop objects
3000 * @param {object} config an object containing configurable attributes
3001 * Valid properties for DDTarget in addition to those in
3005 Roo.dd.DDTarget = function(id, sGroup, config) {
3007 this.initTarget(id, sGroup, config);
3011 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3012 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3013 toString: function() {
3014 return ("DDTarget " + this.id);
3019 * Ext JS Library 1.1.1
3020 * Copyright(c) 2006-2007, Ext JS, LLC.
3022 * Originally Released Under LGPL - original licence link has changed is not relivant.
3025 * <script type="text/javascript">
3030 * @class Roo.dd.ScrollManager
3031 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3032 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3035 Roo.dd.ScrollManager = function(){
3036 var ddm = Roo.dd.DragDropMgr;
3041 var onStop = function(e){
3046 var triggerRefresh = function(){
3047 if(ddm.dragCurrent){
3048 ddm.refreshCache(ddm.dragCurrent.groups);
3052 var doScroll = function(){
3053 if(ddm.dragCurrent){
3054 var dds = Roo.dd.ScrollManager;
3056 if(proc.el.scroll(proc.dir, dds.increment)){
3060 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3065 var clearProc = function(){
3067 clearInterval(proc.id);
3074 var startProc = function(el, dir){
3078 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3081 var onFire = function(e, isDrop){
3082 if(isDrop || !ddm.dragCurrent){ return; }
3083 var dds = Roo.dd.ScrollManager;
3084 if(!dragEl || dragEl != ddm.dragCurrent){
3085 dragEl = ddm.dragCurrent;
3086 // refresh regions on drag start
3090 var xy = Roo.lib.Event.getXY(e);
3091 var pt = new Roo.lib.Point(xy[0], xy[1]);
3093 var el = els[id], r = el._region;
3094 if(r && r.contains(pt) && el.isScrollable()){
3095 if(r.bottom - pt.y <= dds.thresh){
3097 startProc(el, "down");
3100 }else if(r.right - pt.x <= dds.thresh){
3102 startProc(el, "left");
3105 }else if(pt.y - r.top <= dds.thresh){
3107 startProc(el, "up");
3110 }else if(pt.x - r.left <= dds.thresh){
3112 startProc(el, "right");
3121 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3122 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3126 * Registers new overflow element(s) to auto scroll
3127 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3129 register : function(el){
3130 if(el instanceof Array){
3131 for(var i = 0, len = el.length; i < len; i++) {
3132 this.register(el[i]);
3141 * Unregisters overflow element(s) so they are no longer scrolled
3142 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3144 unregister : function(el){
3145 if(el instanceof Array){
3146 for(var i = 0, len = el.length; i < len; i++) {
3147 this.unregister(el[i]);
3156 * The number of pixels from the edge of a container the pointer needs to be to
3157 * trigger scrolling (defaults to 25)
3163 * The number of pixels to scroll in each scroll increment (defaults to 50)
3169 * The frequency of scrolls in milliseconds (defaults to 500)
3175 * True to animate the scroll (defaults to true)
3181 * The animation duration in seconds -
3182 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3188 * Manually trigger a cache refresh.
3190 refreshCache : function(){
3192 if(typeof els[id] == 'object'){ // for people extending the object prototype
3193 els[id]._region = els[id].getRegion();
3200 * Ext JS Library 1.1.1
3201 * Copyright(c) 2006-2007, Ext JS, LLC.
3203 * Originally Released Under LGPL - original licence link has changed is not relivant.
3206 * <script type="text/javascript">
3211 * @class Roo.dd.Registry
3212 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3213 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3216 Roo.dd.Registry = function(){
3221 var getId = function(el, autogen){
3222 if(typeof el == "string"){
3226 if(!id && autogen !== false){
3227 id = "roodd-" + (++autoIdSeed);
3235 * Register a drag drop element
3236 * @param {String|HTMLElement} element The id or DOM node to register
3237 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3238 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3239 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3240 * populated in the data object (if applicable):
3242 Value Description<br />
3243 --------- ------------------------------------------<br />
3244 handles Array of DOM nodes that trigger dragging<br />
3245 for the element being registered<br />
3246 isHandle True if the element passed in triggers<br />
3247 dragging itself, else false
3250 register : function(el, data){
3252 if(typeof el == "string"){
3253 el = document.getElementById(el);
3256 elements[getId(el)] = data;
3257 if(data.isHandle !== false){
3258 handles[data.ddel.id] = data;
3261 var hs = data.handles;
3262 for(var i = 0, len = hs.length; i < len; i++){
3263 handles[getId(hs[i])] = data;
3269 * Unregister a drag drop element
3270 * @param {String|HTMLElement} element The id or DOM node to unregister
3272 unregister : function(el){
3273 var id = getId(el, false);
3274 var data = elements[id];
3276 delete elements[id];
3278 var hs = data.handles;
3279 for(var i = 0, len = hs.length; i < len; i++){
3280 delete handles[getId(hs[i], false)];
3287 * Returns the handle registered for a DOM Node by id
3288 * @param {String|HTMLElement} id The DOM node or id to look up
3289 * @return {Object} handle The custom handle data
3291 getHandle : function(id){
3292 if(typeof id != "string"){ // must be element?
3299 * Returns the handle that is registered for the DOM node that is the target of the event
3300 * @param {Event} e The event
3301 * @return {Object} handle The custom handle data
3303 getHandleFromEvent : function(e){
3304 var t = Roo.lib.Event.getTarget(e);
3305 return t ? handles[t.id] : null;
3309 * Returns a custom data object that is registered for a DOM node by id
3310 * @param {String|HTMLElement} id The DOM node or id to look up
3311 * @return {Object} data The custom data
3313 getTarget : function(id){
3314 if(typeof id != "string"){ // must be element?
3317 return elements[id];
3321 * Returns a custom data object that is registered for the DOM node that is the target of the event
3322 * @param {Event} e The event
3323 * @return {Object} data The custom data
3325 getTargetFromEvent : function(e){
3326 var t = Roo.lib.Event.getTarget(e);
3327 return t ? elements[t.id] || handles[t.id] : null;
3332 * Ext JS Library 1.1.1
3333 * Copyright(c) 2006-2007, Ext JS, LLC.
3335 * Originally Released Under LGPL - original licence link has changed is not relivant.
3338 * <script type="text/javascript">
3343 * @class Roo.dd.StatusProxy
3344 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3345 * default drag proxy used by all Roo.dd components.
3347 * @param {Object} config
3349 Roo.dd.StatusProxy = function(config){
3350 Roo.apply(this, config);
3351 this.id = this.id || Roo.id();
3352 this.el = new Roo.Layer({
3354 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3355 {tag: "div", cls: "x-dd-drop-icon"},
3356 {tag: "div", cls: "x-dd-drag-ghost"}
3359 shadow: !config || config.shadow !== false
3361 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3362 this.dropStatus = this.dropNotAllowed;
3365 Roo.dd.StatusProxy.prototype = {
3367 * @cfg {String} dropAllowed
3368 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3370 dropAllowed : "x-dd-drop-ok",
3372 * @cfg {String} dropNotAllowed
3373 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3375 dropNotAllowed : "x-dd-drop-nodrop",
3378 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3379 * over the current target element.
3380 * @param {String} cssClass The css class for the new drop status indicator image
3382 setStatus : function(cssClass){
3383 cssClass = cssClass || this.dropNotAllowed;
3384 if(this.dropStatus != cssClass){
3385 this.el.replaceClass(this.dropStatus, cssClass);
3386 this.dropStatus = cssClass;
3391 * Resets the status indicator to the default dropNotAllowed value
3392 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3394 reset : function(clearGhost){
3395 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3396 this.dropStatus = this.dropNotAllowed;
3398 this.ghost.update("");
3403 * Updates the contents of the ghost element
3404 * @param {String} html The html that will replace the current innerHTML of the ghost element
3406 update : function(html){
3407 if(typeof html == "string"){
3408 this.ghost.update(html);
3410 this.ghost.update("");
3411 html.style.margin = "0";
3412 this.ghost.dom.appendChild(html);
3414 // ensure float = none set?? cant remember why though.
3415 var el = this.ghost.dom.firstChild;
3417 Roo.fly(el).setStyle('float', 'none');
3422 * Returns the underlying proxy {@link Roo.Layer}
3423 * @return {Roo.Layer} el
3430 * Returns the ghost element
3431 * @return {Roo.Element} el
3433 getGhost : function(){
3439 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3441 hide : function(clear){
3449 * Stops the repair animation if it's currently running
3452 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3458 * Displays this proxy
3465 * Force the Layer to sync its shadow and shim positions to the element
3472 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3473 * invalid drop operation by the item being dragged.
3474 * @param {Array} xy The XY position of the element ([x, y])
3475 * @param {Function} callback The function to call after the repair is complete
3476 * @param {Object} scope The scope in which to execute the callback
3478 repair : function(xy, callback, scope){
3479 this.callback = callback;
3481 if(xy && this.animRepair !== false){
3482 this.el.addClass("x-dd-drag-repair");
3483 this.el.hideUnders(true);
3484 this.anim = this.el.shift({
3485 duration: this.repairDuration || .5,
3489 callback: this.afterRepair,
3498 afterRepair : function(){
3500 if(typeof this.callback == "function"){
3501 this.callback.call(this.scope || this);
3503 this.callback = null;
3508 * Ext JS Library 1.1.1
3509 * Copyright(c) 2006-2007, Ext JS, LLC.
3511 * Originally Released Under LGPL - original licence link has changed is not relivant.
3514 * <script type="text/javascript">
3518 * @class Roo.dd.DragSource
3519 * @extends Roo.dd.DDProxy
3520 * A simple class that provides the basic implementation needed to make any element draggable.
3522 * @param {String/HTMLElement/Element} el The container element
3523 * @param {Object} config
3525 Roo.dd.DragSource = function(el, config){
3526 this.el = Roo.get(el);
3529 Roo.apply(this, config);
3532 this.proxy = new Roo.dd.StatusProxy();
3535 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3536 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3538 this.dragging = false;
3541 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3543 * @cfg {String} dropAllowed
3544 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3546 dropAllowed : "x-dd-drop-ok",
3548 * @cfg {String} dropNotAllowed
3549 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3551 dropNotAllowed : "x-dd-drop-nodrop",
3554 * Returns the data object associated with this drag source
3555 * @return {Object} data An object containing arbitrary data
3557 getDragData : function(e){
3558 return this.dragData;
3562 onDragEnter : function(e, id){
3563 var target = Roo.dd.DragDropMgr.getDDById(id);
3564 this.cachedTarget = target;
3565 if(this.beforeDragEnter(target, e, id) !== false){
3566 if(target.isNotifyTarget){
3567 var status = target.notifyEnter(this, e, this.dragData);
3568 this.proxy.setStatus(status);
3570 this.proxy.setStatus(this.dropAllowed);
3573 if(this.afterDragEnter){
3575 * An empty function by default, but provided so that you can perform a custom action
3576 * when the dragged item enters the drop target by providing an implementation.
3577 * @param {Roo.dd.DragDrop} target The drop target
3578 * @param {Event} e The event object
3579 * @param {String} id The id of the dragged element
3580 * @method afterDragEnter
3582 this.afterDragEnter(target, e, id);
3588 * An empty function by default, but provided so that you can perform a custom action
3589 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3590 * @param {Roo.dd.DragDrop} target The drop target
3591 * @param {Event} e The event object
3592 * @param {String} id The id of the dragged element
3593 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3595 beforeDragEnter : function(target, e, id){
3600 alignElWithMouse: function() {
3601 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3606 onDragOver : function(e, id){
3607 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3608 if(this.beforeDragOver(target, e, id) !== false){
3609 if(target.isNotifyTarget){
3610 var status = target.notifyOver(this, e, this.dragData);
3611 this.proxy.setStatus(status);
3614 if(this.afterDragOver){
3616 * An empty function by default, but provided so that you can perform a custom action
3617 * while the dragged item is over the drop target by providing an implementation.
3618 * @param {Roo.dd.DragDrop} target The drop target
3619 * @param {Event} e The event object
3620 * @param {String} id The id of the dragged element
3621 * @method afterDragOver
3623 this.afterDragOver(target, e, id);
3629 * An empty function by default, but provided so that you can perform a custom action
3630 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3631 * @param {Roo.dd.DragDrop} target The drop target
3632 * @param {Event} e The event object
3633 * @param {String} id The id of the dragged element
3634 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3636 beforeDragOver : function(target, e, id){
3641 onDragOut : function(e, id){
3642 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3643 if(this.beforeDragOut(target, e, id) !== false){
3644 if(target.isNotifyTarget){
3645 target.notifyOut(this, e, this.dragData);
3648 if(this.afterDragOut){
3650 * An empty function by default, but provided so that you can perform a custom action
3651 * after the dragged item is dragged out of the target without dropping.
3652 * @param {Roo.dd.DragDrop} target The drop target
3653 * @param {Event} e The event object
3654 * @param {String} id The id of the dragged element
3655 * @method afterDragOut
3657 this.afterDragOut(target, e, id);
3660 this.cachedTarget = null;
3664 * An empty function by default, but provided so that you can perform a custom action before the dragged
3665 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3666 * @param {Roo.dd.DragDrop} target The drop target
3667 * @param {Event} e The event object
3668 * @param {String} id The id of the dragged element
3669 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3671 beforeDragOut : function(target, e, id){
3676 onDragDrop : function(e, id){
3677 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3678 if(this.beforeDragDrop(target, e, id) !== false){
3679 if(target.isNotifyTarget){
3680 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3681 this.onValidDrop(target, e, id);
3683 this.onInvalidDrop(target, e, id);
3686 this.onValidDrop(target, e, id);
3689 if(this.afterDragDrop){
3691 * An empty function by default, but provided so that you can perform a custom action
3692 * after a valid drag drop has occurred by providing an implementation.
3693 * @param {Roo.dd.DragDrop} target The drop target
3694 * @param {Event} e The event object
3695 * @param {String} id The id of the dropped element
3696 * @method afterDragDrop
3698 this.afterDragDrop(target, e, id);
3701 delete this.cachedTarget;
3705 * An empty function by default, but provided so that you can perform a custom action before the dragged
3706 * item is dropped onto the target and optionally cancel the onDragDrop.
3707 * @param {Roo.dd.DragDrop} target The drop target
3708 * @param {Event} e The event object
3709 * @param {String} id The id of the dragged element
3710 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3712 beforeDragDrop : function(target, e, id){
3717 onValidDrop : function(target, e, id){
3719 if(this.afterValidDrop){
3721 * An empty function by default, but provided so that you can perform a custom action
3722 * after a valid drop has occurred by providing an implementation.
3723 * @param {Object} target The target DD
3724 * @param {Event} e The event object
3725 * @param {String} id The id of the dropped element
3726 * @method afterInvalidDrop
3728 this.afterValidDrop(target, e, id);
3733 getRepairXY : function(e, data){
3734 return this.el.getXY();
3738 onInvalidDrop : function(target, e, id){
3739 this.beforeInvalidDrop(target, e, id);
3740 if(this.cachedTarget){
3741 if(this.cachedTarget.isNotifyTarget){
3742 this.cachedTarget.notifyOut(this, e, this.dragData);
3744 this.cacheTarget = null;
3746 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3748 if(this.afterInvalidDrop){
3750 * An empty function by default, but provided so that you can perform a custom action
3751 * after an invalid drop has occurred by providing an implementation.
3752 * @param {Event} e The event object
3753 * @param {String} id The id of the dropped element
3754 * @method afterInvalidDrop
3756 this.afterInvalidDrop(e, id);
3761 afterRepair : function(){
3763 this.el.highlight(this.hlColor || "c3daf9");
3765 this.dragging = false;
3769 * An empty function by default, but provided so that you can perform a custom action after an invalid
3770 * drop has occurred.
3771 * @param {Roo.dd.DragDrop} target The drop target
3772 * @param {Event} e The event object
3773 * @param {String} id The id of the dragged element
3774 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3776 beforeInvalidDrop : function(target, e, id){
3781 handleMouseDown : function(e){
3785 var data = this.getDragData(e);
3786 if(data && this.onBeforeDrag(data, e) !== false){
3787 this.dragData = data;
3789 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3794 * An empty function by default, but provided so that you can perform a custom action before the initial
3795 * drag event begins and optionally cancel it.
3796 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3797 * @param {Event} e The event object
3798 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3800 onBeforeDrag : function(data, e){
3805 * An empty function by default, but provided so that you can perform a custom action once the initial
3806 * drag event has begun. The drag cannot be canceled from this function.
3807 * @param {Number} x The x position of the click on the dragged object
3808 * @param {Number} y The y position of the click on the dragged object
3810 onStartDrag : Roo.emptyFn,
3812 // private - YUI override
3813 startDrag : function(x, y){
3815 this.dragging = true;
3816 this.proxy.update("");
3817 this.onInitDrag(x, y);
3822 onInitDrag : function(x, y){
3823 var clone = this.el.dom.cloneNode(true);
3824 clone.id = Roo.id(); // prevent duplicate ids
3825 this.proxy.update(clone);
3826 this.onStartDrag(x, y);
3831 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3832 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3834 getProxy : function(){
3839 * Hides the drag source's {@link Roo.dd.StatusProxy}
3841 hideProxy : function(){
3843 this.proxy.reset(true);
3844 this.dragging = false;
3848 triggerCacheRefresh : function(){
3849 Roo.dd.DDM.refreshCache(this.groups);
3852 // private - override to prevent hiding
3853 b4EndDrag: function(e) {
3856 // private - override to prevent moving
3857 endDrag : function(e){
3858 this.onEndDrag(this.dragData, e);
3862 onEndDrag : function(data, e){
3865 // private - pin to cursor
3866 autoOffset : function(x, y) {
3867 this.setDelta(-12, -20);
3871 * Ext JS Library 1.1.1
3872 * Copyright(c) 2006-2007, Ext JS, LLC.
3874 * Originally Released Under LGPL - original licence link has changed is not relivant.
3877 * <script type="text/javascript">
3882 * @class Roo.dd.DropTarget
3883 * @extends Roo.dd.DDTarget
3884 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3885 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3887 * @param {String/HTMLElement/Element} el The container element
3888 * @param {Object} config
3890 Roo.dd.DropTarget = function(el, config){
3891 this.el = Roo.get(el);
3893 Roo.apply(this, config);
3895 if(this.containerScroll){
3896 Roo.dd.ScrollManager.register(this.el);
3900 Roo.dd.DropTarget.superclass.constructor.call( this,
3902 this.ddGroup || this.group,
3907 * @scope Roo.dd.DropTarget
3912 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3913 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3914 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3916 * IMPORTANT : it should set this.overClass and this.dropAllowed
3918 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3919 * @param {Event} e The event
3920 * @param {Object} data An object containing arbitrary data supplied by the drag source
3926 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3927 * This method will be called on every mouse movement while the drag source is over the drop target.
3928 * This default implementation simply returns the dropAllowed config value.
3930 * IMPORTANT : it should set this.dropAllowed
3932 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3933 * @param {Event} e The event
3934 * @param {Object} data An object containing arbitrary data supplied by the drag source
3940 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3941 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3942 * overClass (if any) from the drop element.
3943 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3944 * @param {Event} e The event
3945 * @param {Object} data An object containing arbitrary data supplied by the drag source
3951 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3952 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3953 * implementation that does something to process the drop event and returns true so that the drag source's
3954 * repair action does not run.
3956 * IMPORTANT : it should set this.success
3958 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3959 * @param {Event} e The event
3960 * @param {Object} data An object containing arbitrary data supplied by the drag source
3971 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3973 * @cfg {String} overClass
3974 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3977 * @cfg {String} dropAllowed
3978 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3980 dropAllowed : "x-dd-drop-ok",
3982 * @cfg {String} dropNotAllowed
3983 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3985 dropNotAllowed : "x-dd-drop-nodrop",
3987 * @cfg {boolean} success
3988 * set this after drop listener..
3992 * @cfg {boolean} valid
3993 * if the drop point is valid for over/enter..
4000 isNotifyTarget : true,
4004 notifyEnter : function(dd, e, data){
4006 this.fireEvent('enter', this, dd, e, data);
4008 this.el.addClass(this.overClass);
4010 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4015 notifyOver : function(dd, e, data){
4017 this.fireEvent('over', this, dd, e, data);
4018 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4022 notifyOut : function(dd, e, data){
4023 this.fireEvent('out', this, dd, e, data);
4025 this.el.removeClass(this.overClass);
4030 notifyDrop : function(dd, e, data){
4031 this.success = false;
4032 this.fireEvent('drop', this, dd, e, data);
4033 return this.success;
4037 * Ext JS Library 1.1.1
4038 * Copyright(c) 2006-2007, Ext JS, LLC.
4040 * Originally Released Under LGPL - original licence link has changed is not relivant.
4043 * <script type="text/javascript">
4048 * @class Roo.dd.DragZone
4049 * @extends Roo.dd.DragSource
4050 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4051 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4053 * @param {String/HTMLElement/Element} el The container element
4054 * @param {Object} config
4056 Roo.dd.DragZone = function(el, config){
4057 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4058 if(this.containerScroll){
4059 Roo.dd.ScrollManager.register(this.el);
4063 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4065 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4066 * for auto scrolling during drag operations.
4069 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4070 * method after a failed drop (defaults to "c3daf9" - light blue)
4074 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4075 * for a valid target to drag based on the mouse down. Override this method
4076 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4077 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4078 * @param {EventObject} e The mouse down event
4079 * @return {Object} The dragData
4081 getDragData : function(e){
4082 return Roo.dd.Registry.getHandleFromEvent(e);
4086 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4087 * this.dragData.ddel
4088 * @param {Number} x The x position of the click on the dragged object
4089 * @param {Number} y The y position of the click on the dragged object
4090 * @return {Boolean} true to continue the drag, false to cancel
4092 onInitDrag : function(x, y){
4093 this.proxy.update(this.dragData.ddel.cloneNode(true));
4094 this.onStartDrag(x, y);
4099 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4101 afterRepair : function(){
4103 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4105 this.dragging = false;
4109 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4110 * the XY of this.dragData.ddel
4111 * @param {EventObject} e The mouse up event
4112 * @return {Array} The xy location (e.g. [100, 200])
4114 getRepairXY : function(e){
4115 return Roo.Element.fly(this.dragData.ddel).getXY();
4119 * Ext JS Library 1.1.1
4120 * Copyright(c) 2006-2007, Ext JS, LLC.
4122 * Originally Released Under LGPL - original licence link has changed is not relivant.
4125 * <script type="text/javascript">
4128 * @class Roo.dd.DropZone
4129 * @extends Roo.dd.DropTarget
4130 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4131 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4133 * @param {String/HTMLElement/Element} el The container element
4134 * @param {Object} config
4136 Roo.dd.DropZone = function(el, config){
4137 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4140 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4142 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4143 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4144 * provide your own custom lookup.
4145 * @param {Event} e The event
4146 * @return {Object} data The custom data
4148 getTargetFromEvent : function(e){
4149 return Roo.dd.Registry.getTargetFromEvent(e);
4153 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4154 * that it has registered. This method has no default implementation and should be overridden to provide
4155 * node-specific processing if necessary.
4156 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4157 * {@link #getTargetFromEvent} for this node)
4158 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4159 * @param {Event} e The event
4160 * @param {Object} data An object containing arbitrary data supplied by the drag source
4162 onNodeEnter : function(n, dd, e, data){
4167 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4168 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4169 * overridden to provide the proper feedback.
4170 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4171 * {@link #getTargetFromEvent} for this node)
4172 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4173 * @param {Event} e The event
4174 * @param {Object} data An object containing arbitrary data supplied by the drag source
4175 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4176 * underlying {@link Roo.dd.StatusProxy} can be updated
4178 onNodeOver : function(n, dd, e, data){
4179 return this.dropAllowed;
4183 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4184 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4185 * node-specific processing if necessary.
4186 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4187 * {@link #getTargetFromEvent} for this node)
4188 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4189 * @param {Event} e The event
4190 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 onNodeOut : function(n, dd, e, data){
4197 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4198 * the drop node. The default implementation returns false, so it should be overridden to provide the
4199 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4200 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4201 * {@link #getTargetFromEvent} for this node)
4202 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4203 * @param {Event} e The event
4204 * @param {Object} data An object containing arbitrary data supplied by the drag source
4205 * @return {Boolean} True if the drop was valid, else false
4207 onNodeDrop : function(n, dd, e, data){
4212 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4213 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4214 * it should be overridden to provide the proper feedback if necessary.
4215 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4216 * @param {Event} e The event
4217 * @param {Object} data An object containing arbitrary data supplied by the drag source
4218 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4219 * underlying {@link Roo.dd.StatusProxy} can be updated
4221 onContainerOver : function(dd, e, data){
4222 return this.dropNotAllowed;
4226 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4227 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4228 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4229 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4230 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4231 * @param {Event} e The event
4232 * @param {Object} data An object containing arbitrary data supplied by the drag source
4233 * @return {Boolean} True if the drop was valid, else false
4235 onContainerDrop : function(dd, e, data){
4240 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4241 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4242 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4243 * you should override this method and provide a custom implementation.
4244 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4245 * @param {Event} e The event
4246 * @param {Object} data An object containing arbitrary data supplied by the drag source
4247 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4248 * underlying {@link Roo.dd.StatusProxy} can be updated
4250 notifyEnter : function(dd, e, data){
4251 return this.dropNotAllowed;
4255 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4256 * This method will be called on every mouse movement while the drag source is over the drop zone.
4257 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4258 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4259 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4260 * registered node, it will call {@link #onContainerOver}.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyOver : function(dd, e, data){
4268 var n = this.getTargetFromEvent(e);
4269 if(!n){ // not over valid drop target
4270 if(this.lastOverNode){
4271 this.onNodeOut(this.lastOverNode, dd, e, data);
4272 this.lastOverNode = null;
4274 return this.onContainerOver(dd, e, data);
4276 if(this.lastOverNode != n){
4277 if(this.lastOverNode){
4278 this.onNodeOut(this.lastOverNode, dd, e, data);
4280 this.onNodeEnter(n, dd, e, data);
4281 this.lastOverNode = n;
4283 return this.onNodeOver(n, dd, e, data);
4287 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4288 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4289 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4290 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4291 * @param {Event} e The event
4292 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4294 notifyOut : function(dd, e, data){
4295 if(this.lastOverNode){
4296 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.lastOverNode = null;
4302 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4303 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4304 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4305 * otherwise it will call {@link #onContainerDrop}.
4306 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4307 * @param {Event} e The event
4308 * @param {Object} data An object containing arbitrary data supplied by the drag source
4309 * @return {Boolean} True if the drop was valid, else false
4311 notifyDrop : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4316 var n = this.getTargetFromEvent(e);
4318 this.onNodeDrop(n, dd, e, data) :
4319 this.onContainerDrop(dd, e, data);
4323 triggerCacheRefresh : function(){
4324 Roo.dd.DDM.refreshCache(this.groups);
4328 * Ext JS Library 1.1.1
4329 * Copyright(c) 2006-2007, Ext JS, LLC.
4331 * Originally Released Under LGPL - original licence link has changed is not relivant.
4334 * <script type="text/javascript">
4339 * @class Roo.data.SortTypes
4341 * Defines the default sorting (casting?) comparison functions used when sorting data.
4343 Roo.data.SortTypes = {
4345 * Default sort that does nothing
4346 * @param {Mixed} s The value being converted
4347 * @return {Mixed} The comparison value
4354 * The regular expression used to strip tags
4358 stripTagsRE : /<\/?[^>]+>/gi,
4361 * Strips all HTML tags to sort on text only
4362 * @param {Mixed} s The value being converted
4363 * @return {String} The comparison value
4365 asText : function(s){
4366 return String(s).replace(this.stripTagsRE, "");
4370 * Strips all HTML tags to sort on text only - Case insensitive
4371 * @param {Mixed} s The value being converted
4372 * @return {String} The comparison value
4374 asUCText : function(s){
4375 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4379 * Case insensitive string
4380 * @param {Mixed} s The value being converted
4381 * @return {String} The comparison value
4383 asUCString : function(s) {
4384 return String(s).toUpperCase();
4389 * @param {Mixed} s The value being converted
4390 * @return {Number} The comparison value
4392 asDate : function(s) {
4396 if(s instanceof Date){
4399 return Date.parse(String(s));
4404 * @param {Mixed} s The value being converted
4405 * @return {Float} The comparison value
4407 asFloat : function(s) {
4408 var val = parseFloat(String(s).replace(/,/g, ""));
4409 if(isNaN(val)) val = 0;
4415 * @param {Mixed} s The value being converted
4416 * @return {Number} The comparison value
4418 asInt : function(s) {
4419 var val = parseInt(String(s).replace(/,/g, ""));
4420 if(isNaN(val)) val = 0;
4425 * Ext JS Library 1.1.1
4426 * Copyright(c) 2006-2007, Ext JS, LLC.
4428 * Originally Released Under LGPL - original licence link has changed is not relivant.
4431 * <script type="text/javascript">
4435 * @class Roo.data.Record
4436 * Instances of this class encapsulate both record <em>definition</em> information, and record
4437 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4438 * to access Records cached in an {@link Roo.data.Store} object.<br>
4440 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4441 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4444 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4446 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4447 * {@link #create}. The parameters are the same.
4448 * @param {Array} data An associative Array of data values keyed by the field name.
4449 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4450 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4451 * not specified an integer id is generated.
4453 Roo.data.Record = function(data, id){
4454 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4459 * Generate a constructor for a specific record layout.
4460 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4461 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4462 * Each field definition object may contain the following properties: <ul>
4463 * <li><b>name</b> : String<p style="margin-left:1em">The name by which the field is referenced within the Record. This is referenced by,
4464 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4465 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4466 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4467 * is being used, then this is a string containing the javascript expression to reference the data relative to
4468 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4469 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4470 * this may be omitted.</p></li>
4471 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4472 * <ul><li>auto (Default, implies no conversion)</li>
4477 * <li>date</li></ul></p></li>
4478 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4479 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4480 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4481 * by the Reader into an object that will be stored in the Record. It is passed the
4482 * following parameters:<ul>
4483 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4485 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4487 * <br>usage:<br><pre><code>
4488 var TopicRecord = Roo.data.Record.create(
4489 {name: 'title', mapping: 'topic_title'},
4490 {name: 'author', mapping: 'username'},
4491 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4492 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4493 {name: 'lastPoster', mapping: 'user2'},
4494 {name: 'excerpt', mapping: 'post_text'}
4497 var myNewRecord = new TopicRecord({
4498 title: 'Do my job please',
4501 lastPost: new Date(),
4502 lastPoster: 'Animal',
4503 excerpt: 'No way dude!'
4505 myStore.add(myNewRecord);
4510 Roo.data.Record.create = function(o){
4512 f.superclass.constructor.apply(this, arguments);
4514 Roo.extend(f, Roo.data.Record);
4515 var p = f.prototype;
4516 p.fields = new Roo.util.MixedCollection(false, function(field){
4519 for(var i = 0, len = o.length; i < len; i++){
4520 p.fields.add(new Roo.data.Field(o[i]));
4522 f.getField = function(name){
4523 return p.fields.get(name);
4528 Roo.data.Record.AUTO_ID = 1000;
4529 Roo.data.Record.EDIT = 'edit';
4530 Roo.data.Record.REJECT = 'reject';
4531 Roo.data.Record.COMMIT = 'commit';
4533 Roo.data.Record.prototype = {
4535 * Readonly flag - true if this record has been modified.
4544 join : function(store){
4549 * Set the named field to the specified value.
4550 * @param {String} name The name of the field to set.
4551 * @param {Object} value The value to set the field to.
4553 set : function(name, value){
4554 if(this.data[name] == value){
4561 if(typeof this.modified[name] == 'undefined'){
4562 this.modified[name] = this.data[name];
4564 this.data[name] = value;
4566 this.store.afterEdit(this);
4571 * Get the value of the named field.
4572 * @param {String} name The name of the field to get the value of.
4573 * @return {Object} The value of the field.
4575 get : function(name){
4576 return this.data[name];
4580 beginEdit : function(){
4581 this.editing = true;
4586 cancelEdit : function(){
4587 this.editing = false;
4588 delete this.modified;
4592 endEdit : function(){
4593 this.editing = false;
4594 if(this.dirty && this.store){
4595 this.store.afterEdit(this);
4600 * Usually called by the {@link Roo.data.Store} which owns the Record.
4601 * Rejects all changes made to the Record since either creation, or the last commit operation.
4602 * Modified fields are reverted to their original values.
4604 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4605 * of reject operations.
4607 reject : function(){
4608 var m = this.modified;
4610 if(typeof m[n] != "function"){
4611 this.data[n] = m[n];
4615 delete this.modified;
4616 this.editing = false;
4618 this.store.afterReject(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Commits all changes made to the Record since either creation, or the last commit operation.
4626 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4627 * of commit operations.
4629 commit : function(){
4631 delete this.modified;
4632 this.editing = false;
4634 this.store.afterCommit(this);
4639 hasError : function(){
4640 return this.error != null;
4644 clearError : function(){
4649 * Creates a copy of this record.
4650 * @param {String} id (optional) A new record id if you don't want to use this record's id
4653 copy : function(newId) {
4654 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4658 * Ext JS Library 1.1.1
4659 * Copyright(c) 2006-2007, Ext JS, LLC.
4661 * Originally Released Under LGPL - original licence link has changed is not relivant.
4664 * <script type="text/javascript">
4670 * @class Roo.data.Store
4671 * @extends Roo.util.Observable
4672 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4673 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4675 * A Store object uses an implementation of {@link Roo.data.DataProxy} to access a data object unless you call loadData() directly and pass in your data. The Store object
4676 * has no knowledge of the format of the data returned by the Proxy.<br>
4678 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4679 * instances from the data object. These records are cached and made available through accessor functions.
4681 * Creates a new Store.
4682 * @param {Object} config A config object containing the objects needed for the Store to access data,
4683 * and read the data into Records.
4685 Roo.data.Store = function(config){
4686 this.data = new Roo.util.MixedCollection(false);
4687 this.data.getKey = function(o){
4690 this.baseParams = {};
4699 if(config && config.data){
4700 this.inlineData = config.data;
4704 Roo.apply(this, config);
4706 if(this.reader){ // reader passed
4707 this.reader = Roo.factory(this.reader, Roo.data);
4708 this.reader.xmodule = this.xmodule || false;
4709 if(!this.recordType){
4710 this.recordType = this.reader.recordType;
4712 if(this.reader.onMetaChange){
4713 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4717 if(this.recordType){
4718 this.fields = this.recordType.prototype.fields;
4724 * @event datachanged
4725 * Fires when the data cache has changed, and a widget which is using this Store
4726 * as a Record cache should refresh its view.
4727 * @param {Store} this
4732 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4733 * @param {Store} this
4734 * @param {Object} meta The JSON metadata
4739 * Fires when Records have been added to the Store
4740 * @param {Store} this
4741 * @param {Roo.data.Record[]} records The array of Records added
4742 * @param {Number} index The index at which the record(s) were added
4747 * Fires when a Record has been removed from the Store
4748 * @param {Store} this
4749 * @param {Roo.data.Record} record The Record that was removed
4750 * @param {Number} index The index at which the record was removed
4755 * Fires when a Record has been updated
4756 * @param {Store} this
4757 * @param {Roo.data.Record} record The Record that was updated
4758 * @param {String} operation The update operation being performed. Value may be one of:
4760 Roo.data.Record.EDIT
4761 Roo.data.Record.REJECT
4762 Roo.data.Record.COMMIT
4768 * Fires when the data cache has been cleared.
4769 * @param {Store} this
4774 * Fires before a request is made for a new data object. If the beforeload handler returns false
4775 * the load action will be canceled.
4776 * @param {Store} this
4777 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4782 * Fires after a new set of Records has been loaded.
4783 * @param {Store} this
4784 * @param {Roo.data.Record[]} records The Records that were loaded
4785 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4789 * @event loadexception
4790 * Fires if an exception occurs in the Proxy during loading.
4791 * Called with the signature of the Proxy's "loadexception" event.
4792 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4795 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4796 * @param {Object} load options
4797 * @param {Object} jsonData from your request (normally this contains the Exception)
4799 loadexception : true
4803 this.proxy = Roo.factory(this.proxy, Roo.data);
4804 this.proxy.xmodule = this.xmodule || false;
4805 this.relayEvents(this.proxy, ["loadexception"]);
4807 this.sortToggle = {};
4809 Roo.data.Store.superclass.constructor.call(this);
4811 if(this.inlineData){
4812 this.loadData(this.inlineData);
4813 delete this.inlineData;
4816 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4818 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4819 * without a remote query - used by combo/forms at present.
4823 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4826 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4829 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4830 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4833 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4834 * on any HTTP request
4837 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4840 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4841 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4846 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4847 * loaded or when a record is removed. (defaults to false).
4849 pruneModifiedRecords : false,
4855 * Add Records to the Store and fires the add event.
4856 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4858 add : function(records){
4859 records = [].concat(records);
4860 for(var i = 0, len = records.length; i < len; i++){
4861 records[i].join(this);
4863 var index = this.data.length;
4864 this.data.addAll(records);
4865 this.fireEvent("add", this, records, index);
4869 * Remove a Record from the Store and fires the remove event.
4870 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4872 remove : function(record){
4873 var index = this.data.indexOf(record);
4874 this.data.removeAt(index);
4875 if(this.pruneModifiedRecords){
4876 this.modified.remove(record);
4878 this.fireEvent("remove", this, record, index);
4882 * Remove all Records from the Store and fires the clear event.
4884 removeAll : function(){
4886 if(this.pruneModifiedRecords){
4889 this.fireEvent("clear", this);
4893 * Inserts Records to the Store at the given index and fires the add event.
4894 * @param {Number} index The start index at which to insert the passed Records.
4895 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4897 insert : function(index, records){
4898 records = [].concat(records);
4899 for(var i = 0, len = records.length; i < len; i++){
4900 this.data.insert(index, records[i]);
4901 records[i].join(this);
4903 this.fireEvent("add", this, records, index);
4907 * Get the index within the cache of the passed Record.
4908 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4909 * @return {Number} The index of the passed Record. Returns -1 if not found.
4911 indexOf : function(record){
4912 return this.data.indexOf(record);
4916 * Get the index within the cache of the Record with the passed id.
4917 * @param {String} id The id of the Record to find.
4918 * @return {Number} The index of the Record. Returns -1 if not found.
4920 indexOfId : function(id){
4921 return this.data.indexOfKey(id);
4925 * Get the Record with the specified id.
4926 * @param {String} id The id of the Record to find.
4927 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4929 getById : function(id){
4930 return this.data.key(id);
4934 * Get the Record at the specified index.
4935 * @param {Number} index The index of the Record to find.
4936 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4938 getAt : function(index){
4939 return this.data.itemAt(index);
4943 * Returns a range of Records between specified indices.
4944 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4945 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4946 * @return {Roo.data.Record[]} An array of Records
4948 getRange : function(start, end){
4949 return this.data.getRange(start, end);
4953 storeOptions : function(o){
4954 o = Roo.apply({}, o);
4957 this.lastOptions = o;
4961 * Loads the Record cache from the configured Proxy using the configured Reader.
4963 * If using remote paging, then the first load call must specify the <em>start</em>
4964 * and <em>limit</em> properties in the options.params property to establish the initial
4965 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4967 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4968 * and this call will return before the new data has been loaded. Perform any post-processing
4969 * in a callback function, or in a "load" event handler.</strong>
4971 * @param {Object} options An object containing properties which control loading options:<ul>
4972 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4973 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4974 * passed the following arguments:<ul>
4975 * <li>r : Roo.data.Record[]</li>
4976 * <li>options: Options object from the load call</li>
4977 * <li>success: Boolean success indicator</li></ul></li>
4978 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4979 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4982 load : function(options){
4983 options = options || {};
4984 if(this.fireEvent("beforeload", this, options) !== false){
4985 this.storeOptions(options);
4986 var p = Roo.apply(options.params || {}, this.baseParams);
4987 // if meta was not loaded from remote source.. try requesting it.
4988 if (!this.reader.metaFromRemote) {
4991 if(this.sortInfo && this.remoteSort){
4992 var pn = this.paramNames;
4993 p[pn["sort"]] = this.sortInfo.field;
4994 p[pn["dir"]] = this.sortInfo.direction;
4996 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5001 * Reloads the Record cache from the configured Proxy using the configured Reader and
5002 * the options from the last load operation performed.
5003 * @param {Object} options (optional) An object containing properties which may override the options
5004 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5005 * the most recently used options are reused).
5007 reload : function(options){
5008 this.load(Roo.applyIf(options||{}, this.lastOptions));
5012 // Called as a callback by the Reader during a load operation.
5013 loadRecords : function(o, options, success){
5014 if(!o || success === false){
5015 if(success !== false){
5016 this.fireEvent("load", this, [], options);
5018 if(options.callback){
5019 options.callback.call(options.scope || this, [], options, false);
5023 // if data returned failure - throw an exception.
5024 if (o.success === false) {
5025 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5028 var r = o.records, t = o.totalRecords || r.length;
5029 if(!options || options.add !== true){
5030 if(this.pruneModifiedRecords){
5033 for(var i = 0, len = r.length; i < len; i++){
5037 this.data = this.snapshot;
5038 delete this.snapshot;
5041 this.data.addAll(r);
5042 this.totalLength = t;
5044 this.fireEvent("datachanged", this);
5046 this.totalLength = Math.max(t, this.data.length+r.length);
5049 this.fireEvent("load", this, r, options);
5050 if(options.callback){
5051 options.callback.call(options.scope || this, r, options, true);
5056 * Loads data from a passed data block. A Reader which understands the format of the data
5057 * must have been configured in the constructor.
5058 * @param {Object} data The data block from which to read the Records. The format of the data expected
5059 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5060 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5062 loadData : function(o, append){
5063 var r = this.reader.readRecords(o);
5064 this.loadRecords(r, {add: append}, true);
5068 * Gets the number of cached records.
5070 * <em>If using paging, this may not be the total size of the dataset. If the data object
5071 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5072 * the data set size</em>
5074 getCount : function(){
5075 return this.data.length || 0;
5079 * Gets the total number of records in the dataset as returned by the server.
5081 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5082 * the dataset size</em>
5084 getTotalCount : function(){
5085 return this.totalLength || 0;
5089 * Returns the sort state of the Store as an object with two properties:
5091 field {String} The name of the field by which the Records are sorted
5092 direction {String} The sort order, "ASC" or "DESC"
5095 getSortState : function(){
5096 return this.sortInfo;
5100 applySort : function(){
5101 if(this.sortInfo && !this.remoteSort){
5102 var s = this.sortInfo, f = s.field;
5103 var st = this.fields.get(f).sortType;
5104 var fn = function(r1, r2){
5105 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5106 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5108 this.data.sort(s.direction, fn);
5109 if(this.snapshot && this.snapshot != this.data){
5110 this.snapshot.sort(s.direction, fn);
5116 * Sets the default sort column and order to be used by the next load operation.
5117 * @param {String} fieldName The name of the field to sort by.
5118 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5120 setDefaultSort : function(field, dir){
5121 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5126 * If remote sorting is used, the sort is performed on the server, and the cache is
5127 * reloaded. If local sorting is used, the cache is sorted internally.
5128 * @param {String} fieldName The name of the field to sort by.
5129 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5131 sort : function(fieldName, dir){
5132 var f = this.fields.get(fieldName);
5134 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5135 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5140 this.sortToggle[f.name] = dir;
5141 this.sortInfo = {field: f.name, direction: dir};
5142 if(!this.remoteSort){
5144 this.fireEvent("datachanged", this);
5146 this.load(this.lastOptions);
5151 * Calls the specified function for each of the Records in the cache.
5152 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5153 * Returning <em>false</em> aborts and exits the iteration.
5154 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5156 each : function(fn, scope){
5157 this.data.each(fn, scope);
5161 * Gets all records modified since the last commit. Modified records are persisted across load operations
5162 * (e.g., during paging).
5163 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5165 getModifiedRecords : function(){
5166 return this.modified;
5170 createFilterFn : function(property, value, anyMatch){
5171 if(!value.exec){ // not a regex
5172 value = String(value);
5173 if(value.length == 0){
5176 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5179 return value.test(r.data[property]);
5184 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5185 * @param {String} property A field on your records
5186 * @param {Number} start The record index to start at (defaults to 0)
5187 * @param {Number} end The last record index to include (defaults to length - 1)
5188 * @return {Number} The sum
5190 sum : function(property, start, end){
5191 var rs = this.data.items, v = 0;
5193 end = (end || end === 0) ? end : rs.length-1;
5195 for(var i = start; i <= end; i++){
5196 v += (rs[i].data[property] || 0);
5202 * Filter the records by a specified property.
5203 * @param {String} field A field on your records
5204 * @param {String/RegExp} value Either a string that the field
5205 * should start with or a RegExp to test against the field
5206 * @param {Boolean} anyMatch True to match any part not just the beginning
5208 filter : function(property, value, anyMatch){
5209 var fn = this.createFilterFn(property, value, anyMatch);
5210 return fn ? this.filterBy(fn) : this.clearFilter();
5214 * Filter by a function. The specified function will be called with each
5215 * record in this data source. If the function returns true the record is included,
5216 * otherwise it is filtered.
5217 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5218 * @param {Object} scope (optional) The scope of the function (defaults to this)
5220 filterBy : function(fn, scope){
5221 this.snapshot = this.snapshot || this.data;
5222 this.data = this.queryBy(fn, scope||this);
5223 this.fireEvent("datachanged", this);
5227 * Query the records by a specified property.
5228 * @param {String} field A field on your records
5229 * @param {String/RegExp} value Either a string that the field
5230 * should start with or a RegExp to test against the field
5231 * @param {Boolean} anyMatch True to match any part not just the beginning
5232 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5234 query : function(property, value, anyMatch){
5235 var fn = this.createFilterFn(property, value, anyMatch);
5236 return fn ? this.queryBy(fn) : this.data.clone();
5240 * Query by a function. The specified function will be called with each
5241 * record in this data source. If the function returns true the record is included
5243 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5244 * @param {Object} scope (optional) The scope of the function (defaults to this)
5245 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5247 queryBy : function(fn, scope){
5248 var data = this.snapshot || this.data;
5249 return data.filterBy(fn, scope||this);
5253 * Collects unique values for a particular dataIndex from this store.
5254 * @param {String} dataIndex The property to collect
5255 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5256 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5257 * @return {Array} An array of the unique values
5259 collect : function(dataIndex, allowNull, bypassFilter){
5260 var d = (bypassFilter === true && this.snapshot) ?
5261 this.snapshot.items : this.data.items;
5262 var v, sv, r = [], l = {};
5263 for(var i = 0, len = d.length; i < len; i++){
5264 v = d[i].data[dataIndex];
5266 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5275 * Revert to a view of the Record cache with no filtering applied.
5276 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5278 clearFilter : function(suppressEvent){
5279 if(this.snapshot && this.snapshot != this.data){
5280 this.data = this.snapshot;
5281 delete this.snapshot;
5282 if(suppressEvent !== true){
5283 this.fireEvent("datachanged", this);
5289 afterEdit : function(record){
5290 if(this.modified.indexOf(record) == -1){
5291 this.modified.push(record);
5293 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5297 afterReject : function(record){
5298 this.modified.remove(record);
5299 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5303 afterCommit : function(record){
5304 this.modified.remove(record);
5305 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5309 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5310 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5312 commitChanges : function(){
5313 var m = this.modified.slice(0);
5315 for(var i = 0, len = m.length; i < len; i++){
5321 * Cancel outstanding changes on all changed records.
5323 rejectChanges : function(){
5324 var m = this.modified.slice(0);
5326 for(var i = 0, len = m.length; i < len; i++){
5331 onMetaChange : function(meta, rtype, o){
5332 this.recordType = rtype;
5333 this.fields = rtype.prototype.fields;
5334 delete this.snapshot;
5335 this.sortInfo = meta.sortInfo || this.sortInfo;
5337 this.fireEvent('metachange', this, this.reader.meta);
5341 * Ext JS Library 1.1.1
5342 * Copyright(c) 2006-2007, Ext JS, LLC.
5344 * Originally Released Under LGPL - original licence link has changed is not relivant.
5347 * <script type="text/javascript">
5351 * @class Roo.data.SimpleStore
5352 * @extends Roo.data.Store
5353 * Small helper class to make creating Stores from Array data easier.
5354 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5355 * @cfg {Array} fields An array of field definition objects, or field name strings.
5356 * @cfg {Array} data The multi-dimensional array of data
5358 * @param {Object} config
5360 Roo.data.SimpleStore = function(config){
5361 Roo.data.SimpleStore.superclass.constructor.call(this, {
5363 reader: new Roo.data.ArrayReader({
5366 Roo.data.Record.create(config.fields)
5368 proxy : new Roo.data.MemoryProxy(config.data)
5372 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5374 * Ext JS Library 1.1.1
5375 * Copyright(c) 2006-2007, Ext JS, LLC.
5377 * Originally Released Under LGPL - original licence link has changed is not relivant.
5380 * <script type="text/javascript">
5385 * @extends Roo.data.Store
5386 * @class Roo.data.JsonStore
5387 * Small helper class to make creating Stores for JSON data easier. <br/>
5389 var store = new Roo.data.JsonStore({
5390 url: 'get-images.php',
5392 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5395 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5396 * JsonReader and HttpProxy (unless inline data is provided).</b>
5397 * @cfg {Array} fields An array of field definition objects, or field name strings.
5399 * @param {Object} config
5401 Roo.data.JsonStore = function(c){
5402 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5403 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5404 reader: new Roo.data.JsonReader(c, c.fields)
5407 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5409 * Ext JS Library 1.1.1
5410 * Copyright(c) 2006-2007, Ext JS, LLC.
5412 * Originally Released Under LGPL - original licence link has changed is not relivant.
5415 * <script type="text/javascript">
5419 Roo.data.Field = function(config){
5420 if(typeof config == "string"){
5421 config = {name: config};
5423 Roo.apply(this, config);
5429 var st = Roo.data.SortTypes;
5430 // named sortTypes are supported, here we look them up
5431 if(typeof this.sortType == "string"){
5432 this.sortType = st[this.sortType];
5435 // set default sortType for strings and dates
5439 this.sortType = st.asUCString;
5442 this.sortType = st.asDate;
5445 this.sortType = st.none;
5450 var stripRe = /[\$,%]/g;
5452 // prebuilt conversion function for this field, instead of
5453 // switching every time we're reading a value
5455 var cv, dateFormat = this.dateFormat;
5460 cv = function(v){ return v; };
5463 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5467 return v !== undefined && v !== null && v !== '' ?
5468 parseInt(String(v).replace(stripRe, ""), 10) : '';
5473 return v !== undefined && v !== null && v !== '' ?
5474 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5479 cv = function(v){ return v === true || v === "true" || v == 1; };
5486 if(v instanceof Date){
5490 if(dateFormat == "timestamp"){
5491 return new Date(v*1000);
5493 return Date.parseDate(v, dateFormat);
5495 var parsed = Date.parse(v);
5496 return parsed ? new Date(parsed) : null;
5505 Roo.data.Field.prototype = {
5513 * Ext JS Library 1.1.1
5514 * Copyright(c) 2006-2007, Ext JS, LLC.
5516 * Originally Released Under LGPL - original licence link has changed is not relivant.
5519 * <script type="text/javascript">
5522 // Base class for reading structured data from a data source. This class is intended to be
5523 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5526 * @class Roo.data.DataReader
5527 * Base class for reading structured data from a data source. This class is intended to be
5528 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5531 Roo.data.DataReader = function(meta, recordType){
5535 this.recordType = recordType instanceof Array ?
5536 Roo.data.Record.create(recordType) : recordType;
5539 Roo.data.DataReader.prototype = {
5541 * Create an empty record
5542 * @param {Object} data (optional) - overlay some values
5543 * @return {Roo.data.Record} record created.
5545 newRow : function(d) {
5547 this.recordType.prototype.fields.each(function(c) {
5549 case 'int' : da[c.name] = 0; break;
5550 case 'date' : da[c.name] = new Date(); break;
5551 case 'float' : da[c.name] = 0.0; break;
5552 case 'boolean' : da[c.name] = false; break;
5553 default : da[c.name] = ""; break;
5557 return new this.recordType(Roo.apply(da, d));
5562 * Ext JS Library 1.1.1
5563 * Copyright(c) 2006-2007, Ext JS, LLC.
5565 * Originally Released Under LGPL - original licence link has changed is not relivant.
5568 * <script type="text/javascript">
5572 * @class Roo.data.DataProxy
5573 * @extends Roo.data.Observable
5574 * This class is an abstract base class for implementations which provide retrieval of
5575 * unformatted data objects.<br>
5577 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5578 * (of the appropriate type which knows how to parse the data object) to provide a block of
5579 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5581 * Custom implementations must implement the load method as described in
5582 * {@link Roo.data.HttpProxy#load}.
5584 Roo.data.DataProxy = function(){
5588 * Fires before a network request is made to retrieve a data object.
5589 * @param {Object} This DataProxy object.
5590 * @param {Object} params The params parameter to the load function.
5595 * Fires before the load method's callback is called.
5596 * @param {Object} This DataProxy object.
5597 * @param {Object} o The data object.
5598 * @param {Object} arg The callback argument object passed to the load function.
5602 * @event loadexception
5603 * Fires if an Exception occurs during data retrieval.
5604 * @param {Object} This DataProxy object.
5605 * @param {Object} o The data object.
5606 * @param {Object} arg The callback argument object passed to the load function.
5607 * @param {Object} e The Exception.
5609 loadexception : true
5611 Roo.data.DataProxy.superclass.constructor.call(this);
5614 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5617 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5621 * Ext JS Library 1.1.1
5622 * Copyright(c) 2006-2007, Ext JS, LLC.
5624 * Originally Released Under LGPL - original licence link has changed is not relivant.
5627 * <script type="text/javascript">
5630 * @class Roo.data.MemoryProxy
5631 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5632 * to the Reader when its load method is called.
5634 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5636 Roo.data.MemoryProxy = function(data){
5640 Roo.data.MemoryProxy.superclass.constructor.call(this);
5644 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5646 * Load data from the requested source (in this case an in-memory
5647 * data object passed to the constructor), read the data object into
5648 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5649 * process that block using the passed callback.
5650 * @param {Object} params This parameter is not used by the MemoryProxy class.
5651 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5652 * object into a block of Roo.data.Records.
5653 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5654 * The function must be passed <ul>
5655 * <li>The Record block object</li>
5656 * <li>The "arg" argument from the load function</li>
5657 * <li>A boolean success indicator</li>
5659 * @param {Object} scope The scope in which to call the callback
5660 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5662 load : function(params, reader, callback, scope, arg){
5663 params = params || {};
5666 result = reader.readRecords(this.data);
5668 this.fireEvent("loadexception", this, arg, null, e);
5669 callback.call(scope, null, arg, false);
5672 callback.call(scope, result, arg, true);
5676 update : function(params, records){
5681 * Ext JS Library 1.1.1
5682 * Copyright(c) 2006-2007, Ext JS, LLC.
5684 * Originally Released Under LGPL - original licence link has changed is not relivant.
5687 * <script type="text/javascript">
5690 * @class Roo.data.HttpProxy
5691 * @extends Roo.data.DataProxy
5692 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5693 * configured to reference a certain URL.<br><br>
5695 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5696 * from which the running page was served.<br><br>
5698 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5700 * Be aware that to enable the browser to parse an XML document, the server must set
5701 * the Content-Type header in the HTTP response to "text/xml".
5703 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5704 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5705 * will be used to make the request.
5707 Roo.data.HttpProxy = function(conn){
5708 Roo.data.HttpProxy.superclass.constructor.call(this);
5709 // is conn a conn config or a real conn?
5711 this.useAjax = !conn || !conn.events;
5715 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5716 // thse are take from connection...
5719 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5722 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5723 * extra parameters to each request made by this object. (defaults to undefined)
5726 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5727 * to each request made by this object. (defaults to undefined)
5730 * @cfg {String} method (Optional) The default HTTP method to be used for requests. (defaults to undefined; if not set but parms are present will use POST, otherwise GET)
5733 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5736 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5742 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5746 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5747 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5748 * a finer-grained basis than the DataProxy events.
5750 getConnection : function(){
5751 return this.useAjax ? Roo.Ajax : this.conn;
5755 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5756 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5757 * process that block using the passed callback.
5758 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5759 * for the request to the remote server.
5760 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5761 * object into a block of Roo.data.Records.
5762 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5763 * The function must be passed <ul>
5764 * <li>The Record block object</li>
5765 * <li>The "arg" argument from the load function</li>
5766 * <li>A boolean success indicator</li>
5768 * @param {Object} scope The scope in which to call the callback
5769 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5771 load : function(params, reader, callback, scope, arg){
5772 if(this.fireEvent("beforeload", this, params) !== false){
5774 params : params || {},
5776 callback : callback,
5781 callback : this.loadResponse,
5785 Roo.applyIf(o, this.conn);
5786 if(this.activeRequest){
5787 Roo.Ajax.abort(this.activeRequest);
5789 this.activeRequest = Roo.Ajax.request(o);
5791 this.conn.request(o);
5794 callback.call(scope||this, null, arg, false);
5799 loadResponse : function(o, success, response){
5800 delete this.activeRequest;
5802 this.fireEvent("loadexception", this, o, response);
5803 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5808 result = o.reader.read(response);
5810 this.fireEvent("loadexception", this, o, response, e);
5811 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5815 this.fireEvent("load", this, o, o.request.arg);
5816 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5820 update : function(dataSet){
5825 updateResponse : function(dataSet){
5830 * Ext JS Library 1.1.1
5831 * Copyright(c) 2006-2007, Ext JS, LLC.
5833 * Originally Released Under LGPL - original licence link has changed is not relivant.
5836 * <script type="text/javascript">
5840 * @class Roo.data.ScriptTagProxy
5841 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5842 * other than the originating domain of the running page.<br><br>
5844 * <em>Note that if you are retrieving data from a page that is in a domain that is NOT the same as the originating domain
5845 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5847 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5848 * source code that is used as the source inside a <script> tag.<br><br>
5850 * In order for the browser to process the returned data, the server must wrap the data object
5851 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5852 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5853 * depending on whether the callback name was passed:
5856 boolean scriptTag = false;
5857 String cb = request.getParameter("callback");
5860 response.setContentType("text/javascript");
5862 response.setContentType("application/x-json");
5864 Writer out = response.getWriter();
5866 out.write(cb + "(");
5868 out.print(dataBlock.toJsonString());
5875 * @param {Object} config A configuration object.
5877 Roo.data.ScriptTagProxy = function(config){
5878 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5879 Roo.apply(this, config);
5880 this.head = document.getElementsByTagName("head")[0];
5883 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5885 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5887 * @cfg {String} url The URL from which to request the data object.
5890 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5894 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5895 * the server the name of the callback function set up by the load call to process the returned data object.
5896 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5897 * javascript output which calls this named function passing the data object as its only parameter.
5899 callbackParam : "callback",
5901 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5902 * name to the request.
5907 * Load data from the configured URL, read the data object into
5908 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5909 * process that block using the passed callback.
5910 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5911 * for the request to the remote server.
5912 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5913 * object into a block of Roo.data.Records.
5914 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5915 * The function must be passed <ul>
5916 * <li>The Record block object</li>
5917 * <li>The "arg" argument from the load function</li>
5918 * <li>A boolean success indicator</li>
5920 * @param {Object} scope The scope in which to call the callback
5921 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5923 load : function(params, reader, callback, scope, arg){
5924 if(this.fireEvent("beforeload", this, params) !== false){
5926 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5929 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5931 url += "&_dc=" + (new Date().getTime());
5933 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5936 cb : "stcCallback"+transId,
5937 scriptId : "stcScript"+transId,
5941 callback : callback,
5947 window[trans.cb] = function(o){
5948 conn.handleResponse(o, trans);
5951 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5953 if(this.autoAbort !== false){
5957 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5959 var script = document.createElement("script");
5960 script.setAttribute("src", url);
5961 script.setAttribute("type", "text/javascript");
5962 script.setAttribute("id", trans.scriptId);
5963 this.head.appendChild(script);
5967 callback.call(scope||this, null, arg, false);
5972 isLoading : function(){
5973 return this.trans ? true : false;
5977 * Abort the current server request.
5980 if(this.isLoading()){
5981 this.destroyTrans(this.trans);
5986 destroyTrans : function(trans, isLoaded){
5987 this.head.removeChild(document.getElementById(trans.scriptId));
5988 clearTimeout(trans.timeoutId);
5990 window[trans.cb] = undefined;
5992 delete window[trans.cb];
5995 // if hasn't been loaded, wait for load to remove it to prevent script error
5996 window[trans.cb] = function(){
5997 window[trans.cb] = undefined;
5999 delete window[trans.cb];
6006 handleResponse : function(o, trans){
6008 this.destroyTrans(trans, true);
6011 result = trans.reader.readRecords(o);
6013 this.fireEvent("loadexception", this, o, trans.arg, e);
6014 trans.callback.call(trans.scope||window, null, trans.arg, false);
6017 this.fireEvent("load", this, o, trans.arg);
6018 trans.callback.call(trans.scope||window, result, trans.arg, true);
6022 handleFailure : function(trans){
6024 this.destroyTrans(trans, false);
6025 this.fireEvent("loadexception", this, null, trans.arg);
6026 trans.callback.call(trans.scope||window, null, trans.arg, false);
6030 * Ext JS Library 1.1.1
6031 * Copyright(c) 2006-2007, Ext JS, LLC.
6033 * Originally Released Under LGPL - original licence link has changed is not relivant.
6036 * <script type="text/javascript">
6040 * @class Roo.data.JsonReader
6041 * @extends Roo.data.DataReader
6042 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6043 * based on mappings in a provided Roo.data.Record constructor.
6045 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6046 * in the reply previously.
6051 var RecordDef = Roo.data.Record.create([
6052 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6053 {name: 'occupation'} // This field will use "occupation" as the mapping.
6055 var myReader = new Roo.data.JsonReader({
6056 totalProperty: "results", // The property which contains the total dataset size (optional)
6057 root: "rows", // The property which contains an Array of row objects
6058 id: "id" // The property within each row object that provides an ID for the record (optional)
6062 * This would consume a JSON file like this:
6064 { 'results': 2, 'rows': [
6065 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6066 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6069 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6070 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6071 * paged from the remote server.
6072 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6073 * @cfg {String} root name of the property which contains the Array of row objects.
6074 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6076 * Create a new JsonReader
6077 * @param {Object} meta Metadata configuration options
6078 * @param {Object} recordType Either an Array of field definition objects,
6079 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6081 Roo.data.JsonReader = function(meta, recordType){
6084 // set some defaults:
6086 totalProperty: 'total',
6087 successProperty : 'success',
6092 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6094 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6097 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6098 * Used by Store query builder to append _requestMeta to params.
6101 metaFromRemote : false,
6103 * This method is only used by a DataProxy which has retrieved data from a remote server.
6104 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6105 * @return {Object} data A data block which is used by an Roo.data.Store object as
6106 * a cache of Roo.data.Records.
6108 read : function(response){
6109 var json = response.responseText;
6111 var o = /* eval:var:o */ eval("("+json+")");
6113 throw {message: "JsonReader.read: Json object not found"};
6119 this.metaFromRemote = true;
6120 this.meta = o.metaData;
6121 this.recordType = Roo.data.Record.create(o.metaData.fields);
6122 this.onMetaChange(this.meta, this.recordType, o);
6124 return this.readRecords(o);
6127 // private function a store will implement
6128 onMetaChange : function(meta, recordType, o){
6135 simpleAccess: function(obj, subsc) {
6142 getJsonAccessor: function(){
6144 return function(expr) {
6146 return(re.test(expr))
6147 ? new Function("obj", "return obj." + expr)
6157 * Create a data block containing Roo.data.Records from an XML document.
6158 * @param {Object} o An object which contains an Array of row objects in the property specified
6159 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6160 * which contains the total size of the dataset.
6161 * @return {Object} data A data block which is used by an Roo.data.Store object as
6162 * a cache of Roo.data.Records.
6164 readRecords : function(o){
6166 * After any data loads, the raw JSON data is available for further custom processing.
6170 var s = this.meta, Record = this.recordType,
6171 f = Record.prototype.fields, fi = f.items, fl = f.length;
6173 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6175 if(s.totalProperty) {
6176 this.getTotal = this.getJsonAccessor(s.totalProperty);
6178 if(s.successProperty) {
6179 this.getSuccess = this.getJsonAccessor(s.successProperty);
6181 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6183 var g = this.getJsonAccessor(s.id);
6184 this.getId = function(rec) {
6186 return (r === undefined || r === "") ? null : r;
6189 this.getId = function(){return null;};
6192 for(var jj = 0; jj < fl; jj++){
6194 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6195 this.ef[jj] = this.getJsonAccessor(map);
6199 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6200 if(s.totalProperty){
6201 var vt = parseInt(this.getTotal(o), 10);
6206 if(s.successProperty){
6207 var vs = this.getSuccess(o);
6208 if(vs === false || vs === 'false'){
6213 for(var i = 0; i < c; i++){
6216 var id = this.getId(n);
6217 for(var j = 0; j < fl; j++){
6219 var v = this.ef[j](n);
6221 Roo.log('missing convert for ' + f.name);
6225 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6227 var record = new Record(values, id);
6229 records[i] = record;
6234 totalRecords : totalRecords
6239 * Ext JS Library 1.1.1
6240 * Copyright(c) 2006-2007, Ext JS, LLC.
6242 * Originally Released Under LGPL - original licence link has changed is not relivant.
6245 * <script type="text/javascript">
6249 * @class Roo.data.XmlReader
6250 * @extends Roo.data.DataReader
6251 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6252 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6254 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6255 * header in the HTTP response must be set to "text/xml".</em>
6259 var RecordDef = Roo.data.Record.create([
6260 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6261 {name: 'occupation'} // This field will use "occupation" as the mapping.
6263 var myReader = new Roo.data.XmlReader({
6264 totalRecords: "results", // The element which contains the total dataset size (optional)
6265 record: "row", // The repeated element which contains row information
6266 id: "id" // The element within the row that provides an ID for the record (optional)
6270 * This would consume an XML file like this:
6274 <results>2</results>
6277 <name>Bill</name>
6278 <occupation>Gardener</occupation>
6282 <name>Ben</name>
6283 <occupation>Horticulturalist</occupation>
6287 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6288 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6289 * paged from the remote server.
6290 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6291 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6292 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6293 * a record identifier value.
6295 * Create a new XmlReader
6296 * @param {Object} meta Metadata configuration options
6297 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6298 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6299 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6301 Roo.data.XmlReader = function(meta, recordType){
6303 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6305 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6307 * This method is only used by a DataProxy which has retrieved data from a remote server.
6308 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6309 * to contain a method called 'responseXML' that returns an XML document object.
6310 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6311 * a cache of Roo.data.Records.
6313 read : function(response){
6314 var doc = response.responseXML;
6316 throw {message: "XmlReader.read: XML Document not available"};
6318 return this.readRecords(doc);
6322 * Create a data block containing Roo.data.Records from an XML document.
6323 * @param {Object} doc A parsed XML document.
6324 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6325 * a cache of Roo.data.Records.
6327 readRecords : function(doc){
6329 * After any data loads/reads, the raw XML Document is available for further custom processing.
6333 var root = doc.documentElement || doc;
6334 var q = Roo.DomQuery;
6335 var recordType = this.recordType, fields = recordType.prototype.fields;
6336 var sid = this.meta.id;
6337 var totalRecords = 0, success = true;
6338 if(this.meta.totalRecords){
6339 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6342 if(this.meta.success){
6343 var sv = q.selectValue(this.meta.success, root, true);
6344 success = sv !== false && sv !== 'false';
6347 var ns = q.select(this.meta.record, root);
6348 for(var i = 0, len = ns.length; i < len; i++) {
6351 var id = sid ? q.selectValue(sid, n) : undefined;
6352 for(var j = 0, jlen = fields.length; j < jlen; j++){
6353 var f = fields.items[j];
6354 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6358 var record = new recordType(values, id);
6360 records[records.length] = record;
6366 totalRecords : totalRecords || records.length
6371 * Ext JS Library 1.1.1
6372 * Copyright(c) 2006-2007, Ext JS, LLC.
6374 * Originally Released Under LGPL - original licence link has changed is not relivant.
6377 * <script type="text/javascript">
6381 * @class Roo.data.ArrayReader
6382 * @extends Roo.data.DataReader
6383 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6384 * Each element of that Array represents a row of data fields. The
6385 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6386 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6390 var RecordDef = Roo.data.Record.create([
6391 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6392 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6394 var myReader = new Roo.data.ArrayReader({
6395 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6399 * This would consume an Array like this:
6401 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6403 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6405 * Create a new JsonReader
6406 * @param {Object} meta Metadata configuration options.
6407 * @param {Object} recordType Either an Array of field definition objects
6408 * as specified to {@link Roo.data.Record#create},
6409 * or an {@link Roo.data.Record} object
6410 * created using {@link Roo.data.Record#create}.
6412 Roo.data.ArrayReader = function(meta, recordType){
6413 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6416 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6418 * Create a data block containing Roo.data.Records from an XML document.
6419 * @param {Object} o An Array of row objects which represents the dataset.
6420 * @return {Object} data A data block which is used by an Roo.data.Store object as
6421 * a cache of Roo.data.Records.
6423 readRecords : function(o){
6424 var sid = this.meta ? this.meta.id : null;
6425 var recordType = this.recordType, fields = recordType.prototype.fields;
6428 for(var i = 0; i < root.length; i++){
6431 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6432 for(var j = 0, jlen = fields.length; j < jlen; j++){
6433 var f = fields.items[j];
6434 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6435 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6439 var record = new recordType(values, id);
6441 records[records.length] = record;
6445 totalRecords : records.length
6450 * Ext JS Library 1.1.1
6451 * Copyright(c) 2006-2007, Ext JS, LLC.
6453 * Originally Released Under LGPL - original licence link has changed is not relivant.
6456 * <script type="text/javascript">
6461 * @class Roo.data.Tree
6462 * @extends Roo.util.Observable
6463 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6464 * in the tree have most standard DOM functionality.
6466 * @param {Node} root (optional) The root node
6468 Roo.data.Tree = function(root){
6471 * The root node for this tree
6476 this.setRootNode(root);
6481 * Fires when a new child node is appended to a node in this tree.
6482 * @param {Tree} tree The owner tree
6483 * @param {Node} parent The parent node
6484 * @param {Node} node The newly appended node
6485 * @param {Number} index The index of the newly appended node
6490 * Fires when a child node is removed from a node in this tree.
6491 * @param {Tree} tree The owner tree
6492 * @param {Node} parent The parent node
6493 * @param {Node} node The child node removed
6498 * Fires when a node is moved to a new location in the tree
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} node The node moved
6501 * @param {Node} oldParent The old parent of this node
6502 * @param {Node} newParent The new parent of this node
6503 * @param {Number} index The index it was moved to
6508 * Fires when a new child node is inserted in a node in this tree.
6509 * @param {Tree} tree The owner tree
6510 * @param {Node} parent The parent node
6511 * @param {Node} node The child node inserted
6512 * @param {Node} refNode The child node the node was inserted before
6516 * @event beforeappend
6517 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6518 * @param {Tree} tree The owner tree
6519 * @param {Node} parent The parent node
6520 * @param {Node} node The child node to be appended
6522 "beforeappend" : true,
6524 * @event beforeremove
6525 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node to be removed
6530 "beforeremove" : true,
6533 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6534 * @param {Tree} tree The owner tree
6535 * @param {Node} node The node being moved
6536 * @param {Node} oldParent The parent of the node
6537 * @param {Node} newParent The new parent the node is moving to
6538 * @param {Number} index The index it is being moved to
6540 "beforemove" : true,
6542 * @event beforeinsert
6543 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6544 * @param {Tree} tree The owner tree
6545 * @param {Node} parent The parent node
6546 * @param {Node} node The child node to be inserted
6547 * @param {Node} refNode The child node the node is being inserted before
6549 "beforeinsert" : true
6552 Roo.data.Tree.superclass.constructor.call(this);
6555 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6558 proxyNodeEvent : function(){
6559 return this.fireEvent.apply(this, arguments);
6563 * Returns the root node for this tree.
6566 getRootNode : function(){
6571 * Sets the root node for this tree.
6572 * @param {Node} node
6575 setRootNode : function(node){
6577 node.ownerTree = this;
6579 this.registerNode(node);
6584 * Gets a node in this tree by its id.
6585 * @param {String} id
6588 getNodeById : function(id){
6589 return this.nodeHash[id];
6592 registerNode : function(node){
6593 this.nodeHash[node.id] = node;
6596 unregisterNode : function(node){
6597 delete this.nodeHash[node.id];
6600 toString : function(){
6601 return "[Tree"+(this.id?" "+this.id:"")+"]";
6606 * @class Roo.data.Node
6607 * @extends Roo.util.Observable
6608 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6609 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6611 * @param {Object} attributes The attributes/config for the node
6613 Roo.data.Node = function(attributes){
6615 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6618 this.attributes = attributes || {};
6619 this.leaf = this.attributes.leaf;
6621 * The node id. @type String
6623 this.id = this.attributes.id;
6625 this.id = Roo.id(null, "ynode-");
6626 this.attributes.id = this.id;
6629 * All child nodes of this node. @type Array
6631 this.childNodes = [];
6632 if(!this.childNodes.indexOf){ // indexOf is a must
6633 this.childNodes.indexOf = function(o){
6634 for(var i = 0, len = this.length; i < len; i++){
6643 * The parent node for this node. @type Node
6645 this.parentNode = null;
6647 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6649 this.firstChild = null;
6651 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6653 this.lastChild = null;
6655 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6657 this.previousSibling = null;
6659 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6661 this.nextSibling = null;
6666 * Fires when a new child node is appended
6667 * @param {Tree} tree The owner tree
6668 * @param {Node} this This node
6669 * @param {Node} node The newly appended node
6670 * @param {Number} index The index of the newly appended node
6675 * Fires when a child node is removed
6676 * @param {Tree} tree The owner tree
6677 * @param {Node} this This node
6678 * @param {Node} node The removed node
6683 * Fires when this node is moved to a new location in the tree
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} oldParent The old parent of this node
6687 * @param {Node} newParent The new parent of this node
6688 * @param {Number} index The index it was moved to
6693 * Fires when a new child node is inserted.
6694 * @param {Tree} tree The owner tree
6695 * @param {Node} this This node
6696 * @param {Node} node The child node inserted
6697 * @param {Node} refNode The child node the node was inserted before
6701 * @event beforeappend
6702 * Fires before a new child is appended, return false to cancel the append.
6703 * @param {Tree} tree The owner tree
6704 * @param {Node} this This node
6705 * @param {Node} node The child node to be appended
6707 "beforeappend" : true,
6709 * @event beforeremove
6710 * Fires before a child is removed, return false to cancel the remove.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node to be removed
6715 "beforeremove" : true,
6718 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6719 * @param {Tree} tree The owner tree
6720 * @param {Node} this This node
6721 * @param {Node} oldParent The parent of this node
6722 * @param {Node} newParent The new parent this node is moving to
6723 * @param {Number} index The index it is being moved to
6725 "beforemove" : true,
6727 * @event beforeinsert
6728 * Fires before a new child is inserted, return false to cancel the insert.
6729 * @param {Tree} tree The owner tree
6730 * @param {Node} this This node
6731 * @param {Node} node The child node to be inserted
6732 * @param {Node} refNode The child node the node is being inserted before
6734 "beforeinsert" : true
6736 this.listeners = this.attributes.listeners;
6737 Roo.data.Node.superclass.constructor.call(this);
6740 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6741 fireEvent : function(evtName){
6742 // first do standard event for this node
6743 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6746 // then bubble it up to the tree if the event wasn't cancelled
6747 var ot = this.getOwnerTree();
6749 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6757 * Returns true if this node is a leaf
6760 isLeaf : function(){
6761 return this.leaf === true;
6765 setFirstChild : function(node){
6766 this.firstChild = node;
6770 setLastChild : function(node){
6771 this.lastChild = node;
6776 * Returns true if this node is the last child of its parent
6779 isLast : function(){
6780 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6784 * Returns true if this node is the first child of its parent
6787 isFirst : function(){
6788 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6791 hasChildNodes : function(){
6792 return !this.isLeaf() && this.childNodes.length > 0;
6796 * Insert node(s) as the last child node of this node.
6797 * @param {Node/Array} node The node or Array of nodes to append
6798 * @return {Node} The appended node if single append, or null if an array was passed
6800 appendChild : function(node){
6802 if(node instanceof Array){
6804 }else if(arguments.length > 1){
6807 // if passed an array or multiple args do them one by one
6809 for(var i = 0, len = multi.length; i < len; i++) {
6810 this.appendChild(multi[i]);
6813 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6816 var index = this.childNodes.length;
6817 var oldParent = node.parentNode;
6818 // it's a move, make sure we move it cleanly
6820 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6823 oldParent.removeChild(node);
6825 index = this.childNodes.length;
6827 this.setFirstChild(node);
6829 this.childNodes.push(node);
6830 node.parentNode = this;
6831 var ps = this.childNodes[index-1];
6833 node.previousSibling = ps;
6834 ps.nextSibling = node;
6836 node.previousSibling = null;
6838 node.nextSibling = null;
6839 this.setLastChild(node);
6840 node.setOwnerTree(this.getOwnerTree());
6841 this.fireEvent("append", this.ownerTree, this, node, index);
6843 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6850 * Removes a child node from this node.
6851 * @param {Node} node The node to remove
6852 * @return {Node} The removed node
6854 removeChild : function(node){
6855 var index = this.childNodes.indexOf(node);
6859 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6863 // remove it from childNodes collection
6864 this.childNodes.splice(index, 1);
6867 if(node.previousSibling){
6868 node.previousSibling.nextSibling = node.nextSibling;
6870 if(node.nextSibling){
6871 node.nextSibling.previousSibling = node.previousSibling;
6874 // update child refs
6875 if(this.firstChild == node){
6876 this.setFirstChild(node.nextSibling);
6878 if(this.lastChild == node){
6879 this.setLastChild(node.previousSibling);
6882 node.setOwnerTree(null);
6883 // clear any references from the node
6884 node.parentNode = null;
6885 node.previousSibling = null;
6886 node.nextSibling = null;
6887 this.fireEvent("remove", this.ownerTree, this, node);
6892 * Inserts the first node before the second node in this nodes childNodes collection.
6893 * @param {Node} node The node to insert
6894 * @param {Node} refNode The node to insert before (if null the node is appended)
6895 * @return {Node} The inserted node
6897 insertBefore : function(node, refNode){
6898 if(!refNode){ // like standard Dom, refNode can be null for append
6899 return this.appendChild(node);
6902 if(node == refNode){
6906 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6909 var index = this.childNodes.indexOf(refNode);
6910 var oldParent = node.parentNode;
6911 var refIndex = index;
6913 // when moving internally, indexes will change after remove
6914 if(oldParent == this && this.childNodes.indexOf(node) < index){
6918 // it's a move, make sure we move it cleanly
6920 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6923 oldParent.removeChild(node);
6926 this.setFirstChild(node);
6928 this.childNodes.splice(refIndex, 0, node);
6929 node.parentNode = this;
6930 var ps = this.childNodes[refIndex-1];
6932 node.previousSibling = ps;
6933 ps.nextSibling = node;
6935 node.previousSibling = null;
6937 node.nextSibling = refNode;
6938 refNode.previousSibling = node;
6939 node.setOwnerTree(this.getOwnerTree());
6940 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6942 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6948 * Returns the child node at the specified index.
6949 * @param {Number} index
6952 item : function(index){
6953 return this.childNodes[index];
6957 * Replaces one child node in this node with another.
6958 * @param {Node} newChild The replacement node
6959 * @param {Node} oldChild The node to replace
6960 * @return {Node} The replaced node
6962 replaceChild : function(newChild, oldChild){
6963 this.insertBefore(newChild, oldChild);
6964 this.removeChild(oldChild);
6969 * Returns the index of a child node
6970 * @param {Node} node
6971 * @return {Number} The index of the node or -1 if it was not found
6973 indexOf : function(child){
6974 return this.childNodes.indexOf(child);
6978 * Returns the tree this node is in.
6981 getOwnerTree : function(){
6982 // if it doesn't have one, look for one
6983 if(!this.ownerTree){
6987 this.ownerTree = p.ownerTree;
6993 return this.ownerTree;
6997 * Returns depth of this node (the root node has a depth of 0)
7000 getDepth : function(){
7003 while(p.parentNode){
7011 setOwnerTree : function(tree){
7012 // if it's move, we need to update everyone
7013 if(tree != this.ownerTree){
7015 this.ownerTree.unregisterNode(this);
7017 this.ownerTree = tree;
7018 var cs = this.childNodes;
7019 for(var i = 0, len = cs.length; i < len; i++) {
7020 cs[i].setOwnerTree(tree);
7023 tree.registerNode(this);
7029 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7030 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7031 * @return {String} The path
7033 getPath : function(attr){
7034 attr = attr || "id";
7035 var p = this.parentNode;
7036 var b = [this.attributes[attr]];
7038 b.unshift(p.attributes[attr]);
7041 var sep = this.getOwnerTree().pathSeparator;
7042 return sep + b.join(sep);
7046 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7047 * function call will be the scope provided or the current node. The arguments to the function
7048 * will be the args provided or the current node. If the function returns false at any point,
7049 * the bubble is stopped.
7050 * @param {Function} fn The function to call
7051 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7052 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7054 bubble : function(fn, scope, args){
7057 if(fn.call(scope || p, args || p) === false){
7065 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7066 * function call will be the scope provided or the current node. The arguments to the function
7067 * will be the args provided or the current node. If the function returns false at any point,
7068 * the cascade is stopped on that branch.
7069 * @param {Function} fn The function to call
7070 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7071 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7073 cascade : function(fn, scope, args){
7074 if(fn.call(scope || this, args || this) !== false){
7075 var cs = this.childNodes;
7076 for(var i = 0, len = cs.length; i < len; i++) {
7077 cs[i].cascade(fn, scope, args);
7083 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7084 * function call will be the scope provided or the current node. The arguments to the function
7085 * will be the args provided or the current node. If the function returns false at any point,
7086 * the iteration stops.
7087 * @param {Function} fn The function to call
7088 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7089 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7091 eachChild : function(fn, scope, args){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 if(fn.call(scope || this, args || cs[i]) === false){
7101 * Finds the first child that has the attribute with the specified value.
7102 * @param {String} attribute The attribute name
7103 * @param {Mixed} value The value to search for
7104 * @return {Node} The found child or null if none was found
7106 findChild : function(attribute, value){
7107 var cs = this.childNodes;
7108 for(var i = 0, len = cs.length; i < len; i++) {
7109 if(cs[i].attributes[attribute] == value){
7117 * Finds the first child by a custom function. The child matches if the function passed
7119 * @param {Function} fn
7120 * @param {Object} scope (optional)
7121 * @return {Node} The found child or null if none was found
7123 findChildBy : function(fn, scope){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(fn.call(scope||cs[i], cs[i]) === true){
7134 * Sorts this nodes children using the supplied sort function
7135 * @param {Function} fn
7136 * @param {Object} scope (optional)
7138 sort : function(fn, scope){
7139 var cs = this.childNodes;
7140 var len = cs.length;
7142 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7144 for(var i = 0; i < len; i++){
7146 n.previousSibling = cs[i-1];
7147 n.nextSibling = cs[i+1];
7149 this.setFirstChild(n);
7152 this.setLastChild(n);
7159 * Returns true if this node is an ancestor (at any point) of the passed node.
7160 * @param {Node} node
7163 contains : function(node){
7164 return node.isAncestor(this);
7168 * Returns true if the passed node is an ancestor (at any point) of this node.
7169 * @param {Node} node
7172 isAncestor : function(node){
7173 var p = this.parentNode;
7183 toString : function(){
7184 return "[Node"+(this.id?" "+this.id:"")+"]";
7188 * Ext JS Library 1.1.1
7189 * Copyright(c) 2006-2007, Ext JS, LLC.
7191 * Originally Released Under LGPL - original licence link has changed is not relivant.
7194 * <script type="text/javascript">
7199 * @class Roo.ComponentMgr
7200 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7203 Roo.ComponentMgr = function(){
7204 var all = new Roo.util.MixedCollection();
7208 * Registers a component.
7209 * @param {Roo.Component} c The component
7211 register : function(c){
7216 * Unregisters a component.
7217 * @param {Roo.Component} c The component
7219 unregister : function(c){
7224 * Returns a component by id
7225 * @param {String} id The component id
7232 * Registers a function that will be called when a specified component is added to ComponentMgr
7233 * @param {String} id The component id
7234 * @param {Funtction} fn The callback function
7235 * @param {Object} scope The scope of the callback
7237 onAvailable : function(id, fn, scope){
7238 all.on("add", function(index, o){
7240 fn.call(scope || o, o);
7241 all.un("add", fn, scope);
7248 * Ext JS Library 1.1.1
7249 * Copyright(c) 2006-2007, Ext JS, LLC.
7251 * Originally Released Under LGPL - original licence link has changed is not relivant.
7254 * <script type="text/javascript">
7258 * @class Roo.Component
7259 * @extends Roo.util.Observable
7260 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7261 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7262 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7263 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7264 * All visual components (widgets) that require rendering into a layout should subclass Component.
7266 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7267 * element and its id used as the component id. If a string is passed, it is assumed to be the id of an existing element
7268 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7270 Roo.Component = function(config){
7271 config = config || {};
7272 if(config.tagName || config.dom || typeof config == "string"){ // element object
7273 config = {el: config, id: config.id || config};
7275 this.initialConfig = config;
7277 Roo.apply(this, config);
7281 * Fires after the component is disabled.
7282 * @param {Roo.Component} this
7287 * Fires after the component is enabled.
7288 * @param {Roo.Component} this
7293 * Fires before the component is shown. Return false to stop the show.
7294 * @param {Roo.Component} this
7299 * Fires after the component is shown.
7300 * @param {Roo.Component} this
7305 * Fires before the component is hidden. Return false to stop the hide.
7306 * @param {Roo.Component} this
7311 * Fires after the component is hidden.
7312 * @param {Roo.Component} this
7316 * @event beforerender
7317 * Fires before the component is rendered. Return false to stop the render.
7318 * @param {Roo.Component} this
7320 beforerender : true,
7323 * Fires after the component is rendered.
7324 * @param {Roo.Component} this
7328 * @event beforedestroy
7329 * Fires before the component is destroyed. Return false to stop the destroy.
7330 * @param {Roo.Component} this
7332 beforedestroy : true,
7335 * Fires after the component is destroyed.
7336 * @param {Roo.Component} this
7341 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7343 Roo.ComponentMgr.register(this);
7344 Roo.Component.superclass.constructor.call(this);
7345 this.initComponent();
7346 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7347 this.render(this.renderTo);
7348 delete this.renderTo;
7353 Roo.Component.AUTO_ID = 1000;
7355 Roo.extend(Roo.Component, Roo.util.Observable, {
7357 * @property {Boolean} hidden
7358 * true if this component is hidden. Read-only.
7362 * true if this component is disabled. Read-only.
7366 * true if this component has been rendered. Read-only.
7370 /** @cfg {String} disableClass
7371 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7373 disabledClass : "x-item-disabled",
7374 /** @cfg {Boolean} allowDomMove
7375 * Whether the component can move the Dom node when rendering (defaults to true).
7377 allowDomMove : true,
7378 /** @cfg {String} hideMode
7379 * How this component should hidden. Supported values are
7380 * "visibility" (css visibility), "offsets" (negative offset position) and
7381 * "display" (css display) - defaults to "display".
7383 hideMode: 'display',
7386 ctype : "Roo.Component",
7388 /** @cfg {String} actionMode
7389 * which property holds the element that used for hide() / show() / disable() / enable()
7395 getActionEl : function(){
7396 return this[this.actionMode];
7399 initComponent : Roo.emptyFn,
7401 * If this is a lazy rendering component, render it to its container element.
7402 * @param {String/HTMLElement/Element} container (optional) The element this component should be rendered into. If it is being applied to existing markup, this should be left off.
7404 render : function(container, position){
7405 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7406 if(!container && this.el){
7407 this.el = Roo.get(this.el);
7408 container = this.el.dom.parentNode;
7409 this.allowDomMove = false;
7411 this.container = Roo.get(container);
7412 this.rendered = true;
7413 if(position !== undefined){
7414 if(typeof position == 'number'){
7415 position = this.container.dom.childNodes[position];
7417 position = Roo.getDom(position);
7420 this.onRender(this.container, position || null);
7422 this.el.addClass(this.cls);
7426 this.el.applyStyles(this.style);
7429 this.fireEvent("render", this);
7430 this.afterRender(this.container);
7442 // default function is not really useful
7443 onRender : function(ct, position){
7445 this.el = Roo.get(this.el);
7446 if(this.allowDomMove !== false){
7447 ct.dom.insertBefore(this.el.dom, position);
7453 getAutoCreate : function(){
7454 var cfg = typeof this.autoCreate == "object" ?
7455 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7456 if(this.id && !cfg.id){
7463 afterRender : Roo.emptyFn,
7466 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7467 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7469 destroy : function(){
7470 if(this.fireEvent("beforedestroy", this) !== false){
7471 this.purgeListeners();
7472 this.beforeDestroy();
7474 this.el.removeAllListeners();
7476 if(this.actionMode == "container"){
7477 this.container.remove();
7481 Roo.ComponentMgr.unregister(this);
7482 this.fireEvent("destroy", this);
7487 beforeDestroy : function(){
7492 onDestroy : function(){
7497 * Returns the underlying {@link Roo.Element}.
7498 * @return {Roo.Element} The element
7505 * Returns the id of this component.
7513 * Try to focus this component.
7514 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7515 * @return {Roo.Component} this
7517 focus : function(selectText){
7520 if(selectText === true){
7521 this.el.dom.select();
7536 * Disable this component.
7537 * @return {Roo.Component} this
7539 disable : function(){
7543 this.disabled = true;
7544 this.fireEvent("disable", this);
7549 onDisable : function(){
7550 this.getActionEl().addClass(this.disabledClass);
7551 this.el.dom.disabled = true;
7555 * Enable this component.
7556 * @return {Roo.Component} this
7558 enable : function(){
7562 this.disabled = false;
7563 this.fireEvent("enable", this);
7568 onEnable : function(){
7569 this.getActionEl().removeClass(this.disabledClass);
7570 this.el.dom.disabled = false;
7574 * Convenience function for setting disabled/enabled by boolean.
7575 * @param {Boolean} disabled
7577 setDisabled : function(disabled){
7578 this[disabled ? "disable" : "enable"]();
7582 * Show this component.
7583 * @return {Roo.Component} this
7586 if(this.fireEvent("beforeshow", this) !== false){
7587 this.hidden = false;
7591 this.fireEvent("show", this);
7597 onShow : function(){
7598 var ae = this.getActionEl();
7599 if(this.hideMode == 'visibility'){
7600 ae.dom.style.visibility = "visible";
7601 }else if(this.hideMode == 'offsets'){
7602 ae.removeClass('x-hidden');
7604 ae.dom.style.display = "";
7609 * Hide this component.
7610 * @return {Roo.Component} this
7613 if(this.fireEvent("beforehide", this) !== false){
7618 this.fireEvent("hide", this);
7624 onHide : function(){
7625 var ae = this.getActionEl();
7626 if(this.hideMode == 'visibility'){
7627 ae.dom.style.visibility = "hidden";
7628 }else if(this.hideMode == 'offsets'){
7629 ae.addClass('x-hidden');
7631 ae.dom.style.display = "none";
7636 * Convenience function to hide or show this component by boolean.
7637 * @param {Boolean} visible True to show, false to hide
7638 * @return {Roo.Component} this
7640 setVisible: function(visible){
7650 * Returns true if this component is visible.
7652 isVisible : function(){
7653 return this.getActionEl().isVisible();
7656 cloneConfig : function(overrides){
7657 overrides = overrides || {};
7658 var id = overrides.id || Roo.id();
7659 var cfg = Roo.applyIf(overrides, this.initialConfig);
7660 cfg.id = id; // prevent dup id
7661 return new this.constructor(cfg);
7665 * Ext JS Library 1.1.1
7666 * Copyright(c) 2006-2007, Ext JS, LLC.
7668 * Originally Released Under LGPL - original licence link has changed is not relivant.
7671 * <script type="text/javascript">
7676 * @extends Roo.Element
7677 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7678 * automatic maintaining of shadow/shim positions.
7679 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7680 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7681 * you can pass a string with a CSS class name. False turns off the shadow.
7682 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7683 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7684 * @cfg {String} cls CSS class to add to the element
7685 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7686 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7688 * @param {Object} config An object with config options.
7689 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7692 Roo.Layer = function(config, existingEl){
7693 config = config || {};
7694 var dh = Roo.DomHelper;
7695 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7697 this.dom = Roo.getDom(existingEl);
7700 var o = config.dh || {tag: "div", cls: "x-layer"};
7701 this.dom = dh.append(pel, o);
7704 this.addClass(config.cls);
7706 this.constrain = config.constrain !== false;
7707 this.visibilityMode = Roo.Element.VISIBILITY;
7709 this.id = this.dom.id = config.id;
7711 this.id = Roo.id(this.dom);
7713 this.zindex = config.zindex || this.getZIndex();
7714 this.position("absolute", this.zindex);
7716 this.shadowOffset = config.shadowOffset || 4;
7717 this.shadow = new Roo.Shadow({
7718 offset : this.shadowOffset,
7719 mode : config.shadow
7722 this.shadowOffset = 0;
7724 this.useShim = config.shim !== false && Roo.useShims;
7725 this.useDisplay = config.useDisplay;
7729 var supr = Roo.Element.prototype;
7731 // shims are shared among layer to keep from having 100 iframes
7734 Roo.extend(Roo.Layer, Roo.Element, {
7736 getZIndex : function(){
7737 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7740 getShim : function(){
7747 var shim = shims.shift();
7749 shim = this.createShim();
7750 shim.enableDisplayMode('block');
7751 shim.dom.style.display = 'none';
7752 shim.dom.style.visibility = 'visible';
7754 var pn = this.dom.parentNode;
7755 if(shim.dom.parentNode != pn){
7756 pn.insertBefore(shim.dom, this.dom);
7758 shim.setStyle('z-index', this.getZIndex()-2);
7763 hideShim : function(){
7765 this.shim.setDisplayed(false);
7766 shims.push(this.shim);
7771 disableShadow : function(){
7773 this.shadowDisabled = true;
7775 this.lastShadowOffset = this.shadowOffset;
7776 this.shadowOffset = 0;
7780 enableShadow : function(show){
7782 this.shadowDisabled = false;
7783 this.shadowOffset = this.lastShadowOffset;
7784 delete this.lastShadowOffset;
7792 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7793 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7794 sync : function(doShow){
7795 var sw = this.shadow;
7796 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7797 var sh = this.getShim();
7799 var w = this.getWidth(),
7800 h = this.getHeight();
7802 var l = this.getLeft(true),
7803 t = this.getTop(true);
7805 if(sw && !this.shadowDisabled){
7806 if(doShow && !sw.isVisible()){
7809 sw.realign(l, t, w, h);
7815 // fit the shim behind the shadow, so it is shimmed too
7816 var a = sw.adjusts, s = sh.dom.style;
7817 s.left = (Math.min(l, l+a.l))+"px";
7818 s.top = (Math.min(t, t+a.t))+"px";
7819 s.width = (w+a.w)+"px";
7820 s.height = (h+a.h)+"px";
7827 sh.setLeftTop(l, t);
7834 destroy : function(){
7839 this.removeAllListeners();
7840 var pn = this.dom.parentNode;
7842 pn.removeChild(this.dom);
7844 Roo.Element.uncache(this.id);
7847 remove : function(){
7852 beginUpdate : function(){
7853 this.updating = true;
7857 endUpdate : function(){
7858 this.updating = false;
7863 hideUnders : function(negOffset){
7871 constrainXY : function(){
7873 var vw = Roo.lib.Dom.getViewWidth(),
7874 vh = Roo.lib.Dom.getViewHeight();
7875 var s = Roo.get(document).getScroll();
7877 var xy = this.getXY();
7878 var x = xy[0], y = xy[1];
7879 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7880 // only move it if it needs it
7882 // first validate right/bottom
7883 if((x + w) > vw+s.left){
7884 x = vw - w - this.shadowOffset;
7887 if((y + h) > vh+s.top){
7888 y = vh - h - this.shadowOffset;
7891 // then make sure top/left isn't negative
7902 var ay = this.avoidY;
7903 if(y <= ay && (y+h) >= ay){
7909 supr.setXY.call(this, xy);
7915 isVisible : function(){
7916 return this.visible;
7920 showAction : function(){
7921 this.visible = true; // track visibility to prevent getStyle calls
7922 if(this.useDisplay === true){
7923 this.setDisplayed("");
7924 }else if(this.lastXY){
7925 supr.setXY.call(this, this.lastXY);
7926 }else if(this.lastLT){
7927 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7932 hideAction : function(){
7933 this.visible = false;
7934 if(this.useDisplay === true){
7935 this.setDisplayed(false);
7937 this.setLeftTop(-10000,-10000);
7941 // overridden Element method
7942 setVisible : function(v, a, d, c, e){
7947 var cb = function(){
7952 }.createDelegate(this);
7953 supr.setVisible.call(this, true, true, d, cb, e);
7956 this.hideUnders(true);
7965 }.createDelegate(this);
7967 supr.setVisible.call(this, v, a, d, cb, e);
7976 storeXY : function(xy){
7981 storeLeftTop : function(left, top){
7983 this.lastLT = [left, top];
7987 beforeFx : function(){
7988 this.beforeAction();
7989 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
7993 afterFx : function(){
7994 Roo.Layer.superclass.afterFx.apply(this, arguments);
7995 this.sync(this.isVisible());
7999 beforeAction : function(){
8000 if(!this.updating && this.shadow){
8005 // overridden Element method
8006 setLeft : function(left){
8007 this.storeLeftTop(left, this.getTop(true));
8008 supr.setLeft.apply(this, arguments);
8012 setTop : function(top){
8013 this.storeLeftTop(this.getLeft(true), top);
8014 supr.setTop.apply(this, arguments);
8018 setLeftTop : function(left, top){
8019 this.storeLeftTop(left, top);
8020 supr.setLeftTop.apply(this, arguments);
8024 setXY : function(xy, a, d, c, e){
8026 this.beforeAction();
8028 var cb = this.createCB(c);
8029 supr.setXY.call(this, xy, a, d, cb, e);
8036 createCB : function(c){
8047 // overridden Element method
8048 setX : function(x, a, d, c, e){
8049 this.setXY([x, this.getY()], a, d, c, e);
8052 // overridden Element method
8053 setY : function(y, a, d, c, e){
8054 this.setXY([this.getX(), y], a, d, c, e);
8057 // overridden Element method
8058 setSize : function(w, h, a, d, c, e){
8059 this.beforeAction();
8060 var cb = this.createCB(c);
8061 supr.setSize.call(this, w, h, a, d, cb, e);
8067 // overridden Element method
8068 setWidth : function(w, a, d, c, e){
8069 this.beforeAction();
8070 var cb = this.createCB(c);
8071 supr.setWidth.call(this, w, a, d, cb, e);
8077 // overridden Element method
8078 setHeight : function(h, a, d, c, e){
8079 this.beforeAction();
8080 var cb = this.createCB(c);
8081 supr.setHeight.call(this, h, a, d, cb, e);
8087 // overridden Element method
8088 setBounds : function(x, y, w, h, a, d, c, e){
8089 this.beforeAction();
8090 var cb = this.createCB(c);
8092 this.storeXY([x, y]);
8093 supr.setXY.call(this, [x, y]);
8094 supr.setSize.call(this, w, h, a, d, cb, e);
8097 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8103 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8104 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8105 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8106 * @param {Number} zindex The new z-index to set
8107 * @return {this} The Layer
8109 setZIndex : function(zindex){
8110 this.zindex = zindex;
8111 this.setStyle("z-index", zindex + 2);
8113 this.shadow.setZIndex(zindex + 1);
8116 this.shim.setStyle("z-index", zindex);
8122 * Ext JS Library 1.1.1
8123 * Copyright(c) 2006-2007, Ext JS, LLC.
8125 * Originally Released Under LGPL - original licence link has changed is not relivant.
8128 * <script type="text/javascript">
8134 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8135 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8136 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8138 * Create a new Shadow
8139 * @param {Object} config The config object
8141 Roo.Shadow = function(config){
8142 Roo.apply(this, config);
8143 if(typeof this.mode != "string"){
8144 this.mode = this.defaultMode;
8146 var o = this.offset, a = {h: 0};
8147 var rad = Math.floor(this.offset/2);
8148 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8154 a.l -= this.offset + rad;
8155 a.t -= this.offset + rad;
8166 a.l -= (this.offset - rad);
8167 a.t -= this.offset + rad;
8169 a.w -= (this.offset - rad)*2;
8180 a.l -= (this.offset - rad);
8181 a.t -= (this.offset - rad);
8183 a.w -= (this.offset + rad + 1);
8184 a.h -= (this.offset + rad);
8193 Roo.Shadow.prototype = {
8195 * @cfg {String} mode
8196 * The shadow display mode. Supports the following options:<br />
8197 * sides: Shadow displays on both sides and bottom only<br />
8198 * frame: Shadow displays equally on all four sides<br />
8199 * drop: Traditional bottom-right drop shadow (default)
8202 * @cfg {String} offset
8203 * The number of pixels to offset the shadow from the element (defaults to 4)
8208 defaultMode: "drop",
8211 * Displays the shadow under the target element
8212 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8214 show : function(target){
8215 target = Roo.get(target);
8217 this.el = Roo.Shadow.Pool.pull();
8218 if(this.el.dom.nextSibling != target.dom){
8219 this.el.insertBefore(target);
8222 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8224 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8227 target.getLeft(true),
8228 target.getTop(true),
8232 this.el.dom.style.display = "block";
8236 * Returns true if the shadow is visible, else false
8238 isVisible : function(){
8239 return this.el ? true : false;
8243 * Direct alignment when values are already available. Show must be called at least once before
8244 * calling this method to ensure it is initialized.
8245 * @param {Number} left The target element left position
8246 * @param {Number} top The target element top position
8247 * @param {Number} width The target element width
8248 * @param {Number} height The target element height
8250 realign : function(l, t, w, h){
8254 var a = this.adjusts, d = this.el.dom, s = d.style;
8256 s.left = (l+a.l)+"px";
8257 s.top = (t+a.t)+"px";
8258 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8260 if(s.width != sws || s.height != shs){
8264 var cn = d.childNodes;
8265 var sww = Math.max(0, (sw-12))+"px";
8266 cn[0].childNodes[1].style.width = sww;
8267 cn[1].childNodes[1].style.width = sww;
8268 cn[2].childNodes[1].style.width = sww;
8269 cn[1].style.height = Math.max(0, (sh-12))+"px";
8279 this.el.dom.style.display = "none";
8280 Roo.Shadow.Pool.push(this.el);
8286 * Adjust the z-index of this shadow
8287 * @param {Number} zindex The new z-index
8289 setZIndex : function(z){
8292 this.el.setStyle("z-index", z);
8297 // Private utility class that manages the internal Shadow cache
8298 Roo.Shadow.Pool = function(){
8300 var markup = Roo.isIE ?
8301 '<div class="x-ie-shadow"></div>' :
8302 '<div class="x-shadow"><div class="xst"><div class="xstl"></div><div class="xstc"></div><div class="xstr"></div></div><div class="xsc"><div class="xsml"></div><div class="xsmc"></div><div class="xsmr"></div></div><div class="xsb"><div class="xsbl"></div><div class="xsbc"></div><div class="xsbr"></div></div></div>';
8307 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8308 sh.autoBoxAdjust = false;
8313 push : function(sh){
8319 * Ext JS Library 1.1.1
8320 * Copyright(c) 2006-2007, Ext JS, LLC.
8322 * Originally Released Under LGPL - original licence link has changed is not relivant.
8325 * <script type="text/javascript">
8329 * @class Roo.BoxComponent
8330 * @extends Roo.Component
8331 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8332 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8333 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8334 * layout containers.
8336 * @param {Roo.Element/String/Object} config The configuration options.
8338 Roo.BoxComponent = function(config){
8339 Roo.Component.call(this, config);
8343 * Fires after the component is resized.
8344 * @param {Roo.Component} this
8345 * @param {Number} adjWidth The box-adjusted width that was set
8346 * @param {Number} adjHeight The box-adjusted height that was set
8347 * @param {Number} rawWidth The width that was originally specified
8348 * @param {Number} rawHeight The height that was originally specified
8353 * Fires after the component is moved.
8354 * @param {Roo.Component} this
8355 * @param {Number} x The new x position
8356 * @param {Number} y The new y position
8362 Roo.extend(Roo.BoxComponent, Roo.Component, {
8363 // private, set in afterRender to signify that the component has been rendered
8365 // private, used to defer height settings to subclasses
8367 /** @cfg {Number} width
8368 * width (optional) size of component
8370 /** @cfg {Number} height
8371 * height (optional) size of component
8375 * Sets the width and height of the component. This method fires the resize event. This method can accept
8376 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8377 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8378 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8379 * @return {Roo.BoxComponent} this
8381 setSize : function(w, h){
8382 // support for standard size objects
8383 if(typeof w == 'object'){
8394 // prevent recalcs when not needed
8395 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8398 this.lastSize = {width: w, height: h};
8400 var adj = this.adjustSize(w, h);
8401 var aw = adj.width, ah = adj.height;
8402 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8403 var rz = this.getResizeEl();
8404 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8406 }else if(!this.deferHeight && ah !== undefined){
8408 }else if(aw !== undefined){
8411 this.onResize(aw, ah, w, h);
8412 this.fireEvent('resize', this, aw, ah, w, h);
8418 * Gets the current size of the component's underlying element.
8419 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8421 getSize : function(){
8422 return this.el.getSize();
8426 * Gets the current XY position of the component's underlying element.
8427 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8428 * @return {Array} The XY position of the element (e.g., [100, 200])
8430 getPosition : function(local){
8432 return [this.el.getLeft(true), this.el.getTop(true)];
8434 return this.xy || this.el.getXY();
8438 * Gets the current box measurements of the component's underlying element.
8439 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8440 * @returns {Object} box An object in the format {x, y, width, height}
8442 getBox : function(local){
8443 var s = this.el.getSize();
8445 s.x = this.el.getLeft(true);
8446 s.y = this.el.getTop(true);
8448 var xy = this.xy || this.el.getXY();
8456 * Sets the current box measurements of the component's underlying element.
8457 * @param {Object} box An object in the format {x, y, width, height}
8458 * @returns {Roo.BoxComponent} this
8460 updateBox : function(box){
8461 this.setSize(box.width, box.height);
8462 this.setPagePosition(box.x, box.y);
8467 getResizeEl : function(){
8468 return this.resizeEl || this.el;
8472 getPositionEl : function(){
8473 return this.positionEl || this.el;
8477 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8478 * This method fires the move event.
8479 * @param {Number} left The new left
8480 * @param {Number} top The new top
8481 * @returns {Roo.BoxComponent} this
8483 setPosition : function(x, y){
8489 var adj = this.adjustPosition(x, y);
8490 var ax = adj.x, ay = adj.y;
8492 var el = this.getPositionEl();
8493 if(ax !== undefined || ay !== undefined){
8494 if(ax !== undefined && ay !== undefined){
8495 el.setLeftTop(ax, ay);
8496 }else if(ax !== undefined){
8498 }else if(ay !== undefined){
8501 this.onPosition(ax, ay);
8502 this.fireEvent('move', this, ax, ay);
8508 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8509 * This method fires the move event.
8510 * @param {Number} x The new x position
8511 * @param {Number} y The new y position
8512 * @returns {Roo.BoxComponent} this
8514 setPagePosition : function(x, y){
8520 if(x === undefined || y === undefined){ // cannot translate undefined points
8523 var p = this.el.translatePoints(x, y);
8524 this.setPosition(p.left, p.top);
8529 onRender : function(ct, position){
8530 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8532 this.resizeEl = Roo.get(this.resizeEl);
8534 if(this.positionEl){
8535 this.positionEl = Roo.get(this.positionEl);
8540 afterRender : function(){
8541 Roo.BoxComponent.superclass.afterRender.call(this);
8542 this.boxReady = true;
8543 this.setSize(this.width, this.height);
8544 if(this.x || this.y){
8545 this.setPosition(this.x, this.y);
8547 if(this.pageX || this.pageY){
8548 this.setPagePosition(this.pageX, this.pageY);
8553 * Force the component's size to recalculate based on the underlying element's current height and width.
8554 * @returns {Roo.BoxComponent} this
8556 syncSize : function(){
8557 delete this.lastSize;
8558 this.setSize(this.el.getWidth(), this.el.getHeight());
8563 * Called after the component is resized, this method is empty by default but can be implemented by any
8564 * subclass that needs to perform custom logic after a resize occurs.
8565 * @param {Number} adjWidth The box-adjusted width that was set
8566 * @param {Number} adjHeight The box-adjusted height that was set
8567 * @param {Number} rawWidth The width that was originally specified
8568 * @param {Number} rawHeight The height that was originally specified
8570 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8575 * Called after the component is moved, this method is empty by default but can be implemented by any
8576 * subclass that needs to perform custom logic after a move occurs.
8577 * @param {Number} x The new x position
8578 * @param {Number} y The new y position
8580 onPosition : function(x, y){
8585 adjustSize : function(w, h){
8589 if(this.autoHeight){
8592 return {width : w, height: h};
8596 adjustPosition : function(x, y){
8597 return {x : x, y: y};
8601 * Ext JS Library 1.1.1
8602 * Copyright(c) 2006-2007, Ext JS, LLC.
8604 * Originally Released Under LGPL - original licence link has changed is not relivant.
8607 * <script type="text/javascript">
8612 * @class Roo.SplitBar
8613 * @extends Roo.util.Observable
8614 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8618 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8619 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8620 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8621 split.minSize = 100;
8622 split.maxSize = 600;
8623 split.animate = true;
8624 split.on('moved', splitterMoved);
8627 * Create a new SplitBar
8628 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8629 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8630 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8631 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8632 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8633 position of the SplitBar).
8635 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8638 this.el = Roo.get(dragElement, true);
8639 this.el.dom.unselectable = "on";
8641 this.resizingEl = Roo.get(resizingElement, true);
8645 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8646 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8649 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8652 * The minimum size of the resizing element. (Defaults to 0)
8658 * The maximum size of the resizing element. (Defaults to 2000)
8661 this.maxSize = 2000;
8664 * Whether to animate the transition to the new size
8667 this.animate = false;
8670 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8673 this.useShim = false;
8680 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8682 this.proxy = Roo.get(existingProxy).dom;
8685 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8688 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8691 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8694 this.dragSpecs = {};
8697 * @private The adapter to use to positon and resize elements
8699 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8700 this.adapter.init(this);
8702 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8704 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8705 this.el.addClass("x-splitbar-h");
8708 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8709 this.el.addClass("x-splitbar-v");
8715 * Fires when the splitter is moved (alias for {@link #event-moved})
8716 * @param {Roo.SplitBar} this
8717 * @param {Number} newSize the new width or height
8722 * Fires when the splitter is moved
8723 * @param {Roo.SplitBar} this
8724 * @param {Number} newSize the new width or height
8728 * @event beforeresize
8729 * Fires before the splitter is dragged
8730 * @param {Roo.SplitBar} this
8732 "beforeresize" : true,
8734 "beforeapply" : true
8737 Roo.util.Observable.call(this);
8740 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8741 onStartProxyDrag : function(x, y){
8742 this.fireEvent("beforeresize", this);
8744 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8746 o.enableDisplayMode("block");
8747 // all splitbars share the same overlay
8748 Roo.SplitBar.prototype.overlay = o;
8750 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8751 this.overlay.show();
8752 Roo.get(this.proxy).setDisplayed("block");
8753 var size = this.adapter.getElementSize(this);
8754 this.activeMinSize = this.getMinimumSize();;
8755 this.activeMaxSize = this.getMaximumSize();;
8756 var c1 = size - this.activeMinSize;
8757 var c2 = Math.max(this.activeMaxSize - size, 0);
8758 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8759 this.dd.resetConstraints();
8760 this.dd.setXConstraint(
8761 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8762 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8764 this.dd.setYConstraint(0, 0);
8766 this.dd.resetConstraints();
8767 this.dd.setXConstraint(0, 0);
8768 this.dd.setYConstraint(
8769 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8770 this.placement == Roo.SplitBar.TOP ? c2 : c1
8773 this.dragSpecs.startSize = size;
8774 this.dragSpecs.startPoint = [x, y];
8775 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8779 * @private Called after the drag operation by the DDProxy
8781 onEndProxyDrag : function(e){
8782 Roo.get(this.proxy).setDisplayed(false);
8783 var endPoint = Roo.lib.Event.getXY(e);
8785 this.overlay.hide();
8788 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8789 newSize = this.dragSpecs.startSize +
8790 (this.placement == Roo.SplitBar.LEFT ?
8791 endPoint[0] - this.dragSpecs.startPoint[0] :
8792 this.dragSpecs.startPoint[0] - endPoint[0]
8795 newSize = this.dragSpecs.startSize +
8796 (this.placement == Roo.SplitBar.TOP ?
8797 endPoint[1] - this.dragSpecs.startPoint[1] :
8798 this.dragSpecs.startPoint[1] - endPoint[1]
8801 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8802 if(newSize != this.dragSpecs.startSize){
8803 if(this.fireEvent('beforeapply', this, newSize) !== false){
8804 this.adapter.setElementSize(this, newSize);
8805 this.fireEvent("moved", this, newSize);
8806 this.fireEvent("resize", this, newSize);
8812 * Get the adapter this SplitBar uses
8813 * @return The adapter object
8815 getAdapter : function(){
8816 return this.adapter;
8820 * Set the adapter this SplitBar uses
8821 * @param {Object} adapter A SplitBar adapter object
8823 setAdapter : function(adapter){
8824 this.adapter = adapter;
8825 this.adapter.init(this);
8829 * Gets the minimum size for the resizing element
8830 * @return {Number} The minimum size
8832 getMinimumSize : function(){
8833 return this.minSize;
8837 * Sets the minimum size for the resizing element
8838 * @param {Number} minSize The minimum size
8840 setMinimumSize : function(minSize){
8841 this.minSize = minSize;
8845 * Gets the maximum size for the resizing element
8846 * @return {Number} The maximum size
8848 getMaximumSize : function(){
8849 return this.maxSize;
8853 * Sets the maximum size for the resizing element
8854 * @param {Number} maxSize The maximum size
8856 setMaximumSize : function(maxSize){
8857 this.maxSize = maxSize;
8861 * Sets the initialize size for the resizing element
8862 * @param {Number} size The initial size
8864 setCurrentSize : function(size){
8865 var oldAnimate = this.animate;
8866 this.animate = false;
8867 this.adapter.setElementSize(this, size);
8868 this.animate = oldAnimate;
8872 * Destroy this splitbar.
8873 * @param {Boolean} removeEl True to remove the element
8875 destroy : function(removeEl){
8880 this.proxy.parentNode.removeChild(this.proxy);
8888 * @private static Create our own proxy element element. So it will be the same same size on all browsers, we won't use borders. Instead we use a background color.
8890 Roo.SplitBar.createProxy = function(dir){
8891 var proxy = new Roo.Element(document.createElement("div"));
8892 proxy.unselectable();
8893 var cls = 'x-splitbar-proxy';
8894 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8895 document.body.appendChild(proxy.dom);
8900 * @class Roo.SplitBar.BasicLayoutAdapter
8901 * Default Adapter. It assumes the splitter and resizing element are not positioned
8902 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8904 Roo.SplitBar.BasicLayoutAdapter = function(){
8907 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8908 // do nothing for now
8913 * Called before drag operations to get the current size of the resizing element.
8914 * @param {Roo.SplitBar} s The SplitBar using this adapter
8916 getElementSize : function(s){
8917 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8918 return s.resizingEl.getWidth();
8920 return s.resizingEl.getHeight();
8925 * Called after drag operations to set the size of the resizing element.
8926 * @param {Roo.SplitBar} s The SplitBar using this adapter
8927 * @param {Number} newSize The new size to set
8928 * @param {Function} onComplete A function to be invoked when resizing is complete
8930 setElementSize : function(s, newSize, onComplete){
8931 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8933 s.resizingEl.setWidth(newSize);
8935 onComplete(s, newSize);
8938 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8943 s.resizingEl.setHeight(newSize);
8945 onComplete(s, newSize);
8948 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8955 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8956 * @extends Roo.SplitBar.BasicLayoutAdapter
8957 * Adapter that moves the splitter element to align with the resized sizing element.
8958 * Used with an absolute positioned SplitBar.
8959 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8960 * document.body, make sure you assign an id to the body element.
8962 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8963 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8964 this.container = Roo.get(container);
8967 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8972 getElementSize : function(s){
8973 return this.basic.getElementSize(s);
8976 setElementSize : function(s, newSize, onComplete){
8977 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8980 moveSplitter : function(s){
8981 var yes = Roo.SplitBar;
8982 switch(s.placement){
8984 s.el.setX(s.resizingEl.getRight());
8987 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
8990 s.el.setY(s.resizingEl.getBottom());
8993 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9000 * Orientation constant - Create a vertical SplitBar
9004 Roo.SplitBar.VERTICAL = 1;
9007 * Orientation constant - Create a horizontal SplitBar
9011 Roo.SplitBar.HORIZONTAL = 2;
9014 * Placement constant - The resizing element is to the left of the splitter element
9018 Roo.SplitBar.LEFT = 1;
9021 * Placement constant - The resizing element is to the right of the splitter element
9025 Roo.SplitBar.RIGHT = 2;
9028 * Placement constant - The resizing element is positioned above the splitter element
9032 Roo.SplitBar.TOP = 3;
9035 * Placement constant - The resizing element is positioned under splitter element
9039 Roo.SplitBar.BOTTOM = 4;
9042 * Ext JS Library 1.1.1
9043 * Copyright(c) 2006-2007, Ext JS, LLC.
9045 * Originally Released Under LGPL - original licence link has changed is not relivant.
9048 * <script type="text/javascript">
9053 * @extends Roo.util.Observable
9054 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9055 * This class also supports single and multi selection modes. <br>
9056 * Create a data model bound view:
9058 var store = new Roo.data.Store(...);
9060 var view = new Roo.View({
9062 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9065 selectedClass: "ydataview-selected",
9069 // listen for node click?
9070 view.on("click", function(vw, index, node, e){
9071 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9075 dataModel.load("foobar.xml");
9077 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9079 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9080 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9082 * Note: old style constructor is still suported (container, template, config)
9086 * @param {Object} config The config object
9089 Roo.View = function(config, depreciated_tpl, depreciated_config){
9091 if (typeof(depreciated_tpl) == 'undefined') {
9092 // new way.. - universal constructor.
9093 Roo.apply(this, config);
9094 this.el = Roo.get(this.el);
9097 this.el = Roo.get(config);
9098 this.tpl = depreciated_tpl;
9099 Roo.apply(this, depreciated_config);
9103 if(typeof(this.tpl) == "string"){
9104 this.tpl = new Roo.Template(this.tpl);
9106 // support xtype ctors..
9107 this.tpl = new Roo.factory(this.tpl, Roo);
9118 * @event beforeclick
9119 * Fires before a click is processed. Returns false to cancel the default action.
9120 * @param {Roo.View} this
9121 * @param {Number} index The index of the target node
9122 * @param {HTMLElement} node The target node
9123 * @param {Roo.EventObject} e The raw event object
9125 "beforeclick" : true,
9128 * Fires when a template node is clicked.
9129 * @param {Roo.View} this
9130 * @param {Number} index The index of the target node
9131 * @param {HTMLElement} node The target node
9132 * @param {Roo.EventObject} e The raw event object
9137 * Fires when a template node is double clicked.
9138 * @param {Roo.View} this
9139 * @param {Number} index The index of the target node
9140 * @param {HTMLElement} node The target node
9141 * @param {Roo.EventObject} e The raw event object
9145 * @event contextmenu
9146 * Fires when a template node is right clicked.
9147 * @param {Roo.View} this
9148 * @param {Number} index The index of the target node
9149 * @param {HTMLElement} node The target node
9150 * @param {Roo.EventObject} e The raw event object
9152 "contextmenu" : true,
9154 * @event selectionchange
9155 * Fires when the selected nodes change.
9156 * @param {Roo.View} this
9157 * @param {Array} selections Array of the selected nodes
9159 "selectionchange" : true,
9162 * @event beforeselect
9163 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9164 * @param {Roo.View} this
9165 * @param {HTMLElement} node The node to be selected
9166 * @param {Array} selections Array of currently selected nodes
9168 "beforeselect" : true
9172 "click": this.onClick,
9173 "dblclick": this.onDblClick,
9174 "contextmenu": this.onContextMenu,
9178 this.selections = [];
9180 this.cmp = new Roo.CompositeElementLite([]);
9182 this.store = Roo.factory(this.store, Roo.data);
9183 this.setStore(this.store, true);
9185 Roo.View.superclass.constructor.call(this);
9188 Roo.extend(Roo.View, Roo.util.Observable, {
9191 * @cfg {Roo.data.Store} store Data store to load data from.
9196 * @cfg {String|Roo.Element} el The container element.
9201 * @cfg {String|Roo.Template} tpl The template used by this View
9206 * @cfg {String} selectedClass The css class to add to selected nodes
9208 selectedClass : "x-view-selected",
9210 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9214 * @cfg {Boolean} multiSelect Allow multiple selection
9217 multiSelect : false,
9219 * @cfg {Boolean} singleSelect Allow single selection
9221 singleSelect: false,
9224 * Returns the element this view is bound to.
9225 * @return {Roo.Element}
9232 * Refreshes the view.
9234 refresh : function(){
9236 this.clearSelections();
9239 var records = this.store.getRange();
9240 if(records.length < 1){
9241 this.el.update(this.emptyText);
9244 for(var i = 0, len = records.length; i < len; i++){
9245 var data = this.prepareData(records[i].data, i, records[i]);
9246 html[html.length] = t.apply(data);
9248 this.el.update(html.join(""));
9249 this.nodes = this.el.dom.childNodes;
9250 this.updateIndexes(0);
9254 * Function to override to reformat the data that is sent to
9255 * the template for each node.
9256 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9257 * a JSON object for an UpdateManager bound view).
9259 prepareData : function(data){
9263 onUpdate : function(ds, record){
9264 this.clearSelections();
9265 var index = this.store.indexOf(record);
9266 var n = this.nodes[index];
9267 this.tpl.insertBefore(n, this.prepareData(record.data));
9268 n.parentNode.removeChild(n);
9269 this.updateIndexes(index, index);
9272 onAdd : function(ds, records, index){
9273 this.clearSelections();
9274 if(this.nodes.length == 0){
9278 var n = this.nodes[index];
9279 for(var i = 0, len = records.length; i < len; i++){
9280 var d = this.prepareData(records[i].data);
9282 this.tpl.insertBefore(n, d);
9284 this.tpl.append(this.el, d);
9287 this.updateIndexes(index);
9290 onRemove : function(ds, record, index){
9291 this.clearSelections();
9292 this.el.dom.removeChild(this.nodes[index]);
9293 this.updateIndexes(index);
9297 * Refresh an individual node.
9298 * @param {Number} index
9300 refreshNode : function(index){
9301 this.onUpdate(this.store, this.store.getAt(index));
9304 updateIndexes : function(startIndex, endIndex){
9305 var ns = this.nodes;
9306 startIndex = startIndex || 0;
9307 endIndex = endIndex || ns.length - 1;
9308 for(var i = startIndex; i <= endIndex; i++){
9309 ns[i].nodeIndex = i;
9314 * Changes the data store this view uses and refresh the view.
9315 * @param {Store} store
9317 setStore : function(store, initial){
9318 if(!initial && this.store){
9319 this.store.un("datachanged", this.refresh);
9320 this.store.un("add", this.onAdd);
9321 this.store.un("remove", this.onRemove);
9322 this.store.un("update", this.onUpdate);
9323 this.store.un("clear", this.refresh);
9327 store.on("datachanged", this.refresh, this);
9328 store.on("add", this.onAdd, this);
9329 store.on("remove", this.onRemove, this);
9330 store.on("update", this.onUpdate, this);
9331 store.on("clear", this.refresh, this);
9340 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9341 * @param {HTMLElement} node
9342 * @return {HTMLElement} The template node
9344 findItemFromChild : function(node){
9345 var el = this.el.dom;
9346 if(!node || node.parentNode == el){
9349 var p = node.parentNode;
9350 while(p && p != el){
9351 if(p.parentNode == el){
9360 onClick : function(e){
9361 var item = this.findItemFromChild(e.getTarget());
9363 var index = this.indexOf(item);
9364 if(this.onItemClick(item, index, e) !== false){
9365 this.fireEvent("click", this, index, item, e);
9368 this.clearSelections();
9373 onContextMenu : function(e){
9374 var item = this.findItemFromChild(e.getTarget());
9376 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9381 onDblClick : function(e){
9382 var item = this.findItemFromChild(e.getTarget());
9384 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9388 onItemClick : function(item, index, e){
9389 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9392 if(this.multiSelect || this.singleSelect){
9393 if(this.multiSelect && e.shiftKey && this.lastSelection){
9394 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9396 this.select(item, this.multiSelect && e.ctrlKey);
9397 this.lastSelection = item;
9405 * Get the number of selected nodes.
9408 getSelectionCount : function(){
9409 return this.selections.length;
9413 * Get the currently selected nodes.
9414 * @return {Array} An array of HTMLElements
9416 getSelectedNodes : function(){
9417 return this.selections;
9421 * Get the indexes of the selected nodes.
9424 getSelectedIndexes : function(){
9425 var indexes = [], s = this.selections;
9426 for(var i = 0, len = s.length; i < len; i++){
9427 indexes.push(s[i].nodeIndex);
9433 * Clear all selections
9434 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9436 clearSelections : function(suppressEvent){
9437 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9438 this.cmp.elements = this.selections;
9439 this.cmp.removeClass(this.selectedClass);
9440 this.selections = [];
9442 this.fireEvent("selectionchange", this, this.selections);
9448 * Returns true if the passed node is selected
9449 * @param {HTMLElement/Number} node The node or node index
9452 isSelected : function(node){
9453 var s = this.selections;
9457 node = this.getNode(node);
9458 return s.indexOf(node) !== -1;
9463 * @param {Array/HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node, id of a template node or an array of any of those to select
9464 * @param {Boolean} keepExisting (optional) true to keep existing selections
9465 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9467 select : function(nodeInfo, keepExisting, suppressEvent){
9468 if(nodeInfo instanceof Array){
9470 this.clearSelections(true);
9472 for(var i = 0, len = nodeInfo.length; i < len; i++){
9473 this.select(nodeInfo[i], true, true);
9476 var node = this.getNode(nodeInfo);
9477 if(node && !this.isSelected(node)){
9479 this.clearSelections(true);
9481 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9482 Roo.fly(node).addClass(this.selectedClass);
9483 this.selections.push(node);
9485 this.fireEvent("selectionchange", this, this.selections);
9493 * Gets a template node.
9494 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9495 * @return {HTMLElement} The node or null if it wasn't found
9497 getNode : function(nodeInfo){
9498 if(typeof nodeInfo == "string"){
9499 return document.getElementById(nodeInfo);
9500 }else if(typeof nodeInfo == "number"){
9501 return this.nodes[nodeInfo];
9507 * Gets a range template nodes.
9508 * @param {Number} startIndex
9509 * @param {Number} endIndex
9510 * @return {Array} An array of nodes
9512 getNodes : function(start, end){
9513 var ns = this.nodes;
9515 end = typeof end == "undefined" ? ns.length - 1 : end;
9518 for(var i = start; i <= end; i++){
9522 for(var i = start; i >= end; i--){
9530 * Finds the index of the passed node
9531 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9532 * @return {Number} The index of the node or -1
9534 indexOf : function(node){
9535 node = this.getNode(node);
9536 if(typeof node.nodeIndex == "number"){
9537 return node.nodeIndex;
9539 var ns = this.nodes;
9540 for(var i = 0, len = ns.length; i < len; i++){
9550 * Ext JS Library 1.1.1
9551 * Copyright(c) 2006-2007, Ext JS, LLC.
9553 * Originally Released Under LGPL - original licence link has changed is not relivant.
9556 * <script type="text/javascript">
9560 * @class Roo.JsonView
9562 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9564 var view = new Roo.JsonView({
9565 container: "my-element",
9566 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9571 // listen for node click?
9572 view.on("click", function(vw, index, node, e){
9573 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9576 // direct load of JSON data
9577 view.load("foobar.php");
9579 // Example from my blog list
9580 var tpl = new Roo.Template(
9581 '<div class="entry">' +
9582 '<a class="entry-title" href="{link}">{title}</a>' +
9583 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9584 "</div><hr />"
9587 var moreView = new Roo.JsonView({
9588 container : "entry-list",
9592 moreView.on("beforerender", this.sortEntries, this);
9594 url: "/blog/get-posts.php",
9595 params: "allposts=true",
9596 text: "Loading Blog Entries..."
9600 * Note: old code is supported with arguments : (container, template, config)
9604 * Create a new JsonView
9606 * @param {Object} config The config object
9609 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9612 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9614 var um = this.el.getUpdateManager();
9615 um.setRenderer(this);
9616 um.on("update", this.onLoad, this);
9617 um.on("failure", this.onLoadException, this);
9620 * @event beforerender
9621 * Fires before rendering of the downloaded JSON data.
9622 * @param {Roo.JsonView} this
9623 * @param {Object} data The JSON data loaded
9627 * Fires when data is loaded.
9628 * @param {Roo.JsonView} this
9629 * @param {Object} data The JSON data loaded
9630 * @param {Object} response The raw Connect response object
9633 * @event loadexception
9634 * Fires when loading fails.
9635 * @param {Roo.JsonView} this
9636 * @param {Object} response The raw Connect response object
9639 'beforerender' : true,
9641 'loadexception' : true
9644 Roo.extend(Roo.JsonView, Roo.View, {
9646 * @type {String} The root property in the loaded JSON object that contains the data
9651 * Refreshes the view.
9653 refresh : function(){
9654 this.clearSelections();
9657 var o = this.jsonData;
9658 if(o && o.length > 0){
9659 for(var i = 0, len = o.length; i < len; i++){
9660 var data = this.prepareData(o[i], i, o);
9661 html[html.length] = this.tpl.apply(data);
9664 html.push(this.emptyText);
9666 this.el.update(html.join(""));
9667 this.nodes = this.el.dom.childNodes;
9668 this.updateIndexes(0);
9672 * Performs an async HTTP request, and loads the JSON from the response. If <i>params</i> are specified it uses POST, otherwise it uses GET.
9673 * @param {Object/String/Function} url The URL for this request, or a function to call to get the URL, or a config object containing any of the following options:
9676 url: "your-url.php",
9677 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9678 callback: yourFunction,
9679 scope: yourObject, //(optional scope)
9687 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9688 * are respectively shorthand for <i>disableCaching</i>, <i>indicatorText</i>, and <i>loadScripts</i> and are used to set their associated property on this UpdateManager instance.
9689 * @param {String/Object} params (optional) The parameters to pass, as either a URL encoded string "param1=1&param2=2" or an object {param1: 1, param2: 2}
9690 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9691 * @param {Boolean} discardUrl (optional) By default when you execute an update the defaultUrl is changed to the last used URL. If true, it will not store the URL.
9694 var um = this.el.getUpdateManager();
9695 um.update.apply(um, arguments);
9698 render : function(el, response){
9699 this.clearSelections();
9703 o = Roo.util.JSON.decode(response.responseText);
9706 o = o[this.jsonRoot];
9711 * The current JSON data or null
9714 this.beforeRender();
9719 * Get the number of records in the current JSON dataset
9722 getCount : function(){
9723 return this.jsonData ? this.jsonData.length : 0;
9727 * Returns the JSON object for the specified node(s)
9728 * @param {HTMLElement/Array} node The node or an array of nodes
9729 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9730 * you get the JSON object for the node
9732 getNodeData : function(node){
9733 if(node instanceof Array){
9735 for(var i = 0, len = node.length; i < len; i++){
9736 data.push(this.getNodeData(node[i]));
9740 return this.jsonData[this.indexOf(node)] || null;
9743 beforeRender : function(){
9744 this.snapshot = this.jsonData;
9746 this.sort.apply(this, this.sortInfo);
9748 this.fireEvent("beforerender", this, this.jsonData);
9751 onLoad : function(el, o){
9752 this.fireEvent("load", this, this.jsonData, o);
9755 onLoadException : function(el, o){
9756 this.fireEvent("loadexception", this, o);
9760 * Filter the data by a specific property.
9761 * @param {String} property A property on your JSON objects
9762 * @param {String/RegExp} value Either string that the property values
9763 * should start with, or a RegExp to test against the property
9765 filter : function(property, value){
9768 var ss = this.snapshot;
9769 if(typeof value == "string"){
9770 var vlen = value.length;
9775 value = value.toLowerCase();
9776 for(var i = 0, len = ss.length; i < len; i++){
9778 if(o[property].substr(0, vlen).toLowerCase() == value){
9782 } else if(value.exec){ // regex?
9783 for(var i = 0, len = ss.length; i < len; i++){
9785 if(value.test(o[property])){
9792 this.jsonData = data;
9798 * Filter by a function. The passed function will be called with each
9799 * object in the current dataset. If the function returns true the value is kept,
9800 * otherwise it is filtered.
9801 * @param {Function} fn
9802 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9804 filterBy : function(fn, scope){
9807 var ss = this.snapshot;
9808 for(var i = 0, len = ss.length; i < len; i++){
9810 if(fn.call(scope || this, o)){
9814 this.jsonData = data;
9820 * Clears the current filter.
9822 clearFilter : function(){
9823 if(this.snapshot && this.jsonData != this.snapshot){
9824 this.jsonData = this.snapshot;
9831 * Sorts the data for this view and refreshes it.
9832 * @param {String} property A property on your JSON objects to sort on
9833 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9834 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9836 sort : function(property, dir, sortType){
9837 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9840 var dsc = dir && dir.toLowerCase() == "desc";
9841 var f = function(o1, o2){
9842 var v1 = sortType ? sortType(o1[p]) : o1[p];
9843 var v2 = sortType ? sortType(o2[p]) : o2[p];
9846 return dsc ? +1 : -1;
9848 return dsc ? -1 : +1;
9853 this.jsonData.sort(f);
9855 if(this.jsonData != this.snapshot){
9856 this.snapshot.sort(f);
9862 * Ext JS Library 1.1.1
9863 * Copyright(c) 2006-2007, Ext JS, LLC.
9865 * Originally Released Under LGPL - original licence link has changed is not relivant.
9868 * <script type="text/javascript">
9873 * @class Roo.ColorPalette
9874 * @extends Roo.Component
9875 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9876 * Here's an example of typical usage:
9878 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9879 cp.render('my-div');
9881 cp.on('select', function(palette, selColor){
9882 // do something with selColor
9886 * Create a new ColorPalette
9887 * @param {Object} config The config object
9889 Roo.ColorPalette = function(config){
9890 Roo.ColorPalette.superclass.constructor.call(this, config);
9894 * Fires when a color is selected
9895 * @param {ColorPalette} this
9896 * @param {String} color The 6-digit color hex code (without the # symbol)
9902 this.on("select", this.handler, this.scope, true);
9905 Roo.extend(Roo.ColorPalette, Roo.Component, {
9907 * @cfg {String} itemCls
9908 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9910 itemCls : "x-color-palette",
9912 * @cfg {String} value
9913 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9914 * the hex codes are case-sensitive.
9919 ctype: "Roo.ColorPalette",
9922 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9924 allowReselect : false,
9927 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9928 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9929 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9930 * of colors with the width setting until the box is symmetrical.</p>
9931 * <p>You can override individual colors if needed:</p>
9933 var cp = new Roo.ColorPalette();
9934 cp.colors[0] = "FF0000"; // change the first box to red
9937 Or you can provide a custom array of your own for complete control:
9939 var cp = new Roo.ColorPalette();
9940 cp.colors = ["000000", "993300", "333300"];
9945 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9946 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9947 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9948 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9949 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9953 onRender : function(container, position){
9954 var t = new Roo.MasterTemplate(
9955 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9957 var c = this.colors;
9958 for(var i = 0, len = c.length; i < len; i++){
9961 var el = document.createElement("div");
9962 el.className = this.itemCls;
9964 container.dom.insertBefore(el, position);
9965 this.el = Roo.get(el);
9966 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9967 if(this.clickEvent != 'click'){
9968 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9973 afterRender : function(){
9974 Roo.ColorPalette.superclass.afterRender.call(this);
9983 handleClick : function(e, t){
9986 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
9987 this.select(c.toUpperCase());
9992 * Selects the specified color in the palette (fires the select event)
9993 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
9995 select : function(color){
9996 color = color.replace("#", "");
9997 if(color != this.value || this.allowReselect){
10000 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10002 el.child("a.color-"+color).addClass("x-color-palette-sel");
10003 this.value = color;
10004 this.fireEvent("select", this, color);
10009 * Ext JS Library 1.1.1
10010 * Copyright(c) 2006-2007, Ext JS, LLC.
10012 * Originally Released Under LGPL - original licence link has changed is not relivant.
10015 * <script type="text/javascript">
10019 * @class Roo.DatePicker
10020 * @extends Roo.Component
10021 * Simple date picker class.
10023 * Create a new DatePicker
10024 * @param {Object} config The config object
10026 Roo.DatePicker = function(config){
10027 Roo.DatePicker.superclass.constructor.call(this, config);
10029 this.value = config && config.value ?
10030 config.value.clearTime() : new Date().clearTime();
10035 * Fires when a date is selected
10036 * @param {DatePicker} this
10037 * @param {Date} date The selected date
10043 this.on("select", this.handler, this.scope || this);
10045 // build the disabledDatesRE
10046 if(!this.disabledDatesRE && this.disabledDates){
10047 var dd = this.disabledDates;
10049 for(var i = 0; i < dd.length; i++){
10051 if(i != dd.length-1) re += "|";
10053 this.disabledDatesRE = new RegExp(re + ")");
10057 Roo.extend(Roo.DatePicker, Roo.Component, {
10059 * @cfg {String} todayText
10060 * The text to display on the button that selects the current date (defaults to "Today")
10062 todayText : "Today",
10064 * @cfg {String} okText
10065 * The text to display on the ok button
10067 okText : " OK ", //   to give the user extra clicking room
10069 * @cfg {String} cancelText
10070 * The text to display on the cancel button
10072 cancelText : "Cancel",
10074 * @cfg {String} todayTip
10075 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10077 todayTip : "{0} (Spacebar)",
10079 * @cfg {Date} minDate
10080 * Minimum allowable date (JavaScript date object, defaults to null)
10084 * @cfg {Date} maxDate
10085 * Maximum allowable date (JavaScript date object, defaults to null)
10089 * @cfg {String} minText
10090 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10092 minText : "This date is before the minimum date",
10094 * @cfg {String} maxText
10095 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10097 maxText : "This date is after the maximum date",
10099 * @cfg {String} format
10100 * The default date format string which can be overriden for localization support. The format must be
10101 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10105 * @cfg {Array} disabledDays
10106 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10108 disabledDays : null,
10110 * @cfg {String} disabledDaysText
10111 * The tooltip to display when the date falls on a disabled day (defaults to "")
10113 disabledDaysText : "",
10115 * @cfg {RegExp} disabledDatesRE
10116 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10118 disabledDatesRE : null,
10120 * @cfg {String} disabledDatesText
10121 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10123 disabledDatesText : "",
10125 * @cfg {Boolean} constrainToViewport
10126 * True to constrain the date picker to the viewport (defaults to true)
10128 constrainToViewport : true,
10130 * @cfg {Array} monthNames
10131 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10133 monthNames : Date.monthNames,
10135 * @cfg {Array} dayNames
10136 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10138 dayNames : Date.dayNames,
10140 * @cfg {String} nextText
10141 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10143 nextText: 'Next Month (Control+Right)',
10145 * @cfg {String} prevText
10146 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10148 prevText: 'Previous Month (Control+Left)',
10150 * @cfg {String} monthYearText
10151 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10153 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10155 * @cfg {Number} startDay
10156 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10160 * @cfg {Bool} showClear
10161 * Show a clear button (usefull for date form elements that can be blank.)
10167 * Sets the value of the date field
10168 * @param {Date} value The date to set
10170 setValue : function(value){
10171 var old = this.value;
10172 this.value = value.clearTime(true);
10174 this.update(this.value);
10179 * Gets the current selected value of the date field
10180 * @return {Date} The selected date
10182 getValue : function(){
10187 focus : function(){
10189 this.update(this.activeDate);
10194 onRender : function(container, position){
10196 '<table cellspacing="0">',
10197 '<tr><td class="x-date-left"><a href="#" title="', this.prevText ,'"> </a></td><td class="x-date-middle" align="center"></td><td class="x-date-right"><a href="#" title="', this.nextText ,'"> </a></td></tr>',
10198 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10199 var dn = this.dayNames;
10200 for(var i = 0; i < 7; i++){
10201 var d = this.startDay+i;
10205 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10207 m[m.length] = "</tr></thead><tbody><tr>";
10208 for(var i = 0; i < 42; i++) {
10209 if(i % 7 == 0 && i != 0){
10210 m[m.length] = "</tr><tr>";
10212 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10214 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10215 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10217 var el = document.createElement("div");
10218 el.className = "x-date-picker";
10219 el.innerHTML = m.join("");
10221 container.dom.insertBefore(el, position);
10223 this.el = Roo.get(el);
10224 this.eventEl = Roo.get(el.firstChild);
10226 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10227 handler: this.showPrevMonth,
10229 preventDefault:true,
10233 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10234 handler: this.showNextMonth,
10236 preventDefault:true,
10240 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10242 this.monthPicker = this.el.down('div.x-date-mp');
10243 this.monthPicker.enableDisplayMode('block');
10245 var kn = new Roo.KeyNav(this.eventEl, {
10246 "left" : function(e){
10248 this.showPrevMonth() :
10249 this.update(this.activeDate.add("d", -1));
10252 "right" : function(e){
10254 this.showNextMonth() :
10255 this.update(this.activeDate.add("d", 1));
10258 "up" : function(e){
10260 this.showNextYear() :
10261 this.update(this.activeDate.add("d", -7));
10264 "down" : function(e){
10266 this.showPrevYear() :
10267 this.update(this.activeDate.add("d", 7));
10270 "pageUp" : function(e){
10271 this.showNextMonth();
10274 "pageDown" : function(e){
10275 this.showPrevMonth();
10278 "enter" : function(e){
10279 e.stopPropagation();
10286 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10288 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10290 this.el.unselectable();
10292 this.cells = this.el.select("table.x-date-inner tbody td");
10293 this.textNodes = this.el.query("table.x-date-inner tbody span");
10295 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10297 tooltip: this.monthYearText
10300 this.mbtn.on('click', this.showMonthPicker, this);
10301 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10304 var today = (new Date()).dateFormat(this.format);
10306 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10307 if (this.showClear) {
10308 baseTb.add( new Roo.Toolbar.Fill());
10311 text: String.format(this.todayText, today),
10312 tooltip: String.format(this.todayTip, today),
10313 handler: this.selectToday,
10317 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10320 if (this.showClear) {
10322 baseTb.add( new Roo.Toolbar.Fill());
10325 cls: 'x-btn-icon x-btn-clear',
10326 handler: function() {
10328 this.fireEvent("select", this, '');
10338 this.update(this.value);
10341 createMonthPicker : function(){
10342 if(!this.monthPicker.dom.firstChild){
10343 var buf = ['<table border="0" cellspacing="0">'];
10344 for(var i = 0; i < 6; i++){
10346 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10347 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10349 '<td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-prev"></a></td><td class="x-date-mp-ybtn" align="center"><a class="x-date-mp-next"></a></td></tr>' :
10350 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10354 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10356 '</button><button type="button" class="x-date-mp-cancel">',
10358 '</button></td></tr>',
10361 this.monthPicker.update(buf.join(''));
10362 this.monthPicker.on('click', this.onMonthClick, this);
10363 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10365 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10366 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10368 this.mpMonths.each(function(m, a, i){
10371 m.dom.xmonth = 5 + Math.round(i * .5);
10373 m.dom.xmonth = Math.round((i-1) * .5);
10379 showMonthPicker : function(){
10380 this.createMonthPicker();
10381 var size = this.el.getSize();
10382 this.monthPicker.setSize(size);
10383 this.monthPicker.child('table').setSize(size);
10385 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10386 this.updateMPMonth(this.mpSelMonth);
10387 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10388 this.updateMPYear(this.mpSelYear);
10390 this.monthPicker.slideIn('t', {duration:.2});
10393 updateMPYear : function(y){
10395 var ys = this.mpYears.elements;
10396 for(var i = 1; i <= 10; i++){
10397 var td = ys[i-1], y2;
10399 y2 = y + Math.round(i * .5);
10400 td.firstChild.innerHTML = y2;
10403 y2 = y - (5-Math.round(i * .5));
10404 td.firstChild.innerHTML = y2;
10407 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10411 updateMPMonth : function(sm){
10412 this.mpMonths.each(function(m, a, i){
10413 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10417 selectMPMonth: function(m){
10421 onMonthClick : function(e, t){
10423 var el = new Roo.Element(t), pn;
10424 if(el.is('button.x-date-mp-cancel')){
10425 this.hideMonthPicker();
10427 else if(el.is('button.x-date-mp-ok')){
10428 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10429 this.hideMonthPicker();
10431 else if(pn = el.up('td.x-date-mp-month', 2)){
10432 this.mpMonths.removeClass('x-date-mp-sel');
10433 pn.addClass('x-date-mp-sel');
10434 this.mpSelMonth = pn.dom.xmonth;
10436 else if(pn = el.up('td.x-date-mp-year', 2)){
10437 this.mpYears.removeClass('x-date-mp-sel');
10438 pn.addClass('x-date-mp-sel');
10439 this.mpSelYear = pn.dom.xyear;
10441 else if(el.is('a.x-date-mp-prev')){
10442 this.updateMPYear(this.mpyear-10);
10444 else if(el.is('a.x-date-mp-next')){
10445 this.updateMPYear(this.mpyear+10);
10449 onMonthDblClick : function(e, t){
10451 var el = new Roo.Element(t), pn;
10452 if(pn = el.up('td.x-date-mp-month', 2)){
10453 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10454 this.hideMonthPicker();
10456 else if(pn = el.up('td.x-date-mp-year', 2)){
10457 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10458 this.hideMonthPicker();
10462 hideMonthPicker : function(disableAnim){
10463 if(this.monthPicker){
10464 if(disableAnim === true){
10465 this.monthPicker.hide();
10467 this.monthPicker.slideOut('t', {duration:.2});
10473 showPrevMonth : function(e){
10474 this.update(this.activeDate.add("mo", -1));
10478 showNextMonth : function(e){
10479 this.update(this.activeDate.add("mo", 1));
10483 showPrevYear : function(){
10484 this.update(this.activeDate.add("y", -1));
10488 showNextYear : function(){
10489 this.update(this.activeDate.add("y", 1));
10493 handleMouseWheel : function(e){
10494 var delta = e.getWheelDelta();
10496 this.showPrevMonth();
10498 } else if(delta < 0){
10499 this.showNextMonth();
10505 handleDateClick : function(e, t){
10507 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10508 this.setValue(new Date(t.dateValue));
10509 this.fireEvent("select", this, this.value);
10514 selectToday : function(){
10515 this.setValue(new Date().clearTime());
10516 this.fireEvent("select", this, this.value);
10520 update : function(date){
10521 var vd = this.activeDate;
10522 this.activeDate = date;
10524 var t = date.getTime();
10525 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10526 this.cells.removeClass("x-date-selected");
10527 this.cells.each(function(c){
10528 if(c.dom.firstChild.dateValue == t){
10529 c.addClass("x-date-selected");
10530 setTimeout(function(){
10531 try{c.dom.firstChild.focus();}catch(e){}
10539 var days = date.getDaysInMonth();
10540 var firstOfMonth = date.getFirstDateOfMonth();
10541 var startingPos = firstOfMonth.getDay()-this.startDay;
10543 if(startingPos <= this.startDay){
10547 var pm = date.add("mo", -1);
10548 var prevStart = pm.getDaysInMonth()-startingPos;
10550 var cells = this.cells.elements;
10551 var textEls = this.textNodes;
10552 days += startingPos;
10554 // convert everything to numbers so it's fast
10555 var day = 86400000;
10556 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10557 var today = new Date().clearTime().getTime();
10558 var sel = date.clearTime().getTime();
10559 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10560 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10561 var ddMatch = this.disabledDatesRE;
10562 var ddText = this.disabledDatesText;
10563 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10564 var ddaysText = this.disabledDaysText;
10565 var format = this.format;
10567 var setCellClass = function(cal, cell){
10569 var t = d.getTime();
10570 cell.firstChild.dateValue = t;
10572 cell.className += " x-date-today";
10573 cell.title = cal.todayText;
10576 cell.className += " x-date-selected";
10577 setTimeout(function(){
10578 try{cell.firstChild.focus();}catch(e){}
10583 cell.className = " x-date-disabled";
10584 cell.title = cal.minText;
10588 cell.className = " x-date-disabled";
10589 cell.title = cal.maxText;
10593 if(ddays.indexOf(d.getDay()) != -1){
10594 cell.title = ddaysText;
10595 cell.className = " x-date-disabled";
10598 if(ddMatch && format){
10599 var fvalue = d.dateFormat(format);
10600 if(ddMatch.test(fvalue)){
10601 cell.title = ddText.replace("%0", fvalue);
10602 cell.className = " x-date-disabled";
10608 for(; i < startingPos; i++) {
10609 textEls[i].innerHTML = (++prevStart);
10610 d.setDate(d.getDate()+1);
10611 cells[i].className = "x-date-prevday";
10612 setCellClass(this, cells[i]);
10614 for(; i < days; i++){
10615 intDay = i - startingPos + 1;
10616 textEls[i].innerHTML = (intDay);
10617 d.setDate(d.getDate()+1);
10618 cells[i].className = "x-date-active";
10619 setCellClass(this, cells[i]);
10622 for(; i < 42; i++) {
10623 textEls[i].innerHTML = (++extraDays);
10624 d.setDate(d.getDate()+1);
10625 cells[i].className = "x-date-nextday";
10626 setCellClass(this, cells[i]);
10629 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10631 if(!this.internalRender){
10632 var main = this.el.dom.firstChild;
10633 var w = main.offsetWidth;
10634 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10635 Roo.fly(main).setWidth(w);
10636 this.internalRender = true;
10637 // opera does not respect the auto grow header center column
10638 // then, after it gets a width opera refuses to recalculate
10639 // without a second pass
10640 if(Roo.isOpera && !this.secondPass){
10641 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10642 this.secondPass = true;
10643 this.update.defer(10, this, [date]);
10649 * Ext JS Library 1.1.1
10650 * Copyright(c) 2006-2007, Ext JS, LLC.
10652 * Originally Released Under LGPL - original licence link has changed is not relivant.
10655 * <script type="text/javascript">
10658 * @class Roo.TabPanel
10659 * @extends Roo.util.Observable
10660 * A lightweight tab container.
10664 // basic tabs 1, built from existing content
10665 var tabs = new Roo.TabPanel("tabs1");
10666 tabs.addTab("script", "View Script");
10667 tabs.addTab("markup", "View Markup");
10668 tabs.activate("script");
10670 // more advanced tabs, built from javascript
10671 var jtabs = new Roo.TabPanel("jtabs");
10672 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10674 // set up the UpdateManager
10675 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10676 var updater = tab2.getUpdateManager();
10677 updater.setDefaultUrl("ajax1.htm");
10678 tab2.on('activate', updater.refresh, updater, true);
10680 // Use setUrl for Ajax loading
10681 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10682 tab3.setUrl("ajax2.htm", null, true);
10685 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10688 jtabs.activate("jtabs-1");
10691 * Create a new TabPanel.
10692 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10693 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10695 Roo.TabPanel = function(container, config){
10697 * The container element for this TabPanel.
10698 * @type Roo.Element
10700 this.el = Roo.get(container, true);
10702 if(typeof config == "boolean"){
10703 this.tabPosition = config ? "bottom" : "top";
10705 Roo.apply(this, config);
10708 if(this.tabPosition == "bottom"){
10709 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10710 this.el.addClass("x-tabs-bottom");
10712 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10713 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10714 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10716 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10718 if(this.tabPosition != "bottom"){
10719 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10720 * @type Roo.Element
10722 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10723 this.el.addClass("x-tabs-top");
10727 this.bodyEl.setStyle("position", "relative");
10729 this.active = null;
10730 this.activateDelegate = this.activate.createDelegate(this);
10735 * Fires when the active tab changes
10736 * @param {Roo.TabPanel} this
10737 * @param {Roo.TabPanelItem} activePanel The new active tab
10741 * @event beforetabchange
10742 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10743 * @param {Roo.TabPanel} this
10744 * @param {Object} e Set cancel to true on this object to cancel the tab change
10745 * @param {Roo.TabPanelItem} tab The tab being changed to
10747 "beforetabchange" : true
10750 Roo.EventManager.onWindowResize(this.onResize, this);
10751 this.cpad = this.el.getPadding("lr");
10752 this.hiddenCount = 0;
10754 Roo.TabPanel.superclass.constructor.call(this);
10757 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10759 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10761 tabPosition : "top",
10763 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10765 currentTabWidth : 0,
10767 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10771 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10775 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10777 preferredTabWidth : 175,
10779 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10781 resizeTabs : false,
10783 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10785 monitorResize : true,
10788 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10789 * @param {String} id The id of the div to use <b>or create</b>
10790 * @param {String} text The text for the tab
10791 * @param {String} content (optional) Content to put in the TabPanelItem body
10792 * @param {Boolean} closable (optional) True to create a close icon on the tab
10793 * @return {Roo.TabPanelItem} The created TabPanelItem
10795 addTab : function(id, text, content, closable){
10796 var item = new Roo.TabPanelItem(this, id, text, closable);
10797 this.addTabItem(item);
10799 item.setContent(content);
10805 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10806 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10807 * @return {Roo.TabPanelItem}
10809 getTab : function(id){
10810 return this.items[id];
10814 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10815 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10817 hideTab : function(id){
10818 var t = this.items[id];
10821 this.hiddenCount++;
10822 this.autoSizeTabs();
10827 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10828 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10830 unhideTab : function(id){
10831 var t = this.items[id];
10833 t.setHidden(false);
10834 this.hiddenCount--;
10835 this.autoSizeTabs();
10840 * Adds an existing {@link Roo.TabPanelItem}.
10841 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10843 addTabItem : function(item){
10844 this.items[item.id] = item;
10845 this.items.push(item);
10846 if(this.resizeTabs){
10847 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10848 this.autoSizeTabs();
10855 * Removes a {@link Roo.TabPanelItem}.
10856 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10858 removeTab : function(id){
10859 var items = this.items;
10860 var tab = items[id];
10861 if(!tab) { return; }
10862 var index = items.indexOf(tab);
10863 if(this.active == tab && items.length > 1){
10864 var newTab = this.getNextAvailable(index);
10869 this.stripEl.dom.removeChild(tab.pnode.dom);
10870 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10871 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10873 items.splice(index, 1);
10874 delete this.items[tab.id];
10875 tab.fireEvent("close", tab);
10876 tab.purgeListeners();
10877 this.autoSizeTabs();
10880 getNextAvailable : function(start){
10881 var items = this.items;
10883 // look for a next tab that will slide over to
10884 // replace the one being removed
10885 while(index < items.length){
10886 var item = items[++index];
10887 if(item && !item.isHidden()){
10891 // if one isn't found select the previous tab (on the left)
10894 var item = items[--index];
10895 if(item && !item.isHidden()){
10903 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10904 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10906 disableTab : function(id){
10907 var tab = this.items[id];
10908 if(tab && this.active != tab){
10914 * Enables a {@link Roo.TabPanelItem} that is disabled.
10915 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10917 enableTab : function(id){
10918 var tab = this.items[id];
10923 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10924 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10925 * @return {Roo.TabPanelItem} The TabPanelItem.
10927 activate : function(id){
10928 var tab = this.items[id];
10932 if(tab == this.active || tab.disabled){
10936 this.fireEvent("beforetabchange", this, e, tab);
10937 if(e.cancel !== true && !tab.disabled){
10939 this.active.hide();
10941 this.active = this.items[id];
10942 this.active.show();
10943 this.fireEvent("tabchange", this, this.active);
10949 * Gets the active {@link Roo.TabPanelItem}.
10950 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10952 getActiveTab : function(){
10953 return this.active;
10957 * Updates the tab body element to fit the height of the container element
10958 * for overflow scrolling
10959 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10961 syncHeight : function(targetHeight){
10962 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10963 var bm = this.bodyEl.getMargins();
10964 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10965 this.bodyEl.setHeight(newHeight);
10969 onResize : function(){
10970 if(this.monitorResize){
10971 this.autoSizeTabs();
10976 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
10978 beginUpdate : function(){
10979 this.updating = true;
10983 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
10985 endUpdate : function(){
10986 this.updating = false;
10987 this.autoSizeTabs();
10991 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
10993 autoSizeTabs : function(){
10994 var count = this.items.length;
10995 var vcount = count - this.hiddenCount;
10996 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
10997 var w = Math.max(this.el.getWidth() - this.cpad, 10);
10998 var availWidth = Math.floor(w / vcount);
10999 var b = this.stripBody;
11000 if(b.getWidth() > w){
11001 var tabs = this.items;
11002 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11003 if(availWidth < this.minTabWidth){
11004 /*if(!this.sleft){ // incomplete scrolling code
11005 this.createScrollButtons();
11008 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11011 if(this.currentTabWidth < this.preferredTabWidth){
11012 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11018 * Returns the number of tabs in this TabPanel.
11021 getCount : function(){
11022 return this.items.length;
11026 * Resizes all the tabs to the passed width
11027 * @param {Number} The new width
11029 setTabWidth : function(width){
11030 this.currentTabWidth = width;
11031 for(var i = 0, len = this.items.length; i < len; i++) {
11032 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11037 * Destroys this TabPanel
11038 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11040 destroy : function(removeEl){
11041 Roo.EventManager.removeResizeListener(this.onResize, this);
11042 for(var i = 0, len = this.items.length; i < len; i++){
11043 this.items[i].purgeListeners();
11045 if(removeEl === true){
11046 this.el.update("");
11053 * @class Roo.TabPanelItem
11054 * @extends Roo.util.Observable
11055 * Represents an individual item (tab plus body) in a TabPanel.
11056 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11057 * @param {String} id The id of this TabPanelItem
11058 * @param {String} text The text for the tab of this TabPanelItem
11059 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11061 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11063 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11064 * @type Roo.TabPanel
11066 this.tabPanel = tabPanel;
11068 * The id for this TabPanelItem
11073 this.disabled = false;
11077 this.loaded = false;
11078 this.closable = closable;
11081 * The body element for this TabPanelItem.
11082 * @type Roo.Element
11084 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11085 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11086 this.bodyEl.setStyle("display", "block");
11087 this.bodyEl.setStyle("zoom", "1");
11090 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11092 this.el = Roo.get(els.el, true);
11093 this.inner = Roo.get(els.inner, true);
11094 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11095 this.pnode = Roo.get(els.el.parentNode, true);
11096 this.el.on("mousedown", this.onTabMouseDown, this);
11097 this.el.on("click", this.onTabClick, this);
11100 var c = Roo.get(els.close, true);
11101 c.dom.title = this.closeText;
11102 c.addClassOnOver("close-over");
11103 c.on("click", this.closeClick, this);
11109 * Fires when this tab becomes the active tab.
11110 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11111 * @param {Roo.TabPanelItem} this
11115 * @event beforeclose
11116 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11117 * @param {Roo.TabPanelItem} this
11118 * @param {Object} e Set cancel to true on this object to cancel the close.
11120 "beforeclose": true,
11123 * Fires when this tab is closed.
11124 * @param {Roo.TabPanelItem} this
11128 * @event deactivate
11129 * Fires when this tab is no longer the active tab.
11130 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11131 * @param {Roo.TabPanelItem} this
11133 "deactivate" : true
11135 this.hidden = false;
11137 Roo.TabPanelItem.superclass.constructor.call(this);
11140 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11141 purgeListeners : function(){
11142 Roo.util.Observable.prototype.purgeListeners.call(this);
11143 this.el.removeAllListeners();
11146 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11149 this.pnode.addClass("on");
11152 this.tabPanel.stripWrap.repaint();
11154 this.fireEvent("activate", this.tabPanel, this);
11158 * Returns true if this tab is the active tab.
11159 * @return {Boolean}
11161 isActive : function(){
11162 return this.tabPanel.getActiveTab() == this;
11166 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11169 this.pnode.removeClass("on");
11171 this.fireEvent("deactivate", this.tabPanel, this);
11174 hideAction : function(){
11175 this.bodyEl.hide();
11176 this.bodyEl.setStyle("position", "absolute");
11177 this.bodyEl.setLeft("-20000px");
11178 this.bodyEl.setTop("-20000px");
11181 showAction : function(){
11182 this.bodyEl.setStyle("position", "relative");
11183 this.bodyEl.setTop("");
11184 this.bodyEl.setLeft("");
11185 this.bodyEl.show();
11189 * Set the tooltip for the tab.
11190 * @param {String} tooltip The tab's tooltip
11192 setTooltip : function(text){
11193 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11194 this.textEl.dom.qtip = text;
11195 this.textEl.dom.removeAttribute('title');
11197 this.textEl.dom.title = text;
11201 onTabClick : function(e){
11202 e.preventDefault();
11203 this.tabPanel.activate(this.id);
11206 onTabMouseDown : function(e){
11207 e.preventDefault();
11208 this.tabPanel.activate(this.id);
11211 getWidth : function(){
11212 return this.inner.getWidth();
11215 setWidth : function(width){
11216 var iwidth = width - this.pnode.getPadding("lr");
11217 this.inner.setWidth(iwidth);
11218 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11219 this.pnode.setWidth(width);
11223 * Show or hide the tab
11224 * @param {Boolean} hidden True to hide or false to show.
11226 setHidden : function(hidden){
11227 this.hidden = hidden;
11228 this.pnode.setStyle("display", hidden ? "none" : "");
11232 * Returns true if this tab is "hidden"
11233 * @return {Boolean}
11235 isHidden : function(){
11236 return this.hidden;
11240 * Returns the text for this tab
11243 getText : function(){
11247 autoSize : function(){
11248 //this.el.beginMeasure();
11249 this.textEl.setWidth(1);
11250 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11251 //this.el.endMeasure();
11255 * Sets the text for the tab (Note: this also sets the tooltip text)
11256 * @param {String} text The tab's text and tooltip
11258 setText : function(text){
11260 this.textEl.update(text);
11261 this.setTooltip(text);
11262 if(!this.tabPanel.resizeTabs){
11267 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11269 activate : function(){
11270 this.tabPanel.activate(this.id);
11274 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11276 disable : function(){
11277 if(this.tabPanel.active != this){
11278 this.disabled = true;
11279 this.pnode.addClass("disabled");
11284 * Enables this TabPanelItem if it was previously disabled.
11286 enable : function(){
11287 this.disabled = false;
11288 this.pnode.removeClass("disabled");
11292 * Sets the content for this TabPanelItem.
11293 * @param {String} content The content
11294 * @param {Boolean} loadScripts true to look for and load scripts
11296 setContent : function(content, loadScripts){
11297 this.bodyEl.update(content, loadScripts);
11301 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11302 * @return {Roo.UpdateManager} The UpdateManager
11304 getUpdateManager : function(){
11305 return this.bodyEl.getUpdateManager();
11309 * Set a URL to be used to load the content for this TabPanelItem.
11310 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11311 * @param {String/Object} params (optional) The string params for the update call or an object of the params. See {@link Roo.UpdateManager#update} for more details. (Defaults to null)
11312 * @param {Boolean} loadOnce (optional) Whether to only load the content once. If this is false it makes the Ajax call every time this TabPanelItem is activated. (Defaults to false)
11313 * @return {Roo.UpdateManager} The UpdateManager
11315 setUrl : function(url, params, loadOnce){
11316 if(this.refreshDelegate){
11317 this.un('activate', this.refreshDelegate);
11319 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11320 this.on("activate", this.refreshDelegate);
11321 return this.bodyEl.getUpdateManager();
11325 _handleRefresh : function(url, params, loadOnce){
11326 if(!loadOnce || !this.loaded){
11327 var updater = this.bodyEl.getUpdateManager();
11328 updater.update(url, params, this._setLoaded.createDelegate(this));
11333 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11334 * Will fail silently if the setUrl method has not been called.
11335 * This does not activate the panel, just updates its content.
11337 refresh : function(){
11338 if(this.refreshDelegate){
11339 this.loaded = false;
11340 this.refreshDelegate();
11345 _setLoaded : function(){
11346 this.loaded = true;
11350 closeClick : function(e){
11353 this.fireEvent("beforeclose", this, o);
11354 if(o.cancel !== true){
11355 this.tabPanel.removeTab(this.id);
11359 * The text displayed in the tooltip for the close icon.
11362 closeText : "Close this tab"
11366 Roo.TabPanel.prototype.createStrip = function(container){
11367 var strip = document.createElement("div");
11368 strip.className = "x-tabs-wrap";
11369 container.appendChild(strip);
11373 Roo.TabPanel.prototype.createStripList = function(strip){
11374 // div wrapper for retard IE
11375 strip.innerHTML = '<div class="x-tabs-strip-wrap"><table class="x-tabs-strip" cellspacing="0" cellpadding="0" border="0"><tbody><tr></tr></tbody></table></div>';
11376 return strip.firstChild.firstChild.firstChild.firstChild;
11379 Roo.TabPanel.prototype.createBody = function(container){
11380 var body = document.createElement("div");
11381 Roo.id(body, "tab-body");
11382 Roo.fly(body).addClass("x-tabs-body");
11383 container.appendChild(body);
11387 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11388 var body = Roo.getDom(id);
11390 body = document.createElement("div");
11393 Roo.fly(body).addClass("x-tabs-item-body");
11394 bodyEl.insertBefore(body, bodyEl.firstChild);
11398 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11399 var td = document.createElement("td");
11400 stripEl.appendChild(td);
11402 td.className = "x-tabs-closable";
11403 if(!this.closeTpl){
11404 this.closeTpl = new Roo.Template(
11405 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11406 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11407 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11410 var el = this.closeTpl.overwrite(td, {"text": text});
11411 var close = el.getElementsByTagName("div")[0];
11412 var inner = el.getElementsByTagName("em")[0];
11413 return {"el": el, "close": close, "inner": inner};
11416 this.tabTpl = new Roo.Template(
11417 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11418 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11421 var el = this.tabTpl.overwrite(td, {"text": text});
11422 var inner = el.getElementsByTagName("em")[0];
11423 return {"el": el, "inner": inner};
11427 * Ext JS Library 1.1.1
11428 * Copyright(c) 2006-2007, Ext JS, LLC.
11430 * Originally Released Under LGPL - original licence link has changed is not relivant.
11433 * <script type="text/javascript">
11437 * @class Roo.Button
11438 * @extends Roo.util.Observable
11439 * Simple Button class
11440 * @cfg {String} text The button text
11441 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11442 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11443 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11444 * @cfg {Object} scope The scope of the handler
11445 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11446 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11447 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11448 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11449 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11450 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11451 applies if enableToggle = true)
11452 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11453 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11454 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11456 * Create a new button
11457 * @param {Object} config The config object
11459 Roo.Button = function(renderTo, config)
11463 renderTo = config.renderTo || false;
11466 Roo.apply(this, config);
11470 * Fires when this button is clicked
11471 * @param {Button} this
11472 * @param {EventObject} e The click event
11477 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11478 * @param {Button} this
11479 * @param {Boolean} pressed
11484 * Fires when the mouse hovers over the button
11485 * @param {Button} this
11486 * @param {Event} e The event object
11488 'mouseover' : true,
11491 * Fires when the mouse exits the button
11492 * @param {Button} this
11493 * @param {Event} e The event object
11498 * Fires when the button is rendered
11499 * @param {Button} this
11504 this.menu = Roo.menu.MenuMgr.get(this.menu);
11506 // register listeners first!! - so render can be captured..
11507 Roo.util.Observable.call(this);
11509 this.render(renderTo);
11515 Roo.extend(Roo.Button, Roo.util.Observable, {
11521 * Read-only. True if this button is hidden
11526 * Read-only. True if this button is disabled
11531 * Read-only. True if this button is pressed (only if enableToggle = true)
11537 * @cfg {Number} tabIndex
11538 * The DOM tabIndex for this button (defaults to undefined)
11540 tabIndex : undefined,
11543 * @cfg {Boolean} enableToggle
11544 * True to enable pressed/not pressed toggling (defaults to false)
11546 enableToggle: false,
11548 * @cfg {Mixed} menu
11549 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11553 * @cfg {String} menuAlign
11554 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11556 menuAlign : "tl-bl?",
11559 * @cfg {String} iconCls
11560 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11562 iconCls : undefined,
11564 * @cfg {String} type
11565 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11570 menuClassTarget: 'tr',
11573 * @cfg {String} clickEvent
11574 * The type of event to map to the button's event handler (defaults to 'click')
11576 clickEvent : 'click',
11579 * @cfg {Boolean} handleMouseEvents
11580 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11582 handleMouseEvents : true,
11585 * @cfg {String} tooltipType
11586 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11588 tooltipType : 'qtip',
11591 * @cfg {String} cls
11592 * A CSS class to apply to the button's main element.
11596 * @cfg {Roo.Template} template (Optional)
11597 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11598 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11599 * require code modifications if required elements (e.g. a button) aren't present.
11603 render : function(renderTo){
11605 if(this.hideParent){
11606 this.parentEl = Roo.get(renderTo);
11608 if(!this.dhconfig){
11609 if(!this.template){
11610 if(!Roo.Button.buttonTemplate){
11611 // hideous table template
11612 Roo.Button.buttonTemplate = new Roo.Template(
11613 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11614 '<td class="x-btn-left"><i> </i></td><td class="x-btn-center"><em unselectable="on"><button class="x-btn-text" type="{1}">{0}</button></em></td><td class="x-btn-right"><i> </i></td>',
11615 "</tr></tbody></table>");
11617 this.template = Roo.Button.buttonTemplate;
11619 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11620 var btnEl = btn.child("button:first");
11621 btnEl.on('focus', this.onFocus, this);
11622 btnEl.on('blur', this.onBlur, this);
11624 btn.addClass(this.cls);
11627 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11630 btnEl.addClass(this.iconCls);
11632 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11635 if(this.tabIndex !== undefined){
11636 btnEl.dom.tabIndex = this.tabIndex;
11639 if(typeof this.tooltip == 'object'){
11640 Roo.QuickTips.tips(Roo.apply({
11644 btnEl.dom[this.tooltipType] = this.tooltip;
11648 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11652 this.el.dom.id = this.el.id = this.id;
11655 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11656 this.menu.on("show", this.onMenuShow, this);
11657 this.menu.on("hide", this.onMenuHide, this);
11659 btn.addClass("x-btn");
11660 if(Roo.isIE && !Roo.isIE7){
11661 this.autoWidth.defer(1, this);
11665 if(this.handleMouseEvents){
11666 btn.on("mouseover", this.onMouseOver, this);
11667 btn.on("mouseout", this.onMouseOut, this);
11668 btn.on("mousedown", this.onMouseDown, this);
11670 btn.on(this.clickEvent, this.onClick, this);
11671 //btn.on("mouseup", this.onMouseUp, this);
11678 Roo.ButtonToggleMgr.register(this);
11680 this.el.addClass("x-btn-pressed");
11683 var repeater = new Roo.util.ClickRepeater(btn,
11684 typeof this.repeat == "object" ? this.repeat : {}
11686 repeater.on("click", this.onClick, this);
11689 this.fireEvent('render', this);
11693 * Returns the button's underlying element
11694 * @return {Roo.Element} The element
11696 getEl : function(){
11701 * Destroys this Button and removes any listeners.
11703 destroy : function(){
11704 Roo.ButtonToggleMgr.unregister(this);
11705 this.el.removeAllListeners();
11706 this.purgeListeners();
11711 autoWidth : function(){
11713 this.el.setWidth("auto");
11714 if(Roo.isIE7 && Roo.isStrict){
11715 var ib = this.el.child('button');
11716 if(ib && ib.getWidth() > 20){
11718 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11723 this.el.beginMeasure();
11725 if(this.el.getWidth() < this.minWidth){
11726 this.el.setWidth(this.minWidth);
11729 this.el.endMeasure();
11736 * Assigns this button's click handler
11737 * @param {Function} handler The function to call when the button is clicked
11738 * @param {Object} scope (optional) Scope for the function passed in
11740 setHandler : function(handler, scope){
11741 this.handler = handler;
11742 this.scope = scope;
11746 * Sets this button's text
11747 * @param {String} text The button text
11749 setText : function(text){
11752 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11758 * Gets the text for this button
11759 * @return {String} The button text
11761 getText : function(){
11769 this.hidden = false;
11771 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11779 this.hidden = true;
11781 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11786 * Convenience function for boolean show/hide
11787 * @param {Boolean} visible True to show, false to hide
11789 setVisible: function(visible){
11798 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11799 * @param {Boolean} state (optional) Force a particular state
11801 toggle : function(state){
11802 state = state === undefined ? !this.pressed : state;
11803 if(state != this.pressed){
11805 this.el.addClass("x-btn-pressed");
11806 this.pressed = true;
11807 this.fireEvent("toggle", this, true);
11809 this.el.removeClass("x-btn-pressed");
11810 this.pressed = false;
11811 this.fireEvent("toggle", this, false);
11813 if(this.toggleHandler){
11814 this.toggleHandler.call(this.scope || this, this, state);
11822 focus : function(){
11823 this.el.child('button:first').focus();
11827 * Disable this button
11829 disable : function(){
11831 this.el.addClass("x-btn-disabled");
11833 this.disabled = true;
11837 * Enable this button
11839 enable : function(){
11841 this.el.removeClass("x-btn-disabled");
11843 this.disabled = false;
11847 * Convenience function for boolean enable/disable
11848 * @param {Boolean} enabled True to enable, false to disable
11850 setDisabled : function(v){
11851 this[v !== true ? "enable" : "disable"]();
11855 onClick : function(e){
11857 e.preventDefault();
11862 if(!this.disabled){
11863 if(this.enableToggle){
11866 if(this.menu && !this.menu.isVisible()){
11867 this.menu.show(this.el, this.menuAlign);
11869 this.fireEvent("click", this, e);
11871 this.el.removeClass("x-btn-over");
11872 this.handler.call(this.scope || this, this, e);
11877 onMouseOver : function(e){
11878 if(!this.disabled){
11879 this.el.addClass("x-btn-over");
11880 this.fireEvent('mouseover', this, e);
11884 onMouseOut : function(e){
11885 if(!e.within(this.el, true)){
11886 this.el.removeClass("x-btn-over");
11887 this.fireEvent('mouseout', this, e);
11891 onFocus : function(e){
11892 if(!this.disabled){
11893 this.el.addClass("x-btn-focus");
11897 onBlur : function(e){
11898 this.el.removeClass("x-btn-focus");
11901 onMouseDown : function(e){
11902 if(!this.disabled && e.button == 0){
11903 this.el.addClass("x-btn-click");
11904 Roo.get(document).on('mouseup', this.onMouseUp, this);
11908 onMouseUp : function(e){
11910 this.el.removeClass("x-btn-click");
11911 Roo.get(document).un('mouseup', this.onMouseUp, this);
11915 onMenuShow : function(e){
11916 this.el.addClass("x-btn-menu-active");
11919 onMenuHide : function(e){
11920 this.el.removeClass("x-btn-menu-active");
11924 // Private utility class used by Button
11925 Roo.ButtonToggleMgr = function(){
11928 function toggleGroup(btn, state){
11930 var g = groups[btn.toggleGroup];
11931 for(var i = 0, l = g.length; i < l; i++){
11933 g[i].toggle(false);
11940 register : function(btn){
11941 if(!btn.toggleGroup){
11944 var g = groups[btn.toggleGroup];
11946 g = groups[btn.toggleGroup] = [];
11949 btn.on("toggle", toggleGroup);
11952 unregister : function(btn){
11953 if(!btn.toggleGroup){
11956 var g = groups[btn.toggleGroup];
11959 btn.un("toggle", toggleGroup);
11965 * Ext JS Library 1.1.1
11966 * Copyright(c) 2006-2007, Ext JS, LLC.
11968 * Originally Released Under LGPL - original licence link has changed is not relivant.
11971 * <script type="text/javascript">
11975 * @class Roo.SplitButton
11976 * @extends Roo.Button
11977 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
11978 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
11979 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
11980 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
11981 * @cfg {String} arrowTooltip The title attribute of the arrow
11983 * Create a new menu button
11984 * @param {String/HTMLElement/Element} renderTo The element to append the button to
11985 * @param {Object} config The config object
11987 Roo.SplitButton = function(renderTo, config){
11988 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
11990 * @event arrowclick
11991 * Fires when this button's arrow is clicked
11992 * @param {SplitButton} this
11993 * @param {EventObject} e The click event
11995 this.addEvents({"arrowclick":true});
11998 Roo.extend(Roo.SplitButton, Roo.Button, {
11999 render : function(renderTo){
12000 // this is one sweet looking template!
12001 var tpl = new Roo.Template(
12002 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12003 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12004 '<tr><td class="x-btn-left"><i> </i></td><td class="x-btn-center"><button class="x-btn-text" type="{1}">{0}</button></td></tr>',
12005 "</tbody></table></td><td>",
12006 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12007 '<tr><td class="x-btn-center"><button class="x-btn-menu-arrow-el" type="button"> </button></td><td class="x-btn-right"><i> </i></td></tr>',
12008 "</tbody></table></td></tr></table>"
12010 var btn = tpl.append(renderTo, [this.text, this.type], true);
12011 var btnEl = btn.child("button");
12013 btn.addClass(this.cls);
12016 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12019 btnEl.addClass(this.iconCls);
12021 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12025 if(this.handleMouseEvents){
12026 btn.on("mouseover", this.onMouseOver, this);
12027 btn.on("mouseout", this.onMouseOut, this);
12028 btn.on("mousedown", this.onMouseDown, this);
12029 btn.on("mouseup", this.onMouseUp, this);
12031 btn.on(this.clickEvent, this.onClick, this);
12033 if(typeof this.tooltip == 'object'){
12034 Roo.QuickTips.tips(Roo.apply({
12038 btnEl.dom[this.tooltipType] = this.tooltip;
12041 if(this.arrowTooltip){
12042 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12051 this.el.addClass("x-btn-pressed");
12053 if(Roo.isIE && !Roo.isIE7){
12054 this.autoWidth.defer(1, this);
12059 this.menu.on("show", this.onMenuShow, this);
12060 this.menu.on("hide", this.onMenuHide, this);
12062 this.fireEvent('render', this);
12066 autoWidth : function(){
12068 var tbl = this.el.child("table:first");
12069 var tbl2 = this.el.child("table:last");
12070 this.el.setWidth("auto");
12071 tbl.setWidth("auto");
12072 if(Roo.isIE7 && Roo.isStrict){
12073 var ib = this.el.child('button:first');
12074 if(ib && ib.getWidth() > 20){
12076 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12081 this.el.beginMeasure();
12083 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12084 tbl.setWidth(this.minWidth-tbl2.getWidth());
12087 this.el.endMeasure();
12090 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12094 * Sets this button's click handler
12095 * @param {Function} handler The function to call when the button is clicked
12096 * @param {Object} scope (optional) Scope for the function passed above
12098 setHandler : function(handler, scope){
12099 this.handler = handler;
12100 this.scope = scope;
12104 * Sets this button's arrow click handler
12105 * @param {Function} handler The function to call when the arrow is clicked
12106 * @param {Object} scope (optional) Scope for the function passed above
12108 setArrowHandler : function(handler, scope){
12109 this.arrowHandler = handler;
12110 this.scope = scope;
12116 focus : function(){
12118 this.el.child("button:first").focus();
12123 onClick : function(e){
12124 e.preventDefault();
12125 if(!this.disabled){
12126 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12127 if(this.menu && !this.menu.isVisible()){
12128 this.menu.show(this.el, this.menuAlign);
12130 this.fireEvent("arrowclick", this, e);
12131 if(this.arrowHandler){
12132 this.arrowHandler.call(this.scope || this, this, e);
12135 this.fireEvent("click", this, e);
12137 this.handler.call(this.scope || this, this, e);
12143 onMouseDown : function(e){
12144 if(!this.disabled){
12145 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12149 onMouseUp : function(e){
12150 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12155 // backwards compat
12156 Roo.MenuButton = Roo.SplitButton;/*
12158 * Ext JS Library 1.1.1
12159 * Copyright(c) 2006-2007, Ext JS, LLC.
12161 * Originally Released Under LGPL - original licence link has changed is not relivant.
12164 * <script type="text/javascript">
12168 * @class Roo.Toolbar
12169 * Basic Toolbar class.
12171 * Creates a new Toolbar
12172 * @param {Object} config The config object
12174 Roo.Toolbar = function(container, buttons, config)
12176 /// old consturctor format still supported..
12177 if(container instanceof Array){ // omit the container for later rendering
12178 buttons = container;
12182 if (typeof(container) == 'object' && container.xtype) {
12183 config = container;
12184 container = config.container;
12185 buttons = config.buttons; // not really - use items!!
12188 if (config && config.items) {
12189 xitems = config.items;
12190 delete config.items;
12192 Roo.apply(this, config);
12193 this.buttons = buttons;
12196 this.render(container);
12198 Roo.each(xitems, function(b) {
12204 Roo.Toolbar.prototype = {
12206 * @cfg {Roo.data.Store} items
12207 * array of button configs or elements to add
12211 * @cfg {String/HTMLElement/Element} container
12212 * The id or element that will contain the toolbar
12215 render : function(ct){
12216 this.el = Roo.get(ct);
12218 this.el.addClass(this.cls);
12220 // using a table allows for vertical alignment
12221 // 100% width is needed by Safari...
12222 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12223 this.tr = this.el.child("tr", true);
12225 this.items = new Roo.util.MixedCollection(false, function(o){
12226 return o.id || ("item" + (++autoId));
12229 this.add.apply(this, this.buttons);
12230 delete this.buttons;
12235 * Adds element(s) to the toolbar -- this function takes a variable number of
12236 * arguments of mixed type and adds them to the toolbar.
12237 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12239 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12240 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12241 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12242 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12243 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12244 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12245 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12246 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12247 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12249 * @param {Mixed} arg2
12250 * @param {Mixed} etc.
12253 var a = arguments, l = a.length;
12254 for(var i = 0; i < l; i++){
12259 _add : function(el) {
12262 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12265 if (el.applyTo){ // some kind of form field
12266 return this.addField(el);
12268 if (el.render){ // some kind of Toolbar.Item
12269 return this.addItem(el);
12271 if (typeof el == "string"){ // string
12272 if(el == "separator" || el == "-"){
12273 return this.addSeparator();
12276 return this.addSpacer();
12279 return this.addFill();
12281 return this.addText(el);
12284 if(el.tagName){ // element
12285 return this.addElement(el);
12287 if(typeof el == "object"){ // must be button config?
12288 return this.addButton(el);
12290 // and now what?!?!
12296 * Add an Xtype element
12297 * @param {Object} xtype Xtype Object
12298 * @return {Object} created Object
12300 addxtype : function(e){
12301 return this.add(e);
12305 * Returns the Element for this toolbar.
12306 * @return {Roo.Element}
12308 getEl : function(){
12314 * @return {Roo.Toolbar.Item} The separator item
12316 addSeparator : function(){
12317 return this.addItem(new Roo.Toolbar.Separator());
12321 * Adds a spacer element
12322 * @return {Roo.Toolbar.Spacer} The spacer item
12324 addSpacer : function(){
12325 return this.addItem(new Roo.Toolbar.Spacer());
12329 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12330 * @return {Roo.Toolbar.Fill} The fill item
12332 addFill : function(){
12333 return this.addItem(new Roo.Toolbar.Fill());
12337 * Adds any standard HTML element to the toolbar
12338 * @param {String/HTMLElement/Element} el The element or id of the element to add
12339 * @return {Roo.Toolbar.Item} The element's item
12341 addElement : function(el){
12342 return this.addItem(new Roo.Toolbar.Item(el));
12345 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12346 * @type Roo.util.MixedCollection
12351 * Adds any Toolbar.Item or subclass
12352 * @param {Roo.Toolbar.Item} item
12353 * @return {Roo.Toolbar.Item} The item
12355 addItem : function(item){
12356 var td = this.nextBlock();
12358 this.items.add(item);
12363 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12364 * @param {Object/Array} config A button config or array of configs
12365 * @return {Roo.Toolbar.Button/Array}
12367 addButton : function(config){
12368 if(config instanceof Array){
12370 for(var i = 0, len = config.length; i < len; i++) {
12371 buttons.push(this.addButton(config[i]));
12376 if(!(config instanceof Roo.Toolbar.Button)){
12378 new Roo.Toolbar.SplitButton(config) :
12379 new Roo.Toolbar.Button(config);
12381 var td = this.nextBlock();
12388 * Adds text to the toolbar
12389 * @param {String} text The text to add
12390 * @return {Roo.Toolbar.Item} The element's item
12392 addText : function(text){
12393 return this.addItem(new Roo.Toolbar.TextItem(text));
12397 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12398 * @param {Number} index The index where the item is to be inserted
12399 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12400 * @return {Roo.Toolbar.Button/Item}
12402 insertButton : function(index, item){
12403 if(item instanceof Array){
12405 for(var i = 0, len = item.length; i < len; i++) {
12406 buttons.push(this.insertButton(index + i, item[i]));
12410 if (!(item instanceof Roo.Toolbar.Button)){
12411 item = new Roo.Toolbar.Button(item);
12413 var td = document.createElement("td");
12414 this.tr.insertBefore(td, this.tr.childNodes[index]);
12416 this.items.insert(index, item);
12421 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12422 * @param {Object} config
12423 * @return {Roo.Toolbar.Item} The element's item
12425 addDom : function(config, returnEl){
12426 var td = this.nextBlock();
12427 Roo.DomHelper.overwrite(td, config);
12428 var ti = new Roo.Toolbar.Item(td.firstChild);
12430 this.items.add(ti);
12435 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12436 * @type Roo.util.MixedCollection
12441 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12442 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12443 * @param {Roo.form.Field} field
12444 * @return {Roo.ToolbarItem}
12448 addField : function(field) {
12449 if (!this.fields) {
12451 this.fields = new Roo.util.MixedCollection(false, function(o){
12452 return o.id || ("item" + (++autoId));
12457 var td = this.nextBlock();
12459 var ti = new Roo.Toolbar.Item(td.firstChild);
12461 this.items.add(ti);
12462 this.fields.add(field);
12473 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12474 this.el.child('div').hide();
12482 this.el.child('div').show();
12486 nextBlock : function(){
12487 var td = document.createElement("td");
12488 this.tr.appendChild(td);
12493 destroy : function(){
12494 if(this.items){ // rendered?
12495 Roo.destroy.apply(Roo, this.items.items);
12497 if(this.fields){ // rendered?
12498 Roo.destroy.apply(Roo, this.fields.items);
12500 Roo.Element.uncache(this.el, this.tr);
12505 * @class Roo.Toolbar.Item
12506 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12508 * Creates a new Item
12509 * @param {HTMLElement} el
12511 Roo.Toolbar.Item = function(el){
12512 this.el = Roo.getDom(el);
12513 this.id = Roo.id(this.el);
12514 this.hidden = false;
12517 Roo.Toolbar.Item.prototype = {
12520 * Get this item's HTML Element
12521 * @return {HTMLElement}
12523 getEl : function(){
12528 render : function(td){
12530 td.appendChild(this.el);
12534 * Removes and destroys this item.
12536 destroy : function(){
12537 this.td.parentNode.removeChild(this.td);
12544 this.hidden = false;
12545 this.td.style.display = "";
12552 this.hidden = true;
12553 this.td.style.display = "none";
12557 * Convenience function for boolean show/hide.
12558 * @param {Boolean} visible true to show/false to hide
12560 setVisible: function(visible){
12569 * Try to focus this item.
12571 focus : function(){
12572 Roo.fly(this.el).focus();
12576 * Disables this item.
12578 disable : function(){
12579 Roo.fly(this.td).addClass("x-item-disabled");
12580 this.disabled = true;
12581 this.el.disabled = true;
12585 * Enables this item.
12587 enable : function(){
12588 Roo.fly(this.td).removeClass("x-item-disabled");
12589 this.disabled = false;
12590 this.el.disabled = false;
12596 * @class Roo.Toolbar.Separator
12597 * @extends Roo.Toolbar.Item
12598 * A simple toolbar separator class
12600 * Creates a new Separator
12602 Roo.Toolbar.Separator = function(){
12603 var s = document.createElement("span");
12604 s.className = "ytb-sep";
12605 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12607 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12608 enable:Roo.emptyFn,
12609 disable:Roo.emptyFn,
12614 * @class Roo.Toolbar.Spacer
12615 * @extends Roo.Toolbar.Item
12616 * A simple element that adds extra horizontal space to a toolbar.
12618 * Creates a new Spacer
12620 Roo.Toolbar.Spacer = function(){
12621 var s = document.createElement("div");
12622 s.className = "ytb-spacer";
12623 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12625 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12626 enable:Roo.emptyFn,
12627 disable:Roo.emptyFn,
12632 * @class Roo.Toolbar.Fill
12633 * @extends Roo.Toolbar.Spacer
12634 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12636 * Creates a new Spacer
12638 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12640 render : function(td){
12641 td.style.width = '100%';
12642 Roo.Toolbar.Fill.superclass.render.call(this, td);
12647 * @class Roo.Toolbar.TextItem
12648 * @extends Roo.Toolbar.Item
12649 * A simple class that renders text directly into a toolbar.
12651 * Creates a new TextItem
12652 * @param {String} text
12654 Roo.Toolbar.TextItem = function(text){
12655 if (typeof(text) == 'object') {
12658 var s = document.createElement("span");
12659 s.className = "ytb-text";
12660 s.innerHTML = text;
12661 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12663 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12664 enable:Roo.emptyFn,
12665 disable:Roo.emptyFn,
12670 * @class Roo.Toolbar.Button
12671 * @extends Roo.Button
12672 * A button that renders into a toolbar.
12674 * Creates a new Button
12675 * @param {Object} config A standard {@link Roo.Button} config object
12677 Roo.Toolbar.Button = function(config){
12678 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12680 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12681 render : function(td){
12683 Roo.Toolbar.Button.superclass.render.call(this, td);
12687 * Removes and destroys this button
12689 destroy : function(){
12690 Roo.Toolbar.Button.superclass.destroy.call(this);
12691 this.td.parentNode.removeChild(this.td);
12695 * Shows this button
12698 this.hidden = false;
12699 this.td.style.display = "";
12703 * Hides this button
12706 this.hidden = true;
12707 this.td.style.display = "none";
12711 * Disables this item
12713 disable : function(){
12714 Roo.fly(this.td).addClass("x-item-disabled");
12715 this.disabled = true;
12719 * Enables this item
12721 enable : function(){
12722 Roo.fly(this.td).removeClass("x-item-disabled");
12723 this.disabled = false;
12726 // backwards compat
12727 Roo.ToolbarButton = Roo.Toolbar.Button;
12730 * @class Roo.Toolbar.SplitButton
12731 * @extends Roo.SplitButton
12732 * A menu button that renders into a toolbar.
12734 * Creates a new SplitButton
12735 * @param {Object} config A standard {@link Roo.SplitButton} config object
12737 Roo.Toolbar.SplitButton = function(config){
12738 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12740 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12741 render : function(td){
12743 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12747 * Removes and destroys this button
12749 destroy : function(){
12750 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12751 this.td.parentNode.removeChild(this.td);
12755 * Shows this button
12758 this.hidden = false;
12759 this.td.style.display = "";
12763 * Hides this button
12766 this.hidden = true;
12767 this.td.style.display = "none";
12771 // backwards compat
12772 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12774 * Ext JS Library 1.1.1
12775 * Copyright(c) 2006-2007, Ext JS, LLC.
12777 * Originally Released Under LGPL - original licence link has changed is not relivant.
12780 * <script type="text/javascript">
12784 * @class Roo.PagingToolbar
12785 * @extends Roo.Toolbar
12786 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12788 * Create a new PagingToolbar
12789 * @param {Object} config The config object
12791 Roo.PagingToolbar = function(el, ds, config)
12793 // old args format still supported... - xtype is prefered..
12794 if (typeof(el) == 'object' && el.xtype) {
12795 // created from xtype...
12797 ds = el.dataSource;
12798 el = config.container;
12801 if (config.items) {
12802 items = config.items;
12806 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12809 this.renderButtons(this.el);
12812 // supprot items array.
12814 Roo.each(items, function(e) {
12815 this.add(Roo.factory(e));
12820 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12822 * @cfg {Roo.data.Store} dataSource
12823 * The underlying data store providing the paged data
12826 * @cfg {String/HTMLElement/Element} container
12827 * container The id or element that will contain the toolbar
12830 * @cfg {Boolean} displayInfo
12831 * True to display the displayMsg (defaults to false)
12834 * @cfg {Number} pageSize
12835 * The number of records to display per page (defaults to 20)
12839 * @cfg {String} displayMsg
12840 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12842 displayMsg : 'Displaying {0} - {1} of {2}',
12844 * @cfg {String} emptyMsg
12845 * The message to display when no records are found (defaults to "No data to display")
12847 emptyMsg : 'No data to display',
12849 * Customizable piece of the default paging text (defaults to "Page")
12852 beforePageText : "Page",
12854 * Customizable piece of the default paging text (defaults to "of %0")
12857 afterPageText : "of {0}",
12859 * Customizable piece of the default paging text (defaults to "First Page")
12862 firstText : "First Page",
12864 * Customizable piece of the default paging text (defaults to "Previous Page")
12867 prevText : "Previous Page",
12869 * Customizable piece of the default paging text (defaults to "Next Page")
12872 nextText : "Next Page",
12874 * Customizable piece of the default paging text (defaults to "Last Page")
12877 lastText : "Last Page",
12879 * Customizable piece of the default paging text (defaults to "Refresh")
12882 refreshText : "Refresh",
12885 renderButtons : function(el){
12886 Roo.PagingToolbar.superclass.render.call(this, el);
12887 this.first = this.addButton({
12888 tooltip: this.firstText,
12889 cls: "x-btn-icon x-grid-page-first",
12891 handler: this.onClick.createDelegate(this, ["first"])
12893 this.prev = this.addButton({
12894 tooltip: this.prevText,
12895 cls: "x-btn-icon x-grid-page-prev",
12897 handler: this.onClick.createDelegate(this, ["prev"])
12899 //this.addSeparator();
12900 this.add(this.beforePageText);
12901 this.field = Roo.get(this.addDom({
12906 cls: "x-grid-page-number"
12908 this.field.on("keydown", this.onPagingKeydown, this);
12909 this.field.on("focus", function(){this.dom.select();});
12910 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12911 this.field.setHeight(18);
12912 //this.addSeparator();
12913 this.next = this.addButton({
12914 tooltip: this.nextText,
12915 cls: "x-btn-icon x-grid-page-next",
12917 handler: this.onClick.createDelegate(this, ["next"])
12919 this.last = this.addButton({
12920 tooltip: this.lastText,
12921 cls: "x-btn-icon x-grid-page-last",
12923 handler: this.onClick.createDelegate(this, ["last"])
12925 //this.addSeparator();
12926 this.loading = this.addButton({
12927 tooltip: this.refreshText,
12928 cls: "x-btn-icon x-grid-loading",
12929 handler: this.onClick.createDelegate(this, ["refresh"])
12932 if(this.displayInfo){
12933 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12938 updateInfo : function(){
12939 if(this.displayEl){
12940 var count = this.ds.getCount();
12941 var msg = count == 0 ?
12945 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12947 this.displayEl.update(msg);
12952 onLoad : function(ds, r, o){
12953 this.cursor = o.params ? o.params.start : 0;
12954 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12956 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12957 this.field.dom.value = ap;
12958 this.first.setDisabled(ap == 1);
12959 this.prev.setDisabled(ap == 1);
12960 this.next.setDisabled(ap == ps);
12961 this.last.setDisabled(ap == ps);
12962 this.loading.enable();
12967 getPageData : function(){
12968 var total = this.ds.getTotalCount();
12971 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12972 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
12977 onLoadError : function(){
12978 this.loading.enable();
12982 onPagingKeydown : function(e){
12983 var k = e.getKey();
12984 var d = this.getPageData();
12986 var v = this.field.dom.value, pageNum;
12987 if(!v || isNaN(pageNum = parseInt(v, 10))){
12988 this.field.dom.value = d.activePage;
12991 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
12992 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
12995 else if(k == e.HOME || (k == e.UP && e.ctrlKey) || (k == e.PAGEUP && e.ctrlKey) || (k == e.RIGHT && e.ctrlKey) || k == e.END || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey))
12997 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
12998 this.field.dom.value = pageNum;
12999 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13002 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13004 var v = this.field.dom.value, pageNum;
13005 var increment = (e.shiftKey) ? 10 : 1;
13006 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13008 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13009 this.field.dom.value = d.activePage;
13012 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13014 this.field.dom.value = parseInt(v, 10) + increment;
13015 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13016 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13023 beforeLoad : function(){
13025 this.loading.disable();
13030 onClick : function(which){
13034 ds.load({params:{start: 0, limit: this.pageSize}});
13037 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13040 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13043 var total = ds.getTotalCount();
13044 var extra = total % this.pageSize;
13045 var lastStart = extra ? (total - extra) : total-this.pageSize;
13046 ds.load({params:{start: lastStart, limit: this.pageSize}});
13049 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13055 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13056 * @param {Roo.data.Store} store The data store to unbind
13058 unbind : function(ds){
13059 ds.un("beforeload", this.beforeLoad, this);
13060 ds.un("load", this.onLoad, this);
13061 ds.un("loadexception", this.onLoadError, this);
13062 ds.un("remove", this.updateInfo, this);
13063 ds.un("add", this.updateInfo, this);
13064 this.ds = undefined;
13068 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13069 * @param {Roo.data.Store} store The data store to bind
13071 bind : function(ds){
13072 ds.on("beforeload", this.beforeLoad, this);
13073 ds.on("load", this.onLoad, this);
13074 ds.on("loadexception", this.onLoadError, this);
13075 ds.on("remove", this.updateInfo, this);
13076 ds.on("add", this.updateInfo, this);
13081 * Ext JS Library 1.1.1
13082 * Copyright(c) 2006-2007, Ext JS, LLC.
13084 * Originally Released Under LGPL - original licence link has changed is not relivant.
13087 * <script type="text/javascript">
13091 * @class Roo.Resizable
13092 * @extends Roo.util.Observable
13093 * <p>Applies drag handles to an element to make it resizable. The drag handles are inserted into the element
13094 * and positioned absolute. Some elements, such as a textarea or image, don't support this. To overcome that, you can wrap
13095 * the textarea in a div and set "resizeChild" to true (or to the id of the element), <b>or</b> set wrap:true in your config and
13096 * the element will be wrapped for you automatically.</p>
13097 * <p>Here is the list of valid resize handles:</p>
13100 ------ -------------------
13109 'hd' horizontal drag
13112 * <p>Here's an example showing the creation of a typical Resizable:</p>
13114 var resizer = new Roo.Resizable("element-id", {
13122 resizer.on("resize", myHandler);
13124 * <p>To hide a particular handle, set its display to none in CSS, or through script:<br>
13125 * resizer.east.setDisplayed(false);</p>
13126 * @cfg {Boolean/String/Element} resizeChild True to resize the first child, or id/element to resize (defaults to false)
13127 * @cfg {Array/String} adjustments String "auto" or an array [width, height] with values to be <b>added</b> to the
13128 * resize operation's new size (defaults to [0, 0])
13129 * @cfg {Number} minWidth The minimum width for the element (defaults to 5)
13130 * @cfg {Number} minHeight The minimum height for the element (defaults to 5)
13131 * @cfg {Number} maxWidth The maximum width for the element (defaults to 10000)
13132 * @cfg {Number} maxHeight The maximum height for the element (defaults to 10000)
13133 * @cfg {Boolean} enabled False to disable resizing (defaults to true)
13134 * @cfg {Boolean} wrap True to wrap an element with a div if needed (required for textareas and images, defaults to false)
13135 * @cfg {Number} width The width of the element in pixels (defaults to null)
13136 * @cfg {Number} height The height of the element in pixels (defaults to null)
13137 * @cfg {Boolean} animate True to animate the resize (not compatible with dynamic sizing, defaults to false)
13138 * @cfg {Number} duration Animation duration if animate = true (defaults to .35)
13139 * @cfg {Boolean} dynamic True to resize the element while dragging instead of using a proxy (defaults to false)
13140 * @cfg {String} handles String consisting of the resize handles to display (defaults to undefined)
13141 * @cfg {Boolean} multiDirectional <b>Deprecated</b>. The old style of adding multi-direction resize handles, deprecated
13142 * in favor of the handles config option (defaults to false)
13143 * @cfg {Boolean} disableTrackOver True to disable mouse tracking. This is only applied at config time. (defaults to false)
13144 * @cfg {String} easing Animation easing if animate = true (defaults to 'easingOutStrong')
13145 * @cfg {Number} widthIncrement The increment to snap the width resize in pixels (dynamic must be true, defaults to 0)
13146 * @cfg {Number} heightIncrement The increment to snap the height resize in pixels (dynamic must be true, defaults to 0)
13147 * @cfg {Boolean} pinned True to ensure that the resize handles are always visible, false to display them only when the
13148 * user mouses over the resizable borders. This is only applied at config time. (defaults to false)
13149 * @cfg {Boolean} preserveRatio True to preserve the original ratio between height and width during resize (defaults to false)
13150 * @cfg {Boolean} transparent True for transparent handles. This is only applied at config time. (defaults to false)
13151 * @cfg {Number} minX The minimum allowed page X for the element (only used for west resizing, defaults to 0)
13152 * @cfg {Number} minY The minimum allowed page Y for the element (only used for north resizing, defaults to 0)
13153 * @cfg {Boolean} draggable Convenience to initialize drag drop (defaults to false)
13155 * Create a new resizable component
13156 * @param {String/HTMLElement/Roo.Element} el The id or element to resize
13157 * @param {Object} config configuration options
13159 Roo.Resizable = function(el, config)
13161 this.el = Roo.get(el);
13163 if(config && config.wrap){
13164 config.resizeChild = this.el;
13165 this.el = this.el.wrap(typeof config.wrap == "object" ? config.wrap : {cls:"xresizable-wrap"});
13166 this.el.id = this.el.dom.id = config.resizeChild.id + "-rzwrap";
13167 this.el.setStyle("overflow", "hidden");
13168 this.el.setPositioning(config.resizeChild.getPositioning());
13169 config.resizeChild.clearPositioning();
13170 if(!config.width || !config.height){
13171 var csize = config.resizeChild.getSize();
13172 this.el.setSize(csize.width, csize.height);
13174 if(config.pinned && !config.adjustments){
13175 config.adjustments = "auto";
13179 this.proxy = this.el.createProxy({tag: "div", cls: "x-resizable-proxy", id: this.el.id + "-rzproxy"});
13180 this.proxy.unselectable();
13181 this.proxy.enableDisplayMode('block');
13183 Roo.apply(this, config);
13186 this.disableTrackOver = true;
13187 this.el.addClass("x-resizable-pinned");
13189 // if the element isn't positioned, make it relative
13190 var position = this.el.getStyle("position");
13191 if(position != "absolute" && position != "fixed"){
13192 this.el.setStyle("position", "relative");
13194 if(!this.handles){ // no handles passed, must be legacy style
13195 this.handles = 's,e,se';
13196 if(this.multiDirectional){
13197 this.handles += ',n,w';
13200 if(this.handles == "all"){
13201 this.handles = "n s e w ne nw se sw";
13203 var hs = this.handles.split(/\s*?[,;]\s*?| /);
13204 var ps = Roo.Resizable.positions;
13205 for(var i = 0, len = hs.length; i < len; i++){
13206 if(hs[i] && ps[hs[i]]){
13207 var pos = ps[hs[i]];
13208 this[pos] = new Roo.Resizable.Handle(this, pos, this.disableTrackOver, this.transparent);
13212 this.corner = this.southeast;
13214 // updateBox = the box can move..
13215 if(this.handles.indexOf("n") != -1 || this.handles.indexOf("w") != -1 || this.handles.indexOf("hd") != -1) {
13216 this.updateBox = true;
13219 this.activeHandle = null;
13221 if(this.resizeChild){
13222 if(typeof this.resizeChild == "boolean"){
13223 this.resizeChild = Roo.get(this.el.dom.firstChild, true);
13225 this.resizeChild = Roo.get(this.resizeChild, true);
13229 if(this.adjustments == "auto"){
13230 var rc = this.resizeChild;
13231 var hw = this.west, he = this.east, hn = this.north, hs = this.south;
13232 if(rc && (hw || hn)){
13233 rc.position("relative");
13234 rc.setLeft(hw ? hw.el.getWidth() : 0);
13235 rc.setTop(hn ? hn.el.getHeight() : 0);
13237 this.adjustments = [
13238 (he ? -he.el.getWidth() : 0) + (hw ? -hw.el.getWidth() : 0),
13239 (hn ? -hn.el.getHeight() : 0) + (hs ? -hs.el.getHeight() : 0) -1
13243 if(this.draggable){
13244 this.dd = this.dynamic ?
13245 this.el.initDD(null) : this.el.initDDProxy(null, {dragElId: this.proxy.id});
13246 this.dd.setHandleElId(this.resizeChild ? this.resizeChild.id : this.el.id);
13252 * @event beforeresize
13253 * Fired before resize is allowed. Set enabled to false to cancel resize.
13254 * @param {Roo.Resizable} this
13255 * @param {Roo.EventObject} e The mousedown event
13257 "beforeresize" : true,
13260 * Fired after a resize.
13261 * @param {Roo.Resizable} this
13262 * @param {Number} width The new width
13263 * @param {Number} height The new height
13264 * @param {Roo.EventObject} e The mouseup event
13269 if(this.width !== null && this.height !== null){
13270 this.resizeTo(this.width, this.height);
13272 this.updateChildSize();
13275 this.el.dom.style.zoom = 1;
13277 Roo.Resizable.superclass.constructor.call(this);
13280 Roo.extend(Roo.Resizable, Roo.util.Observable, {
13281 resizeChild : false,
13282 adjustments : [0, 0],
13292 multiDirectional : false,
13293 disableTrackOver : false,
13294 easing : 'easeOutStrong',
13295 widthIncrement : 0,
13296 heightIncrement : 0,
13300 preserveRatio : false,
13301 transparent: false,
13307 * @cfg {String/HTMLElement/Element} constrainTo Constrain the resize to a particular element
13309 constrainTo: undefined,
13311 * @cfg {Roo.lib.Region} resizeRegion Constrain the resize to a particular region
13313 resizeRegion: undefined,
13317 * Perform a manual resize
13318 * @param {Number} width
13319 * @param {Number} height
13321 resizeTo : function(width, height){
13322 this.el.setSize(width, height);
13323 this.updateChildSize();
13324 this.fireEvent("resize", this, width, height, null);
13328 startSizing : function(e, handle){
13329 this.fireEvent("beforeresize", this, e);
13330 if(this.enabled){ // 2nd enabled check in case disabled before beforeresize handler
13333 this.overlay = this.el.createProxy({tag: "div", cls: "x-resizable-overlay", html: " "});
13334 this.overlay.unselectable();
13335 this.overlay.enableDisplayMode("block");
13336 this.overlay.on("mousemove", this.onMouseMove, this);
13337 this.overlay.on("mouseup", this.onMouseUp, this);
13339 this.overlay.setStyle("cursor", handle.el.getStyle("cursor"));
13341 this.resizing = true;
13342 this.startBox = this.el.getBox();
13343 this.startPoint = e.getXY();
13344 this.offsets = [(this.startBox.x + this.startBox.width) - this.startPoint[0],
13345 (this.startBox.y + this.startBox.height) - this.startPoint[1]];
13347 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
13348 this.overlay.show();
13350 if(this.constrainTo) {
13351 var ct = Roo.get(this.constrainTo);
13352 this.resizeRegion = ct.getRegion().adjust(
13353 ct.getFrameWidth('t'),
13354 ct.getFrameWidth('l'),
13355 -ct.getFrameWidth('b'),
13356 -ct.getFrameWidth('r')
13360 this.proxy.setStyle('visibility', 'hidden'); // workaround display none
13362 this.proxy.setBox(this.startBox);
13364 this.proxy.setStyle('visibility', 'visible');
13370 onMouseDown : function(handle, e){
13373 this.activeHandle = handle;
13374 this.startSizing(e, handle);
13379 onMouseUp : function(e){
13380 var size = this.resizeElement();
13381 this.resizing = false;
13383 this.overlay.hide();
13385 this.fireEvent("resize", this, size.width, size.height, e);
13389 updateChildSize : function(){
13390 if(this.resizeChild){
13392 var child = this.resizeChild;
13393 var adj = this.adjustments;
13394 if(el.dom.offsetWidth){
13395 var b = el.getSize(true);
13396 child.setSize(b.width+adj[0], b.height+adj[1]);
13398 // Second call here for IE
13399 // The first call enables instant resizing and
13400 // the second call corrects scroll bars if they
13403 setTimeout(function(){
13404 if(el.dom.offsetWidth){
13405 var b = el.getSize(true);
13406 child.setSize(b.width+adj[0], b.height+adj[1]);
13414 snap : function(value, inc, min){
13415 if(!inc || !value) return value;
13416 var newValue = value;
13417 var m = value % inc;
13420 newValue = value + (inc-m);
13422 newValue = value - m;
13425 return Math.max(min, newValue);
13429 resizeElement : function(){
13430 var box = this.proxy.getBox();
13431 if(this.updateBox){
13432 this.el.setBox(box, false, this.animate, this.duration, null, this.easing);
13434 this.el.setSize(box.width, box.height, this.animate, this.duration, null, this.easing);
13436 this.updateChildSize();
13444 constrain : function(v, diff, m, mx){
13447 }else if(v - diff > mx){
13454 onMouseMove : function(e){
13456 try{// try catch so if something goes wrong the user doesn't get hung
13458 if(this.resizeRegion && !this.resizeRegion.contains(e.getPoint())) {
13462 //var curXY = this.startPoint;
13463 var curSize = this.curSize || this.startBox;
13464 var x = this.startBox.x, y = this.startBox.y;
13465 var ox = x, oy = y;
13466 var w = curSize.width, h = curSize.height;
13467 var ow = w, oh = h;
13468 var mw = this.minWidth, mh = this.minHeight;
13469 var mxw = this.maxWidth, mxh = this.maxHeight;
13470 var wi = this.widthIncrement;
13471 var hi = this.heightIncrement;
13473 var eventXY = e.getXY();
13474 var diffX = -(this.startPoint[0] - Math.max(this.minX, eventXY[0]));
13475 var diffY = -(this.startPoint[1] - Math.max(this.minY, eventXY[1]));
13477 var pos = this.activeHandle.position;
13482 w = Math.min(Math.max(mw, w), mxw);
13487 h = Math.min(Math.max(mh, h), mxh);
13492 w = Math.min(Math.max(mw, w), mxw);
13493 h = Math.min(Math.max(mh, h), mxh);
13496 diffY = this.constrain(h, diffY, mh, mxh);
13503 var adiffX = Math.abs(diffX);
13504 var sub = (adiffX % wi); // how much
13505 if (sub > (wi/2)) { // far enough to snap
13506 diffX = (diffX > 0) ? diffX-sub + wi : diffX+sub - wi;
13508 // remove difference..
13509 diffX = (diffX > 0) ? diffX-sub : diffX+sub;
13513 x = Math.max(this.minX, x);
13516 diffX = this.constrain(w, diffX, mw, mxw);
13522 w = Math.min(Math.max(mw, w), mxw);
13523 diffY = this.constrain(h, diffY, mh, mxh);
13528 diffX = this.constrain(w, diffX, mw, mxw);
13529 diffY = this.constrain(h, diffY, mh, mxh);
13536 diffX = this.constrain(w, diffX, mw, mxw);
13538 h = Math.min(Math.max(mh, h), mxh);
13544 var sw = this.snap(w, wi, mw);
13545 var sh = this.snap(h, hi, mh);
13546 if(sw != w || sh != h){
13569 if(this.preserveRatio){
13574 h = Math.min(Math.max(mh, h), mxh);
13579 w = Math.min(Math.max(mw, w), mxw);
13584 w = Math.min(Math.max(mw, w), mxw);
13590 w = Math.min(Math.max(mw, w), mxw);
13596 h = Math.min(Math.max(mh, h), mxh);
13604 h = Math.min(Math.max(mh, h), mxh);
13614 h = Math.min(Math.max(mh, h), mxh);
13622 if (pos == 'hdrag') {
13625 this.proxy.setBounds(x, y, w, h);
13627 this.resizeElement();
13634 handleOver : function(){
13636 this.el.addClass("x-resizable-over");
13641 handleOut : function(){
13642 if(!this.resizing){
13643 this.el.removeClass("x-resizable-over");
13648 * Returns the element this component is bound to.
13649 * @return {Roo.Element}
13651 getEl : function(){
13656 * Returns the resizeChild element (or null).
13657 * @return {Roo.Element}
13659 getResizeChild : function(){
13660 return this.resizeChild;
13664 * Destroys this resizable. If the element was wrapped and
13665 * removeEl is not true then the element remains.
13666 * @param {Boolean} removeEl (optional) true to remove the element from the DOM
13668 destroy : function(removeEl){
13669 this.proxy.remove();
13671 this.overlay.removeAllListeners();
13672 this.overlay.remove();
13674 var ps = Roo.Resizable.positions;
13676 if(typeof ps[k] != "function" && this[ps[k]]){
13677 var h = this[ps[k]];
13678 h.el.removeAllListeners();
13683 this.el.update("");
13690 // hash to map config positions to true positions
13691 Roo.Resizable.positions = {
13692 n: "north", s: "south", e: "east", w: "west", se: "southeast", sw: "southwest", nw: "northwest", ne: "northeast",
13697 Roo.Resizable.Handle = function(rz, pos, disableTrackOver, transparent){
13699 // only initialize the template if resizable is used
13700 var tpl = Roo.DomHelper.createTemplate(
13701 {tag: "div", cls: "x-resizable-handle x-resizable-handle-{0}"}
13704 Roo.Resizable.Handle.prototype.tpl = tpl;
13706 this.position = pos;
13708 // show north drag fro topdra
13709 var handlepos = pos == 'hdrag' ? 'north' : pos;
13711 this.el = this.tpl.append(rz.el.dom, [handlepos], true);
13712 if (pos == 'hdrag') {
13713 this.el.setStyle('cursor', 'pointer');
13715 this.el.unselectable();
13717 this.el.setOpacity(0);
13719 this.el.on("mousedown", this.onMouseDown, this);
13720 if(!disableTrackOver){
13721 this.el.on("mouseover", this.onMouseOver, this);
13722 this.el.on("mouseout", this.onMouseOut, this);
13727 Roo.Resizable.Handle.prototype = {
13728 afterResize : function(rz){
13732 onMouseDown : function(e){
13733 this.rz.onMouseDown(this, e);
13736 onMouseOver : function(e){
13737 this.rz.handleOver(this, e);
13740 onMouseOut : function(e){
13741 this.rz.handleOut(this, e);