4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
15 * These classes are derivatives of the similarly named classes in the YUI Library.
16 * The original license:
17 * Copyright (c) 2006, Yahoo! Inc. All rights reserved.
18 * Code licensed under the BSD License:
19 * http://developer.yahoo.net/yui/license.txt
24 var Event=Roo.EventManager;
28 * @class Roo.dd.DragDrop
29 * Defines the interface and base operation of items that that can be
30 * dragged or can be drop targets. It was designed to be extended, overriding
31 * the event handlers for startDrag, onDrag, onDragOver and onDragOut.
32 * Up to three html elements can be associated with a DragDrop instance:
34 * <li>linked element: the element that is passed into the constructor.
35 * This is the element which defines the boundaries for interaction with
36 * other DragDrop objects.</li>
37 * <li>handle element(s): The drag operation only occurs if the element that
38 * was clicked matches a handle element. By default this is the linked
39 * element, but there are times that you will want only a portion of the
40 * linked element to initiate the drag operation, and the setHandleElId()
41 * method provides a way to define this.</li>
42 * <li>drag element: this represents the element that would be moved along
43 * with the cursor during a drag operation. By default, this is the linked
44 * element itself as in {@link Roo.dd.DD}. setDragElId() lets you define
45 * a separate element that would be moved, as in {@link Roo.dd.DDProxy}.
48 * This class should not be instantiated until the onload event to ensure that
49 * the associated elements are available.
50 * The following would define a DragDrop obj that would interact with any
51 * other DragDrop obj in the "group1" group:
53 * dd = new Roo.dd.DragDrop("div1", "group1");
55 * Since none of the event handlers have been implemented, nothing would
56 * actually happen if you were to run the code above. Normally you would
57 * override this class or one of the default implementations, but you can
58 * also override the methods you want on an instance of the class...
60 * dd.onDragDrop = function(e, id) {
61 * alert("dd was dropped on " + id);
65 * @param {String} id of the element that is linked to this instance
66 * @param {String} sGroup the group of related DragDrop objects
67 * @param {object} config an object containing configurable attributes
68 * Valid properties for DragDrop:
69 * padding, isTarget, maintainOffset, primaryButtonOnly
71 Roo.dd.DragDrop = function(id, sGroup, config) {
73 this.init(id, sGroup, config);
78 Roo.extend(Roo.dd.DragDrop, Roo.util.Observable , {
81 * The id of the element associated with this object. This is what we
82 * refer to as the "linked element" because the size and position of
83 * this element is used to determine when the drag and drop objects have
91 * Configuration attributes passed into the constructor
98 * The id of the element that will be dragged. By default this is same
99 * as the linked element , but could be changed to another element. Ex:
108 * the id of the element that initiates the drag operation. By default
109 * this is the linked element, but could be changed to be a child of this
110 * element. This lets us do things like only starting the drag when the
111 * header element within the linked html element is clicked.
112 * @property handleElId
119 * An associative array of HTML tags that will be ignored if clicked.
120 * @property invalidHandleTypes
121 * @type {string: string}
123 invalidHandleTypes: null,
126 * An associative array of ids for elements that will be ignored if clicked
127 * @property invalidHandleIds
128 * @type {string: string}
130 invalidHandleIds: null,
133 * An indexted array of css class names for elements that will be ignored
135 * @property invalidHandleClasses
138 invalidHandleClasses: null,
141 * The linked element's absolute X position at the time the drag was
143 * @property startPageX
150 * The linked element's absolute X position at the time the drag was
152 * @property startPageY
159 * The group defines a logical collection of DragDrop objects that are
160 * related. Instances only get events when interacting with other
161 * DragDrop object in the same group. This lets us define multiple
162 * groups using a single DragDrop subclass if we want.
164 * @type {string: string}
169 * Individual drag/drop instances can be locked. This will prevent
170 * onmousedown start drag.
181 lock: function() { this.locked = true; },
184 * Unlock this instace
187 unlock: function() { this.locked = false; },
190 * By default, all insances can be a drop target. This can be disabled by
191 * setting isTarget to false.
198 * The padding configured for this drag and drop object for calculating
199 * the drop zone intersection with this object.
206 * Cached reference to the linked element
213 * Internal typeof flag
214 * @property __ygDragDrop
220 * Set to true when horizontal contraints are applied
221 * @property constrainX
228 * Set to true when vertical contraints are applied
229 * @property constrainY
236 * The left constraint
244 * The right constraint
261 * The down constraint
269 * Maintain offsets when we resetconstraints. Set to true when you want
270 * the position of the element relative to its parent to stay the same
271 * when the page changes
273 * @property maintainOffset
276 maintainOffset: false,
279 * Array of pixel locations the element will snap to if we specified a
280 * horizontal graduation/interval. This array is generated automatically
281 * when you define a tick interval.
288 * Array of pixel locations the element will snap to if we specified a
289 * vertical graduation/interval. This array is generated automatically
290 * when you define a tick interval.
297 * By default the drag and drop instance will only respond to the primary
298 * button click (left button for a right-handed mouse). Set to true to
299 * allow drag and drop to start with any mouse click that is propogated
301 * @property primaryButtonOnly
304 primaryButtonOnly: true,
307 * The availabe property is false until the linked dom element is accessible.
308 * @property available
314 * By default, drags can only be initiated if the mousedown occurs in the
315 * region the linked element is. This is done in part to work around a
316 * bug in some browsers that mis-report the mousedown if the previous
317 * mouseup happened outside of the window. This property is set to true
318 * if outer handles are defined.
320 * @property hasOuterHandles
324 hasOuterHandles: false,
327 * Code that executes immediately before the startDrag event
328 * @method b4StartDrag
331 b4StartDrag: function(x, y) { },
334 * Abstract method called after a drag/drop object is clicked
335 * and the drag or mousedown time thresholds have beeen met.
337 * @param {int} X click location
338 * @param {int} Y click location
340 startDrag: function(x, y) { /* override this */ },
343 * Code that executes immediately before the onDrag event
347 b4Drag: function(e) { },
350 * Abstract method called during the onMouseMove event while dragging an
353 * @param {Event} e the mousemove event
355 onDrag: function(e) { /* override this */ },
358 * Abstract method called when this element fist begins hovering over
359 * another DragDrop obj
360 * @method onDragEnter
361 * @param {Event} e the mousemove event
362 * @param {String|DragDrop[]} id In POINT mode, the element
363 * id this is hovering over. In INTERSECT mode, an array of one or more
364 * dragdrop items being hovered over.
366 onDragEnter: function(e, id) { /* override this */ },
369 * Code that executes immediately before the onDragOver event
373 b4DragOver: function(e) { },
376 * Abstract method called when this element is hovering over another
379 * @param {Event} e the mousemove event
380 * @param {String|DragDrop[]} id In POINT mode, the element
381 * id this is hovering over. In INTERSECT mode, an array of dd items
382 * being hovered over.
384 onDragOver: function(e, id) { /* override this */ },
387 * Code that executes immediately before the onDragOut event
391 b4DragOut: function(e) { },
394 * Abstract method called when we are no longer hovering over an element
396 * @param {Event} e the mousemove event
397 * @param {String|DragDrop[]} id In POINT mode, the element
398 * id this was hovering over. In INTERSECT mode, an array of dd items
399 * that the mouse is no longer over.
401 onDragOut: function(e, id) { /* override this */ },
404 * Code that executes immediately before the onDragDrop event
408 b4DragDrop: function(e) { },
411 * Abstract method called when this item is dropped on another DragDrop
414 * @param {Event} e the mouseup event
415 * @param {String|DragDrop[]} id In POINT mode, the element
416 * id this was dropped on. In INTERSECT mode, an array of dd items this
419 onDragDrop: function(e, id) { /* override this */ },
422 * Abstract method called when this item is dropped on an area with no
424 * @method onInvalidDrop
425 * @param {Event} e the mouseup event
427 onInvalidDrop: function(e) { /* override this */ },
430 * Code that executes immediately before the endDrag event
434 b4EndDrag: function(e) { },
437 * Fired when we are done dragging the object
439 * @param {Event} e the mouseup event
441 endDrag: function(e) { /* override this */ },
444 * Code executed immediately before the onMouseDown event
445 * @method b4MouseDown
446 * @param {Event} e the mousedown event
449 b4MouseDown: function(e) { },
452 * Event handler that fires when a drag/drop obj gets a mousedown
453 * @method onMouseDown
454 * @param {Event} e the mousedown event
456 onMouseDown: function(e) { /* override this */ },
459 * Event handler that fires when a drag/drop obj gets a mouseup
461 * @param {Event} e the mouseup event
463 onMouseUp: function(e) { /* override this */ },
466 * Override the onAvailable method to do what is needed after the initial
467 * position was determined.
468 * @method onAvailable
470 onAvailable: function () {
474 * Provides default constraint padding to "constrainTo" elements (defaults to {left: 0, right:0, top:0, bottom:0}).
477 defaultPadding : {left:0, right:0, top:0, bottom:0},
480 * Initializes the drag drop object's constraints to restrict movement to a certain element.
484 var dd = new Roo.dd.DDProxy("dragDiv1", "proxytest",
485 { dragElId: "existingProxyDiv" });
486 dd.startDrag = function(){
487 this.constrainTo("parent-id");
490 * Or you can initalize it using the {@link Roo.Element} object:
492 Roo.get("dragDiv1").initDDProxy("proxytest", {dragElId: "existingProxyDiv"}, {
493 startDrag : function(){
494 this.constrainTo("parent-id");
498 * @param {String/HTMLElement/Element} constrainTo The element to constrain to.
499 * @param {Object/Number} pad (optional) Pad provides a way to specify "padding" of the constraints,
500 * and can be either a number for symmetrical padding (4 would be equal to {left:4, right:4, top:4, bottom:4}) or
501 * an object containing the sides to pad. For example: {right:10, bottom:10}
502 * @param {Boolean} inContent (optional) Constrain the draggable in the content box of the element (inside padding and borders)
504 constrainTo : function(constrainTo, pad, inContent){
505 if(typeof pad == "number"){
506 pad = {left: pad, right:pad, top:pad, bottom:pad};
508 pad = pad || this.defaultPadding;
509 var b = Roo.get(this.getEl()).getBox();
510 var ce = Roo.get(constrainTo);
511 var s = ce.getScroll();
513 if(cd == document.body){
514 c = { x: s.left, y: s.top, width: Roo.lib.Dom.getViewWidth(), height: Roo.lib.Dom.getViewHeight()};
517 c = {x : xy[0]+s.left, y: xy[1]+s.top, width: cd.clientWidth, height: cd.clientHeight};
521 var topSpace = b.y - c.y;
522 var leftSpace = b.x - c.x;
524 this.resetConstraints();
525 this.setXConstraint(leftSpace - (pad.left||0), // left
526 c.width - leftSpace - b.width - (pad.right||0) //right
528 this.setYConstraint(topSpace - (pad.top||0), //top
529 c.height - topSpace - b.height - (pad.bottom||0) //bottom
534 * Returns a reference to the linked element
536 * @return {HTMLElement} the html element
540 this._domRef = Roo.getDom(this.id);
547 * Returns a reference to the actual element to drag. By default this is
548 * the same as the html element, but it can be assigned to another
549 * element. An example of this can be found in Roo.dd.DDProxy
551 * @return {HTMLElement} the html element
553 getDragEl: function() {
554 return Roo.getDom(this.dragElId);
558 * Sets up the DragDrop object. Must be called in the constructor of any
559 * Roo.dd.DragDrop subclass
561 * @param id the id of the linked element
562 * @param {String} sGroup the group of related items
563 * @param {object} config configuration attributes
565 init: function(id, sGroup, config) {
566 this.initTarget(id, sGroup, config);
567 Event.on(this.id, "mousedown", this.handleMouseDown, this);
568 // Event.on(this.id, "selectstart", Event.preventDefault);
572 * Initializes Targeting functionality only... the object does not
573 * get a mousedown handler.
575 * @param id the id of the linked element
576 * @param {String} sGroup the group of related items
577 * @param {object} config configuration attributes
579 initTarget: function(id, sGroup, config) {
581 // configuration attributes
582 this.config = config || {};
584 // create a local reference to the drag and drop manager
585 this.DDM = Roo.dd.DDM;
586 // initialize the groups array
589 // assume that we have an element reference instead of an id if the
590 // parameter is not a string
591 if (typeof id !== "string") {
598 // add to an interaction group
599 this.addToGroup((sGroup) ? sGroup : "default");
601 // We don't want to register this as the handle with the manager
602 // so we just set the id rather than calling the setter.
603 this.handleElId = id;
605 // the linked element is the element that gets dragged by default
606 this.setDragElId(id);
608 // by default, clicked anchors will not start drag operations.
609 this.invalidHandleTypes = { A: "A" };
610 this.invalidHandleIds = {};
611 this.invalidHandleClasses = [];
615 this.handleOnAvailable();
619 * Applies the configuration parameters that were passed into the constructor.
620 * This is supposed to happen at each level through the inheritance chain. So
621 * a DDProxy implentation will execute apply config on DDProxy, DD, and
622 * DragDrop in order to get all of the parameters that are available in
624 * @method applyConfig
626 applyConfig: function() {
628 // configurable properties:
629 // padding, isTarget, maintainOffset, primaryButtonOnly
630 this.padding = this.config.padding || [0, 0, 0, 0];
631 this.isTarget = (this.config.isTarget !== false);
632 this.maintainOffset = (this.config.maintainOffset);
633 this.primaryButtonOnly = (this.config.primaryButtonOnly !== false);
638 * Executed when the linked element is available
639 * @method handleOnAvailable
642 handleOnAvailable: function() {
643 this.available = true;
644 this.resetConstraints();
649 * Configures the padding for the target zone in px. Effectively expands
650 * (or reduces) the virtual object size for targeting calculations.
651 * Supports css-style shorthand; if only one parameter is passed, all sides
652 * will have that padding, and if only two are passed, the top and bottom
653 * will have the first param, the left and right the second.
655 * @param {int} iTop Top pad
656 * @param {int} iRight Right pad
657 * @param {int} iBot Bot pad
658 * @param {int} iLeft Left pad
660 setPadding: function(iTop, iRight, iBot, iLeft) {
661 // this.padding = [iLeft, iRight, iTop, iBot];
662 if (!iRight && 0 !== iRight) {
663 this.padding = [iTop, iTop, iTop, iTop];
664 } else if (!iBot && 0 !== iBot) {
665 this.padding = [iTop, iRight, iTop, iRight];
667 this.padding = [iTop, iRight, iBot, iLeft];
672 * Stores the initial placement of the linked element.
673 * @method setInitialPosition
674 * @param {int} diffX the X offset, default 0
675 * @param {int} diffY the Y offset, default 0
677 setInitPosition: function(diffX, diffY) {
678 var el = this.getEl();
680 if (!this.DDM.verifyEl(el)) {
687 var p = Dom.getXY( el );
689 this.initPageX = p[0] - dx;
690 this.initPageY = p[1] - dy;
692 this.lastPageX = p[0];
693 this.lastPageY = p[1];
696 this.setStartPosition(p);
700 * Sets the start position of the element. This is set when the obj
701 * is initialized, the reset when a drag is started.
702 * @method setStartPosition
703 * @param pos current position (from previous lookup)
706 setStartPosition: function(pos) {
707 var p = pos || Dom.getXY( this.getEl() );
708 this.deltaSetXY = null;
710 this.startPageX = p[0];
711 this.startPageY = p[1];
715 * Add this instance to a group of related drag/drop objects. All
716 * instances belong to at least one group, and can belong to as many
719 * @param sGroup {string} the name of the group
721 addToGroup: function(sGroup) {
722 this.groups[sGroup] = true;
723 this.DDM.regDragDrop(this, sGroup);
727 * Remove's this instance from the supplied interaction group
728 * @method removeFromGroup
729 * @param {string} sGroup The group to drop
731 removeFromGroup: function(sGroup) {
732 if (this.groups[sGroup]) {
733 delete this.groups[sGroup];
736 this.DDM.removeDDFromGroup(this, sGroup);
740 * Allows you to specify that an element other than the linked element
741 * will be moved with the cursor during a drag
742 * @method setDragElId
743 * @param id {string} the id of the element that will be used to initiate the drag
745 setDragElId: function(id) {
750 * Allows you to specify a child of the linked element that should be
751 * used to initiate the drag operation. An example of this would be if
752 * you have a content div with text and links. Clicking anywhere in the
753 * content area would normally start the drag operation. Use this method
754 * to specify that an element inside of the content div is the element
755 * that starts the drag operation.
756 * @method setHandleElId
757 * @param id {string} the id of the element that will be used to
760 setHandleElId: function(id) {
761 if (typeof id !== "string") {
764 this.handleElId = id;
765 this.DDM.regHandle(this.id, id);
769 * Allows you to set an element outside of the linked element as a drag
771 * @method setOuterHandleElId
772 * @param id the id of the element that will be used to initiate the drag
774 setOuterHandleElId: function(id) {
775 if (typeof id !== "string") {
778 Event.on(id, "mousedown",
779 this.handleMouseDown, this);
780 this.setHandleElId(id);
782 this.hasOuterHandles = true;
786 * Remove all drag and drop hooks for this element
790 Event.un(this.id, "mousedown",
791 this.handleMouseDown);
793 this.DDM._remove(this);
796 destroy : function(){
801 * Returns true if this instance is locked, or the drag drop mgr is locked
802 * (meaning that all drag/drop is disabled on the page.)
804 * @return {boolean} true if this obj or all drag/drop is locked, else
807 isLocked: function() {
808 return (this.DDM.isLocked() || this.locked);
812 * Fired when this object is clicked
813 * @method handleMouseDown
815 * @param {Roo.dd.DragDrop} oDD the clicked dd object (this dd obj)
818 handleMouseDown: function(e, oDD){
819 if (this.primaryButtonOnly && e.button != 0) {
823 if (this.isLocked()) {
827 this.DDM.refreshCache(this.groups);
829 var pt = new Roo.lib.Point(Roo.lib.Event.getPageX(e), Roo.lib.Event.getPageY(e));
830 if (!this.hasOuterHandles && !this.DDM.isOverTarget(pt, this) ) {
832 if (this.clickValidator(e)) {
834 // set the initial element position
835 this.setStartPosition();
841 this.DDM.handleMouseDown(e, this);
843 this.DDM.stopEvent(e);
851 clickValidator: function(e) {
852 var target = e.getTarget();
853 return ( this.isValidHandleChild(target) &&
854 (this.id == this.handleElId ||
855 this.DDM.handleWasClicked(target, this.id)) );
859 * Allows you to specify a tag name that should not start a drag operation
860 * when clicked. This is designed to facilitate embedding links within a
861 * drag handle that do something other than start the drag.
862 * @method addInvalidHandleType
863 * @param {string} tagName the type of element to exclude
865 addInvalidHandleType: function(tagName) {
866 var type = tagName.toUpperCase();
867 this.invalidHandleTypes[type] = type;
871 * Lets you to specify an element id for a child of a drag handle
872 * that should not initiate a drag
873 * @method addInvalidHandleId
874 * @param {string} id the element id of the element you wish to ignore
876 addInvalidHandleId: function(id) {
877 if (typeof id !== "string") {
880 this.invalidHandleIds[id] = id;
884 * Lets you specify a css class of elements that will not initiate a drag
885 * @method addInvalidHandleClass
886 * @param {string} cssClass the class of the elements you wish to ignore
888 addInvalidHandleClass: function(cssClass) {
889 this.invalidHandleClasses.push(cssClass);
893 * Unsets an excluded tag name set by addInvalidHandleType
894 * @method removeInvalidHandleType
895 * @param {string} tagName the type of element to unexclude
897 removeInvalidHandleType: function(tagName) {
898 var type = tagName.toUpperCase();
899 // this.invalidHandleTypes[type] = null;
900 delete this.invalidHandleTypes[type];
904 * Unsets an invalid handle id
905 * @method removeInvalidHandleId
906 * @param {string} id the id of the element to re-enable
908 removeInvalidHandleId: function(id) {
909 if (typeof id !== "string") {
912 delete this.invalidHandleIds[id];
916 * Unsets an invalid css class
917 * @method removeInvalidHandleClass
918 * @param {string} cssClass the class of the element(s) you wish to
921 removeInvalidHandleClass: function(cssClass) {
922 for (var i=0, len=this.invalidHandleClasses.length; i<len; ++i) {
923 if (this.invalidHandleClasses[i] == cssClass) {
924 delete this.invalidHandleClasses[i];
930 * Checks the tag exclusion list to see if this click should be ignored
931 * @method isValidHandleChild
932 * @param {HTMLElement} node the HTMLElement to evaluate
933 * @return {boolean} true if this is a valid tag type, false if not
935 isValidHandleChild: function(node) {
938 // var n = (node.nodeName == "#text") ? node.parentNode : node;
941 nodeName = node.nodeName.toUpperCase();
943 nodeName = node.nodeName;
945 valid = valid && !this.invalidHandleTypes[nodeName];
946 valid = valid && !this.invalidHandleIds[node.id];
948 for (var i=0, len=this.invalidHandleClasses.length; valid && i<len; ++i) {
949 valid = !Dom.hasClass(node, this.invalidHandleClasses[i]);
958 * Create the array of horizontal tick marks if an interval was specified
959 * in setXConstraint().
963 setXTicks: function(iStartX, iTickSize) {
965 this.xTickSize = iTickSize;
969 for (var i = this.initPageX; i >= this.minX; i = i - iTickSize) {
971 this.xTicks[this.xTicks.length] = i;
976 for (i = this.initPageX; i <= this.maxX; i = i + iTickSize) {
978 this.xTicks[this.xTicks.length] = i;
983 this.xTicks.sort(this.DDM.numericSort) ;
987 * Create the array of vertical tick marks if an interval was specified in
992 setYTicks: function(iStartY, iTickSize) {
994 this.yTickSize = iTickSize;
998 for (var i = this.initPageY; i >= this.minY; i = i - iTickSize) {
1000 this.yTicks[this.yTicks.length] = i;
1005 for (i = this.initPageY; i <= this.maxY; i = i + iTickSize) {
1007 this.yTicks[this.yTicks.length] = i;
1012 this.yTicks.sort(this.DDM.numericSort) ;
1016 * By default, the element can be dragged any place on the screen. Use
1017 * this method to limit the horizontal travel of the element. Pass in
1018 * 0,0 for the parameters if you want to lock the drag to the y axis.
1019 * @method setXConstraint
1020 * @param {int} iLeft the number of pixels the element can move to the left
1021 * @param {int} iRight the number of pixels the element can move to the
1023 * @param {int} iTickSize optional parameter for specifying that the
1025 * should move iTickSize pixels at a time.
1027 setXConstraint: function(iLeft, iRight, iTickSize) {
1028 this.leftConstraint = iLeft;
1029 this.rightConstraint = iRight;
1031 this.minX = this.initPageX - iLeft;
1032 this.maxX = this.initPageX + iRight;
1033 if (iTickSize) { this.setXTicks(this.initPageX, iTickSize); }
1035 this.constrainX = true;
1039 * Clears any constraints applied to this instance. Also clears ticks
1040 * since they can't exist independent of a constraint at this time.
1041 * @method clearConstraints
1043 clearConstraints: function() {
1044 this.constrainX = false;
1045 this.constrainY = false;
1050 * Clears any tick interval defined for this instance
1051 * @method clearTicks
1053 clearTicks: function() {
1061 * By default, the element can be dragged any place on the screen. Set
1062 * this to limit the vertical travel of the element. Pass in 0,0 for the
1063 * parameters if you want to lock the drag to the x axis.
1064 * @method setYConstraint
1065 * @param {int} iUp the number of pixels the element can move up
1066 * @param {int} iDown the number of pixels the element can move down
1067 * @param {int} iTickSize optional parameter for specifying that the
1068 * element should move iTickSize pixels at a time.
1070 setYConstraint: function(iUp, iDown, iTickSize) {
1071 this.topConstraint = iUp;
1072 this.bottomConstraint = iDown;
1074 this.minY = this.initPageY - iUp;
1075 this.maxY = this.initPageY + iDown;
1076 if (iTickSize) { this.setYTicks(this.initPageY, iTickSize); }
1078 this.constrainY = true;
1083 * resetConstraints must be called if you manually reposition a dd element.
1084 * @method resetConstraints
1085 * @param {boolean} maintainOffset
1087 resetConstraints: function() {
1090 // Maintain offsets if necessary
1091 if (this.initPageX || this.initPageX === 0) {
1092 // figure out how much this thing has moved
1093 var dx = (this.maintainOffset) ? this.lastPageX - this.initPageX : 0;
1094 var dy = (this.maintainOffset) ? this.lastPageY - this.initPageY : 0;
1096 this.setInitPosition(dx, dy);
1098 // This is the first time we have detected the element's position
1100 this.setInitPosition();
1103 if (this.constrainX) {
1104 this.setXConstraint( this.leftConstraint,
1105 this.rightConstraint,
1109 if (this.constrainY) {
1110 this.setYConstraint( this.topConstraint,
1111 this.bottomConstraint,
1117 * Normally the drag element is moved pixel by pixel, but we can specify
1118 * that it move a number of pixels at a time. This method resolves the
1119 * location when we have it set up like this.
1121 * @param {int} val where we want to place the object
1122 * @param {int[]} tickArray sorted array of valid points
1123 * @return {int} the closest tick
1126 getTick: function(val, tickArray) {
1129 // If tick interval is not defined, it is effectively 1 pixel,
1130 // so we return the value passed to us.
1132 } else if (tickArray[0] >= val) {
1133 // The value is lower than the first tick, so we return the first
1135 return tickArray[0];
1137 for (var i=0, len=tickArray.length; i<len; ++i) {
1139 if (tickArray[next] && tickArray[next] >= val) {
1140 var diff1 = val - tickArray[i];
1141 var diff2 = tickArray[next] - val;
1142 return (diff2 > diff1) ? tickArray[i] : tickArray[next];
1146 // The value is larger than the last tick, so we return the last
1148 return tickArray[tickArray.length - 1];
1155 * @return {string} string representation of the dd obj
1157 toString: function() {
1158 return ("DragDrop " + this.id);
1166 * Ext JS Library 1.1.1
1167 * Copyright(c) 2006-2007, Ext JS, LLC.
1169 * Originally Released Under LGPL - original licence link has changed is not relivant.
1172 * <script type="text/javascript">
1177 * The drag and drop utility provides a framework for building drag and drop
1178 * applications. In addition to enabling drag and drop for specific elements,
1179 * the drag and drop elements are tracked by the manager class, and the
1180 * interactions between the various elements are tracked during the drag and
1181 * the implementing code is notified about these important moments.
1184 // Only load the library once. Rewriting the manager class would orphan
1185 // existing drag and drop instances.
1186 if (!Roo.dd.DragDropMgr) {
1189 * @class Roo.dd.DragDropMgr
1190 * DragDropMgr is a singleton that tracks the element interaction for
1191 * all DragDrop items in the window. Generally, you will not call
1192 * this class directly, but it does have helper methods that could
1193 * be useful in your DragDrop implementations.
1196 Roo.dd.DragDropMgr = function() {
1198 var Event = Roo.EventManager;
1203 * Two dimensional Array of registered DragDrop objects. The first
1204 * dimension is the DragDrop item group, the second the DragDrop
1207 * @type {string: string}
1214 * Array of element ids defined as drag handles. Used to determine
1215 * if the element that generated the mousedown event is actually the
1216 * handle and not the html element itself.
1217 * @property handleIds
1218 * @type {string: string}
1225 * the DragDrop object that is currently being dragged
1226 * @property dragCurrent
1234 * the DragDrop object(s) that are being hovered over
1235 * @property dragOvers
1243 * the X distance between the cursor and the object being dragged
1252 * the Y distance between the cursor and the object being dragged
1261 * Flag to determine if we should prevent the default behavior of the
1262 * events we define. By default this is true, but this can be set to
1263 * false if you need the default behavior (not recommended)
1264 * @property preventDefault
1268 preventDefault: true,
1271 * Flag to determine if we should stop the propagation of the events
1272 * we generate. This is true by default but you may want to set it to
1273 * false if the html element contains other features that require the
1275 * @property stopPropagation
1279 stopPropagation: true,
1282 * Internal flag that is set to true when drag and drop has been
1284 * @property initialized
1291 * All drag and drop can be disabled.
1299 * Called the first time an element is registered.
1305 this.initialized = true;
1309 * In point mode, drag and drop interaction is defined by the
1310 * location of the cursor during the drag/drop
1318 * In intersect mode, drag and drop interactio nis defined by the
1319 * overlap of two or more drag and drop objects.
1320 * @property INTERSECT
1327 * The current drag and drop mode. Default: POINT
1335 * Runs method on all drag and drop objects
1336 * @method _execOnAll
1340 _execOnAll: function(sMethod, args) {
1341 for (var i in this.ids) {
1342 for (var j in this.ids[i]) {
1343 var oDD = this.ids[i][j];
1344 if (! this.isTypeOfDD(oDD)) {
1347 oDD[sMethod].apply(oDD, args);
1353 * Drag and drop initialization. Sets up the global event handlers
1358 _onLoad: function() {
1363 Event.on(document, "mouseup", this.handleMouseUp, this, true);
1364 Event.on(document, "mousemove", this.handleMouseMove, this, true);
1365 Event.on(window, "unload", this._onUnload, this, true);
1366 Event.on(window, "resize", this._onResize, this, true);
1367 // Event.on(window, "mouseout", this._test);
1372 * Reset constraints on all drag and drop objs
1377 _onResize: function(e) {
1378 this._execOnAll("resetConstraints", []);
1382 * Lock all drag and drop functionality
1386 lock: function() { this.locked = true; },
1389 * Unlock all drag and drop functionality
1393 unlock: function() { this.locked = false; },
1396 * Is drag and drop locked?
1398 * @return {boolean} True if drag and drop is locked, false otherwise.
1401 isLocked: function() { return this.locked; },
1404 * Location cache that is set for all drag drop objects when a drag is
1405 * initiated, cleared when the drag is finished.
1406 * @property locationCache
1413 * Set useCache to false if you want to force object the lookup of each
1414 * drag and drop linked element constantly during a drag.
1415 * @property useCache
1422 * The number of pixels that the mouse needs to move after the
1423 * mousedown before the drag is initiated. Default=3;
1424 * @property clickPixelThresh
1428 clickPixelThresh: 3,
1431 * The number of milliseconds after the mousedown event to initiate the
1432 * drag if we don't get a mouseup event. Default=1000
1433 * @property clickTimeThresh
1437 clickTimeThresh: 350,
1440 * Flag that indicates that either the drag pixel threshold or the
1441 * mousdown time threshold has been met
1442 * @property dragThreshMet
1447 dragThreshMet: false,
1450 * Timeout used for the click time threshold
1451 * @property clickTimeout
1459 * The X position of the mousedown event stored for later use when a
1460 * drag threshold is met.
1469 * The Y position of the mousedown event stored for later use when a
1470 * drag threshold is met.
1479 * Each DragDrop instance must be registered with the DragDropMgr.
1480 * This is executed in DragDrop.init()
1481 * @method regDragDrop
1482 * @param {DragDrop} oDD the DragDrop object to register
1483 * @param {String} sGroup the name of the group this element belongs to
1486 regDragDrop: function(oDD, sGroup) {
1487 if (!this.initialized) { this.init(); }
1489 if (!this.ids[sGroup]) {
1490 this.ids[sGroup] = {};
1492 this.ids[sGroup][oDD.id] = oDD;
1496 * Removes the supplied dd instance from the supplied group. Executed
1497 * by DragDrop.removeFromGroup, so don't call this function directly.
1498 * @method removeDDFromGroup
1502 removeDDFromGroup: function(oDD, sGroup) {
1503 if (!this.ids[sGroup]) {
1504 this.ids[sGroup] = {};
1507 var obj = this.ids[sGroup];
1508 if (obj && obj[oDD.id]) {
1514 * Unregisters a drag and drop item. This is executed in
1515 * DragDrop.unreg, use that method instead of calling this directly.
1520 _remove: function(oDD) {
1521 for (var g in oDD.groups) {
1522 if (g && this.ids[g][oDD.id]) {
1523 delete this.ids[g][oDD.id];
1526 delete this.handleIds[oDD.id];
1530 * Each DragDrop handle element must be registered. This is done
1531 * automatically when executing DragDrop.setHandleElId()
1533 * @param {String} sDDId the DragDrop id this element is a handle for
1534 * @param {String} sHandleId the id of the element that is the drag
1538 regHandle: function(sDDId, sHandleId) {
1539 if (!this.handleIds[sDDId]) {
1540 this.handleIds[sDDId] = {};
1542 this.handleIds[sDDId][sHandleId] = sHandleId;
1546 * Utility function to determine if a given element has been
1547 * registered as a drag drop item.
1548 * @method isDragDrop
1549 * @param {String} id the element id to check
1550 * @return {boolean} true if this element is a DragDrop item,
1554 isDragDrop: function(id) {
1555 return ( this.getDDById(id) ) ? true : false;
1559 * Returns the drag and drop instances that are in all groups the
1560 * passed in instance belongs to.
1561 * @method getRelated
1562 * @param {DragDrop} p_oDD the obj to get related data for
1563 * @param {boolean} bTargetsOnly if true, only return targetable objs
1564 * @return {DragDrop[]} the related instances
1567 getRelated: function(p_oDD, bTargetsOnly) {
1569 for (var i in p_oDD.groups) {
1570 for (j in this.ids[i]) {
1571 var dd = this.ids[i][j];
1572 if (! this.isTypeOfDD(dd)) {
1575 if (!bTargetsOnly || dd.isTarget) {
1576 oDDs[oDDs.length] = dd;
1585 * Returns true if the specified dd target is a legal target for
1586 * the specifice drag obj
1587 * @method isLegalTarget
1588 * @param {DragDrop} the drag obj
1589 * @param {DragDrop} the target
1590 * @return {boolean} true if the target is a legal target for the
1594 isLegalTarget: function (oDD, oTargetDD) {
1595 var targets = this.getRelated(oDD, true);
1596 for (var i=0, len=targets.length;i<len;++i) {
1597 if (targets[i].id == oTargetDD.id) {
1606 * My goal is to be able to transparently determine if an object is
1607 * typeof DragDrop, and the exact subclass of DragDrop. typeof
1608 * returns "object", oDD.constructor.toString() always returns
1609 * "DragDrop" and not the name of the subclass. So for now it just
1610 * evaluates a well-known variable in DragDrop.
1611 * @method isTypeOfDD
1612 * @param {Object} the object to evaluate
1613 * @return {boolean} true if typeof oDD = DragDrop
1616 isTypeOfDD: function (oDD) {
1617 return (oDD && oDD.__ygDragDrop);
1621 * Utility function to determine if a given element has been
1622 * registered as a drag drop handle for the given Drag Drop object.
1624 * @param {String} id the element id to check
1625 * @return {boolean} true if this element is a DragDrop handle, false
1629 isHandle: function(sDDId, sHandleId) {
1630 return ( this.handleIds[sDDId] &&
1631 this.handleIds[sDDId][sHandleId] );
1635 * Returns the DragDrop instance for a given id
1637 * @param {String} id the id of the DragDrop object
1638 * @return {DragDrop} the drag drop object, null if it is not found
1641 getDDById: function(id) {
1642 for (var i in this.ids) {
1643 if (this.ids[i][id]) {
1644 return this.ids[i][id];
1651 * Fired after a registered DragDrop object gets the mousedown event.
1652 * Sets up the events required to track the object being dragged
1653 * @method handleMouseDown
1654 * @param {Event} e the event
1655 * @param oDD the DragDrop object being dragged
1659 handleMouseDown: function(e, oDD) {
1661 Roo.QuickTips.disable();
1663 this.currentTarget = e.getTarget();
1665 this.dragCurrent = oDD;
1667 var el = oDD.getEl();
1669 // track start position
1670 this.startX = e.getPageX();
1671 this.startY = e.getPageY();
1673 this.deltaX = this.startX - el.offsetLeft;
1674 this.deltaY = this.startY - el.offsetTop;
1676 this.dragThreshMet = false;
1678 this.clickTimeout = setTimeout(
1680 var DDM = Roo.dd.DDM;
1681 DDM.startDrag(DDM.startX, DDM.startY);
1683 this.clickTimeThresh );
1687 * Fired when either the drag pixel threshol or the mousedown hold
1688 * time threshold has been met.
1690 * @param x {int} the X position of the original mousedown
1691 * @param y {int} the Y position of the original mousedown
1694 startDrag: function(x, y) {
1695 clearTimeout(this.clickTimeout);
1696 if (this.dragCurrent) {
1697 this.dragCurrent.b4StartDrag(x, y);
1698 this.dragCurrent.startDrag(x, y);
1700 this.dragThreshMet = true;
1704 * Internal function to handle the mouseup event. Will be invoked
1705 * from the context of the document.
1706 * @method handleMouseUp
1707 * @param {Event} e the event
1711 handleMouseUp: function(e) {
1714 Roo.QuickTips.enable();
1716 if (! this.dragCurrent) {
1720 clearTimeout(this.clickTimeout);
1722 if (this.dragThreshMet) {
1723 this.fireEvents(e, true);
1733 * Utility to stop event propagation and event default, if these
1734 * features are turned on.
1736 * @param {Event} e the event as returned by this.getEvent()
1739 stopEvent: function(e){
1740 if(this.stopPropagation) {
1741 e.stopPropagation();
1744 if (this.preventDefault) {
1750 * Internal function to clean up event handlers after the drag
1751 * operation is complete
1753 * @param {Event} e the event
1757 stopDrag: function(e) {
1758 // Fire the drag end event for the item that was dragged
1759 if (this.dragCurrent) {
1760 if (this.dragThreshMet) {
1761 this.dragCurrent.b4EndDrag(e);
1762 this.dragCurrent.endDrag(e);
1765 this.dragCurrent.onMouseUp(e);
1768 this.dragCurrent = null;
1769 this.dragOvers = {};
1773 * Internal function to handle the mousemove event. Will be invoked
1774 * from the context of the html element.
1776 * @TODO figure out what we can do about mouse events lost when the
1777 * user drags objects beyond the window boundary. Currently we can
1778 * detect this in internet explorer by verifying that the mouse is
1779 * down during the mousemove event. Firefox doesn't give us the
1780 * button state on the mousemove event.
1781 * @method handleMouseMove
1782 * @param {Event} e the event
1786 handleMouseMove: function(e) {
1787 if (! this.dragCurrent) {
1791 // var button = e.which || e.button;
1793 // check for IE mouseup outside of page boundary
1794 if (Roo.isIE && (e.button !== 0 && e.button !== 1 && e.button !== 2)) {
1796 return this.handleMouseUp(e);
1799 if (!this.dragThreshMet) {
1800 var diffX = Math.abs(this.startX - e.getPageX());
1801 var diffY = Math.abs(this.startY - e.getPageY());
1802 if (diffX > this.clickPixelThresh ||
1803 diffY > this.clickPixelThresh) {
1804 this.startDrag(this.startX, this.startY);
1808 if (this.dragThreshMet) {
1809 this.dragCurrent.b4Drag(e);
1810 this.dragCurrent.onDrag(e);
1811 if(!this.dragCurrent.moveOnly){
1812 this.fireEvents(e, false);
1822 * Iterates over all of the DragDrop elements to find ones we are
1823 * hovering over or dropping on
1824 * @method fireEvents
1825 * @param {Event} e the event
1826 * @param {boolean} isDrop is this a drop op or a mouseover op?
1830 fireEvents: function(e, isDrop) {
1831 var dc = this.dragCurrent;
1833 // If the user did the mouse up outside of the window, we could
1834 // get here even though we have ended the drag.
1835 if (!dc || dc.isLocked()) {
1839 var pt = e.getPoint();
1841 // cache the previous dragOver array
1849 // Check to see if the object(s) we were hovering over is no longer
1850 // being hovered over so we can fire the onDragOut event
1851 for (var i in this.dragOvers) {
1853 var ddo = this.dragOvers[i];
1855 if (! this.isTypeOfDD(ddo)) {
1859 if (! this.isOverTarget(pt, ddo, this.mode)) {
1860 outEvts.push( ddo );
1864 delete this.dragOvers[i];
1867 for (var sGroup in dc.groups) {
1869 if ("string" != typeof sGroup) {
1873 for (i in this.ids[sGroup]) {
1874 var oDD = this.ids[sGroup][i];
1875 if (! this.isTypeOfDD(oDD)) {
1879 if (oDD.isTarget && !oDD.isLocked() && oDD != dc) {
1880 if (this.isOverTarget(pt, oDD, this.mode)) {
1881 // look for drop interactions
1883 dropEvts.push( oDD );
1884 // look for drag enter and drag over interactions
1887 // initial drag over: dragEnter fires
1888 if (!oldOvers[oDD.id]) {
1889 enterEvts.push( oDD );
1890 // subsequent drag overs: dragOver fires
1892 overEvts.push( oDD );
1895 this.dragOvers[oDD.id] = oDD;
1903 if (outEvts.length) {
1904 dc.b4DragOut(e, outEvts);
1905 dc.onDragOut(e, outEvts);
1908 if (enterEvts.length) {
1909 dc.onDragEnter(e, enterEvts);
1912 if (overEvts.length) {
1913 dc.b4DragOver(e, overEvts);
1914 dc.onDragOver(e, overEvts);
1917 if (dropEvts.length) {
1918 dc.b4DragDrop(e, dropEvts);
1919 dc.onDragDrop(e, dropEvts);
1923 // fire dragout events
1925 for (i=0, len=outEvts.length; i<len; ++i) {
1926 dc.b4DragOut(e, outEvts[i].id);
1927 dc.onDragOut(e, outEvts[i].id);
1930 // fire enter events
1931 for (i=0,len=enterEvts.length; i<len; ++i) {
1932 // dc.b4DragEnter(e, oDD.id);
1933 dc.onDragEnter(e, enterEvts[i].id);
1937 for (i=0,len=overEvts.length; i<len; ++i) {
1938 dc.b4DragOver(e, overEvts[i].id);
1939 dc.onDragOver(e, overEvts[i].id);
1943 for (i=0, len=dropEvts.length; i<len; ++i) {
1944 dc.b4DragDrop(e, dropEvts[i].id);
1945 dc.onDragDrop(e, dropEvts[i].id);
1950 // notify about a drop that did not find a target
1951 if (isDrop && !dropEvts.length) {
1952 dc.onInvalidDrop(e);
1958 * Helper function for getting the best match from the list of drag
1959 * and drop objects returned by the drag and drop events when we are
1960 * in INTERSECT mode. It returns either the first object that the
1961 * cursor is over, or the object that has the greatest overlap with
1962 * the dragged element.
1963 * @method getBestMatch
1964 * @param {DragDrop[]} dds The array of drag and drop objects
1966 * @return {DragDrop} The best single match
1969 getBestMatch: function(dds) {
1971 // Return null if the input is not what we expect
1972 //if (!dds || !dds.length || dds.length == 0) {
1974 // If there is only one item, it wins
1975 //} else if (dds.length == 1) {
1977 var len = dds.length;
1982 // Loop through the targeted items
1983 for (var i=0; i<len; ++i) {
1985 // If the cursor is over the object, it wins. If the
1986 // cursor is over multiple matches, the first one we come
1988 if (dd.cursorIsOver) {
1991 // Otherwise the object with the most overlap wins
1994 winner.overlap.getArea() < dd.overlap.getArea()) {
2005 * Refreshes the cache of the top-left and bottom-right points of the
2006 * drag and drop objects in the specified group(s). This is in the
2007 * format that is stored in the drag and drop instance, so typical
2010 * Roo.dd.DragDropMgr.refreshCache(ddinstance.groups);
2014 * Roo.dd.DragDropMgr.refreshCache({group1:true, group2:true});
2016 * @TODO this really should be an indexed array. Alternatively this
2017 * method could accept both.
2018 * @method refreshCache
2019 * @param {Object} groups an associative array of groups to refresh
2022 refreshCache: function(groups) {
2023 for (var sGroup in groups) {
2024 if ("string" != typeof sGroup) {
2027 for (var i in this.ids[sGroup]) {
2028 var oDD = this.ids[sGroup][i];
2030 if (this.isTypeOfDD(oDD)) {
2031 // if (this.isTypeOfDD(oDD) && oDD.isTarget) {
2032 var loc = this.getLocation(oDD);
2034 this.locationCache[oDD.id] = loc;
2036 delete this.locationCache[oDD.id];
2037 // this will unregister the drag and drop object if
2038 // the element is not in a usable state
2047 * This checks to make sure an element exists and is in the DOM. The
2048 * main purpose is to handle cases where innerHTML is used to remove
2049 * drag and drop objects from the DOM. IE provides an 'unspecified
2050 * error' when trying to access the offsetParent of such an element
2052 * @param {HTMLElement} el the element to check
2053 * @return {boolean} true if the element looks usable
2056 verifyEl: function(el) {
2061 parent = el.offsetParent;
2064 parent = el.offsetParent;
2075 * Returns a Region object containing the drag and drop element's position
2076 * and size, including the padding configured for it
2077 * @method getLocation
2078 * @param {DragDrop} oDD the drag and drop object to get the
2080 * @return {Roo.lib.Region} a Region object representing the total area
2081 * the element occupies, including any padding
2082 * the instance is configured for.
2085 getLocation: function(oDD) {
2086 if (! this.isTypeOfDD(oDD)) {
2090 var el = oDD.getEl(), pos, x1, x2, y1, y2, t, r, b, l;
2093 pos= Roo.lib.Dom.getXY(el);
2101 x2 = x1 + el.offsetWidth;
2103 y2 = y1 + el.offsetHeight;
2105 t = y1 - oDD.padding[0];
2106 r = x2 + oDD.padding[1];
2107 b = y2 + oDD.padding[2];
2108 l = x1 - oDD.padding[3];
2110 return new Roo.lib.Region( t, r, b, l );
2114 * Checks the cursor location to see if it over the target
2115 * @method isOverTarget
2116 * @param {Roo.lib.Point} pt The point to evaluate
2117 * @param {DragDrop} oTarget the DragDrop object we are inspecting
2118 * @return {boolean} true if the mouse is over the target
2122 isOverTarget: function(pt, oTarget, intersect) {
2123 // use cache if available
2124 var loc = this.locationCache[oTarget.id];
2125 if (!loc || !this.useCache) {
2126 loc = this.getLocation(oTarget);
2127 this.locationCache[oTarget.id] = loc;
2135 oTarget.cursorIsOver = loc.contains( pt );
2137 // DragDrop is using this as a sanity check for the initial mousedown
2138 // in this case we are done. In POINT mode, if the drag obj has no
2139 // contraints, we are also done. Otherwise we need to evaluate the
2140 // location of the target as related to the actual location of the
2142 var dc = this.dragCurrent;
2143 if (!dc || !dc.getTargetCoord ||
2144 (!intersect && !dc.constrainX && !dc.constrainY)) {
2145 return oTarget.cursorIsOver;
2148 oTarget.overlap = null;
2150 // Get the current location of the drag element, this is the
2151 // location of the mouse event less the delta that represents
2152 // where the original mousedown happened on the element. We
2153 // need to consider constraints and ticks as well.
2154 var pos = dc.getTargetCoord(pt.x, pt.y);
2156 var el = dc.getDragEl();
2157 var curRegion = new Roo.lib.Region( pos.y,
2158 pos.x + el.offsetWidth,
2159 pos.y + el.offsetHeight,
2162 var overlap = curRegion.intersect(loc);
2165 oTarget.overlap = overlap;
2166 return (intersect) ? true : oTarget.cursorIsOver;
2173 * unload event handler
2178 _onUnload: function(e, me) {
2179 Roo.dd.DragDropMgr.unregAll();
2183 * Cleans up the drag and drop events and objects.
2188 unregAll: function() {
2190 if (this.dragCurrent) {
2192 this.dragCurrent = null;
2195 this._execOnAll("unreg", []);
2197 for (i in this.elementCache) {
2198 delete this.elementCache[i];
2201 this.elementCache = {};
2206 * A cache of DOM elements
2207 * @property elementCache
2214 * Get the wrapper for the DOM element specified
2215 * @method getElWrapper
2216 * @param {String} id the id of the element to get
2217 * @return {Roo.dd.DDM.ElementWrapper} the wrapped element
2219 * @deprecated This wrapper isn't that useful
2222 getElWrapper: function(id) {
2223 var oWrapper = this.elementCache[id];
2224 if (!oWrapper || !oWrapper.el) {
2225 oWrapper = this.elementCache[id] =
2226 new this.ElementWrapper(Roo.getDom(id));
2232 * Returns the actual DOM element
2233 * @method getElement
2234 * @param {String} id the id of the elment to get
2235 * @return {Object} The element
2236 * @deprecated use Roo.getDom instead
2239 getElement: function(id) {
2240 return Roo.getDom(id);
2244 * Returns the style property for the DOM element (i.e.,
2245 * document.getElById(id).style)
2247 * @param {String} id the id of the elment to get
2248 * @return {Object} The style property of the element
2249 * @deprecated use Roo.getDom instead
2252 getCss: function(id) {
2253 var el = Roo.getDom(id);
2254 return (el) ? el.style : null;
2258 * Inner class for cached elements
2259 * @class DragDropMgr.ElementWrapper
2264 ElementWrapper: function(el) {
2269 this.el = el || null;
2274 this.id = this.el && el.id;
2276 * A reference to the style property
2279 this.css = this.el && el.style;
2283 * Returns the X position of an html element
2285 * @param el the element for which to get the position
2286 * @return {int} the X coordinate
2288 * @deprecated use Roo.lib.Dom.getX instead
2291 getPosX: function(el) {
2292 return Roo.lib.Dom.getX(el);
2296 * Returns the Y position of an html element
2298 * @param el the element for which to get the position
2299 * @return {int} the Y coordinate
2300 * @deprecated use Roo.lib.Dom.getY instead
2303 getPosY: function(el) {
2304 return Roo.lib.Dom.getY(el);
2308 * Swap two nodes. In IE, we use the native method, for others we
2309 * emulate the IE behavior
2311 * @param n1 the first node to swap
2312 * @param n2 the other node to swap
2315 swapNode: function(n1, n2) {
2319 var p = n2.parentNode;
2320 var s = n2.nextSibling;
2323 p.insertBefore(n1, n2);
2324 } else if (n2 == n1.nextSibling) {
2325 p.insertBefore(n2, n1);
2327 n1.parentNode.replaceChild(n2, n1);
2328 p.insertBefore(n1, s);
2334 * Returns the current scroll position
2339 getScroll: function () {
2340 var t, l, dde=document.documentElement, db=document.body;
2341 if (dde && (dde.scrollTop || dde.scrollLeft)) {
2350 return { top: t, left: l };
2354 * Returns the specified element style property
2356 * @param {HTMLElement} el the element
2357 * @param {string} styleProp the style property
2358 * @return {string} The value of the style property
2359 * @deprecated use Roo.lib.Dom.getStyle
2362 getStyle: function(el, styleProp) {
2363 return Roo.fly(el).getStyle(styleProp);
2367 * Gets the scrollTop
2368 * @method getScrollTop
2369 * @return {int} the document's scrollTop
2372 getScrollTop: function () { return this.getScroll().top; },
2375 * Gets the scrollLeft
2376 * @method getScrollLeft
2377 * @return {int} the document's scrollTop
2380 getScrollLeft: function () { return this.getScroll().left; },
2383 * Sets the x/y position of an element to the location of the
2386 * @param {HTMLElement} moveEl The element to move
2387 * @param {HTMLElement} targetEl The position reference element
2390 moveToEl: function (moveEl, targetEl) {
2391 var aCoord = Roo.lib.Dom.getXY(targetEl);
2392 Roo.lib.Dom.setXY(moveEl, aCoord);
2396 * Numeric array sort function
2397 * @method numericSort
2400 numericSort: function(a, b) { return (a - b); },
2404 * @property _timeoutCount
2411 * Trying to make the load order less important. Without this we get
2412 * an error if this file is loaded before the Event Utility.
2413 * @method _addListeners
2417 _addListeners: function() {
2418 var DDM = Roo.dd.DDM;
2419 if ( Roo.lib.Event && document ) {
2422 if (DDM._timeoutCount > 2000) {
2424 setTimeout(DDM._addListeners, 10);
2425 if (document && document.body) {
2426 DDM._timeoutCount += 1;
2433 * Recursively searches the immediate parent and all child nodes for
2434 * the handle element in order to determine wheter or not it was
2436 * @method handleWasClicked
2437 * @param node the html element to inspect
2440 handleWasClicked: function(node, id) {
2441 if (this.isHandle(id, node.id)) {
2444 // check to see if this is a text node child of the one we want
2445 var p = node.parentNode;
2448 if (this.isHandle(id, p.id)) {
2463 // shorter alias, save a few bytes
2464 Roo.dd.DDM = Roo.dd.DragDropMgr;
2465 Roo.dd.DDM._addListeners();
2469 * Ext JS Library 1.1.1
2470 * Copyright(c) 2006-2007, Ext JS, LLC.
2472 * Originally Released Under LGPL - original licence link has changed is not relivant.
2475 * <script type="text/javascript">
2480 * A DragDrop implementation where the linked element follows the
2481 * mouse cursor during a drag.
2482 * @extends Roo.dd.DragDrop
2484 * @param {String} id the id of the linked element
2485 * @param {String} sGroup the group of related DragDrop items
2486 * @param {object} config an object containing configurable attributes
2487 * Valid properties for DD:
2490 Roo.dd.DD = function(id, sGroup, config) {
2492 this.init(id, sGroup, config);
2496 Roo.extend(Roo.dd.DD, Roo.dd.DragDrop, {
2499 * When set to true, the utility automatically tries to scroll the browser
2500 * window wehn a drag and drop element is dragged near the viewport boundary.
2508 * Sets the pointer offset to the distance between the linked element's top
2509 * left corner and the location the element was clicked
2510 * @method autoOffset
2511 * @param {int} iPageX the X coordinate of the click
2512 * @param {int} iPageY the Y coordinate of the click
2514 autoOffset: function(iPageX, iPageY) {
2515 var x = iPageX - this.startPageX;
2516 var y = iPageY - this.startPageY;
2517 this.setDelta(x, y);
2521 * Sets the pointer offset. You can call this directly to force the
2522 * offset to be in a particular location (e.g., pass in 0,0 to set it
2523 * to the center of the object)
2525 * @param {int} iDeltaX the distance from the left
2526 * @param {int} iDeltaY the distance from the top
2528 setDelta: function(iDeltaX, iDeltaY) {
2529 this.deltaX = iDeltaX;
2530 this.deltaY = iDeltaY;
2534 * Sets the drag element to the location of the mousedown or click event,
2535 * maintaining the cursor location relative to the location on the element
2536 * that was clicked. Override this if you want to place the element in a
2537 * location other than where the cursor is.
2538 * @method setDragElPos
2539 * @param {int} iPageX the X coordinate of the mousedown or drag event
2540 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2542 setDragElPos: function(iPageX, iPageY) {
2543 // the first time we do this, we are going to check to make sure
2544 // the element has css positioning
2546 var el = this.getDragEl();
2547 this.alignElWithMouse(el, iPageX, iPageY);
2551 * Sets the element to the location of the mousedown or click event,
2552 * maintaining the cursor location relative to the location on the element
2553 * that was clicked. Override this if you want to place the element in a
2554 * location other than where the cursor is.
2555 * @method alignElWithMouse
2556 * @param {HTMLElement} el the element to move
2557 * @param {int} iPageX the X coordinate of the mousedown or drag event
2558 * @param {int} iPageY the Y coordinate of the mousedown or drag event
2560 alignElWithMouse: function(el, iPageX, iPageY) {
2561 var oCoord = this.getTargetCoord(iPageX, iPageY);
2562 var fly = el.dom ? el : Roo.fly(el);
2563 if (!this.deltaSetXY) {
2564 var aCoord = [oCoord.x, oCoord.y];
2566 var newLeft = fly.getLeft(true);
2567 var newTop = fly.getTop(true);
2568 this.deltaSetXY = [ newLeft - oCoord.x, newTop - oCoord.y ];
2570 fly.setLeftTop(oCoord.x + this.deltaSetXY[0], oCoord.y + this.deltaSetXY[1]);
2573 this.cachePosition(oCoord.x, oCoord.y);
2574 this.autoScroll(oCoord.x, oCoord.y, el.offsetHeight, el.offsetWidth);
2579 * Saves the most recent position so that we can reset the constraints and
2580 * tick marks on-demand. We need to know this so that we can calculate the
2581 * number of pixels the element is offset from its original position.
2582 * @method cachePosition
2583 * @param iPageX the current x position (optional, this just makes it so we
2584 * don't have to look it up again)
2585 * @param iPageY the current y position (optional, this just makes it so we
2586 * don't have to look it up again)
2588 cachePosition: function(iPageX, iPageY) {
2590 this.lastPageX = iPageX;
2591 this.lastPageY = iPageY;
2593 var aCoord = Roo.lib.Dom.getXY(this.getEl());
2594 this.lastPageX = aCoord[0];
2595 this.lastPageY = aCoord[1];
2600 * Auto-scroll the window if the dragged object has been moved beyond the
2601 * visible window boundary.
2602 * @method autoScroll
2603 * @param {int} x the drag element's x position
2604 * @param {int} y the drag element's y position
2605 * @param {int} h the height of the drag element
2606 * @param {int} w the width of the drag element
2609 autoScroll: function(x, y, h, w) {
2612 // The client height
2613 var clientH = Roo.lib.Dom.getViewWidth();
2616 var clientW = Roo.lib.Dom.getViewHeight();
2618 // The amt scrolled down
2619 var st = this.DDM.getScrollTop();
2621 // The amt scrolled right
2622 var sl = this.DDM.getScrollLeft();
2624 // Location of the bottom of the element
2627 // Location of the right of the element
2630 // The distance from the cursor to the bottom of the visible area,
2631 // adjusted so that we don't scroll if the cursor is beyond the
2632 // element drag constraints
2633 var toBot = (clientH + st - y - this.deltaY);
2635 // The distance from the cursor to the right of the visible area
2636 var toRight = (clientW + sl - x - this.deltaX);
2639 // How close to the edge the cursor must be before we scroll
2640 // var thresh = (document.all) ? 100 : 40;
2643 // How many pixels to scroll per autoscroll op. This helps to reduce
2644 // clunky scrolling. IE is more sensitive about this ... it needs this
2645 // value to be higher.
2646 var scrAmt = (document.all) ? 80 : 30;
2648 // Scroll down if we are near the bottom of the visible page and the
2649 // obj extends below the crease
2650 if ( bot > clientH && toBot < thresh ) {
2651 window.scrollTo(sl, st + scrAmt);
2654 // Scroll up if the window is scrolled down and the top of the object
2655 // goes above the top border
2656 if ( y < st && st > 0 && y - st < thresh ) {
2657 window.scrollTo(sl, st - scrAmt);
2660 // Scroll right if the obj is beyond the right border and the cursor is
2662 if ( right > clientW && toRight < thresh ) {
2663 window.scrollTo(sl + scrAmt, st);
2666 // Scroll left if the window has been scrolled to the right and the obj
2667 // extends past the left border
2668 if ( x < sl && sl > 0 && x - sl < thresh ) {
2669 window.scrollTo(sl - scrAmt, st);
2675 * Finds the location the element should be placed if we want to move
2676 * it to where the mouse location less the click offset would place us.
2677 * @method getTargetCoord
2678 * @param {int} iPageX the X coordinate of the click
2679 * @param {int} iPageY the Y coordinate of the click
2680 * @return an object that contains the coordinates (Object.x and Object.y)
2683 getTargetCoord: function(iPageX, iPageY) {
2686 var x = iPageX - this.deltaX;
2687 var y = iPageY - this.deltaY;
2689 if (this.constrainX) {
2690 if (x < this.minX) { x = this.minX; }
2691 if (x > this.maxX) { x = this.maxX; }
2694 if (this.constrainY) {
2695 if (y < this.minY) { y = this.minY; }
2696 if (y > this.maxY) { y = this.maxY; }
2699 x = this.getTick(x, this.xTicks);
2700 y = this.getTick(y, this.yTicks);
2707 * Sets up config options specific to this class. Overrides
2708 * Roo.dd.DragDrop, but all versions of this method through the
2709 * inheritance chain are called
2711 applyConfig: function() {
2712 Roo.dd.DD.superclass.applyConfig.call(this);
2713 this.scroll = (this.config.scroll !== false);
2717 * Event that fires prior to the onMouseDown event. Overrides
2720 b4MouseDown: function(e) {
2721 // this.resetConstraints();
2722 this.autoOffset(e.getPageX(),
2727 * Event that fires prior to the onDrag event. Overrides
2730 b4Drag: function(e) {
2731 this.setDragElPos(e.getPageX(),
2735 toString: function() {
2736 return ("DD " + this.id);
2739 //////////////////////////////////////////////////////////////////////////
2740 // Debugging ygDragDrop events that can be overridden
2741 //////////////////////////////////////////////////////////////////////////
2743 startDrag: function(x, y) {
2746 onDrag: function(e) {
2749 onDragEnter: function(e, id) {
2752 onDragOver: function(e, id) {
2755 onDragOut: function(e, id) {
2758 onDragDrop: function(e, id) {
2761 endDrag: function(e) {
2768 * Ext JS Library 1.1.1
2769 * Copyright(c) 2006-2007, Ext JS, LLC.
2771 * Originally Released Under LGPL - original licence link has changed is not relivant.
2774 * <script type="text/javascript">
2778 * @class Roo.dd.DDProxy
2779 * A DragDrop implementation that inserts an empty, bordered div into
2780 * the document that follows the cursor during drag operations. At the time of
2781 * the click, the frame div is resized to the dimensions of the linked html
2782 * element, and moved to the exact location of the linked element.
2784 * References to the "frame" element refer to the single proxy element that
2785 * was created to be dragged in place of all DDProxy elements on the
2788 * @extends Roo.dd.DD
2790 * @param {String} id the id of the linked html element
2791 * @param {String} sGroup the group of related DragDrop objects
2792 * @param {object} config an object containing configurable attributes
2793 * Valid properties for DDProxy in addition to those in DragDrop:
2794 * resizeFrame, centerFrame, dragElId
2796 Roo.dd.DDProxy = function(id, sGroup, config) {
2798 this.init(id, sGroup, config);
2804 * The default drag frame div id
2805 * @property Roo.dd.DDProxy.dragElId
2809 Roo.dd.DDProxy.dragElId = "ygddfdiv";
2811 Roo.extend(Roo.dd.DDProxy, Roo.dd.DD, {
2814 * By default we resize the drag frame to be the same size as the element
2815 * we want to drag (this is to get the frame effect). We can turn it off
2816 * if we want a different behavior.
2817 * @property resizeFrame
2823 * By default the frame is positioned exactly where the drag element is, so
2824 * we use the cursor offset provided by Roo.dd.DD. Another option that works only if
2825 * you do not have constraints on the obj is to have the drag frame centered
2826 * around the cursor. Set centerFrame to true for this effect.
2827 * @property centerFrame
2833 * Creates the proxy element if it does not yet exist
2834 * @method createFrame
2836 createFrame: function() {
2838 var body = document.body;
2840 if (!body || !body.firstChild) {
2841 setTimeout( function() { self.createFrame(); }, 50 );
2845 var div = this.getDragEl();
2848 div = document.createElement("div");
2849 div.id = this.dragElId;
2852 s.position = "absolute";
2853 s.visibility = "hidden";
2855 s.border = "2px solid #aaa";
2858 // appendChild can blow up IE if invoked prior to the window load event
2859 // while rendering a table. It is possible there are other scenarios
2860 // that would cause this to happen as well.
2861 body.insertBefore(div, body.firstChild);
2866 * Initialization for the drag frame element. Must be called in the
2867 * constructor of all subclasses
2870 initFrame: function() {
2874 applyConfig: function() {
2875 Roo.dd.DDProxy.superclass.applyConfig.call(this);
2877 this.resizeFrame = (this.config.resizeFrame !== false);
2878 this.centerFrame = (this.config.centerFrame);
2879 this.setDragElId(this.config.dragElId || Roo.dd.DDProxy.dragElId);
2883 * Resizes the drag frame to the dimensions of the clicked object, positions
2884 * it over the object, and finally displays it
2886 * @param {int} iPageX X click position
2887 * @param {int} iPageY Y click position
2890 showFrame: function(iPageX, iPageY) {
2891 var el = this.getEl();
2892 var dragEl = this.getDragEl();
2893 var s = dragEl.style;
2895 this._resizeProxy();
2897 if (this.centerFrame) {
2898 this.setDelta( Math.round(parseInt(s.width, 10)/2),
2899 Math.round(parseInt(s.height, 10)/2) );
2902 this.setDragElPos(iPageX, iPageY);
2904 Roo.fly(dragEl).show();
2908 * The proxy is automatically resized to the dimensions of the linked
2909 * element when a drag is initiated, unless resizeFrame is set to false
2910 * @method _resizeProxy
2913 _resizeProxy: function() {
2914 if (this.resizeFrame) {
2915 var el = this.getEl();
2916 Roo.fly(this.getDragEl()).setSize(el.offsetWidth, el.offsetHeight);
2920 // overrides Roo.dd.DragDrop
2921 b4MouseDown: function(e) {
2922 var x = e.getPageX();
2923 var y = e.getPageY();
2924 this.autoOffset(x, y);
2925 this.setDragElPos(x, y);
2928 // overrides Roo.dd.DragDrop
2929 b4StartDrag: function(x, y) {
2930 // show the drag frame
2931 this.showFrame(x, y);
2934 // overrides Roo.dd.DragDrop
2935 b4EndDrag: function(e) {
2936 Roo.fly(this.getDragEl()).hide();
2939 // overrides Roo.dd.DragDrop
2940 // By default we try to move the element to the last location of the frame.
2941 // This is so that the default behavior mirrors that of Roo.dd.DD.
2942 endDrag: function(e) {
2944 var lel = this.getEl();
2945 var del = this.getDragEl();
2947 // Show the drag frame briefly so we can get its position
2948 del.style.visibility = "";
2951 // Hide the linked element before the move to get around a Safari
2953 lel.style.visibility = "hidden";
2954 Roo.dd.DDM.moveToEl(lel, del);
2955 del.style.visibility = "hidden";
2956 lel.style.visibility = "";
2961 beforeMove : function(){
2965 afterDrag : function(){
2969 toString: function() {
2970 return ("DDProxy " + this.id);
2976 * Ext JS Library 1.1.1
2977 * Copyright(c) 2006-2007, Ext JS, LLC.
2979 * Originally Released Under LGPL - original licence link has changed is not relivant.
2982 * <script type="text/javascript">
2986 * @class Roo.dd.DDTarget
2987 * A DragDrop implementation that does not move, but can be a drop
2988 * target. You would get the same result by simply omitting implementation
2989 * for the event callbacks, but this way we reduce the processing cost of the
2990 * event listener and the callbacks.
2991 * @extends Roo.dd.DragDrop
2993 * @param {String} id the id of the element that is a drop target
2994 * @param {String} sGroup the group of related DragDrop objects
2995 * @param {object} config an object containing configurable attributes
2996 * Valid properties for DDTarget in addition to those in
3000 Roo.dd.DDTarget = function(id, sGroup, config) {
3002 this.initTarget(id, sGroup, config);
3004 if (config.listeners || config.events) {
3005 Roo.dd.DragDrop.superclass.constructor.call(this, {
3006 listeners : config.listeners || {},
3007 events : config.events || {}
3012 // Roo.dd.DDTarget.prototype = new Roo.dd.DragDrop();
3013 Roo.extend(Roo.dd.DDTarget, Roo.dd.DragDrop, {
3014 toString: function() {
3015 return ("DDTarget " + this.id);
3020 * Ext JS Library 1.1.1
3021 * Copyright(c) 2006-2007, Ext JS, LLC.
3023 * Originally Released Under LGPL - original licence link has changed is not relivant.
3026 * <script type="text/javascript">
3031 * @class Roo.dd.ScrollManager
3032 * Provides automatic scrolling of overflow regions in the page during drag operations.<br><br>
3033 * <b>Note: This class uses "Point Mode" and is untested in "Intersect Mode".</b>
3036 Roo.dd.ScrollManager = function(){
3037 var ddm = Roo.dd.DragDropMgr;
3042 var onStop = function(e){
3047 var triggerRefresh = function(){
3048 if(ddm.dragCurrent){
3049 ddm.refreshCache(ddm.dragCurrent.groups);
3053 var doScroll = function(){
3054 if(ddm.dragCurrent){
3055 var dds = Roo.dd.ScrollManager;
3057 if(proc.el.scroll(proc.dir, dds.increment)){
3061 proc.el.scroll(proc.dir, dds.increment, true, dds.animDuration, triggerRefresh);
3066 var clearProc = function(){
3068 clearInterval(proc.id);
3075 var startProc = function(el, dir){
3079 proc.id = setInterval(doScroll, Roo.dd.ScrollManager.frequency);
3082 var onFire = function(e, isDrop){
3083 if(isDrop || !ddm.dragCurrent){ return; }
3084 var dds = Roo.dd.ScrollManager;
3085 if(!dragEl || dragEl != ddm.dragCurrent){
3086 dragEl = ddm.dragCurrent;
3087 // refresh regions on drag start
3091 var xy = Roo.lib.Event.getXY(e);
3092 var pt = new Roo.lib.Point(xy[0], xy[1]);
3094 var el = els[id], r = el._region;
3095 if(r && r.contains(pt) && el.isScrollable()){
3096 if(r.bottom - pt.y <= dds.thresh){
3098 startProc(el, "down");
3101 }else if(r.right - pt.x <= dds.thresh){
3103 startProc(el, "left");
3106 }else if(pt.y - r.top <= dds.thresh){
3108 startProc(el, "up");
3111 }else if(pt.x - r.left <= dds.thresh){
3113 startProc(el, "right");
3122 ddm.fireEvents = ddm.fireEvents.createSequence(onFire, ddm);
3123 ddm.stopDrag = ddm.stopDrag.createSequence(onStop, ddm);
3127 * Registers new overflow element(s) to auto scroll
3128 * @param {String/HTMLElement/Element/Array} el The id of or the element to be scrolled or an array of either
3130 register : function(el){
3131 if(el instanceof Array){
3132 for(var i = 0, len = el.length; i < len; i++) {
3133 this.register(el[i]);
3142 * Unregisters overflow element(s) so they are no longer scrolled
3143 * @param {String/HTMLElement/Element/Array} el The id of or the element to be removed or an array of either
3145 unregister : function(el){
3146 if(el instanceof Array){
3147 for(var i = 0, len = el.length; i < len; i++) {
3148 this.unregister(el[i]);
3157 * The number of pixels from the edge of a container the pointer needs to be to
3158 * trigger scrolling (defaults to 25)
3164 * The number of pixels to scroll in each scroll increment (defaults to 50)
3170 * The frequency of scrolls in milliseconds (defaults to 500)
3176 * True to animate the scroll (defaults to true)
3182 * The animation duration in seconds -
3183 * MUST BE less than Roo.dd.ScrollManager.frequency! (defaults to .4)
3189 * Manually trigger a cache refresh.
3191 refreshCache : function(){
3193 if(typeof els[id] == 'object'){ // for people extending the object prototype
3194 els[id]._region = els[id].getRegion();
3201 * Ext JS Library 1.1.1
3202 * Copyright(c) 2006-2007, Ext JS, LLC.
3204 * Originally Released Under LGPL - original licence link has changed is not relivant.
3207 * <script type="text/javascript">
3212 * @class Roo.dd.Registry
3213 * Provides easy access to all drag drop components that are registered on a page. Items can be retrieved either
3214 * directly by DOM node id, or by passing in the drag drop event that occurred and looking up the event target.
3217 Roo.dd.Registry = function(){
3222 var getId = function(el, autogen){
3223 if(typeof el == "string"){
3227 if(!id && autogen !== false){
3228 id = "roodd-" + (++autoIdSeed);
3236 * Register a drag drop element
3237 * @param {String|HTMLElement} element The id or DOM node to register
3238 * @param {Object} data (optional) A custom data object that will be passed between the elements that are involved
3239 * in drag drop operations. You can populate this object with any arbitrary properties that your own code
3240 * knows how to interpret, plus there are some specific properties known to the Registry that should be
3241 * populated in the data object (if applicable):
3243 Value Description<br />
3244 --------- ------------------------------------------<br />
3245 handles Array of DOM nodes that trigger dragging<br />
3246 for the element being registered<br />
3247 isHandle True if the element passed in triggers<br />
3248 dragging itself, else false
3251 register : function(el, data){
3253 if(typeof el == "string"){
3254 el = document.getElementById(el);
3257 elements[getId(el)] = data;
3258 if(data.isHandle !== false){
3259 handles[data.ddel.id] = data;
3262 var hs = data.handles;
3263 for(var i = 0, len = hs.length; i < len; i++){
3264 handles[getId(hs[i])] = data;
3270 * Unregister a drag drop element
3271 * @param {String|HTMLElement} element The id or DOM node to unregister
3273 unregister : function(el){
3274 var id = getId(el, false);
3275 var data = elements[id];
3277 delete elements[id];
3279 var hs = data.handles;
3280 for(var i = 0, len = hs.length; i < len; i++){
3281 delete handles[getId(hs[i], false)];
3288 * Returns the handle registered for a DOM Node by id
3289 * @param {String|HTMLElement} id The DOM node or id to look up
3290 * @return {Object} handle The custom handle data
3292 getHandle : function(id){
3293 if(typeof id != "string"){ // must be element?
3300 * Returns the handle that is registered for the DOM node that is the target of the event
3301 * @param {Event} e The event
3302 * @return {Object} handle The custom handle data
3304 getHandleFromEvent : function(e){
3305 var t = Roo.lib.Event.getTarget(e);
3306 return t ? handles[t.id] : null;
3310 * Returns a custom data object that is registered for a DOM node by id
3311 * @param {String|HTMLElement} id The DOM node or id to look up
3312 * @return {Object} data The custom data
3314 getTarget : function(id){
3315 if(typeof id != "string"){ // must be element?
3318 return elements[id];
3322 * Returns a custom data object that is registered for the DOM node that is the target of the event
3323 * @param {Event} e The event
3324 * @return {Object} data The custom data
3326 getTargetFromEvent : function(e){
3327 var t = Roo.lib.Event.getTarget(e);
3328 return t ? elements[t.id] || handles[t.id] : null;
3333 * Ext JS Library 1.1.1
3334 * Copyright(c) 2006-2007, Ext JS, LLC.
3336 * Originally Released Under LGPL - original licence link has changed is not relivant.
3339 * <script type="text/javascript">
3344 * @class Roo.dd.StatusProxy
3345 * A specialized drag proxy that supports a drop status icon, {@link Roo.Layer} styles and auto-repair. This is the
3346 * default drag proxy used by all Roo.dd components.
3348 * @param {Object} config
3350 Roo.dd.StatusProxy = function(config){
3351 Roo.apply(this, config);
3352 this.id = this.id || Roo.id();
3353 this.el = new Roo.Layer({
3355 id: this.id, tag: "div", cls: "x-dd-drag-proxy "+this.dropNotAllowed, children: [
3356 {tag: "div", cls: "x-dd-drop-icon"},
3357 {tag: "div", cls: "x-dd-drag-ghost"}
3360 shadow: !config || config.shadow !== false
3362 this.ghost = Roo.get(this.el.dom.childNodes[1]);
3363 this.dropStatus = this.dropNotAllowed;
3366 Roo.dd.StatusProxy.prototype = {
3368 * @cfg {String} dropAllowed
3369 * The CSS class to apply to the status element when drop is allowed (defaults to "x-dd-drop-ok").
3371 dropAllowed : "x-dd-drop-ok",
3373 * @cfg {String} dropNotAllowed
3374 * The CSS class to apply to the status element when drop is not allowed (defaults to "x-dd-drop-nodrop").
3376 dropNotAllowed : "x-dd-drop-nodrop",
3379 * Updates the proxy's visual element to indicate the status of whether or not drop is allowed
3380 * over the current target element.
3381 * @param {String} cssClass The css class for the new drop status indicator image
3383 setStatus : function(cssClass){
3384 cssClass = cssClass || this.dropNotAllowed;
3385 if(this.dropStatus != cssClass){
3386 this.el.replaceClass(this.dropStatus, cssClass);
3387 this.dropStatus = cssClass;
3392 * Resets the status indicator to the default dropNotAllowed value
3393 * @param {Boolean} clearGhost True to also remove all content from the ghost, false to preserve it
3395 reset : function(clearGhost){
3396 this.el.dom.className = "x-dd-drag-proxy " + this.dropNotAllowed;
3397 this.dropStatus = this.dropNotAllowed;
3399 this.ghost.update("");
3404 * Updates the contents of the ghost element
3405 * @param {String} html The html that will replace the current innerHTML of the ghost element
3407 update : function(html){
3408 if(typeof html == "string"){
3409 this.ghost.update(html);
3411 this.ghost.update("");
3412 html.style.margin = "0";
3413 this.ghost.dom.appendChild(html);
3415 // ensure float = none set?? cant remember why though.
3416 var el = this.ghost.dom.firstChild;
3418 Roo.fly(el).setStyle('float', 'none');
3423 * Returns the underlying proxy {@link Roo.Layer}
3424 * @return {Roo.Layer} el
3431 * Returns the ghost element
3432 * @return {Roo.Element} el
3434 getGhost : function(){
3440 * @param {Boolean} clear True to reset the status and clear the ghost contents, false to preserve them
3442 hide : function(clear){
3450 * Stops the repair animation if it's currently running
3453 if(this.anim && this.anim.isAnimated && this.anim.isAnimated()){
3459 * Displays this proxy
3466 * Force the Layer to sync its shadow and shim positions to the element
3473 * Causes the proxy to return to its position of origin via an animation. Should be called after an
3474 * invalid drop operation by the item being dragged.
3475 * @param {Array} xy The XY position of the element ([x, y])
3476 * @param {Function} callback The function to call after the repair is complete
3477 * @param {Object} scope The scope in which to execute the callback
3479 repair : function(xy, callback, scope){
3480 this.callback = callback;
3482 if(xy && this.animRepair !== false){
3483 this.el.addClass("x-dd-drag-repair");
3484 this.el.hideUnders(true);
3485 this.anim = this.el.shift({
3486 duration: this.repairDuration || .5,
3490 callback: this.afterRepair,
3499 afterRepair : function(){
3501 if(typeof this.callback == "function"){
3502 this.callback.call(this.scope || this);
3504 this.callback = null;
3509 * Ext JS Library 1.1.1
3510 * Copyright(c) 2006-2007, Ext JS, LLC.
3512 * Originally Released Under LGPL - original licence link has changed is not relivant.
3515 * <script type="text/javascript">
3519 * @class Roo.dd.DragSource
3520 * @extends Roo.dd.DDProxy
3521 * A simple class that provides the basic implementation needed to make any element draggable.
3523 * @param {String/HTMLElement/Element} el The container element
3524 * @param {Object} config
3526 Roo.dd.DragSource = function(el, config){
3527 this.el = Roo.get(el);
3530 Roo.apply(this, config);
3533 this.proxy = new Roo.dd.StatusProxy();
3536 Roo.dd.DragSource.superclass.constructor.call(this, this.el.dom, this.ddGroup || this.group,
3537 {dragElId : this.proxy.id, resizeFrame: false, isTarget: false, scroll: this.scroll === true});
3539 this.dragging = false;
3542 Roo.extend(Roo.dd.DragSource, Roo.dd.DDProxy, {
3544 * @cfg {String} dropAllowed
3545 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3547 dropAllowed : "x-dd-drop-ok",
3549 * @cfg {String} dropNotAllowed
3550 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3552 dropNotAllowed : "x-dd-drop-nodrop",
3555 * Returns the data object associated with this drag source
3556 * @return {Object} data An object containing arbitrary data
3558 getDragData : function(e){
3559 return this.dragData;
3563 onDragEnter : function(e, id){
3564 var target = Roo.dd.DragDropMgr.getDDById(id);
3565 this.cachedTarget = target;
3566 if(this.beforeDragEnter(target, e, id) !== false){
3567 if(target.isNotifyTarget){
3568 var status = target.notifyEnter(this, e, this.dragData);
3569 this.proxy.setStatus(status);
3571 this.proxy.setStatus(this.dropAllowed);
3574 if(this.afterDragEnter){
3576 * An empty function by default, but provided so that you can perform a custom action
3577 * when the dragged item enters the drop target by providing an implementation.
3578 * @param {Roo.dd.DragDrop} target The drop target
3579 * @param {Event} e The event object
3580 * @param {String} id The id of the dragged element
3581 * @method afterDragEnter
3583 this.afterDragEnter(target, e, id);
3589 * An empty function by default, but provided so that you can perform a custom action
3590 * before the dragged item enters the drop target and optionally cancel the onDragEnter.
3591 * @param {Roo.dd.DragDrop} target The drop target
3592 * @param {Event} e The event object
3593 * @param {String} id The id of the dragged element
3594 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3596 beforeDragEnter : function(target, e, id){
3601 alignElWithMouse: function() {
3602 Roo.dd.DragSource.superclass.alignElWithMouse.apply(this, arguments);
3607 onDragOver : function(e, id){
3608 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3609 if(this.beforeDragOver(target, e, id) !== false){
3610 if(target.isNotifyTarget){
3611 var status = target.notifyOver(this, e, this.dragData);
3612 this.proxy.setStatus(status);
3615 if(this.afterDragOver){
3617 * An empty function by default, but provided so that you can perform a custom action
3618 * while the dragged item is over the drop target by providing an implementation.
3619 * @param {Roo.dd.DragDrop} target The drop target
3620 * @param {Event} e The event object
3621 * @param {String} id The id of the dragged element
3622 * @method afterDragOver
3624 this.afterDragOver(target, e, id);
3630 * An empty function by default, but provided so that you can perform a custom action
3631 * while the dragged item is over the drop target and optionally cancel the onDragOver.
3632 * @param {Roo.dd.DragDrop} target The drop target
3633 * @param {Event} e The event object
3634 * @param {String} id The id of the dragged element
3635 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3637 beforeDragOver : function(target, e, id){
3642 onDragOut : function(e, id){
3643 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3644 if(this.beforeDragOut(target, e, id) !== false){
3645 if(target.isNotifyTarget){
3646 target.notifyOut(this, e, this.dragData);
3649 if(this.afterDragOut){
3651 * An empty function by default, but provided so that you can perform a custom action
3652 * after the dragged item is dragged out of the target without dropping.
3653 * @param {Roo.dd.DragDrop} target The drop target
3654 * @param {Event} e The event object
3655 * @param {String} id The id of the dragged element
3656 * @method afterDragOut
3658 this.afterDragOut(target, e, id);
3661 this.cachedTarget = null;
3665 * An empty function by default, but provided so that you can perform a custom action before the dragged
3666 * item is dragged out of the target without dropping, and optionally cancel the onDragOut.
3667 * @param {Roo.dd.DragDrop} target The drop target
3668 * @param {Event} e The event object
3669 * @param {String} id The id of the dragged element
3670 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3672 beforeDragOut : function(target, e, id){
3677 onDragDrop : function(e, id){
3678 var target = this.cachedTarget || Roo.dd.DragDropMgr.getDDById(id);
3679 if(this.beforeDragDrop(target, e, id) !== false){
3680 if(target.isNotifyTarget){
3681 if(target.notifyDrop(this, e, this.dragData)){ // valid drop?
3682 this.onValidDrop(target, e, id);
3684 this.onInvalidDrop(target, e, id);
3687 this.onValidDrop(target, e, id);
3690 if(this.afterDragDrop){
3692 * An empty function by default, but provided so that you can perform a custom action
3693 * after a valid drag drop has occurred by providing an implementation.
3694 * @param {Roo.dd.DragDrop} target The drop target
3695 * @param {Event} e The event object
3696 * @param {String} id The id of the dropped element
3697 * @method afterDragDrop
3699 this.afterDragDrop(target, e, id);
3702 delete this.cachedTarget;
3706 * An empty function by default, but provided so that you can perform a custom action before the dragged
3707 * item is dropped onto the target and optionally cancel the onDragDrop.
3708 * @param {Roo.dd.DragDrop} target The drop target
3709 * @param {Event} e The event object
3710 * @param {String} id The id of the dragged element
3711 * @return {Boolean} isValid True if the drag drop event is valid, else false to cancel
3713 beforeDragDrop : function(target, e, id){
3718 onValidDrop : function(target, e, id){
3720 if(this.afterValidDrop){
3722 * An empty function by default, but provided so that you can perform a custom action
3723 * after a valid drop has occurred by providing an implementation.
3724 * @param {Object} target The target DD
3725 * @param {Event} e The event object
3726 * @param {String} id The id of the dropped element
3727 * @method afterInvalidDrop
3729 this.afterValidDrop(target, e, id);
3734 getRepairXY : function(e, data){
3735 return this.el.getXY();
3739 onInvalidDrop : function(target, e, id){
3740 this.beforeInvalidDrop(target, e, id);
3741 if(this.cachedTarget){
3742 if(this.cachedTarget.isNotifyTarget){
3743 this.cachedTarget.notifyOut(this, e, this.dragData);
3745 this.cacheTarget = null;
3747 this.proxy.repair(this.getRepairXY(e, this.dragData), this.afterRepair, this);
3749 if(this.afterInvalidDrop){
3751 * An empty function by default, but provided so that you can perform a custom action
3752 * after an invalid drop has occurred by providing an implementation.
3753 * @param {Event} e The event object
3754 * @param {String} id The id of the dropped element
3755 * @method afterInvalidDrop
3757 this.afterInvalidDrop(e, id);
3762 afterRepair : function(){
3764 this.el.highlight(this.hlColor || "c3daf9");
3766 this.dragging = false;
3770 * An empty function by default, but provided so that you can perform a custom action after an invalid
3771 * drop has occurred.
3772 * @param {Roo.dd.DragDrop} target The drop target
3773 * @param {Event} e The event object
3774 * @param {String} id The id of the dragged element
3775 * @return {Boolean} isValid True if the invalid drop should proceed, else false to cancel
3777 beforeInvalidDrop : function(target, e, id){
3782 handleMouseDown : function(e){
3786 var data = this.getDragData(e);
3787 if(data && this.onBeforeDrag(data, e) !== false){
3788 this.dragData = data;
3790 Roo.dd.DragSource.superclass.handleMouseDown.apply(this, arguments);
3795 * An empty function by default, but provided so that you can perform a custom action before the initial
3796 * drag event begins and optionally cancel it.
3797 * @param {Object} data An object containing arbitrary data to be shared with drop targets
3798 * @param {Event} e The event object
3799 * @return {Boolean} isValid True if the drag event is valid, else false to cancel
3801 onBeforeDrag : function(data, e){
3806 * An empty function by default, but provided so that you can perform a custom action once the initial
3807 * drag event has begun. The drag cannot be canceled from this function.
3808 * @param {Number} x The x position of the click on the dragged object
3809 * @param {Number} y The y position of the click on the dragged object
3811 onStartDrag : Roo.emptyFn,
3813 // private - YUI override
3814 startDrag : function(x, y){
3816 this.dragging = true;
3817 this.proxy.update("");
3818 this.onInitDrag(x, y);
3823 onInitDrag : function(x, y){
3824 var clone = this.el.dom.cloneNode(true);
3825 clone.id = Roo.id(); // prevent duplicate ids
3826 this.proxy.update(clone);
3827 this.onStartDrag(x, y);
3832 * Returns the drag source's underlying {@link Roo.dd.StatusProxy}
3833 * @return {Roo.dd.StatusProxy} proxy The StatusProxy
3835 getProxy : function(){
3840 * Hides the drag source's {@link Roo.dd.StatusProxy}
3842 hideProxy : function(){
3844 this.proxy.reset(true);
3845 this.dragging = false;
3849 triggerCacheRefresh : function(){
3850 Roo.dd.DDM.refreshCache(this.groups);
3853 // private - override to prevent hiding
3854 b4EndDrag: function(e) {
3857 // private - override to prevent moving
3858 endDrag : function(e){
3859 this.onEndDrag(this.dragData, e);
3863 onEndDrag : function(data, e){
3866 // private - pin to cursor
3867 autoOffset : function(x, y) {
3868 this.setDelta(-12, -20);
3872 * Ext JS Library 1.1.1
3873 * Copyright(c) 2006-2007, Ext JS, LLC.
3875 * Originally Released Under LGPL - original licence link has changed is not relivant.
3878 * <script type="text/javascript">
3883 * @class Roo.dd.DropTarget
3884 * @extends Roo.dd.DDTarget
3885 * A simple class that provides the basic implementation needed to make any element a drop target that can have
3886 * draggable items dropped onto it. The drop has no effect until an implementation of notifyDrop is provided.
3888 * @param {String/HTMLElement/Element} el The container element
3889 * @param {Object} config
3891 Roo.dd.DropTarget = function(el, config){
3892 this.el = Roo.get(el);
3894 var listeners = config.listeners;
3896 delete config.listeners;
3898 Roo.apply(this, config);
3900 if(this.containerScroll){
3901 Roo.dd.ScrollManager.register(this.el);
3905 * @scope Roo.dd.DropTarget
3910 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source is now over the
3911 * target. This default implementation adds the CSS class specified by overClass (if any) to the drop element
3912 * and returns the dropAllowed config value. This method should be overridden if drop validation is required.
3914 * IMPORTANT : it should set this.overClass and this.dropAllowed
3916 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3917 * @param {Event} e The event
3918 * @param {Object} data An object containing arbitrary data supplied by the drag source
3924 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the target.
3925 * This method will be called on every mouse movement while the drag source is over the drop target.
3926 * This default implementation simply returns the dropAllowed config value.
3928 * IMPORTANT : it should set this.dropAllowed
3930 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3931 * @param {Event} e The event
3932 * @param {Object} data An object containing arbitrary data supplied by the drag source
3938 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the source has been dragged
3939 * out of the target without dropping. This default implementation simply removes the CSS class specified by
3940 * overClass (if any) from the drop element.
3941 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3942 * @param {Event} e The event
3943 * @param {Object} data An object containing arbitrary data supplied by the drag source
3949 * The function a {@link Roo.dd.DragSource} calls once to notify this drop target that the dragged item has
3950 * been dropped on it. This method has no default implementation and returns false, so you must provide an
3951 * implementation that does something to process the drop event and returns true so that the drag source's
3952 * repair action does not run.
3954 * IMPORTANT : it should set this.success
3956 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
3957 * @param {Event} e The event
3958 * @param {Object} data An object containing arbitrary data supplied by the drag source
3964 Roo.dd.DropTarget.superclass.constructor.call( this,
3966 this.ddGroup || this.group,
3969 listeners : listeners || {}
3977 Roo.extend(Roo.dd.DropTarget, Roo.dd.DDTarget, {
3979 * @cfg {String} overClass
3980 * The CSS class applied to the drop target element while the drag source is over it (defaults to "").
3983 * @cfg {String} ddGroup
3984 * The drag drop group to handle drop events for
3988 * @cfg {String} dropAllowed
3989 * The CSS class returned to the drag source when drop is allowed (defaults to "x-dd-drop-ok").
3991 dropAllowed : "x-dd-drop-ok",
3993 * @cfg {String} dropNotAllowed
3994 * The CSS class returned to the drag source when drop is not allowed (defaults to "x-dd-drop-nodrop").
3996 dropNotAllowed : "x-dd-drop-nodrop",
3998 * @cfg {boolean} success
3999 * set this after drop listener..
4003 * @cfg {boolean} valid
4004 * if the drop point is valid for over/enter..
4011 isNotifyTarget : true,
4016 notifyEnter : function(dd, e, data){
4018 this.fireEvent('enter', this, dd, e, data);
4020 this.el.addClass(this.overClass);
4022 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4028 notifyOver : function(dd, e, data){
4030 this.fireEvent('over', this, dd, e, data);
4031 return this.valid ? this.dropAllowed : this.dropNotAllowed;
4037 notifyOut : function(dd, e, data){
4038 this.fireEvent('out', this, dd, e, data);
4040 this.el.removeClass(this.overClass);
4047 notifyDrop : function(dd, e, data){
4048 this.success = false;
4049 this.fireEvent('drop', this, dd, e, data);
4050 return this.success;
4054 * Ext JS Library 1.1.1
4055 * Copyright(c) 2006-2007, Ext JS, LLC.
4057 * Originally Released Under LGPL - original licence link has changed is not relivant.
4060 * <script type="text/javascript">
4065 * @class Roo.dd.DragZone
4066 * @extends Roo.dd.DragSource
4067 * This class provides a container DD instance that proxies for multiple child node sources.<br />
4068 * By default, this class requires that draggable child nodes are registered with {@link Roo.dd.Registry}.
4070 * @param {String/HTMLElement/Element} el The container element
4071 * @param {Object} config
4073 Roo.dd.DragZone = function(el, config){
4074 Roo.dd.DragZone.superclass.constructor.call(this, el, config);
4075 if(this.containerScroll){
4076 Roo.dd.ScrollManager.register(this.el);
4080 Roo.extend(Roo.dd.DragZone, Roo.dd.DragSource, {
4082 * @cfg {Boolean} containerScroll True to register this container with the Scrollmanager
4083 * for auto scrolling during drag operations.
4086 * @cfg {String} hlColor The color to use when visually highlighting the drag source in the afterRepair
4087 * method after a failed drop (defaults to "c3daf9" - light blue)
4091 * Called when a mousedown occurs in this container. Looks in {@link Roo.dd.Registry}
4092 * for a valid target to drag based on the mouse down. Override this method
4093 * to provide your own lookup logic (e.g. finding a child by class name). Make sure your returned
4094 * object has a "ddel" attribute (with an HTML Element) for other functions to work.
4095 * @param {EventObject} e The mouse down event
4096 * @return {Object} The dragData
4098 getDragData : function(e){
4099 return Roo.dd.Registry.getHandleFromEvent(e);
4103 * Called once drag threshold has been reached to initialize the proxy element. By default, it clones the
4104 * this.dragData.ddel
4105 * @param {Number} x The x position of the click on the dragged object
4106 * @param {Number} y The y position of the click on the dragged object
4107 * @return {Boolean} true to continue the drag, false to cancel
4109 onInitDrag : function(x, y){
4110 this.proxy.update(this.dragData.ddel.cloneNode(true));
4111 this.onStartDrag(x, y);
4116 * Called after a repair of an invalid drop. By default, highlights this.dragData.ddel
4118 afterRepair : function(){
4120 Roo.Element.fly(this.dragData.ddel).highlight(this.hlColor || "c3daf9");
4122 this.dragging = false;
4126 * Called before a repair of an invalid drop to get the XY to animate to. By default returns
4127 * the XY of this.dragData.ddel
4128 * @param {EventObject} e The mouse up event
4129 * @return {Array} The xy location (e.g. [100, 200])
4131 getRepairXY : function(e){
4132 return Roo.Element.fly(this.dragData.ddel).getXY();
4136 * Ext JS Library 1.1.1
4137 * Copyright(c) 2006-2007, Ext JS, LLC.
4139 * Originally Released Under LGPL - original licence link has changed is not relivant.
4142 * <script type="text/javascript">
4145 * @class Roo.dd.DropZone
4146 * @extends Roo.dd.DropTarget
4147 * This class provides a container DD instance that proxies for multiple child node targets.<br />
4148 * By default, this class requires that child nodes accepting drop are registered with {@link Roo.dd.Registry}.
4150 * @param {String/HTMLElement/Element} el The container element
4151 * @param {Object} config
4153 Roo.dd.DropZone = function(el, config){
4154 Roo.dd.DropZone.superclass.constructor.call(this, el, config);
4157 Roo.extend(Roo.dd.DropZone, Roo.dd.DropTarget, {
4159 * Returns a custom data object associated with the DOM node that is the target of the event. By default
4160 * this looks up the event target in the {@link Roo.dd.Registry}, although you can override this method to
4161 * provide your own custom lookup.
4162 * @param {Event} e The event
4163 * @return {Object} data The custom data
4165 getTargetFromEvent : function(e){
4166 return Roo.dd.Registry.getTargetFromEvent(e);
4170 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has entered a drop node
4171 * that it has registered. This method has no default implementation and should be overridden to provide
4172 * node-specific processing if necessary.
4173 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4174 * {@link #getTargetFromEvent} for this node)
4175 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4176 * @param {Event} e The event
4177 * @param {Object} data An object containing arbitrary data supplied by the drag source
4179 onNodeEnter : function(n, dd, e, data){
4184 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is over a drop node
4185 * that it has registered. The default implementation returns this.dropNotAllowed, so it should be
4186 * overridden to provide the proper feedback.
4187 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4188 * {@link #getTargetFromEvent} for this node)
4189 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4190 * @param {Event} e The event
4191 * @param {Object} data An object containing arbitrary data supplied by the drag source
4192 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4193 * underlying {@link Roo.dd.StatusProxy} can be updated
4195 onNodeOver : function(n, dd, e, data){
4196 return this.dropAllowed;
4200 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dragged out of
4201 * the drop node without dropping. This method has no default implementation and should be overridden to provide
4202 * node-specific processing if necessary.
4203 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4204 * {@link #getTargetFromEvent} for this node)
4205 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4206 * @param {Event} e The event
4207 * @param {Object} data An object containing arbitrary data supplied by the drag source
4209 onNodeOut : function(n, dd, e, data){
4214 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped onto
4215 * the drop node. The default implementation returns false, so it should be overridden to provide the
4216 * appropriate processing of the drop event and return true so that the drag source's repair action does not run.
4217 * @param {Object} nodeData The custom data associated with the drop node (this is the same value returned from
4218 * {@link #getTargetFromEvent} for this node)
4219 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4220 * @param {Event} e The event
4221 * @param {Object} data An object containing arbitrary data supplied by the drag source
4222 * @return {Boolean} True if the drop was valid, else false
4224 onNodeDrop : function(n, dd, e, data){
4229 * Called internally while the DropZone determines that a {@link Roo.dd.DragSource} is being dragged over it,
4230 * but not over any of its registered drop nodes. The default implementation returns this.dropNotAllowed, so
4231 * it should be overridden to provide the proper feedback if necessary.
4232 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4233 * @param {Event} e The event
4234 * @param {Object} data An object containing arbitrary data supplied by the drag source
4235 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4236 * underlying {@link Roo.dd.StatusProxy} can be updated
4238 onContainerOver : function(dd, e, data){
4239 return this.dropNotAllowed;
4243 * Called internally when the DropZone determines that a {@link Roo.dd.DragSource} has been dropped on it,
4244 * but not on any of its registered drop nodes. The default implementation returns false, so it should be
4245 * overridden to provide the appropriate processing of the drop event if you need the drop zone itself to
4246 * be able to accept drops. It should return true when valid so that the drag source's repair action does not run.
4247 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4248 * @param {Event} e The event
4249 * @param {Object} data An object containing arbitrary data supplied by the drag source
4250 * @return {Boolean} True if the drop was valid, else false
4252 onContainerDrop : function(dd, e, data){
4257 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source is now over
4258 * the zone. The default implementation returns this.dropNotAllowed and expects that only registered drop
4259 * nodes can process drag drop operations, so if you need the drop zone itself to be able to process drops
4260 * you should override this method and provide a custom implementation.
4261 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4262 * @param {Event} e The event
4263 * @param {Object} data An object containing arbitrary data supplied by the drag source
4264 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4265 * underlying {@link Roo.dd.StatusProxy} can be updated
4267 notifyEnter : function(dd, e, data){
4268 return this.dropNotAllowed;
4272 * The function a {@link Roo.dd.DragSource} calls continuously while it is being dragged over the drop zone.
4273 * This method will be called on every mouse movement while the drag source is over the drop zone.
4274 * It will call {@link #onNodeOver} while the drag source is over a registered node, and will also automatically
4275 * delegate to the appropriate node-specific methods as necessary when the drag source enters and exits
4276 * registered nodes ({@link #onNodeEnter}, {@link #onNodeOut}). If the drag source is not currently over a
4277 * registered node, it will call {@link #onContainerOver}.
4278 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4279 * @param {Event} e The event
4280 * @param {Object} data An object containing arbitrary data supplied by the drag source
4281 * @return {String} status The CSS class that communicates the drop status back to the source so that the
4282 * underlying {@link Roo.dd.StatusProxy} can be updated
4284 notifyOver : function(dd, e, data){
4285 var n = this.getTargetFromEvent(e);
4286 if(!n){ // not over valid drop target
4287 if(this.lastOverNode){
4288 this.onNodeOut(this.lastOverNode, dd, e, data);
4289 this.lastOverNode = null;
4291 return this.onContainerOver(dd, e, data);
4293 if(this.lastOverNode != n){
4294 if(this.lastOverNode){
4295 this.onNodeOut(this.lastOverNode, dd, e, data);
4297 this.onNodeEnter(n, dd, e, data);
4298 this.lastOverNode = n;
4300 return this.onNodeOver(n, dd, e, data);
4304 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the source has been dragged
4305 * out of the zone without dropping. If the drag source is currently over a registered node, the notification
4306 * will be delegated to {@link #onNodeOut} for node-specific handling, otherwise it will be ignored.
4307 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop target
4308 * @param {Event} e The event
4309 * @param {Object} data An object containing arbitrary data supplied by the drag zone
4311 notifyOut : function(dd, e, data){
4312 if(this.lastOverNode){
4313 this.onNodeOut(this.lastOverNode, dd, e, data);
4314 this.lastOverNode = null;
4319 * The function a {@link Roo.dd.DragSource} calls once to notify this drop zone that the dragged item has
4320 * been dropped on it. The drag zone will look up the target node based on the event passed in, and if there
4321 * is a node registered for that event, it will delegate to {@link #onNodeDrop} for node-specific handling,
4322 * otherwise it will call {@link #onContainerDrop}.
4323 * @param {Roo.dd.DragSource} source The drag source that was dragged over this drop zone
4324 * @param {Event} e The event
4325 * @param {Object} data An object containing arbitrary data supplied by the drag source
4326 * @return {Boolean} True if the drop was valid, else false
4328 notifyDrop : function(dd, e, data){
4329 if(this.lastOverNode){
4330 this.onNodeOut(this.lastOverNode, dd, e, data);
4331 this.lastOverNode = null;
4333 var n = this.getTargetFromEvent(e);
4335 this.onNodeDrop(n, dd, e, data) :
4336 this.onContainerDrop(dd, e, data);
4340 triggerCacheRefresh : function(){
4341 Roo.dd.DDM.refreshCache(this.groups);
4345 * Ext JS Library 1.1.1
4346 * Copyright(c) 2006-2007, Ext JS, LLC.
4348 * Originally Released Under LGPL - original licence link has changed is not relivant.
4351 * <script type="text/javascript">
4356 * @class Roo.data.SortTypes
4358 * Defines the default sorting (casting?) comparison functions used when sorting data.
4360 Roo.data.SortTypes = {
4362 * Default sort that does nothing
4363 * @param {Mixed} s The value being converted
4364 * @return {Mixed} The comparison value
4371 * The regular expression used to strip tags
4375 stripTagsRE : /<\/?[^>]+>/gi,
4378 * Strips all HTML tags to sort on text only
4379 * @param {Mixed} s The value being converted
4380 * @return {String} The comparison value
4382 asText : function(s){
4383 return String(s).replace(this.stripTagsRE, "");
4387 * Strips all HTML tags to sort on text only - Case insensitive
4388 * @param {Mixed} s The value being converted
4389 * @return {String} The comparison value
4391 asUCText : function(s){
4392 return String(s).toUpperCase().replace(this.stripTagsRE, "");
4396 * Case insensitive string
4397 * @param {Mixed} s The value being converted
4398 * @return {String} The comparison value
4400 asUCString : function(s) {
4401 return String(s).toUpperCase();
4406 * @param {Mixed} s The value being converted
4407 * @return {Number} The comparison value
4409 asDate : function(s) {
4413 if(s instanceof Date){
4416 return Date.parse(String(s));
4421 * @param {Mixed} s The value being converted
4422 * @return {Float} The comparison value
4424 asFloat : function(s) {
4425 var val = parseFloat(String(s).replace(/,/g, ""));
4426 if(isNaN(val)) val = 0;
4432 * @param {Mixed} s The value being converted
4433 * @return {Number} The comparison value
4435 asInt : function(s) {
4436 var val = parseInt(String(s).replace(/,/g, ""));
4437 if(isNaN(val)) val = 0;
4442 * Ext JS Library 1.1.1
4443 * Copyright(c) 2006-2007, Ext JS, LLC.
4445 * Originally Released Under LGPL - original licence link has changed is not relivant.
4448 * <script type="text/javascript">
4452 * @class Roo.data.Record
4453 * Instances of this class encapsulate both record <em>definition</em> information, and record
4454 * <em>value</em> information for use in {@link Roo.data.Store} objects, or any code which needs
4455 * to access Records cached in an {@link Roo.data.Store} object.<br>
4457 * Constructors for this class are generated by passing an Array of field definition objects to {@link #create}.
4458 * Instances are usually only created by {@link Roo.data.Reader} implementations when processing unformatted data
4461 * Record objects generated by this constructor inherit all the methods of Roo.data.Record listed below.
4463 * This constructor should not be used to create Record objects. Instead, use the constructor generated by
4464 * {@link #create}. The parameters are the same.
4465 * @param {Array} data An associative Array of data values keyed by the field name.
4466 * @param {Object} id (Optional) The id of the record. This id should be unique, and is used by the
4467 * {@link Roo.data.Store} object which owns the Record to index its collection of Records. If
4468 * not specified an integer id is generated.
4470 Roo.data.Record = function(data, id){
4471 this.id = (id || id === 0) ? id : ++Roo.data.Record.AUTO_ID;
4476 * Generate a constructor for a specific record layout.
4477 * @param {Array} o An Array of field definition objects which specify field names, and optionally,
4478 * data types, and a mapping for an {@link Roo.data.Reader} to extract the field's value from a data object.
4479 * Each field definition object may contain the following properties: <ul>
4480 * <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,
4481 * for example the <em>dataIndex</em> property in column definition objects passed to {@link Roo.grid.ColumnModel}</p></li>
4482 * <li><b>mapping</b> : String<p style="margin-left:1em">(Optional) A path specification for use by the {@link Roo.data.Reader} implementation
4483 * that is creating the Record to access the data value from the data object. If an {@link Roo.data.JsonReader}
4484 * is being used, then this is a string containing the javascript expression to reference the data relative to
4485 * the record item's root. If an {@link Roo.data.XmlReader} is being used, this is an {@link Roo.DomQuery} path
4486 * to the data item relative to the record element. If the mapping expression is the same as the field name,
4487 * this may be omitted.</p></li>
4488 * <li><b>type</b> : String<p style="margin-left:1em">(Optional) The data type for conversion to displayable value. Possible values are
4489 * <ul><li>auto (Default, implies no conversion)</li>
4494 * <li>date</li></ul></p></li>
4495 * <li><b>sortType</b> : Mixed<p style="margin-left:1em">(Optional) A member of {@link Roo.data.SortTypes}.</p></li>
4496 * <li><b>sortDir</b> : String<p style="margin-left:1em">(Optional) Initial direction to sort. "ASC" or "DESC"</p></li>
4497 * <li><b>convert</b> : Function<p style="margin-left:1em">(Optional) A function which converts the value provided
4498 * by the Reader into an object that will be stored in the Record. It is passed the
4499 * following parameters:<ul>
4500 * <li><b>v</b> : Mixed<p style="margin-left:1em">The data value as read by the Reader.</p></li>
4502 * <li><b>dateFormat</b> : String<p style="margin-left:1em">(Optional) A format String for the Date.parseDate function.</p></li>
4504 * <br>usage:<br><pre><code>
4505 var TopicRecord = Roo.data.Record.create(
4506 {name: 'title', mapping: 'topic_title'},
4507 {name: 'author', mapping: 'username'},
4508 {name: 'totalPosts', mapping: 'topic_replies', type: 'int'},
4509 {name: 'lastPost', mapping: 'post_time', type: 'date'},
4510 {name: 'lastPoster', mapping: 'user2'},
4511 {name: 'excerpt', mapping: 'post_text'}
4514 var myNewRecord = new TopicRecord({
4515 title: 'Do my job please',
4518 lastPost: new Date(),
4519 lastPoster: 'Animal',
4520 excerpt: 'No way dude!'
4522 myStore.add(myNewRecord);
4527 Roo.data.Record.create = function(o){
4529 f.superclass.constructor.apply(this, arguments);
4531 Roo.extend(f, Roo.data.Record);
4532 var p = f.prototype;
4533 p.fields = new Roo.util.MixedCollection(false, function(field){
4536 for(var i = 0, len = o.length; i < len; i++){
4537 p.fields.add(new Roo.data.Field(o[i]));
4539 f.getField = function(name){
4540 return p.fields.get(name);
4545 Roo.data.Record.AUTO_ID = 1000;
4546 Roo.data.Record.EDIT = 'edit';
4547 Roo.data.Record.REJECT = 'reject';
4548 Roo.data.Record.COMMIT = 'commit';
4550 Roo.data.Record.prototype = {
4552 * Readonly flag - true if this record has been modified.
4561 join : function(store){
4566 * Set the named field to the specified value.
4567 * @param {String} name The name of the field to set.
4568 * @param {Object} value The value to set the field to.
4570 set : function(name, value){
4571 if(this.data[name] == value){
4578 if(typeof this.modified[name] == 'undefined'){
4579 this.modified[name] = this.data[name];
4581 this.data[name] = value;
4583 this.store.afterEdit(this);
4588 * Get the value of the named field.
4589 * @param {String} name The name of the field to get the value of.
4590 * @return {Object} The value of the field.
4592 get : function(name){
4593 return this.data[name];
4597 beginEdit : function(){
4598 this.editing = true;
4603 cancelEdit : function(){
4604 this.editing = false;
4605 delete this.modified;
4609 endEdit : function(){
4610 this.editing = false;
4611 if(this.dirty && this.store){
4612 this.store.afterEdit(this);
4617 * Usually called by the {@link Roo.data.Store} which owns the Record.
4618 * Rejects all changes made to the Record since either creation, or the last commit operation.
4619 * Modified fields are reverted to their original values.
4621 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4622 * of reject operations.
4624 reject : function(){
4625 var m = this.modified;
4627 if(typeof m[n] != "function"){
4628 this.data[n] = m[n];
4632 delete this.modified;
4633 this.editing = false;
4635 this.store.afterReject(this);
4640 * Usually called by the {@link Roo.data.Store} which owns the Record.
4641 * Commits all changes made to the Record since either creation, or the last commit operation.
4643 * Developers should subscribe to the {@link Roo.data.Store#update} event to have their code notified
4644 * of commit operations.
4646 commit : function(){
4648 delete this.modified;
4649 this.editing = false;
4651 this.store.afterCommit(this);
4656 hasError : function(){
4657 return this.error != null;
4661 clearError : function(){
4666 * Creates a copy of this record.
4667 * @param {String} id (optional) A new record id if you don't want to use this record's id
4670 copy : function(newId) {
4671 return new this.constructor(Roo.apply({}, this.data), newId || this.id);
4675 * Ext JS Library 1.1.1
4676 * Copyright(c) 2006-2007, Ext JS, LLC.
4678 * Originally Released Under LGPL - original licence link has changed is not relivant.
4681 * <script type="text/javascript">
4687 * @class Roo.data.Store
4688 * @extends Roo.util.Observable
4689 * The Store class encapsulates a client side cache of {@link Roo.data.Record} objects which provide input data
4690 * for widgets such as the Roo.grid.Grid, or the Roo.form.ComboBox.<br>
4692 * 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
4693 * has no knowledge of the format of the data returned by the Proxy.<br>
4695 * A Store object uses its configured implementation of {@link Roo.data.DataReader} to create {@link Roo.data.Record}
4696 * instances from the data object. These records are cached and made available through accessor functions.
4698 * Creates a new Store.
4699 * @param {Object} config A config object containing the objects needed for the Store to access data,
4700 * and read the data into Records.
4702 Roo.data.Store = function(config){
4703 this.data = new Roo.util.MixedCollection(false);
4704 this.data.getKey = function(o){
4707 this.baseParams = {};
4716 if(config && config.data){
4717 this.inlineData = config.data;
4721 Roo.apply(this, config);
4723 if(this.reader){ // reader passed
4724 this.reader = Roo.factory(this.reader, Roo.data);
4725 this.reader.xmodule = this.xmodule || false;
4726 if(!this.recordType){
4727 this.recordType = this.reader.recordType;
4729 if(this.reader.onMetaChange){
4730 this.reader.onMetaChange = this.onMetaChange.createDelegate(this);
4734 if(this.recordType){
4735 this.fields = this.recordType.prototype.fields;
4741 * @event datachanged
4742 * Fires when the data cache has changed, and a widget which is using this Store
4743 * as a Record cache should refresh its view.
4744 * @param {Store} this
4749 * Fires when this store's reader provides new metadata (fields). This is currently only support for JsonReaders.
4750 * @param {Store} this
4751 * @param {Object} meta The JSON metadata
4756 * Fires when Records have been added to the Store
4757 * @param {Store} this
4758 * @param {Roo.data.Record[]} records The array of Records added
4759 * @param {Number} index The index at which the record(s) were added
4764 * Fires when a Record has been removed from the Store
4765 * @param {Store} this
4766 * @param {Roo.data.Record} record The Record that was removed
4767 * @param {Number} index The index at which the record was removed
4772 * Fires when a Record has been updated
4773 * @param {Store} this
4774 * @param {Roo.data.Record} record The Record that was updated
4775 * @param {String} operation The update operation being performed. Value may be one of:
4777 Roo.data.Record.EDIT
4778 Roo.data.Record.REJECT
4779 Roo.data.Record.COMMIT
4785 * Fires when the data cache has been cleared.
4786 * @param {Store} this
4791 * Fires before a request is made for a new data object. If the beforeload handler returns false
4792 * the load action will be canceled.
4793 * @param {Store} this
4794 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4799 * Fires after a new set of Records has been loaded.
4800 * @param {Store} this
4801 * @param {Roo.data.Record[]} records The Records that were loaded
4802 * @param {Object} options The loading options that were specified (see {@link #load} for details)
4806 * @event loadexception
4807 * Fires if an exception occurs in the Proxy during loading.
4808 * Called with the signature of the Proxy's "loadexception" event.
4809 * If you return Json { data: [] , success: false, .... } then this will be thrown with the following args
4812 * @param {Object} return from JsonData.reader() - success, totalRecords, records
4813 * @param {Object} load options
4814 * @param {Object} jsonData from your request (normally this contains the Exception)
4816 loadexception : true
4820 this.proxy = Roo.factory(this.proxy, Roo.data);
4821 this.proxy.xmodule = this.xmodule || false;
4822 this.relayEvents(this.proxy, ["loadexception"]);
4824 this.sortToggle = {};
4826 Roo.data.Store.superclass.constructor.call(this);
4828 if(this.inlineData){
4829 this.loadData(this.inlineData);
4830 delete this.inlineData;
4833 Roo.extend(Roo.data.Store, Roo.util.Observable, {
4835 * @cfg {boolean} isLocal flag if data is locally available (and can be always looked up
4836 * without a remote query - used by combo/forms at present.
4840 * @cfg {Roo.data.DataProxy} proxy The Proxy object which provides access to a data object.
4843 * @cfg {Array} data Inline data to be loaded when the store is initialized.
4846 * @cfg {Roo.data.Reader} reader The Reader object which processes the data object and returns
4847 * an Array of Roo.data.record objects which are cached keyed by their <em>id</em> property.
4850 * @cfg {Object} baseParams An object containing properties which are to be sent as parameters
4851 * on any HTTP request
4854 * @cfg {Object} sortInfo A config object in the format: {field: "fieldName", direction: "ASC|DESC"}
4857 * @cfg {boolean} remoteSort True if sorting is to be handled by requesting the Proxy to provide a refreshed
4858 * version of the data object in sorted order, as opposed to sorting the Record cache in place (defaults to false).
4863 * @cfg {boolean} pruneModifiedRecords True to clear all modified record information each time the store is
4864 * loaded or when a record is removed. (defaults to false).
4866 pruneModifiedRecords : false,
4872 * Add Records to the Store and fires the add event.
4873 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4875 add : function(records){
4876 records = [].concat(records);
4877 for(var i = 0, len = records.length; i < len; i++){
4878 records[i].join(this);
4880 var index = this.data.length;
4881 this.data.addAll(records);
4882 this.fireEvent("add", this, records, index);
4886 * Remove a Record from the Store and fires the remove event.
4887 * @param {Ext.data.Record} record The Roo.data.Record object to remove from the cache.
4889 remove : function(record){
4890 var index = this.data.indexOf(record);
4891 this.data.removeAt(index);
4892 if(this.pruneModifiedRecords){
4893 this.modified.remove(record);
4895 this.fireEvent("remove", this, record, index);
4899 * Remove all Records from the Store and fires the clear event.
4901 removeAll : function(){
4903 if(this.pruneModifiedRecords){
4906 this.fireEvent("clear", this);
4910 * Inserts Records to the Store at the given index and fires the add event.
4911 * @param {Number} index The start index at which to insert the passed Records.
4912 * @param {Roo.data.Record[]} records An Array of Roo.data.Record objects to add to the cache.
4914 insert : function(index, records){
4915 records = [].concat(records);
4916 for(var i = 0, len = records.length; i < len; i++){
4917 this.data.insert(index, records[i]);
4918 records[i].join(this);
4920 this.fireEvent("add", this, records, index);
4924 * Get the index within the cache of the passed Record.
4925 * @param {Roo.data.Record} record The Roo.data.Record object to to find.
4926 * @return {Number} The index of the passed Record. Returns -1 if not found.
4928 indexOf : function(record){
4929 return this.data.indexOf(record);
4933 * Get the index within the cache of the Record with the passed id.
4934 * @param {String} id The id of the Record to find.
4935 * @return {Number} The index of the Record. Returns -1 if not found.
4937 indexOfId : function(id){
4938 return this.data.indexOfKey(id);
4942 * Get the Record with the specified id.
4943 * @param {String} id The id of the Record to find.
4944 * @return {Roo.data.Record} The Record with the passed id. Returns undefined if not found.
4946 getById : function(id){
4947 return this.data.key(id);
4951 * Get the Record at the specified index.
4952 * @param {Number} index The index of the Record to find.
4953 * @return {Roo.data.Record} The Record at the passed index. Returns undefined if not found.
4955 getAt : function(index){
4956 return this.data.itemAt(index);
4960 * Returns a range of Records between specified indices.
4961 * @param {Number} startIndex (optional) The starting index (defaults to 0)
4962 * @param {Number} endIndex (optional) The ending index (defaults to the last Record in the Store)
4963 * @return {Roo.data.Record[]} An array of Records
4965 getRange : function(start, end){
4966 return this.data.getRange(start, end);
4970 storeOptions : function(o){
4971 o = Roo.apply({}, o);
4974 this.lastOptions = o;
4978 * Loads the Record cache from the configured Proxy using the configured Reader.
4980 * If using remote paging, then the first load call must specify the <em>start</em>
4981 * and <em>limit</em> properties in the options.params property to establish the initial
4982 * position within the dataset, and the number of Records to cache on each read from the Proxy.
4984 * <strong>It is important to note that for remote data sources, loading is asynchronous,
4985 * and this call will return before the new data has been loaded. Perform any post-processing
4986 * in a callback function, or in a "load" event handler.</strong>
4988 * @param {Object} options An object containing properties which control loading options:<ul>
4989 * <li>params {Object} An object containing properties to pass as HTTP parameters to a remote data source.</li>
4990 * <li>callback {Function} A function to be called after the Records have been loaded. The callback is
4991 * passed the following arguments:<ul>
4992 * <li>r : Roo.data.Record[]</li>
4993 * <li>options: Options object from the load call</li>
4994 * <li>success: Boolean success indicator</li></ul></li>
4995 * <li>scope {Object} Scope with which to call the callback (defaults to the Store object)</li>
4996 * <li>add {Boolean} indicator to append loaded records rather than replace the current cache.</li>
4999 load : function(options){
5000 options = options || {};
5001 if(this.fireEvent("beforeload", this, options) !== false){
5002 this.storeOptions(options);
5003 var p = Roo.apply(options.params || {}, this.baseParams);
5004 // if meta was not loaded from remote source.. try requesting it.
5005 if (!this.reader.metaFromRemote) {
5008 if(this.sortInfo && this.remoteSort){
5009 var pn = this.paramNames;
5010 p[pn["sort"]] = this.sortInfo.field;
5011 p[pn["dir"]] = this.sortInfo.direction;
5013 this.proxy.load(p, this.reader, this.loadRecords, this, options);
5018 * Reloads the Record cache from the configured Proxy using the configured Reader and
5019 * the options from the last load operation performed.
5020 * @param {Object} options (optional) An object containing properties which may override the options
5021 * used in the last load operation. See {@link #load} for details (defaults to null, in which case
5022 * the most recently used options are reused).
5024 reload : function(options){
5025 this.load(Roo.applyIf(options||{}, this.lastOptions));
5029 // Called as a callback by the Reader during a load operation.
5030 loadRecords : function(o, options, success){
5031 if(!o || success === false){
5032 if(success !== false){
5033 this.fireEvent("load", this, [], options);
5035 if(options.callback){
5036 options.callback.call(options.scope || this, [], options, false);
5040 // if data returned failure - throw an exception.
5041 if (o.success === false) {
5042 this.fireEvent("loadexception", this, o, options, this.reader.jsonData);
5045 var r = o.records, t = o.totalRecords || r.length;
5046 if(!options || options.add !== true){
5047 if(this.pruneModifiedRecords){
5050 for(var i = 0, len = r.length; i < len; i++){
5054 this.data = this.snapshot;
5055 delete this.snapshot;
5058 this.data.addAll(r);
5059 this.totalLength = t;
5061 this.fireEvent("datachanged", this);
5063 this.totalLength = Math.max(t, this.data.length+r.length);
5066 this.fireEvent("load", this, r, options);
5067 if(options.callback){
5068 options.callback.call(options.scope || this, r, options, true);
5073 * Loads data from a passed data block. A Reader which understands the format of the data
5074 * must have been configured in the constructor.
5075 * @param {Object} data The data block from which to read the Records. The format of the data expected
5076 * is dependent on the type of Reader that is configured and should correspond to that Reader's readRecords parameter.
5077 * @param {Boolean} append (Optional) True to append the new Records rather than replace the existing cache.
5079 loadData : function(o, append){
5080 var r = this.reader.readRecords(o);
5081 this.loadRecords(r, {add: append}, true);
5085 * Gets the number of cached records.
5087 * <em>If using paging, this may not be the total size of the dataset. If the data object
5088 * used by the Reader contains the dataset size, then the getTotalCount() function returns
5089 * the data set size</em>
5091 getCount : function(){
5092 return this.data.length || 0;
5096 * Gets the total number of records in the dataset as returned by the server.
5098 * <em>If using paging, for this to be accurate, the data object used by the Reader must contain
5099 * the dataset size</em>
5101 getTotalCount : function(){
5102 return this.totalLength || 0;
5106 * Returns the sort state of the Store as an object with two properties:
5108 field {String} The name of the field by which the Records are sorted
5109 direction {String} The sort order, "ASC" or "DESC"
5112 getSortState : function(){
5113 return this.sortInfo;
5117 applySort : function(){
5118 if(this.sortInfo && !this.remoteSort){
5119 var s = this.sortInfo, f = s.field;
5120 var st = this.fields.get(f).sortType;
5121 var fn = function(r1, r2){
5122 var v1 = st(r1.data[f]), v2 = st(r2.data[f]);
5123 return v1 > v2 ? 1 : (v1 < v2 ? -1 : 0);
5125 this.data.sort(s.direction, fn);
5126 if(this.snapshot && this.snapshot != this.data){
5127 this.snapshot.sort(s.direction, fn);
5133 * Sets the default sort column and order to be used by the next load operation.
5134 * @param {String} fieldName The name of the field to sort by.
5135 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5137 setDefaultSort : function(field, dir){
5138 this.sortInfo = {field: field, direction: dir ? dir.toUpperCase() : "ASC"};
5143 * If remote sorting is used, the sort is performed on the server, and the cache is
5144 * reloaded. If local sorting is used, the cache is sorted internally.
5145 * @param {String} fieldName The name of the field to sort by.
5146 * @param {String} dir (optional) The sort order, "ASC" or "DESC" (defaults to "ASC")
5148 sort : function(fieldName, dir){
5149 var f = this.fields.get(fieldName);
5151 if(this.sortInfo && this.sortInfo.field == f.name){ // toggle sort dir
5152 dir = (this.sortToggle[f.name] || "ASC").toggle("ASC", "DESC");
5157 this.sortToggle[f.name] = dir;
5158 this.sortInfo = {field: f.name, direction: dir};
5159 if(!this.remoteSort){
5161 this.fireEvent("datachanged", this);
5163 this.load(this.lastOptions);
5168 * Calls the specified function for each of the Records in the cache.
5169 * @param {Function} fn The function to call. The Record is passed as the first parameter.
5170 * Returning <em>false</em> aborts and exits the iteration.
5171 * @param {Object} scope (optional) The scope in which to call the function (defaults to the Record).
5173 each : function(fn, scope){
5174 this.data.each(fn, scope);
5178 * Gets all records modified since the last commit. Modified records are persisted across load operations
5179 * (e.g., during paging).
5180 * @return {Roo.data.Record[]} An array of Records containing outstanding modifications.
5182 getModifiedRecords : function(){
5183 return this.modified;
5187 createFilterFn : function(property, value, anyMatch){
5188 if(!value.exec){ // not a regex
5189 value = String(value);
5190 if(value.length == 0){
5193 value = new RegExp((anyMatch === true ? '' : '^') + Roo.escapeRe(value), "i");
5196 return value.test(r.data[property]);
5201 * Sums the value of <i>property</i> for each record between start and end and returns the result.
5202 * @param {String} property A field on your records
5203 * @param {Number} start The record index to start at (defaults to 0)
5204 * @param {Number} end The last record index to include (defaults to length - 1)
5205 * @return {Number} The sum
5207 sum : function(property, start, end){
5208 var rs = this.data.items, v = 0;
5210 end = (end || end === 0) ? end : rs.length-1;
5212 for(var i = start; i <= end; i++){
5213 v += (rs[i].data[property] || 0);
5219 * Filter the records by a specified property.
5220 * @param {String} field A field on your records
5221 * @param {String/RegExp} value Either a string that the field
5222 * should start with or a RegExp to test against the field
5223 * @param {Boolean} anyMatch True to match any part not just the beginning
5225 filter : function(property, value, anyMatch){
5226 var fn = this.createFilterFn(property, value, anyMatch);
5227 return fn ? this.filterBy(fn) : this.clearFilter();
5231 * Filter by a function. The specified function will be called with each
5232 * record in this data source. If the function returns true the record is included,
5233 * otherwise it is filtered.
5234 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5235 * @param {Object} scope (optional) The scope of the function (defaults to this)
5237 filterBy : function(fn, scope){
5238 this.snapshot = this.snapshot || this.data;
5239 this.data = this.queryBy(fn, scope||this);
5240 this.fireEvent("datachanged", this);
5244 * Query the records by a specified property.
5245 * @param {String} field A field on your records
5246 * @param {String/RegExp} value Either a string that the field
5247 * should start with or a RegExp to test against the field
5248 * @param {Boolean} anyMatch True to match any part not just the beginning
5249 * @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5251 query : function(property, value, anyMatch){
5252 var fn = this.createFilterFn(property, value, anyMatch);
5253 return fn ? this.queryBy(fn) : this.data.clone();
5257 * Query by a function. The specified function will be called with each
5258 * record in this data source. If the function returns true the record is included
5260 * @param {Function} fn The function to be called, it will receive 2 args (record, id)
5261 * @param {Object} scope (optional) The scope of the function (defaults to this)
5262 @return {MixedCollection} Returns an Roo.util.MixedCollection of the matched records
5264 queryBy : function(fn, scope){
5265 var data = this.snapshot || this.data;
5266 return data.filterBy(fn, scope||this);
5270 * Collects unique values for a particular dataIndex from this store.
5271 * @param {String} dataIndex The property to collect
5272 * @param {Boolean} allowNull (optional) Pass true to allow null, undefined or empty string values
5273 * @param {Boolean} bypassFilter (optional) Pass true to collect from all records, even ones which are filtered
5274 * @return {Array} An array of the unique values
5276 collect : function(dataIndex, allowNull, bypassFilter){
5277 var d = (bypassFilter === true && this.snapshot) ?
5278 this.snapshot.items : this.data.items;
5279 var v, sv, r = [], l = {};
5280 for(var i = 0, len = d.length; i < len; i++){
5281 v = d[i].data[dataIndex];
5283 if((allowNull || !Roo.isEmpty(v)) && !l[sv]){
5292 * Revert to a view of the Record cache with no filtering applied.
5293 * @param {Boolean} suppressEvent If true the filter is cleared silently without notifying listeners
5295 clearFilter : function(suppressEvent){
5296 if(this.snapshot && this.snapshot != this.data){
5297 this.data = this.snapshot;
5298 delete this.snapshot;
5299 if(suppressEvent !== true){
5300 this.fireEvent("datachanged", this);
5306 afterEdit : function(record){
5307 if(this.modified.indexOf(record) == -1){
5308 this.modified.push(record);
5310 this.fireEvent("update", this, record, Roo.data.Record.EDIT);
5314 afterReject : function(record){
5315 this.modified.remove(record);
5316 this.fireEvent("update", this, record, Roo.data.Record.REJECT);
5320 afterCommit : function(record){
5321 this.modified.remove(record);
5322 this.fireEvent("update", this, record, Roo.data.Record.COMMIT);
5326 * Commit all Records with outstanding changes. To handle updates for changes, subscribe to the
5327 * Store's "update" event, and perform updating when the third parameter is Roo.data.Record.COMMIT.
5329 commitChanges : function(){
5330 var m = this.modified.slice(0);
5332 for(var i = 0, len = m.length; i < len; i++){
5338 * Cancel outstanding changes on all changed records.
5340 rejectChanges : function(){
5341 var m = this.modified.slice(0);
5343 for(var i = 0, len = m.length; i < len; i++){
5348 onMetaChange : function(meta, rtype, o){
5349 this.recordType = rtype;
5350 this.fields = rtype.prototype.fields;
5351 delete this.snapshot;
5352 this.sortInfo = meta.sortInfo || this.sortInfo;
5354 this.fireEvent('metachange', this, this.reader.meta);
5358 * Ext JS Library 1.1.1
5359 * Copyright(c) 2006-2007, Ext JS, LLC.
5361 * Originally Released Under LGPL - original licence link has changed is not relivant.
5364 * <script type="text/javascript">
5368 * @class Roo.data.SimpleStore
5369 * @extends Roo.data.Store
5370 * Small helper class to make creating Stores from Array data easier.
5371 * @cfg {Number} id The array index of the record id. Leave blank to auto generate ids.
5372 * @cfg {Array} fields An array of field definition objects, or field name strings.
5373 * @cfg {Array} data The multi-dimensional array of data
5375 * @param {Object} config
5377 Roo.data.SimpleStore = function(config){
5378 Roo.data.SimpleStore.superclass.constructor.call(this, {
5380 reader: new Roo.data.ArrayReader({
5383 Roo.data.Record.create(config.fields)
5385 proxy : new Roo.data.MemoryProxy(config.data)
5389 Roo.extend(Roo.data.SimpleStore, Roo.data.Store);/*
5391 * Ext JS Library 1.1.1
5392 * Copyright(c) 2006-2007, Ext JS, LLC.
5394 * Originally Released Under LGPL - original licence link has changed is not relivant.
5397 * <script type="text/javascript">
5402 * @extends Roo.data.Store
5403 * @class Roo.data.JsonStore
5404 * Small helper class to make creating Stores for JSON data easier. <br/>
5406 var store = new Roo.data.JsonStore({
5407 url: 'get-images.php',
5409 fields: ['name', 'url', {name:'size', type: 'float'}, {name:'lastmod', type:'date'}]
5412 * <b>Note: Although they are not listed, this class inherits all of the config options of Store,
5413 * JsonReader and HttpProxy (unless inline data is provided).</b>
5414 * @cfg {Array} fields An array of field definition objects, or field name strings.
5416 * @param {Object} config
5418 Roo.data.JsonStore = function(c){
5419 Roo.data.JsonStore.superclass.constructor.call(this, Roo.apply(c, {
5420 proxy: !c.data ? new Roo.data.HttpProxy({url: c.url}) : undefined,
5421 reader: new Roo.data.JsonReader(c, c.fields)
5424 Roo.extend(Roo.data.JsonStore, Roo.data.Store);/*
5426 * Ext JS Library 1.1.1
5427 * Copyright(c) 2006-2007, Ext JS, LLC.
5429 * Originally Released Under LGPL - original licence link has changed is not relivant.
5432 * <script type="text/javascript">
5436 Roo.data.Field = function(config){
5437 if(typeof config == "string"){
5438 config = {name: config};
5440 Roo.apply(this, config);
5446 var st = Roo.data.SortTypes;
5447 // named sortTypes are supported, here we look them up
5448 if(typeof this.sortType == "string"){
5449 this.sortType = st[this.sortType];
5452 // set default sortType for strings and dates
5456 this.sortType = st.asUCString;
5459 this.sortType = st.asDate;
5462 this.sortType = st.none;
5467 var stripRe = /[\$,%]/g;
5469 // prebuilt conversion function for this field, instead of
5470 // switching every time we're reading a value
5472 var cv, dateFormat = this.dateFormat;
5477 cv = function(v){ return v; };
5480 cv = function(v){ return (v === undefined || v === null) ? '' : String(v); };
5484 return v !== undefined && v !== null && v !== '' ?
5485 parseInt(String(v).replace(stripRe, ""), 10) : '';
5490 return v !== undefined && v !== null && v !== '' ?
5491 parseFloat(String(v).replace(stripRe, ""), 10) : '';
5496 cv = function(v){ return v === true || v === "true" || v == 1; };
5503 if(v instanceof Date){
5507 if(dateFormat == "timestamp"){
5508 return new Date(v*1000);
5510 return Date.parseDate(v, dateFormat);
5512 var parsed = Date.parse(v);
5513 return parsed ? new Date(parsed) : null;
5522 Roo.data.Field.prototype = {
5530 * Ext JS Library 1.1.1
5531 * Copyright(c) 2006-2007, Ext JS, LLC.
5533 * Originally Released Under LGPL - original licence link has changed is not relivant.
5536 * <script type="text/javascript">
5539 // Base class for reading structured data from a data source. This class is intended to be
5540 // extended (see ArrayReader, JsonReader and XmlReader) and should not be created directly.
5543 * @class Roo.data.DataReader
5544 * Base class for reading structured data from a data source. This class is intended to be
5545 * extended (see {Roo.data.ArrayReader}, {Roo.data.JsonReader} and {Roo.data.XmlReader}) and should not be created directly.
5548 Roo.data.DataReader = function(meta, recordType){
5552 this.recordType = recordType instanceof Array ?
5553 Roo.data.Record.create(recordType) : recordType;
5556 Roo.data.DataReader.prototype = {
5558 * Create an empty record
5559 * @param {Object} data (optional) - overlay some values
5560 * @return {Roo.data.Record} record created.
5562 newRow : function(d) {
5564 this.recordType.prototype.fields.each(function(c) {
5566 case 'int' : da[c.name] = 0; break;
5567 case 'date' : da[c.name] = new Date(); break;
5568 case 'float' : da[c.name] = 0.0; break;
5569 case 'boolean' : da[c.name] = false; break;
5570 default : da[c.name] = ""; break;
5574 return new this.recordType(Roo.apply(da, d));
5579 * Ext JS Library 1.1.1
5580 * Copyright(c) 2006-2007, Ext JS, LLC.
5582 * Originally Released Under LGPL - original licence link has changed is not relivant.
5585 * <script type="text/javascript">
5589 * @class Roo.data.DataProxy
5590 * @extends Roo.data.Observable
5591 * This class is an abstract base class for implementations which provide retrieval of
5592 * unformatted data objects.<br>
5594 * DataProxy implementations are usually used in conjunction with an implementation of Roo.data.DataReader
5595 * (of the appropriate type which knows how to parse the data object) to provide a block of
5596 * {@link Roo.data.Records} to an {@link Roo.data.Store}.<br>
5598 * Custom implementations must implement the load method as described in
5599 * {@link Roo.data.HttpProxy#load}.
5601 Roo.data.DataProxy = function(){
5605 * Fires before a network request is made to retrieve a data object.
5606 * @param {Object} This DataProxy object.
5607 * @param {Object} params The params parameter to the load function.
5612 * Fires before the load method's callback is called.
5613 * @param {Object} This DataProxy object.
5614 * @param {Object} o The data object.
5615 * @param {Object} arg The callback argument object passed to the load function.
5619 * @event loadexception
5620 * Fires if an Exception occurs during data retrieval.
5621 * @param {Object} This DataProxy object.
5622 * @param {Object} o The data object.
5623 * @param {Object} arg The callback argument object passed to the load function.
5624 * @param {Object} e The Exception.
5626 loadexception : true
5628 Roo.data.DataProxy.superclass.constructor.call(this);
5631 Roo.extend(Roo.data.DataProxy, Roo.util.Observable);
5634 * @cfg {void} listeners (Not available) Constructor blocks listeners from being set
5638 * Ext JS Library 1.1.1
5639 * Copyright(c) 2006-2007, Ext JS, LLC.
5641 * Originally Released Under LGPL - original licence link has changed is not relivant.
5644 * <script type="text/javascript">
5647 * @class Roo.data.MemoryProxy
5648 * An implementation of Roo.data.DataProxy that simply passes the data specified in its constructor
5649 * to the Reader when its load method is called.
5651 * @param {Object} data The data object which the Reader uses to construct a block of Roo.data.Records.
5653 Roo.data.MemoryProxy = function(data){
5657 Roo.data.MemoryProxy.superclass.constructor.call(this);
5661 Roo.extend(Roo.data.MemoryProxy, Roo.data.DataProxy, {
5663 * Load data from the requested source (in this case an in-memory
5664 * data object passed to the constructor), read the data object into
5665 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5666 * process that block using the passed callback.
5667 * @param {Object} params This parameter is not used by the MemoryProxy class.
5668 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5669 * object into a block of Roo.data.Records.
5670 * @param {Function} callback The function into which to pass the block of Roo.data.records.
5671 * The function must be passed <ul>
5672 * <li>The Record block object</li>
5673 * <li>The "arg" argument from the load function</li>
5674 * <li>A boolean success indicator</li>
5676 * @param {Object} scope The scope in which to call the callback
5677 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5679 load : function(params, reader, callback, scope, arg){
5680 params = params || {};
5683 result = reader.readRecords(this.data);
5685 this.fireEvent("loadexception", this, arg, null, e);
5686 callback.call(scope, null, arg, false);
5689 callback.call(scope, result, arg, true);
5693 update : function(params, records){
5698 * Ext JS Library 1.1.1
5699 * Copyright(c) 2006-2007, Ext JS, LLC.
5701 * Originally Released Under LGPL - original licence link has changed is not relivant.
5704 * <script type="text/javascript">
5707 * @class Roo.data.HttpProxy
5708 * @extends Roo.data.DataProxy
5709 * An implementation of {@link Roo.data.DataProxy} that reads a data object from an {@link Roo.data.Connection} object
5710 * configured to reference a certain URL.<br><br>
5712 * <em>Note that this class cannot be used to retrieve data from a domain other than the domain
5713 * from which the running page was served.<br><br>
5715 * For cross-domain access to remote data, use an {@link Roo.data.ScriptTagProxy}.</em><br><br>
5717 * Be aware that to enable the browser to parse an XML document, the server must set
5718 * the Content-Type header in the HTTP response to "text/xml".
5720 * @param {Object} conn Connection config options to add to each request (e.g. {url: 'foo.php'} or
5721 * an {@link Roo.data.Connection} object. If a Connection config is passed, the singleton {@link Roo.Ajax} object
5722 * will be used to make the request.
5724 Roo.data.HttpProxy = function(conn){
5725 Roo.data.HttpProxy.superclass.constructor.call(this);
5726 // is conn a conn config or a real conn?
5728 this.useAjax = !conn || !conn.events;
5732 Roo.extend(Roo.data.HttpProxy, Roo.data.DataProxy, {
5733 // thse are take from connection...
5736 * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
5739 * @cfg {Object} extraParams (Optional) An object containing properties which are used as
5740 * extra parameters to each request made by this object. (defaults to undefined)
5743 * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
5744 * to each request made by this object. (defaults to undefined)
5747 * @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)
5750 * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
5753 * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
5759 * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
5763 * Return the {@link Roo.data.Connection} object being used by this Proxy.
5764 * @return {Connection} The Connection object. This object may be used to subscribe to events on
5765 * a finer-grained basis than the DataProxy events.
5767 getConnection : function(){
5768 return this.useAjax ? Roo.Ajax : this.conn;
5772 * Load data from the configured {@link Roo.data.Connection}, read the data object into
5773 * a block of Roo.data.Records using the passed {@link Roo.data.DataReader} implementation, and
5774 * process that block using the passed callback.
5775 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5776 * for the request to the remote server.
5777 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5778 * object into a block of Roo.data.Records.
5779 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5780 * The function must be passed <ul>
5781 * <li>The Record block object</li>
5782 * <li>The "arg" argument from the load function</li>
5783 * <li>A boolean success indicator</li>
5785 * @param {Object} scope The scope in which to call the callback
5786 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5788 load : function(params, reader, callback, scope, arg){
5789 if(this.fireEvent("beforeload", this, params) !== false){
5791 params : params || {},
5793 callback : callback,
5798 callback : this.loadResponse,
5802 Roo.applyIf(o, this.conn);
5803 if(this.activeRequest){
5804 Roo.Ajax.abort(this.activeRequest);
5806 this.activeRequest = Roo.Ajax.request(o);
5808 this.conn.request(o);
5811 callback.call(scope||this, null, arg, false);
5816 loadResponse : function(o, success, response){
5817 delete this.activeRequest;
5819 this.fireEvent("loadexception", this, o, response);
5820 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5825 result = o.reader.read(response);
5827 this.fireEvent("loadexception", this, o, response, e);
5828 o.request.callback.call(o.request.scope, null, o.request.arg, false);
5832 this.fireEvent("load", this, o, o.request.arg);
5833 o.request.callback.call(o.request.scope, result, o.request.arg, true);
5837 update : function(dataSet){
5842 updateResponse : function(dataSet){
5847 * Ext JS Library 1.1.1
5848 * Copyright(c) 2006-2007, Ext JS, LLC.
5850 * Originally Released Under LGPL - original licence link has changed is not relivant.
5853 * <script type="text/javascript">
5857 * @class Roo.data.ScriptTagProxy
5858 * An implementation of Roo.data.DataProxy that reads a data object from a URL which may be in a domain
5859 * other than the originating domain of the running page.<br><br>
5861 * <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
5862 * of the running page, you must use this class, rather than DataProxy.</em><br><br>
5864 * The content passed back from a server resource requested by a ScriptTagProxy is executable JavaScript
5865 * source code that is used as the source inside a <script> tag.<br><br>
5867 * In order for the browser to process the returned data, the server must wrap the data object
5868 * with a call to a callback function, the name of which is passed as a parameter by the ScriptTagProxy.
5869 * Below is a Java example for a servlet which returns data for either a ScriptTagProxy, or an HttpProxy
5870 * depending on whether the callback name was passed:
5873 boolean scriptTag = false;
5874 String cb = request.getParameter("callback");
5877 response.setContentType("text/javascript");
5879 response.setContentType("application/x-json");
5881 Writer out = response.getWriter();
5883 out.write(cb + "(");
5885 out.print(dataBlock.toJsonString());
5892 * @param {Object} config A configuration object.
5894 Roo.data.ScriptTagProxy = function(config){
5895 Roo.data.ScriptTagProxy.superclass.constructor.call(this);
5896 Roo.apply(this, config);
5897 this.head = document.getElementsByTagName("head")[0];
5900 Roo.data.ScriptTagProxy.TRANS_ID = 1000;
5902 Roo.extend(Roo.data.ScriptTagProxy, Roo.data.DataProxy, {
5904 * @cfg {String} url The URL from which to request the data object.
5907 * @cfg {Number} timeout (Optional) The number of milliseconds to wait for a response. Defaults to 30 seconds.
5911 * @cfg {String} callbackParam (Optional) The name of the parameter to pass to the server which tells
5912 * the server the name of the callback function set up by the load call to process the returned data object.
5913 * Defaults to "callback".<p>The server-side processing must read this parameter value, and generate
5914 * javascript output which calls this named function passing the data object as its only parameter.
5916 callbackParam : "callback",
5918 * @cfg {Boolean} nocache (Optional) Defaults to true. Disable cacheing by adding a unique parameter
5919 * name to the request.
5924 * Load data from the configured URL, read the data object into
5925 * a block of Roo.data.Records using the passed Roo.data.DataReader implementation, and
5926 * process that block using the passed callback.
5927 * @param {Object} params An object containing properties which are to be used as HTTP parameters
5928 * for the request to the remote server.
5929 * @param {Roo.data.DataReader} reader The Reader object which converts the data
5930 * object into a block of Roo.data.Records.
5931 * @param {Function} callback The function into which to pass the block of Roo.data.Records.
5932 * The function must be passed <ul>
5933 * <li>The Record block object</li>
5934 * <li>The "arg" argument from the load function</li>
5935 * <li>A boolean success indicator</li>
5937 * @param {Object} scope The scope in which to call the callback
5938 * @param {Object} arg An optional argument which is passed to the callback as its second parameter.
5940 load : function(params, reader, callback, scope, arg){
5941 if(this.fireEvent("beforeload", this, params) !== false){
5943 var p = Roo.urlEncode(Roo.apply(params, this.extraParams));
5946 url += (url.indexOf("?") != -1 ? "&" : "?") + p;
5948 url += "&_dc=" + (new Date().getTime());
5950 var transId = ++Roo.data.ScriptTagProxy.TRANS_ID;
5953 cb : "stcCallback"+transId,
5954 scriptId : "stcScript"+transId,
5958 callback : callback,
5964 window[trans.cb] = function(o){
5965 conn.handleResponse(o, trans);
5968 url += String.format("&{0}={1}", this.callbackParam, trans.cb);
5970 if(this.autoAbort !== false){
5974 trans.timeoutId = this.handleFailure.defer(this.timeout, this, [trans]);
5976 var script = document.createElement("script");
5977 script.setAttribute("src", url);
5978 script.setAttribute("type", "text/javascript");
5979 script.setAttribute("id", trans.scriptId);
5980 this.head.appendChild(script);
5984 callback.call(scope||this, null, arg, false);
5989 isLoading : function(){
5990 return this.trans ? true : false;
5994 * Abort the current server request.
5997 if(this.isLoading()){
5998 this.destroyTrans(this.trans);
6003 destroyTrans : function(trans, isLoaded){
6004 this.head.removeChild(document.getElementById(trans.scriptId));
6005 clearTimeout(trans.timeoutId);
6007 window[trans.cb] = undefined;
6009 delete window[trans.cb];
6012 // if hasn't been loaded, wait for load to remove it to prevent script error
6013 window[trans.cb] = function(){
6014 window[trans.cb] = undefined;
6016 delete window[trans.cb];
6023 handleResponse : function(o, trans){
6025 this.destroyTrans(trans, true);
6028 result = trans.reader.readRecords(o);
6030 this.fireEvent("loadexception", this, o, trans.arg, e);
6031 trans.callback.call(trans.scope||window, null, trans.arg, false);
6034 this.fireEvent("load", this, o, trans.arg);
6035 trans.callback.call(trans.scope||window, result, trans.arg, true);
6039 handleFailure : function(trans){
6041 this.destroyTrans(trans, false);
6042 this.fireEvent("loadexception", this, null, trans.arg);
6043 trans.callback.call(trans.scope||window, null, trans.arg, false);
6047 * Ext JS Library 1.1.1
6048 * Copyright(c) 2006-2007, Ext JS, LLC.
6050 * Originally Released Under LGPL - original licence link has changed is not relivant.
6053 * <script type="text/javascript">
6057 * @class Roo.data.JsonReader
6058 * @extends Roo.data.DataReader
6059 * Data reader class to create an Array of Roo.data.Record objects from a JSON response
6060 * based on mappings in a provided Roo.data.Record constructor.
6062 * The default behaviour of a store is to send ?_requestMeta=1, unless the class has recieved 'metaData' property
6063 * in the reply previously.
6068 var RecordDef = Roo.data.Record.create([
6069 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6070 {name: 'occupation'} // This field will use "occupation" as the mapping.
6072 var myReader = new Roo.data.JsonReader({
6073 totalProperty: "results", // The property which contains the total dataset size (optional)
6074 root: "rows", // The property which contains an Array of row objects
6075 id: "id" // The property within each row object that provides an ID for the record (optional)
6079 * This would consume a JSON file like this:
6081 { 'results': 2, 'rows': [
6082 { 'id': 1, 'name': 'Bill', occupation: 'Gardener' },
6083 { 'id': 2, 'name': 'Ben', occupation: 'Horticulturalist' } ]
6086 * @cfg {String} totalProperty Name of the property from which to retrieve the total number of records
6087 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6088 * paged from the remote server.
6089 * @cfg {String} successProperty Name of the property from which to retrieve the success attribute used by forms.
6090 * @cfg {String} root name of the property which contains the Array of row objects.
6091 * @cfg {String} id Name of the property within a row object that contains a record identifier value.
6093 * Create a new JsonReader
6094 * @param {Object} meta Metadata configuration options
6095 * @param {Object} recordType Either an Array of field definition objects,
6096 * or an {@link Roo.data.Record} object created using {@link Roo.data.Record#create}.
6098 Roo.data.JsonReader = function(meta, recordType){
6101 // set some defaults:
6103 totalProperty: 'total',
6104 successProperty : 'success',
6109 Roo.data.JsonReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6111 Roo.extend(Roo.data.JsonReader, Roo.data.DataReader, {
6114 * @prop {Boolean} metaFromRemote - if the meta data was loaded from the remote source.
6115 * Used by Store query builder to append _requestMeta to params.
6118 metaFromRemote : false,
6120 * This method is only used by a DataProxy which has retrieved data from a remote server.
6121 * @param {Object} response The XHR object which contains the JSON data in its responseText.
6122 * @return {Object} data A data block which is used by an Roo.data.Store object as
6123 * a cache of Roo.data.Records.
6125 read : function(response){
6126 var json = response.responseText;
6128 var o = /* eval:var:o */ eval("("+json+")");
6130 throw {message: "JsonReader.read: Json object not found"};
6136 this.metaFromRemote = true;
6137 this.meta = o.metaData;
6138 this.recordType = Roo.data.Record.create(o.metaData.fields);
6139 this.onMetaChange(this.meta, this.recordType, o);
6141 return this.readRecords(o);
6144 // private function a store will implement
6145 onMetaChange : function(meta, recordType, o){
6152 simpleAccess: function(obj, subsc) {
6159 getJsonAccessor: function(){
6161 return function(expr) {
6163 return(re.test(expr))
6164 ? new Function("obj", "return obj." + expr)
6174 * Create a data block containing Roo.data.Records from an XML document.
6175 * @param {Object} o An object which contains an Array of row objects in the property specified
6176 * in the config as 'root, and optionally a property, specified in the config as 'totalProperty'
6177 * which contains the total size of the dataset.
6178 * @return {Object} data A data block which is used by an Roo.data.Store object as
6179 * a cache of Roo.data.Records.
6181 readRecords : function(o){
6183 * After any data loads, the raw JSON data is available for further custom processing.
6187 var s = this.meta, Record = this.recordType,
6188 f = Record.prototype.fields, fi = f.items, fl = f.length;
6190 // Generate extraction functions for the totalProperty, the root, the id, and for each field
6192 if(s.totalProperty) {
6193 this.getTotal = this.getJsonAccessor(s.totalProperty);
6195 if(s.successProperty) {
6196 this.getSuccess = this.getJsonAccessor(s.successProperty);
6198 this.getRoot = s.root ? this.getJsonAccessor(s.root) : function(p){return p;};
6200 var g = this.getJsonAccessor(s.id);
6201 this.getId = function(rec) {
6203 return (r === undefined || r === "") ? null : r;
6206 this.getId = function(){return null;};
6209 for(var jj = 0; jj < fl; jj++){
6211 var map = (f.mapping !== undefined && f.mapping !== null) ? f.mapping : f.name;
6212 this.ef[jj] = this.getJsonAccessor(map);
6216 var root = this.getRoot(o), c = root.length, totalRecords = c, success = true;
6217 if(s.totalProperty){
6218 var vt = parseInt(this.getTotal(o), 10);
6223 if(s.successProperty){
6224 var vs = this.getSuccess(o);
6225 if(vs === false || vs === 'false'){
6230 for(var i = 0; i < c; i++){
6233 var id = this.getId(n);
6234 for(var j = 0; j < fl; j++){
6236 var v = this.ef[j](n);
6238 Roo.log('missing convert for ' + f.name);
6242 values[f.name] = f.convert((v !== undefined) ? v : f.defaultValue);
6244 var record = new Record(values, id);
6246 records[i] = record;
6251 totalRecords : totalRecords
6256 * Ext JS Library 1.1.1
6257 * Copyright(c) 2006-2007, Ext JS, LLC.
6259 * Originally Released Under LGPL - original licence link has changed is not relivant.
6262 * <script type="text/javascript">
6266 * @class Roo.data.XmlReader
6267 * @extends Roo.data.DataReader
6268 * Data reader class to create an Array of {@link Roo.data.Record} objects from an XML document
6269 * based on mappings in a provided Roo.data.Record constructor.<br><br>
6271 * <em>Note that in order for the browser to parse a returned XML document, the Content-Type
6272 * header in the HTTP response must be set to "text/xml".</em>
6276 var RecordDef = Roo.data.Record.create([
6277 {name: 'name', mapping: 'name'}, // "mapping" property not needed if it's the same as "name"
6278 {name: 'occupation'} // This field will use "occupation" as the mapping.
6280 var myReader = new Roo.data.XmlReader({
6281 totalRecords: "results", // The element which contains the total dataset size (optional)
6282 record: "row", // The repeated element which contains row information
6283 id: "id" // The element within the row that provides an ID for the record (optional)
6287 * This would consume an XML file like this:
6291 <results>2</results>
6294 <name>Bill</name>
6295 <occupation>Gardener</occupation>
6299 <name>Ben</name>
6300 <occupation>Horticulturalist</occupation>
6304 * @cfg {String} totalRecords The DomQuery path from which to retrieve the total number of records
6305 * in the dataset. This is only needed if the whole dataset is not passed in one go, but is being
6306 * paged from the remote server.
6307 * @cfg {String} record The DomQuery path to the repeated element which contains record information.
6308 * @cfg {String} success The DomQuery path to the success attribute used by forms.
6309 * @cfg {String} id The DomQuery path relative from the record element to the element that contains
6310 * a record identifier value.
6312 * Create a new XmlReader
6313 * @param {Object} meta Metadata configuration options
6314 * @param {Mixed} recordType The definition of the data record type to produce. This can be either a valid
6315 * Record subclass created with {@link Roo.data.Record#create}, or an array of objects with which to call
6316 * Roo.data.Record.create. See the {@link Roo.data.Record} class for more details.
6318 Roo.data.XmlReader = function(meta, recordType){
6320 Roo.data.XmlReader.superclass.constructor.call(this, meta, recordType||meta.fields);
6322 Roo.extend(Roo.data.XmlReader, Roo.data.DataReader, {
6324 * This method is only used by a DataProxy which has retrieved data from a remote server.
6325 * @param {Object} response The XHR object which contains the parsed XML document. The response is expected
6326 * to contain a method called 'responseXML' that returns an XML document object.
6327 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6328 * a cache of Roo.data.Records.
6330 read : function(response){
6331 var doc = response.responseXML;
6333 throw {message: "XmlReader.read: XML Document not available"};
6335 return this.readRecords(doc);
6339 * Create a data block containing Roo.data.Records from an XML document.
6340 * @param {Object} doc A parsed XML document.
6341 * @return {Object} records A data block which is used by an {@link Roo.data.Store} as
6342 * a cache of Roo.data.Records.
6344 readRecords : function(doc){
6346 * After any data loads/reads, the raw XML Document is available for further custom processing.
6350 var root = doc.documentElement || doc;
6351 var q = Roo.DomQuery;
6352 var recordType = this.recordType, fields = recordType.prototype.fields;
6353 var sid = this.meta.id;
6354 var totalRecords = 0, success = true;
6355 if(this.meta.totalRecords){
6356 totalRecords = q.selectNumber(this.meta.totalRecords, root, 0);
6359 if(this.meta.success){
6360 var sv = q.selectValue(this.meta.success, root, true);
6361 success = sv !== false && sv !== 'false';
6364 var ns = q.select(this.meta.record, root);
6365 for(var i = 0, len = ns.length; i < len; i++) {
6368 var id = sid ? q.selectValue(sid, n) : undefined;
6369 for(var j = 0, jlen = fields.length; j < jlen; j++){
6370 var f = fields.items[j];
6371 var v = q.selectValue(f.mapping || f.name, n, f.defaultValue);
6375 var record = new recordType(values, id);
6377 records[records.length] = record;
6383 totalRecords : totalRecords || records.length
6388 * Ext JS Library 1.1.1
6389 * Copyright(c) 2006-2007, Ext JS, LLC.
6391 * Originally Released Under LGPL - original licence link has changed is not relivant.
6394 * <script type="text/javascript">
6398 * @class Roo.data.ArrayReader
6399 * @extends Roo.data.DataReader
6400 * Data reader class to create an Array of Roo.data.Record objects from an Array.
6401 * Each element of that Array represents a row of data fields. The
6402 * fields are pulled into a Record object using as a subscript, the <em>mapping</em> property
6403 * of the field definition if it exists, or the field's ordinal position in the definition.<br>
6407 var RecordDef = Roo.data.Record.create([
6408 {name: 'name', mapping: 1}, // "mapping" only needed if an "id" field is present which
6409 {name: 'occupation', mapping: 2} // precludes using the ordinal position as the index.
6411 var myReader = new Roo.data.ArrayReader({
6412 id: 0 // The subscript within row Array that provides an ID for the Record (optional)
6416 * This would consume an Array like this:
6418 [ [1, 'Bill', 'Gardener'], [2, 'Ben', 'Horticulturalist'] ]
6420 * @cfg {String} id (optional) The subscript within row Array that provides an ID for the Record
6422 * Create a new JsonReader
6423 * @param {Object} meta Metadata configuration options.
6424 * @param {Object} recordType Either an Array of field definition objects
6425 * as specified to {@link Roo.data.Record#create},
6426 * or an {@link Roo.data.Record} object
6427 * created using {@link Roo.data.Record#create}.
6429 Roo.data.ArrayReader = function(meta, recordType){
6430 Roo.data.ArrayReader.superclass.constructor.call(this, meta, recordType);
6433 Roo.extend(Roo.data.ArrayReader, Roo.data.JsonReader, {
6435 * Create a data block containing Roo.data.Records from an XML document.
6436 * @param {Object} o An Array of row objects which represents the dataset.
6437 * @return {Object} data A data block which is used by an Roo.data.Store object as
6438 * a cache of Roo.data.Records.
6440 readRecords : function(o){
6441 var sid = this.meta ? this.meta.id : null;
6442 var recordType = this.recordType, fields = recordType.prototype.fields;
6445 for(var i = 0; i < root.length; i++){
6448 var id = ((sid || sid === 0) && n[sid] !== undefined && n[sid] !== "" ? n[sid] : null);
6449 for(var j = 0, jlen = fields.length; j < jlen; j++){
6450 var f = fields.items[j];
6451 var k = f.mapping !== undefined && f.mapping !== null ? f.mapping : j;
6452 var v = n[k] !== undefined ? n[k] : f.defaultValue;
6456 var record = new recordType(values, id);
6458 records[records.length] = record;
6462 totalRecords : records.length
6467 * Ext JS Library 1.1.1
6468 * Copyright(c) 2006-2007, Ext JS, LLC.
6470 * Originally Released Under LGPL - original licence link has changed is not relivant.
6473 * <script type="text/javascript">
6478 * @class Roo.data.Tree
6479 * @extends Roo.util.Observable
6480 * Represents a tree data structure and bubbles all the events for its nodes. The nodes
6481 * in the tree have most standard DOM functionality.
6483 * @param {Node} root (optional) The root node
6485 Roo.data.Tree = function(root){
6488 * The root node for this tree
6493 this.setRootNode(root);
6498 * Fires when a new child node is appended to a node in this tree.
6499 * @param {Tree} tree The owner tree
6500 * @param {Node} parent The parent node
6501 * @param {Node} node The newly appended node
6502 * @param {Number} index The index of the newly appended node
6507 * Fires when a child node is removed from a node in this tree.
6508 * @param {Tree} tree The owner tree
6509 * @param {Node} parent The parent node
6510 * @param {Node} node The child node removed
6515 * Fires when a node is moved to a new location in the tree
6516 * @param {Tree} tree The owner tree
6517 * @param {Node} node The node moved
6518 * @param {Node} oldParent The old parent of this node
6519 * @param {Node} newParent The new parent of this node
6520 * @param {Number} index The index it was moved to
6525 * Fires when a new child node is inserted in a node in this tree.
6526 * @param {Tree} tree The owner tree
6527 * @param {Node} parent The parent node
6528 * @param {Node} node The child node inserted
6529 * @param {Node} refNode The child node the node was inserted before
6533 * @event beforeappend
6534 * Fires before a new child is appended to a node in this tree, return false to cancel the append.
6535 * @param {Tree} tree The owner tree
6536 * @param {Node} parent The parent node
6537 * @param {Node} node The child node to be appended
6539 "beforeappend" : true,
6541 * @event beforeremove
6542 * Fires before a child is removed from a node in this tree, return false to cancel the remove.
6543 * @param {Tree} tree The owner tree
6544 * @param {Node} parent The parent node
6545 * @param {Node} node The child node to be removed
6547 "beforeremove" : true,
6550 * Fires before a node is moved to a new location in the tree. Return false to cancel the move.
6551 * @param {Tree} tree The owner tree
6552 * @param {Node} node The node being moved
6553 * @param {Node} oldParent The parent of the node
6554 * @param {Node} newParent The new parent the node is moving to
6555 * @param {Number} index The index it is being moved to
6557 "beforemove" : true,
6559 * @event beforeinsert
6560 * Fires before a new child is inserted in a node in this tree, return false to cancel the insert.
6561 * @param {Tree} tree The owner tree
6562 * @param {Node} parent The parent node
6563 * @param {Node} node The child node to be inserted
6564 * @param {Node} refNode The child node the node is being inserted before
6566 "beforeinsert" : true
6569 Roo.data.Tree.superclass.constructor.call(this);
6572 Roo.extend(Roo.data.Tree, Roo.util.Observable, {
6575 proxyNodeEvent : function(){
6576 return this.fireEvent.apply(this, arguments);
6580 * Returns the root node for this tree.
6583 getRootNode : function(){
6588 * Sets the root node for this tree.
6589 * @param {Node} node
6592 setRootNode : function(node){
6594 node.ownerTree = this;
6596 this.registerNode(node);
6601 * Gets a node in this tree by its id.
6602 * @param {String} id
6605 getNodeById : function(id){
6606 return this.nodeHash[id];
6609 registerNode : function(node){
6610 this.nodeHash[node.id] = node;
6613 unregisterNode : function(node){
6614 delete this.nodeHash[node.id];
6617 toString : function(){
6618 return "[Tree"+(this.id?" "+this.id:"")+"]";
6623 * @class Roo.data.Node
6624 * @extends Roo.util.Observable
6625 * @cfg {Boolean} leaf true if this node is a leaf and does not have children
6626 * @cfg {String} id The id for this node. If one is not specified, one is generated.
6628 * @param {Object} attributes The attributes/config for the node
6630 Roo.data.Node = function(attributes){
6632 * The attributes supplied for the node. You can use this property to access any custom attributes you supplied.
6635 this.attributes = attributes || {};
6636 this.leaf = this.attributes.leaf;
6638 * The node id. @type String
6640 this.id = this.attributes.id;
6642 this.id = Roo.id(null, "ynode-");
6643 this.attributes.id = this.id;
6646 * All child nodes of this node. @type Array
6648 this.childNodes = [];
6649 if(!this.childNodes.indexOf){ // indexOf is a must
6650 this.childNodes.indexOf = function(o){
6651 for(var i = 0, len = this.length; i < len; i++){
6660 * The parent node for this node. @type Node
6662 this.parentNode = null;
6664 * The first direct child node of this node, or null if this node has no child nodes. @type Node
6666 this.firstChild = null;
6668 * The last direct child node of this node, or null if this node has no child nodes. @type Node
6670 this.lastChild = null;
6672 * The node immediately preceding this node in the tree, or null if there is no sibling node. @type Node
6674 this.previousSibling = null;
6676 * The node immediately following this node in the tree, or null if there is no sibling node. @type Node
6678 this.nextSibling = null;
6683 * Fires when a new child node is appended
6684 * @param {Tree} tree The owner tree
6685 * @param {Node} this This node
6686 * @param {Node} node The newly appended node
6687 * @param {Number} index The index of the newly appended node
6692 * Fires when a child node is removed
6693 * @param {Tree} tree The owner tree
6694 * @param {Node} this This node
6695 * @param {Node} node The removed node
6700 * Fires when this node is moved to a new location in the tree
6701 * @param {Tree} tree The owner tree
6702 * @param {Node} this This node
6703 * @param {Node} oldParent The old parent of this node
6704 * @param {Node} newParent The new parent of this node
6705 * @param {Number} index The index it was moved to
6710 * Fires when a new child node is inserted.
6711 * @param {Tree} tree The owner tree
6712 * @param {Node} this This node
6713 * @param {Node} node The child node inserted
6714 * @param {Node} refNode The child node the node was inserted before
6718 * @event beforeappend
6719 * Fires before a new child is appended, return false to cancel the append.
6720 * @param {Tree} tree The owner tree
6721 * @param {Node} this This node
6722 * @param {Node} node The child node to be appended
6724 "beforeappend" : true,
6726 * @event beforeremove
6727 * Fires before a child is removed, return false to cancel the remove.
6728 * @param {Tree} tree The owner tree
6729 * @param {Node} this This node
6730 * @param {Node} node The child node to be removed
6732 "beforeremove" : true,
6735 * Fires before this node is moved to a new location in the tree. Return false to cancel the move.
6736 * @param {Tree} tree The owner tree
6737 * @param {Node} this This node
6738 * @param {Node} oldParent The parent of this node
6739 * @param {Node} newParent The new parent this node is moving to
6740 * @param {Number} index The index it is being moved to
6742 "beforemove" : true,
6744 * @event beforeinsert
6745 * Fires before a new child is inserted, return false to cancel the insert.
6746 * @param {Tree} tree The owner tree
6747 * @param {Node} this This node
6748 * @param {Node} node The child node to be inserted
6749 * @param {Node} refNode The child node the node is being inserted before
6751 "beforeinsert" : true
6753 this.listeners = this.attributes.listeners;
6754 Roo.data.Node.superclass.constructor.call(this);
6757 Roo.extend(Roo.data.Node, Roo.util.Observable, {
6758 fireEvent : function(evtName){
6759 // first do standard event for this node
6760 if(Roo.data.Node.superclass.fireEvent.apply(this, arguments) === false){
6763 // then bubble it up to the tree if the event wasn't cancelled
6764 var ot = this.getOwnerTree();
6766 if(ot.proxyNodeEvent.apply(ot, arguments) === false){
6774 * Returns true if this node is a leaf
6777 isLeaf : function(){
6778 return this.leaf === true;
6782 setFirstChild : function(node){
6783 this.firstChild = node;
6787 setLastChild : function(node){
6788 this.lastChild = node;
6793 * Returns true if this node is the last child of its parent
6796 isLast : function(){
6797 return (!this.parentNode ? true : this.parentNode.lastChild == this);
6801 * Returns true if this node is the first child of its parent
6804 isFirst : function(){
6805 return (!this.parentNode ? true : this.parentNode.firstChild == this);
6808 hasChildNodes : function(){
6809 return !this.isLeaf() && this.childNodes.length > 0;
6813 * Insert node(s) as the last child node of this node.
6814 * @param {Node/Array} node The node or Array of nodes to append
6815 * @return {Node} The appended node if single append, or null if an array was passed
6817 appendChild : function(node){
6819 if(node instanceof Array){
6821 }else if(arguments.length > 1){
6824 // if passed an array or multiple args do them one by one
6826 for(var i = 0, len = multi.length; i < len; i++) {
6827 this.appendChild(multi[i]);
6830 if(this.fireEvent("beforeappend", this.ownerTree, this, node) === false){
6833 var index = this.childNodes.length;
6834 var oldParent = node.parentNode;
6835 // it's a move, make sure we move it cleanly
6837 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index) === false){
6840 oldParent.removeChild(node);
6842 index = this.childNodes.length;
6844 this.setFirstChild(node);
6846 this.childNodes.push(node);
6847 node.parentNode = this;
6848 var ps = this.childNodes[index-1];
6850 node.previousSibling = ps;
6851 ps.nextSibling = node;
6853 node.previousSibling = null;
6855 node.nextSibling = null;
6856 this.setLastChild(node);
6857 node.setOwnerTree(this.getOwnerTree());
6858 this.fireEvent("append", this.ownerTree, this, node, index);
6860 node.fireEvent("move", this.ownerTree, node, oldParent, this, index);
6867 * Removes a child node from this node.
6868 * @param {Node} node The node to remove
6869 * @return {Node} The removed node
6871 removeChild : function(node){
6872 var index = this.childNodes.indexOf(node);
6876 if(this.fireEvent("beforeremove", this.ownerTree, this, node) === false){
6880 // remove it from childNodes collection
6881 this.childNodes.splice(index, 1);
6884 if(node.previousSibling){
6885 node.previousSibling.nextSibling = node.nextSibling;
6887 if(node.nextSibling){
6888 node.nextSibling.previousSibling = node.previousSibling;
6891 // update child refs
6892 if(this.firstChild == node){
6893 this.setFirstChild(node.nextSibling);
6895 if(this.lastChild == node){
6896 this.setLastChild(node.previousSibling);
6899 node.setOwnerTree(null);
6900 // clear any references from the node
6901 node.parentNode = null;
6902 node.previousSibling = null;
6903 node.nextSibling = null;
6904 this.fireEvent("remove", this.ownerTree, this, node);
6909 * Inserts the first node before the second node in this nodes childNodes collection.
6910 * @param {Node} node The node to insert
6911 * @param {Node} refNode The node to insert before (if null the node is appended)
6912 * @return {Node} The inserted node
6914 insertBefore : function(node, refNode){
6915 if(!refNode){ // like standard Dom, refNode can be null for append
6916 return this.appendChild(node);
6919 if(node == refNode){
6923 if(this.fireEvent("beforeinsert", this.ownerTree, this, node, refNode) === false){
6926 var index = this.childNodes.indexOf(refNode);
6927 var oldParent = node.parentNode;
6928 var refIndex = index;
6930 // when moving internally, indexes will change after remove
6931 if(oldParent == this && this.childNodes.indexOf(node) < index){
6935 // it's a move, make sure we move it cleanly
6937 if(node.fireEvent("beforemove", node.getOwnerTree(), node, oldParent, this, index, refNode) === false){
6940 oldParent.removeChild(node);
6943 this.setFirstChild(node);
6945 this.childNodes.splice(refIndex, 0, node);
6946 node.parentNode = this;
6947 var ps = this.childNodes[refIndex-1];
6949 node.previousSibling = ps;
6950 ps.nextSibling = node;
6952 node.previousSibling = null;
6954 node.nextSibling = refNode;
6955 refNode.previousSibling = node;
6956 node.setOwnerTree(this.getOwnerTree());
6957 this.fireEvent("insert", this.ownerTree, this, node, refNode);
6959 node.fireEvent("move", this.ownerTree, node, oldParent, this, refIndex, refNode);
6965 * Returns the child node at the specified index.
6966 * @param {Number} index
6969 item : function(index){
6970 return this.childNodes[index];
6974 * Replaces one child node in this node with another.
6975 * @param {Node} newChild The replacement node
6976 * @param {Node} oldChild The node to replace
6977 * @return {Node} The replaced node
6979 replaceChild : function(newChild, oldChild){
6980 this.insertBefore(newChild, oldChild);
6981 this.removeChild(oldChild);
6986 * Returns the index of a child node
6987 * @param {Node} node
6988 * @return {Number} The index of the node or -1 if it was not found
6990 indexOf : function(child){
6991 return this.childNodes.indexOf(child);
6995 * Returns the tree this node is in.
6998 getOwnerTree : function(){
6999 // if it doesn't have one, look for one
7000 if(!this.ownerTree){
7004 this.ownerTree = p.ownerTree;
7010 return this.ownerTree;
7014 * Returns depth of this node (the root node has a depth of 0)
7017 getDepth : function(){
7020 while(p.parentNode){
7028 setOwnerTree : function(tree){
7029 // if it's move, we need to update everyone
7030 if(tree != this.ownerTree){
7032 this.ownerTree.unregisterNode(this);
7034 this.ownerTree = tree;
7035 var cs = this.childNodes;
7036 for(var i = 0, len = cs.length; i < len; i++) {
7037 cs[i].setOwnerTree(tree);
7040 tree.registerNode(this);
7046 * Returns the path for this node. The path can be used to expand or select this node programmatically.
7047 * @param {String} attr (optional) The attr to use for the path (defaults to the node's id)
7048 * @return {String} The path
7050 getPath : function(attr){
7051 attr = attr || "id";
7052 var p = this.parentNode;
7053 var b = [this.attributes[attr]];
7055 b.unshift(p.attributes[attr]);
7058 var sep = this.getOwnerTree().pathSeparator;
7059 return sep + b.join(sep);
7063 * Bubbles up the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7064 * function call will be the scope provided or the current node. The arguments to the function
7065 * will be the args provided or the current node. If the function returns false at any point,
7066 * the bubble is stopped.
7067 * @param {Function} fn The function to call
7068 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7069 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7071 bubble : function(fn, scope, args){
7074 if(fn.call(scope || p, args || p) === false){
7082 * Cascades down the tree from this node, calling the specified function with each node. The scope (<i>this</i>) of
7083 * function call will be the scope provided or the current node. The arguments to the function
7084 * will be the args provided or the current node. If the function returns false at any point,
7085 * the cascade is stopped on that branch.
7086 * @param {Function} fn The function to call
7087 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7088 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7090 cascade : function(fn, scope, args){
7091 if(fn.call(scope || this, args || this) !== false){
7092 var cs = this.childNodes;
7093 for(var i = 0, len = cs.length; i < len; i++) {
7094 cs[i].cascade(fn, scope, args);
7100 * Interates the child nodes of this node, calling the specified function with each node. The scope (<i>this</i>) of
7101 * function call will be the scope provided or the current node. The arguments to the function
7102 * will be the args provided or the current node. If the function returns false at any point,
7103 * the iteration stops.
7104 * @param {Function} fn The function to call
7105 * @param {Object} scope (optional) The scope of the function (defaults to current node)
7106 * @param {Array} args (optional) The args to call the function with (default to passing the current node)
7108 eachChild : function(fn, scope, args){
7109 var cs = this.childNodes;
7110 for(var i = 0, len = cs.length; i < len; i++) {
7111 if(fn.call(scope || this, args || cs[i]) === false){
7118 * Finds the first child that has the attribute with the specified value.
7119 * @param {String} attribute The attribute name
7120 * @param {Mixed} value The value to search for
7121 * @return {Node} The found child or null if none was found
7123 findChild : function(attribute, value){
7124 var cs = this.childNodes;
7125 for(var i = 0, len = cs.length; i < len; i++) {
7126 if(cs[i].attributes[attribute] == value){
7134 * Finds the first child by a custom function. The child matches if the function passed
7136 * @param {Function} fn
7137 * @param {Object} scope (optional)
7138 * @return {Node} The found child or null if none was found
7140 findChildBy : function(fn, scope){
7141 var cs = this.childNodes;
7142 for(var i = 0, len = cs.length; i < len; i++) {
7143 if(fn.call(scope||cs[i], cs[i]) === true){
7151 * Sorts this nodes children using the supplied sort function
7152 * @param {Function} fn
7153 * @param {Object} scope (optional)
7155 sort : function(fn, scope){
7156 var cs = this.childNodes;
7157 var len = cs.length;
7159 var sortFn = scope ? function(){fn.apply(scope, arguments);} : fn;
7161 for(var i = 0; i < len; i++){
7163 n.previousSibling = cs[i-1];
7164 n.nextSibling = cs[i+1];
7166 this.setFirstChild(n);
7169 this.setLastChild(n);
7176 * Returns true if this node is an ancestor (at any point) of the passed node.
7177 * @param {Node} node
7180 contains : function(node){
7181 return node.isAncestor(this);
7185 * Returns true if the passed node is an ancestor (at any point) of this node.
7186 * @param {Node} node
7189 isAncestor : function(node){
7190 var p = this.parentNode;
7200 toString : function(){
7201 return "[Node"+(this.id?" "+this.id:"")+"]";
7205 * Ext JS Library 1.1.1
7206 * Copyright(c) 2006-2007, Ext JS, LLC.
7208 * Originally Released Under LGPL - original licence link has changed is not relivant.
7211 * <script type="text/javascript">
7216 * @class Roo.ComponentMgr
7217 * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
7220 Roo.ComponentMgr = function(){
7221 var all = new Roo.util.MixedCollection();
7225 * Registers a component.
7226 * @param {Roo.Component} c The component
7228 register : function(c){
7233 * Unregisters a component.
7234 * @param {Roo.Component} c The component
7236 unregister : function(c){
7241 * Returns a component by id
7242 * @param {String} id The component id
7249 * Registers a function that will be called when a specified component is added to ComponentMgr
7250 * @param {String} id The component id
7251 * @param {Funtction} fn The callback function
7252 * @param {Object} scope The scope of the callback
7254 onAvailable : function(id, fn, scope){
7255 all.on("add", function(index, o){
7257 fn.call(scope || o, o);
7258 all.un("add", fn, scope);
7265 * Ext JS Library 1.1.1
7266 * Copyright(c) 2006-2007, Ext JS, LLC.
7268 * Originally Released Under LGPL - original licence link has changed is not relivant.
7271 * <script type="text/javascript">
7275 * @class Roo.Component
7276 * @extends Roo.util.Observable
7277 * Base class for all major Roo components. All subclasses of Component can automatically participate in the standard
7278 * Roo component lifecycle of creation, rendering and destruction. They also have automatic support for basic hide/show
7279 * and enable/disable behavior. Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
7280 * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
7281 * All visual components (widgets) that require rendering into a layout should subclass Component.
7283 * @param {Roo.Element/String/Object} config The configuration options. If an element is passed, it is set as the internal
7284 * 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
7285 * and is used as the component id. Otherwise, it is assumed to be a standard config object and is applied to the component.
7287 Roo.Component = function(config){
7288 config = config || {};
7289 if(config.tagName || config.dom || typeof config == "string"){ // element object
7290 config = {el: config, id: config.id || config};
7292 this.initialConfig = config;
7294 Roo.apply(this, config);
7298 * Fires after the component is disabled.
7299 * @param {Roo.Component} this
7304 * Fires after the component is enabled.
7305 * @param {Roo.Component} this
7310 * Fires before the component is shown. Return false to stop the show.
7311 * @param {Roo.Component} this
7316 * Fires after the component is shown.
7317 * @param {Roo.Component} this
7322 * Fires before the component is hidden. Return false to stop the hide.
7323 * @param {Roo.Component} this
7328 * Fires after the component is hidden.
7329 * @param {Roo.Component} this
7333 * @event beforerender
7334 * Fires before the component is rendered. Return false to stop the render.
7335 * @param {Roo.Component} this
7337 beforerender : true,
7340 * Fires after the component is rendered.
7341 * @param {Roo.Component} this
7345 * @event beforedestroy
7346 * Fires before the component is destroyed. Return false to stop the destroy.
7347 * @param {Roo.Component} this
7349 beforedestroy : true,
7352 * Fires after the component is destroyed.
7353 * @param {Roo.Component} this
7358 this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
7360 Roo.ComponentMgr.register(this);
7361 Roo.Component.superclass.constructor.call(this);
7362 this.initComponent();
7363 if(this.renderTo){ // not supported by all components yet. use at your own risk!
7364 this.render(this.renderTo);
7365 delete this.renderTo;
7370 Roo.Component.AUTO_ID = 1000;
7372 Roo.extend(Roo.Component, Roo.util.Observable, {
7374 * @property {Boolean} hidden
7375 * true if this component is hidden. Read-only.
7379 * true if this component is disabled. Read-only.
7383 * true if this component has been rendered. Read-only.
7387 /** @cfg {String} disableClass
7388 * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
7390 disabledClass : "x-item-disabled",
7391 /** @cfg {Boolean} allowDomMove
7392 * Whether the component can move the Dom node when rendering (defaults to true).
7394 allowDomMove : true,
7395 /** @cfg {String} hideMode
7396 * How this component should hidden. Supported values are
7397 * "visibility" (css visibility), "offsets" (negative offset position) and
7398 * "display" (css display) - defaults to "display".
7400 hideMode: 'display',
7403 ctype : "Roo.Component",
7405 /** @cfg {String} actionMode
7406 * which property holds the element that used for hide() / show() / disable() / enable()
7412 getActionEl : function(){
7413 return this[this.actionMode];
7416 initComponent : Roo.emptyFn,
7418 * If this is a lazy rendering component, render it to its container element.
7419 * @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.
7421 render : function(container, position){
7422 if(!this.rendered && this.fireEvent("beforerender", this) !== false){
7423 if(!container && this.el){
7424 this.el = Roo.get(this.el);
7425 container = this.el.dom.parentNode;
7426 this.allowDomMove = false;
7428 this.container = Roo.get(container);
7429 this.rendered = true;
7430 if(position !== undefined){
7431 if(typeof position == 'number'){
7432 position = this.container.dom.childNodes[position];
7434 position = Roo.getDom(position);
7437 this.onRender(this.container, position || null);
7439 this.el.addClass(this.cls);
7443 this.el.applyStyles(this.style);
7446 this.fireEvent("render", this);
7447 this.afterRender(this.container);
7459 // default function is not really useful
7460 onRender : function(ct, position){
7462 this.el = Roo.get(this.el);
7463 if(this.allowDomMove !== false){
7464 ct.dom.insertBefore(this.el.dom, position);
7470 getAutoCreate : function(){
7471 var cfg = typeof this.autoCreate == "object" ?
7472 this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
7473 if(this.id && !cfg.id){
7480 afterRender : Roo.emptyFn,
7483 * Destroys this component by purging any event listeners, removing the component's element from the DOM,
7484 * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
7486 destroy : function(){
7487 if(this.fireEvent("beforedestroy", this) !== false){
7488 this.purgeListeners();
7489 this.beforeDestroy();
7491 this.el.removeAllListeners();
7493 if(this.actionMode == "container"){
7494 this.container.remove();
7498 Roo.ComponentMgr.unregister(this);
7499 this.fireEvent("destroy", this);
7504 beforeDestroy : function(){
7509 onDestroy : function(){
7514 * Returns the underlying {@link Roo.Element}.
7515 * @return {Roo.Element} The element
7522 * Returns the id of this component.
7530 * Try to focus this component.
7531 * @param {Boolean} selectText True to also select the text in this component (if applicable)
7532 * @return {Roo.Component} this
7534 focus : function(selectText){
7537 if(selectText === true){
7538 this.el.dom.select();
7553 * Disable this component.
7554 * @return {Roo.Component} this
7556 disable : function(){
7560 this.disabled = true;
7561 this.fireEvent("disable", this);
7566 onDisable : function(){
7567 this.getActionEl().addClass(this.disabledClass);
7568 this.el.dom.disabled = true;
7572 * Enable this component.
7573 * @return {Roo.Component} this
7575 enable : function(){
7579 this.disabled = false;
7580 this.fireEvent("enable", this);
7585 onEnable : function(){
7586 this.getActionEl().removeClass(this.disabledClass);
7587 this.el.dom.disabled = false;
7591 * Convenience function for setting disabled/enabled by boolean.
7592 * @param {Boolean} disabled
7594 setDisabled : function(disabled){
7595 this[disabled ? "disable" : "enable"]();
7599 * Show this component.
7600 * @return {Roo.Component} this
7603 if(this.fireEvent("beforeshow", this) !== false){
7604 this.hidden = false;
7608 this.fireEvent("show", this);
7614 onShow : function(){
7615 var ae = this.getActionEl();
7616 if(this.hideMode == 'visibility'){
7617 ae.dom.style.visibility = "visible";
7618 }else if(this.hideMode == 'offsets'){
7619 ae.removeClass('x-hidden');
7621 ae.dom.style.display = "";
7626 * Hide this component.
7627 * @return {Roo.Component} this
7630 if(this.fireEvent("beforehide", this) !== false){
7635 this.fireEvent("hide", this);
7641 onHide : function(){
7642 var ae = this.getActionEl();
7643 if(this.hideMode == 'visibility'){
7644 ae.dom.style.visibility = "hidden";
7645 }else if(this.hideMode == 'offsets'){
7646 ae.addClass('x-hidden');
7648 ae.dom.style.display = "none";
7653 * Convenience function to hide or show this component by boolean.
7654 * @param {Boolean} visible True to show, false to hide
7655 * @return {Roo.Component} this
7657 setVisible: function(visible){
7667 * Returns true if this component is visible.
7669 isVisible : function(){
7670 return this.getActionEl().isVisible();
7673 cloneConfig : function(overrides){
7674 overrides = overrides || {};
7675 var id = overrides.id || Roo.id();
7676 var cfg = Roo.applyIf(overrides, this.initialConfig);
7677 cfg.id = id; // prevent dup id
7678 return new this.constructor(cfg);
7682 * Ext JS Library 1.1.1
7683 * Copyright(c) 2006-2007, Ext JS, LLC.
7685 * Originally Released Under LGPL - original licence link has changed is not relivant.
7688 * <script type="text/javascript">
7693 * @extends Roo.Element
7694 * An extended {@link Roo.Element} object that supports a shadow and shim, constrain to viewport and
7695 * automatic maintaining of shadow/shim positions.
7696 * @cfg {Boolean} shim False to disable the iframe shim in browsers which need one (defaults to true)
7697 * @cfg {String/Boolean} shadow True to create a shadow element with default class "x-layer-shadow", or
7698 * you can pass a string with a CSS class name. False turns off the shadow.
7699 * @cfg {Object} dh DomHelper object config to create element with (defaults to {tag: "div", cls: "x-layer"}).
7700 * @cfg {Boolean} constrain False to disable constrain to viewport (defaults to true)
7701 * @cfg {String} cls CSS class to add to the element
7702 * @cfg {Number} zindex Starting z-index (defaults to 11000)
7703 * @cfg {Number} shadowOffset Number of pixels to offset the shadow (defaults to 3)
7705 * @param {Object} config An object with config options.
7706 * @param {String/HTMLElement} existingEl (optional) Uses an existing DOM element. If the element is not found it creates it.
7709 Roo.Layer = function(config, existingEl){
7710 config = config || {};
7711 var dh = Roo.DomHelper;
7712 var cp = config.parentEl, pel = cp ? Roo.getDom(cp) : document.body;
7714 this.dom = Roo.getDom(existingEl);
7717 var o = config.dh || {tag: "div", cls: "x-layer"};
7718 this.dom = dh.append(pel, o);
7721 this.addClass(config.cls);
7723 this.constrain = config.constrain !== false;
7724 this.visibilityMode = Roo.Element.VISIBILITY;
7726 this.id = this.dom.id = config.id;
7728 this.id = Roo.id(this.dom);
7730 this.zindex = config.zindex || this.getZIndex();
7731 this.position("absolute", this.zindex);
7733 this.shadowOffset = config.shadowOffset || 4;
7734 this.shadow = new Roo.Shadow({
7735 offset : this.shadowOffset,
7736 mode : config.shadow
7739 this.shadowOffset = 0;
7741 this.useShim = config.shim !== false && Roo.useShims;
7742 this.useDisplay = config.useDisplay;
7746 var supr = Roo.Element.prototype;
7748 // shims are shared among layer to keep from having 100 iframes
7751 Roo.extend(Roo.Layer, Roo.Element, {
7753 getZIndex : function(){
7754 return this.zindex || parseInt(this.getStyle("z-index"), 10) || 11000;
7757 getShim : function(){
7764 var shim = shims.shift();
7766 shim = this.createShim();
7767 shim.enableDisplayMode('block');
7768 shim.dom.style.display = 'none';
7769 shim.dom.style.visibility = 'visible';
7771 var pn = this.dom.parentNode;
7772 if(shim.dom.parentNode != pn){
7773 pn.insertBefore(shim.dom, this.dom);
7775 shim.setStyle('z-index', this.getZIndex()-2);
7780 hideShim : function(){
7782 this.shim.setDisplayed(false);
7783 shims.push(this.shim);
7788 disableShadow : function(){
7790 this.shadowDisabled = true;
7792 this.lastShadowOffset = this.shadowOffset;
7793 this.shadowOffset = 0;
7797 enableShadow : function(show){
7799 this.shadowDisabled = false;
7800 this.shadowOffset = this.lastShadowOffset;
7801 delete this.lastShadowOffset;
7809 // this code can execute repeatedly in milliseconds (i.e. during a drag) so
7810 // code size was sacrificed for effeciency (e.g. no getBox/setBox, no XY calls)
7811 sync : function(doShow){
7812 var sw = this.shadow;
7813 if(!this.updating && this.isVisible() && (sw || this.useShim)){
7814 var sh = this.getShim();
7816 var w = this.getWidth(),
7817 h = this.getHeight();
7819 var l = this.getLeft(true),
7820 t = this.getTop(true);
7822 if(sw && !this.shadowDisabled){
7823 if(doShow && !sw.isVisible()){
7826 sw.realign(l, t, w, h);
7832 // fit the shim behind the shadow, so it is shimmed too
7833 var a = sw.adjusts, s = sh.dom.style;
7834 s.left = (Math.min(l, l+a.l))+"px";
7835 s.top = (Math.min(t, t+a.t))+"px";
7836 s.width = (w+a.w)+"px";
7837 s.height = (h+a.h)+"px";
7844 sh.setLeftTop(l, t);
7851 destroy : function(){
7856 this.removeAllListeners();
7857 var pn = this.dom.parentNode;
7859 pn.removeChild(this.dom);
7861 Roo.Element.uncache(this.id);
7864 remove : function(){
7869 beginUpdate : function(){
7870 this.updating = true;
7874 endUpdate : function(){
7875 this.updating = false;
7880 hideUnders : function(negOffset){
7888 constrainXY : function(){
7890 var vw = Roo.lib.Dom.getViewWidth(),
7891 vh = Roo.lib.Dom.getViewHeight();
7892 var s = Roo.get(document).getScroll();
7894 var xy = this.getXY();
7895 var x = xy[0], y = xy[1];
7896 var w = this.dom.offsetWidth+this.shadowOffset, h = this.dom.offsetHeight+this.shadowOffset;
7897 // only move it if it needs it
7899 // first validate right/bottom
7900 if((x + w) > vw+s.left){
7901 x = vw - w - this.shadowOffset;
7904 if((y + h) > vh+s.top){
7905 y = vh - h - this.shadowOffset;
7908 // then make sure top/left isn't negative
7919 var ay = this.avoidY;
7920 if(y <= ay && (y+h) >= ay){
7926 supr.setXY.call(this, xy);
7932 isVisible : function(){
7933 return this.visible;
7937 showAction : function(){
7938 this.visible = true; // track visibility to prevent getStyle calls
7939 if(this.useDisplay === true){
7940 this.setDisplayed("");
7941 }else if(this.lastXY){
7942 supr.setXY.call(this, this.lastXY);
7943 }else if(this.lastLT){
7944 supr.setLeftTop.call(this, this.lastLT[0], this.lastLT[1]);
7949 hideAction : function(){
7950 this.visible = false;
7951 if(this.useDisplay === true){
7952 this.setDisplayed(false);
7954 this.setLeftTop(-10000,-10000);
7958 // overridden Element method
7959 setVisible : function(v, a, d, c, e){
7964 var cb = function(){
7969 }.createDelegate(this);
7970 supr.setVisible.call(this, true, true, d, cb, e);
7973 this.hideUnders(true);
7982 }.createDelegate(this);
7984 supr.setVisible.call(this, v, a, d, cb, e);
7993 storeXY : function(xy){
7998 storeLeftTop : function(left, top){
8000 this.lastLT = [left, top];
8004 beforeFx : function(){
8005 this.beforeAction();
8006 return Roo.Layer.superclass.beforeFx.apply(this, arguments);
8010 afterFx : function(){
8011 Roo.Layer.superclass.afterFx.apply(this, arguments);
8012 this.sync(this.isVisible());
8016 beforeAction : function(){
8017 if(!this.updating && this.shadow){
8022 // overridden Element method
8023 setLeft : function(left){
8024 this.storeLeftTop(left, this.getTop(true));
8025 supr.setLeft.apply(this, arguments);
8029 setTop : function(top){
8030 this.storeLeftTop(this.getLeft(true), top);
8031 supr.setTop.apply(this, arguments);
8035 setLeftTop : function(left, top){
8036 this.storeLeftTop(left, top);
8037 supr.setLeftTop.apply(this, arguments);
8041 setXY : function(xy, a, d, c, e){
8043 this.beforeAction();
8045 var cb = this.createCB(c);
8046 supr.setXY.call(this, xy, a, d, cb, e);
8053 createCB : function(c){
8064 // overridden Element method
8065 setX : function(x, a, d, c, e){
8066 this.setXY([x, this.getY()], a, d, c, e);
8069 // overridden Element method
8070 setY : function(y, a, d, c, e){
8071 this.setXY([this.getX(), y], a, d, c, e);
8074 // overridden Element method
8075 setSize : function(w, h, a, d, c, e){
8076 this.beforeAction();
8077 var cb = this.createCB(c);
8078 supr.setSize.call(this, w, h, a, d, cb, e);
8084 // overridden Element method
8085 setWidth : function(w, a, d, c, e){
8086 this.beforeAction();
8087 var cb = this.createCB(c);
8088 supr.setWidth.call(this, w, a, d, cb, e);
8094 // overridden Element method
8095 setHeight : function(h, a, d, c, e){
8096 this.beforeAction();
8097 var cb = this.createCB(c);
8098 supr.setHeight.call(this, h, a, d, cb, e);
8104 // overridden Element method
8105 setBounds : function(x, y, w, h, a, d, c, e){
8106 this.beforeAction();
8107 var cb = this.createCB(c);
8109 this.storeXY([x, y]);
8110 supr.setXY.call(this, [x, y]);
8111 supr.setSize.call(this, w, h, a, d, cb, e);
8114 supr.setBounds.call(this, x, y, w, h, a, d, cb, e);
8120 * Sets the z-index of this layer and adjusts any shadow and shim z-indexes. The layer z-index is automatically
8121 * incremented by two more than the value passed in so that it always shows above any shadow or shim (the shadow
8122 * element, if any, will be assigned z-index + 1, and the shim element, if any, will be assigned the unmodified z-index).
8123 * @param {Number} zindex The new z-index to set
8124 * @return {this} The Layer
8126 setZIndex : function(zindex){
8127 this.zindex = zindex;
8128 this.setStyle("z-index", zindex + 2);
8130 this.shadow.setZIndex(zindex + 1);
8133 this.shim.setStyle("z-index", zindex);
8139 * Ext JS Library 1.1.1
8140 * Copyright(c) 2006-2007, Ext JS, LLC.
8142 * Originally Released Under LGPL - original licence link has changed is not relivant.
8145 * <script type="text/javascript">
8151 * Simple class that can provide a shadow effect for any element. Note that the element MUST be absolutely positioned,
8152 * and the shadow does not provide any shimming. This should be used only in simple cases -- for more advanced
8153 * functionality that can also provide the same shadow effect, see the {@link Roo.Layer} class.
8155 * Create a new Shadow
8156 * @param {Object} config The config object
8158 Roo.Shadow = function(config){
8159 Roo.apply(this, config);
8160 if(typeof this.mode != "string"){
8161 this.mode = this.defaultMode;
8163 var o = this.offset, a = {h: 0};
8164 var rad = Math.floor(this.offset/2);
8165 switch(this.mode.toLowerCase()){ // all this hideous nonsense calculates the various offsets for shadows
8171 a.l -= this.offset + rad;
8172 a.t -= this.offset + rad;
8183 a.l -= (this.offset - rad);
8184 a.t -= this.offset + rad;
8186 a.w -= (this.offset - rad)*2;
8197 a.l -= (this.offset - rad);
8198 a.t -= (this.offset - rad);
8200 a.w -= (this.offset + rad + 1);
8201 a.h -= (this.offset + rad);
8210 Roo.Shadow.prototype = {
8212 * @cfg {String} mode
8213 * The shadow display mode. Supports the following options:<br />
8214 * sides: Shadow displays on both sides and bottom only<br />
8215 * frame: Shadow displays equally on all four sides<br />
8216 * drop: Traditional bottom-right drop shadow (default)
8219 * @cfg {String} offset
8220 * The number of pixels to offset the shadow from the element (defaults to 4)
8225 defaultMode: "drop",
8228 * Displays the shadow under the target element
8229 * @param {String/HTMLElement/Element} targetEl The id or element under which the shadow should display
8231 show : function(target){
8232 target = Roo.get(target);
8234 this.el = Roo.Shadow.Pool.pull();
8235 if(this.el.dom.nextSibling != target.dom){
8236 this.el.insertBefore(target);
8239 this.el.setStyle("z-index", this.zIndex || parseInt(target.getStyle("z-index"), 10)-1);
8241 this.el.dom.style.filter="progid:DXImageTransform.Microsoft.alpha(opacity=50) progid:DXImageTransform.Microsoft.Blur(pixelradius="+(this.offset)+")";
8244 target.getLeft(true),
8245 target.getTop(true),
8249 this.el.dom.style.display = "block";
8253 * Returns true if the shadow is visible, else false
8255 isVisible : function(){
8256 return this.el ? true : false;
8260 * Direct alignment when values are already available. Show must be called at least once before
8261 * calling this method to ensure it is initialized.
8262 * @param {Number} left The target element left position
8263 * @param {Number} top The target element top position
8264 * @param {Number} width The target element width
8265 * @param {Number} height The target element height
8267 realign : function(l, t, w, h){
8271 var a = this.adjusts, d = this.el.dom, s = d.style;
8273 s.left = (l+a.l)+"px";
8274 s.top = (t+a.t)+"px";
8275 var sw = (w+a.w), sh = (h+a.h), sws = sw +"px", shs = sh + "px";
8277 if(s.width != sws || s.height != shs){
8281 var cn = d.childNodes;
8282 var sww = Math.max(0, (sw-12))+"px";
8283 cn[0].childNodes[1].style.width = sww;
8284 cn[1].childNodes[1].style.width = sww;
8285 cn[2].childNodes[1].style.width = sww;
8286 cn[1].style.height = Math.max(0, (sh-12))+"px";
8296 this.el.dom.style.display = "none";
8297 Roo.Shadow.Pool.push(this.el);
8303 * Adjust the z-index of this shadow
8304 * @param {Number} zindex The new z-index
8306 setZIndex : function(z){
8309 this.el.setStyle("z-index", z);
8314 // Private utility class that manages the internal Shadow cache
8315 Roo.Shadow.Pool = function(){
8317 var markup = Roo.isIE ?
8318 '<div class="x-ie-shadow"></div>' :
8319 '<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>';
8324 sh = Roo.get(Roo.DomHelper.insertHtml("beforeBegin", document.body.firstChild, markup));
8325 sh.autoBoxAdjust = false;
8330 push : function(sh){
8336 * Ext JS Library 1.1.1
8337 * Copyright(c) 2006-2007, Ext JS, LLC.
8339 * Originally Released Under LGPL - original licence link has changed is not relivant.
8342 * <script type="text/javascript">
8346 * @class Roo.BoxComponent
8347 * @extends Roo.Component
8348 * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box
8349 * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All
8350 * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
8351 * layout containers.
8353 * @param {Roo.Element/String/Object} config The configuration options.
8355 Roo.BoxComponent = function(config){
8356 Roo.Component.call(this, config);
8360 * Fires after the component is resized.
8361 * @param {Roo.Component} this
8362 * @param {Number} adjWidth The box-adjusted width that was set
8363 * @param {Number} adjHeight The box-adjusted height that was set
8364 * @param {Number} rawWidth The width that was originally specified
8365 * @param {Number} rawHeight The height that was originally specified
8370 * Fires after the component is moved.
8371 * @param {Roo.Component} this
8372 * @param {Number} x The new x position
8373 * @param {Number} y The new y position
8379 Roo.extend(Roo.BoxComponent, Roo.Component, {
8380 // private, set in afterRender to signify that the component has been rendered
8382 // private, used to defer height settings to subclasses
8384 /** @cfg {Number} width
8385 * width (optional) size of component
8387 /** @cfg {Number} height
8388 * height (optional) size of component
8392 * Sets the width and height of the component. This method fires the resize event. This method can accept
8393 * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
8394 * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
8395 * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
8396 * @return {Roo.BoxComponent} this
8398 setSize : function(w, h){
8399 // support for standard size objects
8400 if(typeof w == 'object'){
8411 // prevent recalcs when not needed
8412 if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
8415 this.lastSize = {width: w, height: h};
8417 var adj = this.adjustSize(w, h);
8418 var aw = adj.width, ah = adj.height;
8419 if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
8420 var rz = this.getResizeEl();
8421 if(!this.deferHeight && aw !== undefined && ah !== undefined){
8423 }else if(!this.deferHeight && ah !== undefined){
8425 }else if(aw !== undefined){
8428 this.onResize(aw, ah, w, h);
8429 this.fireEvent('resize', this, aw, ah, w, h);
8435 * Gets the current size of the component's underlying element.
8436 * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
8438 getSize : function(){
8439 return this.el.getSize();
8443 * Gets the current XY position of the component's underlying element.
8444 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8445 * @return {Array} The XY position of the element (e.g., [100, 200])
8447 getPosition : function(local){
8449 return [this.el.getLeft(true), this.el.getTop(true)];
8451 return this.xy || this.el.getXY();
8455 * Gets the current box measurements of the component's underlying element.
8456 * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
8457 * @returns {Object} box An object in the format {x, y, width, height}
8459 getBox : function(local){
8460 var s = this.el.getSize();
8462 s.x = this.el.getLeft(true);
8463 s.y = this.el.getTop(true);
8465 var xy = this.xy || this.el.getXY();
8473 * Sets the current box measurements of the component's underlying element.
8474 * @param {Object} box An object in the format {x, y, width, height}
8475 * @returns {Roo.BoxComponent} this
8477 updateBox : function(box){
8478 this.setSize(box.width, box.height);
8479 this.setPagePosition(box.x, box.y);
8484 getResizeEl : function(){
8485 return this.resizeEl || this.el;
8489 getPositionEl : function(){
8490 return this.positionEl || this.el;
8494 * Sets the left and top of the component. To set the page XY position instead, use {@link #setPagePosition}.
8495 * This method fires the move event.
8496 * @param {Number} left The new left
8497 * @param {Number} top The new top
8498 * @returns {Roo.BoxComponent} this
8500 setPosition : function(x, y){
8506 var adj = this.adjustPosition(x, y);
8507 var ax = adj.x, ay = adj.y;
8509 var el = this.getPositionEl();
8510 if(ax !== undefined || ay !== undefined){
8511 if(ax !== undefined && ay !== undefined){
8512 el.setLeftTop(ax, ay);
8513 }else if(ax !== undefined){
8515 }else if(ay !== undefined){
8518 this.onPosition(ax, ay);
8519 this.fireEvent('move', this, ax, ay);
8525 * Sets the page XY position of the component. To set the left and top instead, use {@link #setPosition}.
8526 * This method fires the move event.
8527 * @param {Number} x The new x position
8528 * @param {Number} y The new y position
8529 * @returns {Roo.BoxComponent} this
8531 setPagePosition : function(x, y){
8537 if(x === undefined || y === undefined){ // cannot translate undefined points
8540 var p = this.el.translatePoints(x, y);
8541 this.setPosition(p.left, p.top);
8546 onRender : function(ct, position){
8547 Roo.BoxComponent.superclass.onRender.call(this, ct, position);
8549 this.resizeEl = Roo.get(this.resizeEl);
8551 if(this.positionEl){
8552 this.positionEl = Roo.get(this.positionEl);
8557 afterRender : function(){
8558 Roo.BoxComponent.superclass.afterRender.call(this);
8559 this.boxReady = true;
8560 this.setSize(this.width, this.height);
8561 if(this.x || this.y){
8562 this.setPosition(this.x, this.y);
8564 if(this.pageX || this.pageY){
8565 this.setPagePosition(this.pageX, this.pageY);
8570 * Force the component's size to recalculate based on the underlying element's current height and width.
8571 * @returns {Roo.BoxComponent} this
8573 syncSize : function(){
8574 delete this.lastSize;
8575 this.setSize(this.el.getWidth(), this.el.getHeight());
8580 * Called after the component is resized, this method is empty by default but can be implemented by any
8581 * subclass that needs to perform custom logic after a resize occurs.
8582 * @param {Number} adjWidth The box-adjusted width that was set
8583 * @param {Number} adjHeight The box-adjusted height that was set
8584 * @param {Number} rawWidth The width that was originally specified
8585 * @param {Number} rawHeight The height that was originally specified
8587 onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
8592 * Called after the component is moved, this method is empty by default but can be implemented by any
8593 * subclass that needs to perform custom logic after a move occurs.
8594 * @param {Number} x The new x position
8595 * @param {Number} y The new y position
8597 onPosition : function(x, y){
8602 adjustSize : function(w, h){
8606 if(this.autoHeight){
8609 return {width : w, height: h};
8613 adjustPosition : function(x, y){
8614 return {x : x, y: y};
8618 * Ext JS Library 1.1.1
8619 * Copyright(c) 2006-2007, Ext JS, LLC.
8621 * Originally Released Under LGPL - original licence link has changed is not relivant.
8624 * <script type="text/javascript">
8629 * @class Roo.SplitBar
8630 * @extends Roo.util.Observable
8631 * Creates draggable splitter bar functionality from two elements (element to be dragged and element to be resized).
8635 var split = new Roo.SplitBar("elementToDrag", "elementToSize",
8636 Roo.SplitBar.HORIZONTAL, Roo.SplitBar.LEFT);
8637 split.setAdapter(new Roo.SplitBar.AbsoluteLayoutAdapter("container"));
8638 split.minSize = 100;
8639 split.maxSize = 600;
8640 split.animate = true;
8641 split.on('moved', splitterMoved);
8644 * Create a new SplitBar
8645 * @param {String/HTMLElement/Roo.Element} dragElement The element to be dragged and act as the SplitBar.
8646 * @param {String/HTMLElement/Roo.Element} resizingElement The element to be resized based on where the SplitBar element is dragged
8647 * @param {Number} orientation (optional) Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8648 * @param {Number} placement (optional) Either Roo.SplitBar.LEFT or Roo.SplitBar.RIGHT for horizontal or
8649 Roo.SplitBar.TOP or Roo.SplitBar.BOTTOM for vertical. (By default, this is determined automatically by the initial
8650 position of the SplitBar).
8652 Roo.SplitBar = function(dragElement, resizingElement, orientation, placement, existingProxy){
8655 this.el = Roo.get(dragElement, true);
8656 this.el.dom.unselectable = "on";
8658 this.resizingEl = Roo.get(resizingElement, true);
8662 * The orientation of the split. Either Roo.SplitBar.HORIZONTAL or Roo.SplitBar.VERTICAL. (Defaults to HORIZONTAL)
8663 * Note: If this is changed after creating the SplitBar, the placement property must be manually updated
8666 this.orientation = orientation || Roo.SplitBar.HORIZONTAL;
8669 * The minimum size of the resizing element. (Defaults to 0)
8675 * The maximum size of the resizing element. (Defaults to 2000)
8678 this.maxSize = 2000;
8681 * Whether to animate the transition to the new size
8684 this.animate = false;
8687 * Whether to create a transparent shim that overlays the page when dragging, enables dragging across iframes.
8690 this.useShim = false;
8697 this.proxy = Roo.SplitBar.createProxy(this.orientation);
8699 this.proxy = Roo.get(existingProxy).dom;
8702 this.dd = new Roo.dd.DDProxy(this.el.dom.id, "XSplitBars", {dragElId : this.proxy.id});
8705 this.dd.b4StartDrag = this.onStartProxyDrag.createDelegate(this);
8708 this.dd.endDrag = this.onEndProxyDrag.createDelegate(this);
8711 this.dragSpecs = {};
8714 * @private The adapter to use to positon and resize elements
8716 this.adapter = new Roo.SplitBar.BasicLayoutAdapter();
8717 this.adapter.init(this);
8719 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8721 this.placement = placement || (this.el.getX() > this.resizingEl.getX() ? Roo.SplitBar.LEFT : Roo.SplitBar.RIGHT);
8722 this.el.addClass("x-splitbar-h");
8725 this.placement = placement || (this.el.getY() > this.resizingEl.getY() ? Roo.SplitBar.TOP : Roo.SplitBar.BOTTOM);
8726 this.el.addClass("x-splitbar-v");
8732 * Fires when the splitter is moved (alias for {@link #event-moved})
8733 * @param {Roo.SplitBar} this
8734 * @param {Number} newSize the new width or height
8739 * Fires when the splitter is moved
8740 * @param {Roo.SplitBar} this
8741 * @param {Number} newSize the new width or height
8745 * @event beforeresize
8746 * Fires before the splitter is dragged
8747 * @param {Roo.SplitBar} this
8749 "beforeresize" : true,
8751 "beforeapply" : true
8754 Roo.util.Observable.call(this);
8757 Roo.extend(Roo.SplitBar, Roo.util.Observable, {
8758 onStartProxyDrag : function(x, y){
8759 this.fireEvent("beforeresize", this);
8761 var o = Roo.DomHelper.insertFirst(document.body, {cls: "x-drag-overlay", html: " "}, true);
8763 o.enableDisplayMode("block");
8764 // all splitbars share the same overlay
8765 Roo.SplitBar.prototype.overlay = o;
8767 this.overlay.setSize(Roo.lib.Dom.getViewWidth(true), Roo.lib.Dom.getViewHeight(true));
8768 this.overlay.show();
8769 Roo.get(this.proxy).setDisplayed("block");
8770 var size = this.adapter.getElementSize(this);
8771 this.activeMinSize = this.getMinimumSize();;
8772 this.activeMaxSize = this.getMaximumSize();;
8773 var c1 = size - this.activeMinSize;
8774 var c2 = Math.max(this.activeMaxSize - size, 0);
8775 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8776 this.dd.resetConstraints();
8777 this.dd.setXConstraint(
8778 this.placement == Roo.SplitBar.LEFT ? c1 : c2,
8779 this.placement == Roo.SplitBar.LEFT ? c2 : c1
8781 this.dd.setYConstraint(0, 0);
8783 this.dd.resetConstraints();
8784 this.dd.setXConstraint(0, 0);
8785 this.dd.setYConstraint(
8786 this.placement == Roo.SplitBar.TOP ? c1 : c2,
8787 this.placement == Roo.SplitBar.TOP ? c2 : c1
8790 this.dragSpecs.startSize = size;
8791 this.dragSpecs.startPoint = [x, y];
8792 Roo.dd.DDProxy.prototype.b4StartDrag.call(this.dd, x, y);
8796 * @private Called after the drag operation by the DDProxy
8798 onEndProxyDrag : function(e){
8799 Roo.get(this.proxy).setDisplayed(false);
8800 var endPoint = Roo.lib.Event.getXY(e);
8802 this.overlay.hide();
8805 if(this.orientation == Roo.SplitBar.HORIZONTAL){
8806 newSize = this.dragSpecs.startSize +
8807 (this.placement == Roo.SplitBar.LEFT ?
8808 endPoint[0] - this.dragSpecs.startPoint[0] :
8809 this.dragSpecs.startPoint[0] - endPoint[0]
8812 newSize = this.dragSpecs.startSize +
8813 (this.placement == Roo.SplitBar.TOP ?
8814 endPoint[1] - this.dragSpecs.startPoint[1] :
8815 this.dragSpecs.startPoint[1] - endPoint[1]
8818 newSize = Math.min(Math.max(newSize, this.activeMinSize), this.activeMaxSize);
8819 if(newSize != this.dragSpecs.startSize){
8820 if(this.fireEvent('beforeapply', this, newSize) !== false){
8821 this.adapter.setElementSize(this, newSize);
8822 this.fireEvent("moved", this, newSize);
8823 this.fireEvent("resize", this, newSize);
8829 * Get the adapter this SplitBar uses
8830 * @return The adapter object
8832 getAdapter : function(){
8833 return this.adapter;
8837 * Set the adapter this SplitBar uses
8838 * @param {Object} adapter A SplitBar adapter object
8840 setAdapter : function(adapter){
8841 this.adapter = adapter;
8842 this.adapter.init(this);
8846 * Gets the minimum size for the resizing element
8847 * @return {Number} The minimum size
8849 getMinimumSize : function(){
8850 return this.minSize;
8854 * Sets the minimum size for the resizing element
8855 * @param {Number} minSize The minimum size
8857 setMinimumSize : function(minSize){
8858 this.minSize = minSize;
8862 * Gets the maximum size for the resizing element
8863 * @return {Number} The maximum size
8865 getMaximumSize : function(){
8866 return this.maxSize;
8870 * Sets the maximum size for the resizing element
8871 * @param {Number} maxSize The maximum size
8873 setMaximumSize : function(maxSize){
8874 this.maxSize = maxSize;
8878 * Sets the initialize size for the resizing element
8879 * @param {Number} size The initial size
8881 setCurrentSize : function(size){
8882 var oldAnimate = this.animate;
8883 this.animate = false;
8884 this.adapter.setElementSize(this, size);
8885 this.animate = oldAnimate;
8889 * Destroy this splitbar.
8890 * @param {Boolean} removeEl True to remove the element
8892 destroy : function(removeEl){
8897 this.proxy.parentNode.removeChild(this.proxy);
8905 * @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.
8907 Roo.SplitBar.createProxy = function(dir){
8908 var proxy = new Roo.Element(document.createElement("div"));
8909 proxy.unselectable();
8910 var cls = 'x-splitbar-proxy';
8911 proxy.addClass(cls + ' ' + (dir == Roo.SplitBar.HORIZONTAL ? cls +'-h' : cls + '-v'));
8912 document.body.appendChild(proxy.dom);
8917 * @class Roo.SplitBar.BasicLayoutAdapter
8918 * Default Adapter. It assumes the splitter and resizing element are not positioned
8919 * elements and only gets/sets the width of the element. Generally used for table based layouts.
8921 Roo.SplitBar.BasicLayoutAdapter = function(){
8924 Roo.SplitBar.BasicLayoutAdapter.prototype = {
8925 // do nothing for now
8930 * Called before drag operations to get the current size of the resizing element.
8931 * @param {Roo.SplitBar} s The SplitBar using this adapter
8933 getElementSize : function(s){
8934 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8935 return s.resizingEl.getWidth();
8937 return s.resizingEl.getHeight();
8942 * Called after drag operations to set the size of the resizing element.
8943 * @param {Roo.SplitBar} s The SplitBar using this adapter
8944 * @param {Number} newSize The new size to set
8945 * @param {Function} onComplete A function to be invoked when resizing is complete
8947 setElementSize : function(s, newSize, onComplete){
8948 if(s.orientation == Roo.SplitBar.HORIZONTAL){
8950 s.resizingEl.setWidth(newSize);
8952 onComplete(s, newSize);
8955 s.resizingEl.setWidth(newSize, true, .1, onComplete, 'easeOut');
8960 s.resizingEl.setHeight(newSize);
8962 onComplete(s, newSize);
8965 s.resizingEl.setHeight(newSize, true, .1, onComplete, 'easeOut');
8972 *@class Roo.SplitBar.AbsoluteLayoutAdapter
8973 * @extends Roo.SplitBar.BasicLayoutAdapter
8974 * Adapter that moves the splitter element to align with the resized sizing element.
8975 * Used with an absolute positioned SplitBar.
8976 * @param {String/HTMLElement/Roo.Element} container The container that wraps around the absolute positioned content. If it's
8977 * document.body, make sure you assign an id to the body element.
8979 Roo.SplitBar.AbsoluteLayoutAdapter = function(container){
8980 this.basic = new Roo.SplitBar.BasicLayoutAdapter();
8981 this.container = Roo.get(container);
8984 Roo.SplitBar.AbsoluteLayoutAdapter.prototype = {
8989 getElementSize : function(s){
8990 return this.basic.getElementSize(s);
8993 setElementSize : function(s, newSize, onComplete){
8994 this.basic.setElementSize(s, newSize, this.moveSplitter.createDelegate(this, [s]));
8997 moveSplitter : function(s){
8998 var yes = Roo.SplitBar;
8999 switch(s.placement){
9001 s.el.setX(s.resizingEl.getRight());
9004 s.el.setStyle("right", (this.container.getWidth() - s.resizingEl.getLeft()) + "px");
9007 s.el.setY(s.resizingEl.getBottom());
9010 s.el.setY(s.resizingEl.getTop() - s.el.getHeight());
9017 * Orientation constant - Create a vertical SplitBar
9021 Roo.SplitBar.VERTICAL = 1;
9024 * Orientation constant - Create a horizontal SplitBar
9028 Roo.SplitBar.HORIZONTAL = 2;
9031 * Placement constant - The resizing element is to the left of the splitter element
9035 Roo.SplitBar.LEFT = 1;
9038 * Placement constant - The resizing element is to the right of the splitter element
9042 Roo.SplitBar.RIGHT = 2;
9045 * Placement constant - The resizing element is positioned above the splitter element
9049 Roo.SplitBar.TOP = 3;
9052 * Placement constant - The resizing element is positioned under splitter element
9056 Roo.SplitBar.BOTTOM = 4;
9059 * Ext JS Library 1.1.1
9060 * Copyright(c) 2006-2007, Ext JS, LLC.
9062 * Originally Released Under LGPL - original licence link has changed is not relivant.
9065 * <script type="text/javascript">
9070 * @extends Roo.util.Observable
9071 * Create a "View" for an element based on a data model or UpdateManager and the supplied DomHelper template.
9072 * This class also supports single and multi selection modes. <br>
9073 * Create a data model bound view:
9075 var store = new Roo.data.Store(...);
9077 var view = new Roo.View({
9079 tpl : '<div id="{0}">{2} - {1}</div>', // auto create template
9082 selectedClass: "ydataview-selected",
9086 // listen for node click?
9087 view.on("click", function(vw, index, node, e){
9088 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9092 dataModel.load("foobar.xml");
9094 For an example of creating a JSON/UpdateManager view, see {@link Roo.JsonView}.
9096 * <b>Note: The root of your template must be a single node. Table/row implementations may work but are not supported due to
9097 * IE"s limited insertion support with tables and Opera"s faulty event bubbling.</b>
9099 * Note: old style constructor is still suported (container, template, config)
9103 * @param {Object} config The config object
9106 Roo.View = function(config, depreciated_tpl, depreciated_config){
9108 if (typeof(depreciated_tpl) == 'undefined') {
9109 // new way.. - universal constructor.
9110 Roo.apply(this, config);
9111 this.el = Roo.get(this.el);
9114 this.el = Roo.get(config);
9115 this.tpl = depreciated_tpl;
9116 Roo.apply(this, depreciated_config);
9120 if(typeof(this.tpl) == "string"){
9121 this.tpl = new Roo.Template(this.tpl);
9123 // support xtype ctors..
9124 this.tpl = new Roo.factory(this.tpl, Roo);
9135 * @event beforeclick
9136 * Fires before a click is processed. Returns false to cancel the default action.
9137 * @param {Roo.View} this
9138 * @param {Number} index The index of the target node
9139 * @param {HTMLElement} node The target node
9140 * @param {Roo.EventObject} e The raw event object
9142 "beforeclick" : true,
9145 * Fires when a template node is clicked.
9146 * @param {Roo.View} this
9147 * @param {Number} index The index of the target node
9148 * @param {HTMLElement} node The target node
9149 * @param {Roo.EventObject} e The raw event object
9154 * Fires when a template node is double clicked.
9155 * @param {Roo.View} this
9156 * @param {Number} index The index of the target node
9157 * @param {HTMLElement} node The target node
9158 * @param {Roo.EventObject} e The raw event object
9162 * @event contextmenu
9163 * Fires when a template node is right clicked.
9164 * @param {Roo.View} this
9165 * @param {Number} index The index of the target node
9166 * @param {HTMLElement} node The target node
9167 * @param {Roo.EventObject} e The raw event object
9169 "contextmenu" : true,
9171 * @event selectionchange
9172 * Fires when the selected nodes change.
9173 * @param {Roo.View} this
9174 * @param {Array} selections Array of the selected nodes
9176 "selectionchange" : true,
9179 * @event beforeselect
9180 * Fires before a selection is made. If any handlers return false, the selection is cancelled.
9181 * @param {Roo.View} this
9182 * @param {HTMLElement} node The node to be selected
9183 * @param {Array} selections Array of currently selected nodes
9185 "beforeselect" : true
9189 "click": this.onClick,
9190 "dblclick": this.onDblClick,
9191 "contextmenu": this.onContextMenu,
9195 this.selections = [];
9197 this.cmp = new Roo.CompositeElementLite([]);
9199 this.store = Roo.factory(this.store, Roo.data);
9200 this.setStore(this.store, true);
9202 Roo.View.superclass.constructor.call(this);
9205 Roo.extend(Roo.View, Roo.util.Observable, {
9208 * @cfg {Roo.data.Store} store Data store to load data from.
9213 * @cfg {String|Roo.Element} el The container element.
9218 * @cfg {String|Roo.Template} tpl The template used by this View
9223 * @cfg {String} selectedClass The css class to add to selected nodes
9225 selectedClass : "x-view-selected",
9227 * @cfg {String} emptyText The empty text to show when nothing is loaded.
9231 * @cfg {Boolean} multiSelect Allow multiple selection
9234 multiSelect : false,
9236 * @cfg {Boolean} singleSelect Allow single selection
9238 singleSelect: false,
9241 * Returns the element this view is bound to.
9242 * @return {Roo.Element}
9249 * Refreshes the view.
9251 refresh : function(){
9253 this.clearSelections();
9256 var records = this.store.getRange();
9257 if(records.length < 1){
9258 this.el.update(this.emptyText);
9261 for(var i = 0, len = records.length; i < len; i++){
9262 var data = this.prepareData(records[i].data, i, records[i]);
9263 html[html.length] = t.apply(data);
9265 this.el.update(html.join(""));
9266 this.nodes = this.el.dom.childNodes;
9267 this.updateIndexes(0);
9271 * Function to override to reformat the data that is sent to
9272 * the template for each node.
9273 * @param {Array/Object} data The raw data (array of colData for a data model bound view or
9274 * a JSON object for an UpdateManager bound view).
9276 prepareData : function(data){
9280 onUpdate : function(ds, record){
9281 this.clearSelections();
9282 var index = this.store.indexOf(record);
9283 var n = this.nodes[index];
9284 this.tpl.insertBefore(n, this.prepareData(record.data));
9285 n.parentNode.removeChild(n);
9286 this.updateIndexes(index, index);
9289 onAdd : function(ds, records, index){
9290 this.clearSelections();
9291 if(this.nodes.length == 0){
9295 var n = this.nodes[index];
9296 for(var i = 0, len = records.length; i < len; i++){
9297 var d = this.prepareData(records[i].data);
9299 this.tpl.insertBefore(n, d);
9301 this.tpl.append(this.el, d);
9304 this.updateIndexes(index);
9307 onRemove : function(ds, record, index){
9308 this.clearSelections();
9309 this.el.dom.removeChild(this.nodes[index]);
9310 this.updateIndexes(index);
9314 * Refresh an individual node.
9315 * @param {Number} index
9317 refreshNode : function(index){
9318 this.onUpdate(this.store, this.store.getAt(index));
9321 updateIndexes : function(startIndex, endIndex){
9322 var ns = this.nodes;
9323 startIndex = startIndex || 0;
9324 endIndex = endIndex || ns.length - 1;
9325 for(var i = startIndex; i <= endIndex; i++){
9326 ns[i].nodeIndex = i;
9331 * Changes the data store this view uses and refresh the view.
9332 * @param {Store} store
9334 setStore : function(store, initial){
9335 if(!initial && this.store){
9336 this.store.un("datachanged", this.refresh);
9337 this.store.un("add", this.onAdd);
9338 this.store.un("remove", this.onRemove);
9339 this.store.un("update", this.onUpdate);
9340 this.store.un("clear", this.refresh);
9344 store.on("datachanged", this.refresh, this);
9345 store.on("add", this.onAdd, this);
9346 store.on("remove", this.onRemove, this);
9347 store.on("update", this.onUpdate, this);
9348 store.on("clear", this.refresh, this);
9357 * Returns the template node the passed child belongs to or null if it doesn't belong to one.
9358 * @param {HTMLElement} node
9359 * @return {HTMLElement} The template node
9361 findItemFromChild : function(node){
9362 var el = this.el.dom;
9363 if(!node || node.parentNode == el){
9366 var p = node.parentNode;
9367 while(p && p != el){
9368 if(p.parentNode == el){
9377 onClick : function(e){
9378 var item = this.findItemFromChild(e.getTarget());
9380 var index = this.indexOf(item);
9381 if(this.onItemClick(item, index, e) !== false){
9382 this.fireEvent("click", this, index, item, e);
9385 this.clearSelections();
9390 onContextMenu : function(e){
9391 var item = this.findItemFromChild(e.getTarget());
9393 this.fireEvent("contextmenu", this, this.indexOf(item), item, e);
9398 onDblClick : function(e){
9399 var item = this.findItemFromChild(e.getTarget());
9401 this.fireEvent("dblclick", this, this.indexOf(item), item, e);
9405 onItemClick : function(item, index, e){
9406 if(this.fireEvent("beforeclick", this, index, item, e) === false){
9409 if(this.multiSelect || this.singleSelect){
9410 if(this.multiSelect && e.shiftKey && this.lastSelection){
9411 this.select(this.getNodes(this.indexOf(this.lastSelection), index), false);
9413 this.select(item, this.multiSelect && e.ctrlKey);
9414 this.lastSelection = item;
9422 * Get the number of selected nodes.
9425 getSelectionCount : function(){
9426 return this.selections.length;
9430 * Get the currently selected nodes.
9431 * @return {Array} An array of HTMLElements
9433 getSelectedNodes : function(){
9434 return this.selections;
9438 * Get the indexes of the selected nodes.
9441 getSelectedIndexes : function(){
9442 var indexes = [], s = this.selections;
9443 for(var i = 0, len = s.length; i < len; i++){
9444 indexes.push(s[i].nodeIndex);
9450 * Clear all selections
9451 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange event
9453 clearSelections : function(suppressEvent){
9454 if(this.nodes && (this.multiSelect || this.singleSelect) && this.selections.length > 0){
9455 this.cmp.elements = this.selections;
9456 this.cmp.removeClass(this.selectedClass);
9457 this.selections = [];
9459 this.fireEvent("selectionchange", this, this.selections);
9465 * Returns true if the passed node is selected
9466 * @param {HTMLElement/Number} node The node or node index
9469 isSelected : function(node){
9470 var s = this.selections;
9474 node = this.getNode(node);
9475 return s.indexOf(node) !== -1;
9480 * @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
9481 * @param {Boolean} keepExisting (optional) true to keep existing selections
9482 * @param {Boolean} suppressEvent (optional) true to skip firing of the selectionchange vent
9484 select : function(nodeInfo, keepExisting, suppressEvent){
9485 if(nodeInfo instanceof Array){
9487 this.clearSelections(true);
9489 for(var i = 0, len = nodeInfo.length; i < len; i++){
9490 this.select(nodeInfo[i], true, true);
9493 var node = this.getNode(nodeInfo);
9494 if(node && !this.isSelected(node)){
9496 this.clearSelections(true);
9498 if(this.fireEvent("beforeselect", this, node, this.selections) !== false){
9499 Roo.fly(node).addClass(this.selectedClass);
9500 this.selections.push(node);
9502 this.fireEvent("selectionchange", this, this.selections);
9510 * Gets a template node.
9511 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9512 * @return {HTMLElement} The node or null if it wasn't found
9514 getNode : function(nodeInfo){
9515 if(typeof nodeInfo == "string"){
9516 return document.getElementById(nodeInfo);
9517 }else if(typeof nodeInfo == "number"){
9518 return this.nodes[nodeInfo];
9524 * Gets a range template nodes.
9525 * @param {Number} startIndex
9526 * @param {Number} endIndex
9527 * @return {Array} An array of nodes
9529 getNodes : function(start, end){
9530 var ns = this.nodes;
9532 end = typeof end == "undefined" ? ns.length - 1 : end;
9535 for(var i = start; i <= end; i++){
9539 for(var i = start; i >= end; i--){
9547 * Finds the index of the passed node
9548 * @param {HTMLElement/String/Number} nodeInfo An HTMLElement template node, index of a template node or the id of a template node
9549 * @return {Number} The index of the node or -1
9551 indexOf : function(node){
9552 node = this.getNode(node);
9553 if(typeof node.nodeIndex == "number"){
9554 return node.nodeIndex;
9556 var ns = this.nodes;
9557 for(var i = 0, len = ns.length; i < len; i++){
9567 * Ext JS Library 1.1.1
9568 * Copyright(c) 2006-2007, Ext JS, LLC.
9570 * Originally Released Under LGPL - original licence link has changed is not relivant.
9573 * <script type="text/javascript">
9577 * @class Roo.JsonView
9579 * Shortcut class to create a JSON + {@link Roo.UpdateManager} template view. Usage:
9581 var view = new Roo.JsonView({
9582 container: "my-element",
9583 tpl: '<div id="{id}">{foo} - {bar}</div>', // auto create template
9588 // listen for node click?
9589 view.on("click", function(vw, index, node, e){
9590 alert('Node "' + node.id + '" at index: ' + index + " was clicked.");
9593 // direct load of JSON data
9594 view.load("foobar.php");
9596 // Example from my blog list
9597 var tpl = new Roo.Template(
9598 '<div class="entry">' +
9599 '<a class="entry-title" href="{link}">{title}</a>' +
9600 "<h4>{date} by {author} | {comments} Comments</h4>{description}" +
9601 "</div><hr />"
9604 var moreView = new Roo.JsonView({
9605 container : "entry-list",
9609 moreView.on("beforerender", this.sortEntries, this);
9611 url: "/blog/get-posts.php",
9612 params: "allposts=true",
9613 text: "Loading Blog Entries..."
9617 * Note: old code is supported with arguments : (container, template, config)
9621 * Create a new JsonView
9623 * @param {Object} config The config object
9626 Roo.JsonView = function(config, depreciated_tpl, depreciated_config){
9629 Roo.JsonView.superclass.constructor.call(this, config, depreciated_tpl, depreciated_config);
9631 var um = this.el.getUpdateManager();
9632 um.setRenderer(this);
9633 um.on("update", this.onLoad, this);
9634 um.on("failure", this.onLoadException, this);
9637 * @event beforerender
9638 * Fires before rendering of the downloaded JSON data.
9639 * @param {Roo.JsonView} this
9640 * @param {Object} data The JSON data loaded
9644 * Fires when data is loaded.
9645 * @param {Roo.JsonView} this
9646 * @param {Object} data The JSON data loaded
9647 * @param {Object} response The raw Connect response object
9650 * @event loadexception
9651 * Fires when loading fails.
9652 * @param {Roo.JsonView} this
9653 * @param {Object} response The raw Connect response object
9656 'beforerender' : true,
9658 'loadexception' : true
9661 Roo.extend(Roo.JsonView, Roo.View, {
9663 * @type {String} The root property in the loaded JSON object that contains the data
9668 * Refreshes the view.
9670 refresh : function(){
9671 this.clearSelections();
9674 var o = this.jsonData;
9675 if(o && o.length > 0){
9676 for(var i = 0, len = o.length; i < len; i++){
9677 var data = this.prepareData(o[i], i, o);
9678 html[html.length] = this.tpl.apply(data);
9681 html.push(this.emptyText);
9683 this.el.update(html.join(""));
9684 this.nodes = this.el.dom.childNodes;
9685 this.updateIndexes(0);
9689 * 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.
9690 * @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:
9693 url: "your-url.php",
9694 params: {param1: "foo", param2: "bar"}, // or a URL encoded string
9695 callback: yourFunction,
9696 scope: yourObject, //(optional scope)
9704 * The only required property is <i>url</i>. The optional properties <i>nocache</i>, <i>text</i> and <i>scripts</i>
9705 * 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.
9706 * @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}
9707 * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
9708 * @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.
9711 var um = this.el.getUpdateManager();
9712 um.update.apply(um, arguments);
9715 render : function(el, response){
9716 this.clearSelections();
9720 o = Roo.util.JSON.decode(response.responseText);
9723 o = o[this.jsonRoot];
9728 * The current JSON data or null
9731 this.beforeRender();
9736 * Get the number of records in the current JSON dataset
9739 getCount : function(){
9740 return this.jsonData ? this.jsonData.length : 0;
9744 * Returns the JSON object for the specified node(s)
9745 * @param {HTMLElement/Array} node The node or an array of nodes
9746 * @return {Object/Array} If you pass in an array, you get an array back, otherwise
9747 * you get the JSON object for the node
9749 getNodeData : function(node){
9750 if(node instanceof Array){
9752 for(var i = 0, len = node.length; i < len; i++){
9753 data.push(this.getNodeData(node[i]));
9757 return this.jsonData[this.indexOf(node)] || null;
9760 beforeRender : function(){
9761 this.snapshot = this.jsonData;
9763 this.sort.apply(this, this.sortInfo);
9765 this.fireEvent("beforerender", this, this.jsonData);
9768 onLoad : function(el, o){
9769 this.fireEvent("load", this, this.jsonData, o);
9772 onLoadException : function(el, o){
9773 this.fireEvent("loadexception", this, o);
9777 * Filter the data by a specific property.
9778 * @param {String} property A property on your JSON objects
9779 * @param {String/RegExp} value Either string that the property values
9780 * should start with, or a RegExp to test against the property
9782 filter : function(property, value){
9785 var ss = this.snapshot;
9786 if(typeof value == "string"){
9787 var vlen = value.length;
9792 value = value.toLowerCase();
9793 for(var i = 0, len = ss.length; i < len; i++){
9795 if(o[property].substr(0, vlen).toLowerCase() == value){
9799 } else if(value.exec){ // regex?
9800 for(var i = 0, len = ss.length; i < len; i++){
9802 if(value.test(o[property])){
9809 this.jsonData = data;
9815 * Filter by a function. The passed function will be called with each
9816 * object in the current dataset. If the function returns true the value is kept,
9817 * otherwise it is filtered.
9818 * @param {Function} fn
9819 * @param {Object} scope (optional) The scope of the function (defaults to this JsonView)
9821 filterBy : function(fn, scope){
9824 var ss = this.snapshot;
9825 for(var i = 0, len = ss.length; i < len; i++){
9827 if(fn.call(scope || this, o)){
9831 this.jsonData = data;
9837 * Clears the current filter.
9839 clearFilter : function(){
9840 if(this.snapshot && this.jsonData != this.snapshot){
9841 this.jsonData = this.snapshot;
9848 * Sorts the data for this view and refreshes it.
9849 * @param {String} property A property on your JSON objects to sort on
9850 * @param {String} direction (optional) "desc" or "asc" (defaults to "asc")
9851 * @param {Function} sortType (optional) A function to call to convert the data to a sortable value.
9853 sort : function(property, dir, sortType){
9854 this.sortInfo = Array.prototype.slice.call(arguments, 0);
9857 var dsc = dir && dir.toLowerCase() == "desc";
9858 var f = function(o1, o2){
9859 var v1 = sortType ? sortType(o1[p]) : o1[p];
9860 var v2 = sortType ? sortType(o2[p]) : o2[p];
9863 return dsc ? +1 : -1;
9865 return dsc ? -1 : +1;
9870 this.jsonData.sort(f);
9872 if(this.jsonData != this.snapshot){
9873 this.snapshot.sort(f);
9879 * Ext JS Library 1.1.1
9880 * Copyright(c) 2006-2007, Ext JS, LLC.
9882 * Originally Released Under LGPL - original licence link has changed is not relivant.
9885 * <script type="text/javascript">
9890 * @class Roo.ColorPalette
9891 * @extends Roo.Component
9892 * Simple color palette class for choosing colors. The palette can be rendered to any container.<br />
9893 * Here's an example of typical usage:
9895 var cp = new Roo.ColorPalette({value:'993300'}); // initial selected color
9896 cp.render('my-div');
9898 cp.on('select', function(palette, selColor){
9899 // do something with selColor
9903 * Create a new ColorPalette
9904 * @param {Object} config The config object
9906 Roo.ColorPalette = function(config){
9907 Roo.ColorPalette.superclass.constructor.call(this, config);
9911 * Fires when a color is selected
9912 * @param {ColorPalette} this
9913 * @param {String} color The 6-digit color hex code (without the # symbol)
9919 this.on("select", this.handler, this.scope, true);
9922 Roo.extend(Roo.ColorPalette, Roo.Component, {
9924 * @cfg {String} itemCls
9925 * The CSS class to apply to the containing element (defaults to "x-color-palette")
9927 itemCls : "x-color-palette",
9929 * @cfg {String} value
9930 * The initial color to highlight (should be a valid 6-digit color hex code without the # symbol). Note that
9931 * the hex codes are case-sensitive.
9936 ctype: "Roo.ColorPalette",
9939 * @cfg {Boolean} allowReselect If set to true then reselecting a color that is already selected fires the selection event
9941 allowReselect : false,
9944 * <p>An array of 6-digit color hex code strings (without the # symbol). This array can contain any number
9945 * of colors, and each hex code should be unique. The width of the palette is controlled via CSS by adjusting
9946 * the width property of the 'x-color-palette' class (or assigning a custom class), so you can balance the number
9947 * of colors with the width setting until the box is symmetrical.</p>
9948 * <p>You can override individual colors if needed:</p>
9950 var cp = new Roo.ColorPalette();
9951 cp.colors[0] = "FF0000"; // change the first box to red
9954 Or you can provide a custom array of your own for complete control:
9956 var cp = new Roo.ColorPalette();
9957 cp.colors = ["000000", "993300", "333300"];
9962 "000000", "993300", "333300", "003300", "003366", "000080", "333399", "333333",
9963 "800000", "FF6600", "808000", "008000", "008080", "0000FF", "666699", "808080",
9964 "FF0000", "FF9900", "99CC00", "339966", "33CCCC", "3366FF", "800080", "969696",
9965 "FF00FF", "FFCC00", "FFFF00", "00FF00", "00FFFF", "00CCFF", "993366", "C0C0C0",
9966 "FF99CC", "FFCC99", "FFFF99", "CCFFCC", "CCFFFF", "99CCFF", "CC99FF", "FFFFFF"
9970 onRender : function(container, position){
9971 var t = new Roo.MasterTemplate(
9972 '<tpl><a href="#" class="color-{0}" hidefocus="on"><em><span style="background:#{0}" unselectable="on"> </span></em></a></tpl>'
9974 var c = this.colors;
9975 for(var i = 0, len = c.length; i < len; i++){
9978 var el = document.createElement("div");
9979 el.className = this.itemCls;
9981 container.dom.insertBefore(el, position);
9982 this.el = Roo.get(el);
9983 this.el.on(this.clickEvent, this.handleClick, this, {delegate: "a"});
9984 if(this.clickEvent != 'click'){
9985 this.el.on('click', Roo.emptyFn, this, {delegate: "a", preventDefault:true});
9990 afterRender : function(){
9991 Roo.ColorPalette.superclass.afterRender.call(this);
10000 handleClick : function(e, t){
10001 e.preventDefault();
10002 if(!this.disabled){
10003 var c = t.className.match(/(?:^|\s)color-(.{6})(?:\s|$)/)[1];
10004 this.select(c.toUpperCase());
10009 * Selects the specified color in the palette (fires the select event)
10010 * @param {String} color A valid 6-digit color hex code (# will be stripped if included)
10012 select : function(color){
10013 color = color.replace("#", "");
10014 if(color != this.value || this.allowReselect){
10017 el.child("a.color-"+this.value).removeClass("x-color-palette-sel");
10019 el.child("a.color-"+color).addClass("x-color-palette-sel");
10020 this.value = color;
10021 this.fireEvent("select", this, color);
10026 * Ext JS Library 1.1.1
10027 * Copyright(c) 2006-2007, Ext JS, LLC.
10029 * Originally Released Under LGPL - original licence link has changed is not relivant.
10032 * <script type="text/javascript">
10036 * @class Roo.DatePicker
10037 * @extends Roo.Component
10038 * Simple date picker class.
10040 * Create a new DatePicker
10041 * @param {Object} config The config object
10043 Roo.DatePicker = function(config){
10044 Roo.DatePicker.superclass.constructor.call(this, config);
10046 this.value = config && config.value ?
10047 config.value.clearTime() : new Date().clearTime();
10052 * Fires when a date is selected
10053 * @param {DatePicker} this
10054 * @param {Date} date The selected date
10060 this.on("select", this.handler, this.scope || this);
10062 // build the disabledDatesRE
10063 if(!this.disabledDatesRE && this.disabledDates){
10064 var dd = this.disabledDates;
10066 for(var i = 0; i < dd.length; i++){
10068 if(i != dd.length-1) re += "|";
10070 this.disabledDatesRE = new RegExp(re + ")");
10074 Roo.extend(Roo.DatePicker, Roo.Component, {
10076 * @cfg {String} todayText
10077 * The text to display on the button that selects the current date (defaults to "Today")
10079 todayText : "Today",
10081 * @cfg {String} okText
10082 * The text to display on the ok button
10084 okText : " OK ", //   to give the user extra clicking room
10086 * @cfg {String} cancelText
10087 * The text to display on the cancel button
10089 cancelText : "Cancel",
10091 * @cfg {String} todayTip
10092 * The tooltip to display for the button that selects the current date (defaults to "{current date} (Spacebar)")
10094 todayTip : "{0} (Spacebar)",
10096 * @cfg {Date} minDate
10097 * Minimum allowable date (JavaScript date object, defaults to null)
10101 * @cfg {Date} maxDate
10102 * Maximum allowable date (JavaScript date object, defaults to null)
10106 * @cfg {String} minText
10107 * The error text to display if the minDate validation fails (defaults to "This date is before the minimum date")
10109 minText : "This date is before the minimum date",
10111 * @cfg {String} maxText
10112 * The error text to display if the maxDate validation fails (defaults to "This date is after the maximum date")
10114 maxText : "This date is after the maximum date",
10116 * @cfg {String} format
10117 * The default date format string which can be overriden for localization support. The format must be
10118 * valid according to {@link Date#parseDate} (defaults to 'm/d/y').
10122 * @cfg {Array} disabledDays
10123 * An array of days to disable, 0-based. For example, [0, 6] disables Sunday and Saturday (defaults to null).
10125 disabledDays : null,
10127 * @cfg {String} disabledDaysText
10128 * The tooltip to display when the date falls on a disabled day (defaults to "")
10130 disabledDaysText : "",
10132 * @cfg {RegExp} disabledDatesRE
10133 * JavaScript regular expression used to disable a pattern of dates (defaults to null)
10135 disabledDatesRE : null,
10137 * @cfg {String} disabledDatesText
10138 * The tooltip text to display when the date falls on a disabled date (defaults to "")
10140 disabledDatesText : "",
10142 * @cfg {Boolean} constrainToViewport
10143 * True to constrain the date picker to the viewport (defaults to true)
10145 constrainToViewport : true,
10147 * @cfg {Array} monthNames
10148 * An array of textual month names which can be overriden for localization support (defaults to Date.monthNames)
10150 monthNames : Date.monthNames,
10152 * @cfg {Array} dayNames
10153 * An array of textual day names which can be overriden for localization support (defaults to Date.dayNames)
10155 dayNames : Date.dayNames,
10157 * @cfg {String} nextText
10158 * The next month navigation button tooltip (defaults to 'Next Month (Control+Right)')
10160 nextText: 'Next Month (Control+Right)',
10162 * @cfg {String} prevText
10163 * The previous month navigation button tooltip (defaults to 'Previous Month (Control+Left)')
10165 prevText: 'Previous Month (Control+Left)',
10167 * @cfg {String} monthYearText
10168 * The header month selector tooltip (defaults to 'Choose a month (Control+Up/Down to move years)')
10170 monthYearText: 'Choose a month (Control+Up/Down to move years)',
10172 * @cfg {Number} startDay
10173 * Day index at which the week should begin, 0-based (defaults to 0, which is Sunday)
10177 * @cfg {Bool} showClear
10178 * Show a clear button (usefull for date form elements that can be blank.)
10184 * Sets the value of the date field
10185 * @param {Date} value The date to set
10187 setValue : function(value){
10188 var old = this.value;
10189 this.value = value.clearTime(true);
10191 this.update(this.value);
10196 * Gets the current selected value of the date field
10197 * @return {Date} The selected date
10199 getValue : function(){
10204 focus : function(){
10206 this.update(this.activeDate);
10211 onRender : function(container, position){
10213 '<table cellspacing="0">',
10214 '<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>',
10215 '<tr><td colspan="3"><table class="x-date-inner" cellspacing="0"><thead><tr>'];
10216 var dn = this.dayNames;
10217 for(var i = 0; i < 7; i++){
10218 var d = this.startDay+i;
10222 m.push("<th><span>", dn[d].substr(0,1), "</span></th>");
10224 m[m.length] = "</tr></thead><tbody><tr>";
10225 for(var i = 0; i < 42; i++) {
10226 if(i % 7 == 0 && i != 0){
10227 m[m.length] = "</tr><tr>";
10229 m[m.length] = '<td><a href="#" hidefocus="on" class="x-date-date" tabIndex="1"><em><span></span></em></a></td>';
10231 m[m.length] = '</tr></tbody></table></td></tr><tr>'+
10232 '<td colspan="3" class="x-date-bottom" align="center"></td></tr></table><div class="x-date-mp"></div>';
10234 var el = document.createElement("div");
10235 el.className = "x-date-picker";
10236 el.innerHTML = m.join("");
10238 container.dom.insertBefore(el, position);
10240 this.el = Roo.get(el);
10241 this.eventEl = Roo.get(el.firstChild);
10243 new Roo.util.ClickRepeater(this.el.child("td.x-date-left a"), {
10244 handler: this.showPrevMonth,
10246 preventDefault:true,
10250 new Roo.util.ClickRepeater(this.el.child("td.x-date-right a"), {
10251 handler: this.showNextMonth,
10253 preventDefault:true,
10257 this.eventEl.on("mousewheel", this.handleMouseWheel, this);
10259 this.monthPicker = this.el.down('div.x-date-mp');
10260 this.monthPicker.enableDisplayMode('block');
10262 var kn = new Roo.KeyNav(this.eventEl, {
10263 "left" : function(e){
10265 this.showPrevMonth() :
10266 this.update(this.activeDate.add("d", -1));
10269 "right" : function(e){
10271 this.showNextMonth() :
10272 this.update(this.activeDate.add("d", 1));
10275 "up" : function(e){
10277 this.showNextYear() :
10278 this.update(this.activeDate.add("d", -7));
10281 "down" : function(e){
10283 this.showPrevYear() :
10284 this.update(this.activeDate.add("d", 7));
10287 "pageUp" : function(e){
10288 this.showNextMonth();
10291 "pageDown" : function(e){
10292 this.showPrevMonth();
10295 "enter" : function(e){
10296 e.stopPropagation();
10303 this.eventEl.on("click", this.handleDateClick, this, {delegate: "a.x-date-date"});
10305 this.eventEl.addKeyListener(Roo.EventObject.SPACE, this.selectToday, this);
10307 this.el.unselectable();
10309 this.cells = this.el.select("table.x-date-inner tbody td");
10310 this.textNodes = this.el.query("table.x-date-inner tbody span");
10312 this.mbtn = new Roo.Button(this.el.child("td.x-date-middle", true), {
10314 tooltip: this.monthYearText
10317 this.mbtn.on('click', this.showMonthPicker, this);
10318 this.mbtn.el.child(this.mbtn.menuClassTarget).addClass("x-btn-with-menu");
10321 var today = (new Date()).dateFormat(this.format);
10323 var baseTb = new Roo.Toolbar(this.el.child("td.x-date-bottom", true));
10324 if (this.showClear) {
10325 baseTb.add( new Roo.Toolbar.Fill());
10328 text: String.format(this.todayText, today),
10329 tooltip: String.format(this.todayTip, today),
10330 handler: this.selectToday,
10334 //var todayBtn = new Roo.Button(this.el.child("td.x-date-bottom", true), {
10337 if (this.showClear) {
10339 baseTb.add( new Roo.Toolbar.Fill());
10342 cls: 'x-btn-icon x-btn-clear',
10343 handler: function() {
10345 this.fireEvent("select", this, '');
10355 this.update(this.value);
10358 createMonthPicker : function(){
10359 if(!this.monthPicker.dom.firstChild){
10360 var buf = ['<table border="0" cellspacing="0">'];
10361 for(var i = 0; i < 6; i++){
10363 '<tr><td class="x-date-mp-month"><a href="#">', this.monthNames[i].substr(0, 3), '</a></td>',
10364 '<td class="x-date-mp-month x-date-mp-sep"><a href="#">', this.monthNames[i+6].substr(0, 3), '</a></td>',
10366 '<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>' :
10367 '<td class="x-date-mp-year"><a href="#"></a></td><td class="x-date-mp-year"><a href="#"></a></td></tr>'
10371 '<tr class="x-date-mp-btns"><td colspan="4"><button type="button" class="x-date-mp-ok">',
10373 '</button><button type="button" class="x-date-mp-cancel">',
10375 '</button></td></tr>',
10378 this.monthPicker.update(buf.join(''));
10379 this.monthPicker.on('click', this.onMonthClick, this);
10380 this.monthPicker.on('dblclick', this.onMonthDblClick, this);
10382 this.mpMonths = this.monthPicker.select('td.x-date-mp-month');
10383 this.mpYears = this.monthPicker.select('td.x-date-mp-year');
10385 this.mpMonths.each(function(m, a, i){
10388 m.dom.xmonth = 5 + Math.round(i * .5);
10390 m.dom.xmonth = Math.round((i-1) * .5);
10396 showMonthPicker : function(){
10397 this.createMonthPicker();
10398 var size = this.el.getSize();
10399 this.monthPicker.setSize(size);
10400 this.monthPicker.child('table').setSize(size);
10402 this.mpSelMonth = (this.activeDate || this.value).getMonth();
10403 this.updateMPMonth(this.mpSelMonth);
10404 this.mpSelYear = (this.activeDate || this.value).getFullYear();
10405 this.updateMPYear(this.mpSelYear);
10407 this.monthPicker.slideIn('t', {duration:.2});
10410 updateMPYear : function(y){
10412 var ys = this.mpYears.elements;
10413 for(var i = 1; i <= 10; i++){
10414 var td = ys[i-1], y2;
10416 y2 = y + Math.round(i * .5);
10417 td.firstChild.innerHTML = y2;
10420 y2 = y - (5-Math.round(i * .5));
10421 td.firstChild.innerHTML = y2;
10424 this.mpYears.item(i-1)[y2 == this.mpSelYear ? 'addClass' : 'removeClass']('x-date-mp-sel');
10428 updateMPMonth : function(sm){
10429 this.mpMonths.each(function(m, a, i){
10430 m[m.dom.xmonth == sm ? 'addClass' : 'removeClass']('x-date-mp-sel');
10434 selectMPMonth: function(m){
10438 onMonthClick : function(e, t){
10440 var el = new Roo.Element(t), pn;
10441 if(el.is('button.x-date-mp-cancel')){
10442 this.hideMonthPicker();
10444 else if(el.is('button.x-date-mp-ok')){
10445 this.update(new Date(this.mpSelYear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10446 this.hideMonthPicker();
10448 else if(pn = el.up('td.x-date-mp-month', 2)){
10449 this.mpMonths.removeClass('x-date-mp-sel');
10450 pn.addClass('x-date-mp-sel');
10451 this.mpSelMonth = pn.dom.xmonth;
10453 else if(pn = el.up('td.x-date-mp-year', 2)){
10454 this.mpYears.removeClass('x-date-mp-sel');
10455 pn.addClass('x-date-mp-sel');
10456 this.mpSelYear = pn.dom.xyear;
10458 else if(el.is('a.x-date-mp-prev')){
10459 this.updateMPYear(this.mpyear-10);
10461 else if(el.is('a.x-date-mp-next')){
10462 this.updateMPYear(this.mpyear+10);
10466 onMonthDblClick : function(e, t){
10468 var el = new Roo.Element(t), pn;
10469 if(pn = el.up('td.x-date-mp-month', 2)){
10470 this.update(new Date(this.mpSelYear, pn.dom.xmonth, (this.activeDate || this.value).getDate()));
10471 this.hideMonthPicker();
10473 else if(pn = el.up('td.x-date-mp-year', 2)){
10474 this.update(new Date(pn.dom.xyear, this.mpSelMonth, (this.activeDate || this.value).getDate()));
10475 this.hideMonthPicker();
10479 hideMonthPicker : function(disableAnim){
10480 if(this.monthPicker){
10481 if(disableAnim === true){
10482 this.monthPicker.hide();
10484 this.monthPicker.slideOut('t', {duration:.2});
10490 showPrevMonth : function(e){
10491 this.update(this.activeDate.add("mo", -1));
10495 showNextMonth : function(e){
10496 this.update(this.activeDate.add("mo", 1));
10500 showPrevYear : function(){
10501 this.update(this.activeDate.add("y", -1));
10505 showNextYear : function(){
10506 this.update(this.activeDate.add("y", 1));
10510 handleMouseWheel : function(e){
10511 var delta = e.getWheelDelta();
10513 this.showPrevMonth();
10515 } else if(delta < 0){
10516 this.showNextMonth();
10522 handleDateClick : function(e, t){
10524 if(t.dateValue && !Roo.fly(t.parentNode).hasClass("x-date-disabled")){
10525 this.setValue(new Date(t.dateValue));
10526 this.fireEvent("select", this, this.value);
10531 selectToday : function(){
10532 this.setValue(new Date().clearTime());
10533 this.fireEvent("select", this, this.value);
10537 update : function(date){
10538 var vd = this.activeDate;
10539 this.activeDate = date;
10541 var t = date.getTime();
10542 if(vd.getMonth() == date.getMonth() && vd.getFullYear() == date.getFullYear()){
10543 this.cells.removeClass("x-date-selected");
10544 this.cells.each(function(c){
10545 if(c.dom.firstChild.dateValue == t){
10546 c.addClass("x-date-selected");
10547 setTimeout(function(){
10548 try{c.dom.firstChild.focus();}catch(e){}
10556 var days = date.getDaysInMonth();
10557 var firstOfMonth = date.getFirstDateOfMonth();
10558 var startingPos = firstOfMonth.getDay()-this.startDay;
10560 if(startingPos <= this.startDay){
10564 var pm = date.add("mo", -1);
10565 var prevStart = pm.getDaysInMonth()-startingPos;
10567 var cells = this.cells.elements;
10568 var textEls = this.textNodes;
10569 days += startingPos;
10571 // convert everything to numbers so it's fast
10572 var day = 86400000;
10573 var d = (new Date(pm.getFullYear(), pm.getMonth(), prevStart)).clearTime();
10574 var today = new Date().clearTime().getTime();
10575 var sel = date.clearTime().getTime();
10576 var min = this.minDate ? this.minDate.clearTime() : Number.NEGATIVE_INFINITY;
10577 var max = this.maxDate ? this.maxDate.clearTime() : Number.POSITIVE_INFINITY;
10578 var ddMatch = this.disabledDatesRE;
10579 var ddText = this.disabledDatesText;
10580 var ddays = this.disabledDays ? this.disabledDays.join("") : false;
10581 var ddaysText = this.disabledDaysText;
10582 var format = this.format;
10584 var setCellClass = function(cal, cell){
10586 var t = d.getTime();
10587 cell.firstChild.dateValue = t;
10589 cell.className += " x-date-today";
10590 cell.title = cal.todayText;
10593 cell.className += " x-date-selected";
10594 setTimeout(function(){
10595 try{cell.firstChild.focus();}catch(e){}
10600 cell.className = " x-date-disabled";
10601 cell.title = cal.minText;
10605 cell.className = " x-date-disabled";
10606 cell.title = cal.maxText;
10610 if(ddays.indexOf(d.getDay()) != -1){
10611 cell.title = ddaysText;
10612 cell.className = " x-date-disabled";
10615 if(ddMatch && format){
10616 var fvalue = d.dateFormat(format);
10617 if(ddMatch.test(fvalue)){
10618 cell.title = ddText.replace("%0", fvalue);
10619 cell.className = " x-date-disabled";
10625 for(; i < startingPos; i++) {
10626 textEls[i].innerHTML = (++prevStart);
10627 d.setDate(d.getDate()+1);
10628 cells[i].className = "x-date-prevday";
10629 setCellClass(this, cells[i]);
10631 for(; i < days; i++){
10632 intDay = i - startingPos + 1;
10633 textEls[i].innerHTML = (intDay);
10634 d.setDate(d.getDate()+1);
10635 cells[i].className = "x-date-active";
10636 setCellClass(this, cells[i]);
10639 for(; i < 42; i++) {
10640 textEls[i].innerHTML = (++extraDays);
10641 d.setDate(d.getDate()+1);
10642 cells[i].className = "x-date-nextday";
10643 setCellClass(this, cells[i]);
10646 this.mbtn.setText(this.monthNames[date.getMonth()] + " " + date.getFullYear());
10648 if(!this.internalRender){
10649 var main = this.el.dom.firstChild;
10650 var w = main.offsetWidth;
10651 this.el.setWidth(w + this.el.getBorderWidth("lr"));
10652 Roo.fly(main).setWidth(w);
10653 this.internalRender = true;
10654 // opera does not respect the auto grow header center column
10655 // then, after it gets a width opera refuses to recalculate
10656 // without a second pass
10657 if(Roo.isOpera && !this.secondPass){
10658 main.rows[0].cells[1].style.width = (w - (main.rows[0].cells[0].offsetWidth+main.rows[0].cells[2].offsetWidth)) + "px";
10659 this.secondPass = true;
10660 this.update.defer(10, this, [date]);