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 * @extends Roo.util.Observable
30 * Defines the interface and base operation of items that that can be
31 * dragged or can be drop targets. It was designed to be extended, overriding
32 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
33 * Up to three html elements can be associated with a DragDrop instance:
35 * <li>linked element: the element that is passed into the constructor.
36 * This is the element which defines the boundaries for interaction with
37 * other DragDrop objects.</li>
38 * <li>handle element(s): The drag operation only occurs if the element that
39 * was clicked matches a handle element. By default this is the linked
40 * element, but there are times that you will want only a portion of the
41 * linked element to initiate the drag operation, and the setHandleElId()
42 * method provides a way to define this.</li>
43 * <li>drag element: this represents the element that would be moved along
44 * with the cursor during a drag operation. By default, this is the linked
45 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
46 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
49 * This class should not be instantiated until the onload event to ensure that
50 * the associated elements are available.
51 * The following would define a DragDrop obj that would interact with any
52 * other DragDrop obj in the "group1" group:
54 * dd = new Roo.dd.DragDrop("div1", "group1");
56 * Since none of the event handlers have been implemented, nothing would
57 * actually happen if you were to run the code above. Normally you would
58 * override this class or one of the default implementations, but you can
59 * also override the methods you want on an instance of the class...
61 * dd.onDragDrop = function(e, id) {
62 * alert("dd was dropped on " + id);
66 * @param {String} id of the element that is linked to this instance
67 * @param {String} sGroup the group of related DragDrop objects
68 * @param {object} config an object containing configurable attributes
69 * Valid properties for DragDrop:
70 * padding, isTarget, maintainOffset, primaryButtonOnly
72 Roo.dd.DragDrop = function(id, sGroup, config) {
74 this.init(id, sGroup, config);
79 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
82 * The id of the element associated with this object. This is what we
83 * refer to as the "linked element" because the size and position of
84 * this element is used to determine when the drag and drop objects have
92 * Configuration attributes passed into the constructor
99 * The id of the element that will be dragged. By default this is same
100 * as the linked element , but could be changed to another element. Ex:
109 * the id of the element that initiates the drag operation. By default
110 * this is the linked element, but could be changed to be a child of this
111 * element. This lets us do things like only starting the drag when the
112 * header element within the linked html element is clicked.
113 * @property handleElId
120 * An associative array of HTML tags that will be ignored if clicked.
121 * @property invalidHandleTypes
122 * @type {string: string}
124 invalidHandleTypes: null,
127 * An associative array of ids for elements that will be ignored if clicked
128 * @property invalidHandleIds
129 * @type {string: string}
131 invalidHandleIds: null,
134 * An indexted array of css class names for elements that will be ignored
136 * @property invalidHandleClasses
139 invalidHandleClasses: null,
142 * The linked element's absolute X position at the time the drag was
144 * @property startPageX
151 * The linked element's absolute X position at the time the drag was
153 * @property startPageY
160 * The group defines a logical collection of DragDrop objects that are
161 * related. Instances only get events when interacting with other
162 * DragDrop object in the same group. This lets us define multiple
163 * groups using a single DragDrop subclass if we want.
165 * @type {string: string}
170 * Individual drag/drop instances can be locked. This will prevent
171 * onmousedown start drag.
182 lock: function() { this.locked = true; },
185 * Unlock this instace
188 unlock: function() { this.locked = false; },
191 * By default, all insances can be a drop target. This can be disabled by
192 * setting isTarget to false.
199 * The padding configured for this drag and drop object for calculating
200 * the drop zone intersection with this object.
207 * Cached reference to the linked element
214 * Internal typeof flag
215 * @property __ygDragDrop
221 * Set to true when horizontal contraints are applied
222 * @property constrainX
229 * Set to true when vertical contraints are applied
230 * @property constrainY
237 * The left constraint
245 * The right constraint
262 * The down constraint
270 * Maintain offsets when we resetconstraints. Set to true when you want
271 * the position of the element relative to its parent to stay the same
272 * when the page changes
274 * @property maintainOffset
277 maintainOffset: false,
280 * Array of pixel locations the element will snap to if we specified a
281 * horizontal graduation/interval. This array is generated automatically
282 * when you define a tick interval.
289 * Array of pixel locations the element will snap to if we specified a
290 * vertical graduation/interval. This array is generated automatically
291 * when you define a tick interval.
298 * By default the drag and drop instance will only respond to the primary
299 * button click (left button for a right-handed mouse). Set to true to
300 * allow drag and drop to start with any mouse click that is propogated
302 * @property primaryButtonOnly
305 primaryButtonOnly: true,
308 * The availabe property is false until the linked dom element is accessible.
309 * @property available
315 * By default, drags can only be initiated if the mousedown occurs in the
316 * region the linked element is. This is done in part to work around a
317 * bug in some browsers that mis-report the mousedown if the previous
318 * mouseup happened outside of the window. This property is set to true
319 * if outer handles are defined.
321 * @property hasOuterHandles
325 hasOuterHandles: false,
328 * Code that executes immediately before the startDrag event
329 * @method b4StartDrag
332 b4StartDrag: function(x, y) { },
335 * Abstract method called after a drag/drop object is clicked
336 * and the drag or mousedown time thresholds have beeen met.
338 * @param {int} X click location
339 * @param {int} Y click location
341 startDrag: function(x, y) { /* override this */ },
344 * Code that executes immediately before the onDrag event
348 b4Drag: function(e) { },
351 * Abstract method called during the onMouseMove event while dragging an
354 * @param {Event} e the mousemove event
356 onDrag: function(e) { /* override this */ },
359 * Abstract method called when this element fist begins hovering over
360 * another DragDrop obj
361 * @method onDragEnter
362 * @param {Event} e the mousemove event
363 * @param {String|DragDrop[]} id In POINT mode, the element
364 * id this is hovering over. In INTERSECT mode, an array of one or more
365 * dragdrop items being hovered over.
367 onDragEnter: function(e, id) { /* override this */ },
370 * Code that executes immediately before the onDragOver event
374 b4DragOver: function(e) { },
377 * Abstract method called when this element is hovering over another
380 * @param {Event} e the mousemove event
381 * @param {String|DragDrop[]} id In POINT mode, the element
382 * id this is hovering over. In INTERSECT mode, an array of dd items
383 * being hovered over.
385 onDragOver: function(e, id) { /* override this */ },
388 * Code that executes immediately before the onDragOut event
392 b4DragOut: function(e) { },
395 * Abstract method called when we are no longer hovering over an element
397 * @param {Event} e the mousemove event
398 * @param {String|DragDrop[]} id In POINT mode, the element
399 * id this was hovering over. In INTERSECT mode, an array of dd items
400 * that the mouse is no longer over.
402 onDragOut: function(e, id) { /* override this */ },
405 * Code that executes immediately before the onDragDrop event
409 b4DragDrop: function(e) { },
412 * Abstract method called when this item is dropped on another DragDrop
415 * @param {Event} e the mouseup event
416 * @param {String|DragDrop[]} id In POINT mode, the element
417 * id this was dropped on. In INTERSECT mode, an array of dd items this
420 onDragDrop: function(e, id) { /* override this */ },
423 * Abstract method called when this item is dropped on an area with no
425 * @method onInvalidDrop
426 * @param {Event} e the mouseup event
428 onInvalidDrop: function(e) { /* override this */ },
431 * Code that executes immediately before the endDrag event
435 b4EndDrag: function(e) { },
438 * Fired when we are done dragging the object
440 * @param {Event} e the mouseup event
442 endDrag: function(e) { /* override this */ },
445 * Code executed immediately before the onMouseDown event
446 * @method b4MouseDown
447 * @param {Event} e the mousedown event
450 b4MouseDown: function(e) { },
453 * Event handler that fires when a drag/drop obj gets a mousedown
454 * @method onMouseDown
455 * @param {Event} e the mousedown event
457 onMouseDown: function(e) { /* override this */ },
460 * Event handler that fires when a drag/drop obj gets a mouseup
462 * @param {Event} e the mouseup event
464 onMouseUp: function(e) { /* override this */ },
467 * Override the onAvailable method to do what is needed after the initial
468 * position was determined.
469 * @method onAvailable
471 onAvailable: function () {
475 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
478 defaultPadding : {left:0, right:0, top:0, bottom:0},
481 * Initializes the drag drop object's constraints to restrict movement to a certain element.
485 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
486 { dragElId: "existingProxyDiv" });
487 dd.startDrag = function(){
488 this.constrainTo("parent-id");
491 * Or you can initalize it using the {@link Roo.Element} object:
493 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
494 startDrag : function(){
495 this.constrainTo("parent-id");
499 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
500 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
501 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
502 * an object containing the sides to pad. For example: {right:10, bottom:10}
503 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
505 constrainTo : function(constrainTo, pad, inContent){
506 if(typeof pad == "number"){
507 pad = {left: pad, right:pad, top:pad, bottom:pad};
509 pad = pad || this.defaultPadding;
510 var b = Roo.get(this.getEl()).getBox();
511 var ce = Roo.get(constrainTo);
512 var s = ce.getScroll();
514 if(cd == document.body){
515 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
518 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
522 var topSpace = b.y - c.y;
523 var leftSpace = b.x - c.x;
525 this.resetConstraints();
526 this.setXConstraint(leftSpace - (pad.left||0), // left
527 c.width - leftSpace - b.width - (pad.right||0) //right
529 this.setYConstraint(topSpace - (pad.top||0), //top
530 c.height - topSpace - b.height - (pad.bottom||0) //bottom
535 * Returns a reference to the linked element
537 * @return {HTMLElement} the html element
541 this._domRef = Roo.getDom(this.id);
548 * Returns a reference to the actual element to drag. By default this is
549 * the same as the html element, but it can be assigned to another
550 * element. An example of this can be found in Roo.dd.DDProxy
552 * @return {HTMLElement} the html element
554 getDragEl: function() {
555 return Roo.getDom(this.dragElId);
559 * Sets up the DragDrop object. Must be called in the constructor of any
560 * Roo.dd.DragDrop subclass
562 * @param id the id of the linked element
563 * @param {String} sGroup the group of related items
564 * @param {object} config configuration attributes
566 init: function(id, sGroup, config) {
567 this.initTarget(id, sGroup, config);
568 Event.on(this.id, "mousedown", this.handleMouseDown, this);
569 // Event.on(this.id, "selectstart", Event.preventDefault);
573 * Initializes Targeting functionality only... the object does not
574 * get a mousedown handler.
576 * @param id the id of the linked element
577 * @param {String} sGroup the group of related items
578 * @param {object} config configuration attributes
580 initTarget: function(id, sGroup, config) {
582 // configuration attributes
583 this.config = config || {};
585 // create a local reference to the drag and drop manager
586 this.DDM = Roo.dd.DDM;
587 // initialize the groups array
590 // assume that we have an element reference instead of an id if the
591 // parameter is not a string
592 if (typeof id !== "string") {
599 // add to an interaction group
600 this.addToGroup((sGroup) ? sGroup : "default");
602 // We don't want to register this as the handle with the manager
603 // so we just set the id rather than calling the setter.
604 this.handleElId = id;
606 // the linked element is the element that gets dragged by default
607 this.setDragElId(id);
609 // by default, clicked anchors will not start drag operations.
610 this.invalidHandleTypes = { A: "A" };
611 this.invalidHandleIds = {};
612 this.invalidHandleClasses = [];
616 this.handleOnAvailable();
620 * Applies the configuration parameters that were passed into the constructor.
621 * This is supposed to happen at each level through the inheritance chain. So
622 * a DDProxy implentation will execute apply config on DDProxy, DD, and
623 * DragDrop in order to get all of the parameters that are available in
625 * @method applyConfig
627 applyConfig: function() {
629 // configurable properties:
630 // padding, isTarget, maintainOffset, primaryButtonOnly
631 this.padding = this.config.padding || [0, 0, 0, 0];
632 this.isTarget = (this.config.isTarget !== false);
633 this.maintainOffset = (this.config.maintainOffset);
634 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
639 * Executed when the linked element is available
640 * @method handleOnAvailable
643 handleOnAvailable: function() {
644 this.available = true;
645 this.resetConstraints();
650 * Configures the padding for the target zone in px. Effectively expands
651 * (or reduces) the virtual object size for targeting calculations.
652 * Supports css-style shorthand; if only one parameter is passed, all sides
653 * will have that padding, and if only two are passed, the top and bottom
654 * will have the first param, the left and right the second.
656 * @param {int} iTop Top pad
657 * @param {int} iRight Right pad
658 * @param {int} iBot Bot pad
659 * @param {int} iLeft Left pad
661 setPadding: function(iTop, iRight, iBot, iLeft) {
662 // this.padding = [iLeft, iRight, iTop, iBot];
663 if (!iRight && 0 !== iRight) {
664 this.padding = [iTop, iTop, iTop, iTop];
665 } else if (!iBot && 0 !== iBot) {
666 this.padding = [iTop, iRight, iTop, iRight];
668 this.padding = [iTop, iRight, iBot, iLeft];
673 * Stores the initial placement of the linked element.
674 * @method setInitialPosition
675 * @param {int} diffX the X offset, default 0
676 * @param {int} diffY the Y offset, default 0
678 setInitPosition: function(diffX, diffY) {
679 var el = this.getEl();
681 if (!this.DDM.verifyEl(el)) {
688 var p = Dom.getXY( el );
690 this.initPageX = p[0] - dx;
691 this.initPageY = p[1] - dy;
693 this.lastPageX = p[0];
694 this.lastPageY = p[1];
697 this.setStartPosition(p);
701 * Sets the start position of the element. This is set when the obj
702 * is initialized, the reset when a drag is started.
703 * @method setStartPosition
704 * @param pos current position (from previous lookup)
707 setStartPosition: function(pos) {
708 var p = pos || Dom.getXY( this.getEl() );
709 this.deltaSetXY = null;
711 this.startPageX = p[0];
712 this.startPageY = p[1];
716 * Add this instance to a group of related drag/drop objects. All
717 * instances belong to at least one group, and can belong to as many
720 * @param sGroup {string} the name of the group
722 addToGroup: function(sGroup) {
723 this.groups[sGroup] = true;
724 this.DDM.regDragDrop(this, sGroup);
728 * Remove's this instance from the supplied interaction group
729 * @method removeFromGroup
730 * @param {string} sGroup The group to drop
732 removeFromGroup: function(sGroup) {
733 if (this.groups[sGroup]) {
734 delete this.groups[sGroup];
737 this.DDM.removeDDFromGroup(this, sGroup);
741 * Allows you to specify that an element other than the linked element
742 * will be moved with the cursor during a drag
743 * @method setDragElId
744 * @param id {string} the id of the element that will be used to initiate the drag
746 setDragElId: function(id) {
751 * Allows you to specify a child of the linked element that should be
752 * used to initiate the drag operation. An example of this would be if
753 * you have a content div with text and links. Clicking anywhere in the
754 * content area would normally start the drag operation. Use this method
755 * to specify that an element inside of the content div is the element
756 * that starts the drag operation.
757 * @method setHandleElId
758 * @param id {string} the id of the element that will be used to
761 setHandleElId: function(id) {
762 if (typeof id !== "string") {
765 this.handleElId = id;
766 this.DDM.regHandle(this.id, id);
770 * Allows you to set an element outside of the linked element as a drag
772 * @method setOuterHandleElId
773 * @param id the id of the element that will be used to initiate the drag
775 setOuterHandleElId: function(id) {
776 if (typeof id !== "string") {
779 Event.on(id, "mousedown",
780 this.handleMouseDown, this);
781 this.setHandleElId(id);
783 this.hasOuterHandles = true;
787 * Remove all drag and drop hooks for this element
791 Event.un(this.id, "mousedown",
792 this.handleMouseDown);
794 this.DDM._remove(this);
797 destroy : function(){
802 * Returns true if this instance is locked, or the drag drop mgr is locked
803 * (meaning that all drag/drop is disabled on the page.)
805 * @return {boolean} true if this obj or all drag/drop is locked, else
808 isLocked: function() {
809 return (this.DDM.isLocked() || this.locked);
813 * Fired when this object is clicked
814 * @method handleMouseDown
816 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
819 handleMouseDown: function(e, oDD){
820 if (this.primaryButtonOnly && e.button != 0) {
824 if (this.isLocked()) {
828 this.DDM.refreshCache(this.groups);
830 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
831 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
833 if (this.clickValidator(e)) {
835 // set the initial element position
836 this.setStartPosition();
842 this.DDM.handleMouseDown(e, this);
844 this.DDM.stopEvent(e);
852 clickValidator: function(e) {
853 var target = e.getTarget();
854 return ( this.isValidHandleChild(target) &&
855 (this.id == this.handleElId ||
856 this.DDM.handleWasClicked(target, this.id)) );
860 * Allows you to specify a tag name that should not start a drag operation
861 * when clicked. This is designed to facilitate embedding links within a
862 * drag handle that do something other than start the drag.
863 * @method addInvalidHandleType
864 * @param {string} tagName the type of element to exclude
866 addInvalidHandleType: function(tagName) {
867 var type = tagName.toUpperCase();
868 this.invalidHandleTypes[type] = type;
872 * Lets you to specify an element id for a child of a drag handle
873 * that should not initiate a drag
874 * @method addInvalidHandleId
875 * @param {string} id the element id of the element you wish to ignore
877 addInvalidHandleId: function(id) {
878 if (typeof id !== "string") {
881 this.invalidHandleIds[id] = id;
885 * Lets you specify a css class of elements that will not initiate a drag
886 * @method addInvalidHandleClass
887 * @param {string} cssClass the class of the elements you wish to ignore
889 addInvalidHandleClass: function(cssClass) {
890 this.invalidHandleClasses.push(cssClass);
894 * Unsets an excluded tag name set by addInvalidHandleType
895 * @method removeInvalidHandleType
896 * @param {string} tagName the type of element to unexclude
898 removeInvalidHandleType: function(tagName) {
899 var type = tagName.toUpperCase();
900 // this.invalidHandleTypes[type] = null;
901 delete this.invalidHandleTypes[type];
905 * Unsets an invalid handle id
906 * @method removeInvalidHandleId
907 * @param {string} id the id of the element to re-enable
909 removeInvalidHandleId: function(id) {
910 if (typeof id !== "string") {
913 delete this.invalidHandleIds[id];
917 * Unsets an invalid css class
918 * @method removeInvalidHandleClass
919 * @param {string} cssClass the class of the element(s) you wish to
922 removeInvalidHandleClass: function(cssClass) {
923 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
924 if (this.invalidHandleClasses[i] == cssClass) {
925 delete this.invalidHandleClasses[i];
931 * Checks the tag exclusion list to see if this click should be ignored
932 * @method isValidHandleChild
933 * @param {HTMLElement} node the HTMLElement to evaluate
934 * @return {boolean} true if this is a valid tag type, false if not
936 isValidHandleChild: function(node) {
939 // var n = (node.nodeName == "#text") ? node.parentNode : node;
942 nodeName = node.nodeName.toUpperCase();
944 nodeName = node.nodeName;
946 valid = valid && !this.invalidHandleTypes[nodeName];
947 valid = valid && !this.invalidHandleIds[node.id];
949 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
950 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
959 * Create the array of horizontal tick marks if an interval was specified
960 * in setXConstraint().
964 setXTicks: function(iStartX, iTickSize) {
966 this.xTickSize = iTickSize;
970 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
972 this.xTicks[this.xTicks.length] = i;
977 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
979 this.xTicks[this.xTicks.length] = i;
984 this.xTicks.sort(this.DDM.numericSort) ;
988 * Create the array of vertical tick marks if an interval was specified in
993 setYTicks: function(iStartY, iTickSize) {
995 this.yTickSize = iTickSize;
999 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1001 this.yTicks[this.yTicks.length] = i;
1006 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1008 this.yTicks[this.yTicks.length] = i;
1013 this.yTicks.sort(this.DDM.numericSort) ;
1017 * By default, the element can be dragged any place on the screen. Use
1018 * this method to limit the horizontal travel of the element. Pass in
1019 * 0,0 for the parameters if you want to lock the drag to the y axis.
1020 * @method setXConstraint
1021 * @param {int} iLeft the number of pixels the element can move to the left
1022 * @param {int} iRight the number of pixels the element can move to the
1024 * @param {int} iTickSize optional parameter for specifying that the
1026 * should move iTickSize pixels at a time.
1028 setXConstraint: function(iLeft, iRight, iTickSize) {
1029 this.leftConstraint = iLeft;
1030 this.rightConstraint = iRight;
1032 this.minX = this.initPageX - iLeft;
1033 this.maxX = this.initPageX + iRight;
1034 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1036 this.constrainX = true;
1040 * Clears any constraints applied to this instance. Also clears ticks
1041 * since they can't exist independent of a constraint at this time.
1042 * @method clearConstraints
1044 clearConstraints: function() {
1045 this.constrainX = false;
1046 this.constrainY = false;
1051 * Clears any tick interval defined for this instance
1052 * @method clearTicks
1054 clearTicks: function() {
1062 * By default, the element can be dragged any place on the screen. Set
1063 * this to limit the vertical travel of the element. Pass in 0,0 for the
1064 * parameters if you want to lock the drag to the x axis.
1065 * @method setYConstraint
1066 * @param {int} iUp the number of pixels the element can move up
1067 * @param {int} iDown the number of pixels the element can move down
1068 * @param {int} iTickSize optional parameter for specifying that the
1069 * element should move iTickSize pixels at a time.
1071 setYConstraint: function(iUp, iDown, iTickSize) {
1072 this.topConstraint = iUp;
1073 this.bottomConstraint = iDown;
1075 this.minY = this.initPageY - iUp;
1076 this.maxY = this.initPageY + iDown;
1077 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1079 this.constrainY = true;
1084 * resetConstraints must be called if you manually reposition a dd element.
1085 * @method resetConstraints
1086 * @param {boolean} maintainOffset
1088 resetConstraints: function() {
1091 // Maintain offsets if necessary
1092 if (this.initPageX || this.initPageX === 0) {
1093 // figure out how much this thing has moved
1094 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1095 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1097 this.setInitPosition(dx, dy);
1099 // This is the first time we have detected the element's position
1101 this.setInitPosition();
1104 if (this.constrainX) {
1105 this.setXConstraint( this.leftConstraint,
1106 this.rightConstraint,
1110 if (this.constrainY) {
1111 this.setYConstraint( this.topConstraint,
1112 this.bottomConstraint,
1118 * Normally the drag element is moved pixel by pixel, but we can specify
1119 * that it move a number of pixels at a time. This method resolves the
1120 * location when we have it set up like this.
1122 * @param {int} val where we want to place the object
1123 * @param {int[]} tickArray sorted array of valid points
1124 * @return {int} the closest tick
1127 getTick: function(val, tickArray) {
1130 // If tick interval is not defined, it is effectively 1 pixel,
1131 // so we return the value passed to us.
1133 } else if (tickArray[0] >= val) {
1134 // The value is lower than the first tick, so we return the first
1136 return tickArray[0];
1138 for (var i=0, len=tickArray.length; i<len; ++i) {
1140 if (tickArray[next] && tickArray[next] >= val) {
1141 var diff1 = val - tickArray[i];
1142 var diff2 = tickArray[next] - val;
1143 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1147 // The value is larger than the last tick, so we return the last
1149 return tickArray[tickArray.length - 1];
1156 * @return {string} string representation of the dd obj
1158 toString: function() {
1159 return ("DragDrop " + this.id);
1167 * Ext JS Library 1.1.1
1168 * Copyright(c) 2006-2007, Ext JS, LLC.
1170 * Originally Released Under LGPL - original licence link has changed is not relivant.
1173 * <script type="text/javascript">
1178 * The drag and drop utility provides a framework for building drag and drop
1179 * applications. In addition to enabling drag and drop for specific elements,
1180 * the drag and drop elements are tracked by the manager class, and the
1181 * interactions between the various elements are tracked during the drag and
1182 * the implementing code is notified about these important moments.
1185 // Only load the library once. Rewriting the manager class would orphan
1186 // existing drag and drop instances.
1187 if (!Roo.dd.DragDropMgr) {
1190 * @class Roo.dd.DragDropMgr
1191 * DragDropMgr is a singleton that tracks the element interaction for
1192 * all DragDrop items in the window. Generally, you will not call
1193 * this class directly, but it does have helper methods that could
1194 * be useful in your DragDrop implementations.
1197 Roo.dd.DragDropMgr = function() {
1199 var Event = Roo.EventManager;
1204 * Two dimensional Array of registered DragDrop objects. The first
1205 * dimension is the DragDrop item group, the second the DragDrop
1208 * @type {string: string}
1215 * Array of element ids defined as drag handles. Used to determine
1216 * if the element that generated the mousedown event is actually the
1217 * handle and not the html element itself.
1218 * @property handleIds
1219 * @type {string: string}
1226 * the DragDrop object that is currently being dragged
1227 * @property dragCurrent
1235 * the DragDrop object(s) that are being hovered over
1236 * @property dragOvers
1244 * the X distance between the cursor and the object being dragged
1253 * the Y distance between the cursor and the object being dragged
1262 * Flag to determine if we should prevent the default behavior of the
1263 * events we define. By default this is true, but this can be set to
1264 * false if you need the default behavior (not recommended)
1265 * @property preventDefault
1269 preventDefault: true,
1272 * Flag to determine if we should stop the propagation of the events
1273 * we generate. This is true by default but you may want to set it to
1274 * false if the html element contains other features that require the
1276 * @property stopPropagation
1280 stopPropagation: true,
1283 * Internal flag that is set to true when drag and drop has been
1285 * @property initialized
1292 * All drag and drop can be disabled.
1300 * Called the first time an element is registered.
1306 this.initialized = true;
1310 * In point mode, drag and drop interaction is defined by the
1311 * location of the cursor during the drag/drop
1319 * In intersect mode, drag and drop interactio nis defined by the
1320 * overlap of two or more drag and drop objects.
1321 * @property INTERSECT
1328 * The current drag and drop mode. Default: POINT
1336 * Runs method on all drag and drop objects
1337 * @method _execOnAll
1341 _execOnAll: function(sMethod, args) {
1342 for (var i in this.ids) {
1343 for (var j in this.ids[i]) {
1344 var oDD = this.ids[i][j];
1345 if (! this.isTypeOfDD(oDD)) {
1348 oDD[sMethod].apply(oDD, args);
1354 * Drag and drop initialization. Sets up the global event handlers
1359 _onLoad: function() {
1364 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1365 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1366 Event.on(window, "unload", this._onUnload, this, true);
1367 Event.on(window, "resize", this._onResize, this, true);
1368 // Event.on(window, "mouseout", this._test);
1373 * Reset constraints on all drag and drop objs
1378 _onResize: function(e) {
1379 this._execOnAll("resetConstraints", []);
1383 * Lock all drag and drop functionality
1387 lock: function() { this.locked = true; },
1390 * Unlock all drag and drop functionality
1394 unlock: function() { this.locked = false; },
1397 * Is drag and drop locked?
1399 * @return {boolean} True if drag and drop is locked, false otherwise.
1402 isLocked: function() { return this.locked; },
1405 * Location cache that is set for all drag drop objects when a drag is
1406 * initiated, cleared when the drag is finished.
1407 * @property locationCache
1414 * Set useCache to false if you want to force object the lookup of each
1415 * drag and drop linked element constantly during a drag.
1416 * @property useCache
1423 * The number of pixels that the mouse needs to move after the
1424 * mousedown before the drag is initiated. Default=3;
1425 * @property clickPixelThresh
1429 clickPixelThresh: 3,
1432 * The number of milliseconds after the mousedown event to initiate the
1433 * drag if we don't get a mouseup event. Default=1000
1434 * @property clickTimeThresh
1438 clickTimeThresh: 350,
1441 * Flag that indicates that either the drag pixel threshold or the
1442 * mousdown time threshold has been met
1443 * @property dragThreshMet
1448 dragThreshMet: false,
1451 * Timeout used for the click time threshold
1452 * @property clickTimeout
1460 * The X position of the mousedown event stored for later use when a
1461 * drag threshold is met.
1470 * The Y position of the mousedown event stored for later use when a
1471 * drag threshold is met.
1480 * Each DragDrop instance must be registered with the DragDropMgr.
1481 * This is executed in DragDrop.init()
1482 * @method regDragDrop
1483 * @param {DragDrop} oDD the DragDrop object to register
1484 * @param {String} sGroup the name of the group this element belongs to
1487 regDragDrop: function(oDD, sGroup) {
1488 if (!this.initialized) { this.init(); }
1490 if (!this.ids[sGroup]) {
1491 this.ids[sGroup] = {};
1493 this.ids[sGroup][oDD.id] = oDD;
1497 * Removes the supplied dd instance from the supplied group. Executed
1498 * by DragDrop.removeFromGroup, so don't call this function directly.
1499 * @method removeDDFromGroup
1503 removeDDFromGroup: function(oDD, sGroup) {
1504 if (!this.ids[sGroup]) {
1505 this.ids[sGroup] = {};
1508 var obj = this.ids[sGroup];
1509 if (obj && obj[oDD.id]) {
1515 * Unregisters a drag and drop item. This is executed in
1516 * DragDrop.unreg, use that method instead of calling this directly.
1521 _remove: function(oDD) {
1522 for (var g in oDD.groups) {
1523 if (g && this.ids[g][oDD.id]) {
1524 delete this.ids[g][oDD.id];
1527 delete this.handleIds[oDD.id];
1531 * Each DragDrop handle element must be registered. This is done
1532 * automatically when executing DragDrop.setHandleElId()
1534 * @param {String} sDDId the DragDrop id this element is a handle for
1535 * @param {String} sHandleId the id of the element that is the drag
1539 regHandle: function(sDDId, sHandleId) {
1540 if (!this.handleIds[sDDId]) {
1541 this.handleIds[sDDId] = {};
1543 this.handleIds[sDDId][sHandleId] = sHandleId;
1547 * Utility function to determine if a given element has been
1548 * registered as a drag drop item.
1549 * @method isDragDrop
1550 * @param {String} id the element id to check
1551 * @return {boolean} true if this element is a DragDrop item,
1555 isDragDrop: function(id) {
1556 return ( this.getDDById(id) ) ? true : false;
1560 * Returns the drag and drop instances that are in all groups the
1561 * passed in instance belongs to.
1562 * @method getRelated
1563 * @param {DragDrop} p_oDD the obj to get related data for
1564 * @param {boolean} bTargetsOnly if true, only return targetable objs
1565 * @return {DragDrop[]} the related instances
1568 getRelated: function(p_oDD, bTargetsOnly) {
1570 for (var i in p_oDD.groups) {
1571 for (j in this.ids[i]) {
1572 var dd = this.ids[i][j];
1573 if (! this.isTypeOfDD(dd)) {
1576 if (!bTargetsOnly || dd.isTarget) {
1577 oDDs[oDDs.length] = dd;
1586 * Returns true if the specified dd target is a legal target for
1587 * the specifice drag obj
1588 * @method isLegalTarget
1589 * @param {DragDrop} the drag obj
1590 * @param {DragDrop} the target
1591 * @return {boolean} true if the target is a legal target for the
1595 isLegalTarget: function (oDD, oTargetDD) {
1596 var targets = this.getRelated(oDD, true);
1597 for (var i=0, len=targets.length;i<len;++i) {
1598 if (targets[i].id == oTargetDD.id) {
1607 * My goal is to be able to transparently determine if an object is
1608 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1609 * returns "object", oDD.constructor.toString() always returns
1610 * "DragDrop" and not the name of the subclass. So for now it just
1611 * evaluates a well-known variable in DragDrop.
1612 * @method isTypeOfDD
1613 * @param {Object} the object to evaluate
1614 * @return {boolean} true if typeof oDD = DragDrop
1617 isTypeOfDD: function (oDD) {
1618 return (oDD && oDD.__ygDragDrop);
1622 * Utility function to determine if a given element has been
1623 * registered as a drag drop handle for the given Drag Drop object.
1625 * @param {String} id the element id to check
1626 * @return {boolean} true if this element is a DragDrop handle, false
1630 isHandle: function(sDDId, sHandleId) {
1631 return ( this.handleIds[sDDId] &&
1632 this.handleIds[sDDId][sHandleId] );
1636 * Returns the DragDrop instance for a given id
1638 * @param {String} id the id of the DragDrop object
1639 * @return {DragDrop} the drag drop object, null if it is not found
1642 getDDById: function(id) {
1643 for (var i in this.ids) {
1644 if (this.ids[i][id]) {
1645 return this.ids[i][id];
1652 * Fired after a registered DragDrop object gets the mousedown event.
1653 * Sets up the events required to track the object being dragged
1654 * @method handleMouseDown
1655 * @param {Event} e the event
1656 * @param oDD the DragDrop object being dragged
1660 handleMouseDown: function(e, oDD) {
1662 Roo.QuickTips.disable();
1664 this.currentTarget = e.getTarget();
1666 this.dragCurrent = oDD;
1668 var el = oDD.getEl();
1670 // track start position
1671 this.startX = e.getPageX();
1672 this.startY = e.getPageY();
1674 this.deltaX = this.startX - el.offsetLeft;
1675 this.deltaY = this.startY - el.offsetTop;
1677 this.dragThreshMet = false;
1679 this.clickTimeout = setTimeout(
1681 var DDM = Roo.dd.DDM;
1682 DDM.startDrag(DDM.startX, DDM.startY);
1684 this.clickTimeThresh );
1688 * Fired when either the drag pixel threshol or the mousedown hold
1689 * time threshold has been met.
1691 * @param x {int} the X position of the original mousedown
1692 * @param y {int} the Y position of the original mousedown
1695 startDrag: function(x, y) {
1696 clearTimeout(this.clickTimeout);
1697 if (this.dragCurrent) {
1698 this.dragCurrent.b4StartDrag(x, y);
1699 this.dragCurrent.startDrag(x, y);
1701 this.dragThreshMet = true;
1705 * Internal function to handle the mouseup event. Will be invoked
1706 * from the context of the document.
1707 * @method handleMouseUp
1708 * @param {Event} e the event
1712 handleMouseUp: function(e) {
1715 Roo.QuickTips.enable();
1717 if (! this.dragCurrent) {
1721 clearTimeout(this.clickTimeout);
1723 if (this.dragThreshMet) {
1724 this.fireEvents(e, true);
1734 * Utility to stop event propagation and event default, if these
1735 * features are turned on.
1737 * @param {Event} e the event as returned by this.getEvent()
1740 stopEvent: function(e){
1741 if(this.stopPropagation) {
1742 e.stopPropagation();
1745 if (this.preventDefault) {
1751 * Internal function to clean up event handlers after the drag
1752 * operation is complete
1754 * @param {Event} e the event
1758 stopDrag: function(e) {
1759 // Fire the drag end event for the item that was dragged
1760 if (this.dragCurrent) {
1761 if (this.dragThreshMet) {
1762 this.dragCurrent.b4EndDrag(e);
1763 this.dragCurrent.endDrag(e);
1766 this.dragCurrent.onMouseUp(e);
1769 this.dragCurrent = null;
1770 this.dragOvers = {};
1774 * Internal function to handle the mousemove event. Will be invoked
1775 * from the context of the html element.
1777 * @TODO figure out what we can do about mouse events lost when the
1778 * user drags objects beyond the window boundary. Currently we can
1779 * detect this in internet explorer by verifying that the mouse is
1780 * down during the mousemove event. Firefox doesn't give us the
1781 * button state on the mousemove event.
1782 * @method handleMouseMove
1783 * @param {Event} e the event
1787 handleMouseMove: function(e) {
1788 if (! this.dragCurrent) {
1792 // var button = e.which || e.button;
1794 // check for IE mouseup outside of page boundary
1795 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1797 return this.handleMouseUp(e);
1800 if (!this.dragThreshMet) {
1801 var diffX = Math.abs(this.startX - e.getPageX());
1802 var diffY = Math.abs(this.startY - e.getPageY());
1803 if (diffX > this.clickPixelThresh ||
1804 diffY > this.clickPixelThresh) {
1805 this.startDrag(this.startX, this.startY);
1809 if (this.dragThreshMet) {
1810 this.dragCurrent.b4Drag(e);
1811 this.dragCurrent.onDrag(e);
1812 if(!this.dragCurrent.moveOnly){
1813 this.fireEvents(e, false);
1823 * Iterates over all of the DragDrop elements to find ones we are
1824 * hovering over or dropping on
1825 * @method fireEvents
1826 * @param {Event} e the event
1827 * @param {boolean} isDrop is this a drop op or a mouseover op?
1831 fireEvents: function(e, isDrop) {
1832 var dc = this.dragCurrent;
1834 // If the user did the mouse up outside of the window, we could
1835 // get here even though we have ended the drag.
1836 if (!dc || dc.isLocked()) {
1840 var pt = e.getPoint();
1842 // cache the previous dragOver array
1850 // Check to see if the object(s) we were hovering over is no longer
1851 // being hovered over so we can fire the onDragOut event
1852 for (var i in this.dragOvers) {
1854 var ddo = this.dragOvers[i];
1856 if (! this.isTypeOfDD(ddo)) {
1860 if (! this.isOverTarget(pt, ddo, this.mode)) {
1861 outEvts.push( ddo );
1865 delete this.dragOvers[i];
1868 for (var sGroup in dc.groups) {
1870 if ("string" != typeof sGroup) {
1874 for (i in this.ids[sGroup]) {
1875 var oDD = this.ids[sGroup][i];
1876 if (! this.isTypeOfDD(oDD)) {
1880 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1881 if (this.isOverTarget(pt, oDD, this.mode)) {
1882 // look for drop interactions
1884 dropEvts.push( oDD );
1885 // look for drag enter and drag over interactions
1888 // initial drag over: dragEnter fires
1889 if (!oldOvers[oDD.id]) {
1890 enterEvts.push( oDD );
1891 // subsequent drag overs: dragOver fires
1893 overEvts.push( oDD );
1896 this.dragOvers[oDD.id] = oDD;
1904 if (outEvts.length) {
1905 dc.b4DragOut(e, outEvts);
1906 dc.onDragOut(e, outEvts);
1909 if (enterEvts.length) {
1910 dc.onDragEnter(e, enterEvts);
1913 if (overEvts.length) {
1914 dc.b4DragOver(e, overEvts);
1915 dc.onDragOver(e, overEvts);
1918 if (dropEvts.length) {
1919 dc.b4DragDrop(e, dropEvts);
1920 dc.onDragDrop(e, dropEvts);
1924 // fire dragout events
1926 for (i=0, len=outEvts.length; i<len; ++i) {
1927 dc.b4DragOut(e, outEvts[i].id);
1928 dc.onDragOut(e, outEvts[i].id);
1931 // fire enter events
1932 for (i=0,len=enterEvts.length; i<len; ++i) {
1933 // dc.b4DragEnter(e, oDD.id);
1934 dc.onDragEnter(e, enterEvts[i].id);
1938 for (i=0,len=overEvts.length; i<len; ++i) {
1939 dc.b4DragOver(e, overEvts[i].id);
1940 dc.onDragOver(e, overEvts[i].id);
1944 for (i=0, len=dropEvts.length; i<len; ++i) {
1945 dc.b4DragDrop(e, dropEvts[i].id);
1946 dc.onDragDrop(e, dropEvts[i].id);
1951 // notify about a drop that did not find a target
1952 if (isDrop && !dropEvts.length) {
1953 dc.onInvalidDrop(e);
1959 * Helper function for getting the best match from the list of drag
1960 * and drop objects returned by the drag and drop events when we are
1961 * in INTERSECT mode. It returns either the first object that the
1962 * cursor is over, or the object that has the greatest overlap with
1963 * the dragged element.
1964 * @method getBestMatch
1965 * @param {DragDrop[]} dds The array of drag and drop objects
1967 * @return {DragDrop} The best single match
1970 getBestMatch: function(dds) {
1972 // Return null if the input is not what we expect
1973 //if (!dds || !dds.length || dds.length == 0) {
1975 // If there is only one item, it wins
1976 //} else if (dds.length == 1) {
1978 var len = dds.length;
1983 // Loop through the targeted items
1984 for (var i=0; i<len; ++i) {
1986 // If the cursor is over the object, it wins. If the
1987 // cursor is over multiple matches, the first one we come
1989 if (dd.cursorIsOver) {
1992 // Otherwise the object with the most overlap wins
1995 winner.overlap.getArea() < dd.overlap.getArea()) {
2006 * Refreshes the cache of the top-left and bottom-right points of the
2007 * drag and drop objects in the specified group(s). This is in the
2008 * format that is stored in the drag and drop instance, so typical
2011 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2015 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2017 * @TODO this really should be an indexed array. Alternatively this
2018 * method could accept both.
2019 * @method refreshCache
2020 * @param {Object} groups an associative array of groups to refresh
2023 refreshCache: function(groups) {
2024 for (var sGroup in groups) {
2025 if ("string" != typeof sGroup) {
2028 for (var i in this.ids[sGroup]) {
2029 var oDD = this.ids[sGroup][i];
2031 if (this.isTypeOfDD(oDD)) {
2032 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2033 var loc = this.getLocation(oDD);
2035 this.locationCache[oDD.id] = loc;
2037 delete this.locationCache[oDD.id];
2038 // this will unregister the drag and drop object if
2039 // the element is not in a usable state
2048 * This checks to make sure an element exists and is in the DOM. The
2049 * main purpose is to handle cases where innerHTML is used to remove
2050 * drag and drop objects from the DOM. IE provides an 'unspecified
2051 * error' when trying to access the offsetParent of such an element
2053 * @param {HTMLElement} el the element to check
2054 * @return {boolean} true if the element looks usable
2057 verifyEl: function(el) {
2062 parent = el.offsetParent;
2065 parent = el.offsetParent;
2076 * Returns a Region object containing the drag and drop element's position
2077 * and size, including the padding configured for it
2078 * @method getLocation
2079 * @param {DragDrop} oDD the drag and drop object to get the
2081 * @return {Roo.lib.Region} a Region object representing the total area
2082 * the element occupies, including any padding
2083 * the instance is configured for.
2086 getLocation: function(oDD) {
2087 if (! this.isTypeOfDD(oDD)) {
2091 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2094 pos= Roo.lib.Dom.getXY(el);
2102 x2 = x1 + el.offsetWidth;
2104 y2 = y1 + el.offsetHeight;
2106 t = y1 - oDD.padding[0];
2107 r = x2 + oDD.padding[1];
2108 b = y2 + oDD.padding[2];
2109 l = x1 - oDD.padding[3];
2111 return new Roo.lib.Region( t, r, b, l );
2115 * Checks the cursor location to see if it over the target
2116 * @method isOverTarget
2117 * @param {Roo.lib.Point} pt The point to evaluate
2118 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2119 * @return {boolean} true if the mouse is over the target
2123 isOverTarget: function(pt, oTarget, intersect) {
2124 // use cache if available
2125 var loc = this.locationCache[oTarget.id];
2126 if (!loc || !this.useCache) {
2127 loc = this.getLocation(oTarget);
2128 this.locationCache[oTarget.id] = loc;
2136 oTarget.cursorIsOver = loc.contains( pt );
2138 // DragDrop is using this as a sanity check for the initial mousedown
2139 // in this case we are done. In POINT mode, if the drag obj has no
2140 // contraints, we are also done. Otherwise we need to evaluate the
2141 // location of the target as related to the actual location of the
2143 var dc = this.dragCurrent;
2144 if (!dc || !dc.getTargetCoord ||
2145 (!intersect && !dc.constrainX && !dc.constrainY)) {
2146 return oTarget.cursorIsOver;
2149 oTarget.overlap = null;
2151 // Get the current location of the drag element, this is the
2152 // location of the mouse event less the delta that represents
2153 // where the original mousedown happened on the element. We
2154 // need to consider constraints and ticks as well.
2155 var pos = dc.getTargetCoord(pt.x, pt.y);
2157 var el = dc.getDragEl();
2158 var curRegion = new Roo.lib.Region( pos.y,
2159 pos.x + el.offsetWidth,
2160 pos.y + el.offsetHeight,
2163 var overlap = curRegion.intersect(loc);
2166 oTarget.overlap = overlap;
2167 return (intersect) ? true : oTarget.cursorIsOver;
2174 * unload event handler
2179 _onUnload: function(e, me) {
2180 Roo.dd.DragDropMgr.unregAll();
2184 * Cleans up the drag and drop events and objects.
2189 unregAll: function() {
2191 if (this.dragCurrent) {
2193 this.dragCurrent = null;
2196 this._execOnAll("unreg", []);
2198 for (i in this.elementCache) {
2199 delete this.elementCache[i];
2202 this.elementCache = {};
2207 * A cache of DOM elements
2208 * @property elementCache
2215 * Get the wrapper for the DOM element specified
2216 * @method getElWrapper
2217 * @param {String} id the id of the element to get
2218 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2220 * @deprecated This wrapper isn't that useful
2223 getElWrapper: function(id) {
2224 var oWrapper = this.elementCache[id];
2225 if (!oWrapper || !oWrapper.el) {
2226 oWrapper = this.elementCache[id] =
2227 new this.ElementWrapper(Roo.getDom(id));
2233 * Returns the actual DOM element
2234 * @method getElement
2235 * @param {String} id the id of the elment to get
2236 * @return {Object} The element
2237 * @deprecated use Roo.getDom instead
2240 getElement: function(id) {
2241 return Roo.getDom(id);
2245 * Returns the style property for the DOM element (i.e.,
2246 * document.getElById(id).style)
2248 * @param {String} id the id of the elment to get
2249 * @return {Object} The style property of the element
2250 * @deprecated use Roo.getDom instead
2253 getCss: function(id) {
2254 var el = Roo.getDom(id);
2255 return (el) ? el.style : null;
2259 * Inner class for cached elements
2260 * @class DragDropMgr.ElementWrapper
2265 ElementWrapper: function(el) {
2270 this.el = el || null;
2275 this.id = this.el && el.id;
2277 * A reference to the style property
2280 this.css = this.el && el.style;
2284 * Returns the X position of an html element
2286 * @param el the element for which to get the position
2287 * @return {int} the X coordinate
2289 * @deprecated use Roo.lib.Dom.getX instead
2292 getPosX: function(el) {
2293 return Roo.lib.Dom.getX(el);
2297 * Returns the Y position of an html element
2299 * @param el the element for which to get the position
2300 * @return {int} the Y coordinate
2301 * @deprecated use Roo.lib.Dom.getY instead
2304 getPosY: function(el) {
2305 return Roo.lib.Dom.getY(el);
2309 * Swap two nodes. In IE, we use the native method, for others we
2310 * emulate the IE behavior
2312 * @param n1 the first node to swap
2313 * @param n2 the other node to swap
2316 swapNode: function(n1, n2) {
2320 var p = n2.parentNode;
2321 var s = n2.nextSibling;
2324 p.insertBefore(n1, n2);
2325 } else if (n2 == n1.nextSibling) {
2326 p.insertBefore(n2, n1);
2328 n1.parentNode.replaceChild(n2, n1);
2329 p.insertBefore(n1, s);
2335 * Returns the current scroll position
2340 getScroll: function () {
2341 var t, l, dde=document.documentElement, db=document.body;
2342 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2351 return { top: t, left: l };
2355 * Returns the specified element style property
2357 * @param {HTMLElement} el the element
2358 * @param {string} styleProp the style property
2359 * @return {string} The value of the style property
2360 * @deprecated use Roo.lib.Dom.getStyle
2363 getStyle: function(el, styleProp) {
2364 return Roo.fly(el).getStyle(styleProp);
2368 * Gets the scrollTop
2369 * @method getScrollTop
2370 * @return {int} the document's scrollTop
2373 getScrollTop: function () { return this.getScroll().top; },
2376 * Gets the scrollLeft
2377 * @method getScrollLeft
2378 * @return {int} the document's scrollTop
2381 getScrollLeft: function () { return this.getScroll().left; },
2384 * Sets the x/y position of an element to the location of the
2387 * @param {HTMLElement} moveEl The element to move
2388 * @param {HTMLElement} targetEl The position reference element
2391 moveToEl: function (moveEl, targetEl) {
2392 var aCoord = Roo.lib.Dom.getXY(targetEl);
2393 Roo.lib.Dom.setXY(moveEl, aCoord);
2397 * Numeric array sort function
2398 * @method numericSort
2401 numericSort: function(a, b) { return (a - b); },
2405 * @property _timeoutCount
2412 * Trying to make the load order less important. Without this we get
2413 * an error if this file is loaded before the Event Utility.
2414 * @method _addListeners
2418 _addListeners: function() {
2419 var DDM = Roo.dd.DDM;
2420 if ( Roo.lib.Event && document ) {
2423 if (DDM._timeoutCount > 2000) {
2425 setTimeout(DDM._addListeners, 10);
2426 if (document && document.body) {
2427 DDM._timeoutCount += 1;
2434 * Recursively searches the immediate parent and all child nodes for
2435 * the handle element in order to determine wheter or not it was
2437 * @method handleWasClicked
2438 * @param node the html element to inspect
2441 handleWasClicked: function(node, id) {
2442 if (this.isHandle(id, node.id)) {
2445 // check to see if this is a text node child of the one we want
2446 var p = node.parentNode;
2449 if (this.isHandle(id, p.id)) {
2464 // shorter alias, save a few bytes
2465 Roo.dd.DDM = Roo.dd.DragDropMgr;
2466 Roo.dd.DDM._addListeners();
2470 * Ext JS Library 1.1.1
2471 * Copyright(c) 2006-2007, Ext JS, LLC.
2473 * Originally Released Under LGPL - original licence link has changed is not relivant.
2476 * <script type="text/javascript">
2481 * A DragDrop implementation where the linked element follows the
2482 * mouse cursor during a drag.
2483 * @extends Roo.dd.DragDrop
2485 * @param {String} id the id of the linked element
2486 * @param {String} sGroup the group of related DragDrop items
2487 * @param {object} config an object containing configurable attributes
2488 * Valid properties for DD:
2491 Roo.dd.DD = function(id, sGroup, config) {
2493 this.init(id, sGroup, config);
2497 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2500 * When set to true, the utility automatically tries to scroll the browser
2501 * window wehn a drag and drop element is dragged near the viewport boundary.
2509 * Sets the pointer offset to the distance between the linked element's top
2510 * left corner and the location the element was clicked
2511 * @method autoOffset
2512 * @param {int} iPageX the X coordinate of the click
2513 * @param {int} iPageY the Y coordinate of the click
2515 autoOffset: function(iPageX, iPageY) {
2516 var x = iPageX - this.startPageX;
2517 var y = iPageY - this.startPageY;
2518 this.setDelta(x, y);
2522 * Sets the pointer offset. You can call this directly to force the
2523 * offset to be in a particular location (e.g., pass in 0,0 to set it
2524 * to the center of the object)
2526 * @param {int} iDeltaX the distance from the left
2527 * @param {int} iDeltaY the distance from the top
2529 setDelta: function(iDeltaX, iDeltaY) {
2530 this.deltaX = iDeltaX;
2531 this.deltaY = iDeltaY;
2535 * Sets the drag element to the location of the mousedown or click event,
2536 * maintaining the cursor location relative to the location on the element
2537 * that was clicked. Override this if you want to place the element in a
2538 * location other than where the cursor is.
2539 * @method setDragElPos
2540 * @param {int} iPageX the X coordinate of the mousedown or drag event
2541 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2543 setDragElPos: function(iPageX, iPageY) {
2544 // the first time we do this, we are going to check to make sure
2545 // the element has css positioning
2547 var el = this.getDragEl();
2548 this.alignElWithMouse(el, iPageX, iPageY);
2552 * Sets the element to the location of the mousedown or click event,
2553 * maintaining the cursor location relative to the location on the element
2554 * that was clicked. Override this if you want to place the element in a
2555 * location other than where the cursor is.
2556 * @method alignElWithMouse
2557 * @param {HTMLElement} el the element to move
2558 * @param {int} iPageX the X coordinate of the mousedown or drag event
2559 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2561 alignElWithMouse: function(el, iPageX, iPageY) {
2562 var oCoord = this.getTargetCoord(iPageX, iPageY);
2563 var fly = el.dom ? el : Roo.fly(el);
2564 if (!this.deltaSetXY) {
2565 var aCoord = [oCoord.x, oCoord.y];
2567 var newLeft = fly.getLeft(true);
2568 var newTop = fly.getTop(true);
2569 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2571 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2574 this.cachePosition(oCoord.x, oCoord.y);
2575 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2580 * Saves the most recent position so that we can reset the constraints and
2581 * tick marks on-demand. We need to know this so that we can calculate the
2582 * number of pixels the element is offset from its original position.
2583 * @method cachePosition
2584 * @param iPageX the current x position (optional, this just makes it so we
2585 * don't have to look it up again)
2586 * @param iPageY the current y position (optional, this just makes it so we
2587 * don't have to look it up again)
2589 cachePosition: function(iPageX, iPageY) {
2591 this.lastPageX = iPageX;
2592 this.lastPageY = iPageY;
2594 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2595 this.lastPageX = aCoord[0];
2596 this.lastPageY = aCoord[1];
2601 * Auto-scroll the window if the dragged object has been moved beyond the
2602 * visible window boundary.
2603 * @method autoScroll
2604 * @param {int} x the drag element's x position
2605 * @param {int} y the drag element's y position
2606 * @param {int} h the height of the drag element
2607 * @param {int} w the width of the drag element
2610 autoScroll: function(x, y, h, w) {
2613 // The client height
2614 var clientH = Roo.lib.Dom.getViewWidth();
2617 var clientW = Roo.lib.Dom.getViewHeight();
2619 // The amt scrolled down
2620 var st = this.DDM.getScrollTop();
2622 // The amt scrolled right
2623 var sl = this.DDM.getScrollLeft();
2625 // Location of the bottom of the element
2628 // Location of the right of the element
2631 // The distance from the cursor to the bottom of the visible area,
2632 // adjusted so that we don't scroll if the cursor is beyond the
2633 // element drag constraints
2634 var toBot = (clientH + st - y - this.deltaY);
2636 // The distance from the cursor to the right of the visible area
2637 var toRight = (clientW + sl - x - this.deltaX);
2640 // How close to the edge the cursor must be before we scroll
2641 // var thresh = (document.all) ? 100 : 40;
2644 // How many pixels to scroll per autoscroll op. This helps to reduce
2645 // clunky scrolling. IE is more sensitive about this ... it needs this
2646 // value to be higher.
2647 var scrAmt = (document.all) ? 80 : 30;
2649 // Scroll down if we are near the bottom of the visible page and the
2650 // obj extends below the crease
2651 if ( bot > clientH && toBot < thresh ) {
2652 window.scrollTo(sl, st + scrAmt);
2655 // Scroll up if the window is scrolled down and the top of the object
2656 // goes above the top border
2657 if ( y < st && st > 0 && y - st < thresh ) {
2658 window.scrollTo(sl, st - scrAmt);
2661 // Scroll right if the obj is beyond the right border and the cursor is
2663 if ( right > clientW && toRight < thresh ) {
2664 window.scrollTo(sl + scrAmt, st);
2667 // Scroll left if the window has been scrolled to the right and the obj
2668 // extends past the left border
2669 if ( x < sl && sl > 0 && x - sl < thresh ) {
2670 window.scrollTo(sl - scrAmt, st);
2676 * Finds the location the element should be placed if we want to move
2677 * it to where the mouse location less the click offset would place us.
2678 * @method getTargetCoord
2679 * @param {int} iPageX the X coordinate of the click
2680 * @param {int} iPageY the Y coordinate of the click
2681 * @return an object that contains the coordinates (Object.x and Object.y)
2684 getTargetCoord: function(iPageX, iPageY) {
2687 var x = iPageX - this.deltaX;
2688 var y = iPageY - this.deltaY;
2690 if (this.constrainX) {
2691 if (x < this.minX) { x = this.minX; }
2692 if (x > this.maxX) { x = this.maxX; }
2695 if (this.constrainY) {
2696 if (y < this.minY) { y = this.minY; }
2697 if (y > this.maxY) { y = this.maxY; }
2700 x = this.getTick(x, this.xTicks);
2701 y = this.getTick(y, this.yTicks);
2708 * Sets up config options specific to this class. Overrides
2709 * Roo.dd.DragDrop, but all versions of this method through the
2710 * inheritance chain are called
2712 applyConfig: function() {
2713 Roo.dd.DD.superclass.applyConfig.call(this);
2714 this.scroll = (this.config.scroll !== false);
2718 * Event that fires prior to the onMouseDown event. Overrides
2721 b4MouseDown: function(e) {
2722 // this.resetConstraints();
2723 this.autoOffset(e.getPageX(),
2728 * Event that fires prior to the onDrag event. Overrides
2731 b4Drag: function(e) {
2732 this.setDragElPos(e.getPageX(),
2736 toString: function() {
2737 return ("DD " + this.id);
2740 //////////////////////////////////////////////////////////////////////////
2741 // Debugging ygDragDrop events that can be overridden
2742 //////////////////////////////////////////////////////////////////////////
2744 startDrag: function(x, y) {
2747 onDrag: function(e) {
2750 onDragEnter: function(e, id) {
2753 onDragOver: function(e, id) {
2756 onDragOut: function(e, id) {
2759 onDragDrop: function(e, id) {
2762 endDrag: function(e) {
2769 * Ext JS Library 1.1.1
2770 * Copyright(c) 2006-2007, Ext JS, LLC.
2772 * Originally Released Under LGPL - original licence link has changed is not relivant.
2775 * <script type="text/javascript">
2779 * @class Roo.dd.DDProxy
2780 * A DragDrop implementation that inserts an empty, bordered div into
2781 * the document that follows the cursor during drag operations. At the time of
2782 * the click, the frame div is resized to the dimensions of the linked html
2783 * element, and moved to the exact location of the linked element.
2785 * References to the "frame" element refer to the single proxy element that
2786 * was created to be dragged in place of all DDProxy elements on the
2789 * @extends Roo.dd.DD
2791 * @param {String} id the id of the linked html element
2792 * @param {String} sGroup the group of related DragDrop objects
2793 * @param {object} config an object containing configurable attributes
2794 * Valid properties for DDProxy in addition to those in DragDrop:
2795 * resizeFrame, centerFrame, dragElId
2797 Roo.dd.DDProxy = function(id, sGroup, config) {
2799 this.init(id, sGroup, config);
2805 * The default drag frame div id
2806 * @property Roo.dd.DDProxy.dragElId
2810 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2812 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2815 * By default we resize the drag frame to be the same size as the element
2816 * we want to drag (this is to get the frame effect). We can turn it off
2817 * if we want a different behavior.
2818 * @property resizeFrame
2824 * By default the frame is positioned exactly where the drag element is, so
2825 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2826 * you do not have constraints on the obj is to have the drag frame centered
2827 * around the cursor. Set centerFrame to true for this effect.
2828 * @property centerFrame
2834 * Creates the proxy element if it does not yet exist
2835 * @method createFrame
2837 createFrame: function() {
2839 var body = document.body;
2841 if (!body || !body.firstChild) {
2842 setTimeout( function() { self.createFrame(); }, 50 );
2846 var div = this.getDragEl();
2849 div = document.createElement("div");
2850 div.id = this.dragElId;
2853 s.position = "absolute";
2854 s.visibility = "hidden";
2856 s.border = "2px solid #aaa";
2859 // appendChild can blow up IE if invoked prior to the window load event
2860 // while rendering a table. It is possible there are other scenarios
2861 // that would cause this to happen as well.
2862 body.insertBefore(div, body.firstChild);
2867 * Initialization for the drag frame element. Must be called in the
2868 * constructor of all subclasses
2871 initFrame: function() {
2875 applyConfig: function() {
2876 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2878 this.resizeFrame = (this.config.resizeFrame !== false);
2879 this.centerFrame = (this.config.centerFrame);
2880 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2884 * Resizes the drag frame to the dimensions of the clicked object, positions
2885 * it over the object, and finally displays it
2887 * @param {int} iPageX X click position
2888 * @param {int} iPageY Y click position
2891 showFrame: function(iPageX, iPageY) {
2892 var el = this.getEl();
2893 var dragEl = this.getDragEl();
2894 var s = dragEl.style;
2896 this._resizeProxy();
2898 if (this.centerFrame) {
2899 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2900 Math.round(parseInt(s.height, 10)/2) );
2903 this.setDragElPos(iPageX, iPageY);
2905 Roo.fly(dragEl).show();
2909 * The proxy is automatically resized to the dimensions of the linked
2910 * element when a drag is initiated, unless resizeFrame is set to false
2911 * @method _resizeProxy
2914 _resizeProxy: function() {
2915 if (this.resizeFrame) {
2916 var el = this.getEl();
2917 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2921 // overrides Roo.dd.DragDrop
2922 b4MouseDown: function(e) {
2923 var x = e.getPageX();
2924 var y = e.getPageY();
2925 this.autoOffset(x, y);
2926 this.setDragElPos(x, y);
2929 // overrides Roo.dd.DragDrop
2930 b4StartDrag: function(x, y) {
2931 // show the drag frame
2932 this.showFrame(x, y);
2935 // overrides Roo.dd.DragDrop
2936 b4EndDrag: function(e) {
2937 Roo.fly(this.getDragEl()).hide();
2940 // overrides Roo.dd.DragDrop
2941 // By default we try to move the element to the last location of the frame.
2942 // This is so that the default behavior mirrors that of Roo.dd.DD.
2943 endDrag: function(e) {
2945 var lel = this.getEl();
2946 var del = this.getDragEl();
2948 // Show the drag frame briefly so we can get its position
2949 del.style.visibility = "";
2952 // Hide the linked element before the move to get around a Safari
2954 lel.style.visibility = "hidden";
2955 Roo.dd.DDM.moveToEl(lel, del);
2956 del.style.visibility = "hidden";
2957 lel.style.visibility = "";
2962 beforeMove : function(){
2966 afterDrag : function(){
2970 toString: function() {
2971 return ("DDProxy " + this.id);
2977 * Ext JS Library 1.1.1
2978 * Copyright(c) 2006-2007, Ext JS, LLC.
2980 * Originally Released Under LGPL - original licence link has changed is not relivant.
2983 * <script type="text/javascript">
2987 * @class Roo.dd.DDTarget
2988 * A DragDrop implementation that does not move, but can be a drop
2989 * target. You would get the same result by simply omitting implementation
2990 * for the event callbacks, but this way we reduce the processing cost of the
2991 * event listener and the callbacks.
2992 * @extends Roo.dd.DragDrop
2994 * @param {String} id the id of the element that is a drop target
2995 * @param {String} sGroup the group of related DragDrop objects
2996 * @param {object} config an object containing configurable attributes
2997 * Valid properties for DDTarget in addition to those in
3001 Roo.dd.DDTarget = function(id, sGroup, config) {
3003 this.initTarget(id, sGroup, config);
3005 if (config.listeners || config.events) {
3006 Roo.dd.DragDrop.superclass.constructor.call(this, {
3007 listeners : config.listeners || {},
3008 events : config.events || {}
3013 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3014 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3015 toString: function() {
3016 return ("DDTarget " + this.id);
3021 * Ext JS Library 1.1.1
3022 * Copyright(c) 2006-2007, Ext JS, LLC.
3024 * Originally Released Under LGPL - original licence link has changed is not relivant.
3027 * <script type="text/javascript">
3032 * @class Roo.dd.ScrollManager
3033 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3034 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3037 Roo.dd.ScrollManager = function(){
3038 var ddm = Roo.dd.DragDropMgr;
3043 var onStop = function(e){
3048 var triggerRefresh = function(){
3049 if(ddm.dragCurrent){
3050 ddm.refreshCache(ddm.dragCurrent.groups);
3054 var doScroll = function(){
3055 if(ddm.dragCurrent){
3056 var dds = Roo.dd.ScrollManager;
3058 if(proc.el.scroll(proc.dir, dds.increment)){
3062 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3067 var clearProc = function(){
3069 clearInterval(proc.id);
3076 var startProc = function(el, dir){
3080 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3083 var onFire = function(e, isDrop){
3084 if(isDrop || !ddm.dragCurrent){ return; }
3085 var dds = Roo.dd.ScrollManager;
3086 if(!dragEl || dragEl != ddm.dragCurrent){
3087 dragEl = ddm.dragCurrent;
3088 // refresh regions on drag start
3092 var xy = Roo.lib.Event.getXY(e);
3093 var pt = new Roo.lib.Point(xy[0], xy[1]);
3095 var el = els[id], r = el._region;
3096 if(r && r.contains(pt) && el.isScrollable()){
3097 if(r.bottom - pt.y <= dds.thresh){
3099 startProc(el, "down");
3102 }else if(r.right - pt.x <= dds.thresh){
3104 startProc(el, "left");
3107 }else if(pt.y - r.top <= dds.thresh){
3109 startProc(el, "up");
3112 }else if(pt.x - r.left <= dds.thresh){
3114 startProc(el, "right");
3123 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3124 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3128 * Registers new overflow element(s) to auto scroll
3129 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3131 register : function(el){
3132 if(el instanceof Array){
3133 for(var i = 0, len = el.length; i < len; i++) {
3134 this.register(el[i]);
3143 * Unregisters overflow element(s) so they are no longer scrolled
3144 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3146 unregister : function(el){
3147 if(el instanceof Array){
3148 for(var i = 0, len = el.length; i < len; i++) {
3149 this.unregister(el[i]);
3158 * The number of pixels from the edge of a container the pointer needs to be to
3159 * trigger scrolling (defaults to 25)
3165 * The number of pixels to scroll in each scroll increment (defaults to 50)
3171 * The frequency of scrolls in milliseconds (defaults to 500)
3177 * True to animate the scroll (defaults to true)
3183 * The animation duration in seconds -
3184 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3190 * Manually trigger a cache refresh.
3192 refreshCache : function(){
3194 if(typeof els[id] == 'object'){ // for people extending the object prototype
3195 els[id]._region = els[id].getRegion();
3202 * Ext JS Library 1.1.1
3203 * Copyright(c) 2006-2007, Ext JS, LLC.
3205 * Originally Released Under LGPL - original licence link has changed is not relivant.
3208 * <script type="text/javascript">
3213 * @class Roo.dd.Registry
3214 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3215 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3218 Roo.dd.Registry = function(){
3223 var getId = function(el, autogen){
3224 if(typeof el == "string"){
3228 if(!id && autogen !== false){
3229 id = "roodd-" + (++autoIdSeed);
3237 * Register a drag drop element
3238 * @param {String|HTMLElement} element The id or DOM node to register
3239 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3240 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3241 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3242 * populated in the data object (if applicable):
3244 Value Description<br />
3245 --------- ------------------------------------------<br />
3246 handles Array of DOM nodes that trigger dragging<br />
3247 for the element being registered<br />
3248 isHandle True if the element passed in triggers<br />
3249 dragging itself, else false
3252 register : function(el, data){
3254 if(typeof el == "string"){
3255 el = document.getElementById(el);
3258 elements[getId(el)] = data;
3259 if(data.isHandle !== false){
3260 handles[data.ddel.id] = data;
3263 var hs = data.handles;
3264 for(var i = 0, len = hs.length; i < len; i++){
3265 handles[getId(hs[i])] = data;
3271 * Unregister a drag drop element
3272 * @param {String|HTMLElement} element The id or DOM node to unregister
3274 unregister : function(el){
3275 var id = getId(el, false);
3276 var data = elements[id];
3278 delete elements[id];
3280 var hs = data.handles;
3281 for(var i = 0, len = hs.length; i < len; i++){
3282 delete handles[getId(hs[i], false)];
3289 * Returns the handle registered for a DOM Node by id
3290 * @param {String|HTMLElement} id The DOM node or id to look up
3291 * @return {Object} handle The custom handle data
3293 getHandle : function(id){
3294 if(typeof id != "string"){ // must be element?
3301 * Returns the handle that is registered for the DOM node that is the target of the event
3302 * @param {Event} e The event
3303 * @return {Object} handle The custom handle data
3305 getHandleFromEvent : function(e){
3306 var t = Roo.lib.Event.getTarget(e);
3307 return t ? handles[t.id] : null;
3311 * Returns a custom data object that is registered for a DOM node by id
3312 * @param {String|HTMLElement} id The DOM node or id to look up
3313 * @return {Object} data The custom data
3315 getTarget : function(id){
3316 if(typeof id != "string"){ // must be element?
3319 return elements[id];
3323 * Returns a custom data object that is registered for the DOM node that is the target of the event
3324 * @param {Event} e The event
3325 * @return {Object} data The custom data
3327 getTargetFromEvent : function(e){
3328 var t = Roo.lib.Event.getTarget(e);
3329 return t ? elements[t.id] || handles[t.id] : null;
3334 * Ext JS Library 1.1.1
3335 * Copyright(c) 2006-2007, Ext JS, LLC.
3337 * Originally Released Under LGPL - original licence link has changed is not relivant.
3340 * <script type="text/javascript">
3345 * @class Roo.dd.StatusProxy
3346 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3347 * default drag proxy used by all Roo.dd components.
3349 * @param {Object} config
3351 Roo.dd.StatusProxy = function(config){
3352 Roo.apply(this, config);
3353 this.id = this.id || Roo.id();
3354 this.el = new Roo.Layer({
3356 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3357 {tag: "div", cls: "x-dd-drop-icon"},
3358 {tag: "div", cls: "x-dd-drag-ghost"}
3361 shadow: !config || config.shadow !== false
3363 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3364 this.dropStatus = this.dropNotAllowed;
3367 Roo.dd.StatusProxy.prototype = {
3369 * @cfg {String} dropAllowed
3370 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3372 dropAllowed : "x-dd-drop-ok",
3374 * @cfg {String} dropNotAllowed
3375 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3377 dropNotAllowed : "x-dd-drop-nodrop",
3380 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3381 * over the current target element.
3382 * @param {String} cssClass The css class for the new drop status indicator image
3384 setStatus : function(cssClass){
3385 cssClass = cssClass || this.dropNotAllowed;
3386 if(this.dropStatus != cssClass){
3387 this.el.replaceClass(this.dropStatus, cssClass);
3388 this.dropStatus = cssClass;
3393 * Resets the status indicator to the default dropNotAllowed value
3394 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3396 reset : function(clearGhost){
3397 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3398 this.dropStatus = this.dropNotAllowed;
3400 this.ghost.update("");
3405 * Updates the contents of the ghost element
3406 * @param {String} html The html that will replace the current innerHTML of the ghost element
3408 update : function(html){
3409 if(typeof html == "string"){
3410 this.ghost.update(html);
3412 this.ghost.update("");
3413 html.style.margin = "0";
3414 this.ghost.dom.appendChild(html);
3416 // ensure float = none set?? cant remember why though.
3417 var el = this.ghost.dom.firstChild;
3419 Roo.fly(el).setStyle('float', 'none');
3424 * Returns the underlying proxy {@link Roo.Layer}
3425 * @return {Roo.Layer} el
3432 * Returns the ghost element
3433 * @return {Roo.Element} el
3435 getGhost : function(){
3441 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3443 hide : function(clear){
3451 * Stops the repair animation if it's currently running
3454 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3460 * Displays this proxy
3467 * Force the Layer to sync its shadow and shim positions to the element
3474 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3475 * invalid drop operation by the item being dragged.
3476 * @param {Array} xy The XY position of the element ([x, y])
3477 * @param {Function} callback The function to call after the repair is complete
3478 * @param {Object} scope The scope in which to execute the callback
3480 repair : function(xy, callback, scope){
3481 this.callback = callback;
3483 if(xy && this.animRepair !== false){
3484 this.el.addClass("x-dd-drag-repair");
3485 this.el.hideUnders(true);
3486 this.anim = this.el.shift({
3487 duration: this.repairDuration || .5,
3491 callback: this.afterRepair,
3500 afterRepair : function(){
3502 if(typeof this.callback == "function"){
3503 this.callback.call(this.scope || this);
3505 this.callback = null;
3510 * Ext JS Library 1.1.1
3511 * Copyright(c) 2006-2007, Ext JS, LLC.
3513 * Originally Released Under LGPL - original licence link has changed is not relivant.
3516 * <script type="text/javascript">
3520 * @class Roo.dd.DragSource
3521 * @extends Roo.dd.DDProxy
3522 * A simple class that provides the basic implementation needed to make any element draggable.
3524 * @param {String/HTMLElement/Element} el The container element
3525 * @param {Object} config
3527 Roo.dd.DragSource = function(el, config){
3528 this.el = Roo.get(el);
3531 Roo.apply(this, config);
3534 this.proxy = new Roo.dd.StatusProxy();
3537 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3538 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3540 this.dragging = false;
3543 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3545 * @cfg {String} dropAllowed
3546 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3548 dropAllowed : "x-dd-drop-ok",
3550 * @cfg {String} dropNotAllowed
3551 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3553 dropNotAllowed : "x-dd-drop-nodrop",
3556 * Returns the data object associated with this drag source
3557 * @return {Object} data An object containing arbitrary data
3559 getDragData : function(e){
3560 return this.dragData;
3564 onDragEnter : function(e, id){
3565 var target = Roo.dd.DragDropMgr.getDDById(id);
3566 this.cachedTarget = target;
3567 if(this.beforeDragEnter(target, e, id) !== false){
3568 if(target.isNotifyTarget){
3569 var status = target.notifyEnter(this, e, this.dragData);
3570 this.proxy.setStatus(status);
3572 this.proxy.setStatus(this.dropAllowed);
3575 if(this.afterDragEnter){
3577 * An empty function by default, but provided so that you can perform a custom action
3578 * when the dragged item enters the drop target by providing an implementation.
3579 * @param {Roo.dd.DragDrop} target The drop target
3580 * @param {Event} e The event object
3581 * @param {String} id The id of the dragged element
3582 * @method afterDragEnter
3584 this.afterDragEnter(target, e, id);
3590 * An empty function by default, but provided so that you can perform a custom action
3591 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3592 * @param {Roo.dd.DragDrop} target The drop target
3593 * @param {Event} e The event object
3594 * @param {String} id The id of the dragged element
3595 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3597 beforeDragEnter : function(target, e, id){
3602 alignElWithMouse: function() {
3603 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3608 onDragOver : function(e, id){
3609 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3610 if(this.beforeDragOver(target, e, id) !== false){
3611 if(target.isNotifyTarget){
3612 var status = target.notifyOver(this, e, this.dragData);
3613 this.proxy.setStatus(status);
3616 if(this.afterDragOver){
3618 * An empty function by default, but provided so that you can perform a custom action
3619 * while the dragged item is over the drop target by providing an implementation.
3620 * @param {Roo.dd.DragDrop} target The drop target
3621 * @param {Event} e The event object
3622 * @param {String} id The id of the dragged element
3623 * @method afterDragOver
3625 this.afterDragOver(target, e, id);
3631 * An empty function by default, but provided so that you can perform a custom action
3632 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3633 * @param {Roo.dd.DragDrop} target The drop target
3634 * @param {Event} e The event object
3635 * @param {String} id The id of the dragged element
3636 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3638 beforeDragOver : function(target, e, id){
3643 onDragOut : function(e, id){
3644 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3645 if(this.beforeDragOut(target, e, id) !== false){
3646 if(target.isNotifyTarget){
3647 target.notifyOut(this, e, this.dragData);
3650 if(this.afterDragOut){
3652 * An empty function by default, but provided so that you can perform a custom action
3653 * after the dragged item is dragged out of the target without dropping.
3654 * @param {Roo.dd.DragDrop} target The drop target
3655 * @param {Event} e The event object
3656 * @param {String} id The id of the dragged element
3657 * @method afterDragOut
3659 this.afterDragOut(target, e, id);
3662 this.cachedTarget = null;
3666 * An empty function by default, but provided so that you can perform a custom action before the dragged
3667 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3668 * @param {Roo.dd.DragDrop} target The drop target
3669 * @param {Event} e The event object
3670 * @param {String} id The id of the dragged element
3671 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3673 beforeDragOut : function(target, e, id){
3678 onDragDrop : function(e, id){
3679 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3680 if(this.beforeDragDrop(target, e, id) !== false){
3681 if(target.isNotifyTarget){
3682 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3683 this.onValidDrop(target, e, id);
3685 this.onInvalidDrop(target, e, id);
3688 this.onValidDrop(target, e, id);
3691 if(this.afterDragDrop){
3693 * An empty function by default, but provided so that you can perform a custom action
3694 * after a valid drag drop has occurred by providing an implementation.
3695 * @param {Roo.dd.DragDrop} target The drop target
3696 * @param {Event} e The event object
3697 * @param {String} id The id of the dropped element
3698 * @method afterDragDrop
3700 this.afterDragDrop(target, e, id);
3703 delete this.cachedTarget;
3707 * An empty function by default, but provided so that you can perform a custom action before the dragged
3708 * item is dropped onto the target and optionally cancel the onDragDrop.
3709 * @param {Roo.dd.DragDrop} target The drop target
3710 * @param {Event} e The event object
3711 * @param {String} id The id of the dragged element
3712 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3714 beforeDragDrop : function(target, e, id){
3719 onValidDrop : function(target, e, id){
3721 if(this.afterValidDrop){
3723 * An empty function by default, but provided so that you can perform a custom action
3724 * after a valid drop has occurred by providing an implementation.
3725 * @param {Object} target The target DD
3726 * @param {Event} e The event object
3727 * @param {String} id The id of the dropped element
3728 * @method afterInvalidDrop
3730 this.afterValidDrop(target, e, id);
3735 getRepairXY : function(e, data){
3736 return this.el.getXY();
3740 onInvalidDrop : function(target, e, id){
3741 this.beforeInvalidDrop(target, e, id);
3742 if(this.cachedTarget){
3743 if(this.cachedTarget.isNotifyTarget){
3744 this.cachedTarget.notifyOut(this, e, this.dragData);
3746 this.cacheTarget = null;
3748 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3750 if(this.afterInvalidDrop){
3752 * An empty function by default, but provided so that you can perform a custom action
3753 * after an invalid drop has occurred by providing an implementation.
3754 * @param {Event} e The event object
3755 * @param {String} id The id of the dropped element
3756 * @method afterInvalidDrop
3758 this.afterInvalidDrop(e, id);
3763 afterRepair : function(){
3765 this.el.highlight(this.hlColor || "c3daf9");
3767 this.dragging = false;
3771 * An empty function by default, but provided so that you can perform a custom action after an invalid
3772 * drop has occurred.
3773 * @param {Roo.dd.DragDrop} target The drop target
3774 * @param {Event} e The event object
3775 * @param {String} id The id of the dragged element
3776 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3778 beforeInvalidDrop : function(target, e, id){
3783 handleMouseDown : function(e){
3787 var data = this.getDragData(e);
3788 if(data && this.onBeforeDrag(data, e) !== false){
3789 this.dragData = data;
3791 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3796 * An empty function by default, but provided so that you can perform a custom action before the initial
3797 * drag event begins and optionally cancel it.
3798 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3799 * @param {Event} e The event object
3800 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3802 onBeforeDrag : function(data, e){
3807 * An empty function by default, but provided so that you can perform a custom action once the initial
3808 * drag event has begun. The drag cannot be canceled from this function.
3809 * @param {Number} x The x position of the click on the dragged object
3810 * @param {Number} y The y position of the click on the dragged object
3812 onStartDrag : Roo.emptyFn,
3814 // private - YUI override
3815 startDrag : function(x, y){
3817 this.dragging = true;
3818 this.proxy.update("");
3819 this.onInitDrag(x, y);
3824 onInitDrag : function(x, y){
3825 var clone = this.el.dom.cloneNode(true);
3826 clone.id = Roo.id(); // prevent duplicate ids
3827 this.proxy.update(clone);
3828 this.onStartDrag(x, y);
3833 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3834 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3836 getProxy : function(){
3841 * Hides the drag source's {@link Roo.dd.StatusProxy}
3843 hideProxy : function(){
3845 this.proxy.reset(true);
3846 this.dragging = false;
3850 triggerCacheRefresh : function(){
3851 Roo.dd.DDM.refreshCache(this.groups);
3854 // private - override to prevent hiding
3855 b4EndDrag: function(e) {
3858 // private - override to prevent moving
3859 endDrag : function(e){
3860 this.onEndDrag(this.dragData, e);
3864 onEndDrag : function(data, e){
3867 // private - pin to cursor
3868 autoOffset : function(x, y) {
3869 this.setDelta(-12, -20);
3873 * Ext JS Library 1.1.1
3874 * Copyright(c) 2006-2007, Ext JS, LLC.
3876 * Originally Released Under LGPL - original licence link has changed is not relivant.
3879 * <script type="text/javascript">
3884 * @class Roo.dd.DropTarget
3885 * @extends Roo.dd.DDTarget
3886 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3887 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3889 * @param {String/HTMLElement/Element} el The container element
3890 * @param {Object} config
3892 Roo.dd.DropTarget = function(el, config){
3893 this.el = Roo.get(el);
3895 var listeners = false; ;
3896 if (config && config.listeners) {
3897 listeners= config.listeners;
3898 delete config.listeners;
3900 Roo.apply(this, config);
3902 if(this.containerScroll){
3903 Roo.dd.ScrollManager.register(this.el);
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
3966 Roo.dd.DropTarget.superclass.constructor.call( this,
3968 this.ddGroup || this.group,
3971 listeners : listeners || {}
3979 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3981 * @cfg {String} overClass
3982 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3985 * @cfg {String} ddGroup
3986 * The drag drop group to handle drop events for
3990 * @cfg {String} dropAllowed
3991 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3993 dropAllowed : "x-dd-drop-ok",
3995 * @cfg {String} dropNotAllowed
3996 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3998 dropNotAllowed : "x-dd-drop-nodrop",
4000 * @cfg {boolean} success
4001 * set this after drop listener..
4005 * @cfg {boolean|String} valid true/false or string (add/sub/ok/nodrop)
4006 * if the drop point is valid for over/enter..
4013 isNotifyTarget : true,
4018 notifyEnter : function(dd, e, data){
4020 this.fireEvent('enter', dd, e, data);
4022 this.el.addClass(this.overClass);
4024 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4025 this.valid ? this.dropAllowed : this.dropNotAllowed
4032 notifyOver : function(dd, e, data){
4034 this.fireEvent('over', dd, e, data);
4035 return typeof(this.valid) == 'string' ? 'x-dd-drop-' + this.valid : (
4036 this.valid ? this.dropAllowed : this.dropNotAllowed
4043 notifyOut : function(dd, e, data){
4044 this.fireEvent('out', dd, e, data);
4046 this.el.removeClass(this.overClass);
4053 notifyDrop : function(dd, e, data){
4054 this.success = false;
4055 this.fireEvent('drop', dd, e, data);
4056 return this.success;
4060 * Ext JS Library 1.1.1
4061 * Copyright(c) 2006-2007, Ext JS, LLC.
4063 * Originally Released Under LGPL - original licence link has changed is not relivant.
4066 * <script type="text/javascript">
4071 * @class Roo.dd.DragZone
4072 * @extends Roo.dd.DragSource
4073 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4074 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4076 * @param {String/HTMLElement/Element} el The container element
4077 * @param {Object} config
4079 Roo.dd.DragZone = function(el, config){
4080 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4081 if(this.containerScroll){
4082 Roo.dd.ScrollManager.register(this.el);
4086 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4088 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4089 * for auto scrolling during drag operations.
4092 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4093 * method after a failed drop (defaults to "c3daf9" - light blue)
4097 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4098 * for a valid target to drag based on the mouse down. Override this method
4099 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4100 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4101 * @param {EventObject} e The mouse down event
4102 * @return {Object} The dragData
4104 getDragData : function(e){
4105 return Roo.dd.Registry.getHandleFromEvent(e);
4109 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4110 * this.dragData.ddel
4111 * @param {Number} x The x position of the click on the dragged object
4112 * @param {Number} y The y position of the click on the dragged object
4113 * @return {Boolean} true to continue the drag, false to cancel
4115 onInitDrag : function(x, y){
4116 this.proxy.update(this.dragData.ddel.cloneNode(true));
4117 this.onStartDrag(x, y);
4122 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4124 afterRepair : function(){
4126 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4128 this.dragging = false;
4132 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4133 * the XY of this.dragData.ddel
4134 * @param {EventObject} e The mouse up event
4135 * @return {Array} The xy location (e.g. [100, 200])
4137 getRepairXY : function(e){
4138 return Roo.Element.fly(this.dragData.ddel).getXY();
4142 * Ext JS Library 1.1.1
4143 * Copyright(c) 2006-2007, Ext JS, LLC.
4145 * Originally Released Under LGPL - original licence link has changed is not relivant.
4148 * <script type="text/javascript">
4151 * @class Roo.dd.DropZone
4152 * @extends Roo.dd.DropTarget
4153 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4154 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4156 * @param {String/HTMLElement/Element} el The container element
4157 * @param {Object} config
4159 Roo.dd.DropZone = function(el, config){
4160 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4163 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4165 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4166 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4167 * provide your own custom lookup.
4168 * @param {Event} e The event
4169 * @return {Object} data The custom data
4171 getTargetFromEvent : function(e){
4172 return Roo.dd.Registry.getTargetFromEvent(e);
4176 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4177 * that it has registered. This method has no default implementation and should be overridden to provide
4178 * node-specific processing if necessary.
4179 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4180 * {@link #getTargetFromEvent} for this node)
4181 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4182 * @param {Event} e The event
4183 * @param {Object} data An object containing arbitrary data supplied by the drag source
4185 onNodeEnter : function(n, dd, e, data){
4190 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4191 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4192 * overridden to provide the proper feedback.
4193 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4194 * {@link #getTargetFromEvent} for this node)
4195 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4196 * @param {Event} e The event
4197 * @param {Object} data An object containing arbitrary data supplied by the drag source
4198 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4199 * underlying {@link Roo.dd.StatusProxy} can be updated
4201 onNodeOver : function(n, dd, e, data){
4202 return this.dropAllowed;
4206 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4207 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4208 * node-specific processing if necessary.
4209 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4210 * {@link #getTargetFromEvent} for this node)
4211 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4212 * @param {Event} e The event
4213 * @param {Object} data An object containing arbitrary data supplied by the drag source
4215 onNodeOut : function(n, dd, e, data){
4220 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4221 * the drop node. The default implementation returns false, so it should be overridden to provide the
4222 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4223 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4224 * {@link #getTargetFromEvent} for this node)
4225 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4226 * @param {Event} e The event
4227 * @param {Object} data An object containing arbitrary data supplied by the drag source
4228 * @return {Boolean} True if the drop was valid, else false
4230 onNodeDrop : function(n, dd, e, data){
4235 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4236 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4237 * it should be overridden to provide the proper feedback if necessary.
4238 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4239 * @param {Event} e The event
4240 * @param {Object} data An object containing arbitrary data supplied by the drag source
4241 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4242 * underlying {@link Roo.dd.StatusProxy} can be updated
4244 onContainerOver : function(dd, e, data){
4245 return this.dropNotAllowed;
4249 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4250 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4251 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4252 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4253 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4254 * @param {Event} e The event
4255 * @param {Object} data An object containing arbitrary data supplied by the drag source
4256 * @return {Boolean} True if the drop was valid, else false
4258 onContainerDrop : function(dd, e, data){
4263 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4264 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4265 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4266 * you should override this method and provide a custom implementation.
4267 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4268 * @param {Event} e The event
4269 * @param {Object} data An object containing arbitrary data supplied by the drag source
4270 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4271 * underlying {@link Roo.dd.StatusProxy} can be updated
4273 notifyEnter : function(dd, e, data){
4274 return this.dropNotAllowed;
4278 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4279 * This method will be called on every mouse movement while the drag source is over the drop zone.
4280 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4281 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4282 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4283 * registered node, it will call {@link #onContainerOver}.
4284 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4285 * @param {Event} e The event
4286 * @param {Object} data An object containing arbitrary data supplied by the drag source
4287 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4288 * underlying {@link Roo.dd.StatusProxy} can be updated
4290 notifyOver : function(dd, e, data){
4291 var n = this.getTargetFromEvent(e);
4292 if(!n){ // not over valid drop target
4293 if(this.lastOverNode){
4294 this.onNodeOut(this.lastOverNode, dd, e, data);
4295 this.lastOverNode = null;
4297 return this.onContainerOver(dd, e, data);
4299 if(this.lastOverNode != n){
4300 if(this.lastOverNode){
4301 this.onNodeOut(this.lastOverNode, dd, e, data);
4303 this.onNodeEnter(n, dd, e, data);
4304 this.lastOverNode = n;
4306 return this.onNodeOver(n, dd, e, data);
4310 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4311 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4312 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4313 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4314 * @param {Event} e The event
4315 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4317 notifyOut : function(dd, e, data){
4318 if(this.lastOverNode){
4319 this.onNodeOut(this.lastOverNode, dd, e, data);
4320 this.lastOverNode = null;
4325 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4326 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4327 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4328 * otherwise it will call {@link #onContainerDrop}.
4329 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4330 * @param {Event} e The event
4331 * @param {Object} data An object containing arbitrary data supplied by the drag source
4332 * @return {Boolean} True if the drop was valid, else false
4334 notifyDrop : function(dd, e, data){
4335 if(this.lastOverNode){
4336 this.onNodeOut(this.lastOverNode, dd, e, data);
4337 this.lastOverNode = null;
4339 var n = this.getTargetFromEvent(e);
4341 this.onNodeDrop(n, dd, e, data) :
4342 this.onContainerDrop(dd, e, data);
4346 triggerCacheRefresh : function(){
4347 Roo.dd.DDM.refreshCache(this.groups);
4351 * Ext JS Library 1.1.1
4352 * Copyright(c) 2006-2007, Ext JS, LLC.
4354 * Originally Released Under LGPL - original licence link has changed is not relivant.
4357 * <script type="text/javascript">
4362 * @class Roo.data.SortTypes
4364 * Defines the default sorting (casting?) comparison functions used when sorting data.
4366 Roo.data.SortTypes = {
4368 * Default sort that does nothing
4369 * @param {Mixed} s The value being converted
4370 * @return {Mixed} The comparison value
4377 * The regular expression used to strip tags
4381 stripTagsRE : /<\/?[^>]+>/gi,
4384 * Strips all HTML tags to sort on text only
4385 * @param {Mixed} s The value being converted
4386 * @return {String} The comparison value
4388 asText : function(s){
4389 return String(s).replace(this.stripTagsRE, "");
4393 * Strips all HTML tags to sort on text only - Case insensitive
4394 * @param {Mixed} s The value being converted
4395 * @return {String} The comparison value
4397 asUCText : function(s){
4398 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4402 * Case insensitive string
4403 * @param {Mixed} s The value being converted
4404 * @return {String} The comparison value
4406 asUCString : function(s) {
4407 return String(s).toUpperCase();
4412 * @param {Mixed} s The value being converted
4413 * @return {Number} The comparison value
4415 asDate : function(s) {
4419 if(s instanceof Date){
4422 return Date.parse(String(s));
4427 * @param {Mixed} s The value being converted
4428 * @return {Float} The comparison value
4430 asFloat : function(s) {
4431 var val = parseFloat(String(s).replace(/,/g, ""));
4432 if(isNaN(val)) val = 0;
4438 * @param {Mixed} s The value being converted
4439 * @return {Number} The comparison value
4441 asInt : function(s) {
4442 var val = parseInt(String(s).replace(/,/g, ""));
4443 if(isNaN(val)) val = 0;
4448 * Ext JS Library 1.1.1
4449 * Copyright(c) 2006-2007, Ext JS, LLC.
4451 * Originally Released Under LGPL - original licence link has changed is not relivant.
4454 * <script type="text/javascript">
4458 * @class Roo.data.Record
4459 * Instances of this class encapsulate both record <em>definition</em> information, and record
4460 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4461 * to access Records cached in an {@link Roo.data.Store} object.<br>
4463 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4464 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4467 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4469 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4470 * {@link #create}. The parameters are the same.
4471 * @param {Array} data An associative Array of data values keyed by the field name.
4472 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4473 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4474 * not specified an integer id is generated.
4476 Roo.data.Record = function(data, id){
4477 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4482 * Generate a constructor for a specific record layout.
4483 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4484 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4485 * Each field definition object may contain the following properties: <ul>
4486 * <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,
4487 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4488 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4489 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4490 * is being used, then this is a string containing the javascript expression to reference the data relative to
4491 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4492 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4493 * this may be omitted.</p></li>
4494 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4495 * <ul><li>auto (Default, implies no conversion)</li>
4500 * <li>date</li></ul></p></li>
4501 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4502 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4503 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4504 * by the Reader into an object that will be stored in the Record. It is passed the
4505 * following parameters:<ul>
4506 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4508 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4510 * <br>usage:<br><pre><code>
4511 var TopicRecord = Roo.data.Record.create(
4512 {name: 'title', mapping: 'topic_title'},
4513 {name: 'author', mapping: 'username'},
4514 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4515 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4516 {name: 'lastPoster', mapping: 'user2'},
4517 {name: 'excerpt', mapping: 'post_text'}
4520 var myNewRecord = new TopicRecord({
4521 title: 'Do my job please',
4524 lastPost: new Date(),
4525 lastPoster: 'Animal',
4526 excerpt: 'No way dude!'
4528 myStore.add(myNewRecord);
4533 Roo.data.Record.create = function(o){
4535 f.superclass.constructor.apply(this, arguments);
4537 Roo.extend(f, Roo.data.Record);
4538 var p = f.prototype;
4539 p.fields = new Roo.util.MixedCollection(false, function(field){
4542 for(var i = 0, len = o.length; i < len; i++){
4543 p.fields.add(new Roo.data.Field(o[i]));
4545 f.getField = function(name){
4546 return p.fields.get(name);
4551 Roo.data.Record.AUTO_ID = 1000;
4552 Roo.data.Record.EDIT = 'edit';
4553 Roo.data.Record.REJECT = 'reject';
4554 Roo.data.Record.COMMIT = 'commit';
4556 Roo.data.Record.prototype = {
4558 * Readonly flag - true if this record has been modified.
4567 join : function(store){
4572 * Set the named field to the specified value.
4573 * @param {String} name The name of the field to set.
4574 * @param {Object} value The value to set the field to.
4576 set : function(name, value){
4577 if(this.data[name] == value){
4584 if(typeof this.modified[name] == 'undefined'){
4585 this.modified[name] = this.data[name];
4587 this.data[name] = value;
4589 this.store.afterEdit(this);
4594 * Get the value of the named field.
4595 * @param {String} name The name of the field to get the value of.
4596 * @return {Object} The value of the field.
4598 get : function(name){
4599 return this.data[name];
4603 beginEdit : function(){
4604 this.editing = true;
4609 cancelEdit : function(){
4610 this.editing = false;
4611 delete this.modified;
4615 endEdit : function(){
4616 this.editing = false;
4617 if(this.dirty && this.store){
4618 this.store.afterEdit(this);
4623 * Usually called by the {@link Roo.data.Store} which owns the Record.
4624 * Rejects all changes made to the Record since either creation, or the last commit operation.
4625 * Modified fields are reverted to their original values.
4627 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4628 * of reject operations.
4630 reject : function(){
4631 var m = this.modified;
4633 if(typeof m[n] != "function"){
4634 this.data[n] = m[n];
4638 delete this.modified;
4639 this.editing = false;
4641 this.store.afterReject(this);
4646 * Usually called by the {@link Roo.data.Store} which owns the Record.
4647 * Commits all changes made to the Record since either creation, or the last commit operation.
4649 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4650 * of commit operations.
4652 commit : function(){
4654 delete this.modified;
4655 this.editing = false;
4657 this.store.afterCommit(this);
4662 hasError : function(){
4663 return this.error != null;
4667 clearError : function(){
4672 * Creates a copy of this record.
4673 * @param {String} id (optional) A new record id if you don't want to use this record's id
4676 copy : function(newId) {
4677 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4681 * Ext JS Library 1.1.1
4682 * Copyright(c) 2006-2007, Ext JS, LLC.
4684 * Originally Released Under LGPL - original licence link has changed is not relivant.
4687 * <script type="text/javascript">
4693 * @class Roo.data.Store
4694 * @extends Roo.util.Observable
4695 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4696 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4698 * 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
4699 * has no knowledge of the format of the data returned by the Proxy.<br>
4701 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4702 * instances from the data object. These records are cached and made available through accessor functions.
4704 * Creates a new Store.
4705 * @param {Object} config A config object containing the objects needed for the Store to access data,
4706 * and read the data into Records.
4708 Roo.data.Store = function(config){
4709 this.data = new Roo.util.MixedCollection(false);
4710 this.data.getKey = function(o){
4713 this.baseParams = {};
4722 if(config && config.data){
4723 this.inlineData = config.data;
4727 Roo.apply(this, config);
4729 if(this.reader){ // reader passed
4730 this.reader = Roo.factory(this.reader, Roo.data);
4731 this.reader.xmodule = this.xmodule || false;
4732 if(!this.recordType){
4733 this.recordType = this.reader.recordType;
4735 if(this.reader.onMetaChange){
4736 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4740 if(this.recordType){
4741 this.fields = this.recordType.prototype.fields;
4747 * @event datachanged
4748 * Fires when the data cache has changed, and a widget which is using this Store
4749 * as a Record cache should refresh its view.
4750 * @param {Store} this
4755 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4756 * @param {Store} this
4757 * @param {Object} meta The JSON metadata
4762 * Fires when Records have been added to the Store
4763 * @param {Store} this
4764 * @param {Roo.data.Record[]} records The array of Records added
4765 * @param {Number} index The index at which the record(s) were added
4770 * Fires when a Record has been removed from the Store
4771 * @param {Store} this
4772 * @param {Roo.data.Record} record The Record that was removed
4773 * @param {Number} index The index at which the record was removed
4778 * Fires when a Record has been updated
4779 * @param {Store} this
4780 * @param {Roo.data.Record} record The Record that was updated
4781 * @param {String} operation The update operation being performed. Value may be one of:
4783 Roo.data.Record.EDIT
4784 Roo.data.Record.REJECT
4785 Roo.data.Record.COMMIT
4791 * Fires when the data cache has been cleared.
4792 * @param {Store} this
4797 * Fires before a request is made for a new data object. If the beforeload handler returns false
4798 * the load action will be canceled.
4799 * @param {Store} this
4800 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4805 * Fires after a new set of Records has been loaded.
4806 * @param {Store} this
4807 * @param {Roo.data.Record[]} records The Records that were loaded
4808 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4812 * @event loadexception
4813 * Fires if an exception occurs in the Proxy during loading.
4814 * Called with the signature of the Proxy's "loadexception" event.
4815 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4818 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4819 * @param {Object} load options
4820 * @param {Object} jsonData from your request (normally this contains the Exception)
4822 loadexception : true
4826 this.proxy = Roo.factory(this.proxy, Roo.data);
4827 this.proxy.xmodule = this.xmodule || false;
4828 this.relayEvents(this.proxy, ["loadexception"]);
4830 this.sortToggle = {};
4832 Roo.data.Store.superclass.constructor.call(this);
4834 if(this.inlineData){
4835 this.loadData(this.inlineData);
4836 delete this.inlineData;
4839 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4841 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4842 * without a remote query - used by combo/forms at present.
4846 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4849 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4852 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4853 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4856 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4857 * on any HTTP request
4860 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4863 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4864 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4869 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4870 * loaded or when a record is removed. (defaults to false).
4872 pruneModifiedRecords : false,
4878 * Add Records to the Store and fires the add event.
4879 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4881 add : function(records){
4882 records = [].concat(records);
4883 for(var i = 0, len = records.length; i < len; i++){
4884 records[i].join(this);
4886 var index = this.data.length;
4887 this.data.addAll(records);
4888 this.fireEvent("add", this, records, index);
4892 * Remove a Record from the Store and fires the remove event.
4893 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4895 remove : function(record){
4896 var index = this.data.indexOf(record);
4897 this.data.removeAt(index);
4898 if(this.pruneModifiedRecords){
4899 this.modified.remove(record);
4901 this.fireEvent("remove", this, record, index);
4905 * Remove all Records from the Store and fires the clear event.
4907 removeAll : function(){
4909 if(this.pruneModifiedRecords){
4912 this.fireEvent("clear", this);
4916 * Inserts Records to the Store at the given index and fires the add event.
4917 * @param {Number} index The start index at which to insert the passed Records.
4918 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4920 insert : function(index, records){
4921 records = [].concat(records);
4922 for(var i = 0, len = records.length; i < len; i++){
4923 this.data.insert(index, records[i]);
4924 records[i].join(this);
4926 this.fireEvent("add", this, records, index);
4930 * Get the index within the cache of the passed Record.
4931 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4932 * @return {Number} The index of the passed Record. Returns -1 if not found.
4934 indexOf : function(record){
4935 return this.data.indexOf(record);
4939 * Get the index within the cache of the Record with the passed id.
4940 * @param {String} id The id of the Record to find.
4941 * @return {Number} The index of the Record. Returns -1 if not found.
4943 indexOfId : function(id){
4944 return this.data.indexOfKey(id);
4948 * Get the Record with the specified id.
4949 * @param {String} id The id of the Record to find.
4950 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4952 getById : function(id){
4953 return this.data.key(id);
4957 * Get the Record at the specified index.
4958 * @param {Number} index The index of the Record to find.
4959 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4961 getAt : function(index){
4962 return this.data.itemAt(index);
4966 * Returns a range of Records between specified indices.
4967 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4968 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4969 * @return {Roo.data.Record[]} An array of Records
4971 getRange : function(start, end){
4972 return this.data.getRange(start, end);
4976 storeOptions : function(o){
4977 o = Roo.apply({}, o);
4980 this.lastOptions = o;
4984 * Loads the Record cache from the configured Proxy using the configured Reader.
4986 * If using remote paging, then the first load call must specify the <em>start</em>
4987 * and <em>limit</em> properties in the options.params property to establish the initial
4988 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4990 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4991 * and this call will return before the new data has been loaded. Perform any post-processing
4992 * in a callback function, or in a "load" event handler.</strong>
4994 * @param {Object} options An object containing properties which control loading options:<ul>
4995 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4996 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4997 * passed the following arguments:<ul>
4998 * <li>r : Roo.data.Record[]</li>
4999 * <li>options: Options object from the load call</li>
5000 * <li>success: Boolean success indicator</li></ul></li>
5001 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
5002 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
5005 load : function(options){
5006 options = options || {};
5007 if(this.fireEvent("beforeload", this, options) !== false){
5008 this.storeOptions(options);
5009 var p = Roo.apply(options.params || {}, this.baseParams);
5010 // if meta was not loaded from remote source.. try requesting it.
5011 if (!this.reader.metaFromRemote) {
5014 if(this.sortInfo && this.remoteSort){
5015 var pn = this.paramNames;
5016 p[pn["sort"]] = this.sortInfo.field;
5017 p[pn["dir"]] = this.sortInfo.direction;
5019 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5024 * Reloads the Record cache from the configured Proxy using the configured Reader and
5025 * the options from the last load operation performed.
5026 * @param {Object} options (optional) An object containing properties which may override the options
5027 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5028 * the most recently used options are reused).
5030 reload : function(options){
5031 this.load(Roo.applyIf(options||{}, this.lastOptions));
5035 // Called as a callback by the Reader during a load operation.
5036 loadRecords : function(o, options, success){
5037 if(!o || success === false){
5038 if(success !== false){
5039 this.fireEvent("load", this, [], options);
5041 if(options.callback){
5042 options.callback.call(options.scope || this, [], options, false);
5046 // if data returned failure - throw an exception.
5047 if (o.success === false) {
5048 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5051 var r = o.records, t = o.totalRecords || r.length;
5052 if(!options || options.add !== true){
5053 if(this.pruneModifiedRecords){
5056 for(var i = 0, len = r.length; i < len; i++){
5060 this.data = this.snapshot;
5061 delete this.snapshot;
5064 this.data.addAll(r);
5065 this.totalLength = t;
5067 this.fireEvent("datachanged", this);
5069 this.totalLength = Math.max(t, this.data.length+r.length);
5072 this.fireEvent("load", this, r, options);
5073 if(options.callback){
5074 options.callback.call(options.scope || this, r, options, true);
5079 * Loads data from a passed data block. A Reader which understands the format of the data
5080 * must have been configured in the constructor.
5081 * @param {Object} data The data block from which to read the Records. The format of the data expected
5082 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5083 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5085 loadData : function(o, append){
5086 var r = this.reader.readRecords(o);
5087 this.loadRecords(r, {add: append}, true);
5091 * Gets the number of cached records.
5093 * <em>If using paging, this may not be the total size of the dataset. If the data object
5094 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5095 * the data set size</em>
5097 getCount : function(){
5098 return this.data.length || 0;
5102 * Gets the total number of records in the dataset as returned by the server.
5104 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5105 * the dataset size</em>
5107 getTotalCount : function(){
5108 return this.totalLength || 0;
5112 * Returns the sort state of the Store as an object with two properties:
5114 field {String} The name of the field by which the Records are sorted
5115 direction {String} The sort order, "ASC" or "DESC"
5118 getSortState : function(){
5119 return this.sortInfo;
5123 applySort : function(){
5124 if(this.sortInfo && !this.remoteSort){
5125 var s = this.sortInfo, f = s.field;
5126 var st = this.fields.get(f).sortType;
5127 var fn = function(r1, r2){
5128 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5129 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5131 this.data.sort(s.direction, fn);
5132 if(this.snapshot && this.snapshot != this.data){
5133 this.snapshot.sort(s.direction, fn);
5139 * Sets the default sort column and order to be used by the next load operation.
5140 * @param {String} fieldName The name of the field to sort by.
5141 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5143 setDefaultSort : function(field, dir){
5144 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5149 * If remote sorting is used, the sort is performed on the server, and the cache is
5150 * reloaded. If local sorting is used, the cache is sorted internally.
5151 * @param {String} fieldName The name of the field to sort by.
5152 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5154 sort : function(fieldName, dir){
5155 var f = this.fields.get(fieldName);
5157 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5158 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5163 this.sortToggle[f.name] = dir;
5164 this.sortInfo = {field: f.name, direction: dir};
5165 if(!this.remoteSort){
5167 this.fireEvent("datachanged", this);
5169 this.load(this.lastOptions);
5174 * Calls the specified function for each of the Records in the cache.
5175 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5176 * Returning <em>false</em> aborts and exits the iteration.
5177 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5179 each : function(fn, scope){
5180 this.data.each(fn, scope);
5184 * Gets all records modified since the last commit. Modified records are persisted across load operations
5185 * (e.g., during paging).
5186 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5188 getModifiedRecords : function(){
5189 return this.modified;
5193 createFilterFn : function(property, value, anyMatch){
5194 if(!value.exec){ // not a regex
5195 value = String(value);
5196 if(value.length == 0){
5199 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5202 return value.test(r.data[property]);
5207 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5208 * @param {String} property A field on your records
5209 * @param {Number} start The record index to start at (defaults to 0)
5210 * @param {Number} end The last record index to include (defaults to length - 1)
5211 * @return {Number} The sum
5213 sum : function(property, start, end){
5214 var rs = this.data.items, v = 0;
5216 end = (end || end === 0) ? end : rs.length-1;
5218 for(var i = start; i <= end; i++){
5219 v += (rs[i].data[property] || 0);
5225 * Filter the records by a specified property.
5226 * @param {String} field A field on your records
5227 * @param {String/RegExp} value Either a string that the field
5228 * should start with or a RegExp to test against the field
5229 * @param {Boolean} anyMatch True to match any part not just the beginning
5231 filter : function(property, value, anyMatch){
5232 var fn = this.createFilterFn(property, value, anyMatch);
5233 return fn ? this.filterBy(fn) : this.clearFilter();
5237 * Filter by a function. The specified function will be called with each
5238 * record in this data source. If the function returns true the record is included,
5239 * otherwise it is filtered.
5240 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5241 * @param {Object} scope (optional) The scope of the function (defaults to this)
5243 filterBy : function(fn, scope){
5244 this.snapshot = this.snapshot || this.data;
5245 this.data = this.queryBy(fn, scope||this);
5246 this.fireEvent("datachanged", this);
5250 * Query the records by a specified property.
5251 * @param {String} field A field on your records
5252 * @param {String/RegExp} value Either a string that the field
5253 * should start with or a RegExp to test against the field
5254 * @param {Boolean} anyMatch True to match any part not just the beginning
5255 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5257 query : function(property, value, anyMatch){
5258 var fn = this.createFilterFn(property, value, anyMatch);
5259 return fn ? this.queryBy(fn) : this.data.clone();
5263 * Query by a function. The specified function will be called with each
5264 * record in this data source. If the function returns true the record is included
5266 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5267 * @param {Object} scope (optional) The scope of the function (defaults to this)
5268 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5270 queryBy : function(fn, scope){
5271 var data = this.snapshot || this.data;
5272 return data.filterBy(fn, scope||this);
5276 * Collects unique values for a particular dataIndex from this store.
5277 * @param {String} dataIndex The property to collect
5278 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5279 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5280 * @return {Array} An array of the unique values
5282 collect : function(dataIndex, allowNull, bypassFilter){
5283 var d = (bypassFilter === true && this.snapshot) ?
5284 this.snapshot.items : this.data.items;
5285 var v, sv, r = [], l = {};
5286 for(var i = 0, len = d.length; i < len; i++){
5287 v = d[i].data[dataIndex];
5289 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5298 * Revert to a view of the Record cache with no filtering applied.
5299 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5301 clearFilter : function(suppressEvent){
5302 if(this.snapshot && this.snapshot != this.data){
5303 this.data = this.snapshot;
5304 delete this.snapshot;
5305 if(suppressEvent !== true){
5306 this.fireEvent("datachanged", this);
5312 afterEdit : function(record){
5313 if(this.modified.indexOf(record) == -1){
5314 this.modified.push(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5320 afterReject : function(record){
5321 this.modified.remove(record);
5322 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5326 afterCommit : function(record){
5327 this.modified.remove(record);
5328 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5332 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5333 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5335 commitChanges : function(){
5336 var m = this.modified.slice(0);
5338 for(var i = 0, len = m.length; i < len; i++){
5344 * Cancel outstanding changes on all changed records.
5346 rejectChanges : function(){
5347 var m = this.modified.slice(0);
5349 for(var i = 0, len = m.length; i < len; i++){
5354 onMetaChange : function(meta, rtype, o){
5355 this.recordType = rtype;
5356 this.fields = rtype.prototype.fields;
5357 delete this.snapshot;
5358 this.sortInfo = meta.sortInfo || this.sortInfo;
5360 this.fireEvent('metachange', this, this.reader.meta);
5364 * Ext JS Library 1.1.1
5365 * Copyright(c) 2006-2007, Ext JS, LLC.
5367 * Originally Released Under LGPL - original licence link has changed is not relivant.
5370 * <script type="text/javascript">
5374 * @class Roo.data.SimpleStore
5375 * @extends Roo.data.Store
5376 * Small helper class to make creating Stores from Array data easier.
5377 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5378 * @cfg {Array} fields An array of field definition objects, or field name strings.
5379 * @cfg {Array} data The multi-dimensional array of data
5381 * @param {Object} config
5383 Roo.data.SimpleStore = function(config){
5384 Roo.data.SimpleStore.superclass.constructor.call(this, {
5386 reader: new Roo.data.ArrayReader({
5389 Roo.data.Record.create(config.fields)
5391 proxy : new Roo.data.MemoryProxy(config.data)
5395 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5397 * Ext JS Library 1.1.1
5398 * Copyright(c) 2006-2007, Ext JS, LLC.
5400 * Originally Released Under LGPL - original licence link has changed is not relivant.
5403 * <script type="text/javascript">
5408 * @extends Roo.data.Store
5409 * @class Roo.data.JsonStore
5410 * Small helper class to make creating Stores for JSON data easier. <br/>
5412 var store = new Roo.data.JsonStore({
5413 url: 'get-images.php',
5415 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5418 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5419 * JsonReader and HttpProxy (unless inline data is provided).</b>
5420 * @cfg {Array} fields An array of field definition objects, or field name strings.
5422 * @param {Object} config
5424 Roo.data.JsonStore = function(c){
5425 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5426 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5427 reader: new Roo.data.JsonReader(c, c.fields)
5430 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5432 * Ext JS Library 1.1.1
5433 * Copyright(c) 2006-2007, Ext JS, LLC.
5435 * Originally Released Under LGPL - original licence link has changed is not relivant.
5438 * <script type="text/javascript">
5442 Roo.data.Field = function(config){
5443 if(typeof config == "string"){
5444 config = {name: config};
5446 Roo.apply(this, config);
5452 var st = Roo.data.SortTypes;
5453 // named sortTypes are supported, here we look them up
5454 if(typeof this.sortType == "string"){
5455 this.sortType = st[this.sortType];
5458 // set default sortType for strings and dates
5462 this.sortType = st.asUCString;
5465 this.sortType = st.asDate;
5468 this.sortType = st.none;
5473 var stripRe = /[\$,%]/g;
5475 // prebuilt conversion function for this field, instead of
5476 // switching every time we're reading a value
5478 var cv, dateFormat = this.dateFormat;
5483 cv = function(v){ return v; };
5486 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5490 return v !== undefined && v !== null && v !== '' ?
5491 parseInt(String(v).replace(stripRe, ""), 10) : '';
5496 return v !== undefined && v !== null && v !== '' ?
5497 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5502 cv = function(v){ return v === true || v === "true" || v == 1; };
5509 if(v instanceof Date){
5513 if(dateFormat == "timestamp"){
5514 return new Date(v*1000);
5516 return Date.parseDate(v, dateFormat);
5518 var parsed = Date.parse(v);
5519 return parsed ? new Date(parsed) : null;
5528 Roo.data.Field.prototype = {
5536 * Ext JS Library 1.1.1
5537 * Copyright(c) 2006-2007, Ext JS, LLC.
5539 * Originally Released Under LGPL - original licence link has changed is not relivant.
5542 * <script type="text/javascript">
5545 // Base class for reading structured data from a data source. This class is intended to be
5546 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5549 * @class Roo.data.DataReader
5550 * Base class for reading structured data from a data source. This class is intended to be
5551 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5554 Roo.data.DataReader = function(meta, recordType){
5558 this.recordType = recordType instanceof Array ?
5559 Roo.data.Record.create(recordType) : recordType;
5562 Roo.data.DataReader.prototype = {
5564 * Create an empty record
5565 * @param {Object} data (optional) - overlay some values
5566 * @return {Roo.data.Record} record created.
5568 newRow : function(d) {
5570 this.recordType.prototype.fields.each(function(c) {
5572 case 'int' : da[c.name] = 0; break;
5573 case 'date' : da[c.name] = new Date(); break;
5574 case 'float' : da[c.name] = 0.0; break;
5575 case 'boolean' : da[c.name] = false; break;
5576 default : da[c.name] = ""; break;
5580 return new this.recordType(Roo.apply(da, d));
5585 * Ext JS Library 1.1.1
5586 * Copyright(c) 2006-2007, Ext JS, LLC.
5588 * Originally Released Under LGPL - original licence link has changed is not relivant.
5591 * <script type="text/javascript">
5595 * @class Roo.data.DataProxy
5596 * @extends Roo.data.Observable
5597 * This class is an abstract base class for implementations which provide retrieval of
5598 * unformatted data objects.<br>
5600 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5601 * (of the appropriate type which knows how to parse the data object) to provide a block of
5602 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5604 * Custom implementations must implement the load method as described in
5605 * {@link Roo.data.HttpProxy#load}.
5607 Roo.data.DataProxy = function(){
5611 * Fires before a network request is made to retrieve a data object.
5612 * @param {Object} This DataProxy object.
5613 * @param {Object} params The params parameter to the load function.
5618 * Fires before the load method's callback is called.
5619 * @param {Object} This DataProxy object.
5620 * @param {Object} o The data object.
5621 * @param {Object} arg The callback argument object passed to the load function.
5625 * @event loadexception
5626 * Fires if an Exception occurs during data retrieval.
5627 * @param {Object} This DataProxy object.
5628 * @param {Object} o The data object.
5629 * @param {Object} arg The callback argument object passed to the load function.
5630 * @param {Object} e The Exception.
5632 loadexception : true
5634 Roo.data.DataProxy.superclass.constructor.call(this);
5637 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5640 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5644 * Ext JS Library 1.1.1
5645 * Copyright(c) 2006-2007, Ext JS, LLC.
5647 * Originally Released Under LGPL - original licence link has changed is not relivant.
5650 * <script type="text/javascript">
5653 * @class Roo.data.MemoryProxy
5654 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5655 * to the Reader when its load method is called.
5657 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5659 Roo.data.MemoryProxy = function(data){
5663 Roo.data.MemoryProxy.superclass.constructor.call(this);
5667 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5669 * Load data from the requested source (in this case an in-memory
5670 * data object passed to the constructor), read the data object into
5671 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5672 * process that block using the passed callback.
5673 * @param {Object} params This parameter is not used by the MemoryProxy class.
5674 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5675 * object into a block of Roo.data.Records.
5676 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5677 * The function must be passed <ul>
5678 * <li>The Record block object</li>
5679 * <li>The "arg" argument from the load function</li>
5680 * <li>A boolean success indicator</li>
5682 * @param {Object} scope The scope in which to call the callback
5683 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5685 load : function(params, reader, callback, scope, arg){
5686 params = params || {};
5689 result = reader.readRecords(this.data);
5691 this.fireEvent("loadexception", this, arg, null, e);
5692 callback.call(scope, null, arg, false);
5695 callback.call(scope, result, arg, true);
5699 update : function(params, records){
5704 * Ext JS Library 1.1.1
5705 * Copyright(c) 2006-2007, Ext JS, LLC.
5707 * Originally Released Under LGPL - original licence link has changed is not relivant.
5710 * <script type="text/javascript">
5713 * @class Roo.data.HttpProxy
5714 * @extends Roo.data.DataProxy
5715 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5716 * configured to reference a certain URL.<br><br>
5718 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5719 * from which the running page was served.<br><br>
5721 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5723 * Be aware that to enable the browser to parse an XML document, the server must set
5724 * the Content-Type header in the HTTP response to "text/xml".
5726 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5727 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5728 * will be used to make the request.
5730 Roo.data.HttpProxy = function(conn){
5731 Roo.data.HttpProxy.superclass.constructor.call(this);
5732 // is conn a conn config or a real conn?
5734 this.useAjax = !conn || !conn.events;
5738 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5739 // thse are take from connection...
5742 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5745 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5746 * extra parameters to each request made by this object. (defaults to undefined)
5749 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5750 * to each request made by this object. (defaults to undefined)
5753 * @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)
5756 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5759 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5765 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5769 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5770 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5771 * a finer-grained basis than the DataProxy events.
5773 getConnection : function(){
5774 return this.useAjax ? Roo.Ajax : this.conn;
5778 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5779 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5780 * process that block using the passed callback.
5781 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5782 * for the request to the remote server.
5783 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5784 * object into a block of Roo.data.Records.
5785 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5786 * The function must be passed <ul>
5787 * <li>The Record block object</li>
5788 * <li>The "arg" argument from the load function</li>
5789 * <li>A boolean success indicator</li>
5791 * @param {Object} scope The scope in which to call the callback
5792 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5794 load : function(params, reader, callback, scope, arg){
5795 if(this.fireEvent("beforeload", this, params) !== false){
5797 params : params || {},
5799 callback : callback,
5804 callback : this.loadResponse,
5808 Roo.applyIf(o, this.conn);
5809 if(this.activeRequest){
5810 Roo.Ajax.abort(this.activeRequest);
5812 this.activeRequest = Roo.Ajax.request(o);
5814 this.conn.request(o);
5817 callback.call(scope||this, null, arg, false);
5822 loadResponse : function(o, success, response){
5823 delete this.activeRequest;
5825 this.fireEvent("loadexception", this, o, response);
5826 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5831 result = o.reader.read(response);
5833 this.fireEvent("loadexception", this, o, response, e);
5834 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5838 this.fireEvent("load", this, o, o.request.arg);
5839 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5843 update : function(dataSet){
5848 updateResponse : function(dataSet){
5853 * Ext JS Library 1.1.1
5854 * Copyright(c) 2006-2007, Ext JS, LLC.
5856 * Originally Released Under LGPL - original licence link has changed is not relivant.
5859 * <script type="text/javascript">
5863 * @class Roo.data.ScriptTagProxy
5864 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5865 * other than the originating domain of the running page.<br><br>
5867 * <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
5868 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5870 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5871 * source code that is used as the source inside a <script> tag.<br><br>
5873 * In order for the browser to process the returned data, the server must wrap the data object
5874 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5875 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5876 * depending on whether the callback name was passed:
5879 boolean scriptTag = false;
5880 String cb = request.getParameter("callback");
5883 response.setContentType("text/javascript");
5885 response.setContentType("application/x-json");
5887 Writer out = response.getWriter();
5889 out.write(cb + "(");
5891 out.print(dataBlock.toJsonString());
5898 * @param {Object} config A configuration object.
5900 Roo.data.ScriptTagProxy = function(config){
5901 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5902 Roo.apply(this, config);
5903 this.head = document.getElementsByTagName("head")[0];
5906 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5908 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5910 * @cfg {String} url The URL from which to request the data object.
5913 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5917 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5918 * the server the name of the callback function set up by the load call to process the returned data object.
5919 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5920 * javascript output which calls this named function passing the data object as its only parameter.
5922 callbackParam : "callback",
5924 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5925 * name to the request.
5930 * Load data from the configured URL, read the data object into
5931 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5932 * process that block using the passed callback.
5933 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5934 * for the request to the remote server.
5935 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5936 * object into a block of Roo.data.Records.
5937 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5938 * The function must be passed <ul>
5939 * <li>The Record block object</li>
5940 * <li>The "arg" argument from the load function</li>
5941 * <li>A boolean success indicator</li>
5943 * @param {Object} scope The scope in which to call the callback
5944 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5946 load : function(params, reader, callback, scope, arg){
5947 if(this.fireEvent("beforeload", this, params) !== false){
5949 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5952 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5954 url += "&_dc=" + (new Date().getTime());
5956 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5959 cb : "stcCallback"+transId,
5960 scriptId : "stcScript"+transId,
5964 callback : callback,
5970 window[trans.cb] = function(o){
5971 conn.handleResponse(o, trans);
5974 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5976 if(this.autoAbort !== false){
5980 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5982 var script = document.createElement("script");
5983 script.setAttribute("src", url);
5984 script.setAttribute("type", "text/javascript");
5985 script.setAttribute("id", trans.scriptId);
5986 this.head.appendChild(script);
5990 callback.call(scope||this, null, arg, false);
5995 isLoading : function(){
5996 return this.trans ? true : false;
6000 * Abort the current server request.
6003 if(this.isLoading()){
6004 this.destroyTrans(this.trans);
6009 destroyTrans : function(trans, isLoaded){
6010 this.head.removeChild(document.getElementById(trans.scriptId));
6011 clearTimeout(trans.timeoutId);
6013 window[trans.cb] = undefined;
6015 delete window[trans.cb];
6018 // if hasn't been loaded, wait for load to remove it to prevent script error
6019 window[trans.cb] = function(){
6020 window[trans.cb] = undefined;
6022 delete window[trans.cb];
6029 handleResponse : function(o, trans){
6031 this.destroyTrans(trans, true);
6034 result = trans.reader.readRecords(o);
6036 this.fireEvent("loadexception", this, o, trans.arg, e);
6037 trans.callback.call(trans.scope||window, null, trans.arg, false);
6040 this.fireEvent("load", this, o, trans.arg);
6041 trans.callback.call(trans.scope||window, result, trans.arg, true);
6045 handleFailure : function(trans){
6047 this.destroyTrans(trans, false);
6048 this.fireEvent("loadexception", this, null, trans.arg);
6049 trans.callback.call(trans.scope||window, null, trans.arg, false);
6053 * Ext JS Library 1.1.1
6054 * Copyright(c) 2006-2007, Ext JS, LLC.
6056 * Originally Released Under LGPL - original licence link has changed is not relivant.
6059 * <script type="text/javascript">
6063 * @class Roo.data.JsonReader
6064 * @extends Roo.data.DataReader
6065 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6066 * based on mappings in a provided Roo.data.Record constructor.
6068 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6069 * in the reply previously.
6074 var RecordDef = Roo.data.Record.create([
6075 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6076 {name: 'occupation'} // This field will use "occupation" as the mapping.
6078 var myReader = new Roo.data.JsonReader({
6079 totalProperty: "results", // The property which contains the total dataset size (optional)
6080 root: "rows", // The property which contains an Array of row objects
6081 id: "id" // The property within each row object that provides an ID for the record (optional)
6085 * This would consume a JSON file like this:
6087 { 'results': 2, 'rows': [
6088 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6089 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6092 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6093 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6094 * paged from the remote server.
6095 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6096 * @cfg {String} root name of the property which contains the Array of row objects.
6097 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6099 * Create a new JsonReader
6100 * @param {Object} meta Metadata configuration options
6101 * @param {Object} recordType Either an Array of field definition objects,
6102 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6104 Roo.data.JsonReader = function(meta, recordType){
6107 // set some defaults:
6109 totalProperty: 'total',
6110 successProperty : 'success',
6115 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6117 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6120 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6121 * Used by Store query builder to append _requestMeta to params.
6124 metaFromRemote : false,
6126 * This method is only used by a DataProxy which has retrieved data from a remote server.
6127 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6128 * @return {Object} data A data block which is used by an Roo.data.Store object as
6129 * a cache of Roo.data.Records.
6131 read : function(response){
6132 var json = response.responseText;
6134 var o = /* eval:var:o */ eval("("+json+")");
6136 throw {message: "JsonReader.read: Json object not found"};
6142 this.metaFromRemote = true;
6143 this.meta = o.metaData;
6144 this.recordType = Roo.data.Record.create(o.metaData.fields);
6145 this.onMetaChange(this.meta, this.recordType, o);
6147 return this.readRecords(o);
6150 // private function a store will implement
6151 onMetaChange : function(meta, recordType, o){
6158 simpleAccess: function(obj, subsc) {
6165 getJsonAccessor: function(){
6167 return function(expr) {
6169 return(re.test(expr))
6170 ? new Function("obj", "return obj." + expr)
6180 * Create a data block containing Roo.data.Records from an XML document.
6181 * @param {Object} o An object which contains an Array of row objects in the property specified
6182 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6183 * which contains the total size of the dataset.
6184 * @return {Object} data A data block which is used by an Roo.data.Store object as
6185 * a cache of Roo.data.Records.
6187 readRecords : function(o){
6189 * After any data loads, the raw JSON data is available for further custom processing.
6193 var s = this.meta, Record = this.recordType,
6194 f = Record.prototype.fields, fi = f.items, fl = f.length;
6196 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6198 if(s.totalProperty) {
6199 this.getTotal = this.getJsonAccessor(s.totalProperty);
6201 if(s.successProperty) {
6202 this.getSuccess = this.getJsonAccessor(s.successProperty);
6204 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6206 var g = this.getJsonAccessor(s.id);
6207 this.getId = function(rec) {
6209 return (r === undefined || r === "") ? null : r;
6212 this.getId = function(){return null;};
6215 for(var jj = 0; jj < fl; jj++){
6217 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6218 this.ef[jj] = this.getJsonAccessor(map);
6222 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6223 if(s.totalProperty){
6224 var vt = parseInt(this.getTotal(o), 10);
6229 if(s.successProperty){
6230 var vs = this.getSuccess(o);
6231 if(vs === false || vs === 'false'){
6236 for(var i = 0; i < c; i++){
6239 var id = this.getId(n);
6240 for(var j = 0; j < fl; j++){
6242 var v = this.ef[j](n);
6244 Roo.log('missing convert for ' + f.name);
6248 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6250 var record = new Record(values, id);
6252 records[i] = record;
6257 totalRecords : totalRecords
6262 * Ext JS Library 1.1.1
6263 * Copyright(c) 2006-2007, Ext JS, LLC.
6265 * Originally Released Under LGPL - original licence link has changed is not relivant.
6268 * <script type="text/javascript">
6272 * @class Roo.data.XmlReader
6273 * @extends Roo.data.DataReader
6274 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6275 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6277 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6278 * header in the HTTP response must be set to "text/xml".</em>
6282 var RecordDef = Roo.data.Record.create([
6283 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6284 {name: 'occupation'} // This field will use "occupation" as the mapping.
6286 var myReader = new Roo.data.XmlReader({
6287 totalRecords: "results", // The element which contains the total dataset size (optional)
6288 record: "row", // The repeated element which contains row information
6289 id: "id" // The element within the row that provides an ID for the record (optional)
6293 * This would consume an XML file like this:
6297 <results>2</results>
6300 <name>Bill</name>
6301 <occupation>Gardener</occupation>
6305 <name>Ben</name>
6306 <occupation>Horticulturalist</occupation>
6310 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6311 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6312 * paged from the remote server.
6313 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6314 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6315 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6316 * a record identifier value.
6318 * Create a new XmlReader
6319 * @param {Object} meta Metadata configuration options
6320 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6321 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6322 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6324 Roo.data.XmlReader = function(meta, recordType){
6326 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6328 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6330 * This method is only used by a DataProxy which has retrieved data from a remote server.
6331 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6332 * to contain a method called 'responseXML' that returns an XML document object.
6333 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6334 * a cache of Roo.data.Records.
6336 read : function(response){
6337 var doc = response.responseXML;
6339 throw {message: "XmlReader.read: XML Document not available"};
6341 return this.readRecords(doc);
6345 * Create a data block containing Roo.data.Records from an XML document.
6346 * @param {Object} doc A parsed XML document.
6347 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6348 * a cache of Roo.data.Records.
6350 readRecords : function(doc){
6352 * After any data loads/reads, the raw XML Document is available for further custom processing.
6356 var root = doc.documentElement || doc;
6357 var q = Roo.DomQuery;
6358 var recordType = this.recordType, fields = recordType.prototype.fields;
6359 var sid = this.meta.id;
6360 var totalRecords = 0, success = true;
6361 if(this.meta.totalRecords){
6362 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6365 if(this.meta.success){
6366 var sv = q.selectValue(this.meta.success, root, true);
6367 success = sv !== false && sv !== 'false';
6370 var ns = q.select(this.meta.record, root);
6371 for(var i = 0, len = ns.length; i < len; i++) {
6374 var id = sid ? q.selectValue(sid, n) : undefined;
6375 for(var j = 0, jlen = fields.length; j < jlen; j++){
6376 var f = fields.items[j];
6377 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6381 var record = new recordType(values, id);
6383 records[records.length] = record;
6389 totalRecords : totalRecords || records.length
6394 * Ext JS Library 1.1.1
6395 * Copyright(c) 2006-2007, Ext JS, LLC.
6397 * Originally Released Under LGPL - original licence link has changed is not relivant.
6400 * <script type="text/javascript">
6404 * @class Roo.data.ArrayReader
6405 * @extends Roo.data.DataReader
6406 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6407 * Each element of that Array represents a row of data fields. The
6408 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6409 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6413 var RecordDef = Roo.data.Record.create([
6414 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6415 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6417 var myReader = new Roo.data.ArrayReader({
6418 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6422 * This would consume an Array like this:
6424 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6426 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6428 * Create a new JsonReader
6429 * @param {Object} meta Metadata configuration options.
6430 * @param {Object} recordType Either an Array of field definition objects
6431 * as specified to {@link Roo.data.Record#create},
6432 * or an {@link Roo.data.Record} object
6433 * created using {@link Roo.data.Record#create}.
6435 Roo.data.ArrayReader = function(meta, recordType){
6436 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6439 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6441 * Create a data block containing Roo.data.Records from an XML document.
6442 * @param {Object} o An Array of row objects which represents the dataset.
6443 * @return {Object} data A data block which is used by an Roo.data.Store object as
6444 * a cache of Roo.data.Records.
6446 readRecords : function(o){
6447 var sid = this.meta ? this.meta.id : null;
6448 var recordType = this.recordType, fields = recordType.prototype.fields;
6451 for(var i = 0; i < root.length; i++){
6454 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6455 for(var j = 0, jlen = fields.length; j < jlen; j++){
6456 var f = fields.items[j];
6457 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6458 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6462 var record = new recordType(values, id);
6464 records[records.length] = record;
6468 totalRecords : records.length
6473 * Ext JS Library 1.1.1
6474 * Copyright(c) 2006-2007, Ext JS, LLC.
6476 * Originally Released Under LGPL - original licence link has changed is not relivant.
6479 * <script type="text/javascript">
6484 * @class Roo.data.Tree
6485 * @extends Roo.util.Observable
6486 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6487 * in the tree have most standard DOM functionality.
6489 * @param {Node} root (optional) The root node
6491 Roo.data.Tree = function(root){
6494 * The root node for this tree
6499 this.setRootNode(root);
6504 * Fires when a new child node is appended to a node in this tree.
6505 * @param {Tree} tree The owner tree
6506 * @param {Node} parent The parent node
6507 * @param {Node} node The newly appended node
6508 * @param {Number} index The index of the newly appended node
6513 * Fires when a child node is removed from a node in this tree.
6514 * @param {Tree} tree The owner tree
6515 * @param {Node} parent The parent node
6516 * @param {Node} node The child node removed
6521 * Fires when a node is moved to a new location in the tree
6522 * @param {Tree} tree The owner tree
6523 * @param {Node} node The node moved
6524 * @param {Node} oldParent The old parent of this node
6525 * @param {Node} newParent The new parent of this node
6526 * @param {Number} index The index it was moved to
6531 * Fires when a new child node is inserted in a node in this tree.
6532 * @param {Tree} tree The owner tree
6533 * @param {Node} parent The parent node
6534 * @param {Node} node The child node inserted
6535 * @param {Node} refNode The child node the node was inserted before
6539 * @event beforeappend
6540 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6541 * @param {Tree} tree The owner tree
6542 * @param {Node} parent The parent node
6543 * @param {Node} node The child node to be appended
6545 "beforeappend" : true,
6547 * @event beforeremove
6548 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6549 * @param {Tree} tree The owner tree
6550 * @param {Node} parent The parent node
6551 * @param {Node} node The child node to be removed
6553 "beforeremove" : true,
6556 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6557 * @param {Tree} tree The owner tree
6558 * @param {Node} node The node being moved
6559 * @param {Node} oldParent The parent of the node
6560 * @param {Node} newParent The new parent the node is moving to
6561 * @param {Number} index The index it is being moved to
6563 "beforemove" : true,
6565 * @event beforeinsert
6566 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6567 * @param {Tree} tree The owner tree
6568 * @param {Node} parent The parent node
6569 * @param {Node} node The child node to be inserted
6570 * @param {Node} refNode The child node the node is being inserted before
6572 "beforeinsert" : true
6575 Roo.data.Tree.superclass.constructor.call(this);
6578 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6581 proxyNodeEvent : function(){
6582 return this.fireEvent.apply(this, arguments);
6586 * Returns the root node for this tree.
6589 getRootNode : function(){
6594 * Sets the root node for this tree.
6595 * @param {Node} node
6598 setRootNode : function(node){
6600 node.ownerTree = this;
6602 this.registerNode(node);
6607 * Gets a node in this tree by its id.
6608 * @param {String} id
6611 getNodeById : function(id){
6612 return this.nodeHash[id];
6615 registerNode : function(node){
6616 this.nodeHash[node.id] = node;
6619 unregisterNode : function(node){
6620 delete this.nodeHash[node.id];
6623 toString : function(){
6624 return "[Tree"+(this.id?" "+this.id:"")+"]";
6629 * @class Roo.data.Node
6630 * @extends Roo.util.Observable
6631 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6632 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6634 * @param {Object} attributes The attributes/config for the node
6636 Roo.data.Node = function(attributes){
6638 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6641 this.attributes = attributes || {};
6642 this.leaf = this.attributes.leaf;
6644 * The node id. @type String
6646 this.id = this.attributes.id;
6648 this.id = Roo.id(null, "ynode-");
6649 this.attributes.id = this.id;
6652 * All child nodes of this node. @type Array
6654 this.childNodes = [];
6655 if(!this.childNodes.indexOf){ // indexOf is a must
6656 this.childNodes.indexOf = function(o){
6657 for(var i = 0, len = this.length; i < len; i++){
6666 * The parent node for this node. @type Node
6668 this.parentNode = null;
6670 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6672 this.firstChild = null;
6674 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6676 this.lastChild = null;
6678 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6680 this.previousSibling = null;
6682 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6684 this.nextSibling = null;
6689 * Fires when a new child node is appended
6690 * @param {Tree} tree The owner tree
6691 * @param {Node} this This node
6692 * @param {Node} node The newly appended node
6693 * @param {Number} index The index of the newly appended node
6698 * Fires when a child node is removed
6699 * @param {Tree} tree The owner tree
6700 * @param {Node} this This node
6701 * @param {Node} node The removed node
6706 * Fires when this node is moved to a new location in the tree
6707 * @param {Tree} tree The owner tree
6708 * @param {Node} this This node
6709 * @param {Node} oldParent The old parent of this node
6710 * @param {Node} newParent The new parent of this node
6711 * @param {Number} index The index it was moved to
6716 * Fires when a new child node is inserted.
6717 * @param {Tree} tree The owner tree
6718 * @param {Node} this This node
6719 * @param {Node} node The child node inserted
6720 * @param {Node} refNode The child node the node was inserted before
6724 * @event beforeappend
6725 * Fires before a new child is appended, return false to cancel the append.
6726 * @param {Tree} tree The owner tree
6727 * @param {Node} this This node
6728 * @param {Node} node The child node to be appended
6730 "beforeappend" : true,
6732 * @event beforeremove
6733 * Fires before a child is removed, return false to cancel the remove.
6734 * @param {Tree} tree The owner tree
6735 * @param {Node} this This node
6736 * @param {Node} node The child node to be removed
6738 "beforeremove" : true,
6741 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6742 * @param {Tree} tree The owner tree
6743 * @param {Node} this This node
6744 * @param {Node} oldParent The parent of this node
6745 * @param {Node} newParent The new parent this node is moving to
6746 * @param {Number} index The index it is being moved to
6748 "beforemove" : true,
6750 * @event beforeinsert
6751 * Fires before a new child is inserted, return false to cancel the insert.
6752 * @param {Tree} tree The owner tree
6753 * @param {Node} this This node
6754 * @param {Node} node The child node to be inserted
6755 * @param {Node} refNode The child node the node is being inserted before
6757 "beforeinsert" : true
6759 this.listeners = this.attributes.listeners;
6760 Roo.data.Node.superclass.constructor.call(this);
6763 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6764 fireEvent : function(evtName){
6765 // first do standard event for this node
6766 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6769 // then bubble it up to the tree if the event wasn't cancelled
6770 var ot = this.getOwnerTree();
6772 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6780 * Returns true if this node is a leaf
6783 isLeaf : function(){
6784 return this.leaf === true;
6788 setFirstChild : function(node){
6789 this.firstChild = node;
6793 setLastChild : function(node){
6794 this.lastChild = node;
6799 * Returns true if this node is the last child of its parent
6802 isLast : function(){
6803 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6807 * Returns true if this node is the first child of its parent
6810 isFirst : function(){
6811 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6814 hasChildNodes : function(){
6815 return !this.isLeaf() && this.childNodes.length > 0;
6819 * Insert node(s) as the last child node of this node.
6820 * @param {Node/Array} node The node or Array of nodes to append
6821 * @return {Node} The appended node if single append, or null if an array was passed
6823 appendChild : function(node){
6825 if(node instanceof Array){
6827 }else if(arguments.length > 1){
6830 // if passed an array or multiple args do them one by one
6832 for(var i = 0, len = multi.length; i < len; i++) {
6833 this.appendChild(multi[i]);
6836 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6839 var index = this.childNodes.length;
6840 var oldParent = node.parentNode;
6841 // it's a move, make sure we move it cleanly
6843 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6846 oldParent.removeChild(node);
6848 index = this.childNodes.length;
6850 this.setFirstChild(node);
6852 this.childNodes.push(node);
6853 node.parentNode = this;
6854 var ps = this.childNodes[index-1];
6856 node.previousSibling = ps;
6857 ps.nextSibling = node;
6859 node.previousSibling = null;
6861 node.nextSibling = null;
6862 this.setLastChild(node);
6863 node.setOwnerTree(this.getOwnerTree());
6864 this.fireEvent("append", this.ownerTree, this, node, index);
6866 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6873 * Removes a child node from this node.
6874 * @param {Node} node The node to remove
6875 * @return {Node} The removed node
6877 removeChild : function(node){
6878 var index = this.childNodes.indexOf(node);
6882 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6886 // remove it from childNodes collection
6887 this.childNodes.splice(index, 1);
6890 if(node.previousSibling){
6891 node.previousSibling.nextSibling = node.nextSibling;
6893 if(node.nextSibling){
6894 node.nextSibling.previousSibling = node.previousSibling;
6897 // update child refs
6898 if(this.firstChild == node){
6899 this.setFirstChild(node.nextSibling);
6901 if(this.lastChild == node){
6902 this.setLastChild(node.previousSibling);
6905 node.setOwnerTree(null);
6906 // clear any references from the node
6907 node.parentNode = null;
6908 node.previousSibling = null;
6909 node.nextSibling = null;
6910 this.fireEvent("remove", this.ownerTree, this, node);
6915 * Inserts the first node before the second node in this nodes childNodes collection.
6916 * @param {Node} node The node to insert
6917 * @param {Node} refNode The node to insert before (if null the node is appended)
6918 * @return {Node} The inserted node
6920 insertBefore : function(node, refNode){
6921 if(!refNode){ // like standard Dom, refNode can be null for append
6922 return this.appendChild(node);
6925 if(node == refNode){
6929 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6932 var index = this.childNodes.indexOf(refNode);
6933 var oldParent = node.parentNode;
6934 var refIndex = index;
6936 // when moving internally, indexes will change after remove
6937 if(oldParent == this && this.childNodes.indexOf(node) < index){
6941 // it's a move, make sure we move it cleanly
6943 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6946 oldParent.removeChild(node);
6949 this.setFirstChild(node);
6951 this.childNodes.splice(refIndex, 0, node);
6952 node.parentNode = this;
6953 var ps = this.childNodes[refIndex-1];
6955 node.previousSibling = ps;
6956 ps.nextSibling = node;
6958 node.previousSibling = null;
6960 node.nextSibling = refNode;
6961 refNode.previousSibling = node;
6962 node.setOwnerTree(this.getOwnerTree());
6963 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6965 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6971 * Returns the child node at the specified index.
6972 * @param {Number} index
6975 item : function(index){
6976 return this.childNodes[index];
6980 * Replaces one child node in this node with another.
6981 * @param {Node} newChild The replacement node
6982 * @param {Node} oldChild The node to replace
6983 * @return {Node} The replaced node
6985 replaceChild : function(newChild, oldChild){
6986 this.insertBefore(newChild, oldChild);
6987 this.removeChild(oldChild);
6992 * Returns the index of a child node
6993 * @param {Node} node
6994 * @return {Number} The index of the node or -1 if it was not found
6996 indexOf : function(child){
6997 return this.childNodes.indexOf(child);
7001 * Returns the tree this node is in.
7004 getOwnerTree : function(){
7005 // if it doesn't have one, look for one
7006 if(!this.ownerTree){
7010 this.ownerTree = p.ownerTree;
7016 return this.ownerTree;
7020 * Returns depth of this node (the root node has a depth of 0)
7023 getDepth : function(){
7026 while(p.parentNode){
7034 setOwnerTree : function(tree){
7035 // if it's move, we need to update everyone
7036 if(tree != this.ownerTree){
7038 this.ownerTree.unregisterNode(this);
7040 this.ownerTree = tree;
7041 var cs = this.childNodes;
7042 for(var i = 0, len = cs.length; i < len; i++) {
7043 cs[i].setOwnerTree(tree);
7046 tree.registerNode(this);
7052 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7053 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7054 * @return {String} The path
7056 getPath : function(attr){
7057 attr = attr || "id";
7058 var p = this.parentNode;
7059 var b = [this.attributes[attr]];
7061 b.unshift(p.attributes[attr]);
7064 var sep = this.getOwnerTree().pathSeparator;
7065 return sep + b.join(sep);
7069 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7070 * function call will be the scope provided or the current node. The arguments to the function
7071 * will be the args provided or the current node. If the function returns false at any point,
7072 * the bubble is stopped.
7073 * @param {Function} fn The function to call
7074 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7075 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7077 bubble : function(fn, scope, args){
7080 if(fn.call(scope || p, args || p) === false){
7088 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7089 * function call will be the scope provided or the current node. The arguments to the function
7090 * will be the args provided or the current node. If the function returns false at any point,
7091 * the cascade is stopped on that branch.
7092 * @param {Function} fn The function to call
7093 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7094 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7096 cascade : function(fn, scope, args){
7097 if(fn.call(scope || this, args || this) !== false){
7098 var cs = this.childNodes;
7099 for(var i = 0, len = cs.length; i < len; i++) {
7100 cs[i].cascade(fn, scope, args);
7106 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7107 * function call will be the scope provided or the current node. The arguments to the function
7108 * will be the args provided or the current node. If the function returns false at any point,
7109 * the iteration stops.
7110 * @param {Function} fn The function to call
7111 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7112 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7114 eachChild : function(fn, scope, args){
7115 var cs = this.childNodes;
7116 for(var i = 0, len = cs.length; i < len; i++) {
7117 if(fn.call(scope || this, args || cs[i]) === false){
7124 * Finds the first child that has the attribute with the specified value.
7125 * @param {String} attribute The attribute name
7126 * @param {Mixed} value The value to search for
7127 * @return {Node} The found child or null if none was found
7129 findChild : function(attribute, value){
7130 var cs = this.childNodes;
7131 for(var i = 0, len = cs.length; i < len; i++) {
7132 if(cs[i].attributes[attribute] == value){
7140 * Finds the first child by a custom function. The child matches if the function passed
7142 * @param {Function} fn
7143 * @param {Object} scope (optional)
7144 * @return {Node} The found child or null if none was found
7146 findChildBy : function(fn, scope){
7147 var cs = this.childNodes;
7148 for(var i = 0, len = cs.length; i < len; i++) {
7149 if(fn.call(scope||cs[i], cs[i]) === true){
7157 * Sorts this nodes children using the supplied sort function
7158 * @param {Function} fn
7159 * @param {Object} scope (optional)
7161 sort : function(fn, scope){
7162 var cs = this.childNodes;
7163 var len = cs.length;
7165 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7167 for(var i = 0; i < len; i++){
7169 n.previousSibling = cs[i-1];
7170 n.nextSibling = cs[i+1];
7172 this.setFirstChild(n);
7175 this.setLastChild(n);
7182 * Returns true if this node is an ancestor (at any point) of the passed node.
7183 * @param {Node} node
7186 contains : function(node){
7187 return node.isAncestor(this);
7191 * Returns true if the passed node is an ancestor (at any point) of this node.
7192 * @param {Node} node
7195 isAncestor : function(node){
7196 var p = this.parentNode;
7206 toString : function(){
7207 return "[Node"+(this.id?" "+this.id:"")+"]";
7211 * Ext JS Library 1.1.1
7212 * Copyright(c) 2006-2007, Ext JS, LLC.
7214 * Originally Released Under LGPL - original licence link has changed is not relivant.
7217 * <script type="text/javascript">
7222 * @class Roo.ComponentMgr
7223 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7226 Roo.ComponentMgr = function(){
7227 var all = new Roo.util.MixedCollection();
7231 * Registers a component.
7232 * @param {Roo.Component} c The component
7234 register : function(c){
7239 * Unregisters a component.
7240 * @param {Roo.Component} c The component
7242 unregister : function(c){
7247 * Returns a component by id
7248 * @param {String} id The component id
7255 * Registers a function that will be called when a specified component is added to ComponentMgr
7256 * @param {String} id The component id
7257 * @param {Funtction} fn The callback function
7258 * @param {Object} scope The scope of the callback
7260 onAvailable : function(id, fn, scope){
7261 all.on("add", function(index, o){
7263 fn.call(scope || o, o);
7264 all.un("add", fn, scope);
7271 * Ext JS Library 1.1.1
7272 * Copyright(c) 2006-2007, Ext JS, LLC.
7274 * Originally Released Under LGPL - original licence link has changed is not relivant.
7277 * <script type="text/javascript">
7281 * @class Roo.Component
7282 * @extends Roo.util.Observable
7283 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7284 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7285 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7286 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7287 * All visual components (widgets) that require rendering into a layout should subclass Component.
7289 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7290 * 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
7291 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7293 Roo.Component = function(config){
7294 config = config || {};
7295 if(config.tagName || config.dom || typeof config == "string"){ // element object
7296 config = {el: config, id: config.id || config};
7298 this.initialConfig = config;
7300 Roo.apply(this, config);
7304 * Fires after the component is disabled.
7305 * @param {Roo.Component} this
7310 * Fires after the component is enabled.
7311 * @param {Roo.Component} this
7316 * Fires before the component is shown. Return false to stop the show.
7317 * @param {Roo.Component} this
7322 * Fires after the component is shown.
7323 * @param {Roo.Component} this
7328 * Fires before the component is hidden. Return false to stop the hide.
7329 * @param {Roo.Component} this
7334 * Fires after the component is hidden.
7335 * @param {Roo.Component} this
7339 * @event beforerender
7340 * Fires before the component is rendered. Return false to stop the render.
7341 * @param {Roo.Component} this
7343 beforerender : true,
7346 * Fires after the component is rendered.
7347 * @param {Roo.Component} this
7351 * @event beforedestroy
7352 * Fires before the component is destroyed. Return false to stop the destroy.
7353 * @param {Roo.Component} this
7355 beforedestroy : true,
7358 * Fires after the component is destroyed.
7359 * @param {Roo.Component} this
7364 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7366 Roo.ComponentMgr.register(this);
7367 Roo.Component.superclass.constructor.call(this);
7368 this.initComponent();
7369 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7370 this.render(this.renderTo);
7371 delete this.renderTo;
7376 Roo.Component.AUTO_ID = 1000;
7378 Roo.extend(Roo.Component, Roo.util.Observable, {
7380 * @property {Boolean} hidden
7381 * true if this component is hidden. Read-only.
7385 * true if this component is disabled. Read-only.
7389 * true if this component has been rendered. Read-only.
7393 /** @cfg {String} disableClass
7394 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7396 disabledClass : "x-item-disabled",
7397 /** @cfg {Boolean} allowDomMove
7398 * Whether the component can move the Dom node when rendering (defaults to true).
7400 allowDomMove : true,
7401 /** @cfg {String} hideMode
7402 * How this component should hidden. Supported values are
7403 * "visibility" (css visibility), "offsets" (negative offset position) and
7404 * "display" (css display) - defaults to "display".
7406 hideMode: 'display',
7409 ctype : "Roo.Component",
7411 /** @cfg {String} actionMode
7412 * which property holds the element that used for hide() / show() / disable() / enable()
7418 getActionEl : function(){
7419 return this[this.actionMode];
7422 initComponent : Roo.emptyFn,
7424 * If this is a lazy rendering component, render it to its container element.
7425 * @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.
7427 render : function(container, position){
7428 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7429 if(!container && this.el){
7430 this.el = Roo.get(this.el);
7431 container = this.el.dom.parentNode;
7432 this.allowDomMove = false;
7434 this.container = Roo.get(container);
7435 this.rendered = true;
7436 if(position !== undefined){
7437 if(typeof position == 'number'){
7438 position = this.container.dom.childNodes[position];
7440 position = Roo.getDom(position);
7443 this.onRender(this.container, position || null);
7445 this.el.addClass(this.cls);
7449 this.el.applyStyles(this.style);
7452 this.fireEvent("render", this);
7453 this.afterRender(this.container);
7465 // default function is not really useful
7466 onRender : function(ct, position){
7468 this.el = Roo.get(this.el);
7469 if(this.allowDomMove !== false){
7470 ct.dom.insertBefore(this.el.dom, position);
7476 getAutoCreate : function(){
7477 var cfg = typeof this.autoCreate == "object" ?
7478 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7479 if(this.id && !cfg.id){
7486 afterRender : Roo.emptyFn,
7489 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7490 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7492 destroy : function(){
7493 if(this.fireEvent("beforedestroy", this) !== false){
7494 this.purgeListeners();
7495 this.beforeDestroy();
7497 this.el.removeAllListeners();
7499 if(this.actionMode == "container"){
7500 this.container.remove();
7504 Roo.ComponentMgr.unregister(this);
7505 this.fireEvent("destroy", this);
7510 beforeDestroy : function(){
7515 onDestroy : function(){
7520 * Returns the underlying {@link Roo.Element}.
7521 * @return {Roo.Element} The element
7528 * Returns the id of this component.
7536 * Try to focus this component.
7537 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7538 * @return {Roo.Component} this
7540 focus : function(selectText){
7543 if(selectText === true){
7544 this.el.dom.select();
7559 * Disable this component.
7560 * @return {Roo.Component} this
7562 disable : function(){
7566 this.disabled = true;
7567 this.fireEvent("disable", this);
7572 onDisable : function(){
7573 this.getActionEl().addClass(this.disabledClass);
7574 this.el.dom.disabled = true;
7578 * Enable this component.
7579 * @return {Roo.Component} this
7581 enable : function(){
7585 this.disabled = false;
7586 this.fireEvent("enable", this);
7591 onEnable : function(){
7592 this.getActionEl().removeClass(this.disabledClass);
7593 this.el.dom.disabled = false;
7597 * Convenience function for setting disabled/enabled by boolean.
7598 * @param {Boolean} disabled
7600 setDisabled : function(disabled){
7601 this[disabled ? "disable" : "enable"]();
7605 * Show this component.
7606 * @return {Roo.Component} this
7609 if(this.fireEvent("beforeshow", this) !== false){
7610 this.hidden = false;
7614 this.fireEvent("show", this);
7620 onShow : function(){
7621 var ae = this.getActionEl();
7622 if(this.hideMode == 'visibility'){
7623 ae.dom.style.visibility = "visible";
7624 }else if(this.hideMode == 'offsets'){
7625 ae.removeClass('x-hidden');
7627 ae.dom.style.display = "";
7632 * Hide this component.
7633 * @return {Roo.Component} this
7636 if(this.fireEvent("beforehide", this) !== false){
7641 this.fireEvent("hide", this);
7647 onHide : function(){
7648 var ae = this.getActionEl();
7649 if(this.hideMode == 'visibility'){
7650 ae.dom.style.visibility = "hidden";
7651 }else if(this.hideMode == 'offsets'){
7652 ae.addClass('x-hidden');
7654 ae.dom.style.display = "none";
7659 * Convenience function to hide or show this component by boolean.
7660 * @param {Boolean} visible True to show, false to hide
7661 * @return {Roo.Component} this
7663 setVisible: function(visible){
7673 * Returns true if this component is visible.
7675 isVisible : function(){
7676 return this.getActionEl().isVisible();
7679 cloneConfig : function(overrides){
7680 overrides = overrides || {};
7681 var id = overrides.id || Roo.id();
7682 var cfg = Roo.applyIf(overrides, this.initialConfig);
7683 cfg.id = id; // prevent dup id
7684 return new this.constructor(cfg);
7688 * Ext JS Library 1.1.1
7689 * Copyright(c) 2006-2007, Ext JS, LLC.
7691 * Originally Released Under LGPL - original licence link has changed is not relivant.
7694 * <script type="text/javascript">
7699 * @extends Roo.Element
7700 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7701 * automatic maintaining of shadow/shim positions.
7702 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7703 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7704 * you can pass a string with a CSS class name. False turns off the shadow.
7705 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7706 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7707 * @cfg {String} cls CSS class to add to the element
7708 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7709 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7711 * @param {Object} config An object with config options.
7712 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7715 Roo.Layer = function(config, existingEl){
7716 config = config || {};
7717 var dh = Roo.DomHelper;
7718 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7720 this.dom = Roo.getDom(existingEl);
7723 var o = config.dh || {tag: "div", cls: "x-layer"};
7724 this.dom = dh.append(pel, o);
7727 this.addClass(config.cls);
7729 this.constrain = config.constrain !== false;
7730 this.visibilityMode = Roo.Element.VISIBILITY;
7732 this.id = this.dom.id = config.id;
7734 this.id = Roo.id(this.dom);
7736 this.zindex = config.zindex || this.getZIndex();
7737 this.position("absolute", this.zindex);
7739 this.shadowOffset = config.shadowOffset || 4;
7740 this.shadow = new Roo.Shadow({
7741 offset : this.shadowOffset,
7742 mode : config.shadow
7745 this.shadowOffset = 0;
7747 this.useShim = config.shim !== false && Roo.useShims;
7748 this.useDisplay = config.useDisplay;
7752 var supr = Roo.Element.prototype;
7754 // shims are shared among layer to keep from having 100 iframes
7757 Roo.extend(Roo.Layer, Roo.Element, {
7759 getZIndex : function(){
7760 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7763 getShim : function(){
7770 var shim = shims.shift();
7772 shim = this.createShim();
7773 shim.enableDisplayMode('block');
7774 shim.dom.style.display = 'none';
7775 shim.dom.style.visibility = 'visible';
7777 var pn = this.dom.parentNode;
7778 if(shim.dom.parentNode != pn){
7779 pn.insertBefore(shim.dom, this.dom);
7781 shim.setStyle('z-index', this.getZIndex()-2);
7786 hideShim : function(){
7788 this.shim.setDisplayed(false);
7789 shims.push(this.shim);
7794 disableShadow : function(){
7796 this.shadowDisabled = true;
7798 this.lastShadowOffset = this.shadowOffset;
7799 this.shadowOffset = 0;
7803 enableShadow : function(show){
7805 this.shadowDisabled = false;
7806 this.shadowOffset = this.lastShadowOffset;
7807 delete this.lastShadowOffset;
7815 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7816 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7817 sync : function(doShow){
7818 var sw = this.shadow;
7819 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7820 var sh = this.getShim();
7822 var w = this.getWidth(),
7823 h = this.getHeight();
7825 var l = this.getLeft(true),
7826 t = this.getTop(true);
7828 if(sw && !this.shadowDisabled){
7829 if(doShow && !sw.isVisible()){
7832 sw.realign(l, t, w, h);
7838 // fit the shim behind the shadow, so it is shimmed too
7839 var a = sw.adjusts, s = sh.dom.style;
7840 s.left = (Math.min(l, l+a.l))+"px";
7841 s.top = (Math.min(t, t+a.t))+"px";
7842 s.width = (w+a.w)+"px";
7843 s.height = (h+a.h)+"px";
7850 sh.setLeftTop(l, t);
7857 destroy : function(){
7862 this.removeAllListeners();
7863 var pn = this.dom.parentNode;
7865 pn.removeChild(this.dom);
7867 Roo.Element.uncache(this.id);
7870 remove : function(){
7875 beginUpdate : function(){
7876 this.updating = true;
7880 endUpdate : function(){
7881 this.updating = false;
7886 hideUnders : function(negOffset){
7894 constrainXY : function(){
7896 var vw = Roo.lib.Dom.getViewWidth(),
7897 vh = Roo.lib.Dom.getViewHeight();
7898 var s = Roo.get(document).getScroll();
7900 var xy = this.getXY();
7901 var x = xy[0], y = xy[1];
7902 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7903 // only move it if it needs it
7905 // first validate right/bottom
7906 if((x + w) > vw+s.left){
7907 x = vw - w - this.shadowOffset;
7910 if((y + h) > vh+s.top){
7911 y = vh - h - this.shadowOffset;
7914 // then make sure top/left isn't negative
7925 var ay = this.avoidY;
7926 if(y <= ay && (y+h) >= ay){
7932 supr.setXY.call(this, xy);
7938 isVisible : function(){
7939 return this.visible;
7943 showAction : function(){
7944 this.visible = true; // track visibility to prevent getStyle calls
7945 if(this.useDisplay === true){
7946 this.setDisplayed("");
7947 }else if(this.lastXY){
7948 supr.setXY.call(this, this.lastXY);
7949 }else if(this.lastLT){
7950 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7955 hideAction : function(){
7956 this.visible = false;
7957 if(this.useDisplay === true){
7958 this.setDisplayed(false);
7960 this.setLeftTop(-10000,-10000);
7964 // overridden Element method
7965 setVisible : function(v, a, d, c, e){
7970 var cb = function(){
7975 }.createDelegate(this);
7976 supr.setVisible.call(this, true, true, d, cb, e);
7979 this.hideUnders(true);
7988 }.createDelegate(this);
7990 supr.setVisible.call(this, v, a, d, cb, e);
7999 storeXY : function(xy){
8004 storeLeftTop : function(left, top){
8006 this.lastLT = [left, top];
8010 beforeFx : function(){
8011 this.beforeAction();
8012 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8016 afterFx : function(){
8017 Roo.Layer.superclass.afterFx.apply(this, arguments);
8018 this.sync(this.isVisible());
8022 beforeAction : function(){
8023 if(!this.updating && this.shadow){
8028 // overridden Element method
8029 setLeft : function(left){
8030 this.storeLeftTop(left, this.getTop(true));
8031 supr.setLeft.apply(this, arguments);
8035 setTop : function(top){
8036 this.storeLeftTop(this.getLeft(true), top);
8037 supr.setTop.apply(this, arguments);
8041 setLeftTop : function(left, top){
8042 this.storeLeftTop(left, top);
8043 supr.setLeftTop.apply(this, arguments);
8047 setXY : function(xy, a, d, c, e){
8049 this.beforeAction();
8051 var cb = this.createCB(c);
8052 supr.setXY.call(this, xy, a, d, cb, e);
8059 createCB : function(c){
8070 // overridden Element method
8071 setX : function(x, a, d, c, e){
8072 this.setXY([x, this.getY()], a, d, c, e);
8075 // overridden Element method
8076 setY : function(y, a, d, c, e){
8077 this.setXY([this.getX(), y], a, d, c, e);
8080 // overridden Element method
8081 setSize : function(w, h, a, d, c, e){
8082 this.beforeAction();
8083 var cb = this.createCB(c);
8084 supr.setSize.call(this, w, h, a, d, cb, e);
8090 // overridden Element method
8091 setWidth : function(w, a, d, c, e){
8092 this.beforeAction();
8093 var cb = this.createCB(c);
8094 supr.setWidth.call(this, w, a, d, cb, e);
8100 // overridden Element method
8101 setHeight : function(h, a, d, c, e){
8102 this.beforeAction();
8103 var cb = this.createCB(c);
8104 supr.setHeight.call(this, h, a, d, cb, e);
8110 // overridden Element method
8111 setBounds : function(x, y, w, h, a, d, c, e){
8112 this.beforeAction();
8113 var cb = this.createCB(c);
8115 this.storeXY([x, y]);
8116 supr.setXY.call(this, [x, y]);
8117 supr.setSize.call(this, w, h, a, d, cb, e);
8120 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8126 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8127 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8128 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8129 * @param {Number} zindex The new z-index to set
8130 * @return {this} The Layer
8132 setZIndex : function(zindex){
8133 this.zindex = zindex;
8134 this.setStyle("z-index", zindex + 2);
8136 this.shadow.setZIndex(zindex + 1);
8139 this.shim.setStyle("z-index", zindex);
8145 * Ext JS Library 1.1.1
8146 * Copyright(c) 2006-2007, Ext JS, LLC.
8148 * Originally Released Under LGPL - original licence link has changed is not relivant.
8151 * <script type="text/javascript">
8157 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8158 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8159 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8161 * Create a new Shadow
8162 * @param {Object} config The config object
8164 Roo.Shadow = function(config){
8165 Roo.apply(this, config);
8166 if(typeof this.mode != "string"){
8167 this.mode = this.defaultMode;
8169 var o = this.offset, a = {h: 0};
8170 var rad = Math.floor(this.offset/2);
8171 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8177 a.l -= this.offset + rad;
8178 a.t -= this.offset + rad;
8189 a.l -= (this.offset - rad);
8190 a.t -= this.offset + rad;
8192 a.w -= (this.offset - rad)*2;
8203 a.l -= (this.offset - rad);
8204 a.t -= (this.offset - rad);
8206 a.w -= (this.offset + rad + 1);
8207 a.h -= (this.offset + rad);
8216 Roo.Shadow.prototype = {
8218 * @cfg {String} mode
8219 * The shadow display mode. Supports the following options:<br />
8220 * sides: Shadow displays on both sides and bottom only<br />
8221 * frame: Shadow displays equally on all four sides<br />
8222 * drop: Traditional bottom-right drop shadow (default)
8225 * @cfg {String} offset
8226 * The number of pixels to offset the shadow from the element (defaults to 4)
8231 defaultMode: "drop",
8234 * Displays the shadow under the target element
8235 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8237 show : function(target){
8238 target = Roo.get(target);
8240 this.el = Roo.Shadow.Pool.pull();
8241 if(this.el.dom.nextSibling != target.dom){
8242 this.el.insertBefore(target);
8245 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8247 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8250 target.getLeft(true),
8251 target.getTop(true),
8255 this.el.dom.style.display = "block";
8259 * Returns true if the shadow is visible, else false
8261 isVisible : function(){
8262 return this.el ? true : false;
8266 * Direct alignment when values are already available. Show must be called at least once before
8267 * calling this method to ensure it is initialized.
8268 * @param {Number} left The target element left position
8269 * @param {Number} top The target element top position
8270 * @param {Number} width The target element width
8271 * @param {Number} height The target element height
8273 realign : function(l, t, w, h){
8277 var a = this.adjusts, d = this.el.dom, s = d.style;
8279 s.left = (l+a.l)+"px";
8280 s.top = (t+a.t)+"px";
8281 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8283 if(s.width != sws || s.height != shs){
8287 var cn = d.childNodes;
8288 var sww = Math.max(0, (sw-12))+"px";
8289 cn[0].childNodes[1].style.width = sww;
8290 cn[1].childNodes[1].style.width = sww;
8291 cn[2].childNodes[1].style.width = sww;
8292 cn[1].style.height = Math.max(0, (sh-12))+"px";
8302 this.el.dom.style.display = "none";
8303 Roo.Shadow.Pool.push(this.el);
8309 * Adjust the z-index of this shadow
8310 * @param {Number} zindex The new z-index
8312 setZIndex : function(z){
8315 this.el.setStyle("z-index", z);
8320 // Private utility class that manages the internal Shadow cache
8321 Roo.Shadow.Pool = function(){
8323 var markup = Roo.isIE ?
8324 '<div class="x-ie-shadow"></div>' :
8325 '<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>';
8330 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8331 sh.autoBoxAdjust = false;
8336 push : function(sh){
8342 * Ext JS Library 1.1.1
8343 * Copyright(c) 2006-2007, Ext JS, LLC.
8345 * Originally Released Under LGPL - original licence link has changed is not relivant.
8348 * <script type="text/javascript">
8352 * @class Roo.BoxComponent
8353 * @extends Roo.Component
8354 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8355 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8356 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8357 * layout containers.
8359 * @param {Roo.Element/String/Object} config The configuration options.
8361 Roo.BoxComponent = function(config){
8362 Roo.Component.call(this, config);
8366 * Fires after the component is resized.
8367 * @param {Roo.Component} this
8368 * @param {Number} adjWidth The box-adjusted width that was set
8369 * @param {Number} adjHeight The box-adjusted height that was set
8370 * @param {Number} rawWidth The width that was originally specified
8371 * @param {Number} rawHeight The height that was originally specified
8376 * Fires after the component is moved.
8377 * @param {Roo.Component} this
8378 * @param {Number} x The new x position
8379 * @param {Number} y The new y position
8385 Roo.extend(Roo.BoxComponent, Roo.Component, {
8386 // private, set in afterRender to signify that the component has been rendered
8388 // private, used to defer height settings to subclasses
8390 /** @cfg {Number} width
8391 * width (optional) size of component
8393 /** @cfg {Number} height
8394 * height (optional) size of component
8398 * Sets the width and height of the component. This method fires the resize event. This method can accept
8399 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8400 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8401 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8402 * @return {Roo.BoxComponent} this
8404 setSize : function(w, h){
8405 // support for standard size objects
8406 if(typeof w == 'object'){
8417 // prevent recalcs when not needed
8418 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8421 this.lastSize = {width: w, height: h};
8423 var adj = this.adjustSize(w, h);
8424 var aw = adj.width, ah = adj.height;
8425 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8426 var rz = this.getResizeEl();
8427 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8429 }else if(!this.deferHeight && ah !== undefined){
8431 }else if(aw !== undefined){
8434 this.onResize(aw, ah, w, h);
8435 this.fireEvent('resize', this, aw, ah, w, h);
8441 * Gets the current size of the component's underlying element.
8442 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8444 getSize : function(){
8445 return this.el.getSize();
8449 * Gets the current XY position of the component's underlying element.
8450 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8451 * @return {Array} The XY position of the element (e.g., [100, 200])
8453 getPosition : function(local){
8455 return [this.el.getLeft(true), this.el.getTop(true)];
8457 return this.xy || this.el.getXY();
8461 * Gets the current box measurements of the component's underlying element.
8462 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8463 * @returns {Object} box An object in the format {x, y, width, height}
8465 getBox : function(local){
8466 var s = this.el.getSize();
8468 s.x = this.el.getLeft(true);
8469 s.y = this.el.getTop(true);
8471 var xy = this.xy || this.el.getXY();
8479 * Sets the current box measurements of the component's underlying element.
8480 * @param {Object} box An object in the format {x, y, width, height}
8481 * @returns {Roo.BoxComponent} this
8483 updateBox : function(box){
8484 this.setSize(box.width, box.height);
8485 this.setPagePosition(box.x, box.y);
8490 getResizeEl : function(){
8491 return this.resizeEl || this.el;
8495 getPositionEl : function(){
8496 return this.positionEl || this.el;
8500 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8501 * This method fires the move event.
8502 * @param {Number} left The new left
8503 * @param {Number} top The new top
8504 * @returns {Roo.BoxComponent} this
8506 setPosition : function(x, y){
8512 var adj = this.adjustPosition(x, y);
8513 var ax = adj.x, ay = adj.y;
8515 var el = this.getPositionEl();
8516 if(ax !== undefined || ay !== undefined){
8517 if(ax !== undefined && ay !== undefined){
8518 el.setLeftTop(ax, ay);
8519 }else if(ax !== undefined){
8521 }else if(ay !== undefined){
8524 this.onPosition(ax, ay);
8525 this.fireEvent('move', this, ax, ay);
8531 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8532 * This method fires the move event.
8533 * @param {Number} x The new x position
8534 * @param {Number} y The new y position
8535 * @returns {Roo.BoxComponent} this
8537 setPagePosition : function(x, y){
8543 if(x === undefined || y === undefined){ // cannot translate undefined points
8546 var p = this.el.translatePoints(x, y);
8547 this.setPosition(p.left, p.top);
8552 onRender : function(ct, position){
8553 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8555 this.resizeEl = Roo.get(this.resizeEl);
8557 if(this.positionEl){
8558 this.positionEl = Roo.get(this.positionEl);
8563 afterRender : function(){
8564 Roo.BoxComponent.superclass.afterRender.call(this);
8565 this.boxReady = true;
8566 this.setSize(this.width, this.height);
8567 if(this.x || this.y){
8568 this.setPosition(this.x, this.y);
8570 if(this.pageX || this.pageY){
8571 this.setPagePosition(this.pageX, this.pageY);
8576 * Force the component's size to recalculate based on the underlying element's current height and width.
8577 * @returns {Roo.BoxComponent} this
8579 syncSize : function(){
8580 delete this.lastSize;
8581 this.setSize(this.el.getWidth(), this.el.getHeight());
8586 * Called after the component is resized, this method is empty by default but can be implemented by any
8587 * subclass that needs to perform custom logic after a resize occurs.
8588 * @param {Number} adjWidth The box-adjusted width that was set
8589 * @param {Number} adjHeight The box-adjusted height that was set
8590 * @param {Number} rawWidth The width that was originally specified
8591 * @param {Number} rawHeight The height that was originally specified
8593 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8598 * Called after the component is moved, this method is empty by default but can be implemented by any
8599 * subclass that needs to perform custom logic after a move occurs.
8600 * @param {Number} x The new x position
8601 * @param {Number} y The new y position
8603 onPosition : function(x, y){
8608 adjustSize : function(w, h){
8612 if(this.autoHeight){
8615 return {width : w, height: h};
8619 adjustPosition : function(x, y){
8620 return {x : x, y: y};
8624 * Ext JS Library 1.1.1
8625 * Copyright(c) 2006-2007, Ext JS, LLC.
8627 * Originally Released Under LGPL - original licence link has changed is not relivant.
8630 * <script type="text/javascript">
8635 * @class Roo.SplitBar
8636 * @extends Roo.util.Observable
8637 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8641 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8642 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8643 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8644 split.minSize = 100;
8645 split.maxSize = 600;
8646 split.animate = true;
8647 split.on('moved', splitterMoved);
8650 * Create a new SplitBar
8651 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8652 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8653 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8654 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8655 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8656 position of the SplitBar).
8658 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8661 this.el = Roo.get(dragElement, true);
8662 this.el.dom.unselectable = "on";
8664 this.resizingEl = Roo.get(resizingElement, true);
8668 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8669 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8672 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8675 * The minimum size of the resizing element. (Defaults to 0)
8681 * The maximum size of the resizing element. (Defaults to 2000)
8684 this.maxSize = 2000;
8687 * Whether to animate the transition to the new size
8690 this.animate = false;
8693 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8696 this.useShim = false;
8703 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8705 this.proxy = Roo.get(existingProxy).dom;
8708 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8711 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8714 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8717 this.dragSpecs = {};
8720 * @private The adapter to use to positon and resize elements
8722 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8723 this.adapter.init(this);
8725 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8727 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8728 this.el.addClass("x-splitbar-h");
8731 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8732 this.el.addClass("x-splitbar-v");
8738 * Fires when the splitter is moved (alias for {@link #event-moved})
8739 * @param {Roo.SplitBar} this
8740 * @param {Number} newSize the new width or height
8745 * Fires when the splitter is moved
8746 * @param {Roo.SplitBar} this
8747 * @param {Number} newSize the new width or height
8751 * @event beforeresize
8752 * Fires before the splitter is dragged
8753 * @param {Roo.SplitBar} this
8755 "beforeresize" : true,
8757 "beforeapply" : true
8760 Roo.util.Observable.call(this);
8763 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8764 onStartProxyDrag : function(x, y){
8765 this.fireEvent("beforeresize", this);
8767 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8769 o.enableDisplayMode("block");
8770 // all splitbars share the same overlay
8771 Roo.SplitBar.prototype.overlay = o;
8773 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8774 this.overlay.show();
8775 Roo.get(this.proxy).setDisplayed("block");
8776 var size = this.adapter.getElementSize(this);
8777 this.activeMinSize = this.getMinimumSize();;
8778 this.activeMaxSize = this.getMaximumSize();;
8779 var c1 = size - this.activeMinSize;
8780 var c2 = Math.max(this.activeMaxSize - size, 0);
8781 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8782 this.dd.resetConstraints();
8783 this.dd.setXConstraint(
8784 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8785 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8787 this.dd.setYConstraint(0, 0);
8789 this.dd.resetConstraints();
8790 this.dd.setXConstraint(0, 0);
8791 this.dd.setYConstraint(
8792 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8793 this.placement == Roo.SplitBar.TOP ? c2 : c1
8796 this.dragSpecs.startSize = size;
8797 this.dragSpecs.startPoint = [x, y];
8798 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8802 * @private Called after the drag operation by the DDProxy
8804 onEndProxyDrag : function(e){
8805 Roo.get(this.proxy).setDisplayed(false);
8806 var endPoint = Roo.lib.Event.getXY(e);
8808 this.overlay.hide();
8811 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8812 newSize = this.dragSpecs.startSize +
8813 (this.placement == Roo.SplitBar.LEFT ?
8814 endPoint[0] - this.dragSpecs.startPoint[0] :
8815 this.dragSpecs.startPoint[0] - endPoint[0]
8818 newSize = this.dragSpecs.startSize +
8819 (this.placement == Roo.SplitBar.TOP ?
8820 endPoint[1] - this.dragSpecs.startPoint[1] :
8821 this.dragSpecs.startPoint[1] - endPoint[1]
8824 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8825 if(newSize != this.dragSpecs.startSize){
8826 if(this.fireEvent('beforeapply', this, newSize) !== false){
8827 this.adapter.setElementSize(this, newSize);
8828 this.fireEvent("moved", this, newSize);
8829 this.fireEvent("resize", this, newSize);
8835 * Get the adapter this SplitBar uses
8836 * @return The adapter object
8838 getAdapter : function(){
8839 return this.adapter;
8843 * Set the adapter this SplitBar uses
8844 * @param {Object} adapter A SplitBar adapter object
8846 setAdapter : function(adapter){
8847 this.adapter = adapter;
8848 this.adapter.init(this);
8852 * Gets the minimum size for the resizing element
8853 * @return {Number} The minimum size
8855 getMinimumSize : function(){
8856 return this.minSize;
8860 * Sets the minimum size for the resizing element
8861 * @param {Number} minSize The minimum size
8863 setMinimumSize : function(minSize){
8864 this.minSize = minSize;
8868 * Gets the maximum size for the resizing element
8869 * @return {Number} The maximum size
8871 getMaximumSize : function(){
8872 return this.maxSize;
8876 * Sets the maximum size for the resizing element
8877 * @param {Number} maxSize The maximum size
8879 setMaximumSize : function(maxSize){
8880 this.maxSize = maxSize;
8884 * Sets the initialize size for the resizing element
8885 * @param {Number} size The initial size
8887 setCurrentSize : function(size){
8888 var oldAnimate = this.animate;
8889 this.animate = false;
8890 this.adapter.setElementSize(this, size);
8891 this.animate = oldAnimate;
8895 * Destroy this splitbar.
8896 * @param {Boolean} removeEl True to remove the element
8898 destroy : function(removeEl){
8903 this.proxy.parentNode.removeChild(this.proxy);
8911 * @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.
8913 Roo.SplitBar.createProxy = function(dir){
8914 var proxy = new Roo.Element(document.createElement("div"));
8915 proxy.unselectable();
8916 var cls = 'x-splitbar-proxy';
8917 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8918 document.body.appendChild(proxy.dom);
8923 * @class Roo.SplitBar.BasicLayoutAdapter
8924 * Default Adapter. It assumes the splitter and resizing element are not positioned
8925 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8927 Roo.SplitBar.BasicLayoutAdapter = function(){
8930 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8931 // do nothing for now
8936 * Called before drag operations to get the current size of the resizing element.
8937 * @param {Roo.SplitBar} s The SplitBar using this adapter
8939 getElementSize : function(s){
8940 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8941 return s.resizingEl.getWidth();
8943 return s.resizingEl.getHeight();
8948 * Called after drag operations to set the size of the resizing element.
8949 * @param {Roo.SplitBar} s The SplitBar using this adapter
8950 * @param {Number} newSize The new size to set
8951 * @param {Function} onComplete A function to be invoked when resizing is complete
8953 setElementSize : function(s, newSize, onComplete){
8954 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8956 s.resizingEl.setWidth(newSize);
8958 onComplete(s, newSize);
8961 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8966 s.resizingEl.setHeight(newSize);
8968 onComplete(s, newSize);
8971 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8978 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8979 * @extends Roo.SplitBar.BasicLayoutAdapter
8980 * Adapter that moves the splitter element to align with the resized sizing element.
8981 * Used with an absolute positioned SplitBar.
8982 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8983 * document.body, make sure you assign an id to the body element.
8985 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8986 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8987 this.container = Roo.get(container);
8990 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8995 getElementSize : function(s){
8996 return this.basic.getElementSize(s);
8999 setElementSize : function(s, newSize, onComplete){
9000 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
9003 moveSplitter : function(s){
9004 var yes = Roo.SplitBar;
9005 switch(s.placement){
9007 s.el.setX(s.resizingEl.getRight());
9010 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9013 s.el.setY(s.resizingEl.getBottom());
9016 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9023 * Orientation constant - Create a vertical SplitBar
9027 Roo.SplitBar.VERTICAL = 1;
9030 * Orientation constant - Create a horizontal SplitBar
9034 Roo.SplitBar.HORIZONTAL = 2;
9037 * Placement constant - The resizing element is to the left of the splitter element
9041 Roo.SplitBar.LEFT = 1;
9044 * Placement constant - The resizing element is to the right of the splitter element
9048 Roo.SplitBar.RIGHT = 2;
9051 * Placement constant - The resizing element is positioned above the splitter element
9055 Roo.SplitBar.TOP = 3;
9058 * Placement constant - The resizing element is positioned under splitter element
9062 Roo.SplitBar.BOTTOM = 4;
9065 * Ext JS Library 1.1.1
9066 * Copyright(c) 2006-2007, Ext JS, LLC.
9068 * Originally Released Under LGPL - original licence link has changed is not relivant.
9071 * <script type="text/javascript">
9076 * @extends Roo.util.Observable
9077 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9078 * This class also supports single and multi selection modes. <br>
9079 * Create a data model bound view:
9081 var store = new Roo.data.Store(...);
9083 var view = new Roo.View({
9085 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9088 selectedClass: "ydataview-selected",
9092 // listen for node click?
9093 view.on("click", function(vw, index, node, e){
9094 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9098 dataModel.load("foobar.xml");
9100 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9102 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9103 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9105 * Note: old style constructor is still suported (container, template, config)
9109 * @param {Object} config The config object
9112 Roo.View = function(config, depreciated_tpl, depreciated_config){
9114 if (typeof(depreciated_tpl) == 'undefined') {
9115 // new way.. - universal constructor.
9116 Roo.apply(this, config);
9117 this.el = Roo.get(this.el);
9120 this.el = Roo.get(config);
9121 this.tpl = depreciated_tpl;
9122 Roo.apply(this, depreciated_config);
9126 if(typeof(this.tpl) == "string"){
9127 this.tpl = new Roo.Template(this.tpl);
9129 // support xtype ctors..
9130 this.tpl = new Roo.factory(this.tpl, Roo);
9141 * @event beforeclick
9142 * Fires before a click is processed. Returns false to cancel the default action.
9143 * @param {Roo.View} this
9144 * @param {Number} index The index of the target node
9145 * @param {HTMLElement} node The target node
9146 * @param {Roo.EventObject} e The raw event object
9148 "beforeclick" : true,
9151 * Fires when a template node is clicked.
9152 * @param {Roo.View} this
9153 * @param {Number} index The index of the target node
9154 * @param {HTMLElement} node The target node
9155 * @param {Roo.EventObject} e The raw event object
9160 * Fires when a template node is double clicked.
9161 * @param {Roo.View} this
9162 * @param {Number} index The index of the target node
9163 * @param {HTMLElement} node The target node
9164 * @param {Roo.EventObject} e The raw event object
9168 * @event contextmenu
9169 * Fires when a template node is right clicked.
9170 * @param {Roo.View} this
9171 * @param {Number} index The index of the target node
9172 * @param {HTMLElement} node The target node
9173 * @param {Roo.EventObject} e The raw event object
9175 "contextmenu" : true,
9177 * @event selectionchange
9178 * Fires when the selected nodes change.
9179 * @param {Roo.View} this
9180 * @param {Array} selections Array of the selected nodes
9182 "selectionchange" : true,
9185 * @event beforeselect
9186 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9187 * @param {Roo.View} this
9188 * @param {HTMLElement} node The node to be selected
9189 * @param {Array} selections Array of currently selected nodes
9191 "beforeselect" : true
9195 "click": this.onClick,
9196 "dblclick": this.onDblClick,
9197 "contextmenu": this.onContextMenu,
9201 this.selections = [];
9203 this.cmp = new Roo.CompositeElementLite([]);
9205 this.store = Roo.factory(this.store, Roo.data);
9206 this.setStore(this.store, true);
9208 Roo.View.superclass.constructor.call(this);
9211 Roo.extend(Roo.View, Roo.util.Observable, {
9214 * @cfg {Roo.data.Store} store Data store to load data from.
9219 * @cfg {String|Roo.Element} el The container element.
9224 * @cfg {String|Roo.Template} tpl The template used by this View
9229 * @cfg {String} selectedClass The css class to add to selected nodes
9231 selectedClass : "x-view-selected",
9233 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9237 * @cfg {Boolean} multiSelect Allow multiple selection
9240 multiSelect : false,
9242 * @cfg {Boolean} singleSelect Allow single selection
9244 singleSelect: false,
9247 * Returns the element this view is bound to.
9248 * @return {Roo.Element}
9255 * Refreshes the view.
9257 refresh : function(){
9259 this.clearSelections();
9262 var records = this.store.getRange();
9263 if(records.length < 1){
9264 this.el.update(this.emptyText);
9267 for(var i = 0, len = records.length; i < len; i++){
9268 var data = this.prepareData(records[i].data, i, records[i]);
9269 html[html.length] = t.apply(data);
9271 this.el.update(html.join(""));
9272 this.nodes = this.el.dom.childNodes;
9273 this.updateIndexes(0);
9277 * Function to override to reformat the data that is sent to
9278 * the template for each node.
9279 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9280 * a JSON object for an UpdateManager bound view).
9282 prepareData : function(data){
9286 onUpdate : function(ds, record){
9287 this.clearSelections();
9288 var index = this.store.indexOf(record);
9289 var n = this.nodes[index];
9290 this.tpl.insertBefore(n, this.prepareData(record.data));
9291 n.parentNode.removeChild(n);
9292 this.updateIndexes(index, index);
9295 onAdd : function(ds, records, index){
9296 this.clearSelections();
9297 if(this.nodes.length == 0){
9301 var n = this.nodes[index];
9302 for(var i = 0, len = records.length; i < len; i++){
9303 var d = this.prepareData(records[i].data);
9305 this.tpl.insertBefore(n, d);
9307 this.tpl.append(this.el, d);
9310 this.updateIndexes(index);
9313 onRemove : function(ds, record, index){
9314 this.clearSelections();
9315 this.el.dom.removeChild(this.nodes[index]);
9316 this.updateIndexes(index);
9320 * Refresh an individual node.
9321 * @param {Number} index
9323 refreshNode : function(index){
9324 this.onUpdate(this.store, this.store.getAt(index));
9327 updateIndexes : function(startIndex, endIndex){
9328 var ns = this.nodes;
9329 startIndex = startIndex || 0;
9330 endIndex = endIndex || ns.length - 1;
9331 for(var i = startIndex; i <= endIndex; i++){
9332 ns[i].nodeIndex = i;
9337 * Changes the data store this view uses and refresh the view.
9338 * @param {Store} store
9340 setStore : function(store, initial){
9341 if(!initial && this.store){
9342 this.store.un("datachanged", this.refresh);
9343 this.store.un("add", this.onAdd);
9344 this.store.un("remove", this.onRemove);
9345 this.store.un("update", this.onUpdate);
9346 this.store.un("clear", this.refresh);
9350 store.on("datachanged", this.refresh, this);
9351 store.on("add", this.onAdd, this);
9352 store.on("remove", this.onRemove, this);
9353 store.on("update", this.onUpdate, this);
9354 store.on("clear", this.refresh, this);
9363 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9364 * @param {HTMLElement} node
9365 * @return {HTMLElement} The template node
9367 findItemFromChild : function(node){
9368 var el = this.el.dom;
9369 if(!node || node.parentNode == el){
9372 var p = node.parentNode;
9373 while(p && p != el){
9374 if(p.parentNode == el){
9383 onClick : function(e){
9384 var item = this.findItemFromChild(e.getTarget());
9386 var index = this.indexOf(item);
9387 if(this.onItemClick(item, index, e) !== false){
9388 this.fireEvent("click", this, index, item, e);
9391 this.clearSelections();
9396 onContextMenu : function(e){
9397 var item = this.findItemFromChild(e.getTarget());
9399 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9404 onDblClick : function(e){
9405 var item = this.findItemFromChild(e.getTarget());
9407 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9411 onItemClick : function(item, index, e){
9412 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9415 if(this.multiSelect || this.singleSelect){
9416 if(this.multiSelect && e.shiftKey && this.lastSelection){
9417 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9419 this.select(item, this.multiSelect && e.ctrlKey);
9420 this.lastSelection = item;
9428 * Get the number of selected nodes.
9431 getSelectionCount : function(){
9432 return this.selections.length;
9436 * Get the currently selected nodes.
9437 * @return {Array} An array of HTMLElements
9439 getSelectedNodes : function(){
9440 return this.selections;
9444 * Get the indexes of the selected nodes.
9447 getSelectedIndexes : function(){
9448 var indexes = [], s = this.selections;
9449 for(var i = 0, len = s.length; i < len; i++){
9450 indexes.push(s[i].nodeIndex);
9456 * Clear all selections
9457 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9459 clearSelections : function(suppressEvent){
9460 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9461 this.cmp.elements = this.selections;
9462 this.cmp.removeClass(this.selectedClass);
9463 this.selections = [];
9465 this.fireEvent("selectionchange", this, this.selections);
9471 * Returns true if the passed node is selected
9472 * @param {HTMLElement/Number} node The node or node index
9475 isSelected : function(node){
9476 var s = this.selections;
9480 node = this.getNode(node);
9481 return s.indexOf(node) !== -1;
9486 * @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
9487 * @param {Boolean} keepExisting (optional) true to keep existing selections
9488 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9490 select : function(nodeInfo, keepExisting, suppressEvent){
9491 if(nodeInfo instanceof Array){
9493 this.clearSelections(true);
9495 for(var i = 0, len = nodeInfo.length; i < len; i++){
9496 this.select(nodeInfo[i], true, true);
9499 var node = this.getNode(nodeInfo);
9500 if(node && !this.isSelected(node)){
9502 this.clearSelections(true);
9504 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9505 Roo.fly(node).addClass(this.selectedClass);
9506 this.selections.push(node);
9508 this.fireEvent("selectionchange", this, this.selections);
9516 * Gets a template node.
9517 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9518 * @return {HTMLElement} The node or null if it wasn't found
9520 getNode : function(nodeInfo){
9521 if(typeof nodeInfo == "string"){
9522 return document.getElementById(nodeInfo);
9523 }else if(typeof nodeInfo == "number"){
9524 return this.nodes[nodeInfo];
9530 * Gets a range template nodes.
9531 * @param {Number} startIndex
9532 * @param {Number} endIndex
9533 * @return {Array} An array of nodes
9535 getNodes : function(start, end){
9536 var ns = this.nodes;
9538 end = typeof end == "undefined" ? ns.length - 1 : end;
9541 for(var i = start; i <= end; i++){
9545 for(var i = start; i >= end; i--){
9553 * Finds the index of the passed node
9554 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9555 * @return {Number} The index of the node or -1
9557 indexOf : function(node){
9558 node = this.getNode(node);
9559 if(typeof node.nodeIndex == "number"){
9560 return node.nodeIndex;
9562 var ns = this.nodes;
9563 for(var i = 0, len = ns.length; i < len; i++){
9573 * Ext JS Library 1.1.1
9574 * Copyright(c) 2006-2007, Ext JS, LLC.
9576 * Originally Released Under LGPL - original licence link has changed is not relivant.
9579 * <script type="text/javascript">
9583 * @class Roo.JsonView
9585 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9587 var view = new Roo.JsonView({
9588 container: "my-element",
9589 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9594 // listen for node click?
9595 view.on("click", function(vw, index, node, e){
9596 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9599 // direct load of JSON data
9600 view.load("foobar.php");
9602 // Example from my blog list
9603 var tpl = new Roo.Template(
9604 '<div class="entry">' +
9605 '<a class="entry-title" href="{link}">{title}</a>' +
9606 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9607 "</div><hr />"
9610 var moreView = new Roo.JsonView({
9611 container : "entry-list",
9615 moreView.on("beforerender", this.sortEntries, this);
9617 url: "/blog/get-posts.php",
9618 params: "allposts=true",
9619 text: "Loading Blog Entries..."
9623 * Note: old code is supported with arguments : (container, template, config)
9627 * Create a new JsonView
9629 * @param {Object} config The config object
9632 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9635 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9637 var um = this.el.getUpdateManager();
9638 um.setRenderer(this);
9639 um.on("update", this.onLoad, this);
9640 um.on("failure", this.onLoadException, this);
9643 * @event beforerender
9644 * Fires before rendering of the downloaded JSON data.
9645 * @param {Roo.JsonView} this
9646 * @param {Object} data The JSON data loaded
9650 * Fires when data is loaded.
9651 * @param {Roo.JsonView} this
9652 * @param {Object} data The JSON data loaded
9653 * @param {Object} response The raw Connect response object
9656 * @event loadexception
9657 * Fires when loading fails.
9658 * @param {Roo.JsonView} this
9659 * @param {Object} response The raw Connect response object
9662 'beforerender' : true,
9664 'loadexception' : true
9667 Roo.extend(Roo.JsonView, Roo.View, {
9669 * @type {String} The root property in the loaded JSON object that contains the data
9674 * Refreshes the view.
9676 refresh : function(){
9677 this.clearSelections();
9680 var o = this.jsonData;
9681 if(o && o.length > 0){
9682 for(var i = 0, len = o.length; i < len; i++){
9683 var data = this.prepareData(o[i], i, o);
9684 html[html.length] = this.tpl.apply(data);
9687 html.push(this.emptyText);
9689 this.el.update(html.join(""));
9690 this.nodes = this.el.dom.childNodes;
9691 this.updateIndexes(0);
9695 * 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.
9696 * @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:
9699 url: "your-url.php",
9700 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9701 callback: yourFunction,
9702 scope: yourObject, //(optional scope)
9710 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9711 * 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.
9712 * @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}
9713 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9714 * @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.
9717 var um = this.el.getUpdateManager();
9718 um.update.apply(um, arguments);
9721 render : function(el, response){
9722 this.clearSelections();
9726 o = Roo.util.JSON.decode(response.responseText);
9729 o = o[this.jsonRoot];
9734 * The current JSON data or null
9737 this.beforeRender();
9742 * Get the number of records in the current JSON dataset
9745 getCount : function(){
9746 return this.jsonData ? this.jsonData.length : 0;
9750 * Returns the JSON object for the specified node(s)
9751 * @param {HTMLElement/Array} node The node or an array of nodes
9752 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9753 * you get the JSON object for the node
9755 getNodeData : function(node){
9756 if(node instanceof Array){
9758 for(var i = 0, len = node.length; i < len; i++){
9759 data.push(this.getNodeData(node[i]));
9763 return this.jsonData[this.indexOf(node)] || null;
9766 beforeRender : function(){
9767 this.snapshot = this.jsonData;
9769 this.sort.apply(this, this.sortInfo);
9771 this.fireEvent("beforerender", this, this.jsonData);
9774 onLoad : function(el, o){
9775 this.fireEvent("load", this, this.jsonData, o);
9778 onLoadException : function(el, o){
9779 this.fireEvent("loadexception", this, o);
9783 * Filter the data by a specific property.
9784 * @param {String} property A property on your JSON objects
9785 * @param {String/RegExp} value Either string that the property values
9786 * should start with, or a RegExp to test against the property
9788 filter : function(property, value){
9791 var ss = this.snapshot;
9792 if(typeof value == "string"){
9793 var vlen = value.length;
9798 value = value.toLowerCase();
9799 for(var i = 0, len = ss.length; i < len; i++){
9801 if(o[property].substr(0, vlen).toLowerCase() == value){
9805 } else if(value.exec){ // regex?
9806 for(var i = 0, len = ss.length; i < len; i++){
9808 if(value.test(o[property])){
9815 this.jsonData = data;
9821 * Filter by a function. The passed function will be called with each
9822 * object in the current dataset. If the function returns true the value is kept,
9823 * otherwise it is filtered.
9824 * @param {Function} fn
9825 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9827 filterBy : function(fn, scope){
9830 var ss = this.snapshot;
9831 for(var i = 0, len = ss.length; i < len; i++){
9833 if(fn.call(scope || this, o)){
9837 this.jsonData = data;
9843 * Clears the current filter.
9845 clearFilter : function(){
9846 if(this.snapshot && this.jsonData != this.snapshot){
9847 this.jsonData = this.snapshot;
9854 * Sorts the data for this view and refreshes it.
9855 * @param {String} property A property on your JSON objects to sort on
9856 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9857 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9859 sort : function(property, dir, sortType){
9860 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9863 var dsc = dir && dir.toLowerCase() == "desc";
9864 var f = function(o1, o2){
9865 var v1 = sortType ? sortType(o1[p]) : o1[p];
9866 var v2 = sortType ? sortType(o2[p]) : o2[p];
9869 return dsc ? +1 : -1;
9871 return dsc ? -1 : +1;
9876 this.jsonData.sort(f);
9878 if(this.jsonData != this.snapshot){
9879 this.snapshot.sort(f);
9885 * Ext JS Library 1.1.1
9886 * Copyright(c) 2006-2007, Ext JS, LLC.
9888 * Originally Released Under LGPL - original licence link has changed is not relivant.
9891 * <script type="text/javascript">
9896 * @class Roo.ColorPalette
9897 * @extends Roo.Component
9898 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9899 * Here's an example of typical usage:
9901 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9902 cp.render('my-div');
9904 cp.on('select', function(palette, selColor){
9905 // do something with selColor
9909 * Create a new ColorPalette
9910 * @param {Object} config The config object
9912 Roo.ColorPalette = function(config){
9913 Roo.ColorPalette.superclass.constructor.call(this, config);
9917 * Fires when a color is selected
9918 * @param {ColorPalette} this
9919 * @param {String} color The 6-digit color hex code (without the # symbol)
9925 this.on("select", this.handler, this.scope, true);
9928 Roo.extend(Roo.ColorPalette, Roo.Component, {
9930 * @cfg {String} itemCls
9931 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9933 itemCls : "x-color-palette",
9935 * @cfg {String} value
9936 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9937 * the hex codes are case-sensitive.
9942 ctype: "Roo.ColorPalette",
9945 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9947 allowReselect : false,
9950 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9951 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9952 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9953 * of colors with the width setting until the box is symmetrical.</p>
9954 * <p>You can override individual colors if needed:</p>
9956 var cp = new Roo.ColorPalette();
9957 cp.colors[0] = "FF0000"; // change the first box to red
9960 Or you can provide a custom array of your own for complete control:
9962 var cp = new Roo.ColorPalette();
9963 cp.colors = ["000000", "993300", "333300"];
9968 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9969 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9970 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9971 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9972 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9976 onRender : function(container, position){
9977 var t = new Roo.MasterTemplate(
9978 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9980 var c = this.colors;
9981 for(var i = 0, len = c.length; i < len; i++){
9984 var el = document.createElement("div");
9985 el.className = this.itemCls;
9987 container.dom.insertBefore(el, position);
9988 this.el = Roo.get(el);
9989 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9990 if(this.clickEvent != 'click'){
9991 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9996 afterRender : function(){
9997 Roo.ColorPalette.superclass.afterRender.call(this);
10006 handleClick : function(e, t){
10007 e.preventDefault();
10008 if(!this.disabled){
10009 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10010 this.select(c.toUpperCase());
10015 * Selects the specified color in the palette (fires the select event)
10016 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10018 select : function(color){
10019 color = color.replace("#", "");
10020 if(color != this.value || this.allowReselect){
10023 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10025 el.child("a.color-"+color).addClass("x-color-palette-sel");
10026 this.value = color;
10027 this.fireEvent("select", this, color);
10032 * Ext JS Library 1.1.1
10033 * Copyright(c) 2006-2007, Ext JS, LLC.
10035 * Originally Released Under LGPL - original licence link has changed is not relivant.
10038 * <script type="text/javascript">
10042 * @class Roo.DatePicker
10043 * @extends Roo.Component
10044 * Simple date picker class.
10046 * Create a new DatePicker
10047 * @param {Object} config The config object
10049 Roo.DatePicker = function(config){
10050 Roo.DatePicker.superclass.constructor.call(this, config);
10052 this.value = config && config.value ?
10053 config.value.clearTime() : new Date().clearTime();
10058 * Fires when a date is selected
10059 * @param {DatePicker} this
10060 * @param {Date} date The selected date
10066 this.on("select", this.handler, this.scope || this);
10068 // build the disabledDatesRE
10069 if(!this.disabledDatesRE && this.disabledDates){
10070 var dd = this.disabledDates;
10072 for(var i = 0; i < dd.length; i++){
10074 if(i != dd.length-1) re += "|";
10076 this.disabledDatesRE = new RegExp(re + ")");
10080 Roo.extend(Roo.DatePicker, Roo.Component, {
10082 * @cfg {String} todayText
10083 * The text to display on the button that selects the current date (defaults to "Today")
10085 todayText : "Today",
10087 * @cfg {String} okText
10088 * The text to display on the ok button
10090 okText : " OK ", //   to give the user extra clicking room
10092 * @cfg {String} cancelText
10093 * The text to display on the cancel button
10095 cancelText : "Cancel",
10097 * @cfg {String} todayTip
10098 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10100 todayTip : "{0} (Spacebar)",
10102 * @cfg {Date} minDate
10103 * Minimum allowable date (JavaScript date object, defaults to null)
10107 * @cfg {Date} maxDate
10108 * Maximum allowable date (JavaScript date object, defaults to null)
10112 * @cfg {String} minText
10113 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10115 minText : "This date is before the minimum date",
10117 * @cfg {String} maxText
10118 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10120 maxText : "This date is after the maximum date",
10122 * @cfg {String} format
10123 * The default date format string which can be overriden for localization support. The format must be
10124 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10128 * @cfg {Array} disabledDays
10129 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10131 disabledDays : null,
10133 * @cfg {String} disabledDaysText
10134 * The tooltip to display when the date falls on a disabled day (defaults to "")
10136 disabledDaysText : "",
10138 * @cfg {RegExp} disabledDatesRE
10139 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10141 disabledDatesRE : null,
10143 * @cfg {String} disabledDatesText
10144 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10146 disabledDatesText : "",
10148 * @cfg {Boolean} constrainToViewport
10149 * True to constrain the date picker to the viewport (defaults to true)
10151 constrainToViewport : true,
10153 * @cfg {Array} monthNames
10154 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10156 monthNames : Date.monthNames,
10158 * @cfg {Array} dayNames
10159 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10161 dayNames : Date.dayNames,
10163 * @cfg {String} nextText
10164 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10166 nextText: 'Next Month (Control+Right)',
10168 * @cfg {String} prevText
10169 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10171 prevText: 'Previous Month (Control+Left)',
10173 * @cfg {String} monthYearText
10174 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10176 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10178 * @cfg {Number} startDay
10179 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10183 * @cfg {Bool} showClear
10184 * Show a clear button (usefull for date form elements that can be blank.)
10190 * Sets the value of the date field
10191 * @param {Date} value The date to set
10193 setValue : function(value){
10194 var old = this.value;
10195 this.value = value.clearTime(true);
10197 this.update(this.value);
10202 * Gets the current selected value of the date field
10203 * @return {Date} The selected date
10205 getValue : function(){
10210 focus : function(){
10212 this.update(this.activeDate);
10217 onRender : function(container, position){
10219 '<table cellspacing="0">',
10220 '<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>',
10221 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10222 var dn = this.dayNames;
10223 for(var i = 0; i < 7; i++){
10224 var d = this.startDay+i;
10228 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10230 m[m.length] = "</tr></thead><tbody><tr>";
10231 for(var i = 0; i < 42; i++) {
10232 if(i % 7 == 0 && i != 0){
10233 m[m.length] = "</tr><tr>";
10235 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10237 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10238 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10240 var el = document.createElement("div");
10241 el.className = "x-date-picker";
10242 el.innerHTML = m.join("");
10244 container.dom.insertBefore(el, position);
10246 this.el = Roo.get(el);
10247 this.eventEl = Roo.get(el.firstChild);
10249 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10250 handler: this.showPrevMonth,
10252 preventDefault:true,
10256 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10257 handler: this.showNextMonth,
10259 preventDefault:true,
10263 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10265 this.monthPicker = this.el.down('div.x-date-mp');
10266 this.monthPicker.enableDisplayMode('block');
10268 var kn = new Roo.KeyNav(this.eventEl, {
10269 "left" : function(e){
10271 this.showPrevMonth() :
10272 this.update(this.activeDate.add("d", -1));
10275 "right" : function(e){
10277 this.showNextMonth() :
10278 this.update(this.activeDate.add("d", 1));
10281 "up" : function(e){
10283 this.showNextYear() :
10284 this.update(this.activeDate.add("d", -7));
10287 "down" : function(e){
10289 this.showPrevYear() :
10290 this.update(this.activeDate.add("d", 7));
10293 "pageUp" : function(e){
10294 this.showNextMonth();
10297 "pageDown" : function(e){
10298 this.showPrevMonth();
10301 "enter" : function(e){
10302 e.stopPropagation();
10309 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10311 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10313 this.el.unselectable();
10315 this.cells = this.el.select("table.x-date-inner tbody td");
10316 this.textNodes = this.el.query("table.x-date-inner tbody span");
10318 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10320 tooltip: this.monthYearText
10323 this.mbtn.on('click', this.showMonthPicker, this);
10324 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10327 var today = (new Date()).dateFormat(this.format);
10329 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10330 if (this.showClear) {
10331 baseTb.add( new Roo.Toolbar.Fill());
10334 text: String.format(this.todayText, today),
10335 tooltip: String.format(this.todayTip, today),
10336 handler: this.selectToday,
10340 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10343 if (this.showClear) {
10345 baseTb.add( new Roo.Toolbar.Fill());
10348 cls: 'x-btn-icon x-btn-clear',
10349 handler: function() {
10351 this.fireEvent("select", this, '');
10361 this.update(this.value);
10364 createMonthPicker : function(){
10365 if(!this.monthPicker.dom.firstChild){
10366 var buf = ['<table border="0" cellspacing="0">'];
10367 for(var i = 0; i < 6; i++){
10369 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10370 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10372 '<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>' :
10373 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10377 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10379 '</button><button type="button" class="x-date-mp-cancel">',
10381 '</button></td></tr>',
10384 this.monthPicker.update(buf.join(''));
10385 this.monthPicker.on('click', this.onMonthClick, this);
10386 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10388 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10389 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10391 this.mpMonths.each(function(m, a, i){
10394 m.dom.xmonth = 5 + Math.round(i * .5);
10396 m.dom.xmonth = Math.round((i-1) * .5);
10402 showMonthPicker : function(){
10403 this.createMonthPicker();
10404 var size = this.el.getSize();
10405 this.monthPicker.setSize(size);
10406 this.monthPicker.child('table').setSize(size);
10408 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10409 this.updateMPMonth(this.mpSelMonth);
10410 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10411 this.updateMPYear(this.mpSelYear);
10413 this.monthPicker.slideIn('t', {duration:.2});
10416 updateMPYear : function(y){
10418 var ys = this.mpYears.elements;
10419 for(var i = 1; i <= 10; i++){
10420 var td = ys[i-1], y2;
10422 y2 = y + Math.round(i * .5);
10423 td.firstChild.innerHTML = y2;
10426 y2 = y - (5-Math.round(i * .5));
10427 td.firstChild.innerHTML = y2;
10430 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10434 updateMPMonth : function(sm){
10435 this.mpMonths.each(function(m, a, i){
10436 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10440 selectMPMonth: function(m){
10444 onMonthClick : function(e, t){
10446 var el = new Roo.Element(t), pn;
10447 if(el.is('button.x-date-mp-cancel')){
10448 this.hideMonthPicker();
10450 else if(el.is('button.x-date-mp-ok')){
10451 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10452 this.hideMonthPicker();
10454 else if(pn = el.up('td.x-date-mp-month', 2)){
10455 this.mpMonths.removeClass('x-date-mp-sel');
10456 pn.addClass('x-date-mp-sel');
10457 this.mpSelMonth = pn.dom.xmonth;
10459 else if(pn = el.up('td.x-date-mp-year', 2)){
10460 this.mpYears.removeClass('x-date-mp-sel');
10461 pn.addClass('x-date-mp-sel');
10462 this.mpSelYear = pn.dom.xyear;
10464 else if(el.is('a.x-date-mp-prev')){
10465 this.updateMPYear(this.mpyear-10);
10467 else if(el.is('a.x-date-mp-next')){
10468 this.updateMPYear(this.mpyear+10);
10472 onMonthDblClick : function(e, t){
10474 var el = new Roo.Element(t), pn;
10475 if(pn = el.up('td.x-date-mp-month', 2)){
10476 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10477 this.hideMonthPicker();
10479 else if(pn = el.up('td.x-date-mp-year', 2)){
10480 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10481 this.hideMonthPicker();
10485 hideMonthPicker : function(disableAnim){
10486 if(this.monthPicker){
10487 if(disableAnim === true){
10488 this.monthPicker.hide();
10490 this.monthPicker.slideOut('t', {duration:.2});
10496 showPrevMonth : function(e){
10497 this.update(this.activeDate.add("mo", -1));
10501 showNextMonth : function(e){
10502 this.update(this.activeDate.add("mo", 1));
10506 showPrevYear : function(){
10507 this.update(this.activeDate.add("y", -1));
10511 showNextYear : function(){
10512 this.update(this.activeDate.add("y", 1));
10516 handleMouseWheel : function(e){
10517 var delta = e.getWheelDelta();
10519 this.showPrevMonth();
10521 } else if(delta < 0){
10522 this.showNextMonth();
10528 handleDateClick : function(e, t){
10530 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10531 this.setValue(new Date(t.dateValue));
10532 this.fireEvent("select", this, this.value);
10537 selectToday : function(){
10538 this.setValue(new Date().clearTime());
10539 this.fireEvent("select", this, this.value);
10543 update : function(date){
10544 var vd = this.activeDate;
10545 this.activeDate = date;
10547 var t = date.getTime();
10548 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10549 this.cells.removeClass("x-date-selected");
10550 this.cells.each(function(c){
10551 if(c.dom.firstChild.dateValue == t){
10552 c.addClass("x-date-selected");
10553 setTimeout(function(){
10554 try{c.dom.firstChild.focus();}catch(e){}
10562 var days = date.getDaysInMonth();
10563 var firstOfMonth = date.getFirstDateOfMonth();
10564 var startingPos = firstOfMonth.getDay()-this.startDay;
10566 if(startingPos <= this.startDay){
10570 var pm = date.add("mo", -1);
10571 var prevStart = pm.getDaysInMonth()-startingPos;
10573 var cells = this.cells.elements;
10574 var textEls = this.textNodes;
10575 days += startingPos;
10577 // convert everything to numbers so it's fast
10578 var day = 86400000;
10579 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10580 var today = new Date().clearTime().getTime();
10581 var sel = date.clearTime().getTime();
10582 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10583 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10584 var ddMatch = this.disabledDatesRE;
10585 var ddText = this.disabledDatesText;
10586 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10587 var ddaysText = this.disabledDaysText;
10588 var format = this.format;
10590 var setCellClass = function(cal, cell){
10592 var t = d.getTime();
10593 cell.firstChild.dateValue = t;
10595 cell.className += " x-date-today";
10596 cell.title = cal.todayText;
10599 cell.className += " x-date-selected";
10600 setTimeout(function(){
10601 try{cell.firstChild.focus();}catch(e){}
10606 cell.className = " x-date-disabled";
10607 cell.title = cal.minText;
10611 cell.className = " x-date-disabled";
10612 cell.title = cal.maxText;
10616 if(ddays.indexOf(d.getDay()) != -1){
10617 cell.title = ddaysText;
10618 cell.className = " x-date-disabled";
10621 if(ddMatch && format){
10622 var fvalue = d.dateFormat(format);
10623 if(ddMatch.test(fvalue)){
10624 cell.title = ddText.replace("%0", fvalue);
10625 cell.className = " x-date-disabled";
10631 for(; i < startingPos; i++) {
10632 textEls[i].innerHTML = (++prevStart);
10633 d.setDate(d.getDate()+1);
10634 cells[i].className = "x-date-prevday";
10635 setCellClass(this, cells[i]);
10637 for(; i < days; i++){
10638 intDay = i - startingPos + 1;
10639 textEls[i].innerHTML = (intDay);
10640 d.setDate(d.getDate()+1);
10641 cells[i].className = "x-date-active";
10642 setCellClass(this, cells[i]);
10645 for(; i < 42; i++) {
10646 textEls[i].innerHTML = (++extraDays);
10647 d.setDate(d.getDate()+1);
10648 cells[i].className = "x-date-nextday";
10649 setCellClass(this, cells[i]);
10652 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10654 if(!this.internalRender){
10655 var main = this.el.dom.firstChild;
10656 var w = main.offsetWidth;
10657 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10658 Roo.fly(main).setWidth(w);
10659 this.internalRender = true;
10660 // opera does not respect the auto grow header center column
10661 // then, after it gets a width opera refuses to recalculate
10662 // without a second pass
10663 if(Roo.isOpera && !this.secondPass){
10664 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10665 this.secondPass = true;
10666 this.update.defer(10, this, [date]);
10672 * Ext JS Library 1.1.1
10673 * Copyright(c) 2006-2007, Ext JS, LLC.
10675 * Originally Released Under LGPL - original licence link has changed is not relivant.
10678 * <script type="text/javascript">
10681 * @class Roo.TabPanel
10682 * @extends Roo.util.Observable
10683 * A lightweight tab container.
10687 // basic tabs 1, built from existing content
10688 var tabs = new Roo.TabPanel("tabs1");
10689 tabs.addTab("script", "View Script");
10690 tabs.addTab("markup", "View Markup");
10691 tabs.activate("script");
10693 // more advanced tabs, built from javascript
10694 var jtabs = new Roo.TabPanel("jtabs");
10695 jtabs.addTab("jtabs-1", "Normal Tab", "My content was added during construction.");
10697 // set up the UpdateManager
10698 var tab2 = jtabs.addTab("jtabs-2", "Ajax Tab 1");
10699 var updater = tab2.getUpdateManager();
10700 updater.setDefaultUrl("ajax1.htm");
10701 tab2.on('activate', updater.refresh, updater, true);
10703 // Use setUrl for Ajax loading
10704 var tab3 = jtabs.addTab("jtabs-3", "Ajax Tab 2");
10705 tab3.setUrl("ajax2.htm", null, true);
10708 var tab4 = jtabs.addTab("tabs1-5", "Disabled Tab", "Can't see me cause I'm disabled");
10711 jtabs.activate("jtabs-1");
10714 * Create a new TabPanel.
10715 * @param {String/HTMLElement/Roo.Element} container The id, DOM element or Roo.Element container where this TabPanel is to be rendered.
10716 * @param {Object/Boolean} config Config object to set any properties for this TabPanel, or true to render the tabs on the bottom.
10718 Roo.TabPanel = function(container, config){
10720 * The container element for this TabPanel.
10721 * @type Roo.Element
10723 this.el = Roo.get(container, true);
10725 if(typeof config == "boolean"){
10726 this.tabPosition = config ? "bottom" : "top";
10728 Roo.apply(this, config);
10731 if(this.tabPosition == "bottom"){
10732 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10733 this.el.addClass("x-tabs-bottom");
10735 this.stripWrap = Roo.get(this.createStrip(this.el.dom), true);
10736 this.stripEl = Roo.get(this.createStripList(this.stripWrap.dom), true);
10737 this.stripBody = Roo.get(this.stripWrap.dom.firstChild.firstChild, true);
10739 Roo.fly(this.stripWrap.dom.firstChild).setStyle("overflow-x", "hidden");
10741 if(this.tabPosition != "bottom"){
10742 /** The body element that contains {@link Roo.TabPanelItem} bodies.
10743 * @type Roo.Element
10745 this.bodyEl = Roo.get(this.createBody(this.el.dom));
10746 this.el.addClass("x-tabs-top");
10750 this.bodyEl.setStyle("position", "relative");
10752 this.active = null;
10753 this.activateDelegate = this.activate.createDelegate(this);
10758 * Fires when the active tab changes
10759 * @param {Roo.TabPanel} this
10760 * @param {Roo.TabPanelItem} activePanel The new active tab
10764 * @event beforetabchange
10765 * Fires before the active tab changes, set cancel to true on the "e" parameter to cancel the change
10766 * @param {Roo.TabPanel} this
10767 * @param {Object} e Set cancel to true on this object to cancel the tab change
10768 * @param {Roo.TabPanelItem} tab The tab being changed to
10770 "beforetabchange" : true
10773 Roo.EventManager.onWindowResize(this.onResize, this);
10774 this.cpad = this.el.getPadding("lr");
10775 this.hiddenCount = 0;
10777 Roo.TabPanel.superclass.constructor.call(this);
10780 Roo.extend(Roo.TabPanel, Roo.util.Observable, {
10782 *@cfg {String} tabPosition "top" or "bottom" (defaults to "top")
10784 tabPosition : "top",
10786 *@cfg {Number} currentTabWidth The width of the current tab (defaults to 0)
10788 currentTabWidth : 0,
10790 *@cfg {Number} minTabWidth The minimum width of a tab (defaults to 40) (ignored if {@link #resizeTabs} is not true)
10794 *@cfg {Number} maxTabWidth The maximum width of a tab (defaults to 250) (ignored if {@link #resizeTabs} is not true)
10798 *@cfg {Number} preferredTabWidth The preferred (default) width of a tab (defaults to 175) (ignored if {@link #resizeTabs} is not true)
10800 preferredTabWidth : 175,
10802 *@cfg {Boolean} resizeTabs True to enable dynamic tab resizing (defaults to false)
10804 resizeTabs : false,
10806 *@cfg {Boolean} monitorResize Set this to true to turn on window resize monitoring (ignored if {@link #resizeTabs} is not true) (defaults to true)
10808 monitorResize : true,
10811 * Creates a new {@link Roo.TabPanelItem} by looking for an existing element with the provided id -- if it's not found it creates one.
10812 * @param {String} id The id of the div to use <b>or create</b>
10813 * @param {String} text The text for the tab
10814 * @param {String} content (optional) Content to put in the TabPanelItem body
10815 * @param {Boolean} closable (optional) True to create a close icon on the tab
10816 * @return {Roo.TabPanelItem} The created TabPanelItem
10818 addTab : function(id, text, content, closable){
10819 var item = new Roo.TabPanelItem(this, id, text, closable);
10820 this.addTabItem(item);
10822 item.setContent(content);
10828 * Returns the {@link Roo.TabPanelItem} with the specified id/index
10829 * @param {String/Number} id The id or index of the TabPanelItem to fetch.
10830 * @return {Roo.TabPanelItem}
10832 getTab : function(id){
10833 return this.items[id];
10837 * Hides the {@link Roo.TabPanelItem} with the specified id/index
10838 * @param {String/Number} id The id or index of the TabPanelItem to hide.
10840 hideTab : function(id){
10841 var t = this.items[id];
10844 this.hiddenCount++;
10845 this.autoSizeTabs();
10850 * "Unhides" the {@link Roo.TabPanelItem} with the specified id/index.
10851 * @param {String/Number} id The id or index of the TabPanelItem to unhide.
10853 unhideTab : function(id){
10854 var t = this.items[id];
10856 t.setHidden(false);
10857 this.hiddenCount--;
10858 this.autoSizeTabs();
10863 * Adds an existing {@link Roo.TabPanelItem}.
10864 * @param {Roo.TabPanelItem} item The TabPanelItem to add
10866 addTabItem : function(item){
10867 this.items[item.id] = item;
10868 this.items.push(item);
10869 if(this.resizeTabs){
10870 item.setWidth(this.currentTabWidth || this.preferredTabWidth);
10871 this.autoSizeTabs();
10878 * Removes a {@link Roo.TabPanelItem}.
10879 * @param {String/Number} id The id or index of the TabPanelItem to remove.
10881 removeTab : function(id){
10882 var items = this.items;
10883 var tab = items[id];
10884 if(!tab) { return; }
10885 var index = items.indexOf(tab);
10886 if(this.active == tab && items.length > 1){
10887 var newTab = this.getNextAvailable(index);
10892 this.stripEl.dom.removeChild(tab.pnode.dom);
10893 if(tab.bodyEl.dom.parentNode == this.bodyEl.dom){ // if it was moved already prevent error
10894 this.bodyEl.dom.removeChild(tab.bodyEl.dom);
10896 items.splice(index, 1);
10897 delete this.items[tab.id];
10898 tab.fireEvent("close", tab);
10899 tab.purgeListeners();
10900 this.autoSizeTabs();
10903 getNextAvailable : function(start){
10904 var items = this.items;
10906 // look for a next tab that will slide over to
10907 // replace the one being removed
10908 while(index < items.length){
10909 var item = items[++index];
10910 if(item && !item.isHidden()){
10914 // if one isn't found select the previous tab (on the left)
10917 var item = items[--index];
10918 if(item && !item.isHidden()){
10926 * Disables a {@link Roo.TabPanelItem}. It cannot be the active tab, if it is this call is ignored.
10927 * @param {String/Number} id The id or index of the TabPanelItem to disable.
10929 disableTab : function(id){
10930 var tab = this.items[id];
10931 if(tab && this.active != tab){
10937 * Enables a {@link Roo.TabPanelItem} that is disabled.
10938 * @param {String/Number} id The id or index of the TabPanelItem to enable.
10940 enableTab : function(id){
10941 var tab = this.items[id];
10946 * Activates a {@link Roo.TabPanelItem}. The currently active one will be deactivated.
10947 * @param {String/Number} id The id or index of the TabPanelItem to activate.
10948 * @return {Roo.TabPanelItem} The TabPanelItem.
10950 activate : function(id){
10951 var tab = this.items[id];
10955 if(tab == this.active || tab.disabled){
10959 this.fireEvent("beforetabchange", this, e, tab);
10960 if(e.cancel !== true && !tab.disabled){
10962 this.active.hide();
10964 this.active = this.items[id];
10965 this.active.show();
10966 this.fireEvent("tabchange", this, this.active);
10972 * Gets the active {@link Roo.TabPanelItem}.
10973 * @return {Roo.TabPanelItem} The active TabPanelItem or null if none are active.
10975 getActiveTab : function(){
10976 return this.active;
10980 * Updates the tab body element to fit the height of the container element
10981 * for overflow scrolling
10982 * @param {Number} targetHeight (optional) Override the starting height from the elements height
10984 syncHeight : function(targetHeight){
10985 var height = (targetHeight || this.el.getHeight())-this.el.getBorderWidth("tb")-this.el.getPadding("tb");
10986 var bm = this.bodyEl.getMargins();
10987 var newHeight = height-(this.stripWrap.getHeight()||0)-(bm.top+bm.bottom);
10988 this.bodyEl.setHeight(newHeight);
10992 onResize : function(){
10993 if(this.monitorResize){
10994 this.autoSizeTabs();
10999 * Disables tab resizing while tabs are being added (if {@link #resizeTabs} is false this does nothing)
11001 beginUpdate : function(){
11002 this.updating = true;
11006 * Stops an update and resizes the tabs (if {@link #resizeTabs} is false this does nothing)
11008 endUpdate : function(){
11009 this.updating = false;
11010 this.autoSizeTabs();
11014 * Manual call to resize the tabs (if {@link #resizeTabs} is false this does nothing)
11016 autoSizeTabs : function(){
11017 var count = this.items.length;
11018 var vcount = count - this.hiddenCount;
11019 if(!this.resizeTabs || count < 1 || vcount < 1 || this.updating) return;
11020 var w = Math.max(this.el.getWidth() - this.cpad, 10);
11021 var availWidth = Math.floor(w / vcount);
11022 var b = this.stripBody;
11023 if(b.getWidth() > w){
11024 var tabs = this.items;
11025 this.setTabWidth(Math.max(availWidth, this.minTabWidth)-2);
11026 if(availWidth < this.minTabWidth){
11027 /*if(!this.sleft){ // incomplete scrolling code
11028 this.createScrollButtons();
11031 this.stripClip.setWidth(w - (this.sleft.getWidth()+this.sright.getWidth()));*/
11034 if(this.currentTabWidth < this.preferredTabWidth){
11035 this.setTabWidth(Math.min(availWidth, this.preferredTabWidth)-2);
11041 * Returns the number of tabs in this TabPanel.
11044 getCount : function(){
11045 return this.items.length;
11049 * Resizes all the tabs to the passed width
11050 * @param {Number} The new width
11052 setTabWidth : function(width){
11053 this.currentTabWidth = width;
11054 for(var i = 0, len = this.items.length; i < len; i++) {
11055 if(!this.items[i].isHidden())this.items[i].setWidth(width);
11060 * Destroys this TabPanel
11061 * @param {Boolean} removeEl (optional) True to remove the element from the DOM as well (defaults to undefined)
11063 destroy : function(removeEl){
11064 Roo.EventManager.removeResizeListener(this.onResize, this);
11065 for(var i = 0, len = this.items.length; i < len; i++){
11066 this.items[i].purgeListeners();
11068 if(removeEl === true){
11069 this.el.update("");
11076 * @class Roo.TabPanelItem
11077 * @extends Roo.util.Observable
11078 * Represents an individual item (tab plus body) in a TabPanel.
11079 * @param {Roo.TabPanel} tabPanel The {@link Roo.TabPanel} this TabPanelItem belongs to
11080 * @param {String} id The id of this TabPanelItem
11081 * @param {String} text The text for the tab of this TabPanelItem
11082 * @param {Boolean} closable True to allow this TabPanelItem to be closable (defaults to false)
11084 Roo.TabPanelItem = function(tabPanel, id, text, closable){
11086 * The {@link Roo.TabPanel} this TabPanelItem belongs to
11087 * @type Roo.TabPanel
11089 this.tabPanel = tabPanel;
11091 * The id for this TabPanelItem
11096 this.disabled = false;
11100 this.loaded = false;
11101 this.closable = closable;
11104 * The body element for this TabPanelItem.
11105 * @type Roo.Element
11107 this.bodyEl = Roo.get(tabPanel.createItemBody(tabPanel.bodyEl.dom, id));
11108 this.bodyEl.setVisibilityMode(Roo.Element.VISIBILITY);
11109 this.bodyEl.setStyle("display", "block");
11110 this.bodyEl.setStyle("zoom", "1");
11113 var els = tabPanel.createStripElements(tabPanel.stripEl.dom, text, closable);
11115 this.el = Roo.get(els.el, true);
11116 this.inner = Roo.get(els.inner, true);
11117 this.textEl = Roo.get(this.el.dom.firstChild.firstChild.firstChild, true);
11118 this.pnode = Roo.get(els.el.parentNode, true);
11119 this.el.on("mousedown", this.onTabMouseDown, this);
11120 this.el.on("click", this.onTabClick, this);
11123 var c = Roo.get(els.close, true);
11124 c.dom.title = this.closeText;
11125 c.addClassOnOver("close-over");
11126 c.on("click", this.closeClick, this);
11132 * Fires when this tab becomes the active tab.
11133 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11134 * @param {Roo.TabPanelItem} this
11138 * @event beforeclose
11139 * Fires before this tab is closed. To cancel the close, set cancel to true on e (e.cancel = true).
11140 * @param {Roo.TabPanelItem} this
11141 * @param {Object} e Set cancel to true on this object to cancel the close.
11143 "beforeclose": true,
11146 * Fires when this tab is closed.
11147 * @param {Roo.TabPanelItem} this
11151 * @event deactivate
11152 * Fires when this tab is no longer the active tab.
11153 * @param {Roo.TabPanel} tabPanel The parent TabPanel
11154 * @param {Roo.TabPanelItem} this
11156 "deactivate" : true
11158 this.hidden = false;
11160 Roo.TabPanelItem.superclass.constructor.call(this);
11163 Roo.extend(Roo.TabPanelItem, Roo.util.Observable, {
11164 purgeListeners : function(){
11165 Roo.util.Observable.prototype.purgeListeners.call(this);
11166 this.el.removeAllListeners();
11169 * Shows this TabPanelItem -- this <b>does not</b> deactivate the currently active TabPanelItem.
11172 this.pnode.addClass("on");
11175 this.tabPanel.stripWrap.repaint();
11177 this.fireEvent("activate", this.tabPanel, this);
11181 * Returns true if this tab is the active tab.
11182 * @return {Boolean}
11184 isActive : function(){
11185 return this.tabPanel.getActiveTab() == this;
11189 * Hides this TabPanelItem -- if you don't activate another TabPanelItem this could look odd.
11192 this.pnode.removeClass("on");
11194 this.fireEvent("deactivate", this.tabPanel, this);
11197 hideAction : function(){
11198 this.bodyEl.hide();
11199 this.bodyEl.setStyle("position", "absolute");
11200 this.bodyEl.setLeft("-20000px");
11201 this.bodyEl.setTop("-20000px");
11204 showAction : function(){
11205 this.bodyEl.setStyle("position", "relative");
11206 this.bodyEl.setTop("");
11207 this.bodyEl.setLeft("");
11208 this.bodyEl.show();
11212 * Set the tooltip for the tab.
11213 * @param {String} tooltip The tab's tooltip
11215 setTooltip : function(text){
11216 if(Roo.QuickTips && Roo.QuickTips.isEnabled()){
11217 this.textEl.dom.qtip = text;
11218 this.textEl.dom.removeAttribute('title');
11220 this.textEl.dom.title = text;
11224 onTabClick : function(e){
11225 e.preventDefault();
11226 this.tabPanel.activate(this.id);
11229 onTabMouseDown : function(e){
11230 e.preventDefault();
11231 this.tabPanel.activate(this.id);
11234 getWidth : function(){
11235 return this.inner.getWidth();
11238 setWidth : function(width){
11239 var iwidth = width - this.pnode.getPadding("lr");
11240 this.inner.setWidth(iwidth);
11241 this.textEl.setWidth(iwidth-this.inner.getPadding("lr"));
11242 this.pnode.setWidth(width);
11246 * Show or hide the tab
11247 * @param {Boolean} hidden True to hide or false to show.
11249 setHidden : function(hidden){
11250 this.hidden = hidden;
11251 this.pnode.setStyle("display", hidden ? "none" : "");
11255 * Returns true if this tab is "hidden"
11256 * @return {Boolean}
11258 isHidden : function(){
11259 return this.hidden;
11263 * Returns the text for this tab
11266 getText : function(){
11270 autoSize : function(){
11271 //this.el.beginMeasure();
11272 this.textEl.setWidth(1);
11273 this.setWidth(this.textEl.dom.scrollWidth+this.pnode.getPadding("lr")+this.inner.getPadding("lr"));
11274 //this.el.endMeasure();
11278 * Sets the text for the tab (Note: this also sets the tooltip text)
11279 * @param {String} text The tab's text and tooltip
11281 setText : function(text){
11283 this.textEl.update(text);
11284 this.setTooltip(text);
11285 if(!this.tabPanel.resizeTabs){
11290 * Activates this TabPanelItem -- this <b>does</b> deactivate the currently active TabPanelItem.
11292 activate : function(){
11293 this.tabPanel.activate(this.id);
11297 * Disables this TabPanelItem -- this does nothing if this is the active TabPanelItem.
11299 disable : function(){
11300 if(this.tabPanel.active != this){
11301 this.disabled = true;
11302 this.pnode.addClass("disabled");
11307 * Enables this TabPanelItem if it was previously disabled.
11309 enable : function(){
11310 this.disabled = false;
11311 this.pnode.removeClass("disabled");
11315 * Sets the content for this TabPanelItem.
11316 * @param {String} content The content
11317 * @param {Boolean} loadScripts true to look for and load scripts
11319 setContent : function(content, loadScripts){
11320 this.bodyEl.update(content, loadScripts);
11324 * Gets the {@link Roo.UpdateManager} for the body of this TabPanelItem. Enables you to perform Ajax updates.
11325 * @return {Roo.UpdateManager} The UpdateManager
11327 getUpdateManager : function(){
11328 return this.bodyEl.getUpdateManager();
11332 * Set a URL to be used to load the content for this TabPanelItem.
11333 * @param {String/Function} url The URL to load the content from, or a function to call to get the URL
11334 * @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)
11335 * @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)
11336 * @return {Roo.UpdateManager} The UpdateManager
11338 setUrl : function(url, params, loadOnce){
11339 if(this.refreshDelegate){
11340 this.un('activate', this.refreshDelegate);
11342 this.refreshDelegate = this._handleRefresh.createDelegate(this, [url, params, loadOnce]);
11343 this.on("activate", this.refreshDelegate);
11344 return this.bodyEl.getUpdateManager();
11348 _handleRefresh : function(url, params, loadOnce){
11349 if(!loadOnce || !this.loaded){
11350 var updater = this.bodyEl.getUpdateManager();
11351 updater.update(url, params, this._setLoaded.createDelegate(this));
11356 * Forces a content refresh from the URL specified in the {@link #setUrl} method.
11357 * Will fail silently if the setUrl method has not been called.
11358 * This does not activate the panel, just updates its content.
11360 refresh : function(){
11361 if(this.refreshDelegate){
11362 this.loaded = false;
11363 this.refreshDelegate();
11368 _setLoaded : function(){
11369 this.loaded = true;
11373 closeClick : function(e){
11376 this.fireEvent("beforeclose", this, o);
11377 if(o.cancel !== true){
11378 this.tabPanel.removeTab(this.id);
11382 * The text displayed in the tooltip for the close icon.
11385 closeText : "Close this tab"
11389 Roo.TabPanel.prototype.createStrip = function(container){
11390 var strip = document.createElement("div");
11391 strip.className = "x-tabs-wrap";
11392 container.appendChild(strip);
11396 Roo.TabPanel.prototype.createStripList = function(strip){
11397 // div wrapper for retard IE
11398 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>';
11399 return strip.firstChild.firstChild.firstChild.firstChild;
11402 Roo.TabPanel.prototype.createBody = function(container){
11403 var body = document.createElement("div");
11404 Roo.id(body, "tab-body");
11405 Roo.fly(body).addClass("x-tabs-body");
11406 container.appendChild(body);
11410 Roo.TabPanel.prototype.createItemBody = function(bodyEl, id){
11411 var body = Roo.getDom(id);
11413 body = document.createElement("div");
11416 Roo.fly(body).addClass("x-tabs-item-body");
11417 bodyEl.insertBefore(body, bodyEl.firstChild);
11421 Roo.TabPanel.prototype.createStripElements = function(stripEl, text, closable){
11422 var td = document.createElement("td");
11423 stripEl.appendChild(td);
11425 td.className = "x-tabs-closable";
11426 if(!this.closeTpl){
11427 this.closeTpl = new Roo.Template(
11428 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11429 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span>' +
11430 '<div unselectable="on" class="close-icon"> </div></em></span></a>'
11433 var el = this.closeTpl.overwrite(td, {"text": text});
11434 var close = el.getElementsByTagName("div")[0];
11435 var inner = el.getElementsByTagName("em")[0];
11436 return {"el": el, "close": close, "inner": inner};
11439 this.tabTpl = new Roo.Template(
11440 '<a href="#" class="x-tabs-right"><span class="x-tabs-left"><em class="x-tabs-inner">' +
11441 '<span unselectable="on"' + (this.disableTooltips ? '' : ' title="{text}"') +' class="x-tabs-text">{text}</span></em></span></a>'
11444 var el = this.tabTpl.overwrite(td, {"text": text});
11445 var inner = el.getElementsByTagName("em")[0];
11446 return {"el": el, "inner": inner};
11450 * Ext JS Library 1.1.1
11451 * Copyright(c) 2006-2007, Ext JS, LLC.
11453 * Originally Released Under LGPL - original licence link has changed is not relivant.
11456 * <script type="text/javascript">
11460 * @class Roo.Button
11461 * @extends Roo.util.Observable
11462 * Simple Button class
11463 * @cfg {String} text The button text
11464 * @cfg {String} icon The path to an image to display in the button (the image will be set as the background-image
11465 * CSS property of the button by default, so if you want a mixed icon/text button, set cls:"x-btn-text-icon")
11466 * @cfg {Function} handler A function called when the button is clicked (can be used instead of click event)
11467 * @cfg {Object} scope The scope of the handler
11468 * @cfg {Number} minWidth The minimum width for this button (used to give a set of buttons a common width)
11469 * @cfg {String/Object} tooltip The tooltip for the button - can be a string or QuickTips config object
11470 * @cfg {Boolean} hidden True to start hidden (defaults to false)
11471 * @cfg {Boolean} disabled True to start disabled (defaults to false)
11472 * @cfg {Boolean} pressed True to start pressed (only if enableToggle = true)
11473 * @cfg {String} toggleGroup The group this toggle button is a member of (only 1 per group can be pressed, only
11474 applies if enableToggle = true)
11475 * @cfg {String/HTMLElement/Element} renderTo The element to append the button to
11476 * @cfg {Boolean/Object} repeat True to repeat fire the click event while the mouse is down. This can also be
11477 an {@link Roo.util.ClickRepeater} config object (defaults to false).
11479 * Create a new button
11480 * @param {Object} config The config object
11482 Roo.Button = function(renderTo, config)
11486 renderTo = config.renderTo || false;
11489 Roo.apply(this, config);
11493 * Fires when this button is clicked
11494 * @param {Button} this
11495 * @param {EventObject} e The click event
11500 * Fires when the "pressed" state of this button changes (only if enableToggle = true)
11501 * @param {Button} this
11502 * @param {Boolean} pressed
11507 * Fires when the mouse hovers over the button
11508 * @param {Button} this
11509 * @param {Event} e The event object
11511 'mouseover' : true,
11514 * Fires when the mouse exits the button
11515 * @param {Button} this
11516 * @param {Event} e The event object
11521 * Fires when the button is rendered
11522 * @param {Button} this
11527 this.menu = Roo.menu.MenuMgr.get(this.menu);
11529 // register listeners first!! - so render can be captured..
11530 Roo.util.Observable.call(this);
11532 this.render(renderTo);
11538 Roo.extend(Roo.Button, Roo.util.Observable, {
11544 * Read-only. True if this button is hidden
11549 * Read-only. True if this button is disabled
11554 * Read-only. True if this button is pressed (only if enableToggle = true)
11560 * @cfg {Number} tabIndex
11561 * The DOM tabIndex for this button (defaults to undefined)
11563 tabIndex : undefined,
11566 * @cfg {Boolean} enableToggle
11567 * True to enable pressed/not pressed toggling (defaults to false)
11569 enableToggle: false,
11571 * @cfg {Mixed} menu
11572 * Standard menu attribute consisting of a reference to a menu object, a menu id or a menu config blob (defaults to undefined).
11576 * @cfg {String} menuAlign
11577 * The position to align the menu to (see {@link Roo.Element#alignTo} for more details, defaults to 'tl-bl?').
11579 menuAlign : "tl-bl?",
11582 * @cfg {String} iconCls
11583 * A css class which sets a background image to be used as the icon for this button (defaults to undefined).
11585 iconCls : undefined,
11587 * @cfg {String} type
11588 * The button's type, corresponding to the DOM input element type attribute. Either "submit," "reset" or "button" (default).
11593 menuClassTarget: 'tr',
11596 * @cfg {String} clickEvent
11597 * The type of event to map to the button's event handler (defaults to 'click')
11599 clickEvent : 'click',
11602 * @cfg {Boolean} handleMouseEvents
11603 * False to disable visual cues on mouseover, mouseout and mousedown (defaults to true)
11605 handleMouseEvents : true,
11608 * @cfg {String} tooltipType
11609 * The type of tooltip to use. Either "qtip" (default) for QuickTips or "title" for title attribute.
11611 tooltipType : 'qtip',
11614 * @cfg {String} cls
11615 * A CSS class to apply to the button's main element.
11619 * @cfg {Roo.Template} template (Optional)
11620 * An {@link Roo.Template} with which to create the Button's main element. This Template must
11621 * contain numeric substitution parameter 0 if it is to display the tRoo property. Changing the template could
11622 * require code modifications if required elements (e.g. a button) aren't present.
11626 render : function(renderTo){
11628 if(this.hideParent){
11629 this.parentEl = Roo.get(renderTo);
11631 if(!this.dhconfig){
11632 if(!this.template){
11633 if(!Roo.Button.buttonTemplate){
11634 // hideous table template
11635 Roo.Button.buttonTemplate = new Roo.Template(
11636 '<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>',
11637 '<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>',
11638 "</tr></tbody></table>");
11640 this.template = Roo.Button.buttonTemplate;
11642 btn = this.template.append(renderTo, [this.text || ' ', this.type], true);
11643 var btnEl = btn.child("button:first");
11644 btnEl.on('focus', this.onFocus, this);
11645 btnEl.on('blur', this.onBlur, this);
11647 btn.addClass(this.cls);
11650 btnEl.setStyle('background-image', 'url(' +this.icon +')');
11653 btnEl.addClass(this.iconCls);
11655 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
11658 if(this.tabIndex !== undefined){
11659 btnEl.dom.tabIndex = this.tabIndex;
11662 if(typeof this.tooltip == 'object'){
11663 Roo.QuickTips.tips(Roo.apply({
11667 btnEl.dom[this.tooltipType] = this.tooltip;
11671 btn = Roo.DomHelper.append(Roo.get(renderTo).dom, this.dhconfig, true);
11675 this.el.dom.id = this.el.id = this.id;
11678 this.el.child(this.menuClassTarget).addClass("x-btn-with-menu");
11679 this.menu.on("show", this.onMenuShow, this);
11680 this.menu.on("hide", this.onMenuHide, this);
11682 btn.addClass("x-btn");
11683 if(Roo.isIE && !Roo.isIE7){
11684 this.autoWidth.defer(1, this);
11688 if(this.handleMouseEvents){
11689 btn.on("mouseover", this.onMouseOver, this);
11690 btn.on("mouseout", this.onMouseOut, this);
11691 btn.on("mousedown", this.onMouseDown, this);
11693 btn.on(this.clickEvent, this.onClick, this);
11694 //btn.on("mouseup", this.onMouseUp, this);
11701 Roo.ButtonToggleMgr.register(this);
11703 this.el.addClass("x-btn-pressed");
11706 var repeater = new Roo.util.ClickRepeater(btn,
11707 typeof this.repeat == "object" ? this.repeat : {}
11709 repeater.on("click", this.onClick, this);
11712 this.fireEvent('render', this);
11716 * Returns the button's underlying element
11717 * @return {Roo.Element} The element
11719 getEl : function(){
11724 * Destroys this Button and removes any listeners.
11726 destroy : function(){
11727 Roo.ButtonToggleMgr.unregister(this);
11728 this.el.removeAllListeners();
11729 this.purgeListeners();
11734 autoWidth : function(){
11736 this.el.setWidth("auto");
11737 if(Roo.isIE7 && Roo.isStrict){
11738 var ib = this.el.child('button');
11739 if(ib && ib.getWidth() > 20){
11741 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
11746 this.el.beginMeasure();
11748 if(this.el.getWidth() < this.minWidth){
11749 this.el.setWidth(this.minWidth);
11752 this.el.endMeasure();
11759 * Assigns this button's click handler
11760 * @param {Function} handler The function to call when the button is clicked
11761 * @param {Object} scope (optional) Scope for the function passed in
11763 setHandler : function(handler, scope){
11764 this.handler = handler;
11765 this.scope = scope;
11769 * Sets this button's text
11770 * @param {String} text The button text
11772 setText : function(text){
11775 this.el.child("td.x-btn-center button.x-btn-text").update(text);
11781 * Gets the text for this button
11782 * @return {String} The button text
11784 getText : function(){
11792 this.hidden = false;
11794 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "");
11802 this.hidden = true;
11804 this[this.hideParent? 'parentEl' : 'el'].setStyle("display", "none");
11809 * Convenience function for boolean show/hide
11810 * @param {Boolean} visible True to show, false to hide
11812 setVisible: function(visible){
11821 * If a state it passed, it becomes the pressed state otherwise the current state is toggled.
11822 * @param {Boolean} state (optional) Force a particular state
11824 toggle : function(state){
11825 state = state === undefined ? !this.pressed : state;
11826 if(state != this.pressed){
11828 this.el.addClass("x-btn-pressed");
11829 this.pressed = true;
11830 this.fireEvent("toggle", this, true);
11832 this.el.removeClass("x-btn-pressed");
11833 this.pressed = false;
11834 this.fireEvent("toggle", this, false);
11836 if(this.toggleHandler){
11837 this.toggleHandler.call(this.scope || this, this, state);
11845 focus : function(){
11846 this.el.child('button:first').focus();
11850 * Disable this button
11852 disable : function(){
11854 this.el.addClass("x-btn-disabled");
11856 this.disabled = true;
11860 * Enable this button
11862 enable : function(){
11864 this.el.removeClass("x-btn-disabled");
11866 this.disabled = false;
11870 * Convenience function for boolean enable/disable
11871 * @param {Boolean} enabled True to enable, false to disable
11873 setDisabled : function(v){
11874 this[v !== true ? "enable" : "disable"]();
11878 onClick : function(e){
11880 e.preventDefault();
11885 if(!this.disabled){
11886 if(this.enableToggle){
11889 if(this.menu && !this.menu.isVisible()){
11890 this.menu.show(this.el, this.menuAlign);
11892 this.fireEvent("click", this, e);
11894 this.el.removeClass("x-btn-over");
11895 this.handler.call(this.scope || this, this, e);
11900 onMouseOver : function(e){
11901 if(!this.disabled){
11902 this.el.addClass("x-btn-over");
11903 this.fireEvent('mouseover', this, e);
11907 onMouseOut : function(e){
11908 if(!e.within(this.el, true)){
11909 this.el.removeClass("x-btn-over");
11910 this.fireEvent('mouseout', this, e);
11914 onFocus : function(e){
11915 if(!this.disabled){
11916 this.el.addClass("x-btn-focus");
11920 onBlur : function(e){
11921 this.el.removeClass("x-btn-focus");
11924 onMouseDown : function(e){
11925 if(!this.disabled && e.button == 0){
11926 this.el.addClass("x-btn-click");
11927 Roo.get(document).on('mouseup', this.onMouseUp, this);
11931 onMouseUp : function(e){
11933 this.el.removeClass("x-btn-click");
11934 Roo.get(document).un('mouseup', this.onMouseUp, this);
11938 onMenuShow : function(e){
11939 this.el.addClass("x-btn-menu-active");
11942 onMenuHide : function(e){
11943 this.el.removeClass("x-btn-menu-active");
11947 // Private utility class used by Button
11948 Roo.ButtonToggleMgr = function(){
11951 function toggleGroup(btn, state){
11953 var g = groups[btn.toggleGroup];
11954 for(var i = 0, l = g.length; i < l; i++){
11956 g[i].toggle(false);
11963 register : function(btn){
11964 if(!btn.toggleGroup){
11967 var g = groups[btn.toggleGroup];
11969 g = groups[btn.toggleGroup] = [];
11972 btn.on("toggle", toggleGroup);
11975 unregister : function(btn){
11976 if(!btn.toggleGroup){
11979 var g = groups[btn.toggleGroup];
11982 btn.un("toggle", toggleGroup);
11988 * Ext JS Library 1.1.1
11989 * Copyright(c) 2006-2007, Ext JS, LLC.
11991 * Originally Released Under LGPL - original licence link has changed is not relivant.
11994 * <script type="text/javascript">
11998 * @class Roo.SplitButton
11999 * @extends Roo.Button
12000 * A split button that provides a built-in dropdown arrow that can fire an event separately from the default
12001 * click event of the button. Typically this would be used to display a dropdown menu that provides additional
12002 * options to the primary button action, but any custom handler can provide the arrowclick implementation.
12003 * @cfg {Function} arrowHandler A function called when the arrow button is clicked (can be used instead of click event)
12004 * @cfg {String} arrowTooltip The title attribute of the arrow
12006 * Create a new menu button
12007 * @param {String/HTMLElement/Element} renderTo The element to append the button to
12008 * @param {Object} config The config object
12010 Roo.SplitButton = function(renderTo, config){
12011 Roo.SplitButton.superclass.constructor.call(this, renderTo, config);
12013 * @event arrowclick
12014 * Fires when this button's arrow is clicked
12015 * @param {SplitButton} this
12016 * @param {EventObject} e The click event
12018 this.addEvents({"arrowclick":true});
12021 Roo.extend(Roo.SplitButton, Roo.Button, {
12022 render : function(renderTo){
12023 // this is one sweet looking template!
12024 var tpl = new Roo.Template(
12025 '<table cellspacing="0" class="x-btn-menu-wrap x-btn"><tr><td>',
12026 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-text-wrap"><tbody>',
12027 '<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>',
12028 "</tbody></table></td><td>",
12029 '<table cellspacing="0" class="x-btn-wrap x-btn-menu-arrow-wrap"><tbody>',
12030 '<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>',
12031 "</tbody></table></td></tr></table>"
12033 var btn = tpl.append(renderTo, [this.text, this.type], true);
12034 var btnEl = btn.child("button");
12036 btn.addClass(this.cls);
12039 btnEl.setStyle('background-image', 'url(' +this.icon +')');
12042 btnEl.addClass(this.iconCls);
12044 btn.addClass(this.text ? 'x-btn-text-icon' : 'x-btn-icon');
12048 if(this.handleMouseEvents){
12049 btn.on("mouseover", this.onMouseOver, this);
12050 btn.on("mouseout", this.onMouseOut, this);
12051 btn.on("mousedown", this.onMouseDown, this);
12052 btn.on("mouseup", this.onMouseUp, this);
12054 btn.on(this.clickEvent, this.onClick, this);
12056 if(typeof this.tooltip == 'object'){
12057 Roo.QuickTips.tips(Roo.apply({
12061 btnEl.dom[this.tooltipType] = this.tooltip;
12064 if(this.arrowTooltip){
12065 btn.child("button:nth(2)").dom[this.tooltipType] = this.arrowTooltip;
12074 this.el.addClass("x-btn-pressed");
12076 if(Roo.isIE && !Roo.isIE7){
12077 this.autoWidth.defer(1, this);
12082 this.menu.on("show", this.onMenuShow, this);
12083 this.menu.on("hide", this.onMenuHide, this);
12085 this.fireEvent('render', this);
12089 autoWidth : function(){
12091 var tbl = this.el.child("table:first");
12092 var tbl2 = this.el.child("table:last");
12093 this.el.setWidth("auto");
12094 tbl.setWidth("auto");
12095 if(Roo.isIE7 && Roo.isStrict){
12096 var ib = this.el.child('button:first');
12097 if(ib && ib.getWidth() > 20){
12099 ib.setWidth(Roo.util.TextMetrics.measure(ib, this.text).width+ib.getFrameWidth('lr'));
12104 this.el.beginMeasure();
12106 if((tbl.getWidth()+tbl2.getWidth()) < this.minWidth){
12107 tbl.setWidth(this.minWidth-tbl2.getWidth());
12110 this.el.endMeasure();
12113 this.el.setWidth(tbl.getWidth()+tbl2.getWidth());
12117 * Sets this button's click handler
12118 * @param {Function} handler The function to call when the button is clicked
12119 * @param {Object} scope (optional) Scope for the function passed above
12121 setHandler : function(handler, scope){
12122 this.handler = handler;
12123 this.scope = scope;
12127 * Sets this button's arrow click handler
12128 * @param {Function} handler The function to call when the arrow is clicked
12129 * @param {Object} scope (optional) Scope for the function passed above
12131 setArrowHandler : function(handler, scope){
12132 this.arrowHandler = handler;
12133 this.scope = scope;
12139 focus : function(){
12141 this.el.child("button:first").focus();
12146 onClick : function(e){
12147 e.preventDefault();
12148 if(!this.disabled){
12149 if(e.getTarget(".x-btn-menu-arrow-wrap")){
12150 if(this.menu && !this.menu.isVisible()){
12151 this.menu.show(this.el, this.menuAlign);
12153 this.fireEvent("arrowclick", this, e);
12154 if(this.arrowHandler){
12155 this.arrowHandler.call(this.scope || this, this, e);
12158 this.fireEvent("click", this, e);
12160 this.handler.call(this.scope || this, this, e);
12166 onMouseDown : function(e){
12167 if(!this.disabled){
12168 Roo.fly(e.getTarget("table")).addClass("x-btn-click");
12172 onMouseUp : function(e){
12173 Roo.fly(e.getTarget("table")).removeClass("x-btn-click");
12178 // backwards compat
12179 Roo.MenuButton = Roo.SplitButton;/*
12181 * Ext JS Library 1.1.1
12182 * Copyright(c) 2006-2007, Ext JS, LLC.
12184 * Originally Released Under LGPL - original licence link has changed is not relivant.
12187 * <script type="text/javascript">
12191 * @class Roo.Toolbar
12192 * Basic Toolbar class.
12194 * Creates a new Toolbar
12195 * @param {Object} config The config object
12197 Roo.Toolbar = function(container, buttons, config)
12199 /// old consturctor format still supported..
12200 if(container instanceof Array){ // omit the container for later rendering
12201 buttons = container;
12205 if (typeof(container) == 'object' && container.xtype) {
12206 config = container;
12207 container = config.container;
12208 buttons = config.buttons; // not really - use items!!
12211 if (config && config.items) {
12212 xitems = config.items;
12213 delete config.items;
12215 Roo.apply(this, config);
12216 this.buttons = buttons;
12219 this.render(container);
12221 Roo.each(xitems, function(b) {
12227 Roo.Toolbar.prototype = {
12229 * @cfg {Roo.data.Store} items
12230 * array of button configs or elements to add
12234 * @cfg {String/HTMLElement/Element} container
12235 * The id or element that will contain the toolbar
12238 render : function(ct){
12239 this.el = Roo.get(ct);
12241 this.el.addClass(this.cls);
12243 // using a table allows for vertical alignment
12244 // 100% width is needed by Safari...
12245 this.el.update('<div class="x-toolbar x-small-editor"><table cellspacing="0"><tr></tr></table></div>');
12246 this.tr = this.el.child("tr", true);
12248 this.items = new Roo.util.MixedCollection(false, function(o){
12249 return o.id || ("item" + (++autoId));
12252 this.add.apply(this, this.buttons);
12253 delete this.buttons;
12258 * Adds element(s) to the toolbar -- this function takes a variable number of
12259 * arguments of mixed type and adds them to the toolbar.
12260 * @param {Mixed} arg1 The following types of arguments are all valid:<br />
12262 * <li>{@link Roo.Toolbar.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
12263 * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
12264 * <li>Field: Any form field (equivalent to {@link #addField})</li>
12265 * <li>Item: Any subclass of {@link Roo.Toolbar.Item} (equivalent to {@link #addItem})</li>
12266 * <li>String: Any generic string (gets wrapped in a {@link Roo.Toolbar.TextItem}, equivalent to {@link #addText}).
12267 * Note that there are a few special strings that are treated differently as explained nRoo.</li>
12268 * <li>'separator' or '-': Creates a separator element (equivalent to {@link #addSeparator})</li>
12269 * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
12270 * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
12272 * @param {Mixed} arg2
12273 * @param {Mixed} etc.
12276 var a = arguments, l = a.length;
12277 for(var i = 0; i < l; i++){
12282 _add : function(el) {
12285 el = Roo.factory(el, typeof(Roo.Toolbar[el.xtype]) == 'undefined' ? Roo.form : Roo.Toolbar);
12288 if (el.applyTo){ // some kind of form field
12289 return this.addField(el);
12291 if (el.render){ // some kind of Toolbar.Item
12292 return this.addItem(el);
12294 if (typeof el == "string"){ // string
12295 if(el == "separator" || el == "-"){
12296 return this.addSeparator();
12299 return this.addSpacer();
12302 return this.addFill();
12304 return this.addText(el);
12307 if(el.tagName){ // element
12308 return this.addElement(el);
12310 if(typeof el == "object"){ // must be button config?
12311 return this.addButton(el);
12313 // and now what?!?!
12319 * Add an Xtype element
12320 * @param {Object} xtype Xtype Object
12321 * @return {Object} created Object
12323 addxtype : function(e){
12324 return this.add(e);
12328 * Returns the Element for this toolbar.
12329 * @return {Roo.Element}
12331 getEl : function(){
12337 * @return {Roo.Toolbar.Item} The separator item
12339 addSeparator : function(){
12340 return this.addItem(new Roo.Toolbar.Separator());
12344 * Adds a spacer element
12345 * @return {Roo.Toolbar.Spacer} The spacer item
12347 addSpacer : function(){
12348 return this.addItem(new Roo.Toolbar.Spacer());
12352 * Adds a fill element that forces subsequent additions to the right side of the toolbar
12353 * @return {Roo.Toolbar.Fill} The fill item
12355 addFill : function(){
12356 return this.addItem(new Roo.Toolbar.Fill());
12360 * Adds any standard HTML element to the toolbar
12361 * @param {String/HTMLElement/Element} el The element or id of the element to add
12362 * @return {Roo.Toolbar.Item} The element's item
12364 addElement : function(el){
12365 return this.addItem(new Roo.Toolbar.Item(el));
12368 * Collection of items on the toolbar.. (only Toolbar Items, so use fields to retrieve fields)
12369 * @type Roo.util.MixedCollection
12374 * Adds any Toolbar.Item or subclass
12375 * @param {Roo.Toolbar.Item} item
12376 * @return {Roo.Toolbar.Item} The item
12378 addItem : function(item){
12379 var td = this.nextBlock();
12381 this.items.add(item);
12386 * Adds a button (or buttons). See {@link Roo.Toolbar.Button} for more info on the config.
12387 * @param {Object/Array} config A button config or array of configs
12388 * @return {Roo.Toolbar.Button/Array}
12390 addButton : function(config){
12391 if(config instanceof Array){
12393 for(var i = 0, len = config.length; i < len; i++) {
12394 buttons.push(this.addButton(config[i]));
12399 if(!(config instanceof Roo.Toolbar.Button)){
12401 new Roo.Toolbar.SplitButton(config) :
12402 new Roo.Toolbar.Button(config);
12404 var td = this.nextBlock();
12411 * Adds text to the toolbar
12412 * @param {String} text The text to add
12413 * @return {Roo.Toolbar.Item} The element's item
12415 addText : function(text){
12416 return this.addItem(new Roo.Toolbar.TextItem(text));
12420 * Inserts any {@link Roo.Toolbar.Item}/{@link Roo.Toolbar.Button} at the specified index.
12421 * @param {Number} index The index where the item is to be inserted
12422 * @param {Object/Roo.Toolbar.Item/Roo.Toolbar.Button (may be Array)} item The button, or button config object to be inserted.
12423 * @return {Roo.Toolbar.Button/Item}
12425 insertButton : function(index, item){
12426 if(item instanceof Array){
12428 for(var i = 0, len = item.length; i < len; i++) {
12429 buttons.push(this.insertButton(index + i, item[i]));
12433 if (!(item instanceof Roo.Toolbar.Button)){
12434 item = new Roo.Toolbar.Button(item);
12436 var td = document.createElement("td");
12437 this.tr.insertBefore(td, this.tr.childNodes[index]);
12439 this.items.insert(index, item);
12444 * Adds a new element to the toolbar from the passed {@link Roo.DomHelper} config.
12445 * @param {Object} config
12446 * @return {Roo.Toolbar.Item} The element's item
12448 addDom : function(config, returnEl){
12449 var td = this.nextBlock();
12450 Roo.DomHelper.overwrite(td, config);
12451 var ti = new Roo.Toolbar.Item(td.firstChild);
12453 this.items.add(ti);
12458 * Collection of fields on the toolbar.. usefull for quering (value is false if there are no fields)
12459 * @type Roo.util.MixedCollection
12464 * Adds a dynamically rendered Roo.form field (TextField, ComboBox, etc). Note: the field should not have
12465 * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
12466 * @param {Roo.form.Field} field
12467 * @return {Roo.ToolbarItem}
12471 addField : function(field) {
12472 if (!this.fields) {
12474 this.fields = new Roo.util.MixedCollection(false, function(o){
12475 return o.id || ("item" + (++autoId));
12480 var td = this.nextBlock();
12482 var ti = new Roo.Toolbar.Item(td.firstChild);
12484 this.items.add(ti);
12485 this.fields.add(field);
12496 this.el.child('div').setVisibilityMode(Roo.Element.DISPLAY);
12497 this.el.child('div').hide();
12505 this.el.child('div').show();
12509 nextBlock : function(){
12510 var td = document.createElement("td");
12511 this.tr.appendChild(td);
12516 destroy : function(){
12517 if(this.items){ // rendered?
12518 Roo.destroy.apply(Roo, this.items.items);
12520 if(this.fields){ // rendered?
12521 Roo.destroy.apply(Roo, this.fields.items);
12523 Roo.Element.uncache(this.el, this.tr);
12528 * @class Roo.Toolbar.Item
12529 * The base class that other classes should extend in order to get some basic common toolbar item functionality.
12531 * Creates a new Item
12532 * @param {HTMLElement} el
12534 Roo.Toolbar.Item = function(el){
12535 this.el = Roo.getDom(el);
12536 this.id = Roo.id(this.el);
12537 this.hidden = false;
12540 Roo.Toolbar.Item.prototype = {
12543 * Get this item's HTML Element
12544 * @return {HTMLElement}
12546 getEl : function(){
12551 render : function(td){
12553 td.appendChild(this.el);
12557 * Removes and destroys this item.
12559 destroy : function(){
12560 this.td.parentNode.removeChild(this.td);
12567 this.hidden = false;
12568 this.td.style.display = "";
12575 this.hidden = true;
12576 this.td.style.display = "none";
12580 * Convenience function for boolean show/hide.
12581 * @param {Boolean} visible true to show/false to hide
12583 setVisible: function(visible){
12592 * Try to focus this item.
12594 focus : function(){
12595 Roo.fly(this.el).focus();
12599 * Disables this item.
12601 disable : function(){
12602 Roo.fly(this.td).addClass("x-item-disabled");
12603 this.disabled = true;
12604 this.el.disabled = true;
12608 * Enables this item.
12610 enable : function(){
12611 Roo.fly(this.td).removeClass("x-item-disabled");
12612 this.disabled = false;
12613 this.el.disabled = false;
12619 * @class Roo.Toolbar.Separator
12620 * @extends Roo.Toolbar.Item
12621 * A simple toolbar separator class
12623 * Creates a new Separator
12625 Roo.Toolbar.Separator = function(){
12626 var s = document.createElement("span");
12627 s.className = "ytb-sep";
12628 Roo.Toolbar.Separator.superclass.constructor.call(this, s);
12630 Roo.extend(Roo.Toolbar.Separator, Roo.Toolbar.Item, {
12631 enable:Roo.emptyFn,
12632 disable:Roo.emptyFn,
12637 * @class Roo.Toolbar.Spacer
12638 * @extends Roo.Toolbar.Item
12639 * A simple element that adds extra horizontal space to a toolbar.
12641 * Creates a new Spacer
12643 Roo.Toolbar.Spacer = function(){
12644 var s = document.createElement("div");
12645 s.className = "ytb-spacer";
12646 Roo.Toolbar.Spacer.superclass.constructor.call(this, s);
12648 Roo.extend(Roo.Toolbar.Spacer, Roo.Toolbar.Item, {
12649 enable:Roo.emptyFn,
12650 disable:Roo.emptyFn,
12655 * @class Roo.Toolbar.Fill
12656 * @extends Roo.Toolbar.Spacer
12657 * A simple element that adds a greedy (100% width) horizontal space to a toolbar.
12659 * Creates a new Spacer
12661 Roo.Toolbar.Fill = Roo.extend(Roo.Toolbar.Spacer, {
12663 render : function(td){
12664 td.style.width = '100%';
12665 Roo.Toolbar.Fill.superclass.render.call(this, td);
12670 * @class Roo.Toolbar.TextItem
12671 * @extends Roo.Toolbar.Item
12672 * A simple class that renders text directly into a toolbar.
12674 * Creates a new TextItem
12675 * @param {String} text
12677 Roo.Toolbar.TextItem = function(text){
12678 if (typeof(text) == 'object') {
12681 var s = document.createElement("span");
12682 s.className = "ytb-text";
12683 s.innerHTML = text;
12684 Roo.Toolbar.TextItem.superclass.constructor.call(this, s);
12686 Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
12687 enable:Roo.emptyFn,
12688 disable:Roo.emptyFn,
12693 * @class Roo.Toolbar.Button
12694 * @extends Roo.Button
12695 * A button that renders into a toolbar.
12697 * Creates a new Button
12698 * @param {Object} config A standard {@link Roo.Button} config object
12700 Roo.Toolbar.Button = function(config){
12701 Roo.Toolbar.Button.superclass.constructor.call(this, null, config);
12703 Roo.extend(Roo.Toolbar.Button, Roo.Button, {
12704 render : function(td){
12706 Roo.Toolbar.Button.superclass.render.call(this, td);
12710 * Removes and destroys this button
12712 destroy : function(){
12713 Roo.Toolbar.Button.superclass.destroy.call(this);
12714 this.td.parentNode.removeChild(this.td);
12718 * Shows this button
12721 this.hidden = false;
12722 this.td.style.display = "";
12726 * Hides this button
12729 this.hidden = true;
12730 this.td.style.display = "none";
12734 * Disables this item
12736 disable : function(){
12737 Roo.fly(this.td).addClass("x-item-disabled");
12738 this.disabled = true;
12742 * Enables this item
12744 enable : function(){
12745 Roo.fly(this.td).removeClass("x-item-disabled");
12746 this.disabled = false;
12749 // backwards compat
12750 Roo.ToolbarButton = Roo.Toolbar.Button;
12753 * @class Roo.Toolbar.SplitButton
12754 * @extends Roo.SplitButton
12755 * A menu button that renders into a toolbar.
12757 * Creates a new SplitButton
12758 * @param {Object} config A standard {@link Roo.SplitButton} config object
12760 Roo.Toolbar.SplitButton = function(config){
12761 Roo.Toolbar.SplitButton.superclass.constructor.call(this, null, config);
12763 Roo.extend(Roo.Toolbar.SplitButton, Roo.SplitButton, {
12764 render : function(td){
12766 Roo.Toolbar.SplitButton.superclass.render.call(this, td);
12770 * Removes and destroys this button
12772 destroy : function(){
12773 Roo.Toolbar.SplitButton.superclass.destroy.call(this);
12774 this.td.parentNode.removeChild(this.td);
12778 * Shows this button
12781 this.hidden = false;
12782 this.td.style.display = "";
12786 * Hides this button
12789 this.hidden = true;
12790 this.td.style.display = "none";
12794 // backwards compat
12795 Roo.Toolbar.MenuButton = Roo.Toolbar.SplitButton;/*
12797 * Ext JS Library 1.1.1
12798 * Copyright(c) 2006-2007, Ext JS, LLC.
12800 * Originally Released Under LGPL - original licence link has changed is not relivant.
12803 * <script type="text/javascript">
12807 * @class Roo.PagingToolbar
12808 * @extends Roo.Toolbar
12809 * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
12811 * Create a new PagingToolbar
12812 * @param {Object} config The config object
12814 Roo.PagingToolbar = function(el, ds, config)
12816 // old args format still supported... - xtype is prefered..
12817 if (typeof(el) == 'object' && el.xtype) {
12818 // created from xtype...
12820 ds = el.dataSource;
12821 el = config.container;
12824 if (config.items) {
12825 items = config.items;
12829 Roo.PagingToolbar.superclass.constructor.call(this, el, null, config);
12832 this.renderButtons(this.el);
12835 // supprot items array.
12837 Roo.each(items, function(e) {
12838 this.add(Roo.factory(e));
12843 Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
12845 * @cfg {Roo.data.Store} dataSource
12846 * The underlying data store providing the paged data
12849 * @cfg {String/HTMLElement/Element} container
12850 * container The id or element that will contain the toolbar
12853 * @cfg {Boolean} displayInfo
12854 * True to display the displayMsg (defaults to false)
12857 * @cfg {Number} pageSize
12858 * The number of records to display per page (defaults to 20)
12862 * @cfg {String} displayMsg
12863 * The paging status message to display (defaults to "Displaying {start} - {end} of {total}")
12865 displayMsg : 'Displaying {0} - {1} of {2}',
12867 * @cfg {String} emptyMsg
12868 * The message to display when no records are found (defaults to "No data to display")
12870 emptyMsg : 'No data to display',
12872 * Customizable piece of the default paging text (defaults to "Page")
12875 beforePageText : "Page",
12877 * Customizable piece of the default paging text (defaults to "of %0")
12880 afterPageText : "of {0}",
12882 * Customizable piece of the default paging text (defaults to "First Page")
12885 firstText : "First Page",
12887 * Customizable piece of the default paging text (defaults to "Previous Page")
12890 prevText : "Previous Page",
12892 * Customizable piece of the default paging text (defaults to "Next Page")
12895 nextText : "Next Page",
12897 * Customizable piece of the default paging text (defaults to "Last Page")
12900 lastText : "Last Page",
12902 * Customizable piece of the default paging text (defaults to "Refresh")
12905 refreshText : "Refresh",
12908 renderButtons : function(el){
12909 Roo.PagingToolbar.superclass.render.call(this, el);
12910 this.first = this.addButton({
12911 tooltip: this.firstText,
12912 cls: "x-btn-icon x-grid-page-first",
12914 handler: this.onClick.createDelegate(this, ["first"])
12916 this.prev = this.addButton({
12917 tooltip: this.prevText,
12918 cls: "x-btn-icon x-grid-page-prev",
12920 handler: this.onClick.createDelegate(this, ["prev"])
12922 //this.addSeparator();
12923 this.add(this.beforePageText);
12924 this.field = Roo.get(this.addDom({
12929 cls: "x-grid-page-number"
12931 this.field.on("keydown", this.onPagingKeydown, this);
12932 this.field.on("focus", function(){this.dom.select();});
12933 this.afterTextEl = this.addText(String.format(this.afterPageText, 1));
12934 this.field.setHeight(18);
12935 //this.addSeparator();
12936 this.next = this.addButton({
12937 tooltip: this.nextText,
12938 cls: "x-btn-icon x-grid-page-next",
12940 handler: this.onClick.createDelegate(this, ["next"])
12942 this.last = this.addButton({
12943 tooltip: this.lastText,
12944 cls: "x-btn-icon x-grid-page-last",
12946 handler: this.onClick.createDelegate(this, ["last"])
12948 //this.addSeparator();
12949 this.loading = this.addButton({
12950 tooltip: this.refreshText,
12951 cls: "x-btn-icon x-grid-loading",
12952 handler: this.onClick.createDelegate(this, ["refresh"])
12955 if(this.displayInfo){
12956 this.displayEl = Roo.fly(this.el.dom.firstChild).createChild({cls:'x-paging-info'});
12961 updateInfo : function(){
12962 if(this.displayEl){
12963 var count = this.ds.getCount();
12964 var msg = count == 0 ?
12968 this.cursor+1, this.cursor+count, this.ds.getTotalCount()
12970 this.displayEl.update(msg);
12975 onLoad : function(ds, r, o){
12976 this.cursor = o.params ? o.params.start : 0;
12977 var d = this.getPageData(), ap = d.activePage, ps = d.pages;
12979 this.afterTextEl.el.innerHTML = String.format(this.afterPageText, d.pages);
12980 this.field.dom.value = ap;
12981 this.first.setDisabled(ap == 1);
12982 this.prev.setDisabled(ap == 1);
12983 this.next.setDisabled(ap == ps);
12984 this.last.setDisabled(ap == ps);
12985 this.loading.enable();
12990 getPageData : function(){
12991 var total = this.ds.getTotalCount();
12994 activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
12995 pages : total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
13000 onLoadError : function(){
13001 this.loading.enable();
13005 onPagingKeydown : function(e){
13006 var k = e.getKey();
13007 var d = this.getPageData();
13009 var v = this.field.dom.value, pageNum;
13010 if(!v || isNaN(pageNum = parseInt(v, 10))){
13011 this.field.dom.value = d.activePage;
13014 pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
13015 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13018 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))
13020 var pageNum = (k == e.HOME || (k == e.DOWN && e.ctrlKey) || (k == e.LEFT && e.ctrlKey) || (k == e.PAGEDOWN && e.ctrlKey)) ? 1 : d.pages;
13021 this.field.dom.value = pageNum;
13022 this.ds.load({params:{start: (pageNum - 1) * this.pageSize, limit: this.pageSize}});
13025 else if(k == e.UP || k == e.RIGHT || k == e.PAGEUP || k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13027 var v = this.field.dom.value, pageNum;
13028 var increment = (e.shiftKey) ? 10 : 1;
13029 if(k == e.DOWN || k == e.LEFT || k == e.PAGEDOWN)
13031 if(!v || isNaN(pageNum = parseInt(v, 10))) {
13032 this.field.dom.value = d.activePage;
13035 else if(parseInt(v, 10) + increment >= 1 & parseInt(v, 10) + increment <= d.pages)
13037 this.field.dom.value = parseInt(v, 10) + increment;
13038 pageNum = Math.min(Math.max(1, pageNum + increment), d.pages) - 1;
13039 this.ds.load({params:{start: pageNum * this.pageSize, limit: this.pageSize}});
13046 beforeLoad : function(){
13048 this.loading.disable();
13053 onClick : function(which){
13057 ds.load({params:{start: 0, limit: this.pageSize}});
13060 ds.load({params:{start: Math.max(0, this.cursor-this.pageSize), limit: this.pageSize}});
13063 ds.load({params:{start: this.cursor+this.pageSize, limit: this.pageSize}});
13066 var total = ds.getTotalCount();
13067 var extra = total % this.pageSize;
13068 var lastStart = extra ? (total - extra) : total-this.pageSize;
13069 ds.load({params:{start: lastStart, limit: this.pageSize}});
13072 ds.load({params:{start: this.cursor, limit: this.pageSize}});
13078 * Unbinds the paging toolbar from the specified {@link Roo.data.Store}
13079 * @param {Roo.data.Store} store The data store to unbind
13081 unbind : function(ds){
13082 ds.un("beforeload", this.beforeLoad, this);
13083 ds.un("load", this.onLoad, this);
13084 ds.un("loadexception", this.onLoadError, this);
13085 ds.un("remove", this.updateInfo, this);
13086 ds.un("add", this.updateInfo, this);
13087 this.ds = undefined;
13091 * Binds the paging toolbar to the specified {@link Roo.data.Store}
13092 * @param {Roo.data.Store} store The data store to bind
13094 bind : function(ds){
13095 ds.on("beforeload", this.beforeLoad, this);
13096 ds.on("load", this.onLoad, this);
13097 ds.on("loadexception", this.onLoadError, this);
13098 ds.on("remove", this.updateInfo, this);
13099 ds.on("add", this.updateInfo, this);